@classytic/arc 2.38.0 → 2.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/dist/{BaseController-CYaDvmOB.mjs → BaseController-BqJtbiUA.mjs} +107 -23
  2. package/dist/{EventTransport-Cx60_s-6.d.mts → EventTransport-BPOQsEer.d.mts} +8 -0
  3. package/dist/{EventTransport-Gq7JWbWw.mjs → EventTransport-BUkTwY_x.mjs} +13 -2
  4. package/dist/{HookSystem-C0ikzqQf.mjs → HookSystem-96nzZLmk.mjs} +2 -2
  5. package/dist/{ResourceRegistry-DPcX--zk.mjs → ResourceRegistry-B9WnuG2Q.mjs} +2 -2
  6. package/dist/{actionPermissions-jlFZ1it4.mjs → actionPermissions-4OGbe3Hf.mjs} +6 -6
  7. package/dist/audit/index.d.mts +1 -1
  8. package/dist/audit/index.mjs +2 -2
  9. package/dist/auth/audit.mjs +1 -1
  10. package/dist/auth/index.d.mts +1 -1
  11. package/dist/auth/index.mjs +6 -6
  12. package/dist/auth/redis-session.mjs +1 -1
  13. package/dist/{authorizationDecision-BP8GHtjc.mjs → authorizationDecision-D_LFvMlm.mjs} +2 -2
  14. package/dist/{buildHandler-DjXOqIvX.mjs → buildHandler-BG_CHXqQ.mjs} +4 -4
  15. package/dist/cache/index.mjs +4 -4
  16. package/dist/{caching-a3ZEcJJs.mjs → caching-Bqcn3Brl.mjs} +2 -2
  17. package/dist/cleanup/index.d.mts +2 -2
  18. package/dist/cleanup/index.mjs +21 -5
  19. package/dist/cli/commands/describe.d.mts +1 -1
  20. package/dist/cli/commands/describe.mjs +3 -3
  21. package/dist/cli/commands/docs.mjs +3 -3
  22. package/dist/cli/commands/doctor.mjs +1 -1
  23. package/dist/cli/commands/generate.mjs +2 -2
  24. package/dist/cli/commands/init.mjs +2 -2
  25. package/dist/cli/commands/introspect.mjs +2 -2
  26. package/dist/cli/index.mjs +3 -3
  27. package/dist/{constants-BONghE1Y.mjs → constants-BQ2FbhPB.mjs} +1 -1
  28. package/dist/context/index.d.mts +34 -6
  29. package/dist/context/index.mjs +12 -19
  30. package/dist/core/index.d.mts +2 -2
  31. package/dist/core/index.mjs +7 -7
  32. package/dist/{core-8She7FgF.mjs → core-CsZR037F.mjs} +3 -3
  33. package/dist/{createActionRouter-Bqi6Bhhx.mjs → createActionRouter-BR93gCKg.mjs} +7 -7
  34. package/dist/{createAggregationRouter-BsYO7ktd.mjs → createAggregationRouter-CF40Aw95.mjs} +7 -7
  35. package/dist/createMcpServer-BVTs2S5G.d.mts +48 -0
  36. package/dist/{defineAggregation-0KBvqEEC.mjs → defineAggregation-BDA2Tw7v.mjs} +1 -1
  37. package/dist/{defineResource-BMdyRelW.mjs → defineResource-DaIySrQr.mjs} +20 -22
  38. package/dist/discovery/index.mjs +1 -1
  39. package/dist/docs/index.d.mts +1 -1
  40. package/dist/docs/index.mjs +3 -3
  41. package/dist/{elevation-C6woysGC.mjs → elevation-CZy6n50b.mjs} +4 -4
  42. package/dist/encryption/index.mjs +3 -3
  43. package/dist/{errorHandler-DI5AN2b5.d.mts → errorHandler--4rSMMvq.d.mts} +7 -1
  44. package/dist/{errorHandler-BdmIWPba.mjs → errorHandler-By9keRvX.mjs} +3 -3
  45. package/dist/{errors-2ExmOgIJ.mjs → errors-BHD3L8of.mjs} +1 -1
  46. package/dist/{eventPlugin-DJwpGMzx.mjs → eventPlugin-DB26V7uX.mjs} +5 -5
  47. package/dist/{eventPlugin-DFvHa4Nf.d.mts → eventPlugin-DfHaKEWQ.d.mts} +1 -1
  48. package/dist/events/index.d.mts +4 -4
  49. package/dist/events/index.mjs +5 -5
  50. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  51. package/dist/events/transports/redis-stream-entry.mjs +21 -20
  52. package/dist/events/transports/redis.d.mts +1 -1
  53. package/dist/events/transports/redis.mjs +11 -8
  54. package/dist/factory/index.d.mts +4 -4
  55. package/dist/factory/index.mjs +5 -5
  56. package/dist/{fastify-augmentation-jYA2oHyL.d.mts → fastify-augmentation-HncZMmze.d.mts} +3 -3
  57. package/dist/{fields-Cha2QCKH.mjs → fields-fA-Dkou5.mjs} +1 -1
  58. package/dist/{generate-BUP4Oydg.mjs → generate-BSSdtiOy.mjs} +4 -3
  59. package/dist/{headers-DeXNifVj.mjs → headers-BFEEshDS.mjs} +2 -2
  60. package/dist/{health-Bh0N_FLk.mjs → health-BlGHjkqZ.mjs} +1 -1
  61. package/dist/hooks/index.d.mts +1 -1
  62. package/dist/hooks/index.mjs +2 -2
  63. package/dist/idempotency/index.mjs +4 -4
  64. package/dist/idempotency/redis.mjs +1 -1
  65. package/dist/{index-B78WZom8.d.mts → index-D3sIPcD4.d.mts} +47 -11
  66. package/dist/{index-D2uIUSQk.d.mts → index-DbMglURO.d.mts} +2 -2
  67. package/dist/{index-BRoDtjek.d.mts → index-SCsOJxWB.d.mts} +2 -2
  68. package/dist/index.d.mts +3 -3
  69. package/dist/index.mjs +11 -11
  70. package/dist/{init-Dg_Am2o_.mjs → init-pl88PHzb.mjs} +9 -9
  71. package/dist/integrations/event-gateway.d.mts +1 -1
  72. package/dist/integrations/event-gateway.mjs +2 -2
  73. package/dist/integrations/index.d.mts +1 -1
  74. package/dist/integrations/index.mjs +1 -1
  75. package/dist/integrations/jobs/index.mjs +2 -2
  76. package/dist/integrations/mcp/index.d.mts +3 -46
  77. package/dist/integrations/mcp/index.mjs +2 -2
  78. package/dist/integrations/mcp/testing.d.mts +22 -2
  79. package/dist/integrations/mcp/testing.mjs +55 -33
  80. package/dist/integrations/streamline.mjs +3 -3
  81. package/dist/integrations/webhooks.d.mts +2 -2
  82. package/dist/integrations/webhooks.mjs +3 -3
  83. package/dist/integrations/websocket-pushref-redis.mjs +1 -1
  84. package/dist/integrations/websocket-redis.mjs +1 -1
  85. package/dist/integrations/websocket.mjs +13 -6
  86. package/dist/{interface-DYPVscCU.mjs → interface-DjtFnZxH.mjs} +1 -1
  87. package/dist/{jsonBody-DVui0uJl.mjs → jsonBody-Dx6jH_Nb.mjs} +2 -2
  88. package/dist/{keys-BSuxGS-B.mjs → keys-Ds3ekBiu.mjs} +1 -1
  89. package/dist/{loadResources-CNd1DWnK.mjs → loadResources-E5UFlRrT.mjs} +2 -2
  90. package/dist/{loadResourcesFromEntry-DNj8cpiY.mjs → loadResourcesFromEntry-C2jrJbWG.mjs} +2 -2
  91. package/dist/logger/index.mjs +1 -1
  92. package/dist/{mcpPlugin-KWsezMx7.mjs → mcpPlugin-D-3OLxNz.mjs} +75 -31
  93. package/dist/{memory-BiPVaCPg.mjs → memory-CNvjxzB2.mjs} +2 -2
  94. package/dist/{metrics-CsWaIVTa.mjs → metrics-P37sNV5H.mjs} +2 -2
  95. package/dist/middleware/index.d.mts +1 -1
  96. package/dist/middleware/index.mjs +3 -3
  97. package/dist/migrations/index.mjs +2 -2
  98. package/dist/{module-BQXHxMEk.mjs → module-CNcwCKUJ.mjs} +1 -1
  99. package/dist/{multipartBody-u6VrS_iH.mjs → multipartBody-Bl_gU3Wg.mjs} +1 -1
  100. package/dist/{openapi-Dxc8RLy_.mjs → openapi-BYrL8zvY.mjs} +6 -6
  101. package/dist/outbox-admin/index.d.mts +1 -1
  102. package/dist/outbox-admin/index.mjs +4 -4
  103. package/dist/{outbox-module-DyIqA5vo.mjs → outbox-module-6DMC_WNu.mjs} +40 -21
  104. package/dist/{outbox-module-CQXu_O6o.d.mts → outbox-module-CzsKRBvO.d.mts} +11 -2
  105. package/dist/permissions/index.mjs +5 -5
  106. package/dist/{permissions-H7Zcb82Z.mjs → permissions-C0GpDsB_.mjs} +6 -6
  107. package/dist/{pipe-SunhEaZ6.mjs → pipe-4_XamfxI.mjs} +2 -2
  108. package/dist/pipeline/index.d.mts +1 -1
  109. package/dist/pipeline/index.mjs +2 -2
  110. package/dist/plugins/index.d.mts +5 -5
  111. package/dist/plugins/index.mjs +17 -16
  112. package/dist/plugins/response-cache.mjs +2 -2
  113. package/dist/plugins/tracing-entry.mjs +2 -2
  114. package/dist/{pluralize-Da7IT_qJ.mjs → pluralize-BaQ62hOW.mjs} +1 -1
  115. package/dist/{preloadResources-DlhH81py.mjs → preloadResources-BAx5s9EF.mjs} +70 -21
  116. package/dist/{preloadResources-BbBkNkqK.d.mts → preloadResources-DVgPCNcD.d.mts} +7 -7
  117. package/dist/presets/filesUpload.d.mts +1 -1
  118. package/dist/presets/filesUpload.mjs +5 -5
  119. package/dist/presets/index.d.mts +1 -1
  120. package/dist/presets/index.mjs +2 -2
  121. package/dist/presets/multiTenant.d.mts +1 -1
  122. package/dist/presets/multiTenant.mjs +3 -3
  123. package/dist/presets/search.d.mts +1 -1
  124. package/dist/presets/search.mjs +2 -2
  125. package/dist/{presets-CNyfaxGL.mjs → presets-CAaqVVcW.mjs} +4 -4
  126. package/dist/{projection-DSfEoooA.mjs → projection-qbCOEvsh.mjs} +2 -2
  127. package/dist/{queryCachePlugin-oTsmVyEQ.mjs → queryCachePlugin-2Pp9w-8D.mjs} +5 -5
  128. package/dist/rateLimitKey-umrS6-vu.mjs +41 -0
  129. package/dist/{realtime-CPmjjgqd.mjs → realtime-zzoNLDtj.mjs} +9 -9
  130. package/dist/{redis-stream-eh0eOtjh.d.mts → redis-stream-DSsPyYzd.d.mts} +7 -2
  131. package/dist/{registerRoute-XvcI_3sh.mjs → registerRoute-_6zHiz0x.mjs} +6 -6
  132. package/dist/registry/index.d.mts +2 -2
  133. package/dist/registry/index.mjs +3 -3
  134. package/dist/{registry-UFEJQN8R.mjs → registry-CEpoRpLP.mjs} +2 -2
  135. package/dist/{renewingLease-DuRGVOMe.mjs → renewingLease-B5Grm0pI.mjs} +1 -1
  136. package/dist/{replyHelpers-BHebarf0.mjs → replyHelpers-9h-a592u.mjs} +2 -2
  137. package/dist/{requestContext-DpmntRZy.mjs → requestContext-D4PuGhEw.mjs} +1 -1
  138. package/dist/{rolldown-runtime-Add2L50I.mjs → rolldown-runtime-DzE6ikSH.mjs} +1 -1
  139. package/dist/{runtimeCapabilities-D793Pxci.mjs → runtimeCapabilities-Bo7rSKjm.mjs} +1 -1
  140. package/dist/{schedules-DthM8Qag.mjs → schedules-Dm21pqHU.mjs} +8 -4
  141. package/dist/{schemaConverter-Db-MMsH6.mjs → schemaConverter-DENbixyA.mjs} +1 -1
  142. package/dist/{schemaIR-CIXShch7.mjs → schemaIR-C2qUNzC6.mjs} +2 -2
  143. package/dist/schemas/index.mjs +1 -1
  144. package/dist/scim/index.mjs +2 -2
  145. package/dist/scope/index.mjs +5 -5
  146. package/dist/{scope-D03sk17n.mjs → scope-CdYxQVxt.mjs} +4 -4
  147. package/dist/{simpleEqualityMatcher-B7qVjQBv.mjs → simpleEqualityMatcher-Cldubvul.mjs} +1 -1
  148. package/dist/{sse-D4MYqkic.mjs → sse-DbyXoQun.mjs} +5 -5
  149. package/dist/{sseStream-BuMNPR6r.mjs → sseStream-BfZtL5-m.mjs} +2 -2
  150. package/dist/{store-helpers-CIF4RG8s.mjs → store-helpers-BfyOd5i6.mjs} +1 -1
  151. package/dist/{streaming-DkpW1HwJ.mjs → streaming-CFwCzEvU.mjs} +1 -1
  152. package/dist/{subscribe-helpers-CBZOi6pk.mjs → subscribe-helpers-KgVEcn8L.mjs} +2 -2
  153. package/dist/sync/changelog.mjs +1 -1
  154. package/dist/testing/cleanupStoreContract.mjs +1 -1
  155. package/dist/testing/index.d.mts +4 -4
  156. package/dist/testing/index.mjs +10 -10
  157. package/dist/testing/outboxStoreContract.mjs +14 -3
  158. package/dist/testing/storageContract.mjs +1 -1
  159. package/dist/{transactionContext-DMmvcfdo.mjs → transactionContext-46KyUADP.mjs} +1 -1
  160. package/dist/{typeGuards-DHTnEs5X.mjs → typeGuards-t_CVgRXN.mjs} +1 -1
  161. package/dist/types/index.d.mts +1 -1
  162. package/dist/types/index.mjs +1 -1
  163. package/dist/types/storage.mjs +1 -1
  164. package/dist/{types-LQFwC37d.d.mts → types-9rvxn5Ym.d.mts} +46 -1
  165. package/dist/{types-BRU-Kd3t.d.mts → types-BVlowlm7.d.mts} +2 -2
  166. package/dist/{types-BqLyyH0o.mjs → types-CNQyOrLk.mjs} +4 -4
  167. package/dist/usage/index.mjs +0 -0
  168. package/dist/{userHelpers-CXySQFRg.mjs → userHelpers-DLueLQdQ.mjs} +1 -1
  169. package/dist/utils/index.d.mts +4 -4
  170. package/dist/utils/index.mjs +11 -11
  171. package/dist/{utils-BbGG8XNT.mjs → utils-CUFBrhq-.mjs} +14 -6
  172. package/dist/{validate-CidSeUrx.mjs → validate-DV3hRbsz.mjs} +2 -2
  173. package/dist/{versioning-C2r0eOZ4.mjs → versioning-BXwmj5SD.mjs} +3 -3
  174. package/dist/{versioning-B843jOYX.d.mts → versioning-P3V6ATyC.d.mts} +1 -1
  175. package/dist/workScope-CoGpuzDX.mjs +42 -0
  176. package/package.json +48 -39
  177. package/skills/arc/references/mcp.md +20 -0
  178. package/skills/arc/references/testing.md +0 -12
  179. package/skills/arc-code-review/references/anti-patterns.md +1 -1
  180. package/skills/arc-code-review/references/migration-recipes.md +0 -60
  181. package/skills/arc-code-review/references/mongokit-migration.md +0 -27
  182. package/skills/arc-module-publishing/references/package-manifest.md +3 -1
  183. package/dist/rateLimitKey-CewdR-m6.mjs +0 -15
