@classytic/arc 2.10.3 → 2.11.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 (153) hide show
  1. package/README.md +1 -1
  2. package/dist/{BaseController-CbKKIflT.mjs → BaseController-JNV08qOT.mjs} +595 -537
  3. package/dist/{queryCachePlugin-BKbWjgDG.d.mts → QueryCache-DOBNHBE0.d.mts} +2 -32
  4. package/dist/actionPermissions-C8YYU92K.mjs +22 -0
  5. package/dist/adapters/index.d.mts +2 -2
  6. package/dist/adapters/index.mjs +1 -1
  7. package/dist/{adapters-BXY4i-hw.mjs → adapters-D0tT2Tyo.mjs} +54 -0
  8. package/dist/audit/index.d.mts +2 -2
  9. package/dist/audit/index.mjs +15 -17
  10. package/dist/auth/index.d.mts +4 -4
  11. package/dist/auth/index.mjs +3 -3
  12. package/dist/auth/redis-session.d.mts +1 -1
  13. package/dist/{betterAuthOpenApi-BBRVhjQN.mjs → betterAuthOpenApi-DwxtK3uG.mjs} +1 -1
  14. package/dist/cache/index.d.mts +3 -2
  15. package/dist/cache/index.mjs +3 -3
  16. package/dist/cli/commands/docs.mjs +2 -2
  17. package/dist/cli/commands/generate.mjs +37 -27
  18. package/dist/cli/commands/init.mjs +47 -34
  19. package/dist/cli/commands/introspect.mjs +1 -1
  20. package/dist/context/index.d.mts +58 -0
  21. package/dist/context/index.mjs +2 -0
  22. package/dist/core/index.d.mts +3 -3
  23. package/dist/core/index.mjs +4 -3
  24. package/dist/core-DXdSSFW-.mjs +1037 -0
  25. package/dist/createActionRouter-BwaSM0No.mjs +166 -0
  26. package/dist/{createApp-BuvPma24.mjs → createApp-DvNYEhpb.mjs} +118 -36
  27. package/dist/docs/index.d.mts +2 -2
  28. package/dist/docs/index.mjs +1 -1
  29. package/dist/{elevation-C7hgL_aI.mjs → elevation-DOFoxoDs.mjs} +1 -1
  30. package/dist/errorHandler-Co3lnVmJ.d.mts +114 -0
  31. package/dist/{eventPlugin-DCUjuiQT.mjs → eventPlugin--5HIkdPU.mjs} +1 -1
  32. package/dist/{eventPlugin-CxWgpd6K.d.mts → eventPlugin-CUNjYYRY.d.mts} +1 -1
  33. package/dist/events/index.d.mts +4 -4
  34. package/dist/events/index.mjs +69 -51
  35. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  36. package/dist/events/transports/redis.d.mts +1 -1
  37. package/dist/factory/index.d.mts +1 -1
  38. package/dist/factory/index.mjs +2 -2
  39. package/dist/{fields-Lo1VUDpt.d.mts → fields-C8Y0XLAu.d.mts} +1 -1
  40. package/dist/hooks/index.d.mts +1 -1
  41. package/dist/hooks/index.mjs +1 -1
  42. package/dist/idempotency/index.d.mts +3 -3
  43. package/dist/idempotency/index.mjs +38 -27
  44. package/dist/idempotency/redis.d.mts +1 -1
  45. package/dist/{index-ChIw3776.d.mts → index-BYCqHCVu.d.mts} +4 -4
  46. package/dist/{index-Cl0uoKd5.d.mts → index-Cm0vUrr_.d.mts} +2100 -1688
  47. package/dist/{index-DStwgFUK.d.mts → index-DAushRTt.d.mts} +29 -10
  48. package/dist/index-DsJ1MNfC.d.mts +1179 -0
  49. package/dist/{index-8qw4y6ff.d.mts → index-t8pLpPFW.d.mts} +13 -10
  50. package/dist/index.d.mts +7 -251
  51. package/dist/index.mjs +8 -128
  52. package/dist/integrations/event-gateway.d.mts +2 -2
  53. package/dist/integrations/event-gateway.mjs +1 -1
  54. package/dist/integrations/index.d.mts +2 -2
  55. package/dist/integrations/mcp/index.d.mts +2 -2
  56. package/dist/integrations/mcp/index.mjs +1 -1
  57. package/dist/integrations/mcp/testing.d.mts +1 -1
  58. package/dist/integrations/mcp/testing.mjs +1 -1
  59. package/dist/integrations/streamline.d.mts +46 -5
  60. package/dist/integrations/streamline.mjs +50 -21
  61. package/dist/integrations/websocket-redis.d.mts +1 -1
  62. package/dist/integrations/websocket.d.mts +2 -154
  63. package/dist/integrations/websocket.mjs +292 -224
  64. package/dist/{keys-qcD-TVJl.mjs → keys-CARyUjiR.mjs} +2 -0
  65. package/dist/{loadResources-BAzJItAJ.mjs → loadResources-YNwKHvRA.mjs} +3 -1
  66. package/dist/logger/index.d.mts +81 -0
  67. package/dist/{logger-DLg8-Ueg.mjs → logger/index.mjs} +1 -6
  68. package/dist/middleware/index.d.mts +109 -0
  69. package/dist/middleware/index.mjs +70 -0
  70. package/dist/multipartBody-CvTR1Un6.mjs +123 -0
  71. package/dist/{openapi-B5F8AddX.mjs → openapi-C0L9ar7m.mjs} +9 -7
  72. package/dist/org/index.d.mts +2 -2
  73. package/dist/permissions/index.d.mts +2 -2
  74. package/dist/permissions/index.mjs +1 -3
  75. package/dist/{permissions-Dk6mshja.mjs → permissions-B4vU9L0Q.mjs} +220 -2
  76. package/dist/pipe-DVoIheVC.mjs +62 -0
  77. package/dist/pipeline/index.d.mts +62 -0
  78. package/dist/pipeline/index.mjs +53 -0
  79. package/dist/plugins/index.d.mts +25 -5
  80. package/dist/plugins/index.mjs +10 -10
  81. package/dist/plugins/response-cache.mjs +1 -1
  82. package/dist/plugins/tracing-entry.d.mts +1 -1
  83. package/dist/plugins/tracing-entry.mjs +42 -24
  84. package/dist/presets/filesUpload.d.mts +4 -4
  85. package/dist/presets/filesUpload.mjs +255 -1
  86. package/dist/presets/index.d.mts +1 -1
  87. package/dist/presets/index.mjs +2 -2
  88. package/dist/presets/multiTenant.d.mts +1 -1
  89. package/dist/presets/multiTenant.mjs +48 -8
  90. package/dist/presets/search.d.mts +2 -2
  91. package/dist/presets/search.mjs +1 -1
  92. package/dist/{presets-fLJVXdVn.mjs → presets-k604Lj99.mjs} +1 -1
  93. package/dist/queryCachePlugin-BUXBSm4F.d.mts +34 -0
  94. package/dist/{queryCachePlugin-DQCEfJis.mjs → queryCachePlugin-Bq6bO6vc.mjs} +3 -3
  95. package/dist/{redis-DqyeggCa.d.mts → redis-Cm1gnRDf.d.mts} +1 -1
  96. package/dist/{redis-stream-CakIQmwR.d.mts → redis-stream-CM8TXTix.d.mts} +1 -1
  97. package/dist/registry/index.d.mts +1 -1
  98. package/dist/registry/index.mjs +2 -2
  99. package/dist/{requestContext-xHIKedG6.mjs → requestContext-CfRkaxwf.mjs} +1 -1
  100. package/dist/{resourceToTools-BElv3xPT.mjs → resourceToTools--okX6QBr.mjs} +534 -415
  101. package/dist/routerShared-DeESFp4a.mjs +515 -0
  102. package/dist/schemaIR-BlG9bY7v.mjs +137 -0
  103. package/dist/scope/index.d.mts +2 -2
  104. package/dist/scope/index.mjs +1 -1
  105. package/dist/{sse-yBCgOLGu.mjs → sse-V7aXc3bW.mjs} +1 -1
  106. package/dist/{store-helpers-ZCSMJJAX.mjs → store-helpers-BhrzxvyQ.mjs} +4 -0
  107. package/dist/testing/index.d.mts +367 -711
  108. package/dist/testing/index.mjs +646 -1434
  109. package/dist/testing/storageContract.d.mts +1 -1
  110. package/dist/{tracing-65B51Dw3.d.mts → tracing-DokiEsuz.d.mts} +9 -4
  111. package/dist/types/index.d.mts +5 -5
  112. package/dist/types/index.mjs +1 -3
  113. package/dist/types/storage.d.mts +1 -1
  114. package/dist/{types-Co8k3NyS.d.mts → types-CgikqKAj.d.mts} +133 -21
  115. package/dist/{types-Btdda02s.d.mts → types-D9NqiYIw.d.mts} +1 -1
  116. package/dist/utils/index.d.mts +2 -898
  117. package/dist/utils/index.mjs +4 -5
  118. package/dist/utils-D3Yxnrwr.mjs +1639 -0
  119. package/dist/versioning-M9lNLhO8.d.mts +117 -0
  120. package/dist/websocket-CyJ1VIFI.d.mts +186 -0
  121. package/package.json +26 -8
  122. package/skills/arc/SKILL.md +124 -39
  123. package/skills/arc/references/testing.md +212 -183
  124. package/dist/applyPermissionResult-QhV1Pa-g.mjs +0 -37
  125. package/dist/core-CcR01lup.mjs +0 -1411
  126. package/dist/createActionRouter-Bp_5c_2b.mjs +0 -249
  127. package/dist/errorHandler-DRQ3EqfL.d.mts +0 -218
  128. package/dist/errors-CCSsMpXE.d.mts +0 -140
  129. package/dist/fields-bxkeltzz.mjs +0 -126
  130. package/dist/filesUpload-t21LS-py.mjs +0 -377
  131. package/dist/queryParser-DBqBB6AC.mjs +0 -352
  132. package/dist/types-Csi3FLfq.mjs +0 -27
  133. package/dist/utils-B2fNOD_i.mjs +0 -929
  134. /package/dist/{EventTransport-CUw5NNWe.d.mts → EventTransport-CfVEGaEl.d.mts} +0 -0
  135. /package/dist/{HookSystem-BNYKnrXF.mjs → HookSystem-CGsMd6oK.mjs} +0 -0
  136. /package/dist/{ResourceRegistry-BPd6NQDm.mjs → ResourceRegistry-DkAeAuTX.mjs} +0 -0
  137. /package/dist/{caching-CBpK_SCM.mjs → caching-CheW3m-S.mjs} +0 -0
  138. /package/dist/{elevation-C5SwtkAn.d.mts → elevation-s5ykdNHr.d.mts} +0 -0
  139. /package/dist/{errorHandler-Bb49BvPD.mjs → errorHandler-BQm8ZxTK.mjs} +0 -0
  140. /package/dist/{externalPaths-BQ8QijNH.d.mts → externalPaths-Bapitwvd.d.mts} +0 -0
  141. /package/dist/{interface-CSbZdv_3.d.mts → interface-CkkWm5uR.d.mts} +0 -0
  142. /package/dist/{interface-D218ikEo.d.mts → interface-Da0r7Lna.d.mts} +0 -0
  143. /package/dist/{memory-B5Amv9A1.mjs → memory-DikHSvWa.mjs} +0 -0
  144. /package/dist/{metrics-DuhiSEZI.mjs → metrics-Csh4nsvv.mjs} +0 -0
  145. /package/dist/{pluralize-A0tWEl1K.mjs → pluralize-BneOJkpi.mjs} +0 -0
  146. /package/dist/{registry-B3lRFBWo.mjs → registry-D63ee7fl.mjs} +0 -0
  147. /package/dist/{replyHelpers-CXtJDAZ0.mjs → replyHelpers-ByllIXXV.mjs} +0 -0
  148. /package/dist/{schemaConverter-BxFDdtXu.mjs → schemaConverter-B0oKLuqI.mjs} +0 -0
  149. /package/dist/{sessionManager-BkzVU8h2.d.mts → sessionManager-D-oNWHz3.d.mts} +0 -0
  150. /package/dist/{storage-CVk_SEn2.d.mts → storage-BwGQXUpd.d.mts} +0 -0
  151. /package/dist/{typeGuards-Cj5Rgvlg.mjs → typeGuards-CcFZXgU7.mjs} +0 -0
  152. /package/dist/{types-BD85MlEK.d.mts → types-tgR4Pt8F.d.mts} +0 -0
  153. /package/dist/{versioning-C2U_bLY0.mjs → versioning-CGPjkqAg.mjs} +0 -0
