@classytic/arc 1.1.0 → 2.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +247 -794
- package/bin/arc.js +91 -52
- package/dist/EventTransport-BD2U0BTc.d.mts +100 -0
- package/dist/EventTransport-BD2U0BTc.d.mts.map +1 -0
- package/dist/HookSystem-BsGV-j2l.mjs +405 -0
- package/dist/HookSystem-BsGV-j2l.mjs.map +1 -0
- package/dist/ResourceRegistry-DsN4KJjV.mjs +250 -0
- package/dist/ResourceRegistry-DsN4KJjV.mjs.map +1 -0
- package/dist/adapters/index.d.mts +5 -0
- package/dist/adapters/index.mjs +3 -0
- package/dist/audit/index.d.mts +82 -0
- package/dist/audit/index.d.mts.map +1 -0
- package/dist/audit/index.mjs +276 -0
- package/dist/audit/index.mjs.map +1 -0
- package/dist/audit/mongodb.d.mts +5 -0
- package/dist/audit/mongodb.mjs +3 -0
- package/dist/audited-C3T5DTUx.mjs +141 -0
- package/dist/audited-C3T5DTUx.mjs.map +1 -0
- package/dist/auth/index.d.mts +189 -0
- package/dist/auth/index.d.mts.map +1 -0
- package/dist/auth/index.mjs +1102 -0
- package/dist/auth/index.mjs.map +1 -0
- package/dist/auth/redis-session.d.mts +44 -0
- package/dist/auth/redis-session.d.mts.map +1 -0
- package/dist/auth/redis-session.mjs +76 -0
- package/dist/auth/redis-session.mjs.map +1 -0
- package/dist/betterAuthOpenApi-BrHKeSAx.mjs +250 -0
- package/dist/betterAuthOpenApi-BrHKeSAx.mjs.map +1 -0
- package/dist/cache/index.d.mts +146 -0
- package/dist/cache/index.d.mts.map +1 -0
- package/dist/cache/index.mjs +92 -0
- package/dist/cache/index.mjs.map +1 -0
- package/dist/caching-Bl28lYsR.mjs +94 -0
- package/dist/caching-Bl28lYsR.mjs.map +1 -0
- package/dist/chunk-C7Uep-_p.mjs +20 -0
- package/dist/circuitBreaker-DeY4FCjs.mjs +1097 -0
- package/dist/circuitBreaker-DeY4FCjs.mjs.map +1 -0
- package/dist/cli/commands/describe.d.mts +19 -0
- package/dist/cli/commands/describe.d.mts.map +1 -0
- package/dist/cli/commands/describe.mjs +239 -0
- package/dist/cli/commands/describe.mjs.map +1 -0
- package/dist/cli/commands/docs.d.mts +14 -0
- package/dist/cli/commands/docs.d.mts.map +1 -0
- package/dist/cli/commands/docs.mjs +53 -0
- package/dist/cli/commands/docs.mjs.map +1 -0
- package/dist/cli/commands/{generate.d.ts → generate.d.mts} +3 -1
- package/dist/cli/commands/generate.d.mts.map +1 -0
- package/dist/cli/commands/generate.mjs +358 -0
- package/dist/cli/commands/generate.mjs.map +1 -0
- package/dist/cli/commands/{init.d.ts → init.d.mts} +12 -8
- package/dist/cli/commands/init.d.mts.map +1 -0
- package/dist/cli/commands/{init.js → init.mjs} +807 -616
- package/dist/cli/commands/init.mjs.map +1 -0
- package/dist/cli/commands/introspect.d.mts +11 -0
- package/dist/cli/commands/introspect.d.mts.map +1 -0
- package/dist/cli/commands/introspect.mjs +76 -0
- package/dist/cli/commands/introspect.mjs.map +1 -0
- package/dist/cli/index.d.mts +17 -0
- package/dist/cli/index.d.mts.map +1 -0
- package/dist/cli/index.mjs +157 -0
- package/dist/cli/index.mjs.map +1 -0
- package/dist/constants-DdXFXQtN.mjs +85 -0
- package/dist/constants-DdXFXQtN.mjs.map +1 -0
- package/dist/core/index.d.mts +5 -0
- package/dist/core/index.mjs +4 -0
- package/dist/createApp-CUgNqegw.mjs +560 -0
- package/dist/createApp-CUgNqegw.mjs.map +1 -0
- package/dist/defineResource-k0_BDn8v.mjs +2197 -0
- package/dist/defineResource-k0_BDn8v.mjs.map +1 -0
- package/dist/discovery/index.d.mts +47 -0
- package/dist/discovery/index.d.mts.map +1 -0
- package/dist/discovery/index.mjs +110 -0
- package/dist/discovery/index.mjs.map +1 -0
- package/dist/docs/index.d.mts +163 -0
- package/dist/docs/index.d.mts.map +1 -0
- package/dist/docs/index.mjs +73 -0
- package/dist/docs/index.mjs.map +1 -0
- package/dist/elevation-BRy3yFWT.mjs +113 -0
- package/dist/elevation-BRy3yFWT.mjs.map +1 -0
- package/dist/elevation-B_2dRLVP.d.mts +88 -0
- package/dist/elevation-B_2dRLVP.d.mts.map +1 -0
- package/dist/errorHandler-BbcgBmIH.d.mts +73 -0
- package/dist/errorHandler-BbcgBmIH.d.mts.map +1 -0
- package/dist/errorHandler-C1okiriz.mjs +109 -0
- package/dist/errorHandler-C1okiriz.mjs.map +1 -0
- package/dist/errors-B9bZok84.mjs +212 -0
- package/dist/errors-B9bZok84.mjs.map +1 -0
- package/dist/errors-ChKiFz62.d.mts +125 -0
- package/dist/errors-ChKiFz62.d.mts.map +1 -0
- package/dist/eventPlugin-CTrLH3mt.d.mts +125 -0
- package/dist/eventPlugin-CTrLH3mt.d.mts.map +1 -0
- package/dist/eventPlugin-DGR_B2on.mjs +230 -0
- package/dist/eventPlugin-DGR_B2on.mjs.map +1 -0
- package/dist/events/index.d.mts +54 -0
- package/dist/events/index.d.mts.map +1 -0
- package/dist/events/index.mjs +52 -0
- package/dist/events/index.mjs.map +1 -0
- package/dist/events/transports/redis-stream-entry.d.mts +2 -0
- package/dist/events/transports/redis-stream-entry.mjs +178 -0
- package/dist/events/transports/redis-stream-entry.mjs.map +1 -0
- package/dist/events/transports/redis.d.mts +77 -0
- package/dist/events/transports/redis.d.mts.map +1 -0
- package/dist/events/transports/redis.mjs +125 -0
- package/dist/events/transports/redis.mjs.map +1 -0
- package/dist/externalPaths-DlINfKbP.d.mts +51 -0
- package/dist/externalPaths-DlINfKbP.d.mts.map +1 -0
- package/dist/factory/index.d.mts +64 -0
- package/dist/factory/index.d.mts.map +1 -0
- package/dist/factory/index.mjs +3 -0
- package/dist/fastifyAdapter-BkrGrlFi.d.mts +217 -0
- package/dist/fastifyAdapter-BkrGrlFi.d.mts.map +1 -0
- package/dist/fields-DyaDVX4J.d.mts +110 -0
- package/dist/fields-DyaDVX4J.d.mts.map +1 -0
- package/dist/fields-iagOozy0.mjs +115 -0
- package/dist/fields-iagOozy0.mjs.map +1 -0
- package/dist/hooks/index.d.mts +4 -0
- package/dist/hooks/index.mjs +3 -0
- package/dist/idempotency/index.d.mts +97 -0
- package/dist/idempotency/index.d.mts.map +1 -0
- package/dist/idempotency/index.mjs +320 -0
- package/dist/idempotency/index.mjs.map +1 -0
- package/dist/idempotency/mongodb.d.mts +2 -0
- package/dist/idempotency/mongodb.mjs +115 -0
- package/dist/idempotency/mongodb.mjs.map +1 -0
- package/dist/idempotency/redis.d.mts +2 -0
- package/dist/idempotency/redis.mjs +104 -0
- package/dist/idempotency/redis.mjs.map +1 -0
- package/dist/index.d.mts +261 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +105 -0
- package/dist/index.mjs.map +1 -0
- package/dist/integrations/event-gateway.d.mts +47 -0
- package/dist/integrations/event-gateway.d.mts.map +1 -0
- package/dist/integrations/event-gateway.mjs +44 -0
- package/dist/integrations/event-gateway.mjs.map +1 -0
- package/dist/integrations/index.d.mts +5 -0
- package/dist/integrations/index.mjs +1 -0
- package/dist/integrations/jobs.d.mts +104 -0
- package/dist/integrations/jobs.d.mts.map +1 -0
- package/dist/integrations/jobs.mjs +124 -0
- package/dist/integrations/jobs.mjs.map +1 -0
- package/dist/integrations/streamline.d.mts +61 -0
- package/dist/integrations/streamline.d.mts.map +1 -0
- package/dist/integrations/streamline.mjs +126 -0
- package/dist/integrations/streamline.mjs.map +1 -0
- package/dist/integrations/websocket.d.mts +83 -0
- package/dist/integrations/websocket.d.mts.map +1 -0
- package/dist/integrations/websocket.mjs +289 -0
- package/dist/integrations/websocket.mjs.map +1 -0
- package/dist/interface-B01JvPVc.d.mts +78 -0
- package/dist/interface-B01JvPVc.d.mts.map +1 -0
- package/dist/interface-CZe8IkMf.d.mts +55 -0
- package/dist/interface-CZe8IkMf.d.mts.map +1 -0
- package/dist/interface-Ch8HU9uM.d.mts +1098 -0
- package/dist/interface-Ch8HU9uM.d.mts.map +1 -0
- package/dist/introspectionPlugin-rFdO8ZUa.mjs +54 -0
- package/dist/introspectionPlugin-rFdO8ZUa.mjs.map +1 -0
- package/dist/keys-BqNejWup.mjs +43 -0
- package/dist/keys-BqNejWup.mjs.map +1 -0
- package/dist/logger-Df2O2WsW.mjs +79 -0
- package/dist/logger-Df2O2WsW.mjs.map +1 -0
- package/dist/memory-cQgelFOj.mjs +144 -0
- package/dist/memory-cQgelFOj.mjs.map +1 -0
- package/dist/migrations/index.d.mts +157 -0
- package/dist/migrations/index.d.mts.map +1 -0
- package/dist/migrations/index.mjs +261 -0
- package/dist/migrations/index.mjs.map +1 -0
- package/dist/mongodb-BfJVlUJH.mjs +94 -0
- package/dist/mongodb-BfJVlUJH.mjs.map +1 -0
- package/dist/mongodb-CGzRbfAK.d.mts +119 -0
- package/dist/mongodb-CGzRbfAK.d.mts.map +1 -0
- package/dist/mongodb-JN-9JA7K.d.mts +72 -0
- package/dist/mongodb-JN-9JA7K.d.mts.map +1 -0
- package/dist/openapi-G3Cw7XuM.mjs +524 -0
- package/dist/openapi-G3Cw7XuM.mjs.map +1 -0
- package/dist/org/index.d.mts +69 -0
- package/dist/org/index.d.mts.map +1 -0
- package/dist/org/index.mjs +514 -0
- package/dist/org/index.mjs.map +1 -0
- package/dist/org/types.d.mts +83 -0
- package/dist/org/types.d.mts.map +1 -0
- package/dist/org/types.mjs +1 -0
- package/dist/permissions/index.d.mts +279 -0
- package/dist/permissions/index.d.mts.map +1 -0
- package/dist/permissions/index.mjs +579 -0
- package/dist/permissions/index.mjs.map +1 -0
- package/dist/plugins/index.d.mts +173 -0
- package/dist/plugins/index.d.mts.map +1 -0
- package/dist/plugins/index.mjs +523 -0
- package/dist/plugins/index.mjs.map +1 -0
- package/dist/plugins/response-cache.d.mts +88 -0
- package/dist/plugins/response-cache.d.mts.map +1 -0
- package/dist/plugins/response-cache.mjs +284 -0
- package/dist/plugins/response-cache.mjs.map +1 -0
- package/dist/plugins/tracing-entry.d.mts +2 -0
- package/dist/plugins/tracing-entry.mjs +186 -0
- package/dist/plugins/tracing-entry.mjs.map +1 -0
- package/dist/pluralize-CEweyOEm.mjs +87 -0
- package/dist/pluralize-CEweyOEm.mjs.map +1 -0
- package/dist/policies/{index.d.ts → index.d.mts} +204 -169
- package/dist/policies/index.d.mts.map +1 -0
- package/dist/policies/index.mjs +322 -0
- package/dist/policies/index.mjs.map +1 -0
- package/dist/presets/{index.d.ts → index.d.mts} +63 -131
- package/dist/presets/index.d.mts.map +1 -0
- package/dist/presets/index.mjs +144 -0
- package/dist/presets/index.mjs.map +1 -0
- package/dist/presets/multiTenant.d.mts +25 -0
- package/dist/presets/multiTenant.d.mts.map +1 -0
- package/dist/presets/multiTenant.mjs +114 -0
- package/dist/presets/multiTenant.mjs.map +1 -0
- package/dist/presets-BITljm96.mjs +120 -0
- package/dist/presets-BITljm96.mjs.map +1 -0
- package/dist/presets-DzSMwlKj.d.mts +58 -0
- package/dist/presets-DzSMwlKj.d.mts.map +1 -0
- package/dist/prisma-DJbMt3yf.mjs +628 -0
- package/dist/prisma-DJbMt3yf.mjs.map +1 -0
- package/dist/prisma-Dg9GoVdj.d.mts +275 -0
- package/dist/prisma-Dg9GoVdj.d.mts.map +1 -0
- package/dist/queryCachePlugin-7THaI5mt.d.mts +72 -0
- package/dist/queryCachePlugin-7THaI5mt.d.mts.map +1 -0
- package/dist/queryCachePlugin-DMBnp2Q0.mjs +139 -0
- package/dist/queryCachePlugin-DMBnp2Q0.mjs.map +1 -0
- package/dist/redis-D-JAeLtm.d.mts +50 -0
- package/dist/redis-D-JAeLtm.d.mts.map +1 -0
- package/dist/redis-stream-Bdh_vUU8.d.mts +104 -0
- package/dist/redis-stream-Bdh_vUU8.d.mts.map +1 -0
- package/dist/registry/index.d.mts +12 -0
- package/dist/registry/index.d.mts.map +1 -0
- package/dist/registry/index.mjs +4 -0
- package/dist/requestContext-QQD6ROJc.mjs +56 -0
- package/dist/requestContext-QQD6ROJc.mjs.map +1 -0
- package/dist/schemaConverter-BwrmWroW.mjs +99 -0
- package/dist/schemaConverter-BwrmWroW.mjs.map +1 -0
- package/dist/schemas/index.d.mts +64 -0
- package/dist/schemas/index.d.mts.map +1 -0
- package/dist/schemas/index.mjs +83 -0
- package/dist/schemas/index.mjs.map +1 -0
- package/dist/scope/index.d.mts +22 -0
- package/dist/scope/index.d.mts.map +1 -0
- package/dist/scope/index.mjs +66 -0
- package/dist/scope/index.mjs.map +1 -0
- package/dist/sessionManager-jPKLbHE0.d.mts +187 -0
- package/dist/sessionManager-jPKLbHE0.d.mts.map +1 -0
- package/dist/sse-B3c3_yZp.mjs +124 -0
- package/dist/sse-B3c3_yZp.mjs.map +1 -0
- package/dist/testing/index.d.mts +908 -0
- package/dist/testing/index.d.mts.map +1 -0
- package/dist/testing/index.mjs +1977 -0
- package/dist/testing/index.mjs.map +1 -0
- package/dist/tracing-Cc7vVQPp.d.mts +71 -0
- package/dist/tracing-Cc7vVQPp.d.mts.map +1 -0
- package/dist/typeGuards-DhMNLuvU.mjs +10 -0
- package/dist/typeGuards-DhMNLuvU.mjs.map +1 -0
- package/dist/types/index.d.mts +947 -0
- package/dist/types/index.d.mts.map +1 -0
- package/dist/types/index.mjs +15 -0
- package/dist/types/index.mjs.map +1 -0
- package/dist/types-Beqn1Un7.mjs +39 -0
- package/dist/types-Beqn1Un7.mjs.map +1 -0
- package/dist/types-CIgB7UUl.d.mts +446 -0
- package/dist/types-CIgB7UUl.d.mts.map +1 -0
- package/dist/types-aYB4V7uN.d.mts +87 -0
- package/dist/types-aYB4V7uN.d.mts.map +1 -0
- package/dist/utils/index.d.mts +748 -0
- package/dist/utils/index.d.mts.map +1 -0
- package/dist/utils/index.mjs +6 -0
- package/package.json +194 -68
- package/dist/BaseController-DVAiHxEQ.d.ts +0 -233
- package/dist/adapters/index.d.ts +0 -237
- package/dist/adapters/index.js +0 -668
- package/dist/arcCorePlugin-CsShQdyP.d.ts +0 -273
- package/dist/audit/index.d.ts +0 -195
- package/dist/audit/index.js +0 -319
- package/dist/auth/index.d.ts +0 -47
- package/dist/auth/index.js +0 -174
- package/dist/cli/commands/docs.d.ts +0 -11
- package/dist/cli/commands/docs.js +0 -474
- package/dist/cli/commands/generate.js +0 -334
- package/dist/cli/commands/introspect.d.ts +0 -8
- package/dist/cli/commands/introspect.js +0 -338
- package/dist/cli/index.d.ts +0 -4
- package/dist/cli/index.js +0 -3269
- package/dist/core/index.d.ts +0 -220
- package/dist/core/index.js +0 -2786
- package/dist/createApp-Ce9wl8W9.d.ts +0 -77
- package/dist/docs/index.d.ts +0 -166
- package/dist/docs/index.js +0 -658
- package/dist/errors-8WIxGS_6.d.ts +0 -122
- package/dist/events/index.d.ts +0 -117
- package/dist/events/index.js +0 -89
- package/dist/factory/index.d.ts +0 -38
- package/dist/factory/index.js +0 -1652
- package/dist/hooks/index.d.ts +0 -4
- package/dist/hooks/index.js +0 -199
- package/dist/idempotency/index.d.ts +0 -323
- package/dist/idempotency/index.js +0 -500
- package/dist/index-B4t03KQ0.d.ts +0 -1366
- package/dist/index.d.ts +0 -135
- package/dist/index.js +0 -4756
- package/dist/migrations/index.d.ts +0 -185
- package/dist/migrations/index.js +0 -274
- package/dist/org/index.d.ts +0 -129
- package/dist/org/index.js +0 -220
- package/dist/permissions/index.d.ts +0 -144
- package/dist/permissions/index.js +0 -103
- package/dist/plugins/index.d.ts +0 -46
- package/dist/plugins/index.js +0 -1069
- package/dist/policies/index.js +0 -196
- package/dist/presets/index.js +0 -384
- package/dist/presets/multiTenant.d.ts +0 -39
- package/dist/presets/multiTenant.js +0 -112
- package/dist/registry/index.d.ts +0 -16
- package/dist/registry/index.js +0 -253
- package/dist/testing/index.d.ts +0 -618
- package/dist/testing/index.js +0 -48020
- package/dist/types/index.d.ts +0 -4
- package/dist/types/index.js +0 -8
- package/dist/types-B99TBmFV.d.ts +0 -76
- package/dist/types-BvckRbs2.d.ts +0 -143
- package/dist/utils/index.d.ts +0 -679
- package/dist/utils/index.js +0 -931
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
//#region src/constants.ts
|
|
2
|
+
/**
|
|
3
|
+
* Arc Framework Constants — Single Source of Truth
|
|
4
|
+
*
|
|
5
|
+
* Every default value, magic string, and framework constant lives here.
|
|
6
|
+
* Import from this module instead of hard-coding values inline.
|
|
7
|
+
*
|
|
8
|
+
* All exported values are deeply frozen (Object.freeze) to prevent
|
|
9
|
+
* accidental mutation at runtime — inspired by Go's const blocks
|
|
10
|
+
* and Rust's immutable-by-default philosophy.
|
|
11
|
+
*/
|
|
12
|
+
/** Standard CRUD operation names */
|
|
13
|
+
const CRUD_OPERATIONS = Object.freeze([
|
|
14
|
+
"list",
|
|
15
|
+
"get",
|
|
16
|
+
"create",
|
|
17
|
+
"update",
|
|
18
|
+
"delete"
|
|
19
|
+
]);
|
|
20
|
+
/** Mutation operations that emit events */
|
|
21
|
+
const MUTATION_OPERATIONS = Object.freeze([
|
|
22
|
+
"create",
|
|
23
|
+
"update",
|
|
24
|
+
"delete"
|
|
25
|
+
]);
|
|
26
|
+
/** Lifecycle hook phases */
|
|
27
|
+
const HOOK_PHASES = Object.freeze([
|
|
28
|
+
"before",
|
|
29
|
+
"around",
|
|
30
|
+
"after"
|
|
31
|
+
]);
|
|
32
|
+
/** Hook operations (superset of CRUD — includes 'read' alias for 'get') */
|
|
33
|
+
const HOOK_OPERATIONS = Object.freeze([
|
|
34
|
+
"create",
|
|
35
|
+
"update",
|
|
36
|
+
"delete",
|
|
37
|
+
"read",
|
|
38
|
+
"list"
|
|
39
|
+
]);
|
|
40
|
+
/** Default items per page */
|
|
41
|
+
const DEFAULT_LIMIT = 20;
|
|
42
|
+
/** Maximum items per page (framework-wide ceiling) */
|
|
43
|
+
const DEFAULT_MAX_LIMIT = 1e3;
|
|
44
|
+
/** Default sort field (descending creation date) */
|
|
45
|
+
const DEFAULT_SORT = "-createdAt";
|
|
46
|
+
/** Default primary key field name */
|
|
47
|
+
const DEFAULT_ID_FIELD = "_id";
|
|
48
|
+
/** Default multi-tenant scoping field */
|
|
49
|
+
const DEFAULT_TENANT_FIELD = "organizationId";
|
|
50
|
+
/** Default HTTP method for update routes */
|
|
51
|
+
const DEFAULT_UPDATE_METHOD = "PATCH";
|
|
52
|
+
/** System-managed fields that cannot be set via request body */
|
|
53
|
+
const SYSTEM_FIELDS = Object.freeze([
|
|
54
|
+
"_id",
|
|
55
|
+
"__v",
|
|
56
|
+
"createdAt",
|
|
57
|
+
"updatedAt",
|
|
58
|
+
"deletedAt"
|
|
59
|
+
]);
|
|
60
|
+
/** Maximum regex pattern length (ReDoS mitigation) */
|
|
61
|
+
const MAX_REGEX_LENGTH = 200;
|
|
62
|
+
/** Maximum search query length */
|
|
63
|
+
const MAX_SEARCH_LENGTH = 200;
|
|
64
|
+
/** Maximum filter nesting depth (prevents filter bombs) */
|
|
65
|
+
const MAX_FILTER_DEPTH = 10;
|
|
66
|
+
/**
|
|
67
|
+
* Query parameters consumed by the framework — never treated as filters.
|
|
68
|
+
* Shared by all query parsers (Arc built-in, Prisma, custom).
|
|
69
|
+
*/
|
|
70
|
+
const RESERVED_QUERY_PARAMS = Object.freeze(new Set([
|
|
71
|
+
"page",
|
|
72
|
+
"limit",
|
|
73
|
+
"sort",
|
|
74
|
+
"populate",
|
|
75
|
+
"search",
|
|
76
|
+
"select",
|
|
77
|
+
"after",
|
|
78
|
+
"cursor",
|
|
79
|
+
"lean",
|
|
80
|
+
"_policyFilters"
|
|
81
|
+
]));
|
|
82
|
+
|
|
83
|
+
//#endregion
|
|
84
|
+
export { DEFAULT_SORT as a, HOOK_OPERATIONS as c, MAX_REGEX_LENGTH as d, MAX_SEARCH_LENGTH as f, SYSTEM_FIELDS as h, DEFAULT_MAX_LIMIT as i, HOOK_PHASES as l, RESERVED_QUERY_PARAMS as m, DEFAULT_ID_FIELD as n, DEFAULT_TENANT_FIELD as o, MUTATION_OPERATIONS as p, DEFAULT_LIMIT as r, DEFAULT_UPDATE_METHOD as s, CRUD_OPERATIONS as t, MAX_FILTER_DEPTH as u };
|
|
85
|
+
//# sourceMappingURL=constants-DdXFXQtN.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants-DdXFXQtN.mjs","names":[],"sources":["../src/constants.ts"],"sourcesContent":["/**\n * Arc Framework Constants — Single Source of Truth\n *\n * Every default value, magic string, and framework constant lives here.\n * Import from this module instead of hard-coding values inline.\n *\n * All exported values are deeply frozen (Object.freeze) to prevent\n * accidental mutation at runtime — inspired by Go's const blocks\n * and Rust's immutable-by-default philosophy.\n */\n\n// ============================================================================\n// CRUD Operations\n// ============================================================================\n\n/** Standard CRUD operation names */\nexport const CRUD_OPERATIONS = Object.freeze(\n ['list', 'get', 'create', 'update', 'delete'] as const,\n);\nexport type CrudOperation = (typeof CRUD_OPERATIONS)[number];\n\n/** Mutation operations that emit events */\nexport const MUTATION_OPERATIONS = Object.freeze(\n ['create', 'update', 'delete'] as const,\n);\nexport type MutationOperation = (typeof MUTATION_OPERATIONS)[number];\n\n// ============================================================================\n// Hook Phases\n// ============================================================================\n\n/** Lifecycle hook phases */\nexport const HOOK_PHASES = Object.freeze(\n ['before', 'around', 'after'] as const,\n);\nexport type HookPhase = (typeof HOOK_PHASES)[number];\n\n/** Hook operations (superset of CRUD — includes 'read' alias for 'get') */\nexport const HOOK_OPERATIONS = Object.freeze(\n ['create', 'update', 'delete', 'read', 'list'] as const,\n);\nexport type HookOperation = (typeof HOOK_OPERATIONS)[number];\n\n// ============================================================================\n// Pagination & Query Defaults\n// ============================================================================\n\n/** Default items per page */\nexport const DEFAULT_LIMIT = 20 as const;\n\n/** Maximum items per page (framework-wide ceiling) */\nexport const DEFAULT_MAX_LIMIT = 1000 as const;\n\n/** Default sort field (descending creation date) */\nexport const DEFAULT_SORT = '-createdAt' as const;\n\n// ============================================================================\n// Field & Schema Defaults\n// ============================================================================\n\n/** Default primary key field name */\nexport const DEFAULT_ID_FIELD = '_id' as const;\n\n/** Default multi-tenant scoping field */\nexport const DEFAULT_TENANT_FIELD = 'organizationId' as const;\n\n/** Default HTTP method for update routes */\nexport const DEFAULT_UPDATE_METHOD = 'PATCH' as const;\n\n/** System-managed fields that cannot be set via request body */\nexport const SYSTEM_FIELDS = Object.freeze(\n ['_id', '__v', 'createdAt', 'updatedAt', 'deletedAt'] as const,\n);\n\n// ============================================================================\n// Security Limits\n// ============================================================================\n\n/** Maximum regex pattern length (ReDoS mitigation) */\nexport const MAX_REGEX_LENGTH = 200 as const;\n\n/** Maximum search query length */\nexport const MAX_SEARCH_LENGTH = 200 as const;\n\n/** Maximum filter nesting depth (prevents filter bombs) */\nexport const MAX_FILTER_DEPTH = 10 as const;\n\n// ============================================================================\n// Reserved Query Parameters\n// ============================================================================\n\n/**\n * Query parameters consumed by the framework — never treated as filters.\n * Shared by all query parsers (Arc built-in, Prisma, custom).\n */\nexport const RESERVED_QUERY_PARAMS = Object.freeze(\n new Set([\n 'page',\n 'limit',\n 'sort',\n 'populate',\n 'search',\n 'select',\n 'after',\n 'cursor',\n 'lean',\n '_policyFilters',\n ]),\n);\n"],"mappings":";;;;;;;;;;;;AAgBA,MAAa,kBAAkB,OAAO,OACpC;CAAC;CAAQ;CAAO;CAAU;CAAU;CAAS,CAC9C;;AAID,MAAa,sBAAsB,OAAO,OACxC;CAAC;CAAU;CAAU;CAAS,CAC/B;;AAQD,MAAa,cAAc,OAAO,OAChC;CAAC;CAAU;CAAU;CAAQ,CAC9B;;AAID,MAAa,kBAAkB,OAAO,OACpC;CAAC;CAAU;CAAU;CAAU;CAAQ;CAAO,CAC/C;;AAQD,MAAa,gBAAgB;;AAG7B,MAAa,oBAAoB;;AAGjC,MAAa,eAAe;;AAO5B,MAAa,mBAAmB;;AAGhC,MAAa,uBAAuB;;AAGpC,MAAa,wBAAwB;;AAGrC,MAAa,gBAAgB,OAAO,OAClC;CAAC;CAAO;CAAO;CAAa;CAAa;CAAY,CACtD;;AAOD,MAAa,mBAAmB;;AAGhC,MAAa,oBAAoB;;AAGjC,MAAa,mBAAmB;;;;;AAUhC,MAAa,wBAAwB,OAAO,OAC1C,IAAI,IAAI;CACN;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC,CACH"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import "../elevation-B_2dRLVP.mjs";
|
|
2
|
+
import { E as defineResource, T as ResourceDefinition, c as BaseController, d as QueryResolverConfig, f as BodySanitizer, h as AccessControlConfig, l as BaseControllerOptions, m as AccessControl, p as BodySanitizerConfig, u as QueryResolver } from "../interface-Ch8HU9uM.mjs";
|
|
3
|
+
import "../types-aYB4V7uN.mjs";
|
|
4
|
+
import { A as createCrudRouter, C as MutationOperation, D as ActionRouterConfig, E as ActionHandler, O as IdempotencyService, S as MUTATION_OPERATIONS, T as SYSTEM_FIELDS, _ as HookOperation, a as getControllerScope, b as MAX_REGEX_LENGTH, c as CrudOperation, d as DEFAULT_MAX_LIMIT, f as DEFAULT_SORT, g as HOOK_PHASES, h as HOOK_OPERATIONS, i as getControllerContext, j as createPermissionMiddleware, k as createActionRouter, l as DEFAULT_ID_FIELD, m as DEFAULT_UPDATE_METHOD, n as createFastifyHandler, o as sendControllerResponse, p as DEFAULT_TENANT_FIELD, r as createRequestContext, s as CRUD_OPERATIONS, t as createCrudHandlers, u as DEFAULT_LIMIT, v as HookPhase, w as RESERVED_QUERY_PARAMS, x as MAX_SEARCH_LENGTH, y as MAX_FILTER_DEPTH } from "../fastifyAdapter-BkrGrlFi.mjs";
|
|
5
|
+
export { AccessControl, type AccessControlConfig, type ActionHandler, type ActionRouterConfig, BaseController, type BaseControllerOptions, BodySanitizer, type BodySanitizerConfig, CRUD_OPERATIONS, CrudOperation, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, HOOK_OPERATIONS, HOOK_PHASES, HookOperation, HookPhase, type IdempotencyService, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, MutationOperation, QueryResolver, type QueryResolverConfig, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, createActionRouter, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineResource, getControllerContext, getControllerScope, sendControllerResponse };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { a as DEFAULT_SORT, c as HOOK_OPERATIONS, d as MAX_REGEX_LENGTH, f as MAX_SEARCH_LENGTH, h as SYSTEM_FIELDS, i as DEFAULT_MAX_LIMIT, l as HOOK_PHASES, m as RESERVED_QUERY_PARAMS, n as DEFAULT_ID_FIELD, o as DEFAULT_TENANT_FIELD, p as MUTATION_OPERATIONS, r as DEFAULT_LIMIT, s as DEFAULT_UPDATE_METHOD, t as CRUD_OPERATIONS, u as MAX_FILTER_DEPTH } from "../constants-DdXFXQtN.mjs";
|
|
2
|
+
import { _ as QueryResolver, c as createPermissionMiddleware, d as createFastifyHandler, f as createRequestContext, g as BaseController, h as sendControllerResponse, m as getControllerScope, n as defineResource, o as createActionRouter, p as getControllerContext, s as createCrudRouter, t as ResourceDefinition, u as createCrudHandlers, v as BodySanitizer, y as AccessControl } from "../defineResource-k0_BDn8v.mjs";
|
|
3
|
+
|
|
4
|
+
export { AccessControl, BaseController, BodySanitizer, CRUD_OPERATIONS, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, HOOK_OPERATIONS, HOOK_PHASES, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, QueryResolver, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, createActionRouter, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineResource, getControllerContext, getControllerScope, sendControllerResponse };
|
|
@@ -0,0 +1,560 @@
|
|
|
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-Df2O2WsW.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-DGR_B2on.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-Bl28lYsR.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-DMBnp2Q0.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-cQgelFOj.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-B3c3_yZp.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-BRy3yFWT.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-C1okiriz.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 };
|
|
560
|
+
//# sourceMappingURL=createApp-CUgNqegw.mjs.map
|