@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,250 @@
|
|
|
1
|
+
import { s as DEFAULT_UPDATE_METHOD, t as CRUD_OPERATIONS } from "./constants-DdXFXQtN.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/registry/ResourceRegistry.ts
|
|
4
|
+
var ResourceRegistry = class {
|
|
5
|
+
_resources;
|
|
6
|
+
_frozen;
|
|
7
|
+
constructor() {
|
|
8
|
+
this._resources = /* @__PURE__ */ new Map();
|
|
9
|
+
this._frozen = false;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Register a resource
|
|
13
|
+
*/
|
|
14
|
+
register(resource, options = {}) {
|
|
15
|
+
if (this._frozen) throw new Error(`Registry frozen. Cannot register '${resource.name}' after startup.`);
|
|
16
|
+
if (this._resources.has(resource.name)) throw new Error(`Resource '${resource.name}' already registered.`);
|
|
17
|
+
const entry = {
|
|
18
|
+
name: resource.name,
|
|
19
|
+
displayName: resource.displayName,
|
|
20
|
+
tag: resource.tag,
|
|
21
|
+
prefix: resource.prefix,
|
|
22
|
+
module: options.module ?? void 0,
|
|
23
|
+
adapter: resource.adapter ? {
|
|
24
|
+
type: resource.adapter.type,
|
|
25
|
+
name: resource.adapter.name
|
|
26
|
+
} : null,
|
|
27
|
+
permissions: resource.permissions,
|
|
28
|
+
presets: resource._appliedPresets ?? [],
|
|
29
|
+
routes: [],
|
|
30
|
+
additionalRoutes: resource.additionalRoutes.map((r) => ({
|
|
31
|
+
method: r.method,
|
|
32
|
+
path: r.path,
|
|
33
|
+
handler: typeof r.handler === "string" ? r.handler : r.handler.name || "anonymous",
|
|
34
|
+
operation: r.operation,
|
|
35
|
+
summary: r.summary,
|
|
36
|
+
description: r.description,
|
|
37
|
+
permissions: r.permissions,
|
|
38
|
+
wrapHandler: r.wrapHandler,
|
|
39
|
+
schema: r.schema
|
|
40
|
+
})),
|
|
41
|
+
events: Object.keys(resource.events ?? {}),
|
|
42
|
+
registeredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
43
|
+
disableDefaultRoutes: resource.disableDefaultRoutes,
|
|
44
|
+
updateMethod: resource.updateMethod,
|
|
45
|
+
disabledRoutes: resource.disabledRoutes,
|
|
46
|
+
openApiSchemas: options.openApiSchemas,
|
|
47
|
+
fieldPermissions: extractFieldPermissions(resource.fields),
|
|
48
|
+
pipelineSteps: extractPipelineSteps(resource.pipe),
|
|
49
|
+
rateLimit: resource.rateLimit,
|
|
50
|
+
plugin: resource.toPlugin()
|
|
51
|
+
};
|
|
52
|
+
this._resources.set(resource.name, entry);
|
|
53
|
+
return this;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Get resource by name
|
|
57
|
+
*/
|
|
58
|
+
get(name) {
|
|
59
|
+
return this._resources.get(name);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Get all resources
|
|
63
|
+
*/
|
|
64
|
+
getAll() {
|
|
65
|
+
return Array.from(this._resources.values());
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Get resources by module
|
|
69
|
+
*/
|
|
70
|
+
getByModule(moduleName) {
|
|
71
|
+
return this.getAll().filter((r) => r.module === moduleName);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Get resources by preset
|
|
75
|
+
*/
|
|
76
|
+
getByPreset(presetName) {
|
|
77
|
+
return this.getAll().filter((r) => r.presets.includes(presetName));
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Check if resource exists
|
|
81
|
+
*/
|
|
82
|
+
has(name) {
|
|
83
|
+
return this._resources.has(name);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Get registry statistics
|
|
87
|
+
*/
|
|
88
|
+
getStats() {
|
|
89
|
+
const resources = this.getAll();
|
|
90
|
+
const presetCounts = {};
|
|
91
|
+
for (const r of resources) for (const preset of r.presets) presetCounts[preset] = (presetCounts[preset] ?? 0) + 1;
|
|
92
|
+
return {
|
|
93
|
+
totalResources: resources.length,
|
|
94
|
+
byModule: this._groupBy(resources, "module"),
|
|
95
|
+
presetUsage: presetCounts,
|
|
96
|
+
totalRoutes: resources.reduce((sum, r) => {
|
|
97
|
+
if (r.disableDefaultRoutes) return sum + (r.additionalRoutes?.length ?? 0);
|
|
98
|
+
const disabledSet = new Set(r.disabledRoutes ?? []);
|
|
99
|
+
let defaultCount = CRUD_OPERATIONS.filter((route) => !disabledSet.has(route)).length;
|
|
100
|
+
if (!disabledSet.has("update") && r.updateMethod === "both") defaultCount += 1;
|
|
101
|
+
return sum + defaultCount + (r.additionalRoutes?.length ?? 0);
|
|
102
|
+
}, 0),
|
|
103
|
+
totalEvents: resources.reduce((sum, r) => sum + (r.events?.length ?? 0), 0)
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Get full introspection data
|
|
108
|
+
*/
|
|
109
|
+
getIntrospection() {
|
|
110
|
+
return {
|
|
111
|
+
resources: this.getAll().map((r) => {
|
|
112
|
+
const disabledSet = new Set(r.disabledRoutes ?? []);
|
|
113
|
+
const updateMethod = r.updateMethod ?? DEFAULT_UPDATE_METHOD;
|
|
114
|
+
const defaultRoutes = r.disableDefaultRoutes ? [] : [
|
|
115
|
+
...!disabledSet.has("list") ? [{
|
|
116
|
+
method: "GET",
|
|
117
|
+
path: r.prefix,
|
|
118
|
+
operation: "list"
|
|
119
|
+
}] : [],
|
|
120
|
+
...!disabledSet.has("get") ? [{
|
|
121
|
+
method: "GET",
|
|
122
|
+
path: `${r.prefix}/:id`,
|
|
123
|
+
operation: "get"
|
|
124
|
+
}] : [],
|
|
125
|
+
...!disabledSet.has("create") ? [{
|
|
126
|
+
method: "POST",
|
|
127
|
+
path: r.prefix,
|
|
128
|
+
operation: "create"
|
|
129
|
+
}] : [],
|
|
130
|
+
...!disabledSet.has("update") ? updateMethod === "both" ? [{
|
|
131
|
+
method: "PUT",
|
|
132
|
+
path: `${r.prefix}/:id`,
|
|
133
|
+
operation: "update"
|
|
134
|
+
}, {
|
|
135
|
+
method: "PATCH",
|
|
136
|
+
path: `${r.prefix}/:id`,
|
|
137
|
+
operation: "update"
|
|
138
|
+
}] : [{
|
|
139
|
+
method: updateMethod,
|
|
140
|
+
path: `${r.prefix}/:id`,
|
|
141
|
+
operation: "update"
|
|
142
|
+
}] : [],
|
|
143
|
+
...!disabledSet.has("delete") ? [{
|
|
144
|
+
method: "DELETE",
|
|
145
|
+
path: `${r.prefix}/:id`,
|
|
146
|
+
operation: "delete"
|
|
147
|
+
}] : []
|
|
148
|
+
];
|
|
149
|
+
return {
|
|
150
|
+
name: r.name,
|
|
151
|
+
displayName: r.displayName,
|
|
152
|
+
prefix: r.prefix,
|
|
153
|
+
module: r.module,
|
|
154
|
+
presets: r.presets,
|
|
155
|
+
permissions: r.permissions,
|
|
156
|
+
routes: [...defaultRoutes, ...r.additionalRoutes?.map((ar) => ({
|
|
157
|
+
method: ar.method,
|
|
158
|
+
path: `${r.prefix}${ar.path}`,
|
|
159
|
+
operation: ar.operation ?? (typeof ar.handler === "string" ? ar.handler : "custom"),
|
|
160
|
+
handler: typeof ar.handler === "string" ? ar.handler : void 0,
|
|
161
|
+
summary: ar.summary
|
|
162
|
+
})) ?? []],
|
|
163
|
+
events: r.events
|
|
164
|
+
};
|
|
165
|
+
}),
|
|
166
|
+
stats: this.getStats(),
|
|
167
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Freeze registry (prevent further registrations)
|
|
172
|
+
*/
|
|
173
|
+
freeze() {
|
|
174
|
+
this._frozen = true;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Check if frozen
|
|
178
|
+
*/
|
|
179
|
+
isFrozen() {
|
|
180
|
+
return this._frozen;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Unfreeze registry (allow new registrations)
|
|
184
|
+
*/
|
|
185
|
+
unfreeze() {
|
|
186
|
+
this._frozen = false;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Reset registry — clear all resources and unfreeze
|
|
190
|
+
*/
|
|
191
|
+
reset() {
|
|
192
|
+
this._resources.clear();
|
|
193
|
+
this._frozen = false;
|
|
194
|
+
}
|
|
195
|
+
/** @internal Alias for unfreeze() */
|
|
196
|
+
_unfreeze() {
|
|
197
|
+
this.unfreeze();
|
|
198
|
+
}
|
|
199
|
+
/** @internal Alias for reset() */
|
|
200
|
+
_clear() {
|
|
201
|
+
this.reset();
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Group by key
|
|
205
|
+
*/
|
|
206
|
+
_groupBy(arr, key) {
|
|
207
|
+
const result = {};
|
|
208
|
+
for (const item of arr) {
|
|
209
|
+
const k = String(item[key] ?? "uncategorized");
|
|
210
|
+
result[k] = (result[k] ?? 0) + 1;
|
|
211
|
+
}
|
|
212
|
+
return result;
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
function extractFieldPermissions(fields) {
|
|
216
|
+
if (!fields || Object.keys(fields).length === 0) return void 0;
|
|
217
|
+
const result = {};
|
|
218
|
+
for (const [field, perm] of Object.entries(fields)) {
|
|
219
|
+
const entry = { type: perm._type };
|
|
220
|
+
if (perm.roles?.length) entry.roles = perm.roles;
|
|
221
|
+
if (perm.redactValue !== void 0) entry.redactValue = perm.redactValue;
|
|
222
|
+
result[field] = entry;
|
|
223
|
+
}
|
|
224
|
+
return result;
|
|
225
|
+
}
|
|
226
|
+
function extractPipelineSteps(pipe) {
|
|
227
|
+
if (!pipe) return void 0;
|
|
228
|
+
const steps = [];
|
|
229
|
+
if (Array.isArray(pipe)) steps.push(...pipe);
|
|
230
|
+
else {
|
|
231
|
+
const seen = /* @__PURE__ */ new Set();
|
|
232
|
+
for (const opSteps of Object.values(pipe)) if (Array.isArray(opSteps)) for (const step of opSteps) {
|
|
233
|
+
const key = `${step._type}:${step.name}`;
|
|
234
|
+
if (!seen.has(key)) {
|
|
235
|
+
seen.add(key);
|
|
236
|
+
steps.push(step);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (steps.length === 0) return void 0;
|
|
241
|
+
return steps.map((s) => ({
|
|
242
|
+
type: s._type,
|
|
243
|
+
name: s.name,
|
|
244
|
+
operations: s.operations ? [...s.operations] : void 0
|
|
245
|
+
}));
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
//#endregion
|
|
249
|
+
export { ResourceRegistry as t };
|
|
250
|
+
//# sourceMappingURL=ResourceRegistry-DsN4KJjV.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ResourceRegistry-DsN4KJjV.mjs","names":[],"sources":["../src/registry/ResourceRegistry.ts"],"sourcesContent":["/**\n * Resource Registry\n *\n * Singleton that tracks all registered resources for introspection.\n */\n\nimport type {\n IntrospectionData,\n OpenApiSchemas,\n RegistryEntry,\n RegistryStats,\n ResourcePermissions,\n} from '../types/index.js';\nimport type { ResourceDefinition } from '../core/defineResource.js';\nimport type { FieldPermissionMap } from '../permissions/fields.js';\nimport type { PipelineConfig, PipelineStep } from '../pipeline/types.js';\nimport { CRUD_OPERATIONS, DEFAULT_UPDATE_METHOD } from '../constants.js';\n\nexport interface RegisterOptions {\n module?: string;\n /** Pre-generated OpenAPI schemas */\n openApiSchemas?: OpenApiSchemas;\n}\n\nexport class ResourceRegistry {\n private _resources: Map<string, RegistryEntry>;\n private _frozen: boolean;\n\n constructor() {\n this._resources = new Map();\n this._frozen = false;\n }\n\n /**\n * Register a resource\n */\n register(resource: ResourceDefinition<unknown>, options: RegisterOptions = {}): this {\n if (this._frozen) {\n throw new Error(\n `Registry frozen. Cannot register '${resource.name}' after startup.`\n );\n }\n\n if (this._resources.has(resource.name)) {\n throw new Error(`Resource '${resource.name}' already registered.`);\n }\n\n const entry: RegistryEntry = {\n name: resource.name,\n displayName: resource.displayName,\n tag: resource.tag,\n prefix: resource.prefix,\n module: options.module ?? undefined,\n adapter: resource.adapter\n ? {\n type: resource.adapter.type,\n name: resource.adapter.name,\n }\n : null,\n permissions: resource.permissions as ResourcePermissions | undefined,\n presets: resource._appliedPresets ?? [],\n routes: [], // Populated later by getIntrospection()\n additionalRoutes: resource.additionalRoutes.map((r) => ({\n method: r.method,\n path: r.path,\n handler:\n typeof r.handler === 'string'\n ? r.handler\n : (r.handler as Function).name || 'anonymous',\n operation: r.operation,\n summary: r.summary,\n description: r.description,\n permissions: r.permissions,\n wrapHandler: r.wrapHandler,\n schema: r.schema, // Include schema for OpenAPI docs\n })),\n events: Object.keys(resource.events ?? {}),\n registeredAt: new Date().toISOString(),\n disableDefaultRoutes: resource.disableDefaultRoutes,\n updateMethod: resource.updateMethod,\n disabledRoutes: resource.disabledRoutes,\n openApiSchemas: options.openApiSchemas,\n fieldPermissions: extractFieldPermissions(resource.fields),\n pipelineSteps: extractPipelineSteps(resource.pipe),\n rateLimit: resource.rateLimit,\n plugin: resource.toPlugin(), // Store plugin factory\n };\n\n this._resources.set(resource.name, entry);\n return this;\n }\n\n /**\n * Get resource by name\n */\n get(name: string): RegistryEntry | undefined {\n return this._resources.get(name);\n }\n\n /**\n * Get all resources\n */\n getAll(): RegistryEntry[] {\n return Array.from(this._resources.values());\n }\n\n /**\n * Get resources by module\n */\n getByModule(moduleName: string): RegistryEntry[] {\n return this.getAll().filter((r) => r.module === moduleName);\n }\n\n /**\n * Get resources by preset\n */\n getByPreset(presetName: string): RegistryEntry[] {\n return this.getAll().filter((r) => r.presets.includes(presetName));\n }\n\n /**\n * Check if resource exists\n */\n has(name: string): boolean {\n return this._resources.has(name);\n }\n\n /**\n * Get registry statistics\n */\n getStats(): RegistryStats {\n const resources = this.getAll();\n const presetCounts: Record<string, number> = {};\n\n for (const r of resources) {\n for (const preset of r.presets) {\n presetCounts[preset] = (presetCounts[preset] ?? 0) + 1;\n }\n }\n\n return {\n totalResources: resources.length,\n byModule: this._groupBy(resources, 'module'),\n presetUsage: presetCounts,\n totalRoutes: resources.reduce((sum, r) => {\n if (r.disableDefaultRoutes) {\n return sum + (r.additionalRoutes?.length ?? 0);\n }\n const disabledSet = new Set(r.disabledRoutes ?? []);\n let defaultCount = CRUD_OPERATIONS.filter(route => !disabledSet.has(route)).length;\n // 'update' creates 2 routes when updateMethod is 'both' (PUT + PATCH)\n if (!disabledSet.has('update') && r.updateMethod === 'both') {\n defaultCount += 1;\n }\n return sum + defaultCount + (r.additionalRoutes?.length ?? 0);\n }, 0),\n totalEvents: resources.reduce((sum, r) => sum + (r.events?.length ?? 0), 0),\n };\n }\n\n /**\n * Get full introspection data\n */\n getIntrospection(): IntrospectionData {\n return {\n resources: this.getAll().map((r) => {\n // Build default routes accounting for disabledRoutes and updateMethod\n const disabledSet = new Set(r.disabledRoutes ?? []);\n const updateMethod = r.updateMethod ?? DEFAULT_UPDATE_METHOD;\n const defaultRoutes = r.disableDefaultRoutes ? [] : [\n ...(!disabledSet.has('list') ? [{ method: 'GET', path: r.prefix, operation: 'list' }] : []),\n ...(!disabledSet.has('get') ? [{ method: 'GET', path: `${r.prefix}/:id`, operation: 'get' }] : []),\n ...(!disabledSet.has('create') ? [{ method: 'POST', path: r.prefix, operation: 'create' }] : []),\n ...(!disabledSet.has('update') ? (\n updateMethod === 'both'\n ? [\n { method: 'PUT', path: `${r.prefix}/:id`, operation: 'update' },\n { method: 'PATCH', path: `${r.prefix}/:id`, operation: 'update' },\n ]\n : [{ method: updateMethod, path: `${r.prefix}/:id`, operation: 'update' }]\n ) : []),\n ...(!disabledSet.has('delete') ? [{ method: 'DELETE', path: `${r.prefix}/:id`, operation: 'delete' }] : []),\n ];\n\n return {\n name: r.name,\n displayName: r.displayName,\n prefix: r.prefix,\n module: r.module,\n presets: r.presets,\n permissions: r.permissions,\n routes: [\n ...defaultRoutes,\n ...(r.additionalRoutes?.map((ar) => ({\n method: ar.method,\n path: `${r.prefix}${ar.path}`,\n operation: ar.operation ?? (typeof ar.handler === 'string' ? ar.handler : 'custom'),\n handler: typeof ar.handler === 'string' ? ar.handler : undefined,\n summary: ar.summary,\n })) ?? []),\n ],\n events: r.events,\n };\n }),\n stats: this.getStats(),\n generatedAt: new Date().toISOString(),\n };\n }\n\n /**\n * Freeze registry (prevent further registrations)\n */\n freeze(): void {\n this._frozen = true;\n }\n\n /**\n * Check if frozen\n */\n isFrozen(): boolean {\n return this._frozen;\n }\n\n /**\n * Unfreeze registry (allow new registrations)\n */\n unfreeze(): void {\n this._frozen = false;\n }\n\n /**\n * Reset registry — clear all resources and unfreeze\n */\n reset(): void {\n this._resources.clear();\n this._frozen = false;\n }\n\n /** @internal Alias for unfreeze() */\n _unfreeze(): void {\n this.unfreeze();\n }\n\n /** @internal Alias for reset() */\n _clear(): void {\n this.reset();\n }\n\n /**\n * Group by key\n */\n private _groupBy(\n arr: RegistryEntry[],\n key: keyof RegistryEntry\n ): Record<string, number> {\n const result: Record<string, number> = {};\n for (const item of arr) {\n const k = String(item[key] ?? 'uncategorized');\n result[k] = (result[k] ?? 0) + 1;\n }\n return result;\n }\n}\n\nexport default ResourceRegistry;\n\n// ---------------------------------------------------------------------------\n// Helpers for extracting v2.0 metadata\n// ---------------------------------------------------------------------------\n\nfunction extractFieldPermissions(\n fields?: FieldPermissionMap,\n): RegistryEntry['fieldPermissions'] {\n if (!fields || Object.keys(fields).length === 0) return undefined;\n\n const result: NonNullable<RegistryEntry['fieldPermissions']> = {};\n for (const [field, perm] of Object.entries(fields)) {\n const entry: { type: string; roles?: readonly string[]; redactValue?: unknown } = {\n type: perm._type,\n };\n if (perm.roles?.length) entry.roles = perm.roles;\n if (perm.redactValue !== undefined) entry.redactValue = perm.redactValue;\n result[field] = entry;\n }\n return result;\n}\n\nfunction extractPipelineSteps(\n pipe?: PipelineConfig,\n): RegistryEntry['pipelineSteps'] {\n if (!pipe) return undefined;\n\n const steps: PipelineStep[] = [];\n if (Array.isArray(pipe)) {\n steps.push(...pipe);\n } else {\n const seen = new Set<string>();\n for (const opSteps of Object.values(pipe)) {\n if (Array.isArray(opSteps)) {\n for (const step of opSteps) {\n const key = `${step._type}:${step.name}`;\n if (!seen.has(key)) {\n seen.add(key);\n steps.push(step);\n }\n }\n }\n }\n }\n\n if (steps.length === 0) return undefined;\n\n return steps.map((s) => ({\n type: s._type,\n name: s.name,\n operations: s.operations ? [...s.operations] : undefined,\n }));\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import "../elevation-B_2dRLVP.mjs";
|
|
2
|
+
import { a as RepositoryLike, i as RelationMetadata, n as DataAdapter, o as SchemaMetadata, r as FieldMetadata, s as ValidationResult, t as AdapterFactory } from "../interface-Ch8HU9uM.mjs";
|
|
3
|
+
import "../types-aYB4V7uN.mjs";
|
|
4
|
+
import { a as PrismaQueryParserOptions, c as MongooseAdapterOptions, i as PrismaQueryParser, l as createMongooseAdapter, n as PrismaAdapterOptions, o as createPrismaAdapter, r as PrismaQueryOptions, s as MongooseAdapter, t as PrismaAdapter } from "../prisma-Dg9GoVdj.mjs";
|
|
5
|
+
export { type AdapterFactory, type DataAdapter, type FieldMetadata, MongooseAdapter, type MongooseAdapterOptions, PrismaAdapter, type PrismaAdapterOptions, type PrismaQueryOptions, PrismaQueryParser, type PrismaQueryParserOptions, type RelationMetadata, type RepositoryLike, type SchemaMetadata, type ValidationResult, createMongooseAdapter, createPrismaAdapter };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import "../elevation-B_2dRLVP.mjs";
|
|
2
|
+
import "../interface-Ch8HU9uM.mjs";
|
|
3
|
+
import "../types-aYB4V7uN.mjs";
|
|
4
|
+
import { a as AuditContext, c as AuditStore, i as AuditAction, l as AuditStoreOptions, n as MongoAuditStoreOptions, o as AuditEntry, r as MongoConnection, s as AuditQueryOptions, u as createAuditEntry } from "../mongodb-CGzRbfAK.mjs";
|
|
5
|
+
import { FastifyPluginAsync } from "fastify";
|
|
6
|
+
|
|
7
|
+
//#region src/audit/auditPlugin.d.ts
|
|
8
|
+
interface AuditPluginOptions {
|
|
9
|
+
/** Enable audit logging (default: false) */
|
|
10
|
+
enabled?: boolean;
|
|
11
|
+
/** Storage backends to use */
|
|
12
|
+
stores?: ('memory' | 'mongodb')[];
|
|
13
|
+
/** MongoDB connection (required if using mongodb store) */
|
|
14
|
+
mongoConnection?: MongoConnection;
|
|
15
|
+
/** MongoDB collection name (default: 'audit_logs') */
|
|
16
|
+
mongoCollection?: string;
|
|
17
|
+
/** TTL in days for MongoDB (default: 90) */
|
|
18
|
+
ttlDays?: number;
|
|
19
|
+
/** Custom stores (advanced) */
|
|
20
|
+
customStores?: AuditStore[];
|
|
21
|
+
/**
|
|
22
|
+
* Automatically audit CRUD operations via the hook system (default: true when enabled).
|
|
23
|
+
* When enabled, create/update/delete operations are auto-logged without manual calls.
|
|
24
|
+
*
|
|
25
|
+
* - `true`: Auto-audit all CRUD operations on all resources
|
|
26
|
+
* - `{ operations: ['create', 'delete'] }`: Only auto-audit specific operations
|
|
27
|
+
* - `{ exclude: ['health', 'metrics'] }`: Skip specific resources
|
|
28
|
+
* - `false`: Disable auto-audit (manual calls only)
|
|
29
|
+
*/
|
|
30
|
+
autoAudit?: boolean | {
|
|
31
|
+
operations?: ('create' | 'update' | 'delete')[];
|
|
32
|
+
exclude?: string[];
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
declare module 'fastify' {
|
|
36
|
+
interface FastifyInstance {
|
|
37
|
+
/** Log an audit entry */
|
|
38
|
+
audit: AuditLogger;
|
|
39
|
+
}
|
|
40
|
+
interface FastifyRequest {
|
|
41
|
+
/** Audit context for current request */
|
|
42
|
+
auditContext?: AuditContext;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
interface AuditLogger {
|
|
46
|
+
/** Log a create action */
|
|
47
|
+
create: (resource: string, documentId: string, data: Record<string, unknown>, context?: AuditContext) => Promise<void>;
|
|
48
|
+
/** Log an update action */
|
|
49
|
+
update: (resource: string, documentId: string, before: Record<string, unknown>, after: Record<string, unknown>, context?: AuditContext) => Promise<void>;
|
|
50
|
+
/** Log a delete action */
|
|
51
|
+
delete: (resource: string, documentId: string, data: Record<string, unknown>, context?: AuditContext) => Promise<void>;
|
|
52
|
+
/** Log a restore action (soft delete undo) */
|
|
53
|
+
restore: (resource: string, documentId: string, data: Record<string, unknown>, context?: AuditContext) => Promise<void>;
|
|
54
|
+
/** Log a custom action */
|
|
55
|
+
custom: (resource: string, documentId: string, action: string, data?: Record<string, unknown>, context?: AuditContext) => Promise<void>;
|
|
56
|
+
/** Query audit logs (if stores support it) */
|
|
57
|
+
query: (options: AuditQueryOptions) => Promise<AuditEntry[]>;
|
|
58
|
+
}
|
|
59
|
+
declare const auditPlugin: FastifyPluginAsync<AuditPluginOptions>;
|
|
60
|
+
declare const _default: FastifyPluginAsync<AuditPluginOptions>;
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region src/audit/stores/memory.d.ts
|
|
63
|
+
interface MemoryAuditStoreOptions {
|
|
64
|
+
/** Maximum entries to keep (default: 1000) */
|
|
65
|
+
maxEntries?: number;
|
|
66
|
+
}
|
|
67
|
+
declare class MemoryAuditStore implements AuditStore {
|
|
68
|
+
readonly name = "memory";
|
|
69
|
+
private entries;
|
|
70
|
+
private maxEntries;
|
|
71
|
+
constructor(options?: MemoryAuditStoreOptions);
|
|
72
|
+
log(entry: AuditEntry): Promise<void>;
|
|
73
|
+
query(options?: AuditQueryOptions): Promise<AuditEntry[]>;
|
|
74
|
+
close(): Promise<void>;
|
|
75
|
+
/** Get all entries (for testing) */
|
|
76
|
+
getAll(): AuditEntry[];
|
|
77
|
+
/** Clear all entries (for testing) */
|
|
78
|
+
clear(): void;
|
|
79
|
+
}
|
|
80
|
+
//#endregion
|
|
81
|
+
export { type AuditAction, type AuditContext, type AuditEntry, type AuditLogger, type AuditPluginOptions, type AuditQueryOptions, type AuditStore, type AuditStoreOptions, MemoryAuditStore, type MemoryAuditStoreOptions, type MongoAuditStoreOptions, _default as auditPlugin, auditPlugin as auditPluginFn, createAuditEntry };
|
|
82
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/audit/auditPlugin.ts","../../src/audit/stores/memory.ts"],"mappings":";;;;;;;UAgCiB,kBAAA;EAoCc;EAlC7B,OAAA;EA6BE;EA3BF,MAAA;EA8BU;EA5BV,eAAA,GAAkB,eAAA;EA8BD;EA5BjB,eAAA;EA4B6B;EA1B7B,OAAA;EA8Be;EA5Bf,YAAA,GAAe,UAAA;;;;;;;;;;EAUf,SAAA;IACE,UAAA;IACA,OAAA;EAAA;AAAA;AAAA;EAAA,UAKQ,eAAA;IAoDL;IAlDH,KAAA,EAAO,WAAA;EAAA;EAAA,UAGC,cAAA;IAkDoE;IAhD5E,YAAA,GAAe,YAAA;EAAA;AAAA;AAAA,UAIF,WAAA;EAKP;EAHR,MAAA,GACE,QAAA,UACA,UAAA,UACA,IAAA,EAAM,MAAA,mBACN,OAAA,GAAU,YAAA,KACP,OAAA;EADO;EAIZ,MAAA,GACE,QAAA,UACA,UAAA,UACA,MAAA,EAAQ,MAAA,mBACR,KAAA,EAAO,MAAA,mBACP,OAAA,GAAU,YAAA,KACP,OAAA;EATA;EAYL,MAAA,GACE,QAAA,UACA,UAAA,UACA,IAAA,EAAM,MAAA,mBACN,OAAA,GAAU,YAAA,KACP,OAAA;EAbH;EAgBF,OAAA,GACE,QAAA,UACA,UAAA,UACA,IAAA,EAAM,MAAA,mBACN,OAAA,GAAU,YAAA,KACP,OAAA;EAnBK;EAsBV,MAAA,GACE,QAAA,UACA,UAAA,UACA,MAAA,UACA,IAAA,GAAO,MAAA,mBACP,OAAA,GAAU,YAAA,KACP,OAAA;EA3BI;EA8BT,KAAA,GAAQ,OAAA,EAHI,iBAAA,KAG2D,OAAA,CAAQ,UAAA;AAAA;AAAA,cAG3E,WAAA,EAAa,kBAAA,CAAmB,kBAAA;AAAA,cAAkB,QAAA;;;UC9GvC,uBAAA;EDuBkB;ECrBjC,UAAA;AAAA;AAAA,cAGW,gBAAA,YAA4B,UAAA;EAAA,SAC9B,IAAA;EAAA,QACD,OAAA;EAAA,QACA,UAAA;cAEI,OAAA,GAAS,uBAAA;EAIf,GAAA,CAAI,KAAA,EAAO,UAAA,GAAa,OAAA;EASxB,KAAA,CAAM,OAAA,GAAS,iBAAA,GAAyB,OAAA,CAAQ,UAAA;EAwChD,KAAA,CAAA,GAAS,OAAA;EDlBf;ECuBA,MAAA,CAAA,GAAU,UAAA;EDrBR;EC0BF,KAAA,CAAA;AAAA"}
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import { t as MongoAuditStore } from "../mongodb-BfJVlUJH.mjs";
|
|
2
|
+
import fp from "fastify-plugin";
|
|
3
|
+
|
|
4
|
+
//#region src/audit/stores/interface.ts
|
|
5
|
+
/**
|
|
6
|
+
* Create audit entry from context
|
|
7
|
+
*/
|
|
8
|
+
function createAuditEntry(resource, documentId, action, context, data) {
|
|
9
|
+
const changes = data?.before && data?.after ? detectChanges(data.before, data.after) : void 0;
|
|
10
|
+
return {
|
|
11
|
+
id: generateAuditId(),
|
|
12
|
+
resource,
|
|
13
|
+
documentId,
|
|
14
|
+
action,
|
|
15
|
+
userId: context.user?._id?.toString() ?? context.user?.id,
|
|
16
|
+
organizationId: context.organizationId,
|
|
17
|
+
before: data?.before,
|
|
18
|
+
after: data?.after,
|
|
19
|
+
changes,
|
|
20
|
+
requestId: context.requestId,
|
|
21
|
+
ipAddress: context.ipAddress,
|
|
22
|
+
userAgent: context.userAgent,
|
|
23
|
+
metadata: data?.metadata,
|
|
24
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Detect changed fields between two objects
|
|
29
|
+
*/
|
|
30
|
+
function detectChanges(before, after) {
|
|
31
|
+
const changes = [];
|
|
32
|
+
const allKeys = new Set([...Object.keys(before), ...Object.keys(after)]);
|
|
33
|
+
for (const key of allKeys) {
|
|
34
|
+
if (key.startsWith("_") || key === "updatedAt") continue;
|
|
35
|
+
if (JSON.stringify(before[key]) !== JSON.stringify(after[key])) changes.push(key);
|
|
36
|
+
}
|
|
37
|
+
return changes;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Generate unique audit ID
|
|
41
|
+
*/
|
|
42
|
+
function generateAuditId() {
|
|
43
|
+
return `aud_${Date.now().toString(36)}${Math.random().toString(36).substring(2, 10)}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
//#endregion
|
|
47
|
+
//#region src/audit/stores/memory.ts
|
|
48
|
+
var MemoryAuditStore = class {
|
|
49
|
+
name = "memory";
|
|
50
|
+
entries = [];
|
|
51
|
+
maxEntries;
|
|
52
|
+
constructor(options = {}) {
|
|
53
|
+
this.maxEntries = options.maxEntries ?? 1e3;
|
|
54
|
+
}
|
|
55
|
+
async log(entry) {
|
|
56
|
+
this.entries.unshift(entry);
|
|
57
|
+
if (this.entries.length > this.maxEntries) this.entries = this.entries.slice(0, this.maxEntries);
|
|
58
|
+
}
|
|
59
|
+
async query(options = {}) {
|
|
60
|
+
let results = [...this.entries];
|
|
61
|
+
if (options.resource) results = results.filter((e) => e.resource === options.resource);
|
|
62
|
+
if (options.documentId) results = results.filter((e) => e.documentId === options.documentId);
|
|
63
|
+
if (options.userId) results = results.filter((e) => e.userId === options.userId);
|
|
64
|
+
if (options.organizationId) results = results.filter((e) => e.organizationId === options.organizationId);
|
|
65
|
+
if (options.action) {
|
|
66
|
+
const actions = Array.isArray(options.action) ? options.action : [options.action];
|
|
67
|
+
results = results.filter((e) => actions.includes(e.action));
|
|
68
|
+
}
|
|
69
|
+
if (options.from) results = results.filter((e) => e.timestamp >= options.from);
|
|
70
|
+
if (options.to) results = results.filter((e) => e.timestamp <= options.to);
|
|
71
|
+
const offset = options.offset ?? 0;
|
|
72
|
+
const limit = options.limit ?? 100;
|
|
73
|
+
results = results.slice(offset, offset + limit);
|
|
74
|
+
return results;
|
|
75
|
+
}
|
|
76
|
+
async close() {
|
|
77
|
+
this.entries = [];
|
|
78
|
+
}
|
|
79
|
+
/** Get all entries (for testing) */
|
|
80
|
+
getAll() {
|
|
81
|
+
return [...this.entries];
|
|
82
|
+
}
|
|
83
|
+
/** Clear all entries (for testing) */
|
|
84
|
+
clear() {
|
|
85
|
+
this.entries = [];
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
//#endregion
|
|
90
|
+
//#region src/audit/auditPlugin.ts
|
|
91
|
+
/**
|
|
92
|
+
* Audit Plugin
|
|
93
|
+
*
|
|
94
|
+
* Optional audit trail with flexible storage options.
|
|
95
|
+
* Disabled by default - enable explicitly for enterprise use cases.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* import { auditPlugin } from '@classytic/arc/audit';
|
|
99
|
+
*
|
|
100
|
+
* // Development: in-memory
|
|
101
|
+
* await fastify.register(auditPlugin, {
|
|
102
|
+
* enabled: true,
|
|
103
|
+
* stores: ['memory'],
|
|
104
|
+
* });
|
|
105
|
+
*
|
|
106
|
+
* // Production: MongoDB with TTL
|
|
107
|
+
* await fastify.register(auditPlugin, {
|
|
108
|
+
* enabled: true,
|
|
109
|
+
* stores: ['mongodb'],
|
|
110
|
+
* mongoConnection: mongoose.connection,
|
|
111
|
+
* ttlDays: 90,
|
|
112
|
+
* });
|
|
113
|
+
*/
|
|
114
|
+
const auditPlugin = async (fastify, opts = {}) => {
|
|
115
|
+
const { enabled = false, stores: storeTypes = ["memory"], mongoConnection, mongoCollection = "audit_logs", ttlDays = 90, customStores = [] } = opts;
|
|
116
|
+
if (!enabled) {
|
|
117
|
+
fastify.decorate("audit", createNoopLogger());
|
|
118
|
+
fastify.decorateRequest("auditContext", void 0);
|
|
119
|
+
fastify.log?.debug?.("Audit plugin disabled");
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const stores = [...customStores];
|
|
123
|
+
for (const type of storeTypes) switch (type) {
|
|
124
|
+
case "memory":
|
|
125
|
+
stores.push(new MemoryAuditStore());
|
|
126
|
+
break;
|
|
127
|
+
case "mongodb":
|
|
128
|
+
if (!mongoConnection) throw new Error("Audit: mongoConnection required for mongodb store");
|
|
129
|
+
stores.push(new MongoAuditStore({
|
|
130
|
+
connection: mongoConnection,
|
|
131
|
+
collection: mongoCollection,
|
|
132
|
+
ttlDays
|
|
133
|
+
}));
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
if (stores.length === 0) throw new Error("Audit: at least one store must be configured");
|
|
137
|
+
async function logToStores(entry) {
|
|
138
|
+
await Promise.all(stores.map((store) => store.log(entry)));
|
|
139
|
+
}
|
|
140
|
+
const audit = {
|
|
141
|
+
async create(resource, documentId, data, context) {
|
|
142
|
+
await logToStores(createAuditEntry(resource, documentId, "create", context ?? {}, { after: data }));
|
|
143
|
+
},
|
|
144
|
+
async update(resource, documentId, before, after, context) {
|
|
145
|
+
await logToStores(createAuditEntry(resource, documentId, "update", context ?? {}, {
|
|
146
|
+
before,
|
|
147
|
+
after
|
|
148
|
+
}));
|
|
149
|
+
},
|
|
150
|
+
async delete(resource, documentId, data, context) {
|
|
151
|
+
await logToStores(createAuditEntry(resource, documentId, "delete", context ?? {}, { before: data }));
|
|
152
|
+
},
|
|
153
|
+
async restore(resource, documentId, data, context) {
|
|
154
|
+
await logToStores(createAuditEntry(resource, documentId, "restore", context ?? {}, { after: data }));
|
|
155
|
+
},
|
|
156
|
+
async custom(resource, documentId, action, data, context) {
|
|
157
|
+
await logToStores(createAuditEntry(resource, documentId, "custom", context ?? {}, { metadata: {
|
|
158
|
+
customAction: action,
|
|
159
|
+
...data
|
|
160
|
+
} }));
|
|
161
|
+
},
|
|
162
|
+
async query(options) {
|
|
163
|
+
for (const store of stores) if (store.query) return store.query(options);
|
|
164
|
+
return [];
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
fastify.decorate("audit", audit);
|
|
168
|
+
fastify.decorateRequest("auditContext", void 0);
|
|
169
|
+
fastify.addHook("onRequest", async (request) => {
|
|
170
|
+
const user = request.user;
|
|
171
|
+
request.context;
|
|
172
|
+
const scope = request.scope;
|
|
173
|
+
request.auditContext = {
|
|
174
|
+
user,
|
|
175
|
+
organizationId: scope?.kind === "member" ? scope.organizationId : scope?.kind === "elevated" ? scope.organizationId : void 0,
|
|
176
|
+
requestId: request.id,
|
|
177
|
+
ipAddress: request.ip,
|
|
178
|
+
userAgent: request.headers["user-agent"],
|
|
179
|
+
endpoint: void 0,
|
|
180
|
+
duration: void 0
|
|
181
|
+
};
|
|
182
|
+
});
|
|
183
|
+
fastify.addHook("onResponse", async (request, reply) => {
|
|
184
|
+
if (request.auditContext) {
|
|
185
|
+
request.auditContext.endpoint = `${request.method} ${request.routeOptions?.url ?? request.url}`;
|
|
186
|
+
request.auditContext.duration = Math.round(reply.elapsedTime);
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
fastify.addHook("onClose", async () => {
|
|
190
|
+
await Promise.all(stores.map((store) => store.close?.()));
|
|
191
|
+
});
|
|
192
|
+
const autoAuditConfig = opts.autoAudit ?? true;
|
|
193
|
+
if (autoAuditConfig !== false) {
|
|
194
|
+
const defaultOps = [
|
|
195
|
+
"create",
|
|
196
|
+
"update",
|
|
197
|
+
"delete"
|
|
198
|
+
];
|
|
199
|
+
const ops = typeof autoAuditConfig === "object" ? autoAuditConfig.operations ?? defaultOps : defaultOps;
|
|
200
|
+
const excludeResources = new Set(typeof autoAuditConfig === "object" ? autoAuditConfig.exclude ?? [] : []);
|
|
201
|
+
fastify.addHook("onReady", async () => {
|
|
202
|
+
const arc = "arc" in fastify ? fastify.arc : void 0;
|
|
203
|
+
if (!arc?.hooks) {
|
|
204
|
+
fastify.log?.debug?.("Auto-audit skipped: arc-core plugin not registered");
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
for (const op of ops) arc.hooks.after("*", op, async (ctx) => {
|
|
208
|
+
if (excludeResources.has(ctx.resource)) return;
|
|
209
|
+
const docId = autoAuditExtractId(ctx.result);
|
|
210
|
+
const scope = ctx.context?._scope;
|
|
211
|
+
const auditCtx = {
|
|
212
|
+
user: ctx.user,
|
|
213
|
+
organizationId: scope ? autoAuditGetOrgId(scope) : void 0
|
|
214
|
+
};
|
|
215
|
+
try {
|
|
216
|
+
if (op === "create") await audit.create(ctx.resource, docId, autoAuditToPlain(ctx.result), auditCtx);
|
|
217
|
+
else if (op === "update") await audit.update(ctx.resource, docId, autoAuditToPlain(ctx.meta?.existing), autoAuditToPlain(ctx.result), auditCtx);
|
|
218
|
+
else if (op === "delete") await audit.delete(ctx.resource, docId, autoAuditToPlain(ctx.result), auditCtx);
|
|
219
|
+
} catch (err) {
|
|
220
|
+
fastify.log?.warn?.({
|
|
221
|
+
resource: ctx.resource,
|
|
222
|
+
op,
|
|
223
|
+
err
|
|
224
|
+
}, "Auto-audit failed");
|
|
225
|
+
}
|
|
226
|
+
}, 90);
|
|
227
|
+
fastify.log?.debug?.({
|
|
228
|
+
ops,
|
|
229
|
+
exclude: [...excludeResources]
|
|
230
|
+
}, "Auto-audit hooks registered");
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
fastify.log?.debug?.({ stores: storeTypes }, "Audit plugin enabled");
|
|
234
|
+
};
|
|
235
|
+
/** Extract document ID from a result */
|
|
236
|
+
function autoAuditExtractId(doc) {
|
|
237
|
+
if (!doc || typeof doc !== "object") return "";
|
|
238
|
+
const d = doc;
|
|
239
|
+
const rawId = d._id ?? d.id;
|
|
240
|
+
return rawId != null ? String(rawId) : "";
|
|
241
|
+
}
|
|
242
|
+
/** Convert Mongoose doc or plain object to plain object */
|
|
243
|
+
function autoAuditToPlain(doc) {
|
|
244
|
+
if (!doc || typeof doc !== "object") return {};
|
|
245
|
+
if (typeof doc.toObject === "function") return doc.toObject();
|
|
246
|
+
return doc;
|
|
247
|
+
}
|
|
248
|
+
/** Extract org ID from scope (avoids importing scope module to prevent circular deps) */
|
|
249
|
+
function autoAuditGetOrgId(scope) {
|
|
250
|
+
if (!scope || typeof scope !== "object") return void 0;
|
|
251
|
+
const s = scope;
|
|
252
|
+
if (s.kind === "member" || s.kind === "elevated") return s.organizationId;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Create no-op logger for when audit is disabled
|
|
256
|
+
*/
|
|
257
|
+
function createNoopLogger() {
|
|
258
|
+
const noop = async () => {};
|
|
259
|
+
return {
|
|
260
|
+
create: noop,
|
|
261
|
+
update: noop,
|
|
262
|
+
delete: noop,
|
|
263
|
+
restore: noop,
|
|
264
|
+
custom: noop,
|
|
265
|
+
query: async () => []
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
var auditPlugin_default = fp(auditPlugin, {
|
|
269
|
+
name: "arc-audit",
|
|
270
|
+
fastify: "5.x",
|
|
271
|
+
dependencies: ["arc-core"]
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
//#endregion
|
|
275
|
+
export { MemoryAuditStore, auditPlugin_default as auditPlugin, auditPlugin as auditPluginFn, createAuditEntry };
|
|
276
|
+
//# sourceMappingURL=index.mjs.map
|