@classytic/arc 2.3.0 → 2.4.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 (175) hide show
  1. package/README.md +187 -18
  2. package/bin/arc.js +11 -3
  3. package/dist/BaseController-CkM5dUh_.mjs +1031 -0
  4. package/dist/{EventTransport-BkUDYZEb.d.mts → EventTransport-wc5hSLik.d.mts} +1 -1
  5. package/dist/{HookSystem-BsGV-j2l.mjs → HookSystem-COkyWztM.mjs} +2 -3
  6. package/dist/{ResourceRegistry-7Ic20ZMw.mjs → ResourceRegistry-DeCIFlix.mjs} +8 -5
  7. package/dist/adapters/index.d.mts +3 -5
  8. package/dist/adapters/index.mjs +2 -3
  9. package/dist/{prisma-DJbMt3yf.mjs → adapters-DTC4Ug66.mjs} +45 -12
  10. package/dist/audit/index.d.mts +4 -7
  11. package/dist/audit/index.mjs +2 -29
  12. package/dist/audit/mongodb.d.mts +1 -4
  13. package/dist/audit/mongodb.mjs +2 -3
  14. package/dist/auth/index.d.mts +7 -9
  15. package/dist/auth/index.mjs +65 -63
  16. package/dist/auth/redis-session.d.mts +1 -1
  17. package/dist/auth/redis-session.mjs +1 -2
  18. package/dist/{betterAuthOpenApi-DjWDddNc.mjs → betterAuthOpenApi-lz0IRbXJ.mjs} +4 -6
  19. package/dist/cache/index.d.mts +23 -23
  20. package/dist/cache/index.mjs +4 -6
  21. package/dist/{caching-GSDJcA6-.mjs → caching-BSXB-Xr7.mjs} +2 -24
  22. package/dist/chunk-BpYLSNr0.mjs +14 -0
  23. package/dist/circuitBreaker-BOBOpN2w.mjs +284 -0
  24. package/dist/circuitBreaker-JP2GdJ4b.d.mts +206 -0
  25. package/dist/cli/commands/describe.mjs +24 -7
  26. package/dist/cli/commands/docs.mjs +6 -7
  27. package/dist/cli/commands/doctor.d.mts +10 -0
  28. package/dist/cli/commands/doctor.mjs +156 -0
  29. package/dist/cli/commands/generate.mjs +66 -17
  30. package/dist/cli/commands/init.mjs +315 -45
  31. package/dist/cli/commands/introspect.mjs +2 -4
  32. package/dist/cli/index.d.mts +1 -10
  33. package/dist/cli/index.mjs +4 -153
  34. package/dist/{constants-DdXFXQtN.mjs → constants-Cxde4rpC.mjs} +1 -2
  35. package/dist/core/index.d.mts +3 -5
  36. package/dist/core/index.mjs +5 -4
  37. package/dist/core-C1XCMtqM.mjs +185 -0
  38. package/dist/{createApp-CgKOPhA4.mjs → createApp-ByWNRsZj.mjs} +64 -35
  39. package/dist/{defineResource-DWbpJYtm.mjs → defineResource-D9aY5Cy6.mjs} +108 -1157
  40. package/dist/discovery/index.mjs +37 -5
  41. package/dist/docs/index.d.mts +6 -9
  42. package/dist/docs/index.mjs +3 -21
  43. package/dist/dynamic/index.d.mts +93 -0
  44. package/dist/dynamic/index.mjs +122 -0
  45. package/dist/{elevation-DSTbVvYj.mjs → elevation-BEdACOLB.mjs} +5 -36
  46. package/dist/{elevation-DGo5shaX.d.mts → elevation-Ca_yveIO.d.mts} +41 -7
  47. package/dist/{errorHandler-C3GY3_ow.mjs → errorHandler--zp54tGc.mjs} +3 -5
  48. package/dist/errorHandler-Do4vVQ1f.d.mts +139 -0
  49. package/dist/{errors-DBANPbGr.mjs → errors-rxhfP7Hf.mjs} +1 -2
  50. package/dist/{eventPlugin-BEOvaDqo.mjs → eventPlugin-Ba00swHF.mjs} +25 -27
  51. package/dist/{eventPlugin-H6wDDjGO.d.mts → eventPlugin-iGrSEmwJ.d.mts} +105 -5
  52. package/dist/events/index.d.mts +72 -7
  53. package/dist/events/index.mjs +216 -4
  54. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  55. package/dist/events/transports/redis-stream-entry.mjs +19 -7
  56. package/dist/events/transports/redis.d.mts +1 -1
  57. package/dist/events/transports/redis.mjs +3 -4
  58. package/dist/factory/index.d.mts +23 -9
  59. package/dist/factory/index.mjs +48 -3
  60. package/dist/{fields-Bi_AVKSo.d.mts → fields-DFwdaWCq.d.mts} +1 -1
  61. package/dist/{fields-CTd_CrKr.mjs → fields-ipsbIRPK.mjs} +1 -2
  62. package/dist/hooks/index.d.mts +1 -3
  63. package/dist/hooks/index.mjs +2 -3
  64. package/dist/idempotency/index.d.mts +5 -5
  65. package/dist/idempotency/index.mjs +3 -7
  66. package/dist/idempotency/mongodb.d.mts +1 -1
  67. package/dist/idempotency/mongodb.mjs +4 -5
  68. package/dist/idempotency/redis.d.mts +1 -1
  69. package/dist/idempotency/redis.mjs +2 -5
  70. package/dist/{fastifyAdapter-6b_eRDBw.d.mts → index-BL8CaQih.d.mts} +56 -57
  71. package/dist/index-Diqcm14c.d.mts +369 -0
  72. package/dist/{prisma-Dy5S5F5i.d.mts → index-yhxyjqNb.d.mts} +4 -5
  73. package/dist/index.d.mts +100 -105
  74. package/dist/index.mjs +85 -58
  75. package/dist/integrations/event-gateway.d.mts +1 -1
  76. package/dist/integrations/event-gateway.mjs +8 -4
  77. package/dist/integrations/index.d.mts +4 -2
  78. package/dist/integrations/index.mjs +1 -1
  79. package/dist/integrations/jobs.d.mts +2 -2
  80. package/dist/integrations/jobs.mjs +63 -14
  81. package/dist/integrations/mcp/index.d.mts +219 -0
  82. package/dist/integrations/mcp/index.mjs +572 -0
  83. package/dist/integrations/mcp/testing.d.mts +53 -0
  84. package/dist/integrations/mcp/testing.mjs +104 -0
  85. package/dist/integrations/streamline.mjs +39 -19
  86. package/dist/integrations/webhooks.d.mts +56 -0
  87. package/dist/integrations/webhooks.mjs +139 -0
  88. package/dist/integrations/websocket-redis.d.mts +46 -0
  89. package/dist/integrations/websocket-redis.mjs +50 -0
  90. package/dist/integrations/websocket.d.mts +68 -2
  91. package/dist/integrations/websocket.mjs +96 -13
  92. package/dist/{interface-CSNjltAc.d.mts → interface-B4awm1RJ.d.mts} +2 -2
  93. package/dist/interface-DGmPxakH.d.mts +2213 -0
  94. package/dist/{keys-DhqDRxv3.mjs → keys-qcD-TVJl.mjs} +3 -4
  95. package/dist/{logger-ByrvQWZO.mjs → logger-Dz3j1ItV.mjs} +2 -4
  96. package/dist/{memory-B2v7KrCB.mjs → memory-Cb_7iy9e.mjs} +2 -4
  97. package/dist/metrics-Csh4nsvv.mjs +224 -0
  98. package/dist/migrations/index.d.mts +113 -44
  99. package/dist/migrations/index.mjs +84 -102
  100. package/dist/{mongodb-DNKEExbf.mjs → mongodb-BuQ7fNTg.mjs} +1 -4
  101. package/dist/{mongodb-ClykrfGo.d.mts → mongodb-CUpYfxfD.d.mts} +2 -3
  102. package/dist/{mongodb-Dg8O_gvd.d.mts → mongodb-bga9AbkD.d.mts} +2 -2
  103. package/dist/{openapi-9nB_kiuR.mjs → openapi-CBmZ6EQN.mjs} +4 -21
  104. package/dist/org/index.d.mts +12 -14
  105. package/dist/org/index.mjs +92 -119
  106. package/dist/org/types.d.mts +2 -2
  107. package/dist/org/types.mjs +1 -1
  108. package/dist/permissions/index.d.mts +4 -278
  109. package/dist/permissions/index.mjs +4 -579
  110. package/dist/permissions-CA5zg0yK.mjs +751 -0
  111. package/dist/plugins/index.d.mts +104 -107
  112. package/dist/plugins/index.mjs +203 -313
  113. package/dist/plugins/response-cache.mjs +4 -69
  114. package/dist/plugins/tracing-entry.d.mts +1 -1
  115. package/dist/plugins/tracing-entry.mjs +24 -11
  116. package/dist/{pluralize-CM-jZg7p.mjs → pluralize-CcT6qF0a.mjs} +12 -13
  117. package/dist/policies/index.d.mts +2 -2
  118. package/dist/policies/index.mjs +80 -83
  119. package/dist/presets/index.d.mts +26 -19
  120. package/dist/presets/index.mjs +2 -142
  121. package/dist/presets/multiTenant.d.mts +1 -4
  122. package/dist/presets/multiTenant.mjs +4 -6
  123. package/dist/presets-C9QXJV1u.mjs +422 -0
  124. package/dist/{queryCachePlugin-B6R0d4av.mjs → queryCachePlugin-ClosZdNS.mjs} +6 -27
  125. package/dist/{queryCachePlugin-Q6SYuHZ6.d.mts → queryCachePlugin-DcmETvcB.d.mts} +3 -3
  126. package/dist/queryParser-CgCtsjti.mjs +352 -0
  127. package/dist/{redis-UwjEp8Ea.d.mts → redis-CQ5YxMC5.d.mts} +2 -2
  128. package/dist/{redis-stream-CBg0upHI.d.mts → redis-stream-BW9UKLZM.d.mts} +9 -2
  129. package/dist/registry/index.d.mts +1 -4
  130. package/dist/registry/index.mjs +3 -4
  131. package/dist/{introspectionPlugin-B3JkrjwU.mjs → registry-I-ogLgL9.mjs} +1 -8
  132. package/dist/{requestContext-xi6OKBL-.mjs → requestContext-DYtmNpm5.mjs} +1 -3
  133. package/dist/resourceToTools-PMFE8HIv.mjs +533 -0
  134. package/dist/rpc/index.d.mts +90 -0
  135. package/dist/rpc/index.mjs +248 -0
  136. package/dist/{schemaConverter-Dtg0Kt9T.mjs → schemaConverter-DjzHpFam.mjs} +1 -2
  137. package/dist/schemas/index.d.mts +30 -30
  138. package/dist/schemas/index.mjs +2 -4
  139. package/dist/scope/index.d.mts +13 -2
  140. package/dist/scope/index.mjs +18 -5
  141. package/dist/{sessionManager-D_iEHjQl.d.mts → sessionManager-wbkYj2HL.d.mts} +2 -2
  142. package/dist/{sse-DkqQ1uxb.mjs → sse-BkViJPlT.mjs} +4 -25
  143. package/dist/testing/index.d.mts +551 -567
  144. package/dist/testing/index.mjs +1744 -1799
  145. package/dist/{tracing-8CEbhF0w.d.mts → tracing-bz_U4EM1.d.mts} +6 -1
  146. package/dist/{typeGuards-DwxA1t_L.mjs → typeGuards-Cj5Rgvlg.mjs} +1 -2
  147. package/dist/types/index.d.mts +4 -946
  148. package/dist/types/index.mjs +2 -4
  149. package/dist/types-BJmgxNbF.d.mts +275 -0
  150. package/dist/{types-RLkFVgaw.d.mts → types-BNUccdcf.d.mts} +2 -2
  151. package/dist/{types-Beqn1Un7.mjs → types-C6TQjtdi.mjs} +30 -2
  152. package/dist/{types-tKwaViYB.d.mts → types-Dt0-AI6E.d.mts} +68 -27
  153. package/dist/{types-DelU6kln.mjs → types-ZUu_h0jp.mjs} +1 -2
  154. package/dist/utils/index.d.mts +254 -351
  155. package/dist/utils/index.mjs +7 -6
  156. package/dist/utils-Dc0WhlIl.mjs +594 -0
  157. package/dist/versioning-BzfeHmhj.mjs +37 -0
  158. package/package.json +44 -10
  159. package/skills/arc/SKILL.md +518 -0
  160. package/skills/arc/references/auth.md +250 -0
  161. package/skills/arc/references/events.md +272 -0
  162. package/skills/arc/references/integrations.md +385 -0
  163. package/skills/arc/references/mcp.md +431 -0
  164. package/skills/arc/references/production.md +610 -0
  165. package/skills/arc/references/testing.md +183 -0
  166. package/dist/audited-CGdLiSlE.mjs +0 -140
  167. package/dist/chunk-C7Uep-_p.mjs +0 -20
  168. package/dist/circuitBreaker-CSS2VvL6.mjs +0 -1109
  169. package/dist/errorHandler-CW3OOeYq.d.mts +0 -72
  170. package/dist/interface-BtdYtQUA.d.mts +0 -1114
  171. package/dist/presets-BTeYbw7h.d.mts +0 -57
  172. package/dist/presets-CeFtfDR8.mjs +0 -119
  173. /package/dist/{errors-DAWRdiYP.d.mts → errors-CPpvPHT0.d.mts} +0 -0
  174. /package/dist/{externalPaths-SyPF2tgK.d.mts → externalPaths-DpO-s7r8.d.mts} +0 -0
  175. /package/dist/{interface-DTbsvIWe.d.mts → interface-D_BWALyZ.d.mts} +0 -0
