@classytic/arc 1.1.0 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (322) hide show
  1. package/README.md +247 -794
  2. package/bin/arc.js +91 -52
  3. package/dist/EventTransport-BD2U0BTc.d.mts +100 -0
  4. package/dist/EventTransport-BD2U0BTc.d.mts.map +1 -0
  5. package/dist/HookSystem-BsGV-j2l.mjs +405 -0
  6. package/dist/HookSystem-BsGV-j2l.mjs.map +1 -0
  7. package/dist/ResourceRegistry-DsN4KJjV.mjs +250 -0
  8. package/dist/ResourceRegistry-DsN4KJjV.mjs.map +1 -0
  9. package/dist/adapters/index.d.mts +5 -0
  10. package/dist/adapters/index.mjs +3 -0
  11. package/dist/audit/index.d.mts +82 -0
  12. package/dist/audit/index.d.mts.map +1 -0
  13. package/dist/audit/index.mjs +276 -0
  14. package/dist/audit/index.mjs.map +1 -0
  15. package/dist/audit/mongodb.d.mts +5 -0
  16. package/dist/audit/mongodb.mjs +3 -0
  17. package/dist/audited-C3T5DTUx.mjs +141 -0
  18. package/dist/audited-C3T5DTUx.mjs.map +1 -0
  19. package/dist/auth/index.d.mts +189 -0
  20. package/dist/auth/index.d.mts.map +1 -0
  21. package/dist/auth/index.mjs +1102 -0
  22. package/dist/auth/index.mjs.map +1 -0
  23. package/dist/auth/redis-session.d.mts +44 -0
  24. package/dist/auth/redis-session.d.mts.map +1 -0
  25. package/dist/auth/redis-session.mjs +76 -0
  26. package/dist/auth/redis-session.mjs.map +1 -0
  27. package/dist/betterAuthOpenApi-BrHKeSAx.mjs +250 -0
  28. package/dist/betterAuthOpenApi-BrHKeSAx.mjs.map +1 -0
  29. package/dist/cache/index.d.mts +146 -0
  30. package/dist/cache/index.d.mts.map +1 -0
  31. package/dist/cache/index.mjs +92 -0
  32. package/dist/cache/index.mjs.map +1 -0
  33. package/dist/caching-Bl28lYsR.mjs +94 -0
  34. package/dist/caching-Bl28lYsR.mjs.map +1 -0
  35. package/dist/chunk-C7Uep-_p.mjs +20 -0
  36. package/dist/circuitBreaker-DeY4FCjs.mjs +1097 -0
  37. package/dist/circuitBreaker-DeY4FCjs.mjs.map +1 -0
  38. package/dist/cli/commands/describe.d.mts +19 -0
  39. package/dist/cli/commands/describe.d.mts.map +1 -0
  40. package/dist/cli/commands/describe.mjs +239 -0
  41. package/dist/cli/commands/describe.mjs.map +1 -0
  42. package/dist/cli/commands/docs.d.mts +14 -0
  43. package/dist/cli/commands/docs.d.mts.map +1 -0
  44. package/dist/cli/commands/docs.mjs +53 -0
  45. package/dist/cli/commands/docs.mjs.map +1 -0
  46. package/dist/cli/commands/{generate.d.ts → generate.d.mts} +3 -1
  47. package/dist/cli/commands/generate.d.mts.map +1 -0
  48. package/dist/cli/commands/generate.mjs +358 -0
  49. package/dist/cli/commands/generate.mjs.map +1 -0
  50. package/dist/cli/commands/{init.d.ts → init.d.mts} +12 -8
  51. package/dist/cli/commands/init.d.mts.map +1 -0
  52. package/dist/cli/commands/{init.js → init.mjs} +807 -616
  53. package/dist/cli/commands/init.mjs.map +1 -0
  54. package/dist/cli/commands/introspect.d.mts +11 -0
  55. package/dist/cli/commands/introspect.d.mts.map +1 -0
  56. package/dist/cli/commands/introspect.mjs +76 -0
  57. package/dist/cli/commands/introspect.mjs.map +1 -0
  58. package/dist/cli/index.d.mts +17 -0
  59. package/dist/cli/index.d.mts.map +1 -0
  60. package/dist/cli/index.mjs +157 -0
  61. package/dist/cli/index.mjs.map +1 -0
  62. package/dist/constants-DdXFXQtN.mjs +85 -0
  63. package/dist/constants-DdXFXQtN.mjs.map +1 -0
  64. package/dist/core/index.d.mts +5 -0
  65. package/dist/core/index.mjs +4 -0
  66. package/dist/createApp-CUgNqegw.mjs +560 -0
  67. package/dist/createApp-CUgNqegw.mjs.map +1 -0
  68. package/dist/defineResource-k0_BDn8v.mjs +2197 -0
  69. package/dist/defineResource-k0_BDn8v.mjs.map +1 -0
  70. package/dist/discovery/index.d.mts +47 -0
  71. package/dist/discovery/index.d.mts.map +1 -0
  72. package/dist/discovery/index.mjs +110 -0
  73. package/dist/discovery/index.mjs.map +1 -0
  74. package/dist/docs/index.d.mts +163 -0
  75. package/dist/docs/index.d.mts.map +1 -0
  76. package/dist/docs/index.mjs +73 -0
  77. package/dist/docs/index.mjs.map +1 -0
  78. package/dist/elevation-BRy3yFWT.mjs +113 -0
  79. package/dist/elevation-BRy3yFWT.mjs.map +1 -0
  80. package/dist/elevation-B_2dRLVP.d.mts +88 -0
  81. package/dist/elevation-B_2dRLVP.d.mts.map +1 -0
  82. package/dist/errorHandler-BbcgBmIH.d.mts +73 -0
  83. package/dist/errorHandler-BbcgBmIH.d.mts.map +1 -0
  84. package/dist/errorHandler-C1okiriz.mjs +109 -0
  85. package/dist/errorHandler-C1okiriz.mjs.map +1 -0
  86. package/dist/errors-B9bZok84.mjs +212 -0
  87. package/dist/errors-B9bZok84.mjs.map +1 -0
  88. package/dist/errors-ChKiFz62.d.mts +125 -0
  89. package/dist/errors-ChKiFz62.d.mts.map +1 -0
  90. package/dist/eventPlugin-CTrLH3mt.d.mts +125 -0
  91. package/dist/eventPlugin-CTrLH3mt.d.mts.map +1 -0
  92. package/dist/eventPlugin-DGR_B2on.mjs +230 -0
  93. package/dist/eventPlugin-DGR_B2on.mjs.map +1 -0
  94. package/dist/events/index.d.mts +54 -0
  95. package/dist/events/index.d.mts.map +1 -0
  96. package/dist/events/index.mjs +52 -0
  97. package/dist/events/index.mjs.map +1 -0
  98. package/dist/events/transports/redis-stream-entry.d.mts +2 -0
  99. package/dist/events/transports/redis-stream-entry.mjs +178 -0
  100. package/dist/events/transports/redis-stream-entry.mjs.map +1 -0
  101. package/dist/events/transports/redis.d.mts +77 -0
  102. package/dist/events/transports/redis.d.mts.map +1 -0
  103. package/dist/events/transports/redis.mjs +125 -0
  104. package/dist/events/transports/redis.mjs.map +1 -0
  105. package/dist/externalPaths-DlINfKbP.d.mts +51 -0
  106. package/dist/externalPaths-DlINfKbP.d.mts.map +1 -0
  107. package/dist/factory/index.d.mts +64 -0
  108. package/dist/factory/index.d.mts.map +1 -0
  109. package/dist/factory/index.mjs +3 -0
  110. package/dist/fastifyAdapter-BkrGrlFi.d.mts +217 -0
  111. package/dist/fastifyAdapter-BkrGrlFi.d.mts.map +1 -0
  112. package/dist/fields-DyaDVX4J.d.mts +110 -0
  113. package/dist/fields-DyaDVX4J.d.mts.map +1 -0
  114. package/dist/fields-iagOozy0.mjs +115 -0
  115. package/dist/fields-iagOozy0.mjs.map +1 -0
  116. package/dist/hooks/index.d.mts +4 -0
  117. package/dist/hooks/index.mjs +3 -0
  118. package/dist/idempotency/index.d.mts +97 -0
  119. package/dist/idempotency/index.d.mts.map +1 -0
  120. package/dist/idempotency/index.mjs +320 -0
  121. package/dist/idempotency/index.mjs.map +1 -0
  122. package/dist/idempotency/mongodb.d.mts +2 -0
  123. package/dist/idempotency/mongodb.mjs +115 -0
  124. package/dist/idempotency/mongodb.mjs.map +1 -0
  125. package/dist/idempotency/redis.d.mts +2 -0
  126. package/dist/idempotency/redis.mjs +104 -0
  127. package/dist/idempotency/redis.mjs.map +1 -0
  128. package/dist/index.d.mts +261 -0
  129. package/dist/index.d.mts.map +1 -0
  130. package/dist/index.mjs +105 -0
  131. package/dist/index.mjs.map +1 -0
  132. package/dist/integrations/event-gateway.d.mts +47 -0
  133. package/dist/integrations/event-gateway.d.mts.map +1 -0
  134. package/dist/integrations/event-gateway.mjs +44 -0
  135. package/dist/integrations/event-gateway.mjs.map +1 -0
  136. package/dist/integrations/index.d.mts +5 -0
  137. package/dist/integrations/index.mjs +1 -0
  138. package/dist/integrations/jobs.d.mts +104 -0
  139. package/dist/integrations/jobs.d.mts.map +1 -0
  140. package/dist/integrations/jobs.mjs +124 -0
  141. package/dist/integrations/jobs.mjs.map +1 -0
  142. package/dist/integrations/streamline.d.mts +61 -0
  143. package/dist/integrations/streamline.d.mts.map +1 -0
  144. package/dist/integrations/streamline.mjs +126 -0
  145. package/dist/integrations/streamline.mjs.map +1 -0
  146. package/dist/integrations/websocket.d.mts +83 -0
  147. package/dist/integrations/websocket.d.mts.map +1 -0
  148. package/dist/integrations/websocket.mjs +289 -0
  149. package/dist/integrations/websocket.mjs.map +1 -0
  150. package/dist/interface-B01JvPVc.d.mts +78 -0
  151. package/dist/interface-B01JvPVc.d.mts.map +1 -0
  152. package/dist/interface-CZe8IkMf.d.mts +55 -0
  153. package/dist/interface-CZe8IkMf.d.mts.map +1 -0
  154. package/dist/interface-Ch8HU9uM.d.mts +1098 -0
  155. package/dist/interface-Ch8HU9uM.d.mts.map +1 -0
  156. package/dist/introspectionPlugin-rFdO8ZUa.mjs +54 -0
  157. package/dist/introspectionPlugin-rFdO8ZUa.mjs.map +1 -0
  158. package/dist/keys-BqNejWup.mjs +43 -0
  159. package/dist/keys-BqNejWup.mjs.map +1 -0
  160. package/dist/logger-Df2O2WsW.mjs +79 -0
  161. package/dist/logger-Df2O2WsW.mjs.map +1 -0
  162. package/dist/memory-cQgelFOj.mjs +144 -0
  163. package/dist/memory-cQgelFOj.mjs.map +1 -0
  164. package/dist/migrations/index.d.mts +157 -0
  165. package/dist/migrations/index.d.mts.map +1 -0
  166. package/dist/migrations/index.mjs +261 -0
  167. package/dist/migrations/index.mjs.map +1 -0
  168. package/dist/mongodb-BfJVlUJH.mjs +94 -0
  169. package/dist/mongodb-BfJVlUJH.mjs.map +1 -0
  170. package/dist/mongodb-CGzRbfAK.d.mts +119 -0
  171. package/dist/mongodb-CGzRbfAK.d.mts.map +1 -0
  172. package/dist/mongodb-JN-9JA7K.d.mts +72 -0
  173. package/dist/mongodb-JN-9JA7K.d.mts.map +1 -0
  174. package/dist/openapi-G3Cw7XuM.mjs +524 -0
  175. package/dist/openapi-G3Cw7XuM.mjs.map +1 -0
  176. package/dist/org/index.d.mts +69 -0
  177. package/dist/org/index.d.mts.map +1 -0
  178. package/dist/org/index.mjs +514 -0
  179. package/dist/org/index.mjs.map +1 -0
  180. package/dist/org/types.d.mts +83 -0
  181. package/dist/org/types.d.mts.map +1 -0
  182. package/dist/org/types.mjs +1 -0
  183. package/dist/permissions/index.d.mts +279 -0
  184. package/dist/permissions/index.d.mts.map +1 -0
  185. package/dist/permissions/index.mjs +579 -0
  186. package/dist/permissions/index.mjs.map +1 -0
  187. package/dist/plugins/index.d.mts +173 -0
  188. package/dist/plugins/index.d.mts.map +1 -0
  189. package/dist/plugins/index.mjs +523 -0
  190. package/dist/plugins/index.mjs.map +1 -0
  191. package/dist/plugins/response-cache.d.mts +88 -0
  192. package/dist/plugins/response-cache.d.mts.map +1 -0
  193. package/dist/plugins/response-cache.mjs +284 -0
  194. package/dist/plugins/response-cache.mjs.map +1 -0
  195. package/dist/plugins/tracing-entry.d.mts +2 -0
  196. package/dist/plugins/tracing-entry.mjs +186 -0
  197. package/dist/plugins/tracing-entry.mjs.map +1 -0
  198. package/dist/pluralize-CEweyOEm.mjs +87 -0
  199. package/dist/pluralize-CEweyOEm.mjs.map +1 -0
  200. package/dist/policies/{index.d.ts → index.d.mts} +204 -169
  201. package/dist/policies/index.d.mts.map +1 -0
  202. package/dist/policies/index.mjs +322 -0
  203. package/dist/policies/index.mjs.map +1 -0
  204. package/dist/presets/{index.d.ts → index.d.mts} +63 -131
  205. package/dist/presets/index.d.mts.map +1 -0
  206. package/dist/presets/index.mjs +144 -0
  207. package/dist/presets/index.mjs.map +1 -0
  208. package/dist/presets/multiTenant.d.mts +25 -0
  209. package/dist/presets/multiTenant.d.mts.map +1 -0
  210. package/dist/presets/multiTenant.mjs +114 -0
  211. package/dist/presets/multiTenant.mjs.map +1 -0
  212. package/dist/presets-BITljm96.mjs +120 -0
  213. package/dist/presets-BITljm96.mjs.map +1 -0
  214. package/dist/presets-DzSMwlKj.d.mts +58 -0
  215. package/dist/presets-DzSMwlKj.d.mts.map +1 -0
  216. package/dist/prisma-DJbMt3yf.mjs +628 -0
  217. package/dist/prisma-DJbMt3yf.mjs.map +1 -0
  218. package/dist/prisma-Dg9GoVdj.d.mts +275 -0
  219. package/dist/prisma-Dg9GoVdj.d.mts.map +1 -0
  220. package/dist/queryCachePlugin-7THaI5mt.d.mts +72 -0
  221. package/dist/queryCachePlugin-7THaI5mt.d.mts.map +1 -0
  222. package/dist/queryCachePlugin-DMBnp2Q0.mjs +139 -0
  223. package/dist/queryCachePlugin-DMBnp2Q0.mjs.map +1 -0
  224. package/dist/redis-D-JAeLtm.d.mts +50 -0
  225. package/dist/redis-D-JAeLtm.d.mts.map +1 -0
  226. package/dist/redis-stream-Bdh_vUU8.d.mts +104 -0
  227. package/dist/redis-stream-Bdh_vUU8.d.mts.map +1 -0
  228. package/dist/registry/index.d.mts +12 -0
  229. package/dist/registry/index.d.mts.map +1 -0
  230. package/dist/registry/index.mjs +4 -0
  231. package/dist/requestContext-QQD6ROJc.mjs +56 -0
  232. package/dist/requestContext-QQD6ROJc.mjs.map +1 -0
  233. package/dist/schemaConverter-BwrmWroW.mjs +99 -0
  234. package/dist/schemaConverter-BwrmWroW.mjs.map +1 -0
  235. package/dist/schemas/index.d.mts +64 -0
  236. package/dist/schemas/index.d.mts.map +1 -0
  237. package/dist/schemas/index.mjs +83 -0
  238. package/dist/schemas/index.mjs.map +1 -0
  239. package/dist/scope/index.d.mts +22 -0
  240. package/dist/scope/index.d.mts.map +1 -0
  241. package/dist/scope/index.mjs +66 -0
  242. package/dist/scope/index.mjs.map +1 -0
  243. package/dist/sessionManager-jPKLbHE0.d.mts +187 -0
  244. package/dist/sessionManager-jPKLbHE0.d.mts.map +1 -0
  245. package/dist/sse-B3c3_yZp.mjs +124 -0
  246. package/dist/sse-B3c3_yZp.mjs.map +1 -0
  247. package/dist/testing/index.d.mts +908 -0
  248. package/dist/testing/index.d.mts.map +1 -0
  249. package/dist/testing/index.mjs +1977 -0
  250. package/dist/testing/index.mjs.map +1 -0
  251. package/dist/tracing-Cc7vVQPp.d.mts +71 -0
  252. package/dist/tracing-Cc7vVQPp.d.mts.map +1 -0
  253. package/dist/typeGuards-DhMNLuvU.mjs +10 -0
  254. package/dist/typeGuards-DhMNLuvU.mjs.map +1 -0
  255. package/dist/types/index.d.mts +947 -0
  256. package/dist/types/index.d.mts.map +1 -0
  257. package/dist/types/index.mjs +15 -0
  258. package/dist/types/index.mjs.map +1 -0
  259. package/dist/types-Beqn1Un7.mjs +39 -0
  260. package/dist/types-Beqn1Un7.mjs.map +1 -0
  261. package/dist/types-CIgB7UUl.d.mts +446 -0
  262. package/dist/types-CIgB7UUl.d.mts.map +1 -0
  263. package/dist/types-aYB4V7uN.d.mts +87 -0
  264. package/dist/types-aYB4V7uN.d.mts.map +1 -0
  265. package/dist/utils/index.d.mts +748 -0
  266. package/dist/utils/index.d.mts.map +1 -0
  267. package/dist/utils/index.mjs +6 -0
  268. package/package.json +194 -68
  269. package/dist/BaseController-DVAiHxEQ.d.ts +0 -233
  270. package/dist/adapters/index.d.ts +0 -237
  271. package/dist/adapters/index.js +0 -668
  272. package/dist/arcCorePlugin-CsShQdyP.d.ts +0 -273
  273. package/dist/audit/index.d.ts +0 -195
  274. package/dist/audit/index.js +0 -319
  275. package/dist/auth/index.d.ts +0 -47
  276. package/dist/auth/index.js +0 -174
  277. package/dist/cli/commands/docs.d.ts +0 -11
  278. package/dist/cli/commands/docs.js +0 -474
  279. package/dist/cli/commands/generate.js +0 -334
  280. package/dist/cli/commands/introspect.d.ts +0 -8
  281. package/dist/cli/commands/introspect.js +0 -338
  282. package/dist/cli/index.d.ts +0 -4
  283. package/dist/cli/index.js +0 -3269
  284. package/dist/core/index.d.ts +0 -220
  285. package/dist/core/index.js +0 -2786
  286. package/dist/createApp-Ce9wl8W9.d.ts +0 -77
  287. package/dist/docs/index.d.ts +0 -166
  288. package/dist/docs/index.js +0 -658
  289. package/dist/errors-8WIxGS_6.d.ts +0 -122
  290. package/dist/events/index.d.ts +0 -117
  291. package/dist/events/index.js +0 -89
  292. package/dist/factory/index.d.ts +0 -38
  293. package/dist/factory/index.js +0 -1652
  294. package/dist/hooks/index.d.ts +0 -4
  295. package/dist/hooks/index.js +0 -199
  296. package/dist/idempotency/index.d.ts +0 -323
  297. package/dist/idempotency/index.js +0 -500
  298. package/dist/index-B4t03KQ0.d.ts +0 -1366
  299. package/dist/index.d.ts +0 -135
  300. package/dist/index.js +0 -4756
  301. package/dist/migrations/index.d.ts +0 -185
  302. package/dist/migrations/index.js +0 -274
  303. package/dist/org/index.d.ts +0 -129
  304. package/dist/org/index.js +0 -220
  305. package/dist/permissions/index.d.ts +0 -144
  306. package/dist/permissions/index.js +0 -103
  307. package/dist/plugins/index.d.ts +0 -46
  308. package/dist/plugins/index.js +0 -1069
  309. package/dist/policies/index.js +0 -196
  310. package/dist/presets/index.js +0 -384
  311. package/dist/presets/multiTenant.d.ts +0 -39
  312. package/dist/presets/multiTenant.js +0 -112
  313. package/dist/registry/index.d.ts +0 -16
  314. package/dist/registry/index.js +0 -253
  315. package/dist/testing/index.d.ts +0 -618
  316. package/dist/testing/index.js +0 -48020
  317. package/dist/types/index.d.ts +0 -4
  318. package/dist/types/index.js +0 -8
  319. package/dist/types-B99TBmFV.d.ts +0 -76
  320. package/dist/types-BvckRbs2.d.ts +0 -143
  321. package/dist/utils/index.d.ts +0 -679
  322. package/dist/utils/index.js +0 -931
