@classytic/arc 2.21.0 → 2.22.0
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/dist/{BaseController-BnLYgE9A.mjs → BaseController-C6FlRWxF.mjs} +1 -1
- package/dist/audit/index.d.mts +2 -2
- package/dist/auth/index.d.mts +30 -2
- package/dist/auth/index.mjs +5 -2
- package/dist/cli/commands/describe.d.mts +1 -1
- package/dist/cli/commands/docs.mjs +1 -1
- package/dist/cli/commands/init.mjs +1 -1
- package/dist/cli/index.mjs +1 -1
- package/dist/core/index.d.mts +2 -2
- package/dist/core/index.mjs +2 -2
- package/dist/{core-DZ6Xe1jR.mjs → core-b6fgFgnd.mjs} +123 -66
- package/dist/{createActionRouter-BWMDW-dL.mjs → createActionRouter-h1cEEaEX.mjs} +9 -5
- package/dist/{createAggregationRouter-l5mNdYrZ.mjs → createAggregationRouter-B1C0kvTL.mjs} +3 -3
- package/dist/{createApp-Bi61XxqU.mjs → createApp-Ci7yG5gv.mjs} +242 -56
- package/dist/docs/index.d.mts +1 -1
- package/dist/docs/index.mjs +1 -1
- package/dist/encryption/index.mjs +9 -5
- package/dist/{errorHandler-Dxf6P_kV.mjs → errorHandler-BTzXSwIg.mjs} +24 -3
- package/dist/{errorHandler-B0e-bq-O.d.mts → errorHandler-C6yv4ZTW.d.mts} +13 -0
- package/dist/factory/index.d.mts +29 -8
- package/dist/factory/index.mjs +34 -3
- package/dist/{fastify-augmentation-DafigGQp.d.mts → fastify-augmentation-9_fuetB4.d.mts} +2 -2
- package/dist/fields-D3lhgzhD.d.mts +121 -0
- package/dist/health-ScyjIVo5.mjs +202 -0
- package/dist/hooks/index.d.mts +1 -1
- package/dist/idempotency/index.mjs +2 -0
- package/dist/{types-DpxoNX5v.d.mts → index-BEu4wjbL.d.mts} +187 -66
- package/dist/{index-B5N-NaHs.d.mts → index-D8MKYGDa.d.mts} +3 -3
- package/dist/{index-Dtrj6XZk.d.mts → index-DbtgCOCj.d.mts} +1287 -1225
- package/dist/{index-B5PoNbfu.d.mts → index-ogIHvOjo.d.mts} +1 -1
- package/dist/index.d.mts +6 -5
- package/dist/index.mjs +3 -3
- package/dist/{init-0YhHkXGk.mjs → init-DleK3p9f.mjs} +118 -2
- package/dist/integrations/index.d.mts +1 -1
- package/dist/integrations/mcp/index.d.mts +3 -3
- 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/integrations/webhooks.d.mts +8 -4
- package/dist/integrations/webhooks.mjs +9 -5
- package/dist/jsonBody-BlzAoGCe.mjs +43 -0
- package/dist/logger/index.d.mts +26 -1
- package/dist/logger/index.mjs +39 -1
- package/dist/{mcpPlugin-B9XjjNVG.mjs → mcpPlugin-ByA2tf6D.mjs} +6 -2
- package/dist/middleware/index.d.mts +1 -1
- package/dist/{module-WeuU5jfd.d.mts → module-B4u10iOJ.d.mts} +26 -1
- package/dist/{openapi-Kyod_di6.mjs → openapi-BRpMZD7C.mjs} +2 -2
- package/dist/permissions/index.d.mts +3 -2
- package/dist/pipeline/index.d.mts +1 -1
- package/dist/plugins/index.d.mts +22 -5
- package/dist/plugins/index.mjs +11 -280
- package/dist/plugins/response-cache.mjs +1 -0
- package/dist/plugins/tracing-entry.mjs +7 -4
- package/dist/presets/filesUpload.d.mts +2 -2
- package/dist/presets/index.d.mts +1 -1
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/presets/search.d.mts +2 -2
- package/dist/rateLimitKey-BoWRH3e7.mjs +14 -0
- package/dist/{registerRoute-oGAl0oA8.mjs → registerRoute-xHc42fwB.mjs} +37 -17
- package/dist/registry/index.d.mts +2 -2
- package/dist/requestId-5BhTVzBv.mjs +113 -0
- package/dist/schemaConverter-Ds5reSGs.mjs +168 -0
- package/dist/{schemaIR-ajetw3Fv.mjs → schemaIR-B-6SPe7g.mjs} +2 -2
- package/dist/scim/index.mjs +6 -7
- package/dist/scope/index.mjs +2 -76
- package/dist/scope-k15RXfcq.mjs +64 -0
- package/dist/testing/index.d.mts +83 -3
- package/dist/testing/index.mjs +70 -3
- package/dist/types/index.d.mts +2 -2
- package/dist/{types-DRj-Ut4n.d.mts → types-Bc42CUyk.d.mts} +1 -1
- package/dist/{fields-BGqrAa_u.d.mts → types-Csxga7d3.d.mts} +1 -121
- package/dist/usage/index.d.mts +142 -0
- package/dist/usage/index.mjs +0 -0
- package/dist/utils/index.d.mts +40 -18
- package/dist/utils/index.mjs +2 -2
- package/dist/{utils-CO8a3B_1.mjs → utils-FhJ88TJE.mjs} +59 -13
- package/dist/{versioning-DQ4mCvg0.d.mts → versioning-DLwklPlG.d.mts} +0 -5
- package/llms.txt +39 -0
- package/package.json +453 -447
- package/skills/arc/SKILL.md +14 -8
- package/skills/arc/references/api-reference.md +34 -0
- package/skills/arc/references/auth.md +21 -4
- package/skills/arc/references/mcp.md +1 -1
- package/skills/arc/references/production.md +44 -2
- package/skills/arc-code-review/SKILL.md +1 -1
- package/skills/arc-code-review/references/anti-patterns.md +71 -18
- package/skills/arc-code-review/references/arc-cheatsheet.md +15 -2
- package/skills/arc-code-review/references/migration-recipes.md +7 -7
- package/skills/arc-code-review/references/mongokit-migration.md +4 -3
- package/skills/arc-module-publishing/SKILL.md +2 -1
- package/skills/arc-module-publishing/references/authoring-modules.md +55 -0
- package/skills/arc-module-publishing/references/package-manifest.md +4 -2
- package/dist/preloadResources-CHw3_oA_.mjs +0 -45
- package/dist/schemaConverter-U0MnO9vd.mjs +0 -110
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { bn as HookSystem, z as ResourceRegistry } from "./index-
|
|
1
|
+
import { bn as HookSystem, z as ResourceRegistry } from "./index-DbtgCOCj.mjs";
|
|
2
2
|
import { t as ExternalOpenApiPaths } from "./externalPaths-BE6wFpYv.mjs";
|
|
3
|
-
import { r as ArcModuleRegistry } from "./module-
|
|
3
|
+
import { r as ArcModuleRegistry } from "./module-B4u10iOJ.mjs";
|
|
4
4
|
import { FastifyPluginAsync } from "fastify";
|
|
5
5
|
//#region src/core/arcCorePlugin.d.ts
|
|
6
6
|
interface ArcCorePluginOptions {
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
//#region src/permissions/fields.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Field-Level Permissions
|
|
4
|
+
*
|
|
5
|
+
* Control field visibility and writability per role.
|
|
6
|
+
* Integrated into the response path (read) and sanitization path (write).
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { fields, defineResource } from '@classytic/arc';
|
|
11
|
+
*
|
|
12
|
+
* const userResource = defineResource({
|
|
13
|
+
* name: 'user',
|
|
14
|
+
* adapter: userAdapter,
|
|
15
|
+
* fields: {
|
|
16
|
+
* salary: fields.visibleTo(['admin', 'hr']),
|
|
17
|
+
* internalNotes: fields.writableBy(['admin']),
|
|
18
|
+
* email: fields.redactFor(['viewer']),
|
|
19
|
+
* password: fields.hidden(),
|
|
20
|
+
* },
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
type FieldPermissionType = "hidden" | "visibleTo" | "writableBy" | "redactFor";
|
|
25
|
+
interface FieldPermission {
|
|
26
|
+
readonly _type: FieldPermissionType;
|
|
27
|
+
readonly roles?: readonly string[];
|
|
28
|
+
readonly redactValue?: unknown;
|
|
29
|
+
}
|
|
30
|
+
type FieldPermissionMap = Record<string, FieldPermission>;
|
|
31
|
+
declare const fields: {
|
|
32
|
+
/**
|
|
33
|
+
* Field is never included in responses. Not writable via API.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* fields: { password: fields.hidden() }
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
hidden(): FieldPermission;
|
|
41
|
+
/**
|
|
42
|
+
* Field is only visible to users with specified roles.
|
|
43
|
+
* Other users don't see the field at all.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* fields: { salary: fields.visibleTo(['admin', 'hr']) }
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
visibleTo(roles: readonly string[]): FieldPermission;
|
|
51
|
+
/**
|
|
52
|
+
* Field is only writable by users with specified roles.
|
|
53
|
+
* All users can still read the field. Users without the role
|
|
54
|
+
* have the field silently stripped from write operations.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* fields: { role: fields.writableBy(['admin']) }
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
writableBy(roles: readonly string[]): FieldPermission;
|
|
62
|
+
/**
|
|
63
|
+
* Field is redacted (replaced with a placeholder) for specified roles.
|
|
64
|
+
* Other users see the real value.
|
|
65
|
+
*
|
|
66
|
+
* @param roles - Roles that see the redacted value
|
|
67
|
+
* @param redactValue - Replacement value (default: '***')
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```typescript
|
|
71
|
+
* fields: {
|
|
72
|
+
* email: fields.redactFor(['viewer']),
|
|
73
|
+
* ssn: fields.redactFor(['basic'], '***-**-****'),
|
|
74
|
+
* }
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
redactFor(roles: readonly string[], redactValue?: unknown): FieldPermission;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Apply field-level READ permissions to a response object.
|
|
81
|
+
* Strips hidden fields, enforces visibility, and applies redaction.
|
|
82
|
+
*
|
|
83
|
+
* @param data - The response object (mutated in place for performance)
|
|
84
|
+
* @param fieldPermissions - Field permission map from resource config
|
|
85
|
+
* @param userRoles - Current user's roles (empty array for unauthenticated)
|
|
86
|
+
* @returns The filtered object
|
|
87
|
+
*/
|
|
88
|
+
declare function applyFieldReadPermissions<T extends Record<string, unknown>>(data: T, fieldPermissions: FieldPermissionMap, userRoles: readonly string[]): T;
|
|
89
|
+
/**
|
|
90
|
+
* Result of applying write permissions — includes both the filtered body
|
|
91
|
+
* and the list of fields that were stripped so callers can decide whether
|
|
92
|
+
* to reject the request (secure default) or silently strip (legacy).
|
|
93
|
+
*/
|
|
94
|
+
interface FieldWritePermissionResult<T extends Record<string, unknown>> {
|
|
95
|
+
readonly body: T;
|
|
96
|
+
readonly deniedFields: readonly string[];
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Apply field-level WRITE permissions to request body.
|
|
100
|
+
*
|
|
101
|
+
* Returns both the filtered body and the list of denied fields. Callers are
|
|
102
|
+
* expected to reject the request when `deniedFields.length > 0` — silently
|
|
103
|
+
* stripping fields hides misconfigurations and real attacks. See
|
|
104
|
+
* `BodySanitizer` for the default policy.
|
|
105
|
+
*
|
|
106
|
+
* @param body - The request body (returns a new filtered copy)
|
|
107
|
+
* @param fieldPermissions - Field permission map from resource config
|
|
108
|
+
* @param userRoles - Current user's roles
|
|
109
|
+
*/
|
|
110
|
+
declare function applyFieldWritePermissions<T extends Record<string, unknown>>(body: T, fieldPermissions: FieldPermissionMap, userRoles: readonly string[]): FieldWritePermissionResult<T>;
|
|
111
|
+
/**
|
|
112
|
+
* Resolve effective roles by merging global user roles with org-level roles.
|
|
113
|
+
*
|
|
114
|
+
* Global roles come from `req.user.role` (normalized via getUserRoles()).
|
|
115
|
+
* Org roles come from `req.context.orgRoles` (set by BA adapter's org bridge).
|
|
116
|
+
*
|
|
117
|
+
* When no org context exists, returns global roles only — backward compatible.
|
|
118
|
+
*/
|
|
119
|
+
declare function resolveEffectiveRoles(userRoles: readonly string[], orgRoles: readonly string[]): string[];
|
|
120
|
+
//#endregion
|
|
121
|
+
export { applyFieldWritePermissions as a, applyFieldReadPermissions as i, FieldPermissionMap as n, fields as o, FieldPermissionType as r, resolveEffectiveRoles as s, FieldPermission as t };
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import fp from "fastify-plugin";
|
|
2
|
+
//#region src/plugins/health.ts
|
|
3
|
+
function createHttpMetrics() {
|
|
4
|
+
return {
|
|
5
|
+
requestsTotal: {},
|
|
6
|
+
requestDurations: [],
|
|
7
|
+
_ringIndex: 0,
|
|
8
|
+
startTime: Date.now()
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
const healthPlugin = async (fastify, opts = {}) => {
|
|
12
|
+
const { prefix = "/_health", checks = [], metrics = false, metricsCollector, version, collectHttpMetrics = metrics } = opts;
|
|
13
|
+
const httpMetrics = createHttpMetrics();
|
|
14
|
+
fastify.get(prefix, { schema: {
|
|
15
|
+
tags: ["Health"],
|
|
16
|
+
summary: "Liveness probe (alias for /live)",
|
|
17
|
+
description: "Returns 200 if the process is alive",
|
|
18
|
+
response: { 200: {
|
|
19
|
+
type: "object",
|
|
20
|
+
properties: {
|
|
21
|
+
status: {
|
|
22
|
+
type: "string",
|
|
23
|
+
enum: ["ok"]
|
|
24
|
+
},
|
|
25
|
+
timestamp: { type: "string" },
|
|
26
|
+
version: { type: "string" }
|
|
27
|
+
}
|
|
28
|
+
} }
|
|
29
|
+
} }, async () => ({
|
|
30
|
+
status: "ok",
|
|
31
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
32
|
+
...version ? { version } : {}
|
|
33
|
+
}));
|
|
34
|
+
fastify.get(`${prefix}/live`, { schema: {
|
|
35
|
+
tags: ["Health"],
|
|
36
|
+
summary: "Liveness probe",
|
|
37
|
+
description: "Returns 200 if the process is alive",
|
|
38
|
+
response: { 200: {
|
|
39
|
+
type: "object",
|
|
40
|
+
properties: {
|
|
41
|
+
status: {
|
|
42
|
+
type: "string",
|
|
43
|
+
enum: ["ok"]
|
|
44
|
+
},
|
|
45
|
+
timestamp: { type: "string" },
|
|
46
|
+
version: { type: "string" }
|
|
47
|
+
}
|
|
48
|
+
} }
|
|
49
|
+
} }, async () => {
|
|
50
|
+
return {
|
|
51
|
+
status: "ok",
|
|
52
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
53
|
+
...version ? { version } : {}
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
fastify.get(`${prefix}/ready`, { schema: {
|
|
57
|
+
tags: ["Health"],
|
|
58
|
+
summary: "Readiness probe",
|
|
59
|
+
description: "Returns 200 if all dependencies are healthy",
|
|
60
|
+
response: {
|
|
61
|
+
200: {
|
|
62
|
+
type: "object",
|
|
63
|
+
properties: {
|
|
64
|
+
status: {
|
|
65
|
+
type: "string",
|
|
66
|
+
enum: ["ready", "not_ready"]
|
|
67
|
+
},
|
|
68
|
+
timestamp: { type: "string" },
|
|
69
|
+
checks: {
|
|
70
|
+
type: "array",
|
|
71
|
+
items: {
|
|
72
|
+
type: "object",
|
|
73
|
+
properties: {
|
|
74
|
+
name: { type: "string" },
|
|
75
|
+
healthy: { type: "boolean" },
|
|
76
|
+
duration: { type: "number" },
|
|
77
|
+
error: { type: "string" }
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
503: {
|
|
84
|
+
type: "object",
|
|
85
|
+
properties: {
|
|
86
|
+
status: {
|
|
87
|
+
type: "string",
|
|
88
|
+
enum: ["not_ready"]
|
|
89
|
+
},
|
|
90
|
+
timestamp: { type: "string" },
|
|
91
|
+
checks: { type: "array" }
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
} }, async (_, reply) => {
|
|
96
|
+
const results = await runChecks(checks);
|
|
97
|
+
const criticalFailed = results.some((r) => !r.healthy && (checks.find((c) => c.name === r.name)?.critical ?? true));
|
|
98
|
+
const response = {
|
|
99
|
+
status: criticalFailed ? "not_ready" : "ready",
|
|
100
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
101
|
+
checks: results
|
|
102
|
+
};
|
|
103
|
+
if (criticalFailed) reply.code(503);
|
|
104
|
+
return response;
|
|
105
|
+
});
|
|
106
|
+
if (metrics) fastify.get(`${prefix}/metrics`, async (_, reply) => {
|
|
107
|
+
reply.type("text/plain; charset=utf-8");
|
|
108
|
+
if (metricsCollector) return await metricsCollector();
|
|
109
|
+
const uptime = process.uptime();
|
|
110
|
+
const memory = process.memoryUsage();
|
|
111
|
+
const cpu = process.cpuUsage();
|
|
112
|
+
const lines = [
|
|
113
|
+
"# HELP process_uptime_seconds Process uptime in seconds",
|
|
114
|
+
"# TYPE process_uptime_seconds gauge",
|
|
115
|
+
`process_uptime_seconds ${uptime.toFixed(2)}`,
|
|
116
|
+
"",
|
|
117
|
+
"# HELP process_memory_heap_bytes Heap memory usage in bytes",
|
|
118
|
+
"# TYPE process_memory_heap_bytes gauge",
|
|
119
|
+
`process_memory_heap_bytes{type="used"} ${memory.heapUsed}`,
|
|
120
|
+
`process_memory_heap_bytes{type="total"} ${memory.heapTotal}`,
|
|
121
|
+
"",
|
|
122
|
+
"# HELP process_memory_rss_bytes RSS memory in bytes",
|
|
123
|
+
"# TYPE process_memory_rss_bytes gauge",
|
|
124
|
+
`process_memory_rss_bytes ${memory.rss}`,
|
|
125
|
+
"",
|
|
126
|
+
"# HELP process_memory_external_bytes External memory in bytes",
|
|
127
|
+
"# TYPE process_memory_external_bytes gauge",
|
|
128
|
+
`process_memory_external_bytes ${memory.external}`,
|
|
129
|
+
"",
|
|
130
|
+
"# HELP process_cpu_user_microseconds User CPU time in microseconds",
|
|
131
|
+
"# TYPE process_cpu_user_microseconds counter",
|
|
132
|
+
`process_cpu_user_microseconds ${cpu.user}`,
|
|
133
|
+
"",
|
|
134
|
+
"# HELP process_cpu_system_microseconds System CPU time in microseconds",
|
|
135
|
+
"# TYPE process_cpu_system_microseconds counter",
|
|
136
|
+
`process_cpu_system_microseconds ${cpu.system}`,
|
|
137
|
+
""
|
|
138
|
+
];
|
|
139
|
+
if (collectHttpMetrics && Object.keys(httpMetrics.requestsTotal).length > 0) {
|
|
140
|
+
lines.push("# HELP http_requests_total Total HTTP requests by status code", "# TYPE http_requests_total counter");
|
|
141
|
+
for (const [status, count] of Object.entries(httpMetrics.requestsTotal)) lines.push(`http_requests_total{status="${status}"} ${count}`);
|
|
142
|
+
lines.push("");
|
|
143
|
+
if (httpMetrics.requestDurations.length > 0) {
|
|
144
|
+
const sorted = [...httpMetrics.requestDurations].sort((a, b) => a - b);
|
|
145
|
+
const p50 = sorted[Math.floor(sorted.length * .5)] || 0;
|
|
146
|
+
const p95 = sorted[Math.floor(sorted.length * .95)] || 0;
|
|
147
|
+
const p99 = sorted[Math.floor(sorted.length * .99)] || 0;
|
|
148
|
+
const sum = sorted.reduce((a, b) => a + b, 0);
|
|
149
|
+
lines.push("# HELP http_request_duration_milliseconds HTTP request duration", "# TYPE http_request_duration_milliseconds summary", `http_request_duration_milliseconds{quantile="0.5"} ${p50.toFixed(2)}`, `http_request_duration_milliseconds{quantile="0.95"} ${p95.toFixed(2)}`, `http_request_duration_milliseconds{quantile="0.99"} ${p99.toFixed(2)}`, `http_request_duration_milliseconds_sum ${sum.toFixed(2)}`, `http_request_duration_milliseconds_count ${sorted.length}`, "");
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return lines.join("\n");
|
|
153
|
+
});
|
|
154
|
+
if (collectHttpMetrics) fastify.addHook("onResponse", async (_request, reply) => {
|
|
155
|
+
const duration = reply.elapsedTime;
|
|
156
|
+
const statusBucket = `${Math.floor(reply.statusCode / 100)}xx`;
|
|
157
|
+
httpMetrics.requestsTotal[statusBucket] = (httpMetrics.requestsTotal[statusBucket] || 0) + 1;
|
|
158
|
+
if (httpMetrics.requestDurations.length < 1e4) httpMetrics.requestDurations.push(duration);
|
|
159
|
+
else httpMetrics.requestDurations[httpMetrics._ringIndex % 1e4] = duration;
|
|
160
|
+
httpMetrics._ringIndex = httpMetrics._ringIndex + 1;
|
|
161
|
+
});
|
|
162
|
+
fastify.log?.debug?.(`Health plugin registered at ${prefix} (alias), ${prefix}/live, ${prefix}/ready${metrics ? `, ${prefix}/metrics` : ""}`);
|
|
163
|
+
};
|
|
164
|
+
/**
|
|
165
|
+
* Run all health checks with timeout
|
|
166
|
+
*/
|
|
167
|
+
async function runChecks(checks) {
|
|
168
|
+
const results = [];
|
|
169
|
+
for (const check of checks) {
|
|
170
|
+
const start = Date.now();
|
|
171
|
+
const timeout = check.timeout ?? 5e3;
|
|
172
|
+
let timer;
|
|
173
|
+
try {
|
|
174
|
+
const checkPromise = Promise.resolve(check.check());
|
|
175
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
176
|
+
timer = setTimeout(() => reject(/* @__PURE__ */ new Error("Health check timeout")), timeout);
|
|
177
|
+
});
|
|
178
|
+
const healthy = await Promise.race([checkPromise, timeoutPromise]);
|
|
179
|
+
results.push({
|
|
180
|
+
name: check.name,
|
|
181
|
+
healthy: Boolean(healthy),
|
|
182
|
+
duration: Date.now() - start
|
|
183
|
+
});
|
|
184
|
+
} catch (err) {
|
|
185
|
+
results.push({
|
|
186
|
+
name: check.name,
|
|
187
|
+
healthy: false,
|
|
188
|
+
duration: Date.now() - start,
|
|
189
|
+
error: err.message
|
|
190
|
+
});
|
|
191
|
+
} finally {
|
|
192
|
+
if (timer) clearTimeout(timer);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return results;
|
|
196
|
+
}
|
|
197
|
+
var health_default = fp(healthPlugin, {
|
|
198
|
+
name: "arc-health",
|
|
199
|
+
fastify: "5.x"
|
|
200
|
+
});
|
|
201
|
+
//#endregion
|
|
202
|
+
export { health_default as n, healthPlugin as t };
|
package/dist/hooks/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Cn as afterDelete, Dn as beforeUpdate, En as beforeDelete, On as createHookSystem, Sn as afterCreate, Tn as beforeCreate, _n as HookOperation, bn as HookSystem, gn as HookHandler, hn as HookContext, kn as defineHook, mn as DefineHookOptions, vn as HookPhase, wn as afterUpdate, xn as HookSystemOptions, yn as HookRegistration } from "../index-
|
|
1
|
+
import { Cn as afterDelete, Dn as beforeUpdate, En as beforeDelete, On as createHookSystem, Sn as afterCreate, Tn as beforeCreate, _n as HookOperation, bn as HookSystem, gn as HookHandler, hn as HookContext, kn as defineHook, mn as DefineHookOptions, vn as HookPhase, wn as afterUpdate, xn as HookSystemOptions, yn as HookRegistration } from "../index-DbtgCOCj.mjs";
|
|
2
2
|
export { type DefineHookOptions, type HookContext, type HookHandler, type HookOperation, type HookPhase, type HookRegistration, HookSystem, type HookSystemOptions, afterCreate, afterDelete, afterUpdate, beforeCreate, beforeDelete, beforeUpdate, createHookSystem, defineHook };
|
|
@@ -287,12 +287,14 @@ const idempotencyPlugin = async (fastify, opts = {}) => {
|
|
|
287
287
|
});
|
|
288
288
|
fastify.decorateRequest("idempotencyKey", void 0);
|
|
289
289
|
fastify.decorateRequest("idempotencyReplayed", false);
|
|
290
|
+
fastify.decorateRequest("_idempotencyFullKey", void 0);
|
|
290
291
|
fastify.log?.debug?.("Idempotency plugin disabled");
|
|
291
292
|
return;
|
|
292
293
|
}
|
|
293
294
|
const methodSet = new Set(methods.map((m) => m.toUpperCase()));
|
|
294
295
|
fastify.decorateRequest("idempotencyKey", void 0);
|
|
295
296
|
fastify.decorateRequest("idempotencyReplayed", false);
|
|
297
|
+
fastify.decorateRequest("_idempotencyFullKey", void 0);
|
|
296
298
|
/**
|
|
297
299
|
* Check if this request should use idempotency
|
|
298
300
|
*/
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { Ut as Authenticator } from "./index-
|
|
1
|
+
import { Ut as Authenticator } from "./index-DbtgCOCj.mjs";
|
|
2
2
|
import { r as CacheStore } from "./interface-C1_WLTMK.mjs";
|
|
3
3
|
import { n as ElevationOptions } from "./elevation-C9s5hFP_.mjs";
|
|
4
4
|
import { a as EventTransport } from "./EventTransport-QmY7A258.mjs";
|
|
5
5
|
import { t as ExternalOpenApiPaths } from "./externalPaths-BE6wFpYv.mjs";
|
|
6
6
|
import { r as QueryCachePluginOptions } from "./queryCachePlugin-CfYWq-Ak.mjs";
|
|
7
|
-
import { t as ErrorHandlerOptions } from "./errorHandler-
|
|
8
|
-
import { l as ResourceLike, n as ArcModuleInput } from "./module-
|
|
7
|
+
import { t as ErrorHandlerOptions } from "./errorHandler-C6yv4ZTW.mjs";
|
|
8
|
+
import { l as ResourceLike, n as ArcModuleInput } from "./module-B4u10iOJ.mjs";
|
|
9
9
|
import { t as EventPluginOptions } from "./eventPlugin-A6EbthXR.mjs";
|
|
10
|
-
import { _ as HealthOptions, f as CachingOptions, l as SSEOptions, o as MetricsOptions, t as VersioningOptions } from "./versioning-
|
|
10
|
+
import { _ as HealthOptions, f as CachingOptions, l as SSEOptions, o as MetricsOptions, t as VersioningOptions } from "./versioning-DLwklPlG.mjs";
|
|
11
11
|
import { r as IdempotencyStore } from "./interface-Uk8ONJv7.mjs";
|
|
12
12
|
import { FastifyInstance, FastifyPluginAsync, FastifyReply, FastifyRequest, FastifyServerOptions } from "fastify";
|
|
13
13
|
//#region src/testing/preloadResources.d.ts
|
|
@@ -33,30 +33,7 @@ declare function preloadResources(globResult: EagerGlobResult): ResourceLike[];
|
|
|
33
33
|
*/
|
|
34
34
|
declare function preloadResourcesAsync(globResult: LazyGlobResult): Promise<ResourceLike[]>;
|
|
35
35
|
//#endregion
|
|
36
|
-
//#region src/factory/types.d.ts
|
|
37
|
-
type CorsOptions = Record<string, unknown> & {
|
|
38
|
-
origin?: unknown;
|
|
39
|
-
credentials?: boolean;
|
|
40
|
-
methods?: string[];
|
|
41
|
-
allowedHeaders?: string[];
|
|
42
|
-
};
|
|
43
|
-
type HelmetOptions = Record<string, unknown>;
|
|
44
|
-
type RateLimitOpts = Record<string, unknown> & {
|
|
45
|
-
max?: number;
|
|
46
|
-
timeWindow?: string | number;
|
|
47
|
-
/**
|
|
48
|
-
* Path patterns to exempt from rate limiting. Supports exact match
|
|
49
|
-
* (`/health`) or prefix match with trailing `*` (`/api/auth/*`).
|
|
50
|
-
*
|
|
51
|
-
* Implemented by synthesising a `@fastify/rate-limit` `allowList`
|
|
52
|
-
* function. When combined with a user-supplied `allowList`, both
|
|
53
|
-
* are OR-ed together (path OR ip/custom match skips the limit).
|
|
54
|
-
*
|
|
55
|
-
* Use this for endpoints that are hit frequently but independently
|
|
56
|
-
* of user traffic — session heartbeat, webhooks, health probes.
|
|
57
|
-
*/
|
|
58
|
-
skipPaths?: string[];
|
|
59
|
-
};
|
|
36
|
+
//#region src/factory/types/auth.d.ts
|
|
60
37
|
/**
|
|
61
38
|
* Arc's built-in JWT auth
|
|
62
39
|
*
|
|
@@ -161,13 +138,29 @@ interface JwtAuthOption {
|
|
|
161
138
|
* });
|
|
162
139
|
* ```
|
|
163
140
|
*/
|
|
141
|
+
/** The shape `createBetterAuthAdapter()` returns. */
|
|
142
|
+
interface BetterAuthAdapterResult {
|
|
143
|
+
plugin: FastifyPluginAsync;
|
|
144
|
+
openapi?: ExternalOpenApiPaths;
|
|
145
|
+
}
|
|
164
146
|
interface BetterAuthOption {
|
|
165
147
|
type: "betterAuth";
|
|
166
|
-
/**
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
148
|
+
/**
|
|
149
|
+
* Better Auth adapter — the result of `createBetterAuthAdapter()`, or a
|
|
150
|
+
* sync/async THUNK returning it (2.22). The thunk resolves during auth
|
|
151
|
+
* registration — AFTER `beforeBoot` — for adapters whose construction
|
|
152
|
+
* needs a live DB (Better Auth's `mongodbAdapter(mongoose.connection
|
|
153
|
+
* .getClient().db())` requires an OPEN connection, so an eager value
|
|
154
|
+
* forces hosts back into connect-before-createApp ordering dances):
|
|
155
|
+
*
|
|
156
|
+
* ```typescript
|
|
157
|
+
* createApp({
|
|
158
|
+
* beforeBoot: () => connectDatabase(),
|
|
159
|
+
* auth: { type: 'betterAuth', betterAuth: () => createBetterAuthAdapter({ auth: getAuth() }) },
|
|
160
|
+
* });
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
betterAuth: BetterAuthAdapterResult | (() => BetterAuthAdapterResult | Promise<BetterAuthAdapterResult>);
|
|
171
164
|
}
|
|
172
165
|
/**
|
|
173
166
|
* Custom auth plugin — full control over authentication setup
|
|
@@ -234,6 +227,112 @@ interface CustomAuthenticatorOption {
|
|
|
234
227
|
* - `CustomAuthenticatorOption` — A bare authenticate function (`type: 'authenticator'`)
|
|
235
228
|
*/
|
|
236
229
|
type AuthOption = false | JwtAuthOption | BetterAuthOption | CustomPluginAuthOption | CustomAuthenticatorOption;
|
|
230
|
+
//#endregion
|
|
231
|
+
//#region src/factory/types/plugin-options.d.ts
|
|
232
|
+
/**
|
|
233
|
+
* Plugin-specific option shapes for `createApp()` — under-pressure,
|
|
234
|
+
* multipart, and raw-body plugin configuration.
|
|
235
|
+
*/
|
|
236
|
+
interface UnderPressureOptions {
|
|
237
|
+
/** Expose `/_status` route for health checks (default: false) */
|
|
238
|
+
exposeStatusRoute?: boolean;
|
|
239
|
+
/** Event loop lag threshold in ms — requests rejected above this (default: 1000) */
|
|
240
|
+
maxEventLoopDelay?: number;
|
|
241
|
+
/** V8 heap usage threshold in bytes — requests rejected above this */
|
|
242
|
+
maxHeapUsedBytes?: number;
|
|
243
|
+
/** RSS memory threshold in bytes — requests rejected above this */
|
|
244
|
+
maxRssBytes?: number;
|
|
245
|
+
}
|
|
246
|
+
interface MultipartOptions {
|
|
247
|
+
limits?: {
|
|
248
|
+
/** Max file size in bytes (default: Fastify default ~1MB) */
|
|
249
|
+
fileSize?: number;
|
|
250
|
+
/** Max number of files per request */
|
|
251
|
+
files?: number;
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
interface RawBodyOptions {
|
|
255
|
+
/** Body field name to store raw body on (default: 'rawBody') */
|
|
256
|
+
field?: string;
|
|
257
|
+
/** Apply to all routes globally (default: false) */
|
|
258
|
+
global?: boolean;
|
|
259
|
+
/** Encoding for raw body string (default: 'utf8') */
|
|
260
|
+
encoding?: string;
|
|
261
|
+
/** Parse raw body before other parsers (default: false) */
|
|
262
|
+
runFirst?: boolean;
|
|
263
|
+
}
|
|
264
|
+
//#endregion
|
|
265
|
+
//#region src/factory/types/security.d.ts
|
|
266
|
+
/**
|
|
267
|
+
* Security-plugin option shapes — CORS / Helmet / rate-limit config for
|
|
268
|
+
* `createApp()`, including plan-aware rate limiting (2.22).
|
|
269
|
+
*/
|
|
270
|
+
type CorsOptions = Record<string, unknown> & {
|
|
271
|
+
origin?: unknown;
|
|
272
|
+
credentials?: boolean;
|
|
273
|
+
methods?: string[];
|
|
274
|
+
allowedHeaders?: string[];
|
|
275
|
+
};
|
|
276
|
+
type HelmetOptions = Record<string, unknown>;
|
|
277
|
+
type RateLimitOpts = Record<string, unknown> & {
|
|
278
|
+
max?: number;
|
|
279
|
+
timeWindow?: string | number;
|
|
280
|
+
/**
|
|
281
|
+
* Path patterns to exempt from rate limiting. Supports exact match
|
|
282
|
+
* (`/health`) or prefix match with trailing `*` (`/api/auth/*`).
|
|
283
|
+
*
|
|
284
|
+
* Implemented by synthesising a `@fastify/rate-limit` `allowList`
|
|
285
|
+
* function. When combined with a user-supplied `allowList`, both
|
|
286
|
+
* are OR-ed together (path OR ip/custom match skips the limit).
|
|
287
|
+
*
|
|
288
|
+
* Use this for endpoints that are hit frequently but independently
|
|
289
|
+
* of user traffic — session heartbeat, webhooks, health probes.
|
|
290
|
+
*/
|
|
291
|
+
skipPaths?: string[];
|
|
292
|
+
/**
|
|
293
|
+
* Plan-aware limits (2.22) — resolve the caller's plan per request and
|
|
294
|
+
* apply that plan's ceiling instead of the global `max`:
|
|
295
|
+
*
|
|
296
|
+
* ```typescript
|
|
297
|
+
* rateLimit: {
|
|
298
|
+
* timeWindow: '1 minute',
|
|
299
|
+
* plan: {
|
|
300
|
+
* resolve: (req) => lookupPlan(req), // 'free' | 'pro' | ...
|
|
301
|
+
* limits: { free: { max: 60 }, pro: { max: 1000 }, enterprise: false },
|
|
302
|
+
* default: 'free',
|
|
303
|
+
* },
|
|
304
|
+
* }
|
|
305
|
+
* ```
|
|
306
|
+
*
|
|
307
|
+
* `false` = effectively unlimited. When `plan` is set and no
|
|
308
|
+
* `keyGenerator` is supplied, arc defaults to the tenant key chain
|
|
309
|
+
* (org → user → client → IP) so buckets follow actors, not addresses.
|
|
310
|
+
*
|
|
311
|
+
* Timing caveat: the limiter runs before route-level auth, so
|
|
312
|
+
* `req.scope` may be unresolved for token-authenticated calls —
|
|
313
|
+
* `resolve` receives the RAW request and may need to derive the plan
|
|
314
|
+
* from its own header/token/session lookup. Same caveat as
|
|
315
|
+
* `createTenantKeyGenerator`'s IP fallback (documented there).
|
|
316
|
+
*/
|
|
317
|
+
plan?: RateLimitPlanConfig;
|
|
318
|
+
};
|
|
319
|
+
/** Plan-aware rate limiting (2.22) — see `rateLimit.plan` on CreateAppOptions. */
|
|
320
|
+
interface RateLimitPlanConfig {
|
|
321
|
+
/**
|
|
322
|
+
* Name the caller's plan from the raw request. Return `undefined` to
|
|
323
|
+
* fall back to `default`. Sync or async; a throwing resolver also
|
|
324
|
+
* falls back (limits must fail-safe, not fail-open to unlimited).
|
|
325
|
+
*/
|
|
326
|
+
resolve: (req: import("fastify").FastifyRequest) => string | undefined | Promise<string | undefined>;
|
|
327
|
+
/** Per-plan ceilings within the shared `timeWindow`. `false` = effectively unlimited. */
|
|
328
|
+
limits: Record<string, {
|
|
329
|
+
max: number;
|
|
330
|
+
} | false>;
|
|
331
|
+
/** Plan used when `resolve` returns undefined/unknown or throws. Default: fall back to the global `max`. */
|
|
332
|
+
default?: string;
|
|
333
|
+
}
|
|
334
|
+
//#endregion
|
|
335
|
+
//#region src/factory/types/app-options.d.ts
|
|
237
336
|
/**
|
|
238
337
|
* CreateApp Options
|
|
239
338
|
*
|
|
@@ -276,8 +375,18 @@ type AuthOption = false | JwtAuthOption | BetterAuthOption | CustomPluginAuthOpt
|
|
|
276
375
|
* ```
|
|
277
376
|
*/
|
|
278
377
|
interface CreateAppOptions {
|
|
279
|
-
/** Environment preset: 'production', 'development', 'testing', or '
|
|
280
|
-
preset?: "production" | "development" | "testing" | "edge";
|
|
378
|
+
/** Environment preset: 'production', 'development', 'testing', 'edge', or 'worker' */
|
|
379
|
+
preset?: "production" | "development" | "testing" | "edge" | "worker";
|
|
380
|
+
/**
|
|
381
|
+
* Route-mounting switch (2.23) — the worker-role primitive. `false`
|
|
382
|
+
* registers every resource's shared runtime state (registry metadata +
|
|
383
|
+
* adapter, hooks, cache-invalidation rules) WITHOUT mounting any routes,
|
|
384
|
+
* so headless processes keep tenant-purge cascade, per-resource audit,
|
|
385
|
+
* and events metadata intact. Set by `preset: 'worker'` /
|
|
386
|
+
* `createWorker()`; hosts composing a custom worker shape may set it
|
|
387
|
+
* directly. Default: true (routes mount).
|
|
388
|
+
*/
|
|
389
|
+
mountRoutes?: boolean;
|
|
281
390
|
/**
|
|
282
391
|
* Runtime profile for store backends.
|
|
283
392
|
* - 'memory' (default): Uses in-memory stores. Suitable for single-instance deployments.
|
|
@@ -324,10 +433,50 @@ interface CreateAppOptions {
|
|
|
324
433
|
* ```
|
|
325
434
|
*/
|
|
326
435
|
debug?: boolean | string;
|
|
327
|
-
/**
|
|
328
|
-
|
|
436
|
+
/**
|
|
437
|
+
* Trust proxy headers (X-Forwarded-For, etc.). Pass-through to Fastify's
|
|
438
|
+
* `trustProxy` server option — all its forms are supported, not just the
|
|
439
|
+
* boolean:
|
|
440
|
+
*
|
|
441
|
+
* - `true` — trust ALL proxies (only safe when the app is never directly
|
|
442
|
+
* reachable; a spoofed `X-Forwarded-For` otherwise forges `request.ip`,
|
|
443
|
+
* which feeds rate-limit keys and audit logs)
|
|
444
|
+
* - `1` — trust exactly one hop (typical single LB / reverse proxy)
|
|
445
|
+
* - `'10.0.0.0/8'` / `['10.0.0.0/8', '172.16.0.0/12']` — trust only these
|
|
446
|
+
* CIDR ranges
|
|
447
|
+
*
|
|
448
|
+
* @example
|
|
449
|
+
* ```ts
|
|
450
|
+
* createApp({ preset: 'production', trustProxy: 1 }); // one LB hop
|
|
451
|
+
* createApp({ preset: 'production', trustProxy: '10.0.0.0/8' }); // VPC proxies
|
|
452
|
+
* ```
|
|
453
|
+
*/
|
|
454
|
+
trustProxy?: boolean | string | string[] | number;
|
|
329
455
|
/** Fastify plugin/onReady timeout in ms (default: 10_000). Raise for slow boot work (index materialisation, WAL replay, external warm-up). */
|
|
330
456
|
pluginTimeout?: number;
|
|
457
|
+
/**
|
|
458
|
+
* Max time in ms the server waits to RECEIVE an entire request
|
|
459
|
+
* (headers + body). Pass-through to Fastify's `requestTimeout` (Node's
|
|
460
|
+
* `server.requestTimeout`). Default `0` defers to Node's own 300s bound
|
|
461
|
+
* — slow-loris requests are already cut off there, so arc doesn't
|
|
462
|
+
* override; tighten (e.g. `30_000`) for APIs that never accept slow
|
|
463
|
+
* uploads. Response duration (SSE, streaming) is NOT affected.
|
|
464
|
+
*/
|
|
465
|
+
requestTimeout?: number;
|
|
466
|
+
/**
|
|
467
|
+
* Max time in ms to establish a connection before the socket is
|
|
468
|
+
* destroyed. Pass-through to Fastify's `connectionTimeout` (Node's
|
|
469
|
+
* `server.timeout`). Default `0` = no limit (Node's `headersTimeout`
|
|
470
|
+
* ~60s still bounds idle pre-request sockets).
|
|
471
|
+
*/
|
|
472
|
+
connectionTimeout?: number;
|
|
473
|
+
/**
|
|
474
|
+
* Keep-alive idle timeout in ms (Node's `server.keepAliveTimeout`,
|
|
475
|
+
* default 72_000). MUST be longer than the idle timeout of any load
|
|
476
|
+
* balancer in front of the app (ALB default 60s) or the LB reuses
|
|
477
|
+
* sockets the server just closed → intermittent 502s.
|
|
478
|
+
*/
|
|
479
|
+
keepAliveTimeout?: number;
|
|
331
480
|
/**
|
|
332
481
|
* Maximum JSON body size in bytes. Pass-through to Fastify's
|
|
333
482
|
* server-level `bodyLimit` option; default is Fastify's 1 MiB
|
|
@@ -933,33 +1082,5 @@ interface CreateAppOptions {
|
|
|
933
1082
|
/** Hook called when the app is shutting down */
|
|
934
1083
|
onClose?: (fastify: FastifyInstance) => void | Promise<void>;
|
|
935
1084
|
}
|
|
936
|
-
interface UnderPressureOptions {
|
|
937
|
-
/** Expose `/_status` route for health checks (default: false) */
|
|
938
|
-
exposeStatusRoute?: boolean;
|
|
939
|
-
/** Event loop lag threshold in ms — requests rejected above this (default: 1000) */
|
|
940
|
-
maxEventLoopDelay?: number;
|
|
941
|
-
/** V8 heap usage threshold in bytes — requests rejected above this */
|
|
942
|
-
maxHeapUsedBytes?: number;
|
|
943
|
-
/** RSS memory threshold in bytes — requests rejected above this */
|
|
944
|
-
maxRssBytes?: number;
|
|
945
|
-
}
|
|
946
|
-
interface MultipartOptions {
|
|
947
|
-
limits?: {
|
|
948
|
-
/** Max file size in bytes (default: Fastify default ~1MB) */
|
|
949
|
-
fileSize?: number;
|
|
950
|
-
/** Max number of files per request */
|
|
951
|
-
files?: number;
|
|
952
|
-
};
|
|
953
|
-
}
|
|
954
|
-
interface RawBodyOptions {
|
|
955
|
-
/** Body field name to store raw body on (default: 'rawBody') */
|
|
956
|
-
field?: string;
|
|
957
|
-
/** Apply to all routes globally (default: false) */
|
|
958
|
-
global?: boolean;
|
|
959
|
-
/** Encoding for raw body string (default: 'utf8') */
|
|
960
|
-
encoding?: string;
|
|
961
|
-
/** Parse raw body before other parsers (default: false) */
|
|
962
|
-
runFirst?: boolean;
|
|
963
|
-
}
|
|
964
1085
|
//#endregion
|
|
965
|
-
export {
|
|
1086
|
+
export { AuthOption as a, CustomPluginAuthOption as c, preloadResourcesAsync as d, UnderPressureOptions as i, JwtAuthOption as l, MultipartOptions as n, BetterAuthOption as o, RawBodyOptions as r, CustomAuthenticatorOption as s, CreateAppOptions as t, preloadResources as u };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { C as RequestContext, Et as
|
|
1
|
+
import { C as RequestContext, Et as ActionDefinition, F as FastifyWithDecorators, H as CrudController, L as RequestWithExtras, Lt as IController, Rt as IControllerResponse, T as CrudRouterOptions, U as ResourceConfig, V as ResourceDefinition, et as RouteSchemaOptions, jt as RouteMcpConfig, qt as AnyRecord, tt as ArcFieldRule, ut as AggregationConfig, zt as IRequestContext } from "./index-DbtgCOCj.mjs";
|
|
2
2
|
import { i as RequestScope } from "./types-DH0GupI7.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import "./fastify-augmentation-
|
|
3
|
+
import { t as PermissionCheck } from "./types-Csxga7d3.mjs";
|
|
4
|
+
import "./fastify-augmentation-9_fuetB4.mjs";
|
|
5
5
|
import { FastifyReply, FastifyRequest, RouteHandlerMethod } from "fastify";
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
import { DataAdapter } from "@classytic/repo-core/adapter";
|