@@ -0,0 +1,248 @@
1
+ import { t as CircuitBreaker } from "../circuitBreaker-BOBOpN2w.mjs";
2
+ //#region src/rpc/serviceClient.ts
3
+ /**
4
+ * Service Client — Resource-Oriented RPC
5
+ *
6
+ * Typed HTTP client that speaks Arc's resource protocol.
7
+ * Built for microservice-to-microservice communication with:
8
+ * - correlationId propagation (distributed tracing)
9
+ * - Retry with exponential backoff (transient failure recovery)
10
+ * - Circuit breaker integration (cascading failure prevention)
11
+ * - Error normalization (consistent error handling)
12
+ * - Lifecycle hooks (observability)
13
+ *
14
+ * Zero external dependencies — uses native fetch + Arc's CircuitBreaker.
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * import { createServiceClient } from '@classytic/arc/rpc';
19
+ *
20
+ * const catalog = createServiceClient({
21
+ * baseUrl: 'http://catalog-service:3000',
22
+ * token: () => getServiceToken(),
23
+ * correlationId: () => request.id, // propagate trace context
24
+ * organizationId: req.scope.organizationId,
25
+ * retry: { maxRetries: 2, backoffMs: 200 },
26
+ * circuitBreaker: { failureThreshold: 5, resetTimeout: 30000 },
27
+ * onResponse: ({ method, url, status, durationMs }) => {
28
+ * metrics.histogram('rpc_duration', durationMs, { method, url, status });
29
+ * },
30
+ * });
31
+ *
32
+ * const products = await catalog.resource('product').list({ filters: { active: true } });
33
+ * ```
34
+ */
35
+ const DEFAULT_RETRYABLE_STATUSES = [
36
+ 502,
37
+ 503,
38
+ 504,
39
+ 408,
40
+ 429
41
+ ];
42
+ function createServiceClient(options) {
43
+ const { baseUrl, token, organizationId, correlationId, schemaVersion, headers: extraHeaders = {}, timeout = 1e4, retry: retryConfig, circuitBreaker: cbOpts, healthPath = "/_health/live", onRequest, onResponse } = options;
44
+ const base = baseUrl.replace(/\/+$/, "");
45
+ let breaker;
46
+ if (cbOpts) breaker = new CircuitBreaker(singleFetch, {
47
+ name: `service-client:${base}`,
48
+ failureThreshold: cbOpts.failureThreshold ?? 5,
49
+ resetTimeout: cbOpts.resetTimeout ?? 6e4,
50
+ timeout: cbOpts.timeout ?? timeout,
51
+ successThreshold: cbOpts.successThreshold ?? 1
52
+ });
53
+ function buildHeaders(hasBody = false) {
54
+ const h = {
55
+ accept: "application/json",
56
+ ...extraHeaders
57
+ };
58
+ if (hasBody) h["content-type"] = "application/json";
59
+ const resolvedToken = typeof token === "function" ? token() : token;
60
+ if (resolvedToken) h.authorization = `Bearer ${resolvedToken}`;
61
+ if (organizationId) h["x-organization-id"] = organizationId;
62
+ if (schemaVersion) h["x-arc-schema-version"] = schemaVersion;
63
+ const resolvedCorrelationId = typeof correlationId === "function" ? correlationId() : correlationId;
64
+ if (resolvedCorrelationId) h["x-request-id"] = resolvedCorrelationId;
65
+ return h;
66
+ }
67
+ async function singleFetch(url, init) {
68
+ const controller = new AbortController();
69
+ const timer = setTimeout(() => controller.abort(), timeout);
70
+ try {
71
+ const hasBody = !!init.body;
72
+ const response = await fetch(url, {
73
+ ...init,
74
+ signal: controller.signal,
75
+ headers: {
76
+ ...buildHeaders(hasBody),
77
+ ...init.headers ?? {}
78
+ }
79
+ });
80
+ let body;
81
+ if ((response.headers.get("content-type") ?? "").includes("application/json")) body = await response.json();
82
+ else {
83
+ const text = await response.text();
84
+ body = {
85
+ success: false,
86
+ error: response.statusText || "Unknown error",
87
+ message: text.slice(0, 200),
88
+ status: response.status
89
+ };
90
+ }
91
+ if (body.status === void 0) body.status = response.status;
92
+ if (body.success === void 0) body.success = response.ok;
93
+ return {
94
+ response,
95
+ body
96
+ };
97
+ } finally {
98
+ clearTimeout(timer);
99
+ }
100
+ }
101
+ async function execute(method, url, init) {
102
+ const startTime = performance.now();
103
+ let lastResponse;
104
+ let retries = 0;
105
+ const maxRetries = retryConfig?.maxRetries ?? 0;
106
+ const backoffMs = retryConfig?.backoffMs ?? 200;
107
+ const maxBackoffMs = retryConfig?.maxBackoffMs ?? 5e3;
108
+ const retryableStatuses = retryConfig?.retryableStatuses ?? DEFAULT_RETRYABLE_STATUSES;
109
+ onRequest?.({
110
+ method,
111
+ url
112
+ });
113
+ for (let attempt = 0; attempt <= maxRetries; attempt++) try {
114
+ let result;
115
+ if (breaker) result = await breaker.call(url, init);
116
+ else result = await singleFetch(url, init);
117
+ lastResponse = result.body;
118
+ if (result.response.ok || !retryableStatuses.includes(result.response.status)) {
119
+ onResponse?.({
120
+ method,
121
+ url,
122
+ status: result.response.status,
123
+ durationMs: performance.now() - startTime,
124
+ retries
125
+ });
126
+ return result.body;
127
+ }
128
+ if (attempt < maxRetries) {
129
+ retries++;
130
+ await sleep(Math.min(backoffMs * 2 ** attempt, maxBackoffMs));
131
+ continue;
132
+ }
133
+ onResponse?.({
134
+ method,
135
+ url,
136
+ status: result.response.status,
137
+ durationMs: performance.now() - startTime,
138
+ retries
139
+ });
140
+ return result.body;
141
+ } catch (err) {
142
+ if (attempt < maxRetries) {
143
+ retries++;
144
+ await sleep(Math.min(backoffMs * 2 ** attempt, maxBackoffMs));
145
+ continue;
146
+ }
147
+ const error = err instanceof Error ? err : new Error(String(err));
148
+ lastResponse = {
149
+ success: false,
150
+ error: error.message,
151
+ status: 0
152
+ };
153
+ onResponse?.({
154
+ method,
155
+ url,
156
+ status: 0,
157
+ durationMs: performance.now() - startTime,
158
+ retries
159
+ });
160
+ if (maxRetries === 0) throw error;
161
+ return lastResponse;
162
+ }
163
+ return lastResponse ?? {
164
+ success: false,
165
+ error: "Unknown error",
166
+ status: 0
167
+ };
168
+ }
169
+ function toQueryString(query) {
170
+ if (!query || Object.keys(query).length === 0) return "";
171
+ const params = new URLSearchParams();
172
+ for (const [key, value] of Object.entries(query)) if (value !== void 0 && value !== null) if (typeof value === "object") {
173
+ for (const [k, v] of Object.entries(value)) if (v !== void 0 && v !== null) params.set(k, String(v));
174
+ } else params.set(key, String(value));
175
+ const qs = params.toString();
176
+ return qs ? `?${qs}` : "";
177
+ }
178
+ function plural(name) {
179
+ if (name.endsWith("s")) return name;
180
+ if (name.endsWith("y") && !name.endsWith("ay") && !name.endsWith("ey") && !name.endsWith("oy") && !name.endsWith("uy")) return `${name.slice(0, -1)}ies`;
181
+ return `${name}s`;
182
+ }
183
+ return {
184
+ resource(name) {
185
+ const prefix = `${base}/${plural(name)}`;
186
+ return {
187
+ async list(query) {
188
+ return execute("GET", `${prefix}${toQueryString(query?.filters ? query.filters : query)}`, { method: "GET" });
189
+ },
190
+ async get(id) {
191
+ return execute("GET", `${prefix}/${id}`, { method: "GET" });
192
+ },
193
+ async create(data) {
194
+ return execute("POST", prefix, {
195
+ method: "POST",
196
+ body: JSON.stringify(data)
197
+ });
198
+ },
199
+ async update(id, data) {
200
+ return execute("PATCH", `${prefix}/${id}`, {
201
+ method: "PATCH",
202
+ body: JSON.stringify(data)
203
+ });
204
+ },
205
+ async delete(id) {
206
+ return execute("DELETE", `${prefix}/${id}`, { method: "DELETE" });
207
+ },
208
+ async action(id, actionName, data) {
209
+ return execute("POST", `${prefix}/${id}/action`, {
210
+ method: "POST",
211
+ body: JSON.stringify({
212
+ action: actionName,
213
+ ...data
214
+ })
215
+ });
216
+ }
217
+ };
218
+ },
219
+ async call(method, path, body) {
220
+ const url = `${base}${path}`;
221
+ const init = { method };
222
+ if (body !== void 0) init.body = JSON.stringify(body);
223
+ return execute(method, url, init);
224
+ },
225
+ async health() {
226
+ try {
227
+ const controller = new AbortController();
228
+ const timer = setTimeout(() => controller.abort(), timeout);
229
+ try {
230
+ return (await fetch(`${base}${healthPath}`, {
231
+ method: "GET",
232
+ signal: controller.signal,
233
+ headers: buildHeaders()
234
+ })).ok;
235
+ } finally {
236
+ clearTimeout(timer);
237
+ }
238
+ } catch {
239
+ return false;
240
+ }
241
+ }
242
+ };
243
+ }
244
+ function sleep(ms) {
245
+ return new Promise((resolve) => setTimeout(resolve, ms));
246
+ }
247
+ //#endregion
248
+ export { createServiceClient };
@@ -93,6 +93,5 @@ function convertRouteSchema(schema) {
93
93
  }
