@classytic/arc 2.8.0 → 2.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/README.md +10 -1
  2. package/dist/{BaseController-CpMfCXdn.mjs → BaseController-DAGGc5Xn.mjs} +76 -25
  3. package/dist/{EventTransport-n1KBxC_N.d.mts → EventTransport-CinyO7zQ.d.mts} +37 -1
  4. package/dist/{ResourceRegistry-BOtJuRCs.mjs → ResourceRegistry-Dq3_zBQP.mjs} +17 -5
  5. package/dist/adapters/index.d.mts +2 -2
  6. package/dist/adapters/index.mjs +1 -1
  7. package/dist/{adapters-BxGgSHjj.mjs → adapters-BBqAVvPK.mjs} +11 -0
  8. package/dist/audit/index.d.mts +1 -1
  9. package/dist/audit/index.mjs +1 -1
  10. package/dist/audit/mongodb.d.mts +1 -1
  11. package/dist/audit/mongodb.mjs +1 -1
  12. package/dist/auth/index.d.mts +4 -4
  13. package/dist/auth/index.mjs +3 -3
  14. package/dist/auth/redis-session.d.mts +1 -1
  15. package/dist/{betterAuthOpenApi-CHCIuA-p.mjs → betterAuthOpenApi-C5lDyRH2.mjs} +1 -1
  16. package/dist/cache/index.d.mts +2 -2
  17. package/dist/cli/commands/describe.mjs +1 -1
  18. package/dist/cli/commands/docs.mjs +2 -2
  19. package/dist/cli/commands/generate.mjs +1 -1
  20. package/dist/cli/commands/init.mjs +10 -10
  21. package/dist/cli/commands/introspect.mjs +3 -3
  22. package/dist/core/index.d.mts +3 -3
  23. package/dist/core/index.mjs +5 -5
  24. package/dist/{core-BfrfxNqO.mjs → core-DKSwNSXf.mjs} +1 -1
  25. package/dist/{createActionRouter-CbkIAaGh.mjs → createActionRouter-Df1BuawX.mjs} +87 -21
  26. package/dist/{createApp-Cy8eUNKQ.mjs → createApp-BOYjBgdI.mjs} +16 -7
  27. package/dist/{defineResource-CovBXvTB.mjs → defineResource-Bb_Bdhtw.mjs} +60 -33
  28. package/dist/docs/index.d.mts +2 -2
  29. package/dist/docs/index.mjs +1 -1
  30. package/dist/dynamic/index.d.mts +2 -2
  31. package/dist/dynamic/index.mjs +1 -1
  32. package/dist/{errorHandler-BeN-ERN7.d.mts → errorHandler-CdZDavNH.d.mts} +2 -2
  33. package/dist/{errorHandler-BW08lEiy.mjs → errorHandler-mzqk4cGl.mjs} +1 -1
  34. package/dist/{eventPlugin-CAOWMQS8.d.mts → eventPlugin-CVxlE6De.d.mts} +1 -1
  35. package/dist/{eventPlugin-x4jo3sG0.mjs → eventPlugin-D91S2YF4.mjs} +19 -1
  36. package/dist/events/index.d.mts +399 -28
  37. package/dist/events/index.mjs +345 -29
  38. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  39. package/dist/events/transports/redis-stream-entry.mjs +3 -1
  40. package/dist/events/transports/redis.d.mts +1 -1
  41. package/dist/factory/index.d.mts +1 -1
  42. package/dist/factory/index.mjs +2 -152
  43. package/dist/hooks/index.d.mts +1 -1
  44. package/dist/idempotency/index.d.mts +3 -3
  45. package/dist/idempotency/mongodb.d.mts +1 -1
  46. package/dist/idempotency/mongodb.mjs +18 -6
  47. package/dist/idempotency/redis.d.mts +1 -1
  48. package/dist/idempotency/redis.mjs +10 -1
  49. package/dist/{index-BpMhrFgn.d.mts → index-BgmMdpm8.d.mts} +1 -1
  50. package/dist/{index-CBru2y5Y.d.mts → index-CSkeivBx.d.mts} +3 -3
  51. package/dist/{index-qct60lnl.d.mts → index-CpTSDqmD.d.mts} +60 -6
  52. package/dist/index.d.mts +8 -8
  53. package/dist/index.mjs +7 -7
  54. package/dist/integrations/event-gateway.d.mts +1 -1
  55. package/dist/integrations/event-gateway.mjs +1 -1
  56. package/dist/integrations/index.d.mts +1 -1
  57. package/dist/integrations/mcp/index.d.mts +2 -2
  58. package/dist/integrations/mcp/index.mjs +1 -1
  59. package/dist/integrations/mcp/testing.d.mts +1 -1
  60. package/dist/integrations/mcp/testing.mjs +1 -1
  61. package/dist/{interface-IJqN3pXK.d.mts → interface-BVuMfeVv.d.mts} +596 -125
  62. package/dist/loadResources-Bksk8ydA.mjs +154 -0
  63. package/dist/{mongodb-B1eVtFhw.d.mts → mongodb-B8U2xaLj.d.mts} +1 -1
  64. package/dist/{mongodb-NShVZDMr.d.mts → mongodb-X7LbEjTN.d.mts} +10 -1
  65. package/dist/{openapi-AYLVjqVe.mjs → openapi-CYCuekCn.mjs} +50 -3
  66. package/dist/org/index.d.mts +2 -2
  67. package/dist/permissions/index.d.mts +3 -3
  68. package/dist/plugins/index.d.mts +5 -5
  69. package/dist/plugins/index.mjs +8 -8
  70. package/dist/plugins/tracing-entry.d.mts +1 -1
  71. package/dist/plugins/tracing-entry.mjs +1 -1
  72. package/dist/policies/index.d.mts +1 -1
  73. package/dist/presets/index.d.mts +3 -3
  74. package/dist/presets/index.mjs +1 -1
  75. package/dist/presets/multiTenant.d.mts +1 -1
  76. package/dist/{presets-BFrGvvjL.mjs → presets-C2xgzW6x.mjs} +10 -18
  77. package/dist/{queryCachePlugin-BCFVXnxK.d.mts → queryCachePlugin-CnTZZTC5.d.mts} +1 -1
  78. package/dist/{redis-stream-CF1lrKVk.d.mts → redis-stream-D54N5oXs.d.mts} +1 -1
  79. package/dist/{redis-Bunu3qWg.d.mts → redis-z3sFr1UP.d.mts} +1 -1
  80. package/dist/registry/index.d.mts +1 -1
  81. package/dist/registry/index.mjs +1 -1
  82. package/dist/{resourceToTools-C_1SMiCz.mjs → resourceToTools-O_HwWXFa.mjs} +194 -64
  83. package/dist/rpc/index.d.mts +1 -1
  84. package/dist/rpc/index.mjs +1 -1
  85. package/dist/scope/index.d.mts +2 -2
  86. package/dist/testing/index.d.mts +2 -2
  87. package/dist/testing/index.mjs +1 -1
  88. package/dist/types/index.d.mts +5 -5
  89. package/dist/{types-gUxAIZHp.d.mts → types-Bg2X42_m.d.mts} +30 -9
  90. package/dist/{types-BoaZHr-2.d.mts → types-CVC4HOKi.d.mts} +1 -1
  91. package/dist/{types-Ct0PUUSp.d.mts → types-CcG4avic.d.mts} +1 -1
  92. package/dist/utils/index.d.mts +43 -17
  93. package/dist/utils/index.mjs +5 -5
  94. package/dist/{utils-B-l6410F.mjs → utils-yYT3HDXt.mjs} +65 -13
  95. package/package.json +10 -9
  96. package/skills/arc/SKILL.md +79 -6
  97. /package/dist/{caching-CHH-iHs3.mjs → caching-CjybdRwx.mjs} +0 -0
  98. /package/dist/{circuitBreaker-BGVoB1hD.d.mts → circuitBreaker-CvXkjfrW.d.mts} +0 -0
  99. /package/dist/{circuitBreaker-l18oRgL5.mjs → circuitBreaker-cmi5XDv5.mjs} +0 -0
  100. /package/dist/{elevation-UJO3-NvX.d.mts → elevation-s5ykdNHr.d.mts} +0 -0
  101. /package/dist/{errors-Cg58SLNi.mjs → errors-BF2bIOIS.mjs} +0 -0
  102. /package/dist/{errors-BI8kEKsO.d.mts → errors-Bmn3eZT6.d.mts} +0 -0
  103. /package/dist/{externalPaths-BQ8QijNH.d.mts → externalPaths-Bapitwvd.d.mts} +0 -0
  104. /package/dist/{fields-DoeDgh2b.d.mts → fields-DC4So2M2.d.mts} +0 -0
  105. /package/dist/{interface-CkkWm5uR.d.mts → interface-B-pe8fhj.d.mts} +0 -0
  106. /package/dist/{interface-bpoLKKqx.d.mts → interface-DplgQO2e.d.mts} +0 -0
  107. /package/dist/{metrics-DuhiSEZI.mjs → metrics-TuOmguhi.mjs} +0 -0
  108. /package/dist/{mongodb-5Ff3w8jy.mjs → mongodb-B5O6xaW1.mjs} +0 -0
  109. /package/dist/{pluralize-BneOJkpi.mjs → pluralize-A0tWEl1K.mjs} +0 -0
  110. /package/dist/{replyHelpers-CXtJDAZ0.mjs → replyHelpers-BLojtuvR.mjs} +0 -0
  111. /package/dist/{requestContext-xHIKedG6.mjs → requestContext-DYvHl113.mjs} +0 -0
  112. /package/dist/{schemaConverter-Y5EejTnJ.mjs → schemaConverter-OxfCshus.mjs} +0 -0
  113. /package/dist/{sessionManager-BkzVU8h2.d.mts → sessionManager-D-oNWHz3.d.mts} +0 -0
  114. /package/dist/{sse-CD5Hghpu.mjs → sse-CJpt7LGI.mjs} +0 -0
  115. /package/dist/{tracing-xqXzWeaf.d.mts → tracing-DxjKk7eW.d.mts} +0 -0
  116. /package/dist/{types-CN6JvmYz.d.mts → types-C72d3NDn.d.mts} +0 -0
  117. /package/dist/{versioning-CPU_5Xfs.mjs → versioning-Cm8qoFDg.mjs} +0 -0
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Database-agnostic resource framework for Fastify. Define resources, get CRUD routes, permissions, presets, caching, events, OpenAPI, and MCP tools — without boilerplate.
4
4
 
