@classytic/arc 2.20.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-D-MHZ27_.mjs → BaseController-C6FlRWxF.mjs} +2 -2
- package/dist/{EventTransport-IEn7Tn-Q.d.mts → EventTransport-QmY7A258.d.mts} +0 -1
- package/dist/{QueryCache-TRfXau3W.d.mts → QueryCache-Z1B38koh.d.mts} +0 -1
- package/dist/{actionPermissions-C9RMiIpc.mjs → actionPermissions-ze70xXJi.mjs} +1 -1
- package/dist/audit/index.d.mts +9 -5
- package/dist/auth/audit.d.mts +7 -4
- package/dist/auth/audit.mjs +5 -0
- package/dist/auth/index.d.mts +35 -14
- package/dist/auth/index.mjs +6 -3
- package/dist/auth/redis-session.d.mts +1 -2
- package/dist/cache/index.d.mts +2 -3
- package/dist/cli/commands/describe.d.mts +1 -2
- 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/context/index.d.mts +2 -2
- package/dist/core/index.d.mts +3 -3
- package/dist/core/index.mjs +4 -4
- package/dist/{core-CWhyGkiM.mjs → core-b6fgFgnd.mjs} +129 -17
- package/dist/{createActionRouter-HlQso0jO.mjs → createActionRouter-h1cEEaEX.mjs} +10 -6
- package/dist/{createAggregationRouter-5LzPzgw1.mjs → createAggregationRouter-B1C0kvTL.mjs} +3 -3
- package/dist/{createApp-D6uwzCKu.mjs → createApp-Ci7yG5gv.mjs} +390 -192
- package/dist/discovery/index.d.mts +0 -1
- package/dist/docs/index.d.mts +1 -2
- package/dist/docs/index.mjs +1 -1
- package/dist/{elevation-xGUBq6p_.d.mts → elevation-C9s5hFP_.d.mts} +0 -1
- package/dist/encryption/index.d.mts +2 -144
- package/dist/encryption/index.mjs +9 -5
- package/dist/{errorHandler-Dxf6P_kV.mjs → errorHandler-BTzXSwIg.mjs} +24 -3
- package/dist/{errorHandler-BtUUDPEa.d.mts → errorHandler-C6yv4ZTW.d.mts} +13 -1
- package/dist/{errors-DOHkjQlD.d.mts → errors-DHcHVAgk.d.mts} +0 -1
- package/dist/{eventPlugin-DbBFd3x_.d.mts → eventPlugin-A6EbthXR.d.mts} +10 -6
- package/dist/events/index.d.mts +9 -6
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis.d.mts +1 -2
- package/dist/factory/index.d.mts +30 -9
- package/dist/factory/index.mjs +35 -4
- package/dist/{fastify-augmentation-CCQJEDgh.d.mts → fastify-augmentation-9_fuetB4.d.mts} +2 -3
- 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.d.mts +4 -3
- package/dist/idempotency/index.mjs +2 -0
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/{types-BHMKlMBU.d.mts → index-BEu4wjbL.d.mts} +241 -80
- package/dist/{index-DUa8WHz3.d.mts → index-D8MKYGDa.d.mts} +88 -7
- package/dist/{index-_--GyzcO.d.mts → index-DbtgCOCj.d.mts} +1324 -1228
- package/dist/{index-CdFkIMEd.d.mts → index-ogIHvOjo.d.mts} +36 -7
- package/dist/index.d.mts +8 -7
- package/dist/index.mjs +6 -6
- package/dist/{init-YH_nslQR.mjs → init-DleK3p9f.mjs} +272 -139
- package/dist/integrations/event-gateway.d.mts +2 -3
- package/dist/integrations/index.d.mts +2 -2
- package/dist/integrations/jobs.d.mts +0 -1
- package/dist/integrations/mcp/index.d.mts +6 -7
- package/dist/integrations/mcp/index.mjs +1 -1
- package/dist/integrations/mcp/testing.d.mts +1 -2
- package/dist/integrations/mcp/testing.mjs +1 -1
- package/dist/integrations/streamline.d.mts +2 -2
- package/dist/integrations/webhooks.d.mts +8 -5
- package/dist/integrations/webhooks.mjs +9 -5
- package/dist/integrations/websocket-pushref-redis.d.mts +1 -2
- package/dist/integrations/websocket-redis.d.mts +1 -2
- package/dist/integrations/websocket.d.mts +2 -2
- package/dist/jsonBody-BlzAoGCe.mjs +43 -0
- package/dist/{loadResources-B8UmpITt.mjs → loadResources-DpU8pfjV.mjs} +4 -3
- package/dist/logger/index.d.mts +26 -1
- package/dist/logger/index.mjs +39 -1
- package/dist/{mcpPlugin-CuW6L_uD.mjs → mcpPlugin-ByA2tf6D.mjs} +8 -4
- package/dist/middleware/index.d.mts +1 -2
- package/dist/{module-JYH9V0I8.d.mts → module-B4u10iOJ.d.mts} +71 -1
- package/dist/{openapi-Dq6RbEGK.mjs → openapi-BRpMZD7C.mjs} +3 -3
- package/dist/permissions/index.d.mts +4 -3
- package/dist/permissions/index.mjs +2 -2
- package/dist/{permissions-CgbOLJZG.mjs → permissions-BJMuKMl7.mjs} +33 -1
- package/dist/pipeline/index.d.mts +1 -2
- package/dist/plugins/index.d.mts +96 -7
- package/dist/plugins/index.mjs +86 -268
- package/dist/plugins/response-cache.d.mts +5 -3
- package/dist/plugins/response-cache.mjs +1 -0
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +7 -4
- package/dist/presets/filesUpload.d.mts +4 -5
- package/dist/presets/filesUpload.mjs +1 -1
- package/dist/presets/index.d.mts +1 -2
- package/dist/presets/index.mjs +1 -1
- package/dist/presets/multiTenant.d.mts +1 -2
- package/dist/presets/search.d.mts +2 -3
- package/dist/presets/search.mjs +1 -1
- package/dist/{presets-DWsYQdbV.mjs → presets-gw0ciIUD.mjs} +1 -1
- package/dist/{pushref-registry-DnCqL3aa.d.mts → pushref-registry-BbcnpNTm.d.mts} +4 -2
- package/dist/{queryCachePlugin-xzFyKAjT.d.mts → queryCachePlugin-CfYWq-Ak.d.mts} +1 -2
- package/dist/rateLimitKey-BoWRH3e7.mjs +14 -0
- package/dist/{redis-C3W0qbz8.d.mts → redis-UDtLaNj6.d.mts} +0 -1
- package/dist/{redis-stream-DsP1vqZB.d.mts → redis-stream-iVR2l7aS.d.mts} +1 -2
- package/dist/{registerRoute-DGSREwPw.mjs → registerRoute-xHc42fwB.mjs} +38 -18
- 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/schemas/index.d.mts +0 -1
- package/dist/scim/index.d.mts +0 -1
- package/dist/scim/index.mjs +6 -7
- package/dist/scope/index.d.mts +2 -3
- package/dist/scope/index.mjs +2 -76
- package/dist/scope-k15RXfcq.mjs +64 -0
- package/dist/{sessionManager-BXG-HGwG.d.mts → sessionManager-BHOM3N_0.d.mts} +10 -6
- package/dist/{storage-Co_PQpeQ.d.mts → storage-DLUZ04kK.d.mts} +8 -4
- package/dist/testing/index.d.mts +83 -4
- package/dist/testing/index.mjs +74 -4
- package/dist/testing/storageContract.d.mts +1 -2
- package/dist/{tracing-D8jlGXP7.d.mts → tracing-CsGKQJGg.d.mts} +0 -1
- package/dist/types/index.d.mts +4 -4
- package/dist/types/storage.d.mts +1 -1
- package/dist/{types-C9b2HR5W.d.mts → types-Bc42CUyk.d.mts} +1 -2
- package/dist/types-Cc91nXuA.d.mts +132 -0
- package/dist/{fields-C7ahdGYf.d.mts → types-Csxga7d3.d.mts} +2 -123
- package/dist/{types-LNebCoJx.d.mts → types-DH0GupI7.d.mts} +8 -4
- package/dist/usage/index.d.mts +142 -0
- package/dist/usage/index.mjs +0 -0
- package/dist/utils/index.d.mts +220 -144
- package/dist/utils/index.mjs +3 -3
- package/dist/{utils-ChjYQpjn.mjs → utils-FhJ88TJE.mjs} +129 -39
- package/dist/{versioning-D_eBCfNr.d.mts → versioning-DLwklPlG.d.mts} +1 -7
- package/dist/{websocket-MlYlrYq0.d.mts → websocket-uuWqM6UY.d.mts} +5 -4
- 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 +243 -0
- package/skills/arc-module-publishing/references/authoring-modules.md +327 -0
- package/skills/arc-module-publishing/references/package-manifest.md +157 -0
- package/skills/arc-module-publishing/references/publishing-workflow.md +182 -0
- package/dist/preloadResources-CHw3_oA_.mjs +0 -45
- package/dist/schemaConverter-U0MnO9vd.mjs +0 -110
|
@@ -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 };
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { i as createIdempotencyResult, n as IdempotencyResult, r as IdempotencyStore, t as IdempotencyLock } from "../interface-Uk8ONJv7.mjs";
|
|
2
|
-
import { i as RedisIdempotencyStoreOptions, n as RedisClient } from "../redis-
|
|
2
|
+
import { i as RedisIdempotencyStoreOptions, n as RedisClient } from "../redis-UDtLaNj6.mjs";
|
|
3
3
|
import { FastifyPluginAsync } from "fastify";
|
|
4
4
|
import { RepositoryLike } from "@classytic/repo-core/adapter";
|
|
5
|
-
|
|
6
5
|
//#region src/idempotency/idempotencyPlugin.d.ts
|
|
7
6
|
interface IdempotencyPluginOptions {
|
|
8
7
|
/** Enable idempotency (default: false) */
|
|
@@ -60,7 +59,9 @@ declare module "fastify" {
|
|
|
60
59
|
interface FastifyInstance {
|
|
61
60
|
/** Idempotency utilities */
|
|
62
61
|
idempotency: {
|
|
63
|
-
/** Manually invalidate an idempotency key */
|
|
62
|
+
/** Manually invalidate an idempotency key */
|
|
63
|
+
invalidate: (key: string) => Promise<void>;
|
|
64
|
+
/** Check if a key has a cached response */
|
|
64
65
|
has: (key: string) => Promise<boolean>;
|
|
65
66
|
/**
|
|
66
67
|
* Route-level preHandler for idempotency check + lock.
|
|
@@ -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,2 +1,2 @@
|
|
|
1
|
-
import { a as UpstashRedisLike, i as RedisIdempotencyStoreOptions, n as RedisClient, o as ioredisAsIdempotencyClient, r as RedisIdempotencyStore, s as upstashAsIdempotencyClient, t as IoredisLike } from "../redis-
|
|
1
|
+
import { a as UpstashRedisLike, i as RedisIdempotencyStoreOptions, n as RedisClient, o as ioredisAsIdempotencyClient, r as RedisIdempotencyStore, s as upstashAsIdempotencyClient, t as IoredisLike } from "../redis-UDtLaNj6.mjs";
|
|
2
2
|
export { type IoredisLike, type RedisClient, RedisIdempotencyStore, type RedisIdempotencyStoreOptions, type UpstashRedisLike, ioredisAsIdempotencyClient, upstashAsIdempotencyClient };
|
|
@@ -1,16 +1,15 @@
|
|
|
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
|
-
import { n as ElevationOptions } from "./elevation-
|
|
4
|
-
import { a as EventTransport } from "./EventTransport-
|
|
3
|
+
import { n as ElevationOptions } from "./elevation-C9s5hFP_.mjs";
|
|
4
|
+
import { a as EventTransport } from "./EventTransport-QmY7A258.mjs";
|
|
5
5
|
import { t as ExternalOpenApiPaths } from "./externalPaths-BE6wFpYv.mjs";
|
|
6
|
-
import { r as QueryCachePluginOptions } from "./queryCachePlugin-
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { t as
|
|
6
|
+
import { r as QueryCachePluginOptions } from "./queryCachePlugin-CfYWq-Ak.mjs";
|
|
7
|
+
import { t as ErrorHandlerOptions } from "./errorHandler-C6yv4ZTW.mjs";
|
|
8
|
+
import { l as ResourceLike, n as ArcModuleInput } from "./module-B4u10iOJ.mjs";
|
|
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-DLwklPlG.mjs";
|
|
11
11
|
import { r as IdempotencyStore } from "./interface-Uk8ONJv7.mjs";
|
|
12
12
|
import { FastifyInstance, FastifyPluginAsync, FastifyReply, FastifyRequest, FastifyServerOptions } from "fastify";
|
|
13
|
-
|
|
14
13
|
//#region src/testing/preloadResources.d.ts
|
|
15
14
|
/** Eager glob result: `{ '/path/to/file.ts': resourceModule }` */
|
|
16
15
|
type EagerGlobResult = Record<string, unknown>;
|
|
@@ -34,30 +33,7 @@ declare function preloadResources(globResult: EagerGlobResult): ResourceLike[];
|
|
|
34
33
|
*/
|
|
35
34
|
declare function preloadResourcesAsync(globResult: LazyGlobResult): Promise<ResourceLike[]>;
|
|
36
35
|
//#endregion
|
|
37
|
-
//#region src/factory/types.d.ts
|
|
38
|
-
type CorsOptions = Record<string, unknown> & {
|
|
39
|
-
origin?: unknown;
|
|
40
|
-
credentials?: boolean;
|
|
41
|
-
methods?: string[];
|
|
42
|
-
allowedHeaders?: string[];
|
|
43
|
-
};
|
|
44
|
-
type HelmetOptions = Record<string, unknown>;
|
|
45
|
-
type RateLimitOpts = Record<string, unknown> & {
|
|
46
|
-
max?: number;
|
|
47
|
-
timeWindow?: string | number;
|
|
48
|
-
/**
|
|
49
|
-
* Path patterns to exempt from rate limiting. Supports exact match
|
|
50
|
-
* (`/health`) or prefix match with trailing `*` (`/api/auth/*`).
|
|
51
|
-
*
|
|
52
|
-
* Implemented by synthesising a `@fastify/rate-limit` `allowList`
|
|
53
|
-
* function. When combined with a user-supplied `allowList`, both
|
|
54
|
-
* are OR-ed together (path OR ip/custom match skips the limit).
|
|
55
|
-
*
|
|
56
|
-
* Use this for endpoints that are hit frequently but independently
|
|
57
|
-
* of user traffic — session heartbeat, webhooks, health probes.
|
|
58
|
-
*/
|
|
59
|
-
skipPaths?: string[];
|
|
60
|
-
};
|
|
36
|
+
//#region src/factory/types/auth.d.ts
|
|
61
37
|
/**
|
|
62
38
|
* Arc's built-in JWT auth
|
|
63
39
|
*
|
|
@@ -95,11 +71,17 @@ interface JwtAuthOption {
|
|
|
95
71
|
* If provided, jwt utilities are available in authenticator context
|
|
96
72
|
*/
|
|
97
73
|
jwt?: {
|
|
98
|
-
/** JWT secret (required for JWT features) */
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
74
|
+
/** JWT secret (required for JWT features) */
|
|
75
|
+
secret: string;
|
|
76
|
+
/** Access token expiry (default: '15m') */
|
|
77
|
+
expiresIn?: string;
|
|
78
|
+
/** Refresh token secret (defaults to main secret) */
|
|
79
|
+
refreshSecret?: string;
|
|
80
|
+
/** Refresh token expiry (default: '7d') */
|
|
81
|
+
refreshExpiresIn?: string;
|
|
82
|
+
/** Additional @fastify/jwt sign options */
|
|
83
|
+
sign?: Record<string, unknown>;
|
|
84
|
+
/** Additional @fastify/jwt verify options */
|
|
103
85
|
verify?: Record<string, unknown>;
|
|
104
86
|
};
|
|
105
87
|
/**
|
|
@@ -156,13 +138,29 @@ interface JwtAuthOption {
|
|
|
156
138
|
* });
|
|
157
139
|
* ```
|
|
158
140
|
*/
|
|
141
|
+
/** The shape `createBetterAuthAdapter()` returns. */
|
|
142
|
+
interface BetterAuthAdapterResult {
|
|
143
|
+
plugin: FastifyPluginAsync;
|
|
144
|
+
openapi?: ExternalOpenApiPaths;
|
|
145
|
+
}
|
|
159
146
|
interface BetterAuthOption {
|
|
160
147
|
type: "betterAuth";
|
|
161
|
-
/**
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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>);
|
|
166
164
|
}
|
|
167
165
|
/**
|
|
168
166
|
* Custom auth plugin — full control over authentication setup
|
|
@@ -229,6 +227,112 @@ interface CustomAuthenticatorOption {
|
|
|
229
227
|
* - `CustomAuthenticatorOption` — A bare authenticate function (`type: 'authenticator'`)
|
|
230
228
|
*/
|
|
231
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
|
|
232
336
|
/**
|
|
233
337
|
* CreateApp Options
|
|
234
338
|
*
|
|
@@ -271,8 +375,18 @@ type AuthOption = false | JwtAuthOption | BetterAuthOption | CustomPluginAuthOpt
|
|
|
271
375
|
* ```
|
|
272
376
|
*/
|
|
273
377
|
interface CreateAppOptions {
|
|
274
|
-
/** Environment preset: 'production', 'development', 'testing', or '
|
|
275
|
-
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;
|
|
276
390
|
/**
|
|
277
391
|
* Runtime profile for store backends.
|
|
278
392
|
* - 'memory' (default): Uses in-memory stores. Suitable for single-instance deployments.
|
|
@@ -289,9 +403,13 @@ interface CreateAppOptions {
|
|
|
289
403
|
* not memory-backed. Provide Redis or other durable adapters.
|
|
290
404
|
*/
|
|
291
405
|
stores?: {
|
|
292
|
-
/** Event transport (e.g., RedisEventTransport) */
|
|
293
|
-
|
|
294
|
-
|
|
406
|
+
/** Event transport (e.g., RedisEventTransport) */
|
|
407
|
+
events?: EventTransport;
|
|
408
|
+
/** Cache store (e.g., RedisCacheStore) */
|
|
409
|
+
cache?: CacheStore;
|
|
410
|
+
/** Idempotency store (e.g., RedisIdempotencyStore) */
|
|
411
|
+
idempotency?: IdempotencyStore;
|
|
412
|
+
/** QueryCache store (e.g., RedisCacheStore). Default: MemoryCacheStore. */
|
|
295
413
|
queryCache?: CacheStore;
|
|
296
414
|
};
|
|
297
415
|
/** Fastify logger configuration */
|
|
@@ -315,10 +433,50 @@ interface CreateAppOptions {
|
|
|
315
433
|
* ```
|
|
316
434
|
*/
|
|
317
435
|
debug?: boolean | string;
|
|
318
|
-
/**
|
|
319
|
-
|
|
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;
|
|
320
455
|
/** Fastify plugin/onReady timeout in ms (default: 10_000). Raise for slow boot work (index materialisation, WAL replay, external warm-up). */
|
|
321
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;
|
|
322
480
|
/**
|
|
323
481
|
* Maximum JSON body size in bytes. Pass-through to Fastify's
|
|
324
482
|
* server-level `bodyLimit` option; default is Fastify's 1 MiB
|
|
@@ -442,7 +600,8 @@ interface CreateAppOptions {
|
|
|
442
600
|
rawBody?: RawBodyOptions | false;
|
|
443
601
|
/** Enable Arc plugins (requestId, health, gracefulShutdown, events, caching, sse) */
|
|
444
602
|
arcPlugins?: {
|
|
445
|
-
/** Request ID tracking (default: true) */
|
|
603
|
+
/** Request ID tracking (default: true) */
|
|
604
|
+
requestId?: boolean;
|
|
446
605
|
/**
|
|
447
606
|
* Health endpoints (default: true).
|
|
448
607
|
*
|
|
@@ -469,8 +628,10 @@ interface CreateAppOptions {
|
|
|
469
628
|
* }
|
|
470
629
|
* ```
|
|
471
630
|
*/
|
|
472
|
-
health?: boolean | HealthOptions;
|
|
473
|
-
|
|
631
|
+
health?: boolean | HealthOptions;
|
|
632
|
+
/** Graceful shutdown handling (default: true) */
|
|
633
|
+
gracefulShutdown?: boolean;
|
|
634
|
+
/** Emit events for CRUD operations (default: true) */
|
|
474
635
|
emitEvents?: boolean;
|
|
475
636
|
/**
|
|
476
637
|
* Event plugin configuration. Default: true (enabled with MemoryEventTransport).
|
|
@@ -851,6 +1012,32 @@ interface CreateAppOptions {
|
|
|
851
1012
|
* @default false
|
|
852
1013
|
*/
|
|
853
1014
|
strictResources?: boolean;
|
|
1015
|
+
/**
|
|
1016
|
+
* Pre-boot hook — awaited BEFORE arc does anything else: before the
|
|
1017
|
+
* Fastify instance exists, before module thunks resolve, before resource
|
|
1018
|
+
* discovery imports a single host file.
|
|
1019
|
+
*
|
|
1020
|
+
* The canonical slot for the DB connection and anything that
|
|
1021
|
+
* module-EVAL-time code depends on. Engines that register Mongoose models
|
|
1022
|
+
* at import time (top-level `createXEngine(...)`) trigger eager
|
|
1023
|
+
* `createIndex()` calls from schema plugins — if the connection isn't
|
|
1024
|
+
* open yet those buffer and die with `buffering timed out`. Hosts used to
|
|
1025
|
+
* hand-orchestrate this with `await connectDatabase()` + dynamic
|
|
1026
|
+
* `await import(...)` tricks before calling `createApp`; with `beforeBoot`
|
|
1027
|
+
* the ordering is arc's contract instead:
|
|
1028
|
+
*
|
|
1029
|
+
* ```ts
|
|
1030
|
+
* const app = await createApp({
|
|
1031
|
+
* beforeBoot: async () => { await connectDatabase(); },
|
|
1032
|
+
* modules: [() => import('#modules/accounting.js')], // thunks resolve AFTER beforeBoot
|
|
1033
|
+
* resources: async () => [...],
|
|
1034
|
+
* });
|
|
1035
|
+
* ```
|
|
1036
|
+
*
|
|
1037
|
+
* Runs after option validation (config bugs fail fast without touching
|
|
1038
|
+
* the DB). Cleanup stays host-owned — pair with `onClose`.
|
|
1039
|
+
*/
|
|
1040
|
+
beforeBoot?: () => void | Promise<void>;
|
|
854
1041
|
/**
|
|
855
1042
|
* Custom plugin registration — runs after Arc core (security, auth, events)
|
|
856
1043
|
* but before `bootstrap` and `resources`.
|
|
@@ -895,31 +1082,5 @@ interface CreateAppOptions {
|
|
|
895
1082
|
/** Hook called when the app is shutting down */
|
|
896
1083
|
onClose?: (fastify: FastifyInstance) => void | Promise<void>;
|
|
897
1084
|
}
|
|
898
|
-
interface UnderPressureOptions {
|
|
899
|
-
/** Expose `/_status` route for health checks (default: false) */
|
|
900
|
-
exposeStatusRoute?: boolean;
|
|
901
|
-
/** Event loop lag threshold in ms — requests rejected above this (default: 1000) */
|
|
902
|
-
maxEventLoopDelay?: number;
|
|
903
|
-
/** V8 heap usage threshold in bytes — requests rejected above this */
|
|
904
|
-
maxHeapUsedBytes?: number;
|
|
905
|
-
/** RSS memory threshold in bytes — requests rejected above this */
|
|
906
|
-
maxRssBytes?: number;
|
|
907
|
-
}
|
|
908
|
-
interface MultipartOptions {
|
|
909
|
-
limits?: {
|
|
910
|
-
/** Max file size in bytes (default: Fastify default ~1MB) */fileSize?: number; /** Max number of files per request */
|
|
911
|
-
files?: number;
|
|
912
|
-
};
|
|
913
|
-
}
|
|
914
|
-
interface RawBodyOptions {
|
|
915
|
-
/** Body field name to store raw body on (default: 'rawBody') */
|
|
916
|
-
field?: string;
|
|
917
|
-
/** Apply to all routes globally (default: false) */
|
|
918
|
-
global?: boolean;
|
|
919
|
-
/** Encoding for raw body string (default: 'utf8') */
|
|
920
|
-
encoding?: string;
|
|
921
|
-
/** Parse raw body before other parsers (default: false) */
|
|
922
|
-
runFirst?: boolean;
|
|
923
|
-
}
|
|
924
1085
|
//#endregion
|
|
925
|
-
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 };
|