@classytic/arc 1.1.0 → 2.1.3

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.
Files changed (200) hide show
  1. package/README.md +247 -794
  2. package/bin/arc.js +91 -52
  3. package/dist/EventTransport-BkUDYZEb.d.mts +99 -0
  4. package/dist/HookSystem-BsGV-j2l.mjs +404 -0
  5. package/dist/ResourceRegistry-7Ic20ZMw.mjs +249 -0
  6. package/dist/adapters/index.d.mts +5 -0
  7. package/dist/adapters/index.mjs +3 -0
  8. package/dist/audit/index.d.mts +81 -0
  9. package/dist/audit/index.mjs +275 -0
  10. package/dist/audit/mongodb.d.mts +5 -0
  11. package/dist/audit/mongodb.mjs +3 -0
  12. package/dist/audited-CGdLiSlE.mjs +140 -0
  13. package/dist/auth/index.d.mts +188 -0
  14. package/dist/auth/index.mjs +1096 -0
  15. package/dist/auth/redis-session.d.mts +43 -0
  16. package/dist/auth/redis-session.mjs +75 -0
  17. package/dist/betterAuthOpenApi-DjWDddNc.mjs +249 -0
  18. package/dist/cache/index.d.mts +145 -0
  19. package/dist/cache/index.mjs +91 -0
  20. package/dist/caching-GSDJcA6-.mjs +93 -0
  21. package/dist/chunk-C7Uep-_p.mjs +20 -0
  22. package/dist/circuitBreaker-DYhWBW_D.mjs +1096 -0
  23. package/dist/cli/commands/describe.d.mts +18 -0
  24. package/dist/cli/commands/describe.mjs +238 -0
  25. package/dist/cli/commands/docs.d.mts +13 -0
  26. package/dist/cli/commands/docs.mjs +52 -0
  27. package/dist/cli/commands/{generate.d.ts → generate.d.mts} +3 -2
  28. package/dist/cli/commands/generate.mjs +357 -0
  29. package/dist/cli/commands/{init.d.ts → init.d.mts} +11 -8
  30. package/dist/cli/commands/{init.js → init.mjs} +807 -617
  31. package/dist/cli/commands/introspect.d.mts +10 -0
  32. package/dist/cli/commands/introspect.mjs +75 -0
  33. package/dist/cli/index.d.mts +16 -0
  34. package/dist/cli/index.mjs +156 -0
  35. package/dist/constants-DdXFXQtN.mjs +84 -0
  36. package/dist/core/index.d.mts +5 -0
  37. package/dist/core/index.mjs +4 -0
  38. package/dist/createApp-D2D5XXaV.mjs +559 -0
  39. package/dist/defineResource-PXzSJ15_.mjs +2197 -0
  40. package/dist/discovery/index.d.mts +46 -0
  41. package/dist/discovery/index.mjs +109 -0
  42. package/dist/docs/index.d.mts +162 -0
  43. package/dist/docs/index.mjs +74 -0
  44. package/dist/elevation-DGo5shaX.d.mts +87 -0
  45. package/dist/elevation-DSTbVvYj.mjs +113 -0
  46. package/dist/errorHandler-C3GY3_ow.mjs +108 -0
  47. package/dist/errorHandler-CW3OOeYq.d.mts +72 -0
  48. package/dist/errors-DAWRdiYP.d.mts +124 -0
  49. package/dist/errors-DBANPbGr.mjs +211 -0
  50. package/dist/eventPlugin-BEOvaDqo.mjs +229 -0
  51. package/dist/eventPlugin-H6wDDjGO.d.mts +124 -0
  52. package/dist/events/index.d.mts +53 -0
  53. package/dist/events/index.mjs +51 -0
  54. package/dist/events/transports/redis-stream-entry.d.mts +2 -0
  55. package/dist/events/transports/redis-stream-entry.mjs +177 -0
  56. package/dist/events/transports/redis.d.mts +76 -0
  57. package/dist/events/transports/redis.mjs +124 -0
  58. package/dist/externalPaths-SyPF2tgK.d.mts +50 -0
  59. package/dist/factory/index.d.mts +63 -0
  60. package/dist/factory/index.mjs +3 -0
  61. package/dist/fastifyAdapter-C8DlE0YH.d.mts +216 -0
  62. package/dist/fields-Bi_AVKSo.d.mts +109 -0
  63. package/dist/fields-CTd_CrKr.mjs +114 -0
  64. package/dist/hooks/index.d.mts +4 -0
  65. package/dist/hooks/index.mjs +3 -0
  66. package/dist/idempotency/index.d.mts +96 -0
  67. package/dist/idempotency/index.mjs +319 -0
  68. package/dist/idempotency/mongodb.d.mts +2 -0
  69. package/dist/idempotency/mongodb.mjs +114 -0
  70. package/dist/idempotency/redis.d.mts +2 -0
  71. package/dist/idempotency/redis.mjs +103 -0
  72. package/dist/index.d.mts +260 -0
  73. package/dist/index.mjs +104 -0
  74. package/dist/integrations/event-gateway.d.mts +46 -0
  75. package/dist/integrations/event-gateway.mjs +43 -0
  76. package/dist/integrations/index.d.mts +5 -0
  77. package/dist/integrations/index.mjs +1 -0
  78. package/dist/integrations/jobs.d.mts +103 -0
  79. package/dist/integrations/jobs.mjs +123 -0
  80. package/dist/integrations/streamline.d.mts +60 -0
  81. package/dist/integrations/streamline.mjs +125 -0
  82. package/dist/integrations/websocket.d.mts +82 -0
  83. package/dist/integrations/websocket.mjs +288 -0
  84. package/dist/interface-CSNjltAc.d.mts +77 -0
  85. package/dist/interface-DTbsvIWe.d.mts +54 -0
  86. package/dist/interface-e9XfSsUV.d.mts +1097 -0
  87. package/dist/introspectionPlugin-B3JkrjwU.mjs +53 -0
  88. package/dist/keys-DhqDRxv3.mjs +42 -0
  89. package/dist/logger-ByrvQWZO.mjs +78 -0
  90. package/dist/memory-B2v7KrCB.mjs +143 -0
  91. package/dist/migrations/index.d.mts +156 -0
  92. package/dist/migrations/index.mjs +260 -0
  93. package/dist/mongodb-ClykrfGo.d.mts +118 -0
  94. package/dist/mongodb-DNKEExbf.mjs +93 -0
  95. package/dist/mongodb-Dg8O_gvd.d.mts +71 -0
  96. package/dist/openapi-9nB_kiuR.mjs +525 -0
  97. package/dist/org/index.d.mts +68 -0
  98. package/dist/org/index.mjs +513 -0
  99. package/dist/org/types.d.mts +82 -0
  100. package/dist/org/types.mjs +1 -0
  101. package/dist/permissions/index.d.mts +278 -0
  102. package/dist/permissions/index.mjs +579 -0
  103. package/dist/plugins/index.d.mts +172 -0
  104. package/dist/plugins/index.mjs +522 -0
  105. package/dist/plugins/response-cache.d.mts +87 -0
  106. package/dist/plugins/response-cache.mjs +283 -0
  107. package/dist/plugins/tracing-entry.d.mts +2 -0
  108. package/dist/plugins/tracing-entry.mjs +185 -0
  109. package/dist/pluralize-CM-jZg7p.mjs +86 -0
  110. package/dist/policies/{index.d.ts → index.d.mts} +204 -170
  111. package/dist/policies/index.mjs +321 -0
  112. package/dist/presets/{index.d.ts → index.d.mts} +62 -131
  113. package/dist/presets/index.mjs +143 -0
  114. package/dist/presets/multiTenant.d.mts +24 -0
  115. package/dist/presets/multiTenant.mjs +113 -0
  116. package/dist/presets-BTeYbw7h.d.mts +57 -0
  117. package/dist/presets-CeFtfDR8.mjs +119 -0
  118. package/dist/prisma-C3iornoK.d.mts +274 -0
  119. package/dist/prisma-DJbMt3yf.mjs +627 -0
  120. package/dist/queryCachePlugin-B6R0d4av.mjs +138 -0
  121. package/dist/queryCachePlugin-Q6SYuHZ6.d.mts +71 -0
  122. package/dist/redis-UwjEp8Ea.d.mts +49 -0
  123. package/dist/redis-stream-CBg0upHI.d.mts +103 -0
  124. package/dist/registry/index.d.mts +11 -0
  125. package/dist/registry/index.mjs +4 -0
  126. package/dist/requestContext-xi6OKBL-.mjs +55 -0
  127. package/dist/schemaConverter-Dtg0Kt9T.mjs +98 -0
  128. package/dist/schemas/index.d.mts +63 -0
  129. package/dist/schemas/index.mjs +82 -0
  130. package/dist/scope/index.d.mts +21 -0
  131. package/dist/scope/index.mjs +65 -0
  132. package/dist/sessionManager-D_iEHjQl.d.mts +186 -0
  133. package/dist/sse-DkqQ1uxb.mjs +123 -0
  134. package/dist/testing/index.d.mts +907 -0
  135. package/dist/testing/index.mjs +1976 -0
  136. package/dist/tracing-8CEbhF0w.d.mts +70 -0
  137. package/dist/typeGuards-DwxA1t_L.mjs +9 -0
  138. package/dist/types/index.d.mts +946 -0
  139. package/dist/types/index.mjs +14 -0
  140. package/dist/types-B0dhNrnd.d.mts +445 -0
  141. package/dist/types-Beqn1Un7.mjs +38 -0
  142. package/dist/types-DelU6kln.mjs +25 -0
  143. package/dist/types-RLkFVgaw.d.mts +101 -0
  144. package/dist/utils/index.d.mts +747 -0
  145. package/dist/utils/index.mjs +6 -0
  146. package/package.json +194 -68
  147. package/dist/BaseController-DVAiHxEQ.d.ts +0 -233
  148. package/dist/adapters/index.d.ts +0 -237
  149. package/dist/adapters/index.js +0 -668
  150. package/dist/arcCorePlugin-CsShQdyP.d.ts +0 -273
  151. package/dist/audit/index.d.ts +0 -195
  152. package/dist/audit/index.js +0 -319
  153. package/dist/auth/index.d.ts +0 -47
  154. package/dist/auth/index.js +0 -174
  155. package/dist/cli/commands/docs.d.ts +0 -11
  156. package/dist/cli/commands/docs.js +0 -474
  157. package/dist/cli/commands/generate.js +0 -334
  158. package/dist/cli/commands/introspect.d.ts +0 -8
  159. package/dist/cli/commands/introspect.js +0 -338
  160. package/dist/cli/index.d.ts +0 -4
  161. package/dist/cli/index.js +0 -3269
  162. package/dist/core/index.d.ts +0 -220
  163. package/dist/core/index.js +0 -2786
  164. package/dist/createApp-Ce9wl8W9.d.ts +0 -77
  165. package/dist/docs/index.d.ts +0 -166
  166. package/dist/docs/index.js +0 -658
  167. package/dist/errors-8WIxGS_6.d.ts +0 -122
  168. package/dist/events/index.d.ts +0 -117
  169. package/dist/events/index.js +0 -89
  170. package/dist/factory/index.d.ts +0 -38
  171. package/dist/factory/index.js +0 -1652
  172. package/dist/hooks/index.d.ts +0 -4
  173. package/dist/hooks/index.js +0 -199
  174. package/dist/idempotency/index.d.ts +0 -323
  175. package/dist/idempotency/index.js +0 -500
  176. package/dist/index-B4t03KQ0.d.ts +0 -1366
  177. package/dist/index.d.ts +0 -135
  178. package/dist/index.js +0 -4756
  179. package/dist/migrations/index.d.ts +0 -185
  180. package/dist/migrations/index.js +0 -274
  181. package/dist/org/index.d.ts +0 -129
  182. package/dist/org/index.js +0 -220
  183. package/dist/permissions/index.d.ts +0 -144
  184. package/dist/permissions/index.js +0 -103
  185. package/dist/plugins/index.d.ts +0 -46
  186. package/dist/plugins/index.js +0 -1069
  187. package/dist/policies/index.js +0 -196
  188. package/dist/presets/index.js +0 -384
  189. package/dist/presets/multiTenant.d.ts +0 -39
  190. package/dist/presets/multiTenant.js +0 -112
  191. package/dist/registry/index.d.ts +0 -16
  192. package/dist/registry/index.js +0 -253
  193. package/dist/testing/index.d.ts +0 -618
  194. package/dist/testing/index.js +0 -48020
  195. package/dist/types/index.d.ts +0 -4
  196. package/dist/types/index.js +0 -8
  197. package/dist/types-B99TBmFV.d.ts +0 -76
  198. package/dist/types-BvckRbs2.d.ts +0 -143
  199. package/dist/utils/index.d.ts +0 -679
  200. package/dist/utils/index.js +0 -931