@@ -1,5 +1,5 @@
1
- /*! @classytic/arc v2.38.0 | MIT | https://classytic.com */
2
- import { u as ValidationError } from "./errors-2ExmOgIJ.mjs";
1
+ /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
+ import { u as ValidationError } from "./errors-BHD3L8of.mjs";
3
3
  //#region src/utils/headers.ts
4
4
  /**
5
5
  * Canonical header typing + accessor.
@@ -1,4 +1,4 @@
1
- /*! @classytic/arc v2.38.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
2
  import { randomUUID } from "node:crypto";
3
3
  import fp from "fastify-plugin";
4
4
  //#region src/plugins/requestId.ts
@@ -1,3 +1,3 @@
1
1
 
2
- import { an as HookRegistration, cn as afterCreate, dn as beforeCreate, en as DefineHookOptions, fn as beforeDelete, hn as defineHook, in as HookPhase, ln as afterDelete, mn as createHookSystem, nn as HookHandler, on as HookSystem, pn as beforeUpdate, rn as HookOperation, sn as HookSystemOptions, tn as HookContext, un as afterUpdate } from "../index-B78WZom8.mjs";
2
+ import { an as HookRegistration, cn as afterCreate, dn as beforeCreate, en as DefineHookOptions, fn as beforeDelete, hn as defineHook, in as HookPhase, ln as afterDelete, mn as createHookSystem, nn as HookHandler, on as HookSystem, pn as beforeUpdate, rn as HookOperation, sn as HookSystemOptions, tn as HookContext, un as afterUpdate } from "../index-D3sIPcD4.mjs";
3
3
  export { type DefineHookOptions, type HookContext, type HookHandler, type HookOperation, type HookPhase, type HookRegistration, HookSystem, type HookSystemOptions, afterCreate, afterDelete, afterUpdate, beforeCreate, beforeDelete, beforeUpdate, createHookSystem, defineHook };
@@ -1,3 +1,3 @@
1
- /*! @classytic/arc v2.38.0 | MIT | https://classytic.com */
2
- import { a as beforeCreate, c as createHookSystem, i as afterUpdate, l as defineHook, n as afterCreate, o as beforeDelete, r as afterDelete, s as beforeUpdate, t as HookSystem } from "../HookSystem-C0ikzqQf.mjs";
1
+ /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
+ import { a as beforeCreate, c as createHookSystem, i as afterUpdate, l as defineHook, n as afterCreate, o as beforeDelete, r as afterDelete, s as beforeUpdate, t as HookSystem } from "../HookSystem-96nzZLmk.mjs";
3
3
  export { HookSystem, afterCreate, afterDelete, afterUpdate, beforeCreate, beforeDelete, beforeUpdate, createHookSystem, defineHook };