@@ -0,0 +1,50 @@
1
+ import { n as IdempotencyResult, r as IdempotencyStore } from "./interface-B01JvPVc.mjs";
2
+
3
+ //#region src/idempotency/stores/redis.d.ts
4
+ interface RedisClient {
5
+ get(key: string): Promise<string | null>;
6
+ set(key: string, value: string, options?: {
7
+ EX?: number;
8
+ NX?: boolean;
9
+ }): Promise<string | null>;
10
+ del(key: string | string[]): Promise<number>;
11
+ exists(key: string | string[]): Promise<number>;
12
+ /** SCAN command — compatible with node-redis and ioredis varargs signatures. */
13
+ scan?(cursor: string | number, ...args: (string | number)[]): Promise<[string | number, string[]]>;
14
+ quit?(): Promise<string>;
15
+ disconnect?(): Promise<void>;
16
+ }
17
+ interface RedisIdempotencyStoreOptions {
18
+ /** Redis client instance */
19
+ client: RedisClient;
20
+ /** Key prefix (default: 'idem:') */
21
+ prefix?: string;
22
+ /** Lock key prefix (default: 'idem:lock:') */
23
+ lockPrefix?: string;
24
+ /** Default TTL in ms (default: 86400000 = 24 hours) */
25
+ ttlMs?: number;
26
+ }
27
+ declare class RedisIdempotencyStore implements IdempotencyStore {
28
+ readonly name = "redis";
29
+ private client;
30
+ private prefix;
31
+ private lockPrefix;
32
+ private ttlMs;
33
+ constructor(options: RedisIdempotencyStoreOptions);
34
+ private resultKey;
35
+ private lockKey;
36
+ get(key: string): Promise<IdempotencyResult | undefined>;
37
+ set(key: string, result: Omit<IdempotencyResult, 'key'>): Promise<void>;
38
+ tryLock(key: string, requestId: string, ttlMs: number): Promise<boolean>;
39
+ unlock(key: string, requestId: string): Promise<void>;
40
+ isLocked(key: string): Promise<boolean>;
41
+ delete(key: string): Promise<void>;
42
+ deleteByPrefix(prefix: string): Promise<number>;
43
+ findByPrefix(prefix: string): Promise<IdempotencyResult | undefined>;
44
+ /** Scan Redis keys matching a prefix pattern. Falls back to empty if SCAN unavailable. */
45
+ private scanByPrefix;
46
+ close(): Promise<void>;
47
+ }
48
+ //#endregion
49
+ export { RedisIdempotencyStore as n, RedisIdempotencyStoreOptions as r, RedisClient as t };
50
+ //# sourceMappingURL=redis-D-JAeLtm.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis-D-JAeLtm.d.mts","names":[],"sources":["../src/idempotency/stores/redis.ts"],"mappings":";;;UAoBiB,WAAA;EACf,GAAA,CAAI,GAAA,WAAc,OAAA;EAClB,GAAA,CAAI,GAAA,UAAa,KAAA,UAAe,OAAA;IAAY,EAAA;IAAa,EAAA;EAAA,IAAiB,OAAA;EAC1E,GAAA,CAAI,GAAA,sBAAyB,OAAA;EAC7B,MAAA,CAAO,GAAA,sBAAyB,OAAA;EAD5B;EAGJ,IAAA,EAAM,MAAA,sBAA4B,IAAA,wBAA4B,OAAA;EAC9D,IAAA,KAAS,OAAA;EACT,UAAA,KAAe,OAAA;AAAA;AAAA,UAGA,4BAAA;EALT;EAON,MAAA,EAAQ,WAAA;EAPsD;EAS9D,MAAA;EARS;EAUT,UAAA;EATe;EAWf,KAAA;AAAA;AAAA,cAGW,qBAAA,YAAiC,gBAAA;EAAA,SACnC,IAAA;EAAA,QACD,MAAA;EAAA,QACA,MAAA;EAAA,QACA,UAAA;EAAA,QACA,KAAA;cAEI,OAAA,EAAS,4BAAA;EAAA,QAOb,SAAA;EAAA,QAIA,OAAA;EAIF,GAAA,CAAI,GAAA,WAAc,OAAA,CAAQ,iBAAA;EAqB1B,GAAA,CAAI,GAAA,UAAa,MAAA,EAAQ,IAAA,CAAK,iBAAA,WAA4B,OAAA;EAa1D,OAAA,CAAQ,GAAA,UAAa,SAAA,UAAmB,KAAA,WAAgB,OAAA;EAUxD,MAAA,CAAO,GAAA,UAAa,SAAA,WAAoB,OAAA;EAQxC,QAAA,CAAS,GAAA,WAAc,OAAA;EAKvB,MAAA,CAAO,GAAA,WAAc,OAAA;EAIrB,cAAA,CAAe,MAAA,WAAiB,OAAA;EAQhC,YAAA,CAAa,MAAA,WAAiB,OAAA,CAAQ,iBAAA;EAhDR;EAAA,QAqEtB,YAAA;EAcR,KAAA,CAAA,GAAS,OAAA;AAAA"}
@@ -0,0 +1,104 @@
1
+ import { i as EventTransport, n as EventHandler, r as EventLogger, t as DomainEvent } from "./EventTransport-BD2U0BTc.mjs";
2
+
3
+ //#region src/events/transports/redis-stream.d.ts
4
+ interface RedisStreamLike {
5
+ xadd(key: string, id: string, ...fieldValues: string[]): Promise<string | null>;
6
+ xreadgroup(command: 'GROUP', group: string, consumer: string, ...args: (string | number)[]): Promise<Array<[string, Array<[string, string[]]>]> | null>;
7
+ xack(key: string, group: string, ...ids: string[]): Promise<number>;
8
+ xgroup(command: string, key: string, group: string, ...args: string[]): Promise<unknown>;
9
+ xpending(key: string, group: string, ...args: (string | number)[]): Promise<Array<[string, string, number, number]>>;
10
+ xclaim(key: string, group: string, consumer: string, minIdleTime: number, ...ids: string[]): Promise<Array<[string, string[]]>>;
11
+ xlen(key: string): Promise<number>;
12
+ quit(): Promise<unknown>;
13
+ }
14
+ interface RedisStreamTransportOptions {
15
+ /**
16
+ * Redis stream key name.
17
+ * @default 'arc:events'
18
+ */
19
+ stream?: string;
20
+ /**
21
+ * Consumer group name. Each group receives every event independently.
22
+ * Multiple instances of the same service should share a group name.
23
+ * @default 'default'
24
+ */
25
+ group?: string;
26
+ /**
27
+ * Consumer name within the group. Must be unique per instance.
28
+ * @default 'consumer-<random>'
29
+ */
30
+ consumer?: string;
31
+ /**
32
+ * Block time in ms when waiting for new events.
33
+ * @default 5000
34
+ */
35
+ blockTimeMs?: number;
36
+ /**
37
+ * Max events to read per batch.
38
+ * @default 10
39
+ */
40
+ batchSize?: number;
41
+ /**
42
+ * Max delivery attempts before moving to dead letter stream.
43
+ * @default 5
44
+ */
45
+ maxRetries?: number;
46
+ /**
47
+ * Idle time in ms before pending entries are claimed by this consumer.
48
+ * Handles crash recovery — if a consumer dies mid-processing, another
49
+ * consumer will claim its pending entries after this timeout.
50
+ * @default 30000
51
+ */
52
+ claimTimeoutMs?: number;
53
+ /**
54
+ * Dead letter stream name. Failed events are moved here after maxRetries.
55
+ * Set to `false` to disable DLQ (failed events are acked and dropped).
56
+ * @default 'arc:events:dlq'
57
+ */
58
+ deadLetterStream?: string | false;
59
+ /**
60
+ * Max stream length (approximate). Uses XADD MAXLEN ~ to trim old entries.
61
+ * Set to 0 to disable trimming.
62
+ * @default 10000
63
+ */
64
+ maxLen?: number;
65
+ /**
66
+ * Logger for error messages (default: console).
67
+ * Pass `fastify.log` to integrate with your application logger.
68
+ */
69
+ logger?: EventLogger;
70
+ }
71
+ declare class RedisStreamTransport implements EventTransport {
72
+ readonly name = "redis-stream";
73
+ private redis;
74
+ private stream;
75
+ private group;
76
+ private consumer;
77
+ private blockTimeMs;
78
+ private batchSize;
79
+ private maxRetries;
80
+ private claimTimeoutMs;
81
+ private deadLetterStream;
82
+ private maxLen;
83
+ private logger;
84
+ private handlers;
85
+ private running;
86
+ private pollPromise;
87
+ private groupCreated;
88
+ constructor(redis: RedisStreamLike, options?: RedisStreamTransportOptions);
89
+ publish(event: DomainEvent): Promise<void>;
90
+ subscribe(pattern: string, handler: EventHandler): Promise<() => void>;
91
+ close(): Promise<void>;
92
+ private ensureGroup;
93
+ private pollLoop;
94
+ private readNewMessages;
95
+ private claimPending;
96
+ private processEntry;
97
+ private getMatchingHandlers;
98
+ private matchesPattern;
99
+ private moveToDlq;
100
+ private sleep;
101
+ }
102
+ //#endregion
103
+ export { RedisStreamTransport as n, RedisStreamTransportOptions as r, RedisStreamLike as t };
104
+ //# sourceMappingURL=redis-stream-Bdh_vUU8.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis-stream-Bdh_vUU8.d.mts","names":[],"sources":["../src/events/transports/redis-stream.ts"],"mappings":";;;UAkCiB,eAAA;EACf,IAAA,CAAK,GAAA,UAAa,EAAA,aAAe,WAAA,aAAwB,OAAA;EACzD,UAAA,CACE,OAAA,WACA,KAAA,UACA,QAAA,aACG,IAAA,wBACF,OAAA,CAAQ,KAAA,UAAe,KAAA;EAC1B,IAAA,CAAK,GAAA,UAAa,KAAA,aAAkB,GAAA,aAAgB,OAAA;EACpD,MAAA,CAAO,OAAA,UAAiB,GAAA,UAAa,KAAA,aAAkB,IAAA,aAAiB,OAAA;EACxE,QAAA,CACE,GAAA,UACA,KAAA,aACG,IAAA,wBACF,OAAA,CAAQ,KAAA;EACX,MAAA,CACE,GAAA,UACA,KAAA,UACA,QAAA,UACA,WAAA,aACG,GAAA,aACF,OAAA,CAAQ,KAAA;EACX,IAAA,CAAK,GAAA,WAAc,OAAA;EACnB,IAAA,IAAQ,OAAA;AAAA;AAAA,UAOO,2BAAA;EArBR;;;;EA0BP,MAAA;EAzBA;;;;;EAgCA,KAAA;EA3BA;;;;EAiCA,QAAA;EA5BK;;;;EAkCL,WAAA;EAhCmB;;;;EAsCnB,SAAA;EA9Be;;;;EAoCf,UAAA;EAxBA;;;;;;EAgCA,cAAA;EAcA;;;;;EAPA,gBAAA;EAoBgC;;;;;EAbhC,MAAA;EAqE0C;;;;EA/D1C,MAAA,GAAS,WAAA;AAAA;AAAA,cAOE,oBAAA,YAAgC,cAAA;EAAA,SAClC,IAAA;EAAA,QAED,KAAA;EAAA,QACA,MAAA;EAAA,QACA,KAAA;EAAA,QACA,QAAA;EAAA,QACA,WAAA;EAAA,QACA,SAAA;EAAA,QACA,UAAA;EAAA,QACA,cAAA;EAAA,QACA,gBAAA;EAAA,QACA,MAAA;EAAA,QAEA,MAAA;EAAA,QAEA,QAAA;EAAA,QACA,OAAA;EAAA,QACA,WAAA;EAAA,QACA,YAAA;cAEI,KAAA,EAAO,eAAA,EAAiB,OAAA,GAAS,2BAAA;EAkBvC,OAAA,CAAQ,KAAA,EAAO,WAAA,GAAc,OAAA;EAiB7B,SAAA,CAAU,OAAA,UAAiB,OAAA,EAAS,YAAA,GAAe,OAAA;EA8BnD,KAAA,CAAA,GAAS,OAAA;EAAA,QAeD,WAAA;EAAA,QAqBA,QAAA;EAAA,QAkBA,eAAA;EAAA,QAkBA,YAAA;EAAA,QAiDA,YAAA;EAAA,QA8CN,mBAAA;EAAA,QAcA,cAAA;EAAA,QAcM,SAAA;EAAA,QA+BN,KAAA;AAAA"}
@@ -0,0 +1,12 @@
1
+ import "../elevation-B_2dRLVP.mjs";
2
+ import { C as RegisterOptions, w as ResourceRegistry } from "../interface-Ch8HU9uM.mjs";
3
+ import "../types-aYB4V7uN.mjs";
4
+ import { IntrospectionPluginOptions } from "../types/index.mjs";
5
+ import { FastifyPluginAsync } from "fastify";
6
+
7
+ //#region src/registry/introspectionPlugin.d.ts
8
+ declare const introspectionPlugin: FastifyPluginAsync<IntrospectionPluginOptions>;
9
+ declare const _default: FastifyPluginAsync<IntrospectionPluginOptions>;
10
+ //#endregion
11
+ export { type IntrospectionPluginOptions, type RegisterOptions, ResourceRegistry, _default as introspectionPlugin, introspectionPlugin as introspectionPluginFn };
12
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/registry/introspectionPlugin.ts"],"mappings":";;;;;;;cAUM,mBAAA,EAAqB,kBAAA,CAAmB,0BAAA;AAAA,cAA0B,QAAA"}
@@ -0,0 +1,4 @@
1
+ import { t as ResourceRegistry } from "../ResourceRegistry-DsN4KJjV.mjs";
2
+ import { n as introspectionPlugin_default, t as introspectionPlugin } from "../introspectionPlugin-rFdO8ZUa.mjs";
3
+
4
+ export { ResourceRegistry, introspectionPlugin_default as introspectionPlugin, introspectionPlugin as introspectionPluginFn };
@@ -0,0 +1,56 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+
3
+ //#region src/context/requestContext.ts
4
+ /**
5
+ * Request Context via AsyncLocalStorage
6
+ *
7
+ * Provides request-scoped context accessible anywhere in the call stack
8
+ * without threading parameters through every function call.
9
+ *
10
+ * Uses Node.js native AsyncLocalStorage — zero-cost per request, no allocation
11
+ * beyond the store object, and fully supported since Node 16.
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * import { requestContext } from '@classytic/arc';
16
+ *
17
+ * // Anywhere in the call stack — no parameter passing needed
18
+ * async function auditAction(action: string) {
19
+ * const ctx = requestContext.get();
20
+ * await auditLog.write({
21
+ * action,
22
+ * userId: ctx?.user?.id,
23
+ * orgId: ctx?.organizationId,
24
+ * requestId: ctx?.requestId,
25
+ * });
26
+ * }
27
+ *
28
+ * // Type-safe access to specific fields
29
+ * const userId = requestContext.get()?.user?.id;
30
+ * const orgId = requestContext.get()?.organizationId;
31
+ * ```
32
+ */
33
+ const storage = new AsyncLocalStorage();
34
+ /**
35
+ * Request context API.
36
+ *
37
+ * - `get()` — returns current store or undefined if outside request scope
38
+ * - `run(store, fn)` — run a function with a specific store (used by Arc internals)
39
+ * - `getStore()` — alias for get() (matches Node.js API naming)
40
+ */
41
+ const requestContext = {
42
+ get() {
43
+ return storage.getStore();
44
+ },
45
+ getStore() {
46
+ return storage.getStore();
47
+ },
48
+ run(store, fn) {
49
+ return storage.run(store, fn);
50
+ },
51
+ storage
52
+ };
53
+
54
+ //#endregion
55
+ export { requestContext as t };
56
+ //# sourceMappingURL=requestContext-QQD6ROJc.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requestContext-QQD6ROJc.mjs","names":[],"sources":["../src/context/requestContext.ts"],"sourcesContent":["/**\n * Request Context via AsyncLocalStorage\n *\n * Provides request-scoped context accessible anywhere in the call stack\n * without threading parameters through every function call.\n *\n * Uses Node.js native AsyncLocalStorage — zero-cost per request, no allocation\n * beyond the store object, and fully supported since Node 16.\n *\n * @example\n * ```typescript\n * import { requestContext } from '@classytic/arc';\n *\n * // Anywhere in the call stack — no parameter passing needed\n * async function auditAction(action: string) {\n * const ctx = requestContext.get();\n * await auditLog.write({\n * action,\n * userId: ctx?.user?.id,\n * orgId: ctx?.organizationId,\n * requestId: ctx?.requestId,\n * });\n * }\n *\n * // Type-safe access to specific fields\n * const userId = requestContext.get()?.user?.id;\n * const orgId = requestContext.get()?.organizationId;\n * ```\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\n\n/**\n * Shape of the request-scoped context store.\n * Populated by Arc's onRequest hook in arcCorePlugin.\n */\nexport interface RequestStore {\n /** Unique request identifier */\n requestId?: string;\n /** Authenticated user (if any) */\n user?: { id?: string; _id?: string; roles?: string[]; [key: string]: unknown } | null;\n /** Active organization ID (multi-tenant) */\n organizationId?: string;\n /** Active team ID (team-scoped resources) */\n teamId?: string;\n /** Current resource name (set by arcDecorator in CRUD routes) */\n resourceName?: string;\n /** Request start time (for timing) */\n startTime: number;\n /** Additional context — extensible by app */\n [key: string]: unknown;\n}\n\nconst storage = new AsyncLocalStorage<RequestStore>();\n\n/**\n * Request context API.\n *\n * - `get()` — returns current store or undefined if outside request scope\n * - `run(store, fn)` — run a function with a specific store (used by Arc internals)\n * - `getStore()` — alias for get() (matches Node.js API naming)\n */\nexport const requestContext = {\n /**\n * Get the current request context.\n * Returns undefined if called outside a request lifecycle.\n */\n get(): RequestStore | undefined {\n return storage.getStore();\n },\n\n /**\n * Alias for get() — matches Node.js AsyncLocalStorage API naming.\n */\n getStore(): RequestStore | undefined {\n return storage.getStore();\n },\n\n /**\n * Run a function within a specific request context.\n * Used internally by Arc's onRequest hook.\n */\n run<T>(store: RequestStore, fn: () => T): T {\n return storage.run(store, fn);\n },\n\n /**\n * The underlying AsyncLocalStorage instance.\n * Exposed for advanced use cases (testing, custom integrations).\n */\n storage,\n};\n\nexport default requestContext;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqDA,MAAM,UAAU,IAAI,mBAAiC;;;;;;;;AASrD,MAAa,iBAAiB;CAK5B,MAAgC;AAC9B,SAAO,QAAQ,UAAU;;CAM3B,WAAqC;AACnC,SAAO,QAAQ,UAAU;;CAO3B,IAAO,OAAqB,IAAgB;AAC1C,SAAO,QAAQ,IAAI,OAAO,GAAG;;CAO/B;CACD"}
@@ -0,0 +1,99 @@
1
+ //#region src/utils/schemaConverter.ts
2
+ let _toJSONSchema = null;
3
+ import("zod").then(({ z }) => {
4
+ if (typeof z?.toJSONSchema === "function") _toJSONSchema = (schema, opts) => z.toJSONSchema(schema, opts);
5
+ }).catch(() => {});
6
+ /**
7
+ * Check if an object is already a plain JSON Schema.
8
+ * Returns true if it has JSON Schema markers (`type`, `properties`, `$ref`,
9
+ * `allOf`, `anyOf`, `oneOf`, `items`, `enum`) and does NOT have Zod markers.
10
+ */
11
+ function isJsonSchema(input) {
12
+ if (input === null || typeof input !== "object") return false;
13
+ const obj = input;
14
+ if ("_def" in obj || "_zod" in obj) return false;
15
+ return "type" in obj || "properties" in obj || "$ref" in obj || "allOf" in obj || "anyOf" in obj || "oneOf" in obj || "items" in obj || "enum" in obj;
16
+ }
17
+ /**
18
+ * Check if an object is a Zod schema (has `_zod` marker from Zod v4).
19
+ */
20
+ function isZodSchema(input) {
21
+ return input !== null && typeof input === "object" && "_zod" in input;
22
+ }
23
+ /**
24
+ * Convert any schema input to JSON Schema.
25
+ *
26
+ * Detection order:
27
+ * 1. `null`/`undefined` → `undefined`
28
+ * 2. Already JSON Schema → pass through as-is (zero overhead)
29
+ * 3. Zod v4 schema → `z.toJSONSchema(schema, { target: 'openapi-3.0' })`
30
+ * 4. Unrecognized object → return as-is (treat as opaque schema)
31
+ */
32
+ function toJsonSchema(input) {
33
+ if (input == null) return void 0;
34
+ if (typeof input !== "object") return void 0;
35
+ if (isJsonSchema(input)) return input;
36
+ if (isZodSchema(input)) {
37
+ if (!_toJSONSchema) {
38
+ console.warn("[Arc] Zod schema detected but zod is not installed. Install zod v4: npm install zod");
39
+ return input;
40
+ }
41
+ try {
42
+ return _toJSONSchema(input, { target: "openapi-3.0" });
43
+ } catch {
44
+ return { type: "object" };
45
+ }
46
+ }
47
+ return input;
48
+ }
49
+ /**
50
+ * Convert all schema fields in an OpenApiSchemas object.
51
+ * JSON Schema values pass through unchanged. Only Zod schemas are converted.
52
+ */
53
+ function convertOpenApiSchemas(schemas) {
54
+ const result = {};
55
+ const schemaFields = [
56
+ "entity",
57
+ "createBody",
58
+ "updateBody",
59
+ "params",
60
+ "listQuery",
61
+ "response"
62
+ ];
63
+ for (const field of schemaFields) {
64
+ const value = schemas[field];
65
+ if (value !== void 0) result[field] = toJsonSchema(value) ?? value;
66
+ }
67
+ for (const [key, value] of Object.entries(schemas)) if (!schemaFields.includes(key)) result[key] = value;
68
+ return result;
69
+ }
70
+ /**
71
+ * Convert schema values in a Fastify route schema record.
72
+ *
73
+ * Handles `body`, `querystring`, `params`, `headers` (top-level conversion)
74
+ * and `response` (iterates by status code — each value converted individually).
75
+ *
76
+ * JSON Schema values pass through unchanged. Only Zod schemas are converted.
77
+ *
78
+ * Used for both additionalRoutes and customSchemas (CRUD overrides).
79
+ */
80
+ function convertRouteSchema(schema) {
81
+ const result = { ...schema };
82
+ for (const field of [
83
+ "body",
84
+ "querystring",
85
+ "params",
86
+ "headers"
87
+ ]) if (result[field] !== void 0) result[field] = toJsonSchema(result[field]) ?? result[field];
88
+ if (result.response !== void 0 && typeof result.response === "object" && result.response !== null) {
89
+ const responseObj = result.response;
90
+ const convertedResponse = {};
91
+ for (const [statusCode, responseSchema] of Object.entries(responseObj)) convertedResponse[statusCode] = toJsonSchema(responseSchema) ?? responseSchema;
92
+ result.response = convertedResponse;
93
+ }
94
+ return result;
95
+ }
96
+
97
+ //#endregion
98
+ export { toJsonSchema as a, isZodSchema as i, convertRouteSchema as n, isJsonSchema as r, convertOpenApiSchemas as t };
99
+ //# sourceMappingURL=schemaConverter-BwrmWroW.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemaConverter-BwrmWroW.mjs","names":[],"sources":["../src/utils/schemaConverter.ts"],"sourcesContent":["/**\n * Schema Converter — Detect-First, Convert-Only-When-Needed\n *\n * Converts Zod v4 schemas to JSON Schema using Zod's native `z.toJSONSchema()`.\n * Plain JSON Schema objects pass through with zero overhead.\n *\n * Zod is an **optional** peer dependency — loaded lazily at module init.\n * If Zod is not installed, Zod schemas pass through unconverted with a warning.\n *\n * @example\n * ```typescript\n * import { toJsonSchema } from '@classytic/arc/utils';\n *\n * // Zod v4 schema → auto-converted via z.toJSONSchema()\n * const schema = toJsonSchema(z.object({ name: z.string() }));\n *\n * // Plain JSON Schema → passes through as-is\n * const same = toJsonSchema({ type: 'object', properties: { name: { type: 'string' } } });\n * ```\n */\n\nimport type { OpenApiSchemas } from '../types/index.js';\n\n// ============================================================================\n// Lazy Zod Import — loaded once at module init, only if installed\n// ============================================================================\n\ntype ToJSONSchemaFn = (schema: unknown, opts?: unknown) => Record<string, unknown>;\nlet _toJSONSchema: ToJSONSchemaFn | null = null;\n\n// Fire-and-forget: resolve Zod at module load (async but non-blocking).\n// By the time any route handler calls toJsonSchema(), the promise will have settled.\n// Safe for both ESM and CJS (no top-level await).\nimport('zod')\n .then(({ z }) => {\n if (typeof z?.toJSONSchema === 'function') {\n _toJSONSchema = (schema, opts) =>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n z.toJSONSchema(schema as any, opts as any) as Record<string, unknown>;\n }\n })\n .catch(() => {\n // Zod not installed — schema conversion will pass through Zod objects as-is\n });\n\n// ============================================================================\n// Detection — O(1) checks\n// ============================================================================\n\n/**\n * Check if an object is already a plain JSON Schema.\n * Returns true if it has JSON Schema markers (`type`, `properties`, `$ref`,\n * `allOf`, `anyOf`, `oneOf`, `items`, `enum`) and does NOT have Zod markers.\n */\nexport function isJsonSchema(input: unknown): input is Record<string, unknown> {\n if (input === null || typeof input !== 'object') return false;\n const obj = input as Record<string, unknown>;\n\n // Zod markers — if present, this is a Zod schema, not JSON Schema\n if ('_def' in obj || '_zod' in obj) return false;\n\n // JSON Schema markers\n return (\n 'type' in obj ||\n 'properties' in obj ||\n '$ref' in obj ||\n 'allOf' in obj ||\n 'anyOf' in obj ||\n 'oneOf' in obj ||\n 'items' in obj ||\n 'enum' in obj\n );\n}\n\n/**\n * Check if an object is a Zod schema (has `_zod` marker from Zod v4).\n */\nexport function isZodSchema(input: unknown): boolean {\n return input !== null && typeof input === 'object' && '_zod' in (input as Record<string, unknown>);\n}\n\n// ============================================================================\n// Converter\n// ============================================================================\n\n/**\n * Convert any schema input to JSON Schema.\n *\n * Detection order:\n * 1. `null`/`undefined` → `undefined`\n * 2. Already JSON Schema → pass through as-is (zero overhead)\n * 3. Zod v4 schema → `z.toJSONSchema(schema, { target: 'openapi-3.0' })`\n * 4. Unrecognized object → return as-is (treat as opaque schema)\n */\nexport function toJsonSchema(input: unknown): Record<string, unknown> | undefined {\n if (input == null) return undefined;\n if (typeof input !== 'object') return undefined;\n\n // Fast path: already a plain JSON Schema → passthrough\n if (isJsonSchema(input)) return input as Record<string, unknown>;\n\n // Zod v4 schema → native conversion\n if (isZodSchema(input)) {\n if (!_toJSONSchema) {\n // Zod not installed but a Zod schema was passed — can't convert\n console.warn(\n '[Arc] Zod schema detected but zod is not installed. ' +\n 'Install zod v4: npm install zod'\n );\n return input as Record<string, unknown>;\n }\n try {\n return _toJSONSchema(input, { target: 'openapi-3.0' });\n } catch {\n return { type: 'object' };\n }\n }\n\n // Unrecognized — return as-is (don't break opaque schemas)\n return input as Record<string, unknown>;\n}\n\n// ============================================================================\n// Batch Converters\n// ============================================================================\n\n/**\n * Convert all schema fields in an OpenApiSchemas object.\n * JSON Schema values pass through unchanged. Only Zod schemas are converted.\n */\nexport function convertOpenApiSchemas(schemas: OpenApiSchemas): OpenApiSchemas {\n const result: OpenApiSchemas = {};\n const schemaFields = ['entity', 'createBody', 'updateBody', 'params', 'listQuery', 'response'] as const;\n\n for (const field of schemaFields) {\n const value = schemas[field];\n if (value !== undefined) {\n result[field] = toJsonSchema(value) ?? value;\n }\n }\n\n // Copy any extra fields as-is\n for (const [key, value] of Object.entries(schemas)) {\n if (!schemaFields.includes(key as typeof schemaFields[number])) {\n result[key] = value;\n }\n }\n\n return result;\n}\n\n/**\n * Convert schema values in a Fastify route schema record.\n *\n * Handles `body`, `querystring`, `params`, `headers` (top-level conversion)\n * and `response` (iterates by status code — each value converted individually).\n *\n * JSON Schema values pass through unchanged. Only Zod schemas are converted.\n *\n * Used for both additionalRoutes and customSchemas (CRUD overrides).\n */\nexport function convertRouteSchema(schema: Record<string, unknown>): Record<string, unknown> {\n const result: Record<string, unknown> = { ...schema };\n\n // Convert top-level schema fields (body, querystring, params, headers)\n for (const field of ['body', 'querystring', 'params', 'headers'] as const) {\n if (result[field] !== undefined) {\n result[field] = toJsonSchema(result[field]) ?? result[field];\n }\n }\n\n // Convert response schemas (keyed by status code, e.g. { 200: zodSchema, 201: zodSchema })\n if (result.response !== undefined && typeof result.response === 'object' && result.response !== null) {\n const responseObj = result.response as Record<string, unknown>;\n const convertedResponse: Record<string, unknown> = {};\n for (const [statusCode, responseSchema] of Object.entries(responseObj)) {\n convertedResponse[statusCode] = toJsonSchema(responseSchema) ?? responseSchema;\n }\n result.response = convertedResponse;\n }\n\n return result;\n}\n"],"mappings":";AA4BA,IAAI,gBAAuC;AAK3C,OAAO,OACJ,MAAM,EAAE,QAAQ;AACf,KAAI,OAAO,GAAG,iBAAiB,WAC7B,kBAAiB,QAAQ,SAEvB,EAAE,aAAa,QAAe,KAAY;EAE9C,CACD,YAAY,GAEX;;;;;;AAWJ,SAAgB,aAAa,OAAkD;AAC7E,KAAI,UAAU,QAAQ,OAAO,UAAU,SAAU,QAAO;CACxD,MAAM,MAAM;AAGZ,KAAI,UAAU,OAAO,UAAU,IAAK,QAAO;AAG3C,QACE,UAAU,OACV,gBAAgB,OAChB,UAAU,OACV,WAAW,OACX,WAAW,OACX,WAAW,OACX,WAAW,OACX,UAAU;;;;;AAOd,SAAgB,YAAY,OAAyB;AACnD,QAAO,UAAU,QAAQ,OAAO,UAAU,YAAY,UAAW;;;;;;;;;;;AAgBnE,SAAgB,aAAa,OAAqD;AAChF,KAAI,SAAS,KAAM,QAAO;AAC1B,KAAI,OAAO,UAAU,SAAU,QAAO;AAGtC,KAAI,aAAa,MAAM,CAAE,QAAO;AAGhC,KAAI,YAAY,MAAM,EAAE;AACtB,MAAI,CAAC,eAAe;AAElB,WAAQ,KACN,sFAED;AACD,UAAO;;AAET,MAAI;AACF,UAAO,cAAc,OAAO,EAAE,QAAQ,eAAe,CAAC;UAChD;AACN,UAAO,EAAE,MAAM,UAAU;;;AAK7B,QAAO;;;;;;AAWT,SAAgB,sBAAsB,SAAyC;CAC7E,MAAM,SAAyB,EAAE;CACjC,MAAM,eAAe;EAAC;EAAU;EAAc;EAAc;EAAU;EAAa;EAAW;AAE9F,MAAK,MAAM,SAAS,cAAc;EAChC,MAAM,QAAQ,QAAQ;AACtB,MAAI,UAAU,OACZ,QAAO,SAAS,aAAa,MAAM,IAAI;;AAK3C,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,CAChD,KAAI,CAAC,aAAa,SAAS,IAAmC,CAC5D,QAAO,OAAO;AAIlB,QAAO;;;;;;;;;;;;AAaT,SAAgB,mBAAmB,QAA0D;CAC3F,MAAM,SAAkC,EAAE,GAAG,QAAQ;AAGrD,MAAK,MAAM,SAAS;EAAC;EAAQ;EAAe;EAAU;EAAU,CAC9D,KAAI,OAAO,WAAW,OACpB,QAAO,SAAS,aAAa,OAAO,OAAO,IAAI,OAAO;AAK1D,KAAI,OAAO,aAAa,UAAa,OAAO,OAAO,aAAa,YAAY,OAAO,aAAa,MAAM;EACpG,MAAM,cAAc,OAAO;EAC3B,MAAM,oBAA6C,EAAE;AACrD,OAAK,MAAM,CAAC,YAAY,mBAAmB,OAAO,QAAQ,YAAY,CACpE,mBAAkB,cAAc,aAAa,eAAe,IAAI;AAElE,SAAO,WAAW;;AAGpB,QAAO"}
@@ -0,0 +1,64 @@
1
+ import * as _sinclair_typebox0 from "@sinclair/typebox";
2
+ import { Static, TObject, TSchema, TSchema as TSchema$1, Type } from "@sinclair/typebox";
3
+ import { FastifyPluginAsyncTypebox, FastifyPluginCallbackTypebox, TypeBoxTypeProvider, TypeBoxValidatorCompiler } from "@fastify/type-provider-typebox";
4
+
5
+ //#region src/schemas/index.d.ts
6
+ /**
7
+ * Paginated list response — matches Arc's runtime format:
8
+ * `{ success, docs: [...], page, limit, total, pages, hasNext, hasPrev }`
9
+ */
10
+ declare function ArcListResponse<T extends TSchema$1>(itemSchema: T): _sinclair_typebox0.TObject<{
11
+ success: _sinclair_typebox0.TBoolean;
12
+ docs: _sinclair_typebox0.TArray<T>;
13
+ page: _sinclair_typebox0.TInteger;
14
+ limit: _sinclair_typebox0.TInteger;
15
+ total: _sinclair_typebox0.TInteger;
16
+ pages: _sinclair_typebox0.TInteger;
17
+ hasNext: _sinclair_typebox0.TBoolean;
18
+ hasPrev: _sinclair_typebox0.TBoolean;
19
+ }>;
20
+ /**
21
+ * Single item response — `{ success, data: {...} }`
22
+ */
23
+ declare function ArcItemResponse<T extends TSchema$1>(itemSchema: T): _sinclair_typebox0.TObject<{
24
+ success: _sinclair_typebox0.TBoolean;
25
+ data: T;
26
+ }>;
27
+ /**
28
+ * Mutation (create/update) response — `{ success, data: {...}, message? }`
29
+ */
30
+ declare function ArcMutationResponse<T extends TSchema$1>(itemSchema: T): _sinclair_typebox0.TObject<{
31
+ success: _sinclair_typebox0.TBoolean;
32
+ data: T;
33
+ message: _sinclair_typebox0.TOptional<_sinclair_typebox0.TString>;
34
+ }>;
35
+ /**
36
+ * Delete response — `{ success, message }`
37
+ */
38
+ declare function ArcDeleteResponse(): _sinclair_typebox0.TObject<{
39
+ success: _sinclair_typebox0.TBoolean;
40
+ message: _sinclair_typebox0.TOptional<_sinclair_typebox0.TString>;
41
+ }>;
42
+ /**
43
+ * Error response schema
44
+ */
45
+ declare function ArcErrorResponse(): _sinclair_typebox0.TObject<{
46
+ success: _sinclair_typebox0.TLiteral<false>;
47
+ error: _sinclair_typebox0.TString;
48
+ code: _sinclair_typebox0.TOptional<_sinclair_typebox0.TString>;
49
+ message: _sinclair_typebox0.TOptional<_sinclair_typebox0.TString>;
50
+ }>;
51
+ /**
52
+ * Standard pagination + sorting + filtering query parameters.
53
+ * Matches Arc's list endpoint conventions.
54
+ */
55
+ declare function ArcPaginationQuery(): _sinclair_typebox0.TObject<{
56
+ page: _sinclair_typebox0.TOptional<_sinclair_typebox0.TInteger>;
57
+ limit: _sinclair_typebox0.TOptional<_sinclair_typebox0.TInteger>;
58
+ sort: _sinclair_typebox0.TOptional<_sinclair_typebox0.TString>;
59
+ select: _sinclair_typebox0.TOptional<_sinclair_typebox0.TString>;
60
+ populate: _sinclair_typebox0.TOptional<_sinclair_typebox0.TString>;
61
+ }>;
62
+ //#endregion
63
+ export { ArcDeleteResponse, ArcErrorResponse, ArcItemResponse, ArcListResponse, ArcMutationResponse, ArcPaginationQuery, type FastifyPluginAsyncTypebox, type FastifyPluginCallbackTypebox, type Static, type TObject, type TSchema, Type, type TypeBoxTypeProvider, TypeBoxValidatorCompiler };
64
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/schemas/index.ts"],"mappings":";;;;;;;;;iBA+CgB,eAAA,WAA0B,SAAA,CAAA,CAAS,UAAA,EAAY,CAAA,sBAAC,OAAA;WAAA,kBAAA,CAAA,QAAA;;;;;;;;;AAgBhE;;;AAAA,iBAAgB,eAAA,WAA0B,SAAA,CAAA,CAAS,UAAA,EAAY,CAAA,sBAAC,OAAA;WAAA,kBAAA,CAAA,QAAA;;;;;;iBAUhD,mBAAA,WAA8B,SAAA,CAAA,CAAS,UAAA,EAAY,CAAA,sBAAC,OAAA;WAAA,kBAAA,CAAA,QAAA;;;;;;;iBAWpD,iBAAA,CAAA,sBAAiB,OAAA;WAAA,kBAAA,CAAA,QAAA;;;;;;iBAUjB,gBAAA,CAAA,sBAAgB,OAAA;WAAA,kBAAA,CAAA,QAAA;;;;;;;;;iBAiBhB,kBAAA,CAAA,sBAAkB,OAAA;qCAAA,kBAAA,CAAA,QAAA"}
@@ -0,0 +1,83 @@
1
+ import { Type, Type as Type$1 } from "@sinclair/typebox";
2
+ import { TypeBoxValidatorCompiler } from "@fastify/type-provider-typebox";
3
+
4
+ //#region src/schemas/index.ts
5
+ /**
6
+ * Paginated list response — matches Arc's runtime format:
7
+ * `{ success, docs: [...], page, limit, total, pages, hasNext, hasPrev }`
8
+ */
9
+ function ArcListResponse(itemSchema) {
10
+ return Type$1.Object({
11
+ success: Type$1.Boolean(),
12
+ docs: Type$1.Array(itemSchema),
13
+ page: Type$1.Integer(),
14
+ limit: Type$1.Integer(),
15
+ total: Type$1.Integer(),
16
+ pages: Type$1.Integer(),
17
+ hasNext: Type$1.Boolean(),
18
+ hasPrev: Type$1.Boolean()
19
+ });
20
+ }
21
+ /**
22
+ * Single item response — `{ success, data: {...} }`
23
+ */
24
+ function ArcItemResponse(itemSchema) {
25
+ return Type$1.Object({
26
+ success: Type$1.Boolean(),
27
+ data: itemSchema
28
+ });
29
+ }
30
+ /**
31
+ * Mutation (create/update) response — `{ success, data: {...}, message? }`
32
+ */
33
+ function ArcMutationResponse(itemSchema) {
34
+ return Type$1.Object({
35
+ success: Type$1.Boolean(),
36
+ data: itemSchema,
37
+ message: Type$1.Optional(Type$1.String())
38
+ });
39
+ }
40
+ /**
41
+ * Delete response — `{ success, message }`
42
+ */
43
+ function ArcDeleteResponse() {
44
+ return Type$1.Object({
45
+ success: Type$1.Boolean(),
46
+ message: Type$1.Optional(Type$1.String())
47
+ });
48
+ }
49
+ /**
50
+ * Error response schema
51
+ */
52
+ function ArcErrorResponse() {
53
+ return Type$1.Object({
54
+ success: Type$1.Literal(false),
55
+ error: Type$1.String(),
56
+ code: Type$1.Optional(Type$1.String()),
57
+ message: Type$1.Optional(Type$1.String())
58
+ });
59
+ }
60
+ /**
61
+ * Standard pagination + sorting + filtering query parameters.
62
+ * Matches Arc's list endpoint conventions.
63
+ */
64
+ function ArcPaginationQuery() {
65
+ return Type$1.Object({
66
+ page: Type$1.Optional(Type$1.Integer({
67
+ minimum: 1,
68
+ default: 1
69
+ })),
70
+ limit: Type$1.Optional(Type$1.Integer({
71
+ minimum: 1,
72
+ maximum: 100,
73
+ default: 20
74
+ })),
75
+ sort: Type$1.Optional(Type$1.String()),
76
+ select: Type$1.Optional(Type$1.String()),
77
+ populate: Type$1.Optional(Type$1.String())
78
+ });
79
+ }
80
+
81
+ //#endregion
82
+ export { ArcDeleteResponse, ArcErrorResponse, ArcItemResponse, ArcListResponse, ArcMutationResponse, ArcPaginationQuery, Type, TypeBoxValidatorCompiler };
83
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["Type"],"sources":["../../src/schemas/index.ts"],"sourcesContent":["/**\n * Arc Schema Utilities — TypeBox Integration\n *\n * Provides type-safe schema definitions for Fastify routes using TypeBox.\n * Install `@sinclair/typebox` and `@fastify/type-provider-typebox` to use.\n *\n * @example\n * ```typescript\n * import { Type, ArcListResponse, ArcPaginationQuery } from '@classytic/arc/schemas';\n *\n * const ItemSchema = Type.Object({\n * _id: Type.String(),\n * name: Type.String(),\n * createdAt: Type.String({ format: 'date-time' }),\n * });\n *\n * // Use in route definitions\n * fastify.get('/items', {\n * schema: {\n * querystring: ArcPaginationQuery(),\n * response: { 200: ArcListResponse(ItemSchema) },\n * },\n * }, handler);\n * ```\n *\n * @module\n */\n\n// Re-export TypeBox core — users import Type from here instead of @sinclair/typebox directly\nexport { Type } from '@sinclair/typebox';\nexport type { Static, TSchema, TObject } from '@sinclair/typebox';\n\n// Re-export Fastify TypeBox type provider\nexport { TypeBoxValidatorCompiler } from '@fastify/type-provider-typebox';\nexport type { TypeBoxTypeProvider, FastifyPluginAsyncTypebox, FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox';\n\nimport { Type } from '@sinclair/typebox';\nimport type { TSchema } from '@sinclair/typebox';\n\n// ============================================================================\n// Arc Response Schemas (TypeBox versions of responseSchemas.ts)\n// ============================================================================\n\n/**\n * Paginated list response — matches Arc's runtime format:\n * `{ success, docs: [...], page, limit, total, pages, hasNext, hasPrev }`\n */\nexport function ArcListResponse<T extends TSchema>(itemSchema: T) {\n return Type.Object({\n success: Type.Boolean(),\n docs: Type.Array(itemSchema),\n page: Type.Integer(),\n limit: Type.Integer(),\n total: Type.Integer(),\n pages: Type.Integer(),\n hasNext: Type.Boolean(),\n hasPrev: Type.Boolean(),\n });\n}\n\n/**\n * Single item response — `{ success, data: {...} }`\n */\nexport function ArcItemResponse<T extends TSchema>(itemSchema: T) {\n return Type.Object({\n success: Type.Boolean(),\n data: itemSchema,\n });\n}\n\n/**\n * Mutation (create/update) response — `{ success, data: {...}, message? }`\n */\nexport function ArcMutationResponse<T extends TSchema>(itemSchema: T) {\n return Type.Object({\n success: Type.Boolean(),\n data: itemSchema,\n message: Type.Optional(Type.String()),\n });\n}\n\n/**\n * Delete response — `{ success, message }`\n */\nexport function ArcDeleteResponse() {\n return Type.Object({\n success: Type.Boolean(),\n message: Type.Optional(Type.String()),\n });\n}\n\n/**\n * Error response schema\n */\nexport function ArcErrorResponse() {\n return Type.Object({\n success: Type.Literal(false),\n error: Type.String(),\n code: Type.Optional(Type.String()),\n message: Type.Optional(Type.String()),\n });\n}\n\n// ============================================================================\n// Arc Query Schemas\n// ============================================================================\n\n/**\n * Standard pagination + sorting + filtering query parameters.\n * Matches Arc's list endpoint conventions.\n */\nexport function ArcPaginationQuery() {\n return Type.Object({\n page: Type.Optional(Type.Integer({ minimum: 1, default: 1 })),\n limit: Type.Optional(Type.Integer({ minimum: 1, maximum: 100, default: 20 })),\n sort: Type.Optional(Type.String()),\n select: Type.Optional(Type.String()),\n populate: Type.Optional(Type.String()),\n });\n}\n"],"mappings":";;;;;;;;AA+CA,SAAgB,gBAAmC,YAAe;AAChE,QAAOA,OAAK,OAAO;EACjB,SAASA,OAAK,SAAS;EACvB,MAAMA,OAAK,MAAM,WAAW;EAC5B,MAAMA,OAAK,SAAS;EACpB,OAAOA,OAAK,SAAS;EACrB,OAAOA,OAAK,SAAS;EACrB,OAAOA,OAAK,SAAS;EACrB,SAASA,OAAK,SAAS;EACvB,SAASA,OAAK,SAAS;EACxB,CAAC;;;;;AAMJ,SAAgB,gBAAmC,YAAe;AAChE,QAAOA,OAAK,OAAO;EACjB,SAASA,OAAK,SAAS;EACvB,MAAM;EACP,CAAC;;;;;AAMJ,SAAgB,oBAAuC,YAAe;AACpE,QAAOA,OAAK,OAAO;EACjB,SAASA,OAAK,SAAS;EACvB,MAAM;EACN,SAASA,OAAK,SAASA,OAAK,QAAQ,CAAC;EACtC,CAAC;;;;;AAMJ,SAAgB,oBAAoB;AAClC,QAAOA,OAAK,OAAO;EACjB,SAASA,OAAK,SAAS;EACvB,SAASA,OAAK,SAASA,OAAK,QAAQ,CAAC;EACtC,CAAC;;;;;AAMJ,SAAgB,mBAAmB;AACjC,QAAOA,OAAK,OAAO;EACjB,SAASA,OAAK,QAAQ,MAAM;EAC5B,OAAOA,OAAK,QAAQ;EACpB,MAAMA,OAAK,SAASA,OAAK,QAAQ,CAAC;EAClC,SAASA,OAAK,SAASA,OAAK,QAAQ,CAAC;EACtC,CAAC;;;;;;AAWJ,SAAgB,qBAAqB;AACnC,QAAOA,OAAK,OAAO;EACjB,MAAMA,OAAK,SAASA,OAAK,QAAQ;GAAE,SAAS;GAAG,SAAS;GAAG,CAAC,CAAC;EAC7D,OAAOA,OAAK,SAASA,OAAK,QAAQ;GAAE,SAAS;GAAG,SAAS;GAAK,SAAS;GAAI,CAAC,CAAC;EAC7E,MAAMA,OAAK,SAASA,OAAK,QAAQ,CAAC;EAClC,QAAQA,OAAK,SAASA,OAAK,QAAQ,CAAC;EACpC,UAAUA,OAAK,SAASA,OAAK,QAAQ,CAAC;EACvC,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { a as AUTHENTICATED_SCOPE, c as getOrgId, d as hasOrgAccess, f as isAuthenticated, i as elevationPlugin, l as getOrgRoles, m as isMember, n as ElevationOptions, o as PUBLIC_SCOPE, p as isElevated, r as _default, s as RequestScope, t as ElevationEvent, u as getTeamId } from "../elevation-B_2dRLVP.mjs";
2
+ import { FastifyReply, FastifyRequest } from "fastify";
3
+
4
+ //#region src/scope/resolveOrgFromHeader.d.ts
5
+ interface ResolveOrgFromHeaderOptions {
6
+ /** Header name (default: 'x-organization-id') */
7
+ header?: string;
8
+ /** Resolve user's membership in the org. Return roles or null if not a member. */
9
+ resolveMembership: (userId: string, orgId: string) => Promise<{
10
+ roles: string[];
11
+ } | null>;
12
+ }
13
+ /**
14
+ * Create a preHandler hook that resolves org scope from a header.
15
+ * Must run AFTER authentication so `request.user` is populated.
16
+ * If the header is present and user is a member, sets `request.scope` to `member`.
17
+ * If the header is absent, scope stays as-is (typically `authenticated`).
18
+ */
19
+ declare function resolveOrgFromHeader(options: ResolveOrgFromHeaderOptions): (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
20
+ //#endregion
21
+ export { AUTHENTICATED_SCOPE, type ElevationEvent, type ElevationOptions, PUBLIC_SCOPE, type RequestScope, type ResolveOrgFromHeaderOptions, _default as elevationPlugin, elevationPlugin as elevationPluginFn, getOrgId, getOrgRoles, getTeamId, hasOrgAccess, isAuthenticated, isElevated, isMember, resolveOrgFromHeader };
22
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/scope/resolveOrgFromHeader.ts"],"mappings":";;;;UA2BiB,2BAAA;EAcN;EAZT,MAAA;EAaW;EAXX,iBAAA,GAAoB,MAAA,UAAgB,KAAA,aAAkB,OAAA;IAAU,KAAA;EAAA;AAAA;;;;;;;iBASlD,oBAAA,CACd,OAAA,EAAS,2BAAA,IACP,OAAA,EAAS,cAAA,EAAgB,KAAA,EAAO,YAAA,KAAiB,OAAA"}
@@ -0,0 +1,66 @@
1
+ import { a as getTeamId, c as isElevated, i as getOrgRoles, l as isMember, n as PUBLIC_SCOPE, o as hasOrgAccess, r as getOrgId, s as isAuthenticated, t as AUTHENTICATED_SCOPE } from "../types-Beqn1Un7.mjs";
2
+ import { n as elevation_default, t as elevationPlugin } from "../elevation-BRy3yFWT.mjs";
3
+
4
+ //#region src/scope/resolveOrgFromHeader.ts
5
+ /**
6
+ * Create a preHandler hook that resolves org scope from a header.
7
+ * Must run AFTER authentication so `request.user` is populated.
8
+ * If the header is present and user is a member, sets `request.scope` to `member`.
9
+ * If the header is absent, scope stays as-is (typically `authenticated`).
10
+ */
11
+ function resolveOrgFromHeader(options) {
12
+ const { header = "x-organization-id", resolveMembership } = options;
13
+ return async (request, reply) => {
14
+ const orgId = request.headers[header];
15
+ if (!orgId) return;
16
+ const scope = request.scope;
17
+ if (!scope || scope.kind === "public") {
18
+ reply.code(401).send({
19
+ success: false,
20
+ error: "Unauthorized",
21
+ message: "Authentication required for organization access",
22
+ code: "ORG_AUTH_REQUIRED"
23
+ });
24
+ return;
25
+ }
26
+ if (scope.kind === "elevated") return;
27
+ const user = request.user;
28
+ if (!user) {
29
+ reply.code(401).send({
30
+ success: false,
31
+ error: "Unauthorized",
32
+ message: "Authentication required for organization access",
33
+ code: "ORG_AUTH_REQUIRED"
34
+ });
35
+ return;
36
+ }
37
+ const userId = String(user.id ?? user._id ?? "");
38
+ if (!userId) {
39
+ reply.code(401).send({
40
+ success: false,
41
+ error: "Unauthorized",
42
+ message: "User identity required for organization access"
43
+ });
44
+ return;
45
+ }
46
+ const membership = await resolveMembership(userId, orgId);
47
+ if (!membership) {
48
+ reply.code(403).send({
49
+ success: false,
50
+ error: "Forbidden",
51
+ message: "Not a member of this organization",
52
+ code: "ORG_ACCESS_DENIED"
53
+ });
54
+ return;
55
+ }
56
+ request.scope = {
57
+ kind: "member",
58
+ organizationId: orgId,
59
+ orgRoles: membership.roles
60
+ };
61
+ };
62
+ }
63
+
64
+ //#endregion
65
+ export { AUTHENTICATED_SCOPE, PUBLIC_SCOPE, elevation_default as elevationPlugin, elevationPlugin as elevationPluginFn, getOrgId, getOrgRoles, getTeamId, hasOrgAccess, isAuthenticated, isElevated, isMember, resolveOrgFromHeader };
66
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/scope/resolveOrgFromHeader.ts"],"sourcesContent":["/**\n * Resolve Org Scope from Header\n *\n * Utility hook for JWT/custom auth apps that use `x-organization-id` header\n * to select an organization. Better Auth apps don't need this — org context\n * comes from the session automatically.\n *\n * **Important:** This hook reads `request.user` and `request.scope`, which\n * are populated by the auth `preHandler`. Register it as a `preHandler`\n * (not `onRequest`) so it runs after authentication:\n *\n * @example\n * ```typescript\n * import { resolveOrgFromHeader } from '@classytic/arc/scope';\n *\n * app.addHook('preHandler', resolveOrgFromHeader({\n * resolveMembership: async (userId, orgId) => {\n * const member = await MemberModel.findOne({ userId, orgId });\n * return member ? { roles: member.roles } : null;\n * },\n * }));\n * ```\n */\n\nimport type { FastifyReply, FastifyRequest } from 'fastify';\nimport type { RequestScope } from './types.js';\n\nexport interface ResolveOrgFromHeaderOptions {\n /** Header name (default: 'x-organization-id') */\n header?: string;\n /** Resolve user's membership in the org. Return roles or null if not a member. */\n resolveMembership: (userId: string, orgId: string) => Promise<{ roles: string[] } | null>;\n}\n\n/**\n * Create a preHandler hook that resolves org scope from a header.\n * Must run AFTER authentication so `request.user` is populated.\n * If the header is present and user is a member, sets `request.scope` to `member`.\n * If the header is absent, scope stays as-is (typically `authenticated`).\n */\nexport function resolveOrgFromHeader(\n options: ResolveOrgFromHeaderOptions,\n): (request: FastifyRequest, reply: FastifyReply) => Promise<void> {\n const { header = 'x-organization-id', resolveMembership } = options;\n\n return async (request: FastifyRequest, reply: FastifyReply): Promise<void> => {\n const orgId = request.headers[header] as string | undefined;\n if (!orgId) return; // No org header — scope stays as auth adapter set it\n\n const scope = request.scope;\n if (!scope || scope.kind === 'public') {\n reply.code(401).send({\n success: false,\n error: 'Unauthorized',\n message: 'Authentication required for organization access',\n code: 'ORG_AUTH_REQUIRED',\n });\n return;\n }\n\n // Already elevated — don't downgrade\n if (scope.kind === 'elevated') return;\n\n const user = request.user;\n if (!user) {\n reply.code(401).send({\n success: false,\n error: 'Unauthorized',\n message: 'Authentication required for organization access',\n code: 'ORG_AUTH_REQUIRED',\n });\n return;\n }\n\n const userId = String(user.id ?? user._id ?? '');\n if (!userId) {\n reply.code(401).send({\n success: false,\n error: 'Unauthorized',\n message: 'User identity required for organization access',\n });\n return;\n }\n\n const membership = await resolveMembership(userId, orgId);\n if (!membership) {\n reply.code(403).send({\n success: false,\n error: 'Forbidden',\n message: 'Not a member of this organization',\n code: 'ORG_ACCESS_DENIED',\n });\n return;\n }\n\n request.scope = {\n kind: 'member',\n organizationId: orgId,\n orgRoles: membership.roles,\n } satisfies RequestScope;\n };\n}\n"],"mappings":";;;;;;;;;;AAwCA,SAAgB,qBACd,SACiE;CACjE,MAAM,EAAE,SAAS,qBAAqB,sBAAsB;AAE5D,QAAO,OAAO,SAAyB,UAAuC;EAC5E,MAAM,QAAQ,QAAQ,QAAQ;AAC9B,MAAI,CAAC,MAAO;EAEZ,MAAM,QAAQ,QAAQ;AACtB,MAAI,CAAC,SAAS,MAAM,SAAS,UAAU;AACrC,SAAM,KAAK,IAAI,CAAC,KAAK;IACnB,SAAS;IACT,OAAO;IACP,SAAS;IACT,MAAM;IACP,CAAC;AACF;;AAIF,MAAI,MAAM,SAAS,WAAY;EAE/B,MAAM,OAAO,QAAQ;AACrB,MAAI,CAAC,MAAM;AACT,SAAM,KAAK,IAAI,CAAC,KAAK;IACnB,SAAS;IACT,OAAO;IACP,SAAS;IACT,MAAM;IACP,CAAC;AACF;;EAGF,MAAM,SAAS,OAAO,KAAK,MAAM,KAAK,OAAO,GAAG;AAChD,MAAI,CAAC,QAAQ;AACX,SAAM,KAAK,IAAI,CAAC,KAAK;IACnB,SAAS;IACT,OAAO;IACP,SAAS;IACV,CAAC;AACF;;EAGF,MAAM,aAAa,MAAM,kBAAkB,QAAQ,MAAM;AACzD,MAAI,CAAC,YAAY;AACf,SAAM,KAAK,IAAI,CAAC,KAAK;IACnB,SAAS;IACT,OAAO;IACP,SAAS;IACT,MAAM;IACP,CAAC;AACF;;AAGF,UAAQ,QAAQ;GACd,MAAM;GACN,gBAAgB;GAChB,UAAU,WAAW;GACtB"}