@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/discovery/index.mjs
CHANGED
|
@@ -1,16 +1,49 @@
|
|
|
1
1
|
import { extname, join, resolve } from "node:path";
|
|
2
|
-
import { readdir } from "node:fs/promises";
|
|
3
2
|
import { pathToFileURL } from "node:url";
|
|
4
|
-
|
|
3
|
+
import { readdir } from "node:fs/promises";
|
|
5
4
|
//#region src/discovery/index.ts
|
|
6
5
|
/**
|
|
6
|
+
* Arc Auto-Discovery Plugin
|
|
7
|
+
*
|
|
8
|
+
* Automatically discovers and registers resource files matching a glob pattern.
|
|
9
|
+
* Eliminates manual resource registration boilerplate.
|
|
10
|
+
*
|
|
11
|
+
* This is a SEPARATE subpath import — only loaded when explicitly used:
|
|
12
|
+
* import { discoveryPlugin, discoverResources } from '@classytic/arc/discovery';
|
|
13
|
+
*
|
|
14
|
+
* Serverless-safe: only runs at startup, no persistent process needed.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import { discoveryPlugin } from '@classytic/arc/discovery';
|
|
19
|
+
*
|
|
20
|
+
* // Auto-discovers all *.resource.ts files
|
|
21
|
+
* await fastify.register(discoveryPlugin, {
|
|
22
|
+
* paths: ['./src/modules'],
|
|
23
|
+
* pattern: '**\/*.resource.{ts,js}',
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* // Or use the helper directly
|
|
27
|
+
* import { discoverResources } from '@classytic/arc/discovery';
|
|
28
|
+
*
|
|
29
|
+
* const resources = await discoverResources({
|
|
30
|
+
* paths: ['./src/modules'],
|
|
31
|
+
* pattern: '**\/*.resource.{ts,js}',
|
|
32
|
+
* });
|
|
33
|
+
*
|
|
34
|
+
* for (const resource of resources) {
|
|
35
|
+
* await fastify.register(resource.toPlugin());
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
/**
|
|
7
40
|
* Match a filename against a simple pattern.
|
|
8
41
|
* Supports: *.resource.ts, *.resource.js, *.resource.{ts,js}
|
|
9
42
|
*/
|
|
10
43
|
function matchPattern(filename, pattern) {
|
|
11
44
|
if (pattern.includes("{") && pattern.includes("}")) {
|
|
12
45
|
const match = pattern.match(/\{([^}]+)\}/);
|
|
13
|
-
if (match) return match[1]
|
|
46
|
+
if (match) return (match[1]?.split(",").map((s) => s.trim()) ?? []).some((alt) => {
|
|
14
47
|
return matchPattern(filename, pattern.replace(match[0], alt));
|
|
15
48
|
});
|
|
16
49
|
}
|
|
@@ -104,6 +137,5 @@ const discoveryPluginImpl = async (fastify, options) => {
|
|
|
104
137
|
};
|
|
105
138
|
/** Auto-discovery plugin for Arc resources */
|
|
106
139
|
const discoveryPlugin = discoveryPluginImpl;
|
|
107
|
-
|
|
108
140
|
//#endregion
|
|
109
|
-
export { discoveryPlugin as default, discoveryPlugin, discoverResources };
|
|
141
|
+
export { discoveryPlugin as default, discoveryPlugin, discoverResources };
|
package/dist/docs/index.d.mts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import "../
|
|
2
|
-
import "../
|
|
3
|
-
import "../types-RLkFVgaw.mjs";
|
|
4
|
-
import { RegistryEntry } from "../types/index.mjs";
|
|
5
|
-
import { t as ExternalOpenApiPaths } from "../externalPaths-SyPF2tgK.mjs";
|
|
1
|
+
import { Q as RegistryEntry } from "../interface-DGmPxakH.mjs";
|
|
2
|
+
import { t as ExternalOpenApiPaths } from "../externalPaths-DpO-s7r8.mjs";
|
|
6
3
|
import { FastifyPluginAsync } from "fastify";
|
|
7
4
|
|
|
8
5
|
//#region src/docs/openapi.d.ts
|
|
@@ -74,19 +71,19 @@ interface Operation {
|
|
|
74
71
|
responses: Record<string, Response>;
|
|
75
72
|
security?: Array<Record<string, string[]>>;
|
|
76
73
|
/** Arc permission metadata (OpenAPI extension) */
|
|
77
|
-
|
|
74
|
+
"x-arc-permission"?: {
|
|
78
75
|
type: string;
|
|
79
76
|
roles?: readonly string[];
|
|
80
77
|
};
|
|
81
78
|
/** Arc pipeline steps (OpenAPI extension) */
|
|
82
|
-
|
|
79
|
+
"x-arc-pipeline"?: Array<{
|
|
83
80
|
type: string;
|
|
84
81
|
name: string;
|
|
85
82
|
}>;
|
|
86
83
|
}
|
|
87
84
|
interface Parameter {
|
|
88
85
|
name: string;
|
|
89
|
-
in:
|
|
86
|
+
in: "path" | "query" | "header";
|
|
90
87
|
required?: boolean;
|
|
91
88
|
schema: SchemaObject;
|
|
92
89
|
description?: string;
|
|
@@ -144,7 +141,7 @@ interface ScalarOptions {
|
|
|
144
141
|
/** Page title */
|
|
145
142
|
title?: string;
|
|
146
143
|
/** Theme (default: 'default') */
|
|
147
|
-
theme?:
|
|
144
|
+
theme?: "default" | "alternate" | "moon" | "purple" | "solarized" | "bluePlanet" | "saturn" | "kepler" | "mars" | "deepSpace";
|
|
148
145
|
/** Show sidebar (default: true) */
|
|
149
146
|
showSidebar?: boolean;
|
|
150
147
|
/** Dark mode (default: false) */
|
package/dist/docs/index.mjs
CHANGED
|
@@ -1,24 +1,7 @@
|
|
|
1
|
-
import { t as getUserRoles } from "../types-
|
|
2
|
-
import { n as openApiPlugin, r as openapi_default, t as buildOpenApiSpec } from "../openapi-
|
|
1
|
+
import { t as getUserRoles } from "../types-ZUu_h0jp.mjs";
|
|
2
|
+
import { n as openApiPlugin, r as openapi_default, t as buildOpenApiSpec } from "../openapi-CBmZ6EQN.mjs";
|
|
3
3
|
import fp from "fastify-plugin";
|
|
4
|
-
|
|
5
4
|
//#region src/docs/scalar.ts
|
|
6
|
-
/**
|
|
7
|
-
* Scalar API Reference Plugin
|
|
8
|
-
*
|
|
9
|
-
* Beautiful, modern API documentation UI.
|
|
10
|
-
* Lighter and more modern than Swagger UI.
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* import { scalarPlugin } from '@classytic/arc/docs';
|
|
14
|
-
*
|
|
15
|
-
* await fastify.register(scalarPlugin, {
|
|
16
|
-
* routePrefix: '/docs',
|
|
17
|
-
* specUrl: '/_docs/openapi.json',
|
|
18
|
-
* });
|
|
19
|
-
*
|
|
20
|
-
* // UI available at /docs
|
|
21
|
-
*/
|
|
22
5
|
const scalarPlugin = async (fastify, opts = {}) => {
|
|
23
6
|
const { routePrefix = "/docs", specUrl = "/_docs/openapi.json", title = "API Documentation", theme = "default", showSidebar = true, darkMode = false, authRoles = [], customCss = "", favicon } = opts;
|
|
24
7
|
const scalarConfig = JSON.stringify({
|
|
@@ -69,6 +52,5 @@ var scalar_default = fp(scalarPlugin, {
|
|
|
69
52
|
name: "arc-scalar",
|
|
70
53
|
fastify: "5.x"
|
|
71
54
|
});
|
|
72
|
-
|
|
73
55
|
//#endregion
|
|
74
|
-
export { buildOpenApiSpec, openapi_default as openApiPlugin, openApiPlugin as openApiPluginFn, scalar_default as scalarPlugin, scalarPlugin as scalarPluginFn };
|
|
56
|
+
export { buildOpenApiSpec, openapi_default as openApiPlugin, openApiPlugin as openApiPluginFn, scalar_default as scalarPlugin, scalarPlugin as scalarPluginFn };
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { Lt as ResourceDefinition, n as DataAdapter } from "../interface-DGmPxakH.mjs";
|
|
2
|
+
import { t as PermissionCheck } from "../types-BNUccdcf.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/dynamic/ArcDynamicLoader.d.ts
|
|
5
|
+
interface ArcArchitectureSchema {
|
|
6
|
+
/** Application name */
|
|
7
|
+
app: string;
|
|
8
|
+
/** Resources to provision */
|
|
9
|
+
resources: ArcResourceSchema[];
|
|
10
|
+
}
|
|
11
|
+
/** Field type — maps to JSON Schema / Zod types */
|
|
12
|
+
type ArcFieldType = "string" | "number" | "boolean" | "date" | "object" | "array";
|
|
13
|
+
/** Per-field definition — matches Arc's FieldRuleEntry for MCP compatibility */
|
|
14
|
+
interface ArcFieldSchema {
|
|
15
|
+
type: ArcFieldType;
|
|
16
|
+
required?: boolean;
|
|
17
|
+
description?: string;
|
|
18
|
+
enum?: string[];
|
|
19
|
+
min?: number;
|
|
20
|
+
max?: number;
|
|
21
|
+
minLength?: number;
|
|
22
|
+
maxLength?: number;
|
|
23
|
+
/** System-managed fields (createdAt, updatedAt) — excluded from create/update schemas */
|
|
24
|
+
systemManaged?: boolean;
|
|
25
|
+
/** Immutable after creation (e.g. slug, organizationId) */
|
|
26
|
+
immutable?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/** Permission preset name — matches Arc's built-in presets */
|
|
29
|
+
type ArcPermissionPreset = "publicRead" | "publicReadAdminWrite" | "authenticated" | "adminOnly" | "ownerWithAdminBypass" | "fullPublic" | "readOnly";
|
|
30
|
+
/** Fine-grained per-operation permission */
|
|
31
|
+
interface ArcPermissionMap {
|
|
32
|
+
list?: "public" | "auth" | "admin";
|
|
33
|
+
get?: "public" | "auth" | "admin";
|
|
34
|
+
create?: "auth" | "admin";
|
|
35
|
+
update?: "auth" | "admin" | "owner";
|
|
36
|
+
delete?: "auth" | "admin" | "owner";
|
|
37
|
+
}
|
|
38
|
+
interface ArcResourceSchema {
|
|
39
|
+
/** Resource name (e.g., 'product', 'user') — used for URL prefix and tool names */
|
|
40
|
+
name: string;
|
|
41
|
+
/** Display name for docs and MCP descriptions (defaults to capitalized name) */
|
|
42
|
+
displayName?: string;
|
|
43
|
+
/** Custom URL prefix (defaults to `/${name}s`) */
|
|
44
|
+
prefix?: string;
|
|
45
|
+
/** Adapter resolution key — passed to adapterResolver */
|
|
46
|
+
adapterPattern?: string;
|
|
47
|
+
/** Permission preset name or fine-grained per-operation map */
|
|
48
|
+
permissions: ArcPermissionPreset | ArcPermissionMap;
|
|
49
|
+
/** Presets to apply (e.g., 'softDelete', 'slugLookup', 'bulk') */
|
|
50
|
+
presets?: string[];
|
|
51
|
+
/** Field definitions — drives schemaOptions.fieldRules for validation and MCP tool schemas */
|
|
52
|
+
fields?: Record<string, ArcFieldSchema | ArcFieldType>;
|
|
53
|
+
/** Fields allowed for filtering in list operations (drives queryParser + MCP) */
|
|
54
|
+
filterable?: string[];
|
|
55
|
+
/** Fields allowed for sorting (drives queryParser + MCP) */
|
|
56
|
+
sortable?: string[];
|
|
57
|
+
/** CRUD operations to disable (e.g., ['delete'] for append-only resources) */
|
|
58
|
+
disabledRoutes?: string[];
|
|
59
|
+
/** Tenant field name for multi-tenant resources */
|
|
60
|
+
tenantField?: string;
|
|
61
|
+
}
|
|
62
|
+
interface DynamicLoaderContext {
|
|
63
|
+
/** Resolve a data adapter for a resource — receives name and optional pattern key */
|
|
64
|
+
adapterResolver: (resourceName: string, pattern?: string) => DataAdapter;
|
|
65
|
+
/** Resolve custom permission checks beyond built-in presets */
|
|
66
|
+
permissionResolver?: (policy: string) => PermissionCheck;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Load an Arc Architecture Schema (JSON) and produce fully configured ResourceDefinitions.
|
|
70
|
+
*
|
|
71
|
+
* Each resource gets:
|
|
72
|
+
* - Adapter from the resolver
|
|
73
|
+
* - Permissions from presets or fine-grained map
|
|
74
|
+
* - schemaOptions.fieldRules for validation and MCP tool schemas
|
|
75
|
+
* - ArcQueryParser with allowedFilterFields/allowedSortFields for MCP auto-derive
|
|
76
|
+
* - Presets applied
|
|
77
|
+
*/
|
|
78
|
+
declare class ArcDynamicLoader {
|
|
79
|
+
private context;
|
|
80
|
+
constructor(context: DynamicLoaderContext);
|
|
81
|
+
/**
|
|
82
|
+
* Load an AAS definition and return fully constructed ResourceDefinitions.
|
|
83
|
+
* Validates the schema before processing — throws on malformed input.
|
|
84
|
+
*/
|
|
85
|
+
load(schema: ArcArchitectureSchema): ResourceDefinition<unknown>[];
|
|
86
|
+
private buildFieldRules;
|
|
87
|
+
private buildQueryParser;
|
|
88
|
+
private resolvePermissions;
|
|
89
|
+
private resolvePreset;
|
|
90
|
+
private resolveFinGrained;
|
|
91
|
+
}
|
|
92
|
+
//#endregion
|
|
93
|
+
export { ArcArchitectureSchema, ArcDynamicLoader, ArcFieldSchema, ArcFieldType, ArcPermissionMap, ArcPermissionPreset, ArcResourceSchema, DynamicLoaderContext };
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { t as ArcQueryParser } from "../queryParser-CgCtsjti.mjs";
|
|
2
|
+
import { n as defineResource } from "../defineResource-D9aY5Cy6.mjs";
|
|
3
|
+
import { _ as ownerWithAdminBypass, b as publicReadAdminWrite, g as fullPublic, h as authenticated, m as adminOnly, x as readOnly, y as publicRead } from "../permissions-CA5zg0yK.mjs";
|
|
4
|
+
//#region src/dynamic/ArcDynamicLoader.ts
|
|
5
|
+
const VALID_FIELD_TYPES = new Set([
|
|
6
|
+
"string",
|
|
7
|
+
"number",
|
|
8
|
+
"boolean",
|
|
9
|
+
"date",
|
|
10
|
+
"object",
|
|
11
|
+
"array"
|
|
12
|
+
]);
|
|
13
|
+
function validateSchema(schema) {
|
|
14
|
+
if (!schema.app || typeof schema.app !== "string") throw new Error("AAS: 'app' name is required");
|
|
15
|
+
if (!Array.isArray(schema.resources) || schema.resources.length === 0) throw new Error("AAS: 'resources' must be a non-empty array");
|
|
16
|
+
for (const r of schema.resources) {
|
|
17
|
+
if (!r.name || typeof r.name !== "string") throw new Error("AAS: each resource must have a 'name' string");
|
|
18
|
+
if (!r.permissions) throw new Error(`AAS: resource "${r.name}" must have 'permissions'`);
|
|
19
|
+
if (r.fields) for (const [fieldName, fieldDef] of Object.entries(r.fields)) {
|
|
20
|
+
const type = typeof fieldDef === "string" ? fieldDef : fieldDef.type;
|
|
21
|
+
if (!VALID_FIELD_TYPES.has(type)) throw new Error(`AAS: resource "${r.name}" field "${fieldName}" has invalid type "${type}". Valid types: ${[...VALID_FIELD_TYPES].join(", ")}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Load an Arc Architecture Schema (JSON) and produce fully configured ResourceDefinitions.
|
|
27
|
+
*
|
|
28
|
+
* Each resource gets:
|
|
29
|
+
* - Adapter from the resolver
|
|
30
|
+
* - Permissions from presets or fine-grained map
|
|
31
|
+
* - schemaOptions.fieldRules for validation and MCP tool schemas
|
|
32
|
+
* - ArcQueryParser with allowedFilterFields/allowedSortFields for MCP auto-derive
|
|
33
|
+
* - Presets applied
|
|
34
|
+
*/
|
|
35
|
+
var ArcDynamicLoader = class {
|
|
36
|
+
context;
|
|
37
|
+
constructor(context) {
|
|
38
|
+
this.context = context;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Load an AAS definition and return fully constructed ResourceDefinitions.
|
|
42
|
+
* Validates the schema before processing — throws on malformed input.
|
|
43
|
+
*/
|
|
44
|
+
load(schema) {
|
|
45
|
+
validateSchema(schema);
|
|
46
|
+
return schema.resources.map((r) => {
|
|
47
|
+
const adapter = this.context.adapterResolver(r.name, r.adapterPattern);
|
|
48
|
+
const fieldRules = this.buildFieldRules(r.fields);
|
|
49
|
+
const queryParser = this.buildQueryParser(r);
|
|
50
|
+
return defineResource({
|
|
51
|
+
name: r.name,
|
|
52
|
+
displayName: r.displayName,
|
|
53
|
+
prefix: r.prefix,
|
|
54
|
+
adapter,
|
|
55
|
+
queryParser,
|
|
56
|
+
presets: r.presets,
|
|
57
|
+
permissions: this.resolvePermissions(r.permissions),
|
|
58
|
+
disabledRoutes: r.disabledRoutes,
|
|
59
|
+
tenantField: r.tenantField,
|
|
60
|
+
schemaOptions: fieldRules ? {
|
|
61
|
+
fieldRules,
|
|
62
|
+
filterableFields: r.filterable
|
|
63
|
+
} : void 0
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
buildFieldRules(fields) {
|
|
68
|
+
if (!fields) return void 0;
|
|
69
|
+
const rules = {};
|
|
70
|
+
for (const [name, def] of Object.entries(fields)) rules[name] = typeof def === "string" ? { type: def } : def;
|
|
71
|
+
return rules;
|
|
72
|
+
}
|
|
73
|
+
buildQueryParser(r) {
|
|
74
|
+
if (!r.filterable && !r.sortable) return void 0;
|
|
75
|
+
return new ArcQueryParser({
|
|
76
|
+
allowedFilterFields: r.filterable,
|
|
77
|
+
allowedSortFields: r.sortable
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
resolvePermissions(policy) {
|
|
81
|
+
if (typeof policy === "string") return this.resolvePreset(policy);
|
|
82
|
+
return this.resolveFinGrained(policy);
|
|
83
|
+
}
|
|
84
|
+
resolvePreset(preset) {
|
|
85
|
+
switch (preset) {
|
|
86
|
+
case "publicRead": return publicRead();
|
|
87
|
+
case "publicReadAdminWrite": return publicReadAdminWrite();
|
|
88
|
+
case "authenticated": return authenticated();
|
|
89
|
+
case "adminOnly": return adminOnly();
|
|
90
|
+
case "ownerWithAdminBypass": return ownerWithAdminBypass();
|
|
91
|
+
case "fullPublic": return fullPublic();
|
|
92
|
+
case "readOnly": return readOnly();
|
|
93
|
+
default:
|
|
94
|
+
if (this.context.permissionResolver) {
|
|
95
|
+
const resolved = this.context.permissionResolver(preset);
|
|
96
|
+
if (resolved) return resolved;
|
|
97
|
+
}
|
|
98
|
+
throw new Error(`Unknown permission preset: "${preset}"`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
resolveFinGrained(policy) {
|
|
102
|
+
const pick = (preset, op) => preset[op] ?? authenticated()[op];
|
|
103
|
+
const map = {
|
|
104
|
+
public: (op) => pick(publicRead(), op),
|
|
105
|
+
auth: (op) => pick(authenticated(), op),
|
|
106
|
+
admin: (op) => pick(adminOnly(), op),
|
|
107
|
+
owner: (op) => pick(ownerWithAdminBypass(), op)
|
|
108
|
+
};
|
|
109
|
+
const permissions = {};
|
|
110
|
+
const ops = {
|
|
111
|
+
list: policy.list,
|
|
112
|
+
get: policy.get,
|
|
113
|
+
create: policy.create,
|
|
114
|
+
update: policy.update,
|
|
115
|
+
delete: policy.delete
|
|
116
|
+
};
|
|
117
|
+
for (const [op, level] of Object.entries(ops)) if (level && map[level]) permissions[op] = map[level](op);
|
|
118
|
+
return permissions;
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
//#endregion
|
|
122
|
+
export { ArcDynamicLoader };
|
|
@@ -1,39 +1,8 @@
|
|
|
1
|
-
import { t as __exportAll } from "./chunk-
|
|
2
|
-
import { t as getUserRoles } from "./types-
|
|
3
|
-
import { t as arcLog } from "./logger-
|
|
1
|
+
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
2
|
+
import { t as getUserRoles } from "./types-ZUu_h0jp.mjs";
|
|
3
|
+
import { t as arcLog } from "./logger-Dz3j1ItV.mjs";
|
|
4
4
|
import fp from "fastify-plugin";
|
|
5
|
-
|
|
6
5
|
//#region src/scope/elevation.ts
|
|
7
|
-
/**
|
|
8
|
-
* Elevation Plugin — Explicit Platform Admin Access
|
|
9
|
-
*
|
|
10
|
-
* Opt-in Fastify plugin that allows platform admins to explicitly
|
|
11
|
-
* elevate their scope via the `x-arc-scope: platform` header.
|
|
12
|
-
*
|
|
13
|
-
* Without this header, a superadmin is treated as a normal user.
|
|
14
|
-
* This prevents implicit bypass and enables audit logging.
|
|
15
|
-
*
|
|
16
|
-
* ## Lifecycle
|
|
17
|
-
*
|
|
18
|
-
* Elevation wraps `fastify.authenticate` so it always runs AFTER
|
|
19
|
-
* authentication has set `request.user`. This avoids the `onRequest`
|
|
20
|
-
* timing issue where `request.user` doesn't exist yet.
|
|
21
|
-
*
|
|
22
|
-
* Flow: `authenticate()` → user is set → `elevation check` → scope is set
|
|
23
|
-
*
|
|
24
|
-
* Inspired by Stripe Connect's `Stripe-Account` header.
|
|
25
|
-
*
|
|
26
|
-
* @example
|
|
27
|
-
* ```typescript
|
|
28
|
-
* const app = await createApp({
|
|
29
|
-
* auth: { type: 'betterAuth', betterAuth: adapter },
|
|
30
|
-
* elevation: {
|
|
31
|
-
* platformRoles: ['superadmin'],
|
|
32
|
-
* onElevation: (event) => auditLog.write(event),
|
|
33
|
-
* },
|
|
34
|
-
* });
|
|
35
|
-
* ```
|
|
36
|
-
*/
|
|
37
6
|
var elevation_exports = /* @__PURE__ */ __exportAll({
|
|
38
7
|
default: () => elevation_default,
|
|
39
8
|
elevationPlugin: () => elevationPlugin
|
|
@@ -80,6 +49,7 @@ const elevationPlugin = async (fastify, opts = {}) => {
|
|
|
80
49
|
const userId = String(user.id ?? user._id ?? "unknown");
|
|
81
50
|
request.scope = {
|
|
82
51
|
kind: "elevated",
|
|
52
|
+
userId,
|
|
83
53
|
organizationId: orgId || void 0,
|
|
84
54
|
elevatedBy: userId
|
|
85
55
|
};
|
|
@@ -108,6 +78,5 @@ var elevation_default = fp(elevationPlugin, {
|
|
|
108
78
|
name: "arc-elevation",
|
|
109
79
|
fastify: "5.x"
|
|
110
80
|
});
|
|
111
|
-
|
|
112
81
|
//#endregion
|
|
113
|
-
export { elevation_default as n, elevation_exports as r, elevationPlugin as t };
|
|
82
|
+
export { elevation_default as n, elevation_exports as r, elevationPlugin as t };
|
|
@@ -15,6 +15,10 @@ import { FastifyPluginAsync, FastifyRequest } from "fastify";
|
|
|
15
15
|
* const scope = request.scope;
|
|
16
16
|
* if (isElevated(scope)) return true;
|
|
17
17
|
* if (isMember(scope) && scope.orgRoles.includes('admin')) return true;
|
|
18
|
+
*
|
|
19
|
+
* // Get user identity from scope
|
|
20
|
+
* const userId = getUserId(scope);
|
|
21
|
+
* const globalRoles = getUserRoles(scope);
|
|
18
22
|
* ```
|
|
19
23
|
*/
|
|
20
24
|
/**
|
|
@@ -26,28 +30,36 @@ import { FastifyPluginAsync, FastifyRequest } from "fastify";
|
|
|
26
30
|
* | authenticated | Logged in, no org context |
|
|
27
31
|
* | member | In an org with specific roles |
|
|
28
32
|
* | elevated | Platform admin, explicit elevation |
|
|
33
|
+
*
|
|
34
|
+
* `userId` and `userRoles` are available on all authenticated variants.
|
|
35
|
+
* `orgRoles` are org-level roles (from membership); `userRoles` are global roles (from user document).
|
|
29
36
|
*/
|
|
30
37
|
type RequestScope = {
|
|
31
|
-
kind:
|
|
38
|
+
kind: "public";
|
|
32
39
|
} | {
|
|
33
|
-
kind:
|
|
40
|
+
kind: "authenticated";
|
|
41
|
+
userId?: string;
|
|
42
|
+
userRoles?: string[];
|
|
34
43
|
} | {
|
|
35
|
-
kind:
|
|
44
|
+
kind: "member";
|
|
45
|
+
userId?: string;
|
|
46
|
+
userRoles: string[];
|
|
36
47
|
organizationId: string;
|
|
37
48
|
orgRoles: string[];
|
|
38
49
|
teamId?: string;
|
|
39
50
|
} | {
|
|
40
|
-
kind:
|
|
51
|
+
kind: "elevated";
|
|
52
|
+
userId?: string;
|
|
41
53
|
organizationId?: string;
|
|
42
54
|
elevatedBy: string;
|
|
43
55
|
};
|
|
44
56
|
/** Check if scope is `member` kind */
|
|
45
57
|
declare function isMember(scope: RequestScope): scope is Extract<RequestScope, {
|
|
46
|
-
kind:
|
|
58
|
+
kind: "member";
|
|
47
59
|
}>;
|
|
48
60
|
/** Check if scope is `elevated` kind */
|
|
49
61
|
declare function isElevated(scope: RequestScope): scope is Extract<RequestScope, {
|
|
50
|
-
kind:
|
|
62
|
+
kind: "elevated";
|
|
51
63
|
}>;
|
|
52
64
|
/** Check if scope has org access (member OR elevated) */
|
|
53
65
|
declare function hasOrgAccess(scope: RequestScope): boolean;
|
|
@@ -59,6 +71,28 @@ declare function getOrgId(scope: RequestScope): string | undefined;
|
|
|
59
71
|
declare function getOrgRoles(scope: RequestScope): string[];
|
|
60
72
|
/** Get team ID from scope (only available on member kind) */
|
|
61
73
|
declare function getTeamId(scope: RequestScope): string | undefined;
|
|
74
|
+
/**
|
|
75
|
+
* Get userId from scope (available on authenticated, member, elevated).
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```typescript
|
|
79
|
+
* import { getUserId } from '@classytic/arc/scope';
|
|
80
|
+
* const userId = getUserId(request.scope);
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
declare function getUserId(scope: RequestScope): string | undefined;
|
|
84
|
+
/**
|
|
85
|
+
* Get global user roles from scope (available on authenticated and member).
|
|
86
|
+
* These are user-level roles (e.g. superadmin, finance-admin) distinct from
|
|
87
|
+
* org-level roles (scope.orgRoles).
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* import { getUserRoles } from '@classytic/arc/scope';
|
|
92
|
+
* const globalRoles = getUserRoles(request.scope);
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
declare function getUserRoles(scope: RequestScope): string[];
|
|
62
96
|
/** Default public scope — used as initial decoration value */
|
|
63
97
|
declare const PUBLIC_SCOPE: Readonly<RequestScope>;
|
|
64
98
|
/** Default authenticated scope — used when user is logged in but no org */
|
|
@@ -84,4 +118,4 @@ interface ElevationEvent {
|
|
|
84
118
|
declare const elevationPlugin: FastifyPluginAsync<ElevationOptions>;
|
|
85
119
|
declare const _default: FastifyPluginAsync<ElevationOptions>;
|
|
86
120
|
//#endregion
|
|
87
|
-
export { AUTHENTICATED_SCOPE as a, getOrgId as c,
|
|
121
|
+
export { AUTHENTICATED_SCOPE as a, getOrgId as c, getUserId as d, getUserRoles as f, isMember as g, isElevated as h, elevationPlugin as i, getOrgRoles as l, isAuthenticated as m, ElevationOptions as n, PUBLIC_SCOPE as o, hasOrgAccess as p, _default as r, RequestScope as s, ElevationEvent as t, getTeamId as u };
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { t as __exportAll } from "./chunk-
|
|
2
|
-
import { f as isArcError } from "./errors-
|
|
1
|
+
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
2
|
+
import { f as isArcError } from "./errors-rxhfP7Hf.mjs";
|
|
3
3
|
import fp from "fastify-plugin";
|
|
4
|
-
|
|
5
4
|
//#region src/plugins/errorHandler.ts
|
|
6
5
|
var errorHandler_exports = /* @__PURE__ */ __exportAll({
|
|
7
6
|
default: () => errorHandlerPlugin,
|
|
@@ -103,6 +102,5 @@ const errorHandlerPlugin = fp(errorHandlerPluginFn, {
|
|
|
103
102
|
name: "arc-error-handler",
|
|
104
103
|
fastify: "5.x"
|
|
105
104
|
});
|
|
106
|
-
|
|
107
105
|
//#endregion
|
|
108
|
-
export { errorHandler_exports as n, errorHandlerPlugin as t };
|
|
106
|
+
export { errorHandler_exports as n, errorHandlerPlugin as t };
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { t as DomainEvent } from "./EventTransport-wc5hSLik.mjs";
|
|
2
|
+
import { FastifyInstance, 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
|
+
//#region src/plugins/errorHandler.d.ts
|
|
118
|
+
interface ErrorHandlerOptions {
|
|
119
|
+
/**
|
|
120
|
+
* Include stack trace in error responses (default: false in production)
|
|
121
|
+
*/
|
|
122
|
+
includeStack?: boolean;
|
|
123
|
+
/**
|
|
124
|
+
* Custom error callback for logging to external services
|
|
125
|
+
*/
|
|
126
|
+
onError?: (error: Error, request: FastifyRequest) => void | Promise<void>;
|
|
127
|
+
/**
|
|
128
|
+
* Map specific error types to custom responses
|
|
129
|
+
*/
|
|
130
|
+
errorMap?: Record<string, {
|
|
131
|
+
statusCode: number;
|
|
132
|
+
code: string;
|
|
133
|
+
message?: string;
|
|
134
|
+
}>;
|
|
135
|
+
}
|
|
136
|
+
declare function errorHandlerPluginFn(fastify: FastifyInstance, options?: ErrorHandlerOptions): Promise<void>;
|
|
137
|
+
declare const errorHandlerPlugin: typeof errorHandlerPluginFn;
|
|
138
|
+
//#endregion
|
|
139
|
+
export { cachingPlugin as _, versioningPlugin as a, MetricsOptions as c, SSEOptions as d, _default$2 as f, _default$3 as g, CachingRule as h, _default as i, _default$1 as l, CachingOptions as m, errorHandlerPlugin as n, MetricEntry as o, ssePlugin as p, VersioningOptions as r, MetricsCollector as s, ErrorHandlerOptions as t, metricsPlugin as u };
|
|
@@ -206,6 +206,5 @@ function createError(statusCode, message, details) {
|
|
|
206
206
|
function isArcError(error) {
|
|
207
207
|
return error instanceof ArcError;
|
|
208
208
|
}
|
|
209
|
-
|
|
210
209
|
//#endregion
|
|
211
|
-
export { OrgAccessDeniedError as a, ServiceUnavailableError as c, createError as d, isArcError as f, NotFoundError as i, UnauthorizedError as l, ConflictError as n, OrgRequiredError as o, ForbiddenError as r, RateLimitError as s, ArcError as t, ValidationError as u };
|
|
210
|
+
export { OrgAccessDeniedError as a, ServiceUnavailableError as c, createError as d, isArcError as f, NotFoundError as i, UnauthorizedError as l, ConflictError as n, OrgRequiredError as o, ForbiddenError as r, RateLimitError as s, ArcError as t, ValidationError as u };
|