@@ -1,7 +1,7 @@
1
- /*! @classytic/arc v2.38.0 | MIT | https://classytic.com */
2
- import { n as requireSingleHeaderValue } from "../headers-DeXNifVj.mjs";
3
- import { n as createSafeGetOne, t as createIsDuplicateKeyError } from "../store-helpers-CIF4RG8s.mjs";
4
- import { t as createIdempotencyResult } from "../interface-DYPVscCU.mjs";
1
+ /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
+ import { n as requireSingleHeaderValue } from "../headers-BFEEshDS.mjs";
3
+ import { n as createSafeGetOne, t as createIsDuplicateKeyError } from "../store-helpers-BfyOd5i6.mjs";
4
+ import { t as createIdempotencyResult } from "../interface-DjtFnZxH.mjs";
5
5
  import { and, eq, exists, gt, lt, or, startsWith } from "@classytic/repo-core/filter";
6
6
  import { createHash } from "node:crypto";
7
7
  import fp from "fastify-plugin";
@@ -1,4 +1,4 @@
1
- /*! @classytic/arc v2.38.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
2
  //#region src/idempotency/stores/redis.ts
3
3
  var RedisIdempotencyStore = class {
4
4
  name = "redis";
@@ -5,7 +5,7 @@ import { a as QueryCacheConfig } from "./QueryCache-DFA-QrU9.mjs";
5
5
  import "./elevation-BXCfVcNG.mjs";
6
6
  import { n as FieldPermissionMap } from "./fields-I_EeRWND.mjs";
7
7
  import { n as EncryptionDirective } from "./types-ByHn9rEO.mjs";
8
- import { n as DomainEvent } from "./EventTransport-Cx60_s-6.mjs";
8
+ import { n as DomainEvent } from "./EventTransport-BPOQsEer.mjs";
9
9
  import { Filter } from "@classytic/repo-core/filter";
10
10
  import { AggDateBucket, AggMeasure, AggTopN, QueryOptions, StandardRepo, TenantPurgeStrategy, TransactionHandle } from "@classytic/repo-core/repository";
11
11
  import { KeysetPaginationResult, OffsetPaginationResult } from "@classytic/repo-core/pagination";
@@ -516,6 +516,17 @@ type ArcControllerLike = {
516
516
  update: (...args: never[]) => unknown;
517
517
  delete: (...args: never[]) => unknown;
518
518
  };
519
+ /**
520
+ * Constructor constraint for the four preset mixins (`BulkMixin`, `SlugMixin`,
521
+ * `SoftDeleteMixin`, `TreeMixin`).
522
+ *
523
+ * This is the ONE place `any[]` is unavoidable: TypeScript requires a mixin's
524
+ * base-class constraint to be `new (...args: any[]) => T` — `unknown[]` and
525
+ * `never[]` are both rejected with "A mixin class must have a constructor with
526
+ * a single rest parameter of type 'any[]'". Each mixin used to carry its own
527
+ * copy of this line and its own lint waiver; one definition, one waiver.
528
+ */
529
+ type MixinConstructor<T> = new (...args: any[]) => T;
519
530
  /**
520
531
  * Return type of the controller's `list` method.
521
532
  *
@@ -1104,6 +1115,33 @@ declare class QueryResolver {
1104
1115
  * doesn't gate visibility — see `core/fieldRulePredicates.ts`.
1105
1116
  */
1106
1117
  private getBlockedFields;
1118
+ /**
1119
+ * Is this projection path blocked — by its own name, or by a hidden ANCESTOR?
1120
+ *
1121
+ * `hidden: { secret: true }` hides the object, and an exact-name match left its children
1122
+ * reachable: `?select=secret.value` projected the very field the rule exists to withhold.
1123
+ * A rule on a parent covers everything under it, which is what "hidden" already means to
1124
+ * whoever wrote it.
1125
+ */
1126
+ private isBlockedProjection;
1127
+ /**
1128
+ * Refuse a read that FILTERS or SORTS on a `hidden` field.
1129
+ *
1130
+ * `hidden` was enforced on the surfaces that RETURN a value — the response, `select=`,
1131
+ * `_distinct`, aggregations — but a filter key never returns the field, it INTERROGATES it:
1132
+ * `?passwordHash[like]=^ab` narrows the result set, so the row count answers a question about
1133
+ * a value the caller may not read. A resource with no `allowedFilterFields` was a blind
1134
+ * existence oracle over every hidden field it declared.
1135
+ *
1136
+ * Rejected rather than dropped, unlike `select`. Dropping a projection narrows what comes
1137
+ * back; dropping a filter WIDENS the rows, which is the silent-permissive shape this
1138
+ * framework fails loudly on everywhere else.
1139
+ *
1140
+ * Compound keys (`$or`, `$and`) are walked, because the offending key can be nested inside
1141
+ * one. A dotted path is blocked by its own name or by a hidden ancestor, so a rule on
1142
+ * `secret` also covers `secret.value`.
1143
+ */
1144
+ private assertNoBlockedReadKeys;
1107
1145
  }
1108
1146
  //#endregion
1109
1147
  //#region src/core/BaseCrudController.d.ts
@@ -1392,7 +1430,9 @@ declare class BaseCrudController<TDoc = AnyRecord, TRepository extends Repositor
1392
1430
  count: number;
1393
1431
  }>>;
1394
1432
  /** `?_distinct=field` → `repo.distinct(field, filter)` */
1395
- protected dispatchDistinct(req: IRequestContext, field: string): Promise<IControllerResponse<unknown[]>>;
1433
+ protected dispatchDistinct(req: IRequestContext, field: string): Promise<IControllerResponse<{
1434
+ values: unknown[];
1435
+ }>>;
1396
1436
  /** `?_exists=true` → `repo.exists(filter)` */
1397
1437
  protected dispatchExists(req: IRequestContext): Promise<IControllerResponse<{
1398
1438
  exists: boolean;
@@ -1425,7 +1465,6 @@ declare class BaseCrudController<TDoc = AnyRecord, TRepository extends Repositor
1425
1465
  }
1426
1466
  //#endregion
1427
1467
  //#region src/core/mixins/bulk.d.ts
1428
- type Constructor$3<T> = new (...args: any[]) => T;
1429
1468
  /** Public surface contributed by BulkMixin. */
1430
1469
  interface BulkExt {
1431
1470
  bulkCreate(req: IRequestContext): Promise<IControllerResponse<AnyRecord[]>>;
@@ -1437,33 +1476,30 @@ interface BulkExt {
1437
1476
  deletedCount: number;
1438
1477
  }>>;
1439
1478
  }