5
- **v2.8.0** | Fastify 5+ | Node.js 22+ | ESM only | 260+ test files, 3523+ tests
5
+ **v2.8.3** | Fastify 5+ | Node.js 22+ | ESM only | 278+ test files, 3844+ tests
6
6
 
7
7
  ## Install
8
8
 
@@ -694,6 +694,15 @@ npx @classytic/arc doctor # Health check
694
694
  | `@classytic/arc/docs` | OpenAPI generation |
695
695
  | `@classytic/arc/cli` | CLI commands (programmatic) |
696
696
 
697
+ ## v2.8.1 Highlights
698
+
699
+ - **Per-action discriminated validation** — `actions` schemas now enforce required fields via a `oneOf` body schema; missing inputs are rejected at the HTTP layer by AJV (no more silent bypass)
700
+ - **Actions in OpenAPI** — `POST /:id/action` endpoint auto-generated from `ResourceDefinition.actions`, with per-action descriptions and the same discriminated body schema as the runtime router
701
+ - **Route/action metadata preserved** — `mcp: false`, `description`, `annotations` no longer dropped during `routes → additionalRoutes` normalization
702
+ - **Canonical source retained** — `ResourceDefinition.routes` and `ResourceDefinition.actions` now kept as declared, so OpenAPI/MCP/registry can read the original shape
703
+ - **Outbox hardening** — expanded `OutboxStore` contract (`claimPending`, `fail`, write options, dedupe, visibleAt), ownership-mismatch throws, onError reporting, safe multi-worker relay
704
+ - **`slugLookup` fallback** — works with MongoKit's default Repository (no custom `getBySlug` needed)
705
+
697
706
  ## v2.8.0 Highlights