94
94
  return result;
95
95
  }
96
-
97
96
  //#endregion
98
- export { toJsonSchema as a, isZodSchema as i, convertRouteSchema as n, isJsonSchema as r, convertOpenApiSchemas as t };
97
+ export { toJsonSchema as a, isZodSchema as i, convertRouteSchema as n, isJsonSchema as r, convertOpenApiSchemas as t };
@@ -1,63 +1,63 @@
1
- import * as _sinclair_typebox0 from "@sinclair/typebox";
2
- import { Static, TObject, TSchema, TSchema as TSchema$1, Type } from "@sinclair/typebox";
3
1
  import { FastifyPluginAsyncTypebox, FastifyPluginCallbackTypebox, TypeBoxTypeProvider, TypeBoxValidatorCompiler } from "@fastify/type-provider-typebox";
2
+ import * as _$_sinclair_typebox0 from "@sinclair/typebox";
3
+ import { Static, TObject, TSchema, TSchema as TSchema$1, Type } from "@sinclair/typebox";
4
4
 
5
5
  //#region src/schemas/index.d.ts
6
6
  /**
7
7
  * Paginated list response — matches Arc's runtime format:
8
8
  * `{ success, docs: [...], page, limit, total, pages, hasNext, hasPrev }`
9
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;
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
19
  }>;
20
20
  /**
21
21
  * Single item response — `{ success, data: {...} }`
22
22
  */