1440
- declare function BulkMixin<TBase extends Constructor$3<BaseCrudController>>(Base: TBase): TBase & Constructor$3<BulkExt>;
1479
+ declare function BulkMixin<TBase extends MixinConstructor<BaseCrudController>>(Base: TBase): TBase & MixinConstructor<BulkExt>;
1441
1480
  //#endregion
1442
1481
  //#region src/core/mixins/slug.d.ts
1443
- type Constructor$2<T> = new (...args: any[]) => T;
1444
1482
  /** Public surface contributed by SlugMixin. */
1445
1483
  interface SlugExt {
1446
1484
  getBySlug(req: IRequestContext): Promise<IControllerResponse<AnyRecord>>;
1447
1485
  }
1448
- declare function SlugMixin<TBase extends Constructor$2<BaseCrudController>>(Base: TBase): TBase & Constructor$2<SlugExt>;
1486
+ declare function SlugMixin<TBase extends MixinConstructor<BaseCrudController>>(Base: TBase): TBase & MixinConstructor<SlugExt>;
1449
1487
  //#endregion
1450
1488
  //#region src/core/mixins/tree.d.ts
1451
- type Constructor$1<T> = new (...args: any[]) => T;
1452
1489
  /** Public surface contributed by TreeMixin. */
1453
1490
  interface TreeExt {
1454
1491
  getTree(req: IRequestContext): Promise<IControllerResponse<AnyRecord[]>>;
1455
1492
  getChildren(req: IRequestContext): Promise<IControllerResponse<AnyRecord[]>>;
1456
1493
  }
1457
- declare function TreeMixin<TBase extends Constructor$1<BaseCrudController>>(Base: TBase): TBase & Constructor$1<TreeExt>;
1494
+ declare function TreeMixin<TBase extends MixinConstructor<BaseCrudController>>(Base: TBase): TBase & MixinConstructor<TreeExt>;
1458
1495
  //#endregion
1459
1496
  //#region src/core/mixins/softDelete.d.ts
1460
- type Constructor<T> = new (...args: any[]) => T;
1461
1497
  /** Public surface contributed by SoftDeleteMixin. */
1462
1498
  interface SoftDeleteExt {
1463
1499
  getDeleted(req: IRequestContext): Promise<IControllerResponse<PaginationResult<AnyRecord>>>;
1464
1500
  restore(req: IRequestContext): Promise<IControllerResponse<AnyRecord>>;
1465
1501
  }
1466
- declare function SoftDeleteMixin<TBase extends Constructor<BaseCrudController>>(Base: TBase): TBase & Constructor<SoftDeleteExt>;
1502
+ declare function SoftDeleteMixin<TBase extends MixinConstructor<BaseCrudController>>(Base: TBase): TBase & MixinConstructor<SoftDeleteExt>;
1467
1503
  //#endregion
1468
1504
  //#region src/core/BaseController.d.ts