@@ -0,0 +1,559 @@
1
+ import { t as __exportAll } from "./chunk-C7Uep-_p.mjs";
2
+ import { n as PUBLIC_SCOPE } from "./types-Beqn1Un7.mjs";
3
+ import Fastify from "fastify";
4
+ import qs from "qs";
5
+
6
+ //#region src/factory/presets.ts
7
+ /**
8
+ * Production preset - strict security, performance optimized
9
+ */
10
+ const productionPreset = {
11
+ logger: {
12
+ level: "info",
13
+ redact: {
14
+ paths: [
15
+ "req.headers.authorization",
16
+ "req.headers.cookie",
17
+ "req.headers[\"set-cookie\"]",
18
+ "*.password",
19
+ "*.secret",
20
+ "*.token",
21
+ "*.accessToken",
22
+ "*.refreshToken",
23
+ "*.creditCard"
24
+ ],
25
+ censor: "[REDACTED]"
26
+ }
27
+ },
28
+ trustProxy: true,
29
+ helmet: { contentSecurityPolicy: { directives: {
30
+ defaultSrc: ["'self'"],
31
+ styleSrc: ["'self'", "'unsafe-inline'"],
32
+ scriptSrc: ["'self'"],
33
+ imgSrc: [
34
+ "'self'",
35
+ "data:",
36
+ "https:"
37
+ ]
38
+ } } },
39
+ cors: {
40
+ origin: false,
41
+ credentials: true,
42
+ methods: [
43
+ "GET",
44
+ "POST",
45
+ "PUT",
46
+ "DELETE",
47
+ "PATCH",
48
+ "OPTIONS"
49
+ ],
50
+ allowedHeaders: [
51
+ "Content-Type",
52
+ "Authorization",
53
+ "Accept"
54
+ ]
55
+ },
56
+ rateLimit: {
57
+ max: 100,
58
+ timeWindow: "1 minute"
59
+ },
60
+ underPressure: {
61
+ exposeStatusRoute: true,
62
+ maxEventLoopDelay: 1e3,
63
+ maxHeapUsedBytes: 1024 * 1024 * 1024,
64
+ maxRssBytes: 1024 * 1024 * 1024
65
+ }
66
+ };
67
+ /**
68
+ * Development preset - relaxed security, verbose logging
69
+ */
70
+ const developmentPreset = {
71
+ logger: {
72
+ level: "debug",
73
+ transport: {
74
+ target: "pino-pretty",
75
+ options: {
76
+ colorize: true,
77
+ translateTime: "SYS:HH:MM:ss",
78
+ ignore: "pid,hostname"
79
+ }
80
+ }
81
+ },
82
+ trustProxy: true,
83
+ helmet: { contentSecurityPolicy: false },
84
+ cors: {
85
+ origin: true,
86
+ credentials: true,
87
+ methods: [
88
+ "GET",
89
+ "POST",
90
+ "PUT",
91
+ "DELETE",
92
+ "PATCH",
93
+ "OPTIONS"
94
+ ],
95
+ allowedHeaders: [
96
+ "Content-Type",
97
+ "Authorization",
98
+ "Accept"
99
+ ]
100
+ },
101
+ rateLimit: {
102
+ max: 1e3,
103
+ timeWindow: "1 minute"
104
+ },
105
+ underPressure: {
106
+ exposeStatusRoute: true,
107
+ maxEventLoopDelay: 5e3
108
+ }
109
+ };
110
+ /**
111
+ * Testing preset - minimal setup, fast startup
112
+ */
113
+ const testingPreset = {
114
+ logger: false,
115
+ trustProxy: false,
116
+ helmet: false,
117
+ cors: false,
118
+ rateLimit: false,
119
+ underPressure: false,
120
+ sensible: true,
121
+ multipart: { limits: {
122
+ fileSize: 1024 * 1024,
123
+ files: 5
124
+ } }
125
+ };
126
+ /**
127
+ * Edge/Serverless preset - minimal cold-start overhead
128
+ *
129
+ * Optimized for AWS Lambda, Vercel, Cloudflare Workers, and similar environments.
130
+ * Disables all heavy plugins that add cold-start latency:
131
+ * - Security headers (handled by API Gateway / CDN)
132
+ * - Rate limiting (handled by API Gateway / CDN)
133
+ * - Health monitoring (Lambda has its own health checks)
134
+ * - File uploads (use pre-signed URLs instead)
135
+ * - Raw body parsing (register per-route if needed)
136
+ *
137
+ * Arc core plugins (requestId, health, gracefulShutdown) are also disabled
138
+ * since the serverless runtime manages request lifecycle.
139
+ */
140
+ const edgePreset = {
141
+ logger: { level: "warn" },
142
+ trustProxy: true,
143
+ helmet: false,
144
+ cors: false,
145
+ rateLimit: false,
146
+ underPressure: false,
147
+ sensible: true,
148
+ multipart: false,
149
+ rawBody: false,
150
+ arcPlugins: {
151
+ requestId: false,
152
+ health: false,
153
+ gracefulShutdown: false,
154
+ emitEvents: true
155
+ }
156
+ };
157
+ /**
158
+ * Get preset by name
159
+ */
160
+ function getPreset(name) {
161
+ switch (name) {
162
+ case "production": return productionPreset;
163
+ case "development": return developmentPreset;
164
+ case "testing": return testingPreset;
165
+ case "edge": return edgePreset;
166
+ default: throw new Error(`Unknown preset: ${name}`);
167
+ }
168
+ }
169
+
170
+ //#endregion
171
+ //#region src/factory/createApp.ts
172
+ /**
173
+ * ArcFactory - Production-ready Fastify application factory
174
+ *
175
+ * Enforces security best practices by making plugins opt-out instead of opt-in.
176
+ * A developer must explicitly disable security features rather than forget to enable them.
177
+ *
178
+ * Note: Arc is database-agnostic. Connect your database separately and provide
179
+ * adapters when defining resources. This allows multiple databases, custom
180
+ * connection pooling, and full control over your data layer.
181
+ *
182
+ * @example
183
+ * // 1. Connect your database(s) separately
184
+ * import mongoose from 'mongoose';
185
+ * await mongoose.connect(process.env.MONGO_URI);
186
+ *
187
+ * // 2. Create Arc app (no database config needed)
188
+ * const app = await createApp({
189
+ * preset: 'production',
190
+ * auth: { type: 'jwt', jwt: { secret: process.env.JWT_SECRET } },
191
+ * cors: { origin: ['https://example.com'] },
192
+ * });
193
+ *
194
+ * // 3. Register resources with your adapters
195
+ * await app.register(productResource.toPlugin());
196
+ *
197
+ * @example
198
+ * // Multiple databases example
199
+ * const primaryDb = await mongoose.connect(process.env.PRIMARY_DB);
200
+ * const analyticsDb = mongoose.createConnection(process.env.ANALYTICS_DB);
201
+ *
202
+ * const orderResource = defineResource({
203
+ * adapter: createMongooseAdapter({ model: OrderModel, repository: orderRepo }),
204
+ * });
205
+ *
206
+ * const analyticsResource = defineResource({
207
+ * adapter: createMongooseAdapter({ model: AnalyticsModel, repository: analyticsRepo }),
208
+ * });
209
+ */
210
+ var createApp_exports = /* @__PURE__ */ __exportAll({
211
+ ArcFactory: () => ArcFactory,
212
+ createApp: () => createApp
213
+ });
214
+ const PLUGIN_REGISTRY = {
215
+ cors: {
216
+ package: "@fastify/cors",
217
+ loader: () => import("@fastify/cors").then((m) => m.default)
218
+ },
219
+ helmet: {
220
+ package: "@fastify/helmet",
221
+ loader: () => import("@fastify/helmet").then((m) => m.default)
222
+ },
223
+ rateLimit: {
224
+ package: "@fastify/rate-limit",
225
+ loader: () => import("@fastify/rate-limit").then((m) => m.default)
226
+ },
227
+ underPressure: {
228
+ package: "@fastify/under-pressure",
229
+ loader: () => import("@fastify/under-pressure").then((m) => m.default)
230
+ },
231
+ sensible: {
232
+ package: "@fastify/sensible",
233
+ loader: () => import("@fastify/sensible").then((m) => m.default)
234
+ },
235
+ multipart: {
236
+ package: "@fastify/multipart",
237
+ loader: () => import("@fastify/multipart").then((m) => m.default),
238
+ optional: true
239
+ },
240
+ rawBody: {
241
+ package: "fastify-raw-body",
242
+ loader: () => import("fastify-raw-body").then((m) => m.default),
243
+ optional: true
244
+ }
245
+ };
246
+ async function loadPlugin(name, logger) {
247
+ const entry = PLUGIN_REGISTRY[name];
248
+ if (!entry) throw new Error(`Unknown plugin: ${name}`);
249
+ try {
250
+ return await entry.loader();
251
+ } catch (error) {
252
+ const err = error;
253
+ const isModuleNotFound = err.message.includes("Cannot find module") || err.message.includes("Cannot find package") || err.message.includes("MODULE_NOT_FOUND") || err.message.includes("Could not resolve");
254
+ if (isModuleNotFound && entry.optional) {
255
+ logger?.warn(`Optional plugin '${name}' skipped (${entry.package} not installed)`);
256
+ return null;
257
+ }
258
+ if (isModuleNotFound) throw new Error(`Plugin '${name}' requires package '${entry.package}' which is not installed.\nInstall it with: npm install ${entry.package}\nOr disable this plugin by setting ${name}: false in createApp options.`);
259
+ throw new Error(`Failed to load plugin '${name}': ${err.message}`);
260
+ }
261
+ }
262
+ /**
263
+ * Create a production-ready Fastify application with Arc framework
264
+ *
265
+ * Security plugins are enabled by default (opt-out):
266
+ * - helmet (security headers)
267
+ * - cors (cross-origin requests)
268
+ * - rateLimit (DDoS protection)
269
+ * - underPressure (health monitoring)
270
+ *
271
+ * Note: Compression is not included due to known Fastify 5 issues.
272
+ * Use a reverse proxy (Nginx, Caddy) or CDN for compression.
273
+ *
274
+ * @param options - Application configuration
275
+ * @returns Configured Fastify instance
276
+ */
277
+ async function createApp(options) {
278
+ if (options.debug !== void 0 && options.debug !== false) {
279
+ const { configureArcLogger } = await import("./logger-ByrvQWZO.mjs").then((n) => n.r);
280
+ configureArcLogger({ debug: options.debug });
281
+ }
282
+ const authConfig = options.auth;
283
+ const isAuthDisabled = authConfig === false;
284
+ if (!isAuthDisabled && authConfig && authConfig.type === "jwt") {
285
+ if (!authConfig.jwt?.secret && !authConfig.authenticate) throw new Error("createApp: JWT secret required when Arc auth is enabled.\nProvide auth.jwt.secret, auth.authenticate, or set auth: false to disable.\nExample: auth: { type: 'jwt', jwt: { secret: process.env.JWT_SECRET } }");
286
+ }
287
+ if (options.runtime === "distributed") {
288
+ const MEMORY_NAMES = new Set(["memory", "memory-cache"]);
289
+ const missing = [];
290
+ const eventsTransport = options.stores?.events;
291
+ if (!eventsTransport || MEMORY_NAMES.has(eventsTransport.name)) missing.push("events transport");
292
+ const cacheStore = options.stores?.cache;
293
+ if (!cacheStore || MEMORY_NAMES.has(cacheStore.name)) missing.push("cache store");
294
+ const idempotencyStore = options.stores?.idempotency;
295
+ if (!idempotencyStore || MEMORY_NAMES.has(idempotencyStore.name)) missing.push("idempotency store");
296
+ if (options.arcPlugins?.queryCache) {
297
+ const qcStore = options.stores?.queryCache;
298
+ if (!qcStore || MEMORY_NAMES.has(qcStore.name)) missing.push("queryCache store");
299
+ }
300
+ if (missing.length > 0) throw new Error(`[Arc] runtime: 'distributed' requires Redis/durable adapters.\nMissing: ${missing.join(", ")}.\nProvide Redis-backed stores or use runtime: 'memory' for development.`);
301
+ }
302
+ const config = {
303
+ ...options.preset ? getPreset(options.preset) : {},
304
+ ...options
305
+ };
306
+ let fastify = Fastify({
307
+ logger: config.logger ?? true,
308
+ trustProxy: config.trustProxy ?? false,
309
+ routerOptions: { querystringParser: (str) => qs.parse(str) },
310
+ ajv: { customOptions: {
311
+ coerceTypes: true,
312
+ useDefaults: true,
313
+ removeAdditional: false,
314
+ keywords: ["example"]
315
+ } }
316
+ });
317
+ if (config.typeProvider === "typebox") try {
318
+ const { TypeBoxValidatorCompiler } = await import("@fastify/type-provider-typebox");
319
+ fastify.setValidatorCompiler(TypeBoxValidatorCompiler);
320
+ fastify.log.debug("TypeBox type provider enabled");
321
+ } catch {
322
+ fastify.log.warn("typeProvider: \"typebox\" requested but @fastify/type-provider-typebox is not installed. Install it with: npm install @sinclair/typebox @fastify/type-provider-typebox");
323
+ }
324
+ fastify.removeContentTypeParser("application/json");
325
+ fastify.addContentTypeParser("application/json", { parseAs: "string" }, (_req, body, done) => {
326
+ if (!body || body.length === 0) return done(null, void 0);
327
+ try {
328
+ done(null, JSON.parse(body));
329
+ } catch (err) {
330
+ done(err);
331
+ }
332
+ });
333
+ if (config.helmet !== false) {
334
+ const helmet = await loadPlugin("helmet");
335
+ await fastify.register(helmet, config.helmet ?? {});
336
+ fastify.log.debug("Helmet (security headers) enabled");
337
+ } else fastify.log.warn("Helmet disabled - security headers not applied");
338
+ if (config.cors !== false) {
339
+ const cors = await loadPlugin("cors");
340
+ const corsOptions = config.cors ?? {};
341
+ if (config.preset === "production" && (!corsOptions || !("origin" in corsOptions))) throw new Error("CORS origin must be explicitly configured in production.\nSet cors.origin to allowed domains or set cors: false to disable.\nExample: cors: { origin: ['https://yourdomain.com'] }\nDocs: https://github.com/classytic/arc#security");
342
+ await fastify.register(cors, corsOptions);
343
+ fastify.log.debug("CORS enabled");
344
+ } else fastify.log.warn("CORS disabled");
345
+ if (config.rateLimit !== false) {
346
+ const rateLimit = await loadPlugin("rateLimit");
347
+ const rateLimitOpts = config.rateLimit ?? {
348
+ max: 100,
349
+ timeWindow: "1 minute"
350
+ };
351
+ await fastify.register(rateLimit, rateLimitOpts);
352
+ if (config.preset === "production") {
353
+ if (!(typeof rateLimitOpts === "object" && "store" in rateLimitOpts)) fastify.log.warn("Rate limiting is using in-memory store. In multi-instance deployments, each instance tracks limits independently. Configure a Redis store for distributed rate limiting: rateLimit: { store: new RedisStore({ ... }) }");
354
+ }
355
+ fastify.log.debug("Rate limiting enabled");
356
+ } else fastify.log.warn("Rate limiting disabled");
357
+ if (config.preset === "production") fastify.log.warn("Response compression is not enabled (Fastify 5 stream issues). Use a reverse proxy (Nginx, Caddy, Cloudflare) for gzip/brotli in production.");
358
+ if (config.underPressure !== false) {
359
+ const underPressure = await loadPlugin("underPressure");
360
+ await fastify.register(underPressure, config.underPressure ?? { exposeStatusRoute: true });
361
+ fastify.log.debug("Health monitoring (under-pressure) enabled");
362
+ } else fastify.log.debug("Health monitoring disabled");
363
+ if (config.sensible !== false) {
364
+ const sensible = await loadPlugin("sensible");
365
+ await fastify.register(sensible);
366
+ fastify.log.debug("Sensible (HTTP helpers) enabled");
367
+ }
368
+ if (config.multipart !== false) {
369
+ const multipart = await loadPlugin("multipart", fastify.log);
370
+ if (multipart) {
371
+ await fastify.register(multipart, {
372
+ limits: {
373
+ fileSize: 10 * 1024 * 1024,
374
+ files: 10
375
+ },
376
+ throwFileSizeLimit: true,
377
+ ...config.multipart
378
+ });
379
+ fastify.log.debug("Multipart (file uploads) enabled");
380
+ }
381
+ }
382
+ if (config.rawBody !== false) {
383
+ const rawBody = await loadPlugin("rawBody", fastify.log);
384
+ if (rawBody) {
385
+ await fastify.register(rawBody, {
386
+ field: "rawBody",
387
+ global: false,
388
+ encoding: "utf8",
389
+ runFirst: true,
390
+ ...config.rawBody
391
+ });
392
+ fastify.log.debug("Raw body parsing enabled");
393
+ }
394
+ }
395
+ const { arcCorePlugin, requestIdPlugin, healthPlugin, gracefulShutdownPlugin } = await import("./plugins/index.mjs");
396
+ await fastify.register(arcCorePlugin, { emitEvents: config.arcPlugins?.emitEvents !== false });
397
+ /** Track a plugin in the Arc plugin registry */
398
+ const trackPlugin = (name, opts) => {
399
+ fastify.arc.plugins.set(name, {
400
+ name,
401
+ options: opts,
402
+ registeredAt: (/* @__PURE__ */ new Date()).toISOString()
403
+ });
404
+ };
405
+ trackPlugin("arc-core");
406
+ if (config.arcPlugins?.events !== false) {
407
+ const { default: eventPlugin } = await import("./eventPlugin-BEOvaDqo.mjs").then((n) => n.n);
408
+ const eventOpts = typeof config.arcPlugins?.events === "object" ? config.arcPlugins.events : {};
409
+ await fastify.register(eventPlugin, {
410
+ ...eventOpts,
411
+ transport: options.stores?.events
412
+ });
413
+ trackPlugin("arc-events", eventOpts);
414
+ fastify.log.debug(`Arc events plugin enabled (transport: ${fastify.events.transportName})`);
415
+ }
416
+ if (config.arcPlugins?.requestId !== false) {
417
+ await fastify.register(requestIdPlugin);
418
+ trackPlugin("arc-request-id");
419
+ fastify.log.debug("Arc requestId plugin enabled");
420
+ }
421
+ if (config.arcPlugins?.health !== false) {
422
+ await fastify.register(healthPlugin);
423
+ trackPlugin("arc-health");
424
+ fastify.log.debug("Arc health plugin enabled");
425
+ }
426
+ if (config.arcPlugins?.gracefulShutdown !== false) {
427
+ await fastify.register(gracefulShutdownPlugin);
428
+ trackPlugin("arc-graceful-shutdown");
429
+ fastify.log.debug("Arc gracefulShutdown plugin enabled");
430
+ }
431
+ if (config.arcPlugins?.caching) {
432
+ const { default: cachingPlugin } = await import("./caching-GSDJcA6-.mjs").then((n) => n.r);
433
+ const cachingOpts = config.arcPlugins.caching === true ? {} : config.arcPlugins.caching;
434
+ await fastify.register(cachingPlugin, cachingOpts);
435
+ trackPlugin("arc-caching", cachingOpts);
436
+ fastify.log.debug("Arc caching plugin enabled");
437
+ }
438
+ if (config.arcPlugins?.queryCache) {
439
+ const { queryCachePlugin } = await import("./queryCachePlugin-B6R0d4av.mjs").then((n) => n.n);
440
+ const qcOpts = config.arcPlugins.queryCache === true ? {} : config.arcPlugins.queryCache;
441
+ const store = options.stores?.queryCache ?? new (await (import("./memory-B2v7KrCB.mjs").then((n) => n.n))).MemoryCacheStore();
442
+ await fastify.register(queryCachePlugin, {
443
+ store,
444
+ ...qcOpts
445
+ });
446
+ trackPlugin("arc-query-cache", qcOpts);
447
+ fastify.log.debug("Arc queryCache plugin enabled");
448
+ }
449
+ if (config.arcPlugins?.sse) if (config.arcPlugins?.events === false) fastify.log.warn("SSE plugin requires events plugin (arcPlugins.events). SSE disabled.");
450
+ else {
451
+ const { default: ssePlugin } = await import("./sse-DkqQ1uxb.mjs").then((n) => n.r);
452
+ const sseOpts = config.arcPlugins.sse === true ? {} : config.arcPlugins.sse;
453
+ await fastify.register(ssePlugin, sseOpts);
454
+ trackPlugin("arc-sse", sseOpts);
455
+ fastify.log.debug("Arc SSE plugin enabled");
456
+ }
457
+ fastify.decorateRequest("scope", null);
458
+ fastify.addHook("onRequest", async (request) => {
459
+ if (!request.scope) request.scope = PUBLIC_SCOPE;
460
+ });
461
+ if (isAuthDisabled) fastify.log.debug("Authentication disabled");
462
+ else if (authConfig) switch (authConfig.type) {
463
+ case "betterAuth": {
464
+ const { plugin, openapi } = authConfig.betterAuth;
465
+ await fastify.register(plugin);
466
+ trackPlugin("auth-better-auth");
467
+ if (openapi && !fastify.arc.externalOpenApiPaths.includes(openapi)) fastify.arc.externalOpenApiPaths.push(openapi);
468
+ fastify.log.debug("Better Auth authentication enabled");
469
+ break;
470
+ }
471
+ case "custom":
472
+ await fastify.register(authConfig.plugin);
473
+ trackPlugin("auth-custom");
474
+ fastify.log.debug("Custom authentication plugin enabled");
475
+ break;
476
+ case "authenticator": {
477
+ const { authenticate } = authConfig;
478
+ fastify.decorate("authenticate", async function(request, reply) {
479
+ await authenticate(request, reply);
480
+ });
481
+ trackPlugin("auth-authenticator");
482
+ fastify.log.debug("Custom authenticator enabled");
483
+ break;
484
+ }
485
+ case "jwt": {
486
+ const { authPlugin } = await import("./auth/index.mjs");
487
+ const { type: _, ...arcAuthOpts } = authConfig;
488
+ await fastify.register(authPlugin, arcAuthOpts);
489
+ trackPlugin("auth-jwt");
490
+ fastify.log.debug("Arc authentication plugin enabled");
491
+ break;
492
+ }
493
+ }
494
+ if (config.elevation) {
495
+ const { elevationPlugin } = await import("./elevation-DSTbVvYj.mjs").then((n) => n.r);
496
+ await fastify.register(elevationPlugin, config.elevation);
497
+ trackPlugin("arc-elevation", config.elevation);
498
+ fastify.log.debug("Elevation plugin enabled");
499
+ }
500
+ if (config.errorHandler !== false) {
501
+ const { errorHandlerPlugin } = await import("./errorHandler-C3GY3_ow.mjs").then((n) => n.n);
502
+ const errorOpts = typeof config.errorHandler === "object" ? config.errorHandler : { includeStack: config.preset !== "production" };
503
+ await fastify.register(errorHandlerPlugin, errorOpts);
504
+ trackPlugin("arc-error-handler", errorOpts);
505
+ fastify.log.debug("Arc error handler enabled");
506
+ }
507
+ if (config.plugins) {
508
+ await config.plugins(fastify);
509
+ fastify.log.debug("Custom plugins registered");
510
+ }
511
+ if (config.onReady) {
512
+ const onReady = config.onReady;
513
+ fastify.addHook("onReady", async () => {
514
+ await onReady(fastify);
515
+ });
516
+ }
517
+ if (config.onClose) {
518
+ const onClose = config.onClose;
519
+ fastify.addHook("onClose", async () => {
520
+ await onClose(fastify);
521
+ });
522
+ }
523
+ const authMode = isAuthDisabled ? "none" : authConfig ? authConfig.type : "none";
524
+ fastify.log.info({
525
+ preset: config.preset ?? "custom",
526
+ runtime: config.runtime ?? "memory",
527
+ auth: authMode,
528
+ helmet: config.helmet !== false,
529
+ cors: config.cors !== false,
530
+ rateLimit: config.rateLimit !== false
531
+ }, "Arc application created");
532
+ return fastify;
533
+ }
534
+ /**
535
+ * Quick factory for common scenarios
536
+ */
537
+ const ArcFactory = {
538
+ async production(options) {
539
+ return createApp({
540
+ ...options,
541
+ preset: "production"
542
+ });
543
+ },
544
+ async development(options) {
545
+ return createApp({
546
+ ...options,
547
+ preset: "development"
548
+ });
549
+ },
550
+ async testing(options) {
551
+ return createApp({
552
+ ...options,
553
+ preset: "testing"
554
+ });
555
+ }
556
+ };
557
+
558
+ //#endregion
559
+ export { getPreset as a, developmentPreset as i, createApp as n, productionPreset as o, createApp_exports as r, testingPreset as s, ArcFactory as t };