23
- declare function ArcItemResponse<T extends TSchema$1>(itemSchema: T): _sinclair_typebox0.TObject<{
24
- success: _sinclair_typebox0.TBoolean;
23
+ declare function ArcItemResponse<T extends TSchema$1>(itemSchema: T): _$_sinclair_typebox0.TObject<{
24
+ success: _$_sinclair_typebox0.TBoolean;
25
25
  data: T;
26
26
  }>;
27
27
  /**
28
28
  * Mutation (create/update) response — `{ success, data: {...}, message? }`
29
29
  */
30
- declare function ArcMutationResponse<T extends TSchema$1>(itemSchema: T): _sinclair_typebox0.TObject<{
31
- success: _sinclair_typebox0.TBoolean;
30
+ declare function ArcMutationResponse<T extends TSchema$1>(itemSchema: T): _$_sinclair_typebox0.TObject<{
31
+ success: _$_sinclair_typebox0.TBoolean;
32
32
  data: T;
33
- message: _sinclair_typebox0.TOptional<_sinclair_typebox0.TString>;
33
+ message: _$_sinclair_typebox0.TOptional<_$_sinclair_typebox0.TString>;
34
34
  }>;
35
35
  /**
36
36
  * Delete response — `{ success, message }`
37
37
  */
38
- declare function ArcDeleteResponse(): _sinclair_typebox0.TObject<{
39
- success: _sinclair_typebox0.TBoolean;
40
- message: _sinclair_typebox0.TOptional<_sinclair_typebox0.TString>;
38
+ declare function ArcDeleteResponse(): _$_sinclair_typebox0.TObject<{
39
+ success: _$_sinclair_typebox0.TBoolean;
40
+ message: _$_sinclair_typebox0.TOptional<_$_sinclair_typebox0.TString>;
41
41
  }>;
42
42
  /**
43
43
  * Error response schema
44
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>;
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
50
  }>;
51
51
  /**
52
52
  * Standard pagination + sorting + filtering query parameters.
53
53
  * Matches Arc's list endpoint conventions.
54
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.TAny>;
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.TAny>;
61
61
  }>;
62
62
  //#endregion
63
63
  export { ArcDeleteResponse, ArcErrorResponse, ArcItemResponse, ArcListResponse, ArcMutationResponse, ArcPaginationQuery, type FastifyPluginAsyncTypebox, type FastifyPluginCallbackTypebox, type Static, type TObject, type TSchema, Type, type TypeBoxTypeProvider, TypeBoxValidatorCompiler };
@@ -1,6 +1,5 @@
1
- import { Type, Type as Type$1 } from "@sinclair/typebox";
2
1
  import { TypeBoxValidatorCompiler } from "@fastify/type-provider-typebox";
3
-
2
+ import { Type, Type as Type$1 } from "@sinclair/typebox";
4
3
  //#region src/schemas/index.ts
5
4
  /**
6
5
  * Paginated list response — matches Arc's runtime format:
@@ -77,6 +76,5 @@ function ArcPaginationQuery() {
77
76
  populate: Type$1.Optional(Type$1.Any())
78
77
  }, { additionalProperties: true });
79
78
  }
80
-
81
79
  //#endregion
82
- export { ArcDeleteResponse, ArcErrorResponse, ArcItemResponse, ArcListResponse, ArcMutationResponse, ArcPaginationQuery, Type, TypeBoxValidatorCompiler };
80
+ export { ArcDeleteResponse, ArcErrorResponse, ArcItemResponse, ArcListResponse, ArcMutationResponse, ArcPaginationQuery, Type, TypeBoxValidatorCompiler };
@@ -1,6 +1,17 @@
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-DGo5shaX.mjs";
1
+ import { a as AUTHENTICATED_SCOPE, c as getOrgId, d as getUserId, f as getUserRoles, g as isMember, h as isElevated, i as elevationPlugin, l as getOrgRoles, m as isAuthenticated, n as ElevationOptions, o as PUBLIC_SCOPE, p as hasOrgAccess, r as _default, s as RequestScope, t as ElevationEvent, u as getTeamId } from "../elevation-Ca_yveIO.mjs";
2
2
  import { FastifyReply, FastifyRequest } from "fastify";
3
3
 
4
+ //#region src/scope/rateLimitKey.d.ts
5
+ interface RateLimitKeyContext {
6
+ ip: string;
7
+ scope?: RequestScope;
8
+ }
9
+ interface TenantKeyGeneratorOptions {
10
+ /** Custom strategy — overrides default scope-based logic */
11
+ strategy?: (ctx: RateLimitKeyContext) => string;
12
+ }
13
+ declare function createTenantKeyGenerator(opts?: TenantKeyGeneratorOptions): (ctx: RateLimitKeyContext) => string;
14
+ //#endregion
4
15
  //#region src/scope/resolveOrgFromHeader.d.ts
5
16
  interface ResolveOrgFromHeaderOptions {
6
17
  /** Header name (default: 'x-organization-id') */
@@ -18,4 +29,4 @@ interface ResolveOrgFromHeaderOptions {
18
29
  */
19
30
  declare function resolveOrgFromHeader(options: ResolveOrgFromHeaderOptions): (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
20
31
  //#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 };
32
+ export { AUTHENTICATED_SCOPE, type ElevationEvent, type ElevationOptions, PUBLIC_SCOPE, type RateLimitKeyContext, type RequestScope, type ResolveOrgFromHeaderOptions, type TenantKeyGeneratorOptions, createTenantKeyGenerator, _default as elevationPlugin, elevationPlugin as elevationPluginFn, getOrgId, getOrgRoles, getTeamId, getUserId, getUserRoles, hasOrgAccess, isAuthenticated, isElevated, isMember, resolveOrgFromHeader };
@@ -1,6 +1,18 @@
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-DSTbVvYj.mjs";
3
-
1
+ import { a as getTeamId, c as hasOrgAccess, d as isMember, i as getOrgRoles, l as isAuthenticated, n as PUBLIC_SCOPE, o as getUserId, r as getOrgId, s as getUserRoles, t as AUTHENTICATED_SCOPE, u as isElevated } from "../types-C6TQjtdi.mjs";
2
+ import { n as normalizeRoles } from "../types-ZUu_h0jp.mjs";
3
+ import { n as elevation_default, t as elevationPlugin } from "../elevation-BEdACOLB.mjs";
4
+ //#region src/scope/rateLimitKey.ts
5
+ function createTenantKeyGenerator(opts) {
6
+ if (opts?.strategy) return opts.strategy;
7
+ return (ctx) => {
8
+ const scope = ctx.scope;
9
+ if (!scope || scope.kind === "public") return ctx.ip;
10
+ if (scope.kind === "member") return scope.organizationId;
11
+ if (scope.kind === "elevated") return scope.organizationId ?? scope.userId ?? ctx.ip;
12
+ return scope.userId ?? ctx.ip;
13
+ };
14
+ }
15
+ //#endregion
4
16
  //#region src/scope/resolveOrgFromHeader.ts
5
17
  /**
6
18
  * Create a preHandler hook that resolves org scope from a header.
@@ -55,11 +67,12 @@ function resolveOrgFromHeader(options) {
55
67
  }
56
68
  request.scope = {
57
69
  kind: "member",
70
+ userId: userId || void 0,
71
+ userRoles: normalizeRoles(user.role),
58
72
  organizationId: orgId,
59
73
  orgRoles: membership.roles
60
74
  };
61
75
  };
62
76
  }
63
-
64
77
  //#endregion
65
- export { AUTHENTICATED_SCOPE, PUBLIC_SCOPE, elevation_default as elevationPlugin, elevationPlugin as elevationPluginFn, getOrgId, getOrgRoles, getTeamId, hasOrgAccess, isAuthenticated, isElevated, isMember, resolveOrgFromHeader };
78
+ export { AUTHENTICATED_SCOPE, PUBLIC_SCOPE, createTenantKeyGenerator, elevation_default as elevationPlugin, elevationPlugin as elevationPluginFn, getOrgId, getOrgRoles, getTeamId, getUserId, getUserRoles, hasOrgAccess, isAuthenticated, isElevated, isMember, resolveOrgFromHeader };
@@ -41,7 +41,7 @@ interface SessionCookieOptions {
41
41
  /** Prevent client-side JavaScript access (default: true) */
42
42
  httpOnly?: boolean;
43
43
  /** SameSite attribute (default: 'lax') */
44
- sameSite?: 'strict' | 'lax' | 'none';
44
+ sameSite?: "strict" | "lax" | "none";
45
45
  /** Cookie path (default: '/') */
46
46
  path?: string;
47
47
  /** Cookie domain */
@@ -75,7 +75,7 @@ interface SessionManagerResult {
75
75
  /** PreHandler that rejects requests without a fresh session */
76
76
  requireFresh: (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
77
77
  }
78
- declare module 'fastify' {
78
+ declare module "fastify" {
79
79
  interface FastifyInstance {
80
80
  /** Authenticate middleware — validates session and sets request.user */
81
81
  authenticate: (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
@@ -1,28 +1,8 @@
1
- import { t as __exportAll } from "./chunk-C7Uep-_p.mjs";
2
- import { n as PUBLIC_SCOPE, r as getOrgId } from "./types-Beqn1Un7.mjs";
3
- import { t as arcLog } from "./logger-ByrvQWZO.mjs";
1
+ import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
2
+ import { n as PUBLIC_SCOPE, r as getOrgId } from "./types-C6TQjtdi.mjs";
3
+ import { t as arcLog } from "./logger-Dz3j1ItV.mjs";
4
4
  import fp from "fastify-plugin";
5
-
6
5
  //#region src/plugins/sse.ts
7
- /**
8
- * SSE Plugin (Server-Sent Events)
9
- *
10
- * Streams domain events to clients over HTTP using Server-Sent Events.
11
- * Requires the events plugin (`arc-events`) to be registered first.
12
- *
13
- * @example
14
- * import { ssePlugin } from '@classytic/arc/plugins';
15
- *
16
- * // Basic — stream all events at /events/stream
17
- * await fastify.register(ssePlugin);
18
- *
19
- * // Filtered + org-scoped
20
- * await fastify.register(ssePlugin, {
21
- * path: '/api/events',
22
- * patterns: ['order.*', 'product.*'],
23
- * orgScoped: true,
24
- * });
25
- */
26
6
  var sse_exports = /* @__PURE__ */ __exportAll({
27
7
  default: () => sse_default,
28
8
  ssePlugin: () => ssePlugin
@@ -118,6 +98,5 @@ var sse_default = fp(ssePlugin, {
118
98
  fastify: "5.x",
119
99
  dependencies: ["arc-events"]
120
100
  });
121
-
122
101
  //#endregion
123
- export { sse_default as n, sse_exports as r, ssePlugin as t };
102
+ export { sse_default as n, sse_exports as r, ssePlugin as t };