1469
1505
  /**
@@ -1531,7 +1567,7 @@ interface BaseController<TDoc extends AnyRecord = AnyRecord, _TRepository extend
1531
1567
  deletedCount: number;
1532
1568
  }>>;
1533
1569
  }
1534
- declare const BaseController_base: (new (repository: any, options?: BaseControllerOptions) => BaseCrudController<AnyRecord, any>) & (new (...args: any[]) => BulkExt) & (new (...args: any[]) => SlugExt) & (new (...args: any[]) => TreeExt) & (new (...args: any[]) => SoftDeleteExt);
1570
+ declare const BaseController_base: (new (repository: any, options?: BaseControllerOptions) => BaseCrudController<AnyRecord, any>) & MixinConstructor<BulkExt> & MixinConstructor<SlugExt> & MixinConstructor<TreeExt> & MixinConstructor<SoftDeleteExt>;
1535
1571
  /**
1536
1572
  * Fully-composed controller: `BaseCrudController` + SoftDelete + Tree +
1537
1573
  * Slug + Bulk. Drop-in replacement for the pre-2.11 god class. The
@@ -1,5 +1,5 @@
1
1
 
2
- import { _ as HealthCheck, a as ModuleContribution, f as ScheduleDefinition, n as ArcModuleInput, r as ArcModuleRegistry, s as ModuleSetupContext, t as ArcModule } from "./types-BRU-Kd3t.mjs";
2
+ import { _ as HealthCheck, a as ModuleContribution, f as ScheduleDefinition, n as ArcModuleInput, r as ArcModuleRegistry, s as ModuleSetupContext, t as ArcModule } from "./types-BVlowlm7.mjs";
3
3
  import { FastifyInstance } from "fastify";
4
4
  //#region src/factory/module/contributions.d.ts
5
5
  /**
@@ -201,7 +201,7 @@ declare function getModuleExports<TExports = unknown>(fastify: FastifyInstance,
201
201
  * spelling that question as
202
202
  *
203
203
  * ```ts
204
- * (fastify as unknown as { arc?: { modules?: Record<string, unknown> } })
204
+ * (fastify as { arc?: { modules?: Record<string, unknown> } })
205
205
  * .arc?.modules?.inventory;
206
206
  * ```
207
207
  *
@@ -1,8 +1,8 @@
1
1
 
2
2
  import { i as RequestScope } from "./types-Ddl9OjmE.mjs";
3
3
  import { l as PermissionCheck, t as AnyRecord } from "./base-C-NL2fTi.mjs";
4
- import { C as RequestContext, Et as ActionDefinition, F as FastifyWithDecorators, Fn as IControllerResponse, H as CrudController, In as IRequestContext, L as RequestWithExtras, Pn as IController, T as CrudRouterOptions, U as ResourceConfig, V as ResourceDefinition, et as RouteSchemaOptions, jt as RouteMcpConfig, tt as ArcFieldRule, ut as AggregationConfig } from "./index-B78WZom8.mjs";
5
- import "./fastify-augmentation-jYA2oHyL.mjs";
4
+ import { C as RequestContext, Et as ActionDefinition, F as FastifyWithDecorators, Fn as IControllerResponse, H as CrudController, In as IRequestContext, L as RequestWithExtras, Pn as IController, T as CrudRouterOptions, U as ResourceConfig, V as ResourceDefinition, et as RouteSchemaOptions, jt as RouteMcpConfig, tt as ArcFieldRule, ut as AggregationConfig } from "./index-D3sIPcD4.mjs";
5
+ import "./fastify-augmentation-HncZMmze.mjs";
6
6
  import { Filter } from "@classytic/repo-core/filter";
7
7
  import { FastifyReply, FastifyRequest, RouteHandlerMethod } from "fastify";
8
8
  import { z } from "zod";
package/dist/index.d.mts CHANGED
@@ -1,9 +1,9 @@
1
1
 
2
2
  import { c as DataPolicy, d as UserBase, l as PermissionCheck, n as ArcRequest, o as UserOrganization, r as JWTPayload, s as AuthorizationDecision, t as AnyRecord, u as PermissionContext } from "./base-C-NL2fTi.mjs";
3
- import { A as RequestIdOptions, An as WriteVerbKey, B as defineResource, Bt as BaseController, C as RequestContext, Cn as ControllerConstructionOptions, D as HealthCheck, Dn as MutationWriteContext, E as GracefulShutdownOptions, F as FastifyWithDecorators, Fn as IControllerResponse, Ft as AuthPluginOptions, Gt as SlugExt, H as CrudController, Ht as SoftDeleteMixin, In as IRequestContext, Jt as BulkMixin, Kt as SlugMixin, L as RequestWithExtras, Ln as RawRouteHandler, Mn as ControllerLike, N as FastifyRequestExtras, Nt as RateLimitConfig, O as HealthOptions, On as ResourceWrites, P as FastifyWithAuth, Pn as IController, Q as MiddlewareConfig, Rn as RouteHandler, S as QueryParserInterface, Sn as ControllerConfigurableOptions, T as CrudRouterOptions, U as ResourceConfig, Ut as TreeExt, V as ResourceDefinition, Vt as SoftDeleteExt, Wt as TreeMixin, X as CrudRouteKey, Y as PresetResult, Yt as BaseCrudController, Z as CrudSchemas, _n as ArcDeleteResult, a as InferAdapterDoc, bn as ArcUpdateResult, c as TypedController, ct as AggMeasureShorthand, d as PaginationResult, dt as AggregationDateRangeRequirement, et as RouteSchemaOptions, f as IntrospectionData, ft as AggregationIndexHint, g as ArcInternalMetadata, gn as ArcCreateResult, gt as AggregationsMap, h as ResourceMetadata, ht as AggregationRateLimit, i as ValidationResult, k as IntrospectionPluginOptions, kn as WriteContext, l as TypedRepository, lt as AggregationCacheConfig, m as RegistryStats, mt as AggregationMaterializedResult, n as ConfigError, nt as FieldRule, o as InferDocType, ot as EventDefinition, p as RegistryEntry, pt as AggregationMaterializedContext, q as PresetFunction, qt as BulkExt, r as ValidateOptions, s as InferResourceDoc, st as AggMeasureInput, t as RouteHandlerMethod, u as TypedResourceConfig, ut as AggregationConfig, vn as ArcGetResult, w as ServiceContext, wn as ListResult, xn as BaseControllerOptions, y as OwnershipCheck, yn as ArcListResult } from "./index-B78WZom8.mjs";
3
+ import { A as RequestIdOptions, An as WriteVerbKey, B as defineResource, Bt as BaseController, C as RequestContext, Cn as ControllerConstructionOptions, D as HealthCheck, Dn as MutationWriteContext, E as GracefulShutdownOptions, F as FastifyWithDecorators, Fn as IControllerResponse, Ft as AuthPluginOptions, Gt as SlugExt, H as CrudController, Ht as SoftDeleteMixin, In as IRequestContext, Jt as BulkMixin, Kt as SlugMixin, L as RequestWithExtras, Ln as RawRouteHandler, Mn as ControllerLike, N as FastifyRequestExtras, Nt as RateLimitConfig, O as HealthOptions, On as ResourceWrites, P as FastifyWithAuth, Pn as IController, Q as MiddlewareConfig, Rn as RouteHandler, S as QueryParserInterface, Sn as ControllerConfigurableOptions, T as CrudRouterOptions, U as ResourceConfig, Ut as TreeExt, V as ResourceDefinition, Vt as SoftDeleteExt, Wt as TreeMixin, X as CrudRouteKey, Y as PresetResult, Yt as BaseCrudController, Z as CrudSchemas, _n as ArcDeleteResult, a as InferAdapterDoc, bn as ArcUpdateResult, c as TypedController, ct as AggMeasureShorthand, d as PaginationResult, dt as AggregationDateRangeRequirement, et as RouteSchemaOptions, f as IntrospectionData, ft as AggregationIndexHint, g as ArcInternalMetadata, gn as ArcCreateResult, gt as AggregationsMap, h as ResourceMetadata, ht as AggregationRateLimit, i as ValidationResult, k as IntrospectionPluginOptions, kn as WriteContext, l as TypedRepository, lt as AggregationCacheConfig, m as RegistryStats, mt as AggregationMaterializedResult, n as ConfigError, nt as FieldRule, o as InferDocType, ot as EventDefinition, p as RegistryEntry, pt as AggregationMaterializedContext, q as PresetFunction, qt as BulkExt, r as ValidateOptions, s as InferResourceDoc, st as AggMeasureInput, t as RouteHandlerMethod, u as TypedResourceConfig, ut as AggregationConfig, vn as ArcGetResult, w as ServiceContext, wn as ListResult, xn as BaseControllerOptions, y as OwnershipCheck, yn as ArcListResult } from "./index-D3sIPcD4.mjs";
4
4
  import { a as applyFieldWritePermissions, i as applyFieldReadPermissions, n as FieldPermissionMap, o as fields, t as FieldPermission } from "./fields-I_EeRWND.mjs";
5
- import "./fastify-augmentation-jYA2oHyL.mjs";
6
- import { A as CRUD_OPERATIONS, B as HookOperation, C as SeamedResourceConfig, E as defineAction, F as DEFAULT_SORT, G as MUTATION_OPERATIONS, H as MAX_FILTER_DEPTH, I as DEFAULT_TENANT_FIELD, J as SYSTEM_FIELDS, K as MutationOperation, L as DEFAULT_UPDATE_METHOD, M as DEFAULT_ID_FIELD, N as DEFAULT_LIMIT, P as DEFAULT_MAX_LIMIT, R as HOOK_OPERATIONS, S as ResourceSeams, U as MAX_REGEX_LENGTH, V as HookPhase, W as MAX_SEARCH_LENGTH, b as defineResourceVariants, c as nativePolicyFilter, h as getControllerScope, j as CrudOperation, k as defineAggregation, q as RESERVED_QUERY_PARAMS, s as NativePolicyFilter, w as mergeResourceConfig, x as AdapterLike, z as HOOK_PHASES } from "./index-BRoDtjek.mjs";
5
+ import "./fastify-augmentation-HncZMmze.mjs";
6
+ import { A as CRUD_OPERATIONS, B as HookOperation, C as SeamedResourceConfig, E as defineAction, F as DEFAULT_SORT, G as MUTATION_OPERATIONS, H as MAX_FILTER_DEPTH, I as DEFAULT_TENANT_FIELD, J as SYSTEM_FIELDS, K as MutationOperation, L as DEFAULT_UPDATE_METHOD, M as DEFAULT_ID_FIELD, N as DEFAULT_LIMIT, P as DEFAULT_MAX_LIMIT, R as HOOK_OPERATIONS, S as ResourceSeams, U as MAX_REGEX_LENGTH, V as HookPhase, W as MAX_SEARCH_LENGTH, b as defineResourceVariants, c as nativePolicyFilter, h as getControllerScope, j as CrudOperation, k as defineAggregation, q as RESERVED_QUERY_PARAMS, s as NativePolicyFilter, w as mergeResourceConfig, x as AdapterLike, z as HOOK_PHASES } from "./index-SCsOJxWB.mjs";
7
7
  import { $ as requireAuth, C as requireServiceScope, G as createOrgPermissions, H as DynamicPermissionMatrixConfig, J as allowPublic, K as allOf, S as requireScopeContext, V as DynamicPermissionMatrix, W as createDynamicPermissionMatrix, Y as anyOf, Z as denyAll, _ as publicReadAdminWrite, b as requireOrgMembership, d as authenticated, et as requireOwnership, f as fullPublic, g as publicRead, h as presets_d_exports, it as when, nt as requireRoles, p as ownerWithAdminBypass, u as adminOnly, v as readOnly, w as requireTeamMembership, x as requireOrgRole, y as requireOrgInScope } from "./index-BtYoMip1.mjs";
8
8
  import { a as NotFoundError, d as ValidationError, f as createDomainError, i as ForbiddenError, t as ArcError, u as UnauthorizedError } from "./errors-BGdVwP25.mjs";
9
9
  //#region src/index.d.ts
package/dist/index.mjs CHANGED
@@ -1,14 +1,14 @@
1
- /*! @classytic/arc v2.38.0 | MIT | https://classytic.com */
2
- 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-BONghE1Y.mjs";
3
- import { d as createDomainError, i as NotFoundError, l as UnauthorizedError, r as ForbiddenError, t as ArcError, u as ValidationError } from "./errors-2ExmOgIJ.mjs";
4
- import { a as BulkMixin, h as nativePolicyFilter, i as SlugMixin, n as TreeMixin, o as BaseCrudController, r as SoftDeleteMixin, t as BaseController } from "./BaseController-CYaDvmOB.mjs";
5
- import { t as defineAggregation } from "./defineAggregation-0KBvqEEC.mjs";
6
- import { i as fields, n as applyFieldWritePermissions, t as applyFieldReadPermissions } from "./fields-Cha2QCKH.mjs";
7
- import { l as getControllerScope } from "./actionPermissions-jlFZ1it4.mjs";
8
- import { a as ResourceDefinition, t as defineResource } from "./defineResource-BMdyRelW.mjs";
9
- import { a as mergeResourceConfig, i as defineResourceVariants, o as defineAction } from "./core-8She7FgF.mjs";
10
- import { B as requireAuth, C as createOrgPermissions, D as requireScopeContext, E as requireOrgRole, F as allowPublic, G as when, I as anyOf, N as allOf, O as requireServiceScope, R as denyAll, S as createDynamicPermissionMatrix, T as requireOrgMembership, U as requireRoles, V as requireOwnership, a as adminOnly, c as ownerWithAdminBypass, d as publicRead, f as publicReadAdminWrite, k as requireTeamMembership, o as authenticated, p as readOnly, s as fullPublic, u as presets_exports, w as requireOrgInScope } from "./permissions-H7Zcb82Z.mjs";
1
+ /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
+ 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-BQ2FbhPB.mjs";
3
+ import { d as createDomainError, i as NotFoundError, l as UnauthorizedError, r as ForbiddenError, t as ArcError, u as ValidationError } from "./errors-BHD3L8of.mjs";
4
+ import { a as BulkMixin, h as nativePolicyFilter, i as SlugMixin, n as TreeMixin, o as BaseCrudController, r as SoftDeleteMixin, t as BaseController } from "./BaseController-BqJtbiUA.mjs";
5
+ import { t as defineAggregation } from "./defineAggregation-BDA2Tw7v.mjs";
6
+ import { i as fields, n as applyFieldWritePermissions, t as applyFieldReadPermissions } from "./fields-fA-Dkou5.mjs";
7
+ import { l as getControllerScope } from "./actionPermissions-4OGbe3Hf.mjs";
8
+ import { a as ResourceDefinition, t as defineResource } from "./defineResource-DaIySrQr.mjs";
9
+ import { a as mergeResourceConfig, i as defineResourceVariants, o as defineAction } from "./core-CsZR037F.mjs";
10
+ import { B as requireAuth, C as createOrgPermissions, D as requireScopeContext, E as requireOrgRole, F as allowPublic, G as when, I as anyOf, N as allOf, O as requireServiceScope, R as denyAll, S as createDynamicPermissionMatrix, T as requireOrgMembership, U as requireRoles, V as requireOwnership, a as adminOnly, c as ownerWithAdminBypass, d as publicRead, f as publicReadAdminWrite, k as requireTeamMembership, o as authenticated, p as readOnly, s as fullPublic, u as presets_exports, w as requireOrgInScope } from "./permissions-C0GpDsB_.mjs";
11
11
  //#region src/index.ts
