@classytic/arc 2.2.5 → 2.4.1

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 (174) 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-BKHSl2nT.mjs → createApp-ByWNRsZj.mjs} +65 -36
  39. package/dist/{defineResource-DO9ONe_D.mjs → defineResource-D9aY5Cy6.mjs} +154 -1165
  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-CyAA2zlB.d.mts → index-BL8CaQih.d.mts} +56 -57
  71. package/dist/index-Diqcm14c.d.mts +369 -0
  72. package/dist/{prisma-xjhMEq_S.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.mjs +3 -7
  99. package/dist/{mongodb-DNKEExbf.mjs → mongodb-BuQ7fNTg.mjs} +1 -4
  100. package/dist/{mongodb-ClykrfGo.d.mts → mongodb-CUpYfxfD.d.mts} +2 -3
  101. package/dist/{mongodb-Dg8O_gvd.d.mts → mongodb-bga9AbkD.d.mts} +2 -2
  102. package/dist/{openapi-9nB_kiuR.mjs → openapi-CBmZ6EQN.mjs} +4 -21
  103. package/dist/org/index.d.mts +12 -14
  104. package/dist/org/index.mjs +92 -119
  105. package/dist/org/types.d.mts +2 -2
  106. package/dist/org/types.mjs +1 -1
  107. package/dist/permissions/index.d.mts +4 -278
  108. package/dist/permissions/index.mjs +4 -579
  109. package/dist/permissions-CA5zg0yK.mjs +751 -0
  110. package/dist/plugins/index.d.mts +104 -107
  111. package/dist/plugins/index.mjs +203 -313
  112. package/dist/plugins/response-cache.mjs +4 -69
  113. package/dist/plugins/tracing-entry.d.mts +1 -1
  114. package/dist/plugins/tracing-entry.mjs +24 -11
  115. package/dist/{pluralize-CM-jZg7p.mjs → pluralize-CcT6qF0a.mjs} +12 -13
  116. package/dist/policies/index.d.mts +2 -2
  117. package/dist/policies/index.mjs +80 -83
  118. package/dist/presets/index.d.mts +26 -19
  119. package/dist/presets/index.mjs +2 -142
  120. package/dist/presets/multiTenant.d.mts +1 -4
  121. package/dist/presets/multiTenant.mjs +4 -6
  122. package/dist/presets-C9QXJV1u.mjs +422 -0
  123. package/dist/{queryCachePlugin-B6R0d4av.mjs → queryCachePlugin-ClosZdNS.mjs} +6 -27
  124. package/dist/{queryCachePlugin-Q6SYuHZ6.d.mts → queryCachePlugin-DcmETvcB.d.mts} +3 -3
  125. package/dist/queryParser-CgCtsjti.mjs +352 -0
  126. package/dist/{redis-UwjEp8Ea.d.mts → redis-CQ5YxMC5.d.mts} +2 -2
  127. package/dist/{redis-stream-CBg0upHI.d.mts → redis-stream-BW9UKLZM.d.mts} +9 -2
  128. package/dist/registry/index.d.mts +1 -4
  129. package/dist/registry/index.mjs +3 -4
  130. package/dist/{introspectionPlugin-B3JkrjwU.mjs → registry-I-ogLgL9.mjs} +1 -8
  131. package/dist/{requestContext-xi6OKBL-.mjs → requestContext-DYtmNpm5.mjs} +1 -3
  132. package/dist/resourceToTools-B6ZN9Ing.mjs +489 -0
  133. package/dist/rpc/index.d.mts +90 -0
  134. package/dist/rpc/index.mjs +248 -0
  135. package/dist/{schemaConverter-Dtg0Kt9T.mjs → schemaConverter-DjzHpFam.mjs} +1 -2
  136. package/dist/schemas/index.d.mts +30 -30
  137. package/dist/schemas/index.mjs +4 -6
  138. package/dist/scope/index.d.mts +13 -2
  139. package/dist/scope/index.mjs +18 -5
  140. package/dist/{sessionManager-D_iEHjQl.d.mts → sessionManager-wbkYj2HL.d.mts} +2 -2
  141. package/dist/{sse-DkqQ1uxb.mjs → sse-BkViJPlT.mjs} +4 -25
  142. package/dist/testing/index.d.mts +551 -567
  143. package/dist/testing/index.mjs +1744 -1799
  144. package/dist/{tracing-8CEbhF0w.d.mts → tracing-bz_U4EM1.d.mts} +6 -1
  145. package/dist/{typeGuards-DwxA1t_L.mjs → typeGuards-Cj5Rgvlg.mjs} +1 -2
  146. package/dist/types/index.d.mts +4 -946
  147. package/dist/types/index.mjs +2 -4
  148. package/dist/types-BJmgxNbF.d.mts +275 -0
  149. package/dist/{types-RLkFVgaw.d.mts → types-BNUccdcf.d.mts} +2 -2
  150. package/dist/{types-Beqn1Un7.mjs → types-C6TQjtdi.mjs} +30 -2
  151. package/dist/{types-DMSBMkaZ.d.mts → types-Dt0-AI6E.d.mts} +85 -27
  152. package/dist/{types-DelU6kln.mjs → types-ZUu_h0jp.mjs} +1 -2
  153. package/dist/utils/index.d.mts +255 -352
  154. package/dist/utils/index.mjs +7 -6
  155. package/dist/utils-Dc0WhlIl.mjs +594 -0
  156. package/dist/versioning-BzfeHmhj.mjs +37 -0
  157. package/package.json +46 -12
  158. package/skills/arc/SKILL.md +506 -0
  159. package/skills/arc/references/auth.md +250 -0
  160. package/skills/arc/references/events.md +272 -0
  161. package/skills/arc/references/integrations.md +385 -0
  162. package/skills/arc/references/mcp.md +386 -0
  163. package/skills/arc/references/production.md +610 -0
  164. package/skills/arc/references/testing.md +183 -0
  165. package/dist/audited-CGdLiSlE.mjs +0 -140
  166. package/dist/chunk-C7Uep-_p.mjs +0 -20
  167. package/dist/circuitBreaker-DYhWBW_D.mjs +0 -1096
  168. package/dist/errorHandler-CW3OOeYq.d.mts +0 -72
  169. package/dist/interface-DZYNK9bb.d.mts +0 -1112
  170. package/dist/presets-BTeYbw7h.d.mts +0 -57
  171. package/dist/presets-CeFtfDR8.mjs +0 -119
  172. /package/dist/{errors-DAWRdiYP.d.mts → errors-CPpvPHT0.d.mts} +0 -0
  173. /package/dist/{externalPaths-SyPF2tgK.d.mts → externalPaths-DpO-s7r8.d.mts} +0 -0
  174. /package/dist/{interface-DTbsvIWe.d.mts → interface-D_BWALyZ.d.mts} +0 -0
@@ -29,14 +29,13 @@ function hashParams(params) {
29
29
  function stableStringify(value) {
30
30
  if (value === null || value === void 0) return "";
31
31
  if (typeof value !== "object") return String(value);
32
- if (Array.isArray(value)) return "[" + value.map(stableStringify).join(",") + "]";
33
- return "{" + Object.keys(value).sort().map((k) => k + ":" + stableStringify(value[k])).join(",") + "}";
32
+ if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
33
+ return "{" + Object.keys(value).sort().map((k) => `${k}:${stableStringify(value[k])}`).join(",") + "}";
34
34
  }
35
35
  function djb2(str) {
36
36
  let hash = 5381;
37
37
  for (let i = 0; i < str.length; i++) hash = (hash << 5) + hash + str.charCodeAt(i) >>> 0;
38
38
  return hash;
39
39
  }
40
-
41
40
  //#endregion
42
- export { versionKey as i, hashParams as n, tagVersionKey as r, buildQueryKey as t };
41
+ export { versionKey as i, hashParams as n, tagVersionKey as r, buildQueryKey as t };
@@ -1,5 +1,4 @@
1
- import { t as __exportAll } from "./chunk-C7Uep-_p.mjs";
2
-
1
+ import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
3
2
  //#region src/logger/index.ts
4
3
  var logger_exports = /* @__PURE__ */ __exportAll({
5
4
  arcLog: () => arcLog,
@@ -73,6 +72,5 @@ function isSuppressed() {
73
72
  const env = typeof process !== "undefined" ? process.env?.ARC_SUPPRESS_WARNINGS : void 0;
74
73
  return env === "1" || env === "true";
75
74
  }
76
-
77
75
  //#endregion
78
- export { configureArcLogger as n, logger_exports as r, arcLog as t };
76
+ export { configureArcLogger as n, logger_exports as r, arcLog as t };
@@ -1,5 +1,4 @@
1
- import { t as __exportAll } from "./chunk-C7Uep-_p.mjs";
2
-
1
+ import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
3
2
  //#region src/cache/memory.ts
4
3
  var memory_exports = /* @__PURE__ */ __exportAll({
5
4
  MemoryCacheStore: () => MemoryCacheStore,
@@ -138,6 +137,5 @@ var MemoryCacheStore = class {
138
137
  function clamp(value, min, max) {
139
138
  return Math.min(max, Math.max(min, value));
140
139
  }
141
-
142
140
  //#endregion
143
- export { memory_exports as n, MemoryCacheStore as t };
141
+ export { memory_exports as n, MemoryCacheStore as t };
@@ -0,0 +1,224 @@
1
+ import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
2
+ import fp from "fastify-plugin";
3
+ //#region src/plugins/metrics.ts
4
+ var metrics_exports = /* @__PURE__ */ __exportAll({
5
+ default: () => metrics_default,
6
+ metricsPlugin: () => metricsPlugin
7
+ });
8
+ var Counter = class {
9
+ data = /* @__PURE__ */ new Map();
10
+ inc(labels, value = 1) {
11
+ const key = labelKey(labels);
12
+ const existing = this.data.get(key);
13
+ if (existing) existing.value += value;
14
+ else this.data.set(key, {
15
+ labels: { ...labels },
16
+ value
17
+ });
18
+ }
19
+ values() {
20
+ return [...this.data.values()];
21
+ }
22
+ reset() {
23
+ this.data.clear();
24
+ }
25
+ };
26
+ var Histogram = class {
27
+ data = /* @__PURE__ */ new Map();
28
+ observe(labels, value) {
29
+ const key = labelKey(labels);
30
+ const existing = this.data.get(key);
31
+ if (existing) {
32
+ existing.sum += value;
33
+ existing.count += 1;
34
+ } else this.data.set(key, {
35
+ labels: { ...labels },
36
+ sum: value,
37
+ count: 1
38
+ });
39
+ }
40
+ values() {
41
+ return [...this.data.values()].flatMap(({ labels, sum, count }) => [{
42
+ labels: {
43
+ ...labels,
44
+ le: "sum"
45
+ },
46
+ value: sum
47
+ }, {
48
+ labels: {
49
+ ...labels,
50
+ le: "count"
51
+ },
52
+ value: count
53
+ }]);
54
+ }
55
+ reset() {
56
+ this.data.clear();
57
+ }
58
+ };
59
+ var Gauge = class {
60
+ data = /* @__PURE__ */ new Map();
61
+ set(labels, value) {
62
+ const key = labelKey(labels);
63
+ this.data.set(key, {
64
+ labels: { ...labels },
65
+ value
66
+ });
67
+ }
68
+ values() {
69
+ return [...this.data.values()];
70
+ }
71
+ reset() {
72
+ this.data.clear();
73
+ }
74
+ };
75
+ function labelKey(labels) {
76
+ return Object.entries(labels).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${k}=${v}`).join(",");
77
+ }
78
+ function toPrometheusText(metrics) {
79
+ const lines = [];
80
+ for (const m of metrics) {
81
+ lines.push(`# HELP ${m.name} ${m.help}`);
82
+ lines.push(`# TYPE ${m.name} ${m.type}`);
83
+ for (const v of m.values) {
84
+ const labelStr = Object.entries(v.labels).map(([k, val]) => `${k}="${val}"`).join(",");
85
+ lines.push(`${m.name}{${labelStr}} ${v.value}`);
86
+ }
87
+ }
88
+ return `${lines.join("\n")}\n`;
89
+ }
90
+ const metricsPlugin = async (fastify, opts = {}) => {
91
+ const path = opts.path ?? "/_metrics";
92
+ const prefix = opts.prefix ?? "arc";
93
+ const httpRequestsTotal = new Counter();
94
+ const crudOpsTotal = new Counter();
95
+ const cacheHitsTotal = new Counter();
96
+ const cacheMissesTotal = new Counter();
97
+ const eventsPublishedTotal = new Counter();
98
+ const eventsConsumedTotal = new Counter();
99
+ const httpDuration = new Histogram();
100
+ const crudDuration = new Histogram();
101
+ const circuitBreakerState = new Gauge();
102
+ const collector = {
103
+ collect() {
104
+ const metrics = [
105
+ {
106
+ name: `${prefix}_http_requests_total`,
107
+ type: "counter",
108
+ help: "Total HTTP requests",
109
+ values: httpRequestsTotal.values()
110
+ },
111
+ {
112
+ name: `${prefix}_http_request_duration_seconds`,
113
+ type: "histogram",
114
+ help: "HTTP request duration in seconds",
115
+ values: httpDuration.values()
116
+ },
117
+ {
118
+ name: `${prefix}_crud_operations_total`,
119
+ type: "counter",
120
+ help: "Total CRUD operations by resource",
121
+ values: crudOpsTotal.values()
122
+ },
123
+ {
124
+ name: `${prefix}_crud_operation_duration_seconds`,
125
+ type: "histogram",
126
+ help: "CRUD operation duration in seconds",
127
+ values: crudDuration.values()
128
+ },
129
+ {
130
+ name: `${prefix}_cache_hits_total`,
131
+ type: "counter",
132
+ help: "Total cache hits by resource",
133
+ values: cacheHitsTotal.values()
134
+ },
135
+ {
136
+ name: `${prefix}_cache_misses_total`,
137
+ type: "counter",
138
+ help: "Total cache misses by resource",
139
+ values: cacheMissesTotal.values()
140
+ },
141
+ {
142
+ name: `${prefix}_events_published_total`,
143
+ type: "counter",
144
+ help: "Total events published",
145
+ values: eventsPublishedTotal.values()
146
+ },
147
+ {
148
+ name: `${prefix}_events_consumed_total`,
149
+ type: "counter",
150
+ help: "Total events consumed",
151
+ values: eventsConsumedTotal.values()
152
+ },
153
+ {
154
+ name: `${prefix}_circuit_breaker_state`,
155
+ type: "gauge",
156
+ help: "Circuit breaker state (0=closed, 1=open, 2=half-open)",
157
+ values: circuitBreakerState.values()
158
+ }
159
+ ];
160
+ opts.onCollect?.(metrics);
161
+ return metrics;
162
+ },
163
+ reset() {
164
+ httpRequestsTotal.reset();
165
+ httpDuration.reset();
166
+ crudOpsTotal.reset();
167
+ crudDuration.reset();
168
+ cacheHitsTotal.reset();
169
+ cacheMissesTotal.reset();
170
+ eventsPublishedTotal.reset();
171
+ eventsConsumedTotal.reset();
172
+ circuitBreakerState.reset();
173
+ },
174
+ recordOperation(resource, operation, status, durationMs) {
175
+ crudOpsTotal.inc({
176
+ resource,
177
+ operation,
178
+ status: String(status)
179
+ });
180
+ crudDuration.observe({
181
+ resource,
182
+ operation
183
+ }, durationMs / 1e3);
184
+ },
185
+ recordCacheHit(resource) {
186
+ cacheHitsTotal.inc({ resource });
187
+ },
188
+ recordCacheMiss(resource) {
189
+ cacheMissesTotal.inc({ resource });
190
+ },
191
+ recordEventPublish(eventType) {
192
+ eventsPublishedTotal.inc({ event_type: eventType });
193
+ },
194
+ recordEventConsume(eventType) {
195
+ eventsConsumedTotal.inc({ event_type: eventType });
196
+ },
197
+ recordCircuitBreakerState(service, state) {
198
+ const stateValue = state === "open" ? 1 : state === "half-open" ? 2 : 0;
199
+ circuitBreakerState.set({ service }, stateValue);
200
+ }
201
+ };
202
+ fastify.decorate("metrics", collector);
203
+ fastify.addHook("onResponse", async (request, reply) => {
204
+ if (request.url === path) return;
205
+ const duration = reply.elapsedTime / 1e3;
206
+ const labels = {
207
+ method: request.method,
208
+ route: request.routeOptions?.url ?? request.url,
209
+ status: String(reply.statusCode)
210
+ };
211
+ httpRequestsTotal.inc(labels);
212
+ httpDuration.observe(labels, duration);
213
+ });
214
+ fastify.get(path, async (_request, reply) => {
215
+ const text = toPrometheusText(collector.collect());
216
+ return reply.type("text/plain; charset=utf-8").send(text);
217
+ });
218
+ };
219
+ var metrics_default = fp(metricsPlugin, {
220
+ name: "arc-metrics",
221
+ fastify: "5.x"
222
+ });
223
+ //#endregion
224
+ export { metrics_default as n, metrics_exports as r, metricsPlugin as t };
@@ -1,5 +1,3 @@
1
- import mongoose from "mongoose";
2
-
3
1
  //#region src/migrations/index.ts
4
2
  /**
5
3
  * Define a migration
@@ -95,8 +93,7 @@ var MigrationRunner = class {
95
93
  */
96
94
  async runMigration(migration, direction, isRollback = false) {
97
95
  const start = Date.now();
98
- const action = direction === "up" ? "Applying" : "Rolling back";
99
- console.log(`${action} ${migration.resource} v${migration.version}${migration.description ? `: ${migration.description}` : ""}...`);
96
+ console.log(`${direction === "up" ? "Applying" : "Rolling back"} ${migration.resource} v${migration.version}${migration.description ? `: ${migration.description}` : ""}...`);
100
97
  try {
101
98
  if (direction === "up") {
102
99
  await migration.up(this.db);
@@ -238,7 +235,7 @@ const migrationHelpers = {
238
235
  up: async (db) => {
239
236
  await db.collection(collection).updateMany({}, { $unset: { [fieldName]: "" } });
240
237
  },
241
- down: async (db) => {
238
+ down: async (_db) => {
242
239
  console.warn(`Cannot restore ${fieldName} field - data was deleted`);
243
240
  }
244
241
  }),
@@ -255,6 +252,5 @@ const migrationHelpers = {
255
252
  }
256
253
  })
257
254
  };
258
-
259
255
  //#endregion
260
- export { MigrationRegistry, MigrationRunner, defineMigration, migrationHelpers, migrationRegistry, withSchemaVersion };
256
+ export { MigrationRegistry, MigrationRunner, defineMigration, migrationHelpers, migrationRegistry, withSchemaVersion };
@@ -4,9 +4,7 @@ var MongoAuditStore = class {
4
4
  collection;
5
5
  initialized = false;
6
6
  ttlDays;
7
- options;
8
7
  constructor(options) {
9
- this.options = options;
10
8
  const collectionName = options.collection ?? "audit_logs";
11
9
  this.collection = options.connection.collection(collectionName);
12
10
  this.ttlDays = options.ttlDays ?? 90;
@@ -88,6 +86,5 @@ var MongoAuditStore = class {
88
86
  }));
89
87
  }
90
88
  };
91
-
92
89
  //#endregion
93
- export { MongoAuditStore as t };
90
+ export { MongoAuditStore as t };
@@ -1,7 +1,7 @@
1
- import { i as UserBase } from "./types-RLkFVgaw.mjs";
1
+ import { i as UserBase } from "./types-BNUccdcf.mjs";
2
2
 
3
3
  //#region src/audit/stores/interface.d.ts
4
- type AuditAction = 'create' | 'update' | 'delete' | 'restore' | 'custom';
4
+ type AuditAction = "create" | "update" | "delete" | "restore" | "custom";
5
5
  interface AuditEntry {
6
6
  /** Unique audit log ID */
7
7
  id: string;
@@ -108,7 +108,6 @@ declare class MongoAuditStore implements AuditStore {
108
108
  private collection;
109
109
  private initialized;
110
110
  private ttlDays;
111
- private options;
112
111
  constructor(options: MongoAuditStoreOptions);
113
112
  private ensureIndexes;
114
113
  log(entry: AuditEntry): Promise<void>;
@@ -1,4 +1,4 @@
1
- import { n as IdempotencyResult, r as IdempotencyStore } from "./interface-CSNjltAc.mjs";
1
+ import { n as IdempotencyResult, r as IdempotencyStore } from "./interface-B4awm1RJ.mjs";
2
2
 
3
3
  //#region src/idempotency/stores/mongodb.d.ts
4
4
  interface MongoConnection {
@@ -58,7 +58,7 @@ declare class MongoIdempotencyStore implements IdempotencyStore {
58
58
  private get collection();
59
59
  private ensureIndex;
60
60
  get(key: string): Promise<IdempotencyResult | undefined>;
61
- set(key: string, result: Omit<IdempotencyResult, 'key'>): Promise<void>;
61
+ set(key: string, result: Omit<IdempotencyResult, "key">): Promise<void>;
62
62
  tryLock(key: string, requestId: string, ttlMs: number): Promise<boolean>;
63
63
  unlock(key: string, requestId: string): Promise<void>;
64
64
  isLocked(key: string): Promise<boolean>;
@@ -1,23 +1,7 @@
1
- import { t as getUserRoles } from "./types-DelU6kln.mjs";
2
- import { n as convertRouteSchema } from "./schemaConverter-Dtg0Kt9T.mjs";
1
+ import { t as getUserRoles } from "./types-ZUu_h0jp.mjs";
2
+ import { n as convertRouteSchema } from "./schemaConverter-DjzHpFam.mjs";
3
3
  import fp from "fastify-plugin";
4
-
5
4
  //#region src/docs/openapi.ts
6
- /**
7
- * OpenAPI Spec Generator
8
- *
9
- * Auto-generates OpenAPI 3.0 specification from Arc resource registry.
10
- *
11
- * @example
12
- * import { openApiPlugin } from '@classytic/arc/docs';
13
- *
14
- * await fastify.register(openApiPlugin, {
15
- * title: 'My API',
16
- * version: '1.0.0',
17
- * });
18
- *
19
- * // Spec available at /_docs/openapi.json
20
- */
21
5
  const openApiPlugin = async (fastify, opts = {}) => {
22
6
  const { title = "Arc API", version = "1.0.0", description, serverUrl, prefix = "/_docs", apiPrefix = "", authRoles = [] } = opts;
23
7
  const buildSpec = () => {
@@ -481,7 +465,7 @@ function generateSchemas(resources) {
481
465
  if (fieldPerms && schemas[resource.name]?.properties) {
482
466
  const props = schemas[resource.name].properties;
483
467
  for (const [field, perm] of Object.entries(fieldPerms)) if (props[field]) {
484
- const desc = props[field].description ?? "";
468
+ const desc = props[field]?.description ?? "";
485
469
  const permDesc = formatFieldPermDescription(perm);
486
470
  props[field].description = desc ? `${desc} (${permDesc})` : permDesc;
487
471
  } else if (perm.type === "hidden") {}
@@ -520,6 +504,5 @@ var openapi_default = fp(openApiPlugin, {
520
504
  name: "arc-openapi",
521
505
  fastify: "5.x"
522
506
  });
523
-
524
507
  //#endregion
525
- export { openApiPlugin as n, openapi_default as r, buildOpenApiSpec as t };
508
+ export { openApiPlugin as n, openapi_default as r, buildOpenApiSpec as t };
@@ -1,10 +1,18 @@
1
- import "../elevation-DGo5shaX.mjs";
2
- import { S as RouteHandler } from "../interface-DZYNK9bb.mjs";
3
- import { i as UserBase } from "../types-RLkFVgaw.mjs";
4
- import "../types/index.mjs";
1
+ import { Pt as RouteHandler } from "../interface-DGmPxakH.mjs";
2
+ import { i as UserBase } from "../types-BNUccdcf.mjs";
5
3
  import { InvitationAdapter, InvitationDoc, MemberDoc, OrgAdapter, OrgDoc, OrgPermissionStatement, OrgRole, OrganizationPluginOptions } from "./types.mjs";
6
4
  import { FastifyPluginAsync, RouteHandlerMethod } from "fastify";
7
5
 
6
+ //#region src/org/organizationPlugin.d.ts
7
+ declare module "fastify" {
8
+ interface FastifyInstance {
9
+ /** Middleware: require the caller to hold one of the listed org roles */
10
+ requireOrgRole: (roles: string[]) => RouteHandlerMethod;
11
+ }
12
+ }
13
+ declare const organizationPlugin: FastifyPluginAsync<OrganizationPluginOptions>;
14
+ declare const _default: FastifyPluginAsync<OrganizationPluginOptions>;
15
+ //#endregion
8
16
  //#region src/org/orgGuard.d.ts
9
17
  interface OrgGuardOptions {
10
18
  /** Require organization context (default: true) */
@@ -55,14 +63,4 @@ declare function getUserOrgRoles(user: UserBase | undefined | null, orgId: strin
55
63
  */
56
64
  declare function hasOrgRole(user: UserBase | undefined | null, orgId: string | undefined | null, roles: string | string[], options?: OrgRolesOptions): boolean;
57
65
  //#endregion
58
- //#region src/org/organizationPlugin.d.ts
59
- declare module 'fastify' {
60
- interface FastifyInstance {
61
- /** Middleware: require the caller to hold one of the listed org roles */
62
- requireOrgRole: (roles: string[]) => RouteHandlerMethod;
63
- }
64
- }
65
- declare const organizationPlugin: FastifyPluginAsync<OrganizationPluginOptions>;
66
- declare const _default: FastifyPluginAsync<OrganizationPluginOptions>;
67
- //#endregion
68
66
  export { type InvitationAdapter, type InvitationDoc, type MemberDoc, type OrgAdapter, type OrgDoc, type OrgGuardOptions, type OrgMembershipOptions, type OrgPermissionStatement, type OrgRole, type OrgRolesOptions, type OrganizationPluginOptions, getUserOrgRoles, hasOrgRole, orgGuard, orgMembershipCheck, _default as organizationPlugin, organizationPlugin as organizationPluginFn, requireOrg, requireOrgRole };
@@ -1,122 +1,6 @@
1
- import { c as isElevated, i as getOrgRoles, l as isMember, n as PUBLIC_SCOPE, o as hasOrgAccess } from "../types-Beqn1Un7.mjs";
1
+ import { c as hasOrgAccess, d as isMember, i as getOrgRoles, n as PUBLIC_SCOPE, u as isElevated } from "../types-C6TQjtdi.mjs";
2
2
  import fp from "fastify-plugin";
3
-
4
- //#region src/org/orgGuard.ts
5
- /**
6
- * Create org guard middleware.
7
- * Reads `request.scope` for org context and roles.
8
- * Elevated scope always passes.
9
- */
10
- function orgGuard(options = {}) {
11
- const { requireOrgContext = true, roles = [] } = options;
12
- return async function orgGuardMiddleware(request, reply) {
13
- const scope = request.scope ?? PUBLIC_SCOPE;
14
- if (isElevated(scope)) return;
15
- if (requireOrgContext && !hasOrgAccess(scope)) {
16
- reply.code(403).send({
17
- success: false,
18
- error: "Organization context required",
19
- code: "ORG_CONTEXT_REQUIRED",
20
- message: "This endpoint requires an organization context. Please specify organization via x-organization-id header."
21
- });
22
- return;
23
- }
24
- if (roles.length > 0 && isMember(scope)) {
25
- const userOrgRoles = getOrgRoles(scope);
26
- if (!roles.some((role) => userOrgRoles.includes(role))) {
27
- reply.code(403).send({
28
- success: false,
29
- error: "Insufficient organization permissions",
30
- code: "ORG_ROLE_REQUIRED",
31
- message: `This action requires one of these organization roles: ${roles.join(", ")}`,
32
- required: roles,
33
- current: userOrgRoles
34
- });
35
- return;
36
- }
37
- }
38
- };
39
- }
40
- /**
41
- * Shorthand for requiring org context
42
- */
43
- function requireOrg() {
44
- return orgGuard({ requireOrgContext: true });
45
- }
46
- /**
47
- * Require org context with specific roles
48
- */
49
- function requireOrgRole(...roles) {
50
- return orgGuard({
51
- requireOrgContext: true,
52
- roles
53
- });
54
- }
55
-
56
- //#endregion
57
- //#region src/org/orgMembership.ts
58
- /**
59
- * Check if user is member of organization.
60
- * This is a low-level utility for checking membership from user object data.
61
- * For request-level checks, use `request.scope` (isMember/isElevated guards).
62
- */
63
- async function orgMembershipCheck(user, orgId, options = {}) {
64
- const { userOrgsPath = "organizations", validateFromDb } = options;
65
- if (!user || !orgId) return false;
66
- if ((user[userOrgsPath] ?? []).some((o) => {
67
- return (o.organizationId?.toString() ?? String(o)) === orgId.toString();
68
- })) return true;
69
- if (validateFromDb) {
70
- const userId = (user._id ?? user.id)?.toString();
71
- if (userId) return validateFromDb(userId, orgId);
72
- }
73
- return false;
74
- }
75
- /**
76
- * Get user's role in organization from user object data.
77
- * For request-level role checks, use `request.scope.orgRoles` (when scope is 'member').
78
- */
79
- function getUserOrgRoles(user, orgId, options = {}) {
80
- const { userOrgsPath = "organizations" } = options;
81
- if (!user || !orgId) return [];
82
- return (user[userOrgsPath] ?? []).find((o) => {
83
- return (o.organizationId?.toString() ?? String(o)) === orgId.toString();
84
- })?.roles ?? [];
85
- }
86
- /**
87
- * Check if user has specific role in organization from user object data.
88
- * For request-level role checks, use `requireOrgRole()` permission or `request.scope`.
89
- */
90
- function hasOrgRole(user, orgId, roles, options = {}) {
91
- const userOrgRoles = getUserOrgRoles(user, orgId, options);
92
- return (Array.isArray(roles) ? roles : [roles]).some((role) => userOrgRoles.includes(role));
93
- }
94
-
95
- //#endregion
96
3
  //#region src/org/organizationPlugin.ts
97
- /**
98
- * Organization Plugin -- Full org management with REST endpoints
99
- *
100
- * Creates these routes:
101
- * - POST /api/organizations -- Create org
102
- * - GET /api/organizations -- List user's orgs
103
- * - GET /api/organizations/:orgId -- Get org
104
- * - PATCH /api/organizations/:orgId -- Update org
105
- * - DELETE /api/organizations/:orgId -- Delete org
106
- * - GET /api/organizations/:orgId/members -- List members
107
- * - POST /api/organizations/:orgId/members -- Add member
108
- * - PATCH /api/organizations/:orgId/members/:userId -- Update role
109
- * - DELETE /api/organizations/:orgId/members/:userId -- Remove member
110
- *
111
- * @example
112
- * import { organizationPlugin } from '@classytic/arc/org';
113
- *
114
- * await fastify.register(organizationPlugin, {
115
- * adapter: myMongooseOrgAdapter,
116
- * basePath: '/api/organizations',
117
- * enableInvitations: false,
118
- * });
119
- */
120
4
  const DEFAULT_ROLES = [
121
5
  {
122
6
  name: "owner",
@@ -508,6 +392,95 @@ var organizationPlugin_default = fp(organizationPlugin, {
508
392
  name: "arc-organization",
509
393
  fastify: "5.x"
510
394
  });
511
-
512
395
  //#endregion
513
- export { getUserOrgRoles, hasOrgRole, orgGuard, orgMembershipCheck, organizationPlugin_default as organizationPlugin, organizationPlugin as organizationPluginFn, requireOrg, requireOrgRole };
396
+ //#region src/org/orgGuard.ts
397
+ /**
398
+ * Create org guard middleware.
399
+ * Reads `request.scope` for org context and roles.
400
+ * Elevated scope always passes.
401
+ */
402
+ function orgGuard(options = {}) {
403
+ const { requireOrgContext = true, roles = [] } = options;
404
+ return async function orgGuardMiddleware(request, reply) {
405
+ const scope = request.scope ?? PUBLIC_SCOPE;
406
+ if (isElevated(scope)) return;
407
+ if (requireOrgContext && !hasOrgAccess(scope)) {
408
+ reply.code(403).send({
409
+ success: false,
410
+ error: "Organization context required",
411
+ code: "ORG_CONTEXT_REQUIRED",
412
+ message: "This endpoint requires an organization context. Please specify organization via x-organization-id header."
413
+ });
414
+ return;
415
+ }
416
+ if (roles.length > 0 && isMember(scope)) {
417
+ const userOrgRoles = getOrgRoles(scope);
418
+ if (!roles.some((role) => userOrgRoles.includes(role))) {
419
+ reply.code(403).send({
420
+ success: false,
421
+ error: "Insufficient organization permissions",
422
+ code: "ORG_ROLE_REQUIRED",
423
+ message: `This action requires one of these organization roles: ${roles.join(", ")}`,
424
+ required: roles,
425
+ current: userOrgRoles
426
+ });
427
+ return;
428
+ }
429
+ }
430
+ };
431
+ }
432
+ /**
433
+ * Shorthand for requiring org context
434
+ */
435
+ function requireOrg() {
436
+ return orgGuard({ requireOrgContext: true });
437
+ }
438
+ /**
439
+ * Require org context with specific roles
440
+ */
441
+ function requireOrgRole(...roles) {
442
+ return orgGuard({
443
+ requireOrgContext: true,
444
+ roles
445
+ });
446
+ }
447
+ //#endregion
448
+ //#region src/org/orgMembership.ts
449
+ /**
450
+ * Check if user is member of organization.
451
+ * This is a low-level utility for checking membership from user object data.
452
+ * For request-level checks, use `request.scope` (isMember/isElevated guards).
453
+ */
454
+ async function orgMembershipCheck(user, orgId, options = {}) {
455
+ const { userOrgsPath = "organizations", validateFromDb } = options;
456
+ if (!user || !orgId) return false;
457
+ if ((user[userOrgsPath] ?? []).some((o) => {
458
+ return (o.organizationId?.toString() ?? String(o)) === orgId.toString();
459
+ })) return true;
460
+ if (validateFromDb) {
461
+ const userId = (user._id ?? user.id)?.toString();
462
+ if (userId) return validateFromDb(userId, orgId);
463
+ }
464
+ return false;
465
+ }
466
+ /**
467
+ * Get user's role in organization from user object data.
468
+ * For request-level role checks, use `request.scope.orgRoles` (when scope is 'member').
469
+ */
470
+ function getUserOrgRoles(user, orgId, options = {}) {
471
+ const { userOrgsPath = "organizations" } = options;
472
+ if (!user || !orgId) return [];
473
+ return (user[userOrgsPath] ?? []).find((o) => {
474
+ return (o.organizationId?.toString() ?? String(o)) === orgId.toString();
475
+ })?.roles ?? [];
476
+ }
477
+ /**
478
+ * Check if user has specific role in organization from user object data.
479
+ * For request-level role checks, use `requireOrgRole()` permission or `request.scope`.
480
+ */
481
+ function hasOrgRole(user, orgId, roles, options = {}) {
482
+ const userOrgRoles = getUserOrgRoles(user, orgId, options);
483
+ return (Array.isArray(roles) ? roles : [roles]).some((role) => userOrgRoles.includes(role));
484
+ }
485
+ //#endregion
486
+ export { getUserOrgRoles, hasOrgRole, orgGuard, orgMembershipCheck, organizationPlugin_default as organizationPlugin, organizationPlugin as organizationPluginFn, requireOrg, requireOrgRole };
@@ -28,7 +28,7 @@ interface InvitationDoc {
28
28
  email: string;
29
29
  role: string;
30
30
  invitedBy: string;
31
- status: 'pending' | 'accepted' | 'rejected' | 'expired';
31
+ status: "pending" | "accepted" | "rejected" | "expired";
32
32
  expiresAt: Date;
33
33
  createdAt?: Date;
34
34
  }
@@ -53,7 +53,7 @@ interface OrgAdapter {
53
53
  invitations?: InvitationAdapter;
54
54
  }
55
55
  interface InvitationAdapter {
56
- create(data: Omit<InvitationDoc, 'id' | 'createdAt'>): Promise<InvitationDoc>;
56
+ create(data: Omit<InvitationDoc, "id" | "createdAt">): Promise<InvitationDoc>;
57
57
  getByToken(token: string): Promise<InvitationDoc | null>;
58
58
  accept(id: string): Promise<void>;
59
59
  reject(id: string): Promise<void>;
@@ -1 +1 @@
1
- export { };
1
+ export {};