@@ -10,6 +10,20 @@ function resolveSpec(scope, spec) {
10
10
  if (spec.type === "org") return getOrgId(scope);
11
11
  if (spec.type === "team") return getTeamId(scope);
12
12
  }
13
+ /**
14
+ * Stash the resolved tenant field map on the request so `BaseController`
15
+ * can forward it to the repository layer as top-level options. Needed by
16
+ * plugin-scoped repos (mongokit's `multiTenantPlugin`) that read tenant
17
+ * from `context.<field>` rather than from filter/query/data stamping.
18
+ */
19
+ function stashTenantFields(request, resolved) {
20
+ if (Object.keys(resolved).length === 0) return;
21
+ const target = request;
22
+ target._tenantFields = {
23
+ ...target._tenantFields ?? {},
24
+ ...resolved
25
+ };
26
+ }
13
27
  /** Resolve every spec — returns the partial map of fields that have a value. */
14
28
  function resolveAll(scope, specs) {
15
29
  const resolved = {};
@@ -34,10 +48,13 @@ function createTenantFilter(specs) {
34
48
  const scope = getRequestScope(request);
35
49
  if (isElevated(scope)) {
36
50
  const { resolved } = resolveAll(scope, specs);
37
- if (Object.keys(resolved).length > 0) request._policyFilters = {
38
- ...request._policyFilters ?? {},
39
- ...resolved
40
- };
51
+ if (Object.keys(resolved).length > 0) {
52
+ request._policyFilters = {
53
+ ...request._policyFilters ?? {},
54
+ ...resolved
55
+ };
56
+ stashTenantFields(request, resolved);
57
+ }
41
58
  return;
42
59
  }
43
60
  if (hasOrgAccess(scope)) {
@@ -47,6 +64,7 @@ function createTenantFilter(specs) {
47
64
  ...request._policyFilters ?? {},
48
65
  ...resolved
49
66
  };
67
+ stashTenantFields(request, resolved);
50
68
  return;
51
69
  }
52
70
  reply.code(403).send({
@@ -81,10 +99,13 @@ function createFlexibleTenantFilter(specs) {
81
99
  const scope = getRequestScope(request);
82
100
  if (isElevated(scope)) {
83
101
  const { resolved } = resolveAll(scope, specs);
84
- if (Object.keys(resolved).length > 0) request._policyFilters = {
85
- ...request._policyFilters ?? {},
86
- ...resolved
87
- };
102
+ if (Object.keys(resolved).length > 0) {
103
+ request._policyFilters = {
104
+ ...request._policyFilters ?? {},
105
+ ...resolved
106
+ };
107
+ stashTenantFields(request, resolved);
108
+ }
88
109
  return;
89
110
  }
90
111
  if (hasOrgAccess(scope)) {
@@ -94,6 +115,7 @@ function createFlexibleTenantFilter(specs) {
94
115
  ...request._policyFilters ?? {},
95
116
  ...resolved
96
117
  };
118
+ stashTenantFields(request, resolved);
97
119
  return;
98
120
  }
99
121
  reply.code(403).send({
@@ -109,6 +131,14 @@ function createFlexibleTenantFilter(specs) {
109
131
  * Create tenant injection middleware.
110
132
  * Walks the configured tenant fields and writes each into the request body.
111
133
  * Fails closed if any required dimension is missing for non-elevated callers.
134
+ *
135
+ * Also stashes the resolved fields on `request._tenantFields` so
136
+ * `BaseController.tenantRepoOptions()` can forward them to the repo layer
137
+ * as top-level options — needed by plugin-scoped repos like mongokit's
138
+ * `multiTenantPlugin`, which reads tenant from `context.<field>` rather
139
+ * than from `data.<field>`. Without this forwarding, multi-field preset
140
+ * writes (update/delete) work only when the plugin's `allowDataInjection`
141
+ * fallback covers the operation's policy key, which is write-only.
112
142
  */
113
143
  function createTenantInjection(specs) {
114
144
  return async (request, reply) => {
@@ -124,6 +154,10 @@ function createTenantInjection(specs) {
124
154
  return;
125
155
  }
126
156
  if (request.body) Object.assign(request.body, resolved);
157
+ request._tenantFields = {
158
+ ...request._tenantFields ?? {},
159
+ ...resolved
160
+ };
127
161
  };
128
162
  }
129
163
  function multiTenantPreset(options = {}) {
@@ -138,8 +172,14 @@ function multiTenantPreset(options = {}) {
138
172
  const flexibleTenantFilter = createFlexibleTenantFilter(specs);
139
173
  const tenantInjection = createTenantInjection(specs);
140
174
  const getFilter = (route) => allowPublic.includes(route) ? flexibleTenantFilter : strictTenantFilter;
175
+ const fieldRules = {};
176
+ for (const spec of specs) fieldRules[spec.field] = {
177
+ systemManaged: true,
178
+ preserveForElevated: true
179
+ };
141
180
  return {
142
181
  name: "multiTenant",
182
+ schemaOptions: { fieldRules },
143
183
  middlewares: {
144
184
  list: [getFilter("list")],
145
185
  get: [getFilter("get")],
@@ -1,5 +1,5 @@
1
- import { c as PermissionCheck } from "../fields-Lo1VUDpt.mjs";
2
- import { _t as ControllerHandler, mt as RouteMcpConfig, ot as PresetResult, pt as RouteDefinition } from "../index-Cl0uoKd5.mjs";
1
+ import { lt as RouteDefinition, nt as PresetResult, pt as ControllerHandler, ut as RouteMcpConfig } from "../index-Cm0vUrr_.mjs";
2
+ import { c as PermissionCheck } from "../fields-C8Y0XLAu.mjs";
3
3
 
4
4
  //#region src/presets/search.d.ts
5
5
  /**
@@ -1,4 +1,4 @@
1
- import { C as requireAuth, y as allowPublic } from "../permissions-Dk6mshja.mjs";
1
+ import { C as requireAuth, y as allowPublic } from "../permissions-B4vU9L0Q.mjs";
2
2
  //#region src/presets/search.ts
3
3
  const BUILTINS = [
4
4
  {
@@ -1,6 +1,6 @@
1
1
  import { _ as isElevated, n as PUBLIC_SCOPE } from "./types-AOD8fxIw.mjs";
2
+ import { C as requireAuth, T as requireRoles, y as allowPublic } from "./permissions-B4vU9L0Q.mjs";
2
3
  import { multiTenantPreset } from "./presets/multiTenant.mjs";
3
- import { C as requireAuth, T as requireRoles, y as allowPublic } from "./permissions-Dk6mshja.mjs";
4
4
  //#region src/presets/ownedByUser.ts
5
5
  /**
6
6
  * Create ownership check middleware.
@@ -0,0 +1,34 @@
1
+ import { r as CacheStore } from "./interface-Da0r7Lna.mjs";
2
+ import { i as QueryCache } from "./QueryCache-DOBNHBE0.mjs";
3
+ import { FastifyPluginAsync } from "fastify";
4
+
5
+ //#region src/cache/queryCachePlugin.d.ts
6
+ interface QueryCachePluginOptions {
7
+ /** CacheStore instance. Default: MemoryCacheStore with default options. */
8
+ store?: CacheStore;
9
+ /** Global defaults for staleTime/gcTime (seconds) */
10
+ defaults?: {
11
+ staleTime?: number;
12
+ gcTime?: number;
13
+ };
14
+ }
15
+ interface QueryCacheDefaults {
16
+ staleTime: number;
17
+ gcTime: number;
18
+ }
19
+ /** Cross-resource invalidation rules collected from resource configs */
20
+ interface CrossResourceRule {
21
+ pattern: string;
22
+ tags: string[];
23
+ }
24
+ declare module "fastify" {
25
+ interface FastifyInstance {
26
+ queryCache: QueryCache;
27
+ queryCacheConfig: QueryCacheDefaults;
28
+ /** Register cross-resource invalidation rules (called by defineResource) */
29
+ registerCacheInvalidationRule?(rule: CrossResourceRule): void;
30
+ }
31
+ }
32
+ declare const queryCachePlugin: FastifyPluginAsync<QueryCachePluginOptions>;
33
+ //#endregion
34
+ export { queryCachePlugin as i, QueryCacheDefaults as n, QueryCachePluginOptions as r, CrossResourceRule as t };
@@ -1,7 +1,7 @@
1
1
  import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
2
- import { i as versionKey, r as tagVersionKey } from "./keys-qcD-TVJl.mjs";
3
- import { t as hasEvents } from "./typeGuards-Cj5Rgvlg.mjs";
4
- import { t as MemoryCacheStore } from "./memory-B5Amv9A1.mjs";
2
+ import { i as versionKey, r as tagVersionKey } from "./keys-CARyUjiR.mjs";
3
+ import { t as MemoryCacheStore } from "./memory-DikHSvWa.mjs";
4
+ import { t as hasEvents } from "./typeGuards-CcFZXgU7.mjs";
5
5
  import fp from "fastify-plugin";
6
6
  //#region src/cache/QueryCache.ts
7
7
  var QueryCache = class {
@@ -1,4 +1,4 @@
1
- import { n as IdempotencyResult, r as IdempotencyStore } from "./interface-CSbZdv_3.mjs";
1
+ import { n as IdempotencyResult, r as IdempotencyStore } from "./interface-CkkWm5uR.mjs";
2
2
 
3
3
  //#region src/idempotency/stores/redis.d.ts
4
4
  interface RedisClient {
@@ -1,4 +1,4 @@
1
- import { i as EventLogger, n as DomainEvent, o as EventTransport, r as EventHandler } from "./EventTransport-CUw5NNWe.mjs";
1
+ import { i as EventLogger, n as DomainEvent, o as EventTransport, r as EventHandler } from "./EventTransport-CfVEGaEl.mjs";
2
2
 
3
3
  //#region src/events/transports/redis-stream.d.ts
4
4
  interface RedisStreamLike {
@@ -1,4 +1,4 @@
1
- import { O as IntrospectionPluginOptions, U as RegisterOptions, W as ResourceRegistry } from "../index-Cl0uoKd5.mjs";
1
+ import { R as RegisterOptions, k as IntrospectionPluginOptions, z as ResourceRegistry } from "../index-Cm0vUrr_.mjs";
2
2
  import { FastifyPluginAsync } from "fastify";
3
3
 
4
4
  //#region src/registry/introspectionPlugin.d.ts
@@ -1,3 +1,3 @@
1
- import { n as introspectionPlugin_default, t as introspectionPlugin } from "../registry-B3lRFBWo.mjs";
2
- import { t as ResourceRegistry } from "../ResourceRegistry-BPd6NQDm.mjs";
1
+ import { n as introspectionPlugin_default, t as introspectionPlugin } from "../registry-D63ee7fl.mjs";
2
+ import { t as ResourceRegistry } from "../ResourceRegistry-DkAeAuTX.mjs";
3
3
  export { ResourceRegistry, introspectionPlugin_default as introspectionPlugin, introspectionPlugin as introspectionPluginFn };
@@ -11,7 +11,7 @@ import { AsyncLocalStorage } from "node:async_hooks";
11
11
  *
12
12
  * @example
13
13
  * ```typescript
14
- * import { requestContext } from '@classytic/arc';
14
+ * import { requestContext } from '@classytic/arc/context';
15
15
  *
16
16
  * // Anywhere in the call stack — no parameter passing needed
17
17
  * async function auditAction(action: string) {