12
- const version = "2.38.0";
12
+ const version = "2.40.0";
13
13
  //#endregion
14
14
  export { ArcError, BaseController, BaseCrudController, BulkMixin, CRUD_OPERATIONS, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, ForbiddenError, HOOK_OPERATIONS, HOOK_PHASES, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, NotFoundError, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, SlugMixin, SoftDeleteMixin, TreeMixin, UnauthorizedError, ValidationError, adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, authenticated, createDomainError, createDynamicPermissionMatrix, createOrgPermissions, defineAction, defineAggregation, defineResource, defineResourceVariants, denyAll, fields, fullPublic, getControllerScope, mergeResourceConfig, nativePolicyFilter, ownerWithAdminBypass, presets_exports as permissions, publicRead, publicReadAdminWrite, readOnly, requireAuth, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, version, when };
@@ -1,4 +1,4 @@
1
- /*! @classytic/arc v2.38.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
2
  import * as fs from "node:fs/promises";
3
3
  import * as path from "node:path";
4
4
  import { dirname, join } from "node:path";
@@ -605,7 +605,7 @@ export const authResource = defineResource({
605
605
  tag: 'Authentication',
606
606
  prefix: '/auth',
607
607
 
608
- adapter: createAdapter(User${ts ? " as unknown as never" : ""}, userRepository${ts ? " as unknown as never" : ""}),
608
+ adapter: createAdapter(User${ts ? " as never" : ""}, userRepository${ts ? " as never" : ""}),
609
609
  disableDefaultRoutes: true,
610
610
 
611
611
  routes: [
@@ -661,7 +661,7 @@ export const userProfileResource = defineResource({
661
661
  tag: 'User Profile',
662
662
  prefix: '/users',
663
663
 
664
- adapter: createAdapter(User${ts ? " as unknown as never" : ""}, userRepository${ts ? " as unknown as never" : ""}),
664
+ adapter: createAdapter(User${ts ? " as never" : ""}, userRepository${ts ? " as never" : ""}),
665
665
  disableDefaultRoutes: true,
666
666
 
667
667
  routes: [
@@ -702,7 +702,7 @@ import { mongodbAdapter } from '@better-auth/mongo-adapter';` : "";
702
702
  useBearer ? `import { bearer } from 'better-auth/plugins/bearer';` : "",
703
703
  useApiKey ? `import { apiKey } from '@better-auth/api-key';` : ""
704
704
  ].filter(Boolean).join("\n");
705
- const dbAdapter = useMongo ? config.typescript ? `database: mongodbAdapter(mongoose.connection.getClient().db() as unknown as never),` : `database: mongodbAdapter(mongoose.connection.getClient().db()),` : `// Configure your database adapter here
705
+ const dbAdapter = useMongo ? config.typescript ? `database: mongodbAdapter(mongoose.connection.getClient().db() as never),` : `database: mongodbAdapter(mongoose.connection.getClient().db()),` : `// Configure your database adapter here
706
706
  // See: https://www.better-auth.com/docs/concepts/database`;
707
707
  const pluginEntries = [
708
708
  useBearer ? ` bearer(),` : "",
@@ -962,7 +962,7 @@ export async function resetPassword(request${ts ? ": FastifyRequest" : ""}, repl
962
962
  */
963
963
  export async function getUserProfile(request${ts ? ": FastifyRequest" : ""}, reply${ts ? ": FastifyReply" : ""}) {
964
964
  try {
965
- const requestUser = (request${ts ? " as unknown as { user?: { _id?: string; id?: string } }" : ""}).user;
965
+ const requestUser = (request${ts ? " as { user?: { _id?: string; id?: string } }" : ""}).user;
966
966
  const userId = requestUser?._id || requestUser?.id;
967
967
  if (!userId) {
968
968
  return reply.code(401).send({ error: 'Authentication required', code: 'arc.unauthorized' });
@@ -985,7 +985,7 @@ export async function getUserProfile(request${ts ? ": FastifyRequest" : ""}, rep
985
985
  */
986
986
  export async function updateUserProfile(request${ts ? ": FastifyRequest" : ""}, reply${ts ? ": FastifyReply" : ""}) {
987
987
  try {
988
- const requestUser = (request${ts ? " as unknown as { user?: { _id?: string; id?: string } }" : ""}).user;
988
+ const requestUser = (request${ts ? " as { user?: { _id?: string; id?: string } }" : ""}).user;
989
989
  const userId = requestUser?._id || requestUser?.id;
990
990
  if (!userId) {
991
991
  return reply.code(401).send({ error: 'Authentication required', code: 'arc.unauthorized' });
@@ -2727,7 +2727,7 @@ interface FlexibleMultiTenantOptions {
2727
2727
  tenantField?: string;
2728
2728
  }
2729
2729
  ` : `
2730
- const { multiTenantPreset } = require('@classytic/arc/presets/tenant');
2730
+ import { multiTenantPreset } from '@classytic/arc/presets/tenant';
2731
2731
  `}
2732
2732
  export function flexibleMultiTenantPreset(options${ts ? ": FlexibleMultiTenantOptions = {}" : " = {}"}) {
2733
2733
  const { tenantField = 'organizationId' } = options;
@@ -2972,7 +2972,7 @@ ${ts ? "import type { UserDocument } from './user.model.js';\nimport type { Clie
2972
2972
  ${ts ? "type ID = string | Types.ObjectId;\n" : ""}
2973
2973
  class UserRepository extends Repository${ts ? "<UserDocument>" : ""} {
2974
2974
  constructor() {
2975
- super(User${ts ? " as unknown as never" : ""}, [
2975
+ super(User${ts ? " as never" : ""}, [
2976
2976
  methodRegistryPlugin(),
2977
2977
  mongoOperationsPlugin(),
2978
2978
  ]);
@@ -3058,7 +3058,7 @@ import userRepository from './user.repository.js';
3058
3058
 
3059
3059
  class UserController extends BaseController {
3060
3060
  constructor() {
3061
- super(userRepository${config.typescript ? " as unknown as never" : ""});
3061
+ super(userRepository${config.typescript ? " as never" : ""});
3062
3062
  }
3063
3063
 
3064
3064
  // Custom user operations can be added here
@@ -1,5 +1,5 @@
1
1
 
2
- import { n as DomainEvent } from "../EventTransport-Cx60_s-6.mjs";
2
+ import { n as DomainEvent } from "../EventTransport-BPOQsEer.mjs";
3
3
  import { c as WebSocketClient, l as WebSocketMessage } from "../websocket-BOXVggMf.mjs";
4
4
  import { FastifyPluginAsync, FastifyRequest } from "fastify";
5
5
  //#region src/integrations/event-gateway.d.ts
@@ -1,11 +1,11 @@
1
- /*! @classytic/arc v2.38.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
2
  import fp from "fastify-plugin";
3
3
  //#region src/integrations/event-gateway.ts
4
4
  const eventGatewayPluginImpl = async (fastify, opts = {}) => {
5
5
  const { auth = true, orgScoped = false, roomPolicy, maxMessageBytes, maxSubscriptionsPerClient, authenticate } = opts;
6
6
  if (auth && !authenticate && !fastify.hasDecorator("authenticate")) throw new Error("[arc-event-gateway] auth is true but fastify.authenticate is not registered. Register an auth plugin first, provide a custom authenticate function, or set auth: false.");
7
7
  if (opts.sse !== false) {
8
- const { default: ssePlugin } = await import("../sse-D4MYqkic.mjs").then((n) => n.r);
8
+ const { default: ssePlugin } = await import("../sse-DbyXoQun.mjs").then((n) => n.r);
9
9
  await fastify.register(ssePlugin, {
10
10
  path: opts.sse?.path ?? "/events/stream",
11
11
  requireAuth: auth,
@@ -2,7 +2,7 @@
2
2
  import { c as WebSocketClient, l as WebSocketMessage, u as WebSocketPluginOptions } from "../websocket-BOXVggMf.mjs";
3
3
  import { EventGatewayOptions } from "./event-gateway.mjs";
4
4
  import { a as JobMeta, c as JobsPluginOptions, i as JobDispatcher, l as QueueStats, n as JobDefinition, r as JobDispatchOptions } from "../index-eyg5WEcy.mjs";
5
- import { _ as ToolDefinition, c as McpAuthResult, d as McpResourceConfig, f as PromptDefinition, g as ToolContext, h as ToolAnnotations, n as CallToolResult, o as CrudOperation, r as CreateMcpServerConfig, t as BetterAuthHandler, u as McpPluginOptions } from "../types-LQFwC37d.mjs";
5
+ import { _ as ToolDefinition, c as McpAuthResult, d as McpResourceConfig, f as PromptDefinition, g as ToolContext, h as ToolAnnotations, n as CallToolResult, o as CrudOperation, r as CreateMcpServerConfig, t as BetterAuthHandler, u as McpPluginOptions } from "../types-9rvxn5Ym.mjs";
6
6
  import { StreamlinePluginOptions, WorkflowLike, WorkflowRunLike } from "./streamline.mjs";
7
7
  import { WebhookDeliveryRecord, WebhookManager, WebhookPluginOptions, WebhookStore, WebhookSubscription } from "./webhooks.mjs";
8
8
  export type { BetterAuthHandler, CallToolResult, CreateMcpServerConfig, CrudOperation, EventGatewayOptions, JobDefinition, JobDispatchOptions, JobDispatcher, JobMeta, JobsPluginOptions, McpAuthResult, McpPluginOptions, McpResourceConfig, PromptDefinition, QueueStats, StreamlinePluginOptions, ToolAnnotations, ToolContext, ToolDefinition, WebSocketClient, WebSocketMessage, WebSocketPluginOptions, WebhookDeliveryRecord, WebhookManager, WebhookPluginOptions, WebhookStore, WebhookSubscription, WorkflowLike, WorkflowRunLike };
@@ -1,2 +1,2 @@
1
- /*! @classytic/arc v2.38.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
2
  export {};
@@ -1,5 +1,5 @@
1
- /*! @classytic/arc v2.38.0 | MIT | https://classytic.com */
2
- import { n as evaluateAndApplyPermission } from "../../authorizationDecision-BP8GHtjc.mjs";
1
+ /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
+ import { n as evaluateAndApplyPermission } from "../../authorizationDecision-D_LFvMlm.mjs";
3
3
  import fp from "fastify-plugin";
4
4
  //#region src/integrations/jobs/execution.ts
5
5
  async function executeTimedHandler(options) {
@@ -1,9 +1,10 @@
1
1
 
2
2
  import { i as RequestScope } from "../../types-Ddl9OjmE.mjs";
3
3
  import { l as PermissionCheck } from "../../base-C-NL2fTi.mjs";
4
- import { Fn as IControllerResponse, In as IRequestContext, V as ResourceDefinition, zn as ServerAccessor } from "../../index-B78WZom8.mjs";
4
+ import { Fn as IControllerResponse, In as IRequestContext, V as ResourceDefinition, zn as ServerAccessor } from "../../index-D3sIPcD4.mjs";
5
5
  import { n as FieldPermissionMap } from "../../fields-I_EeRWND.mjs";
6
- import { _ as ToolDefinition, a as CrudDescriptionOverride, c as McpAuthResult, d as McpResourceConfig, f as PromptDefinition, g as ToolContext, h as ToolAnnotations, i as CrudDescriptionMeta, l as McpExecutionWiring, m as SessionEntry, n as CallToolResult, o as CrudOperation, p as PromptResult, r as CreateMcpServerConfig, s as McpAuthResolver, t as BetterAuthHandler, u as McpPluginOptions } from "../../types-LQFwC37d.mjs";
6
+ import { _ as ToolDefinition, a as CrudDescriptionOverride, c as McpAuthResult, d as McpResourceConfig, f as PromptDefinition, g as ToolContext, h as ToolAnnotations, i as CrudDescriptionMeta, l as McpExecutionWiring, m as SessionEntry, n as CallToolResult, o as CrudOperation, p as PromptResult, r as CreateMcpServerConfig, s as McpAuthResolver, t as BetterAuthHandler, u as McpPluginOptions } from "../../types-9rvxn5Ym.mjs";
7
+ import { i as resolveToolCollisions, n as McpServerInstance, r as createMcpServer, t as AuthRef } from "../../createMcpServer-BVTs2S5G.mjs";
7
8
  import { ErrorContract } from "@classytic/repo-core/errors";
8
9
  import { FastifyPluginAsync } from "fastify";
9
10
  import { z } from "zod";
@@ -96,50 +97,6 @@ interface CreateMcpAuthFromBetterAuthApiKeyOptions {
96
97
  */
97
98
  declare function createMcpAuthFromBetterAuthApiKey(auth: BetterAuthHandler, options?: CreateMcpAuthFromBetterAuthApiKeyOptions): McpAuthResolver;
98
99
  //#endregion
99
- //#region src/integrations/mcp/createMcpServer.d.ts
100
- /**
101
- * Mutable auth ref — updated per-request by mcpPlugin.
102
- * Tool handlers read from this to get the current request's auth context.
103
- */
104
- interface AuthRef {
105
- current: McpAuthResult | null;
106
- }
107
- /**
108
- * Create a configured MCP server from declarative config.
109
- *
110
- * @param config - Server name, version, tools, prompts
111
- * @returns McpServer instance (not yet connected to a transport)
112
- */
113
- declare function createMcpServer(config: CreateMcpServerConfig, authRef?: AuthRef): Promise<McpServerInstance>;
114
- /**
115
- * Detect and resolve duplicate MCP tool names across the assembled tool list.
116
- *
117
- * Two outcomes:
118
- *
119
- * 1. **Auto-namespace** — when one tool's `source` carries a `preset:<name>`
120
- * prefix and the other doesn't, the preset tool is renamed to
121
- * `<presetName>_<originalName>` (e.g. softDelete's `restore_post`
122
- * becomes `softdelete_restore_post` when the user defines
123
- * `actions.restore`). The user's tool wins the canonical name because
124
- * it's the more-specific intent.
125
- *
126
- * 2. **Typed throw** — every other collision (two user actions, two
127
- * custom routes, two presets) raises `ArcError('arc.mcp.tool_name_collision')`
128
- * naming both sources so the host's stack trace points at the
129
- * resource definitions, not the MCP SDK internals.
130
- *
131
- * Exported for the testing harness so collision behaviour can be exercised
132
- * without a full server boot.
133
- */
134
- declare function resolveToolCollisions(tools: readonly ToolDefinition[]): ToolDefinition[];
135
- /** Minimal interface for McpServer — avoids hard SDK type dependency */
136
- interface McpServerInstance {
137
- connect: (transport: unknown) => Promise<void>;
138
- registerTool: (name: string, config: Record<string, unknown>, handler: (input: Record<string, unknown>, extra: Record<string, unknown>) => unknown) => unknown;
139
- registerPrompt: (name: string, config: Record<string, unknown>, handler: (args: Record<string, unknown>) => unknown) => void;
140
- resource: (...args: unknown[]) => void;
141
- }
142
- //#endregion
143
100
  //#region src/integrations/mcp/crud-tools.d.ts
144
101
  /**
145
102
  * Default description for a CRUD tool. Enriches list descriptions with the
@@ -1,5 +1,5 @@
1
- /*! @classytic/arc v2.38.0 | MIT | https://classytic.com */
2
- import { a as defaultCrudDescription, c as mcpHandlerAdapter, d as toCallToolResult, f as toCallToolSuccess, h as resolveToolCollisions, i as fieldRulesToZod, l as permissionDeniedResult, m as createMcpServer, n as mcpPlugin, o as resolveCrudDescription, p as buildRequestContext, r as resourceToTools, s as invokeController, t as filterResourcesForMcp, u as toCallToolError } from "../../mcpPlugin-KWsezMx7.mjs";
1
+ /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
+ import { a as defaultCrudDescription, c as mcpHandlerAdapter, d as toCallToolResult, f as toCallToolSuccess, h as resolveToolCollisions, i as fieldRulesToZod, l as permissionDeniedResult, m as createMcpServer, n as mcpPlugin, o as resolveCrudDescription, p as buildRequestContext, r as resourceToTools, s as invokeController, t as filterResourcesForMcp, u as toCallToolError } from "../../mcpPlugin-D-3OLxNz.mjs";
3
3
  //#region src/integrations/mcp/defineTool.ts
4
4
  /**
5
5
  * Define a type-safe MCP tool.
@@ -1,6 +1,26 @@
1
1
 
2
- import { c as McpAuthResult, u as McpPluginOptions } from "../../types-LQFwC37d.mjs";
2
+ import { c as McpAuthResult, u as McpPluginOptions } from "../../types-9rvxn5Ym.mjs";
3
+ import { n as McpServerInstance } from "../../createMcpServer-BVTs2S5G.mjs";
4
+ import { Client } from "@modelcontextprotocol/client";
3
5
  //#region src/integrations/mcp/testing.d.ts
6
+ /** An MCP client bound to a live loopback server, plus its teardown. */
7
+ interface ConnectedMcpTestClient {
8
+ /** The connected SDK client — full `listTools` / `callTool` / `listPrompts` surface. */
9
+ client: Client;
10
+ /** Closes the client and the HTTP server. Always await it. */
11
+ close: () => Promise<void>;
12
+ }
13
+ /**
14
+ * Serve an already-built `McpServer` on an ephemeral loopback port and connect
15
+ * a client to it.
16
+ *
17
+ * Split out from {@link createTestMcpClient} because arc's own MCP suites build
18
+ * a server directly and only need the connection — five of them had each grown a
19
+ * private copy of the same connect helper against the v1 in-memory transport.
20
+ * One implementation, two entry points: this for a server you built, that for
21
+ * one built from resources.
22
+ */
23
+ declare function connectMcpTestClient(server: McpServerInstance | unknown): Promise<ConnectedMcpTestClient>;
4
24
  interface TestMcpClientOptions {
5
25
  /** MCP plugin options (resources, overrides, etc.) — same as mcpPlugin config */
6
26
  pluginOptions?: Pick<McpPluginOptions, "resources" | "overrides" | "expose" | "exclude" | "toolNamePrefix" | "extraTools" | "extraPrompts" | "instructions">;
@@ -50,4 +70,4 @@ interface TestMcpClient {
50
70
  */
51
71
  declare function createTestMcpClient(options?: TestMcpClientOptions): Promise<TestMcpClient>;
52
72
  //#endregion
53
- export { TestMcpClient, TestMcpClientOptions, createTestMcpClient };
73
+ export { ConnectedMcpTestClient, TestMcpClient, TestMcpClientOptions, connectMcpTestClient, createTestMcpClient };
@@ -1,26 +1,58 @@
1
- /*! @classytic/arc v2.38.0 | MIT | https://classytic.com */
2
- import { m as createMcpServer, r as resourceToTools, t as filterResourcesForMcp } from "../../mcpPlugin-KWsezMx7.mjs";
1
+ /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
+ import { m as createMcpServer, r as resourceToTools, t as filterResourcesForMcp } from "../../mcpPlugin-D-3OLxNz.mjs";
3
3
  //#region src/integrations/mcp/testing.ts
4
4
  /**
5
- * @classytic/arc/mcp/testing — MCP Test Utilities
5
+ * Serve an already-built `McpServer` on an ephemeral loopback port and connect
6
+ * a client to it.
6
7
  *
7
- * Helpers for testing MCP tool integration without raw JSON-RPC parsing.
8
- * Uses the MCP SDK's InMemoryTransport for fast, in-process testing.
9
- *
10
- * @example
11
- * ```typescript
12
- * import { createTestMcpClient } from '@classytic/arc/mcp/testing';
13
- *
14
- * const client = await createTestMcpClient({
15
- * pluginOptions: { resources: [productResource] },
16
- * auth: { userId: 'test-user', organizationId: 'org-1' },
17
- * });
18
- *
19
- * const tools = await client.listTools();
20
- * const result = await client.callTool('list_products', { limit: 5 });
21
- * await client.close();
22
- * ```
8
+ * Split out from {@link createTestMcpClient} because arc's own MCP suites build
9
+ * a server directly and only need the connection — five of them had each grown a
10
+ * private copy of the same connect helper against the v1 in-memory transport.
11
+ * One implementation, two entry points: this for a server you built, that for
12
+ * one built from resources.
23
13
  */
14
+ async function connectMcpTestClient(server) {
15
+ const { randomUUID } = await import("node:crypto");
16
+ const { createServer } = await import("node:http");
17
+ const { NodeStreamableHTTPServerTransport } = await import("@modelcontextprotocol/node");
18
+ const { Client, StreamableHTTPClientTransport } = await import("@modelcontextprotocol/client");
19
+ const serverTransport = new NodeStreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID() });
20
+ await server.connect(serverTransport);
21
+ const httpServer = createServer((req, res) => {
22
+ serverTransport.handleRequest(req, res);
23
+ });
24
+ await new Promise((resolve, reject) => {
25
+ httpServer.once("error", reject);
26
+ httpServer.listen(0, "127.0.0.1", resolve);
27
+ });
28
+ const address = httpServer.address();
29
+ if (address === null || typeof address === "string") {
30
+ httpServer.close();
31
+ throw new Error("[arc] MCP test harness: HTTP server did not bind a TCP port");
32
+ }
33
+ const client = new Client({
34
+ name: "test-client",
35
+ version: "1.0"
36
+ });
37
+ await client.connect(new StreamableHTTPClientTransport(new URL(`http://127.0.0.1:${address.port}/`)));
38
+ return {
39
+ client,
40
+ /**
41
+ * Client first, THEN the socket. Reversed, the client's in-flight request
42
+ * hangs on a dead server until its own timeout — which reads as a slow test
43
+ * rather than a teardown bug. `httpServer.close()` only stops NEW
44
+ * connections, so keep-alive sockets are destroyed explicitly; without that
45
+ * vitest hangs at end-of-file with no failing assertion.
46
+ */
47
+ async close() {
48
+ await client.close();
49
+ httpServer.closeAllConnections?.();
50
+ await new Promise((resolve, reject) => {
51
+ httpServer.close((err) => err ? reject(err) : resolve());
52
+ });
53
+ }
54
+ };
55
+ }
24
56
  /**
25
57
  * Create an in-process MCP test client connected to an Arc MCP server.
26
58
  *
@@ -44,8 +76,6 @@ import { m as createMcpServer, r as resourceToTools, t as filterResourcesForMcp
44
76
  * ```
45
77
  */
46
78
  async function createTestMcpClient(options = {}) {
47
- const { InMemoryTransport } = await import("@modelcontextprotocol/sdk/inMemory.js");
48
- const { Client } = await import("@modelcontextprotocol/sdk/client/index.js");
49
79
  const pluginOpts = {
50
80
  resources: [],
51
81
  ...options.pluginOptions
@@ -65,19 +95,13 @@ async function createTestMcpClient(options = {}) {
65
95
  });
66
96
  if (pluginOpts.extraTools) tools.push(...pluginOpts.extraTools);
67
97
  const authRef = { current: auth };
68
- const server = await createMcpServer({
98
+ const { client, close } = await connectMcpTestClient(await createMcpServer({
69
99
  name: serverName,
70
100
  version: "1.0.0",
71
101
  instructions: pluginOpts.instructions,
72
102
  tools,
73
103
  prompts: pluginOpts.extraPrompts
74
- }, authRef);
75
- const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
76
- const client = new Client({
77
- name: "test-client",
78
- version: "1.0"
79
- });
80
- await Promise.all([client.connect(clientTransport), server.connect(serverTransport)]);
104
+ }, authRef));
81
105
  return {
82
106
  async listTools() {
83
107
  return (await client.listTools()).tools.map((t) => ({
@@ -91,10 +115,8 @@ async function createTestMcpClient(options = {}) {
91
115
  arguments: args ?? {}
92
116
  });
93
117
  },
94
- async close() {
95
- await client.close();
96
- }
118
+ close
97
119
  };
98
120
  }
99
121
  //#endregion
100
- export { createTestMcpClient };
122
+ export { connectMcpTestClient, createTestMcpClient };