698
707
 
699
708
  - **MCP Integration** — expose resources as AI agent tools (stateless by default, service scope, multi-tenancy)
@@ -843,9 +843,11 @@ var BaseController = class {
843
843
  status: 400
844
844
  };
845
845
  }
846
+ const deleteMode = req.query?.hard === "true" || req.query?.hard === true || req.body?.mode === "hard" ? "hard" : void 0;
846
847
  const repoDelete = async () => this.repository.delete(repoId, {
847
848
  user,
848
- context: arcContext
849
+ context: arcContext,
850
+ ...deleteMode ? { mode: deleteMode } : {}
849
851
  });
850
852
  let result;
851
853
  if (hooks && this.resourceName) result = await hooks.executeAround(this.resourceName, "delete", existing, repoDelete, {
@@ -854,7 +856,13 @@ var BaseController = class {
854
856
  meta: { id }
855
857
  });
856
858
  else result = await repoDelete();
857
- if (!(typeof result === "object" && result !== null ? result.success : result)) return {
859
+ if (!(() => {
860
+ if (typeof result !== "object" || result === null) return !!result;
861
+ const r = result;
862
+ if (typeof r.success === "boolean") return r.success;
863
+ if (typeof r.deletedCount === "number") return r.deletedCount > 0;
864
+ return true;
865
+ })()) return {
858
866
  success: false,
859
867
  error: "Resource not found",
860
868
  status: 404
@@ -876,16 +884,23 @@ var BaseController = class {
876
884
  };
877
885
  }
878
886
  async getBySlug(req) {
887
+ const slugField = this._presetFields.slugField ?? "slug";
888
+ const slug = req.params[slugField] ?? req.params.slug;
889
+ const options = this.queryResolver.resolve(req, this.meta(req));
879
890
  const repo = this.repository;
880
- if (!repo.getBySlug) return {
891
+ let item = null;
892
+ if (repo.getBySlug) item = await repo.getBySlug(slug, options);
893
+ else if (repo.getOne) {
894
+ const filter = {
895
+ [slugField]: slug,
896
+ ...options?.filter ?? {}
897
+ };
898
+ item = await repo.getOne(filter, options);
899
+ } else return {
881
900
  success: false,
882
- error: "Slug lookup not implemented",
901
+ error: "Slug lookup not implemented — repository needs getBySlug() or getOne()",
883
902
  status: 501
884
903
  };
885
- const slugField = this._presetFields.slugField ?? "slug";
886
- const slug = req.params[slugField] ?? req.params.slug;
887
- const options = this.queryResolver.resolve(req, this.meta(req));
888
- const item = await repo.getBySlug(slug, options);
889
904
  if (!this.accessControl.validateItemAccess(item, req)) return {
890
905
  success: false,
891
906
  error: "Resource not found",
@@ -904,21 +919,25 @@ var BaseController = class {
904
919
  error: "Soft delete not implemented",
905
920
  status: 501
906
921
  };
907
- const options = this.queryResolver.resolve(req, this.meta(req));
908
- const result = await repo.getDeleted(options);
909
- if (Array.isArray(result)) return {
910
- success: true,
911
- data: {
912
- docs: result,
913
- page: 1,
914
- limit: result.length,
915
- total: result.length,
916
- pages: 1,
917
- hasNext: false,
918
- hasPrev: false
919
- },
920
- status: 200
921
- };
922
+ const parsed = this.queryResolver.resolve(req, this.meta(req));
923
+ const result = await repo.getDeleted(parsed, parsed);
924
+ if (Array.isArray(result)) {
925
+ const docs = result;
926
+ return {
927
+ success: true,
928
+ data: {
929
+ method: "offset",
930
+ docs,
931
+ page: 1,
932
+ limit: docs.length,
933
+ total: docs.length,
934
+ pages: 1,
935
+ hasNext: false,
936
+ hasPrev: false
937
+ },
938
+ status: 200
939
+ };
940
+ }
922
941
  return {
923
942
  success: true,
924
943
  data: result,
@@ -950,13 +969,45 @@ var BaseController = class {
950
969
  details: { code: "OWNERSHIP_DENIED" },
951
970
  status: 403
952
971
  };
972
+ const arcContext = this.meta(req);
973
+ const user = req.user;
953
974
  const repoId = this.resolveRepoId(id, existing);
954
- const item = await repo.restore(repoId);
975
+ const hooks = this.getHooks(req);
976
+ if (hooks && this.resourceName) try {
977
+ await hooks.executeBefore(this.resourceName, "restore", existing, {
978
+ user,
979
+ context: arcContext,
980
+ meta: { id }
981
+ });
982
+ } catch (err) {
983
+ return {
984
+ success: false,
985
+ error: "Hook execution failed",
986
+ details: {
987
+ code: "BEFORE_RESTORE_HOOK_ERROR",
988
+ message: err.message
989
+ },
990
+ status: 400
991
+ };
992
+ }
993
+ const repoRestore = () => repo.restore(repoId);
994
+ let item;
995
+ if (hooks && this.resourceName) item = await hooks.executeAround(this.resourceName, "restore", existing, repoRestore, {
996
+ user,
997
+ context: arcContext,
998
+ meta: { id }
999
+ });
1000
+ else item = await repoRestore();
955
1001
  if (!item) return {
956
1002
  success: false,
957
1003
  error: "Resource not found",
958
1004
  status: 404
959
1005
  };
1006
+ if (hooks && this.resourceName) await hooks.executeAfter(this.resourceName, "restore", item, {
1007
+ user,
1008
+ context: arcContext,
1009
+ meta: { id }
1010
+ });
960
1011
  return {
961
1012
  success: true,
962
1013
  data: item,
@@ -1223,7 +1274,7 @@ var BaseController = class {
1223
1274
  };
1224
1275
  return {
1225
1276
  success: true,
1226
- data: await repo.deleteMany(scopedFilter),
1277
+ data: req.query?.hard === "true" || req.query?.hard === true || body.mode === "hard" ? await repo.deleteMany(scopedFilter, { mode: "hard" }) : await repo.deleteMany(scopedFilter),
1227
1278
  status: 200
1228
1279
  };
1229
1280
  }
@@ -61,6 +61,25 @@ interface EventTransport {
61
61
  * Publish an event to the transport
62
62
  */
63
63
  publish(event: DomainEvent): Promise<void>;
64
+ /**
65
+ * Publish a batch of events to the transport (optional, v2.8.1+).
66
+ *
67
+ * Transports that can efficiently batch (Kafka producer, Redis pipeline,
68
+ * RabbitMQ publisher confirms, SQS send-message-batch) should implement
69
+ * this. {@link import('./outbox.js').EventOutbox.relay} auto-detects and
70
+ * uses it for much higher throughput than per-event publishing.
71
+ *
72
+ * **Contract**: the returned `PublishManyResult` must describe the
73
+ * per-event outcome so the caller can acknowledge successes and fail the
74
+ * rest. Partial success is allowed — the transport reports it per event.
75
+ *
76
+ * If not implemented, `EventOutbox.relay` falls back to calling
77
+ * {@link publish} once per event.
78
+ *
79
+ * @param events - Events to publish (in order)
80
+ * @returns Per-event outcome map keyed by `event.meta.id`
81
+ */
82
+ publishMany?(events: readonly DomainEvent[]): Promise<PublishManyResult>;
64
83
  /**
65
84
  * Subscribe to events matching a pattern
66
85
  * @param pattern - Event type pattern (e.g., 'product.*', '*')
@@ -73,6 +92,14 @@ interface EventTransport {
73
92
  */
74
93
  close?(): Promise<void>;
75
94
  }
95
+ /**
96
+ * Per-event outcome returned by {@link EventTransport.publishMany}.
97
+ *
98
+ * The key is `event.meta.id`; the value is `null` for success or an `Error`
99
+ * for per-event failure. Transports MUST include an entry for every event
100
+ * in the input batch.
101
+ */
102
+ type PublishManyResult = ReadonlyMap<string, Error | null>;
76
103
  interface MemoryEventTransportOptions {
77
104
  /** Logger for error/warning messages (default: console) */
78
105
  logger?: EventLogger;
@@ -88,6 +115,15 @@ declare class MemoryEventTransport implements EventTransport {
88
115
  private logger;
89
116
  constructor(options?: MemoryEventTransportOptions);
90
117
  publish(event: DomainEvent): Promise<void>;
118
+ /**
119
+ * Reference `publishMany` implementation — delegates to `publish()` in order.
120
+ *
121
+ * Production transports (Kafka, Redis pipeline, SQS batch) should override
122
+ * this with a single batched network call. Memory transport has nothing to
123
+ * batch, so we just loop — the loop still returns a proper result map so
124
+ * `EventOutbox.relay` can exercise the batched code path in tests.
125
+ */
126
+ publishMany(events: readonly DomainEvent[]): Promise<PublishManyResult>;
91
127
  subscribe(pattern: string, handler: EventHandler): Promise<() => void>;
92
128
  close(): Promise<void>;
93
129
  }
@@ -96,4 +132,4 @@ declare class MemoryEventTransport implements EventTransport {
96
132
  */
97
133
  declare function createEvent<T>(type: string, payload: T, meta?: Partial<DomainEvent["meta"]>): DomainEvent<T>;
98
134
  //#endregion
99
- export { MemoryEventTransport as a, EventTransport as i, EventHandler as n, MemoryEventTransportOptions as o, EventLogger as r, createEvent as s, DomainEvent as t };
135
+ export { MemoryEventTransport as a, createEvent as c, EventTransport as i, EventHandler as n, MemoryEventTransportOptions as o, EventLogger as r, PublishManyResult as s, DomainEvent as t };
@@ -31,7 +31,7 @@ var ResourceRegistry = class {
31
31
  permissions: resource.permissions,
32
32
  presets: resource._appliedPresets ?? [],
33
33
  routes: [],
34
- additionalRoutes: resource.additionalRoutes.map((r) => ({
34
+ customRoutes: (resource.routes ?? []).map((r) => ({
35
35
  method: r.method,
36
36
  path: r.path,
37
37
  handler: typeof r.handler === "string" ? r.handler : r.handler.name || "anonymous",
@@ -39,7 +39,7 @@ var ResourceRegistry = class {
39
39
  summary: r.summary,
40
40
  description: r.description,
41
41
  permissions: r.permissions,
42
- wrapHandler: r.wrapHandler,
42
+ raw: r.raw,
43
43
  schema: r.schema
44
44
  })),
45
45
  events: Object.keys(resource.events ?? {}),
@@ -52,6 +52,17 @@ var ResourceRegistry = class {
52
52
  pipelineSteps: extractPipelineSteps(resource.pipe),
53
53
  rateLimit: resource.rateLimit,
54
54
  audit: resource.audit,
55
+ actionPermissions: resource.actionPermissions,
56
+ actions: resource.actions ? Object.entries(resource.actions).map(([name, entry]) => {
57
+ if (typeof entry === "function") return { name };
58
+ return {
59
+ name,
60
+ description: entry.description,
61
+ schema: entry.schema,
62
+ permissions: entry.permissions,
63
+ mcp: entry.mcp
64
+ };
65
+ }) : void 0,
55
66
  plugin: resource.toPlugin()
56
67
  };
57
68
  this._resources.set(resource.name, entry);
@@ -99,11 +110,12 @@ var ResourceRegistry = class {
99
110
  byModule: this._groupBy(resources, "module"),
100
111
  presetUsage: presetCounts,
101
112
  totalRoutes: resources.reduce((sum, r) => {
102
- if (r.disableDefaultRoutes) return sum + (r.additionalRoutes?.length ?? 0);
113
+ const actionsCount = (r.actions?.length ?? 0) > 0 ? 1 : 0;
114
+ if (r.disableDefaultRoutes) return sum + (r.customRoutes?.length ?? 0) + actionsCount;
103
115
  const disabledSet = new Set(r.disabledRoutes ?? []);
104
116
  let defaultCount = CRUD_OPERATIONS.filter((route) => !disabledSet.has(route)).length;
105
117
  if (!disabledSet.has("update") && r.updateMethod === "both") defaultCount += 1;
106
- return sum + defaultCount + (r.additionalRoutes?.length ?? 0);
118
+ return sum + defaultCount + (r.customRoutes?.length ?? 0) + actionsCount;
107
119
  }, 0),
108
120
  totalEvents: resources.reduce((sum, r) => sum + (r.events?.length ?? 0), 0)
109
121
  };
@@ -158,7 +170,7 @@ var ResourceRegistry = class {
158
170
  module: r.module,
159
171
  presets: r.presets,
160
172
  permissions: r.permissions,
161
- routes: [...defaultRoutes, ...r.additionalRoutes?.map((ar) => ({
173
+ routes: [...defaultRoutes, ...r.customRoutes?.map((ar) => ({
162
174
  method: ar.method,
163
175
  path: `${r.prefix}${ar.path}`,
164
176
  operation: ar.operation ?? (typeof ar.handler === "string" ? ar.handler : "custom"),
@@ -1,3 +1,3 @@
1
- import { a as RelationMetadata, c as ValidationResult, i as FieldMetadata, o as RepositoryLike, r as DataAdapter, s as SchemaMetadata, t as AdapterFactory } from "../interface-IJqN3pXK.mjs";
2
- 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 "../index-BpMhrFgn.mjs";
1
+ import { a as RelationMetadata, c as ValidationResult, i as FieldMetadata, o as RepositoryLike, r as DataAdapter, s as SchemaMetadata, t as AdapterFactory } from "../interface-BVuMfeVv.mjs";
2
+ 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 "../index-BgmMdpm8.mjs";
3
3
  export { AdapterFactory, DataAdapter, FieldMetadata, MongooseAdapter, MongooseAdapterOptions, PrismaAdapter, PrismaAdapterOptions, PrismaQueryOptions, PrismaQueryParser, PrismaQueryParserOptions, RelationMetadata, RepositoryLike, SchemaMetadata, ValidationResult, createMongooseAdapter, createPrismaAdapter };
@@ -1,2 +1,2 @@
1
- import { a as createMongooseAdapter, i as MongooseAdapter, n as PrismaQueryParser, r as createPrismaAdapter, t as PrismaAdapter } from "../adapters-BxGgSHjj.mjs";
1
+ import { a as createMongooseAdapter, i as MongooseAdapter, n as PrismaQueryParser, r as createPrismaAdapter, t as PrismaAdapter } from "../adapters-BBqAVvPK.mjs";
2
2
  export { MongooseAdapter, PrismaAdapter, PrismaQueryParser, createMongooseAdapter, createPrismaAdapter };
@@ -90,6 +90,17 @@ var MongooseAdapter = class {
90
90
  if (blockedFields.has(fieldName)) continue;
91
91
  const typeInfo = schemaType;
92
92
  properties[fieldName] = this.mongooseTypeToOpenApi(typeInfo);
93
+ const rule = fieldRules[fieldName];
94
+ if (rule) {
95
+ const prop = properties[fieldName];
96
+ if (rule.minLength != null && prop.minLength == null) prop.minLength = rule.minLength;
97
+ if (rule.maxLength != null && prop.maxLength == null) prop.maxLength = rule.maxLength;
98
+ if (rule.min != null && prop.minimum == null) prop.minimum = rule.min;
99
+ if (rule.max != null && prop.maximum == null) prop.maximum = rule.max;
100
+ if (rule.pattern != null && prop.pattern == null) prop.pattern = rule.pattern;
101
+ if (rule.enum != null && prop.enum == null) prop.enum = rule.enum;
102
+ if (rule.description != null && prop.description == null) prop.description = rule.description;
103
+ }
93
104
  if (typeInfo.isRequired && !optionalSet.has(fieldName) && !fieldRules[fieldName]?.optional) required.push(fieldName);
94
105
  }
95
106
  const readonlyForInput = new Set([...readonlySet]);
@@ -1,4 +1,4 @@
1
- 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-B1eVtFhw.mjs";
1
+ 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-B8U2xaLj.mjs";
2
2
  import { FastifyPluginAsync } from "fastify";
3
3
 
4
4
  //#region src/audit/auditPlugin.d.ts
@@ -1,4 +1,4 @@
1
- import { t as MongoAuditStore } from "../mongodb-5Ff3w8jy.mjs";
1
+ import { t as MongoAuditStore } from "../mongodb-B5O6xaW1.mjs";
2
2
  import fp from "fastify-plugin";
3
3
  //#region src/audit/stores/interface.ts
4
4
  /**
@@ -1,2 +1,2 @@
1
- import { n as MongoAuditStoreOptions, t as MongoAuditStore } from "../mongodb-B1eVtFhw.mjs";
1
+ import { n as MongoAuditStoreOptions, t as MongoAuditStore } from "../mongodb-B8U2xaLj.mjs";
2
2
  export { MongoAuditStore, type MongoAuditStoreOptions };
@@ -1,2 +1,2 @@
1
- import { t as MongoAuditStore } from "../mongodb-5Ff3w8jy.mjs";
1
+ import { t as MongoAuditStore } from "../mongodb-B5O6xaW1.mjs";
2
2
  export { MongoAuditStore };
@@ -1,7 +1,7 @@
1
- import { b as AuthPluginOptions, y as AuthHelpers } from "../interface-IJqN3pXK.mjs";
2
- import { t as PermissionCheck } from "../types-BoaZHr-2.mjs";
3
- import { t as ExternalOpenApiPaths } from "../externalPaths-BQ8QijNH.mjs";
4
- import { a as SessionManagerOptions, c as createSessionManager, i as SessionData, n as MemorySessionStoreOptions, o as SessionManagerResult, r as SessionCookieOptions, s as SessionStore, t as MemorySessionStore } from "../sessionManager-BkzVU8h2.mjs";
1
+ import { b as AuthPluginOptions, y as AuthHelpers } from "../interface-BVuMfeVv.mjs";
2
+ import { t as PermissionCheck } from "../types-CVC4HOKi.mjs";
3
+ import { t as ExternalOpenApiPaths } from "../externalPaths-Bapitwvd.mjs";
4
+ import { a as SessionManagerOptions, c as createSessionManager, i as SessionData, n as MemorySessionStoreOptions, o as SessionManagerResult, r as SessionCookieOptions, s as SessionStore, t as MemorySessionStore } from "../sessionManager-D-oNWHz3.mjs";
5
5
  import { FastifyPluginAsync, FastifyReply as FastifyReply$1, FastifyRequest as FastifyRequest$1 } from "fastify";
6
6
 
7
7
  //#region src/auth/authPlugin.d.ts
@@ -1,7 +1,7 @@
1
1
  import { n as normalizeRoles, t as getUserRoles } from "../types-ZUu_h0jp.mjs";
2
- import { t as ArcError } from "../errors-Cg58SLNi.mjs";
2
+ import { t as ArcError } from "../errors-BF2bIOIS.mjs";
3
3
  import { h as requireTeamMembership, l as requireOrgMembership, u as requireOrgRole } from "../permissions-CH4cNwJi.mjs";
4
- import { n as extractBetterAuthOpenApi } from "../betterAuthOpenApi-CHCIuA-p.mjs";
4
+ import { n as extractBetterAuthOpenApi } from "../betterAuthOpenApi-C5lDyRH2.mjs";
5
5
  import { createHmac, randomUUID, timingSafeEqual } from "node:crypto";
6
6
  import fp from "fastify-plugin";
7
7
  //#region src/auth/authPlugin.ts
@@ -677,7 +677,7 @@ function createBetterAuthAdapter(options) {
677
677
  if (!fastify.hasDecorator("authenticate")) fastify.decorate("authenticate", authenticate);
678
678
  if (!fastify.hasDecorator("optionalAuthenticate")) fastify.decorate("optionalAuthenticate", optionalAuthenticate);
679
679
  if (!extractedOpenApi && openapiOpt !== false && auth.api && typeof auth.api === "object") {
680
- const { extractBetterAuthOpenApi } = await import("../betterAuthOpenApi-CHCIuA-p.mjs").then((n) => n.t);
680
+ const { extractBetterAuthOpenApi } = await import("../betterAuthOpenApi-C5lDyRH2.mjs").then((n) => n.t);
681
681
  extractedOpenApi = extractBetterAuthOpenApi(auth.api, {
682
682
  basePath,
683
683
  userFields
@@ -1,4 +1,4 @@
1
- import { i as SessionData, s as SessionStore } from "../sessionManager-BkzVU8h2.mjs";
1
+ import { i as SessionData, s as SessionStore } from "../sessionManager-D-oNWHz3.mjs";
2
2
 
3
3
  //#region src/auth/redis-session.d.ts
4
4
  /** Minimal Redis client interface — compatible with ioredis */
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
2
- import { a as toJsonSchema } from "./schemaConverter-Y5EejTnJ.mjs";
2
+ import { a as toJsonSchema } from "./schemaConverter-OxfCshus.mjs";
3
3
  //#region src/auth/betterAuthOpenApi.ts
4
4
  var betterAuthOpenApi_exports = /* @__PURE__ */ __exportAll({ extractBetterAuthOpenApi: () => extractBetterAuthOpenApi });
5
5
  /**
@@ -1,5 +1,5 @@
1
- import { i as CacheStore, n as CacheSetOptions, r as CacheStats, t as CacheLogger } from "../interface-bpoLKKqx.mjs";
2
- import { a as CacheEnvelope, c as QueryCache, i as queryCachePlugin, l as QueryCacheConfig, n as QueryCacheDefaults, o as CacheResult, r as QueryCachePluginOptions, s as CacheStatus, t as CrossResourceRule } from "../queryCachePlugin-BCFVXnxK.mjs";
1
+ import { i as CacheStore, n as CacheSetOptions, r as CacheStats, t as CacheLogger } from "../interface-DplgQO2e.mjs";
2
+ import { a as CacheEnvelope, c as QueryCache, i as queryCachePlugin, l as QueryCacheConfig, n as QueryCacheDefaults, o as CacheResult, r as QueryCachePluginOptions, s as CacheStatus, t as CrossResourceRule } from "../queryCachePlugin-CnTZZTC5.mjs";
3
3
 
4
4
  //#region src/cache/keys.d.ts
5
5
  /**
@@ -128,7 +128,7 @@ function describeRoutes(resource) {
128
128
  routes.push(route);
129
129
  }
130
130
  }
131
- for (const ar of resource.additionalRoutes) routes.push({
131
+ for (const ar of resource.routes ?? []) routes.push({
132
132
  method: ar.method,
133
133
  path: `${resource.prefix}${ar.path}`,
134
134
  operation: typeof ar.handler === "string" ? ar.handler : "custom",
@@ -1,5 +1,5 @@
1
- import { t as ResourceRegistry } from "../../ResourceRegistry-BOtJuRCs.mjs";
2
- import { t as buildOpenApiSpec } from "../../openapi-AYLVjqVe.mjs";
1
+ import { t as ResourceRegistry } from "../../ResourceRegistry-Dq3_zBQP.mjs";
2
+ import { t as buildOpenApiSpec } from "../../openapi-CYCuekCn.mjs";
3
3
  import { dirname, resolve } from "node:path";
4
4
  import { pathToFileURL } from "node:url";
5
5
  import { mkdirSync, writeFileSync } from "node:fs";
@@ -1,4 +1,4 @@
1
- import { t as pluralize } from "../../pluralize-BneOJkpi.mjs";
1
+ import { t as pluralize } from "../../pluralize-A0tWEl1K.mjs";
2
2
  import { join } from "node:path";
3
3
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
4
4
  //#region src/cli/commands/generate.ts
@@ -1678,7 +1678,7 @@ const exampleResource = defineResource${ts ? "<ExampleDocument>" : ""}({
1678
1678
  permissions: ${config.tenant === "multi" ? "orgStaffPermissions" : "publicReadPermissions"},
1679
1679
 
1680
1680
  // Add custom routes here:
1681
- // additionalRoutes: [
1681
+ // routes: [
1682
1682
  // {
1683
1683
  // method: 'GET',
1684
1684
  // path: '/custom',
@@ -2134,14 +2134,14 @@ export const authResource = defineResource({
2134
2134
  adapter: createAdapter(User${ts ? " as any" : ""}, userRepository${ts ? " as any" : ""}),
2135
2135
  disableDefaultRoutes: true,
2136
2136
 
2137
- additionalRoutes: [
2137
+ routes: [
2138
2138
  {
2139
2139
  method: 'POST',
2140
2140
  path: '/register',
2141
2141
  summary: 'Register new user',
2142
2142
  permissions: allowPublic(),
2143
2143
  handler: handlers.register,
2144
- wrapHandler: false,
2144
+ raw: true,
2145
2145
  schema: { body: schemas.registerBody, response: { 201: schemas.successResponse } },
2146
2146
  },
2147
2147
  {
@@ -2150,7 +2150,7 @@ export const authResource = defineResource({
2150
2150
  summary: 'User login',
2151
2151
  permissions: allowPublic(),
2152
2152
  handler: handlers.login,
2153
- wrapHandler: false,
2153
+ raw: true,
2154
2154
  schema: { body: schemas.loginBody, response: { 200: schemas.loginResponse } },
2155
2155
  },
2156
2156
  {
@@ -2159,7 +2159,7 @@ export const authResource = defineResource({
2159
2159
  summary: 'Refresh access token',
2160
2160
  permissions: allowPublic(),
2161
2161
  handler: handlers.refreshToken,
2162
- wrapHandler: false,
2162
+ raw: true,
2163
2163
  schema: { body: schemas.refreshBody, response: { 200: schemas.tokenResponse } },
2164
2164
  },
2165
2165
  {
@@ -2168,7 +2168,7 @@ export const authResource = defineResource({
2168
2168
  summary: 'Request password reset',
2169
2169
  permissions: allowPublic(),
2170
2170
  handler: handlers.forgotPassword,
2171
- wrapHandler: false,
2171
+ raw: true,
2172
2172
  schema: { body: schemas.forgotBody, response: { 200: schemas.successResponse } },
2173
2173
  },
2174
2174
  {
@@ -2177,7 +2177,7 @@ export const authResource = defineResource({
2177
2177
  summary: 'Reset password with token',
2178
2178
  permissions: allowPublic(),
2179
2179
  handler: handlers.resetPassword,
2180
- wrapHandler: false,
2180
+ raw: true,
2181
2181
  schema: { body: schemas.resetBody, response: { 200: schemas.successResponse } },
2182
2182
  },
2183
2183
  ],
@@ -2195,14 +2195,14 @@ export const userProfileResource = defineResource({
2195
2195
  adapter: createAdapter(User${ts ? " as any" : ""}, userRepository${ts ? " as any" : ""}),
2196
2196
  disableDefaultRoutes: true,
2197
2197
 
2198
- additionalRoutes: [
2198
+ routes: [
2199
2199
  {
2200
2200
  method: 'GET',
2201
2201
  path: '/me',
2202
2202
  summary: 'Get current user profile',
2203
2203
  permissions: requireAuth(),
2204
2204
  handler: handlers.getUserProfile,
2205
- wrapHandler: false,
2205
+ raw: true,
2206
2206
  schema: { response: { 200: schemas.userProfileResponse } },
2207
2207
  },
2208
2208
  {
@@ -2211,7 +2211,7 @@ export const userProfileResource = defineResource({
2211
2211
  summary: 'Update current user profile',
2212
2212
  permissions: requireAuth(),
2213
2213
  handler: handlers.updateUserProfile,
2214
- wrapHandler: false,
2214
+ raw: true,
2215
2215
  schema: { body: schemas.updateUserBody, response: { 200: schemas.userProfileResponse } },
2216
2216
  },
2217
2217
  ],
@@ -1,4 +1,4 @@
1
- import { t as ResourceRegistry } from "../../ResourceRegistry-BOtJuRCs.mjs";
1
+ import { t as ResourceRegistry } from "../../ResourceRegistry-Dq3_zBQP.mjs";
2
2
  import { resolve } from "node:path";
3
3
  import { pathToFileURL } from "node:url";
4
4
  //#region src/cli/commands/introspect.ts
@@ -56,14 +56,14 @@ async function introspect(args) {
56
56
  });
57
57
  }
58
58
  if (resource.presets && resource.presets.length > 0) console.log(` Presets: ${resource.presets.join(", ")}`);
59
- if (resource.additionalRoutes && resource.additionalRoutes.length > 0) console.log(` Additional Routes: ${resource.additionalRoutes.length}`);
59
+ if (resource.customRoutes && resource.customRoutes.length > 0) console.log(` Additional Routes: ${resource.customRoutes.length}`);
60
60
  console.log("");
61
61
  });
62
62
  const stats = registry.getStats();
63
63
  console.log("Summary:");
64
64
  console.log(` Total Resources: ${stats.totalResources}`);
65
65
  console.log(` With Presets: ${resources.filter((r) => r.presets?.length > 0).length}`);
66
- console.log(` With Custom Routes: ${resources.filter((r) => r.additionalRoutes && r.additionalRoutes.length > 0).length}`);
66
+ console.log(` With Custom Routes: ${resources.filter((r) => r.customRoutes && r.customRoutes.length > 0).length}`);
67
67
  } catch (error) {
68
68
  if (error instanceof Error) throw error;
69
69
  throw new Error(String(error));
@@ -1,3 +1,3 @@
1
- import { At as BaseController, Ft as BodySanitizerConfig, It as AccessControl, Jt as defineResource, Lt as AccessControlConfig, Mt as QueryResolver, Nt as QueryResolverConfig, Pt as BodySanitizer, jt as BaseControllerOptions, qt as ResourceDefinition } from "../interface-IJqN3pXK.mjs";
2
- import { A as MutationOperation, C as HOOK_PHASES, D as MAX_REGEX_LENGTH, E as MAX_FILTER_DEPTH, M as SYSTEM_FIELDS, O as MAX_SEARCH_LENGTH, S as HOOK_OPERATIONS, T as HookPhase, _ as DEFAULT_LIMIT, a as getControllerScope, b as DEFAULT_TENANT_FIELD, c as createCrudRouter, d as ActionRouterConfig, f as IdempotencyService, g as DEFAULT_ID_FIELD, h as CrudOperation, i as getControllerContext, j as RESERVED_QUERY_PARAMS, k as MUTATION_OPERATIONS, l as createPermissionMiddleware, m as CRUD_OPERATIONS, n as createFastifyHandler, o as sendControllerResponse, p as createActionRouter, r as createRequestContext, s as defineResourceVariants, t as createCrudHandlers, u as ActionHandler, v as DEFAULT_MAX_LIMIT, w as HookOperation, x as DEFAULT_UPDATE_METHOD, y as DEFAULT_SORT } from "../index-qct60lnl.mjs";
3
- export { AccessControl, AccessControlConfig, ActionHandler, ActionRouterConfig, BaseController, BaseControllerOptions, BodySanitizer, 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, IdempotencyService, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, MutationOperation, QueryResolver, QueryResolverConfig, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, createActionRouter, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineResource, defineResourceVariants, getControllerContext, getControllerScope, sendControllerResponse };
1
+ import { At as BaseController, Ft as BodySanitizerConfig, It as AccessControl, Jt as defineResource, Lt as AccessControlConfig, Mt as QueryResolver, Nt as QueryResolverConfig, Pt as BodySanitizer, jt as BaseControllerOptions, qt as ResourceDefinition } from "../interface-BVuMfeVv.mjs";
2
+ import { A as MUTATION_OPERATIONS, C as HOOK_OPERATIONS, D as MAX_FILTER_DEPTH, E as HookPhase, M as RESERVED_QUERY_PARAMS, N as SYSTEM_FIELDS, O as MAX_REGEX_LENGTH, S as DEFAULT_UPDATE_METHOD, T as HookOperation, _ as DEFAULT_ID_FIELD, a as getControllerScope, b as DEFAULT_SORT, c as createCrudRouter, d as ActionRouterConfig, f as IdempotencyService, g as CrudOperation, h as CRUD_OPERATIONS, i as getControllerContext, j as MutationOperation, k as MAX_SEARCH_LENGTH, l as createPermissionMiddleware, m as createActionRouter, n as createFastifyHandler, o as sendControllerResponse, p as buildActionBodySchema, r as createRequestContext, s as defineResourceVariants, t as createCrudHandlers, u as ActionHandler, v as DEFAULT_LIMIT, w as HOOK_PHASES, x as DEFAULT_TENANT_FIELD, y as DEFAULT_MAX_LIMIT } from "../index-CpTSDqmD.mjs";
3
+ export { AccessControl, AccessControlConfig, ActionHandler, ActionRouterConfig, BaseController, BaseControllerOptions, BodySanitizer, 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, IdempotencyService, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, MutationOperation, QueryResolver, QueryResolverConfig, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, buildActionBodySchema, createActionRouter, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineResource, defineResourceVariants, getControllerContext, getControllerScope, sendControllerResponse };
@@ -1,6 +1,6 @@
1
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-Cxde4rpC.mjs";
2
- import { i as AccessControl, n as QueryResolver, r as BodySanitizer, t as BaseController } from "../BaseController-CpMfCXdn.mjs";
3
- import { t as createActionRouter } from "../createActionRouter-CbkIAaGh.mjs";
4
- import { c as createCrudHandlers, d as getControllerContext, f as getControllerScope, l as createFastifyHandler, n as defineResource, o as createCrudRouter, p as sendControllerResponse, s as createPermissionMiddleware, t as ResourceDefinition, u as createRequestContext } from "../defineResource-CovBXvTB.mjs";
5
- import { t as defineResourceVariants } from "../core-BfrfxNqO.mjs";
6
- 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, defineResourceVariants, getControllerContext, getControllerScope, sendControllerResponse };
2
+ import { i as AccessControl, n as QueryResolver, r as BodySanitizer, t as BaseController } from "../BaseController-DAGGc5Xn.mjs";
3
+ import { n as createActionRouter, t as buildActionBodySchema } from "../createActionRouter-Df1BuawX.mjs";
4
+ import { c as createCrudHandlers, d as getControllerContext, f as getControllerScope, l as createFastifyHandler, n as defineResource, o as createCrudRouter, p as sendControllerResponse, s as createPermissionMiddleware, t as ResourceDefinition, u as createRequestContext } from "../defineResource-Bb_Bdhtw.mjs";
5
+ import { t as defineResourceVariants } from "../core-DKSwNSXf.mjs";
6
+ 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, buildActionBodySchema, createActionRouter, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineResource, defineResourceVariants, getControllerContext, getControllerScope, sendControllerResponse };
@@ -1,4 +1,4 @@
1
- import { n as defineResource } from "./defineResource-CovBXvTB.mjs";
1
+ import { n as defineResource } from "./defineResource-Bb_Bdhtw.mjs";
2
2
  //#region src/core/defineResourceVariants.ts
3
3
  /**
4
4
  * Define multiple resources from a shared base config and per-variant overrides.