@classytic/arc 2.9.1 → 2.10.8

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 (132) hide show
  1. package/README.md +20 -91
  2. package/dist/{BaseController-Vu2yc56T.mjs → BaseController-DVNKvoX4.mjs} +154 -170
  3. package/dist/{ResourceRegistry-Dq3_zBQP.mjs → ResourceRegistry-CcN2LVrc.mjs} +1 -1
  4. package/dist/actionPermissions-TUVR3uiZ.mjs +22 -0
  5. package/dist/adapters/index.d.mts +3 -3
  6. package/dist/adapters/index.mjs +2 -2
  7. package/dist/{adapters-BBqAVvPK.mjs → adapters-BXY4i-hw.mjs} +210 -41
  8. package/dist/audit/index.d.mts +38 -3
  9. package/dist/audit/index.mjs +54 -22
  10. package/dist/auth/index.d.mts +2 -2
  11. package/dist/auth/index.mjs +3 -3
  12. package/dist/cache/index.d.mts +17 -15
  13. package/dist/cache/index.mjs +16 -15
  14. package/dist/{caching-CjybdRwx.mjs → caching-3h93rkJM.mjs} +8 -3
  15. package/dist/cli/commands/describe.mjs +1 -1
  16. package/dist/cli/commands/docs.mjs +2 -2
  17. package/dist/cli/commands/init.mjs +1 -1
  18. package/dist/cli/commands/introspect.mjs +1 -1
  19. package/dist/context/index.d.mts +58 -0
  20. package/dist/context/index.mjs +2 -0
  21. package/dist/core/index.d.mts +2 -2
  22. package/dist/core/index.mjs +3 -4
  23. package/dist/{defineResource-C__jkwvs.mjs → core-3MWJosCH.mjs} +174 -94
  24. package/dist/{createActionRouter-DH1YFL9m.mjs → createActionRouter-C8UUB3Px.mjs} +1 -1
  25. package/dist/{createApp-CBJUJKGP.mjs → createApp-BwnEAO2h.mjs} +53 -19
  26. package/dist/docs/index.d.mts +1 -1
  27. package/dist/docs/index.mjs +2 -2
  28. package/dist/{elevation-DxQ6ACbt.mjs → elevation-Dci0AYLT.mjs} +2 -2
  29. package/dist/errorHandler-2ii4RIYr.d.mts +114 -0
  30. package/dist/{errorHandler-CZDW4EXS.mjs → errorHandler-CSxe7KIM.mjs} +1 -1
  31. package/dist/{eventPlugin-Dl7MoVWH.mjs → eventPlugin-ByU4Cv0e.mjs} +1 -1
  32. package/dist/{eventPlugin-BxvaCIZF.d.mts → eventPlugin-D1ThQ1Pp.d.mts} +1 -1
  33. package/dist/events/index.d.mts +8 -5
  34. package/dist/events/index.mjs +87 -52
  35. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  36. package/dist/events/transports/redis.d.mts +1 -1
  37. package/dist/factory/index.d.mts +1 -1
  38. package/dist/factory/index.mjs +1 -1
  39. package/dist/{types-DZi1aYhm.d.mts → fields-C8Y0XLAu.d.mts} +122 -2
  40. package/dist/hooks/index.d.mts +1 -1
  41. package/dist/idempotency/index.d.mts +5 -2
  42. package/dist/idempotency/index.mjs +46 -37
  43. package/dist/{interface-YrWsmKqE.d.mts → index-BGbpGVyM.d.mts} +2107 -2756
  44. package/dist/{index-CtGKT0lf.d.mts → index-BziRPS4H.d.mts} +81 -7
  45. package/dist/{index-C-xjcA6F.d.mts → index-C_Noptz-.d.mts} +284 -409
  46. package/dist/{index-Cibkchnx.d.mts → index-EqQN6p0W.d.mts} +3 -3
  47. package/dist/index.d.mts +6 -219
  48. package/dist/index.mjs +10 -131
  49. package/dist/integrations/event-gateway.d.mts +1 -1
  50. package/dist/integrations/event-gateway.mjs +1 -1
  51. package/dist/integrations/index.d.mts +1 -1
  52. package/dist/integrations/mcp/index.d.mts +2 -2
  53. package/dist/integrations/mcp/index.mjs +1 -1
  54. package/dist/integrations/mcp/testing.d.mts +1 -1
  55. package/dist/integrations/mcp/testing.mjs +1 -1
  56. package/dist/interface-yhyb_pLY.d.mts +77 -0
  57. package/dist/logger/index.d.mts +81 -0
  58. package/dist/{logger-CDjpjySd.mjs → logger/index.mjs} +1 -6
  59. package/dist/{memory-BFAYkf8H.mjs → memory-DqI-449b.mjs} +23 -8
  60. package/dist/middleware/index.d.mts +109 -0
  61. package/dist/middleware/index.mjs +70 -0
  62. package/dist/multipartBody-CUQGVlM_.mjs +123 -0
  63. package/dist/{openapi-CXuTG1M9.mjs → openapi-DpNpqBmo.mjs} +9 -7
  64. package/dist/org/index.d.mts +2 -2
  65. package/dist/permissions/index.d.mts +3 -4
  66. package/dist/permissions/index.mjs +5 -5
  67. package/dist/{permissions-oNZawnkR.mjs → permissions-wkqRwicB.mjs} +315 -397
  68. package/dist/pipe-CGJxqDGx.mjs +62 -0
  69. package/dist/pipeline/index.d.mts +62 -0
  70. package/dist/pipeline/index.mjs +53 -0
  71. package/dist/plugins/index.d.mts +23 -3
  72. package/dist/plugins/index.mjs +9 -11
  73. package/dist/plugins/response-cache.mjs +1 -1
  74. package/dist/plugins/tracing-entry.mjs +1 -1
  75. package/dist/presets/filesUpload.d.mts +3 -3
  76. package/dist/presets/filesUpload.mjs +255 -1
  77. package/dist/presets/index.d.mts +1 -1
  78. package/dist/presets/index.mjs +2 -2
  79. package/dist/presets/multiTenant.d.mts +1 -1
  80. package/dist/presets/multiTenant.mjs +43 -9
  81. package/dist/presets/search.d.mts +91 -4
  82. package/dist/presets/search.mjs +1 -1
  83. package/dist/{presets-hM4WhNWY.mjs → presets-CrwOvuXI.mjs} +1 -1
  84. package/dist/{queryCachePlugin-DbUVroUG.mjs → queryCachePlugin-ChLNZvFT.mjs} +9 -9
  85. package/dist/{queryCachePlugin-CnTZZTC5.d.mts → queryCachePlugin-Dumka73q.d.mts} +1 -1
  86. package/dist/{queryParser-Cs-6SHQK.mjs → queryParser-NR__Qiju.mjs} +69 -2
  87. package/dist/{redis-stream-Bz-4q96t.d.mts → redis-stream-bkO88VHx.d.mts} +1 -1
  88. package/dist/registry/index.d.mts +1 -1
  89. package/dist/registry/index.mjs +1 -1
  90. package/dist/{requestContext-DYtmNpm5.mjs → requestContext-C38GskNt.mjs} +1 -1
  91. package/dist/{resourceToTools-C3cWymnW.mjs → resourceToTools-BhF3JV5p.mjs} +8 -3
  92. package/dist/scope/index.d.mts +2 -2
  93. package/dist/scope/index.mjs +2 -2
  94. package/dist/{sse-CJpt7LGI.mjs → sse-D8UeDwis.mjs} +1 -1
  95. package/dist/{store-helpers-DFiZl5TL.mjs → store-helpers-DYYUQbQN.mjs} +4 -0
  96. package/dist/testing/index.d.mts +6 -5
  97. package/dist/testing/index.mjs +17 -10
  98. package/dist/types/index.d.mts +5 -5
  99. package/dist/types/index.mjs +1 -31
  100. package/dist/types-CDnTEpga.mjs +27 -0
  101. package/dist/{types-CoSzA-s-.d.mts → types-CVKBssX5.d.mts} +1 -1
  102. package/dist/{types-CunEX4UX.d.mts → types-CVdgPXBW.d.mts} +20 -7
  103. package/dist/utils/index.d.mts +277 -3
  104. package/dist/utils/index.mjs +4 -5
  105. package/dist/{utils-B7FuRr9w.mjs → utils-LMwVidKy.mjs} +303 -2
  106. package/dist/{versioning-Cm8qoFDg.mjs → versioning-B6mimogM.mjs} +3 -5
  107. package/dist/versioning-CeUXHfjw.d.mts +117 -0
  108. package/package.json +31 -18
  109. package/skills/arc/SKILL.md +8 -12
  110. package/skills/arc/references/production.md +0 -41
  111. package/dist/circuitBreaker-CvXkjfrW.d.mts +0 -206
  112. package/dist/circuitBreaker-l18oRgL5.mjs +0 -284
  113. package/dist/core-DNncu0xF.mjs +0 -34
  114. package/dist/dynamic/index.d.mts +0 -93
  115. package/dist/dynamic/index.mjs +0 -122
  116. package/dist/errorHandler-DixGcttC.d.mts +0 -218
  117. package/dist/fields-BC7zcmI9.d.mts +0 -121
  118. package/dist/filesUpload-q8oHt--L.mjs +0 -377
  119. package/dist/interface-DplgQO2e.d.mts +0 -54
  120. package/dist/policies/index.d.mts +0 -425
  121. package/dist/policies/index.mjs +0 -318
  122. package/dist/rpc/index.d.mts +0 -90
  123. package/dist/rpc/index.mjs +0 -248
  124. /package/dist/{EventTransport-CqZ8FyM_.d.mts → EventTransport-CfVEGaEl.d.mts} +0 -0
  125. /package/dist/{applyPermissionResult-bqGpo9ML.mjs → applyPermissionResult-QhV1Pa-g.mjs} +0 -0
  126. /package/dist/{constants-Cxde4rpC.mjs → constants-BhY1OHoH.mjs} +0 -0
  127. /package/dist/{elevation-B6S5csVA.d.mts → elevation-s5ykdNHr.d.mts} +0 -0
  128. /package/dist/{errors-CqWnSqM-.mjs → errors-BqdUDja_.mjs} +0 -0
  129. /package/dist/{fields-CU6FlaDV.mjs → fields-CTMWOUDt.mjs} +0 -0
  130. /package/dist/{keys-qcD-TVJl.mjs → keys-nWQGUTu1.mjs} +0 -0
  131. /package/dist/{types-ZUu_h0jp.mjs → types-D57iXYb8.mjs} +0 -0
  132. /package/dist/{types-BD85MlEK.d.mts → types-tgR4Pt8F.d.mts} +0 -0
@@ -1,284 +0,0 @@
1
- //#region src/utils/circuitBreaker.ts
2
- /**
3
- * Circuit Breaker Pattern
4
- *
5
- * Wraps external service calls with failure protection.
6
- * Prevents cascading failures by "opening" the circuit when
7
- * a service is failing, allowing it time to recover.
8
- *
9
- * States:
10
- * - CLOSED: Normal operation, requests pass through
11
- * - OPEN: Too many failures, all requests fail fast
12
- * - HALF_OPEN: Testing if service recovered, limited requests
13
- *
14
- * @example
15
- * import { CircuitBreaker } from '@classytic/arc/utils';
16
- *
17
- * const paymentBreaker = new CircuitBreaker(async (amount) => {
18
- * return await stripe.charges.create({ amount });
19
- * }, {
20
- * failureThreshold: 5,
21
- * resetTimeout: 30000,
22
- * timeout: 5000,
23
- * });
24
- *
25
- * try {
26
- * const result = await paymentBreaker.call(100);
27
- * } catch (error) {
28
- * // Handle failure or circuit open
29
- * }
30
- */
31
- const CircuitState = {
32
- CLOSED: "CLOSED",
33
- OPEN: "OPEN",
34
- HALF_OPEN: "HALF_OPEN"
35
- };
36
- var CircuitBreakerError = class extends Error {
37
- state;
38
- constructor(message, state) {
39
- super(message);
40
- this.name = "CircuitBreakerError";
41
- this.state = state;
42
- }
43
- };
44
- var CircuitBreaker = class {
45
- state = CircuitState.CLOSED;
46
- failures = 0;
47
- successes = 0;
48
- totalCalls = 0;
49
- nextAttempt = 0;
50
- lastCallAt = null;
51
- openedAt = null;
52
- failureThreshold;
53
- resetTimeout;
54
- timeout;
55
- successThreshold;
56
- fallback;
57
- onStateChange;
58
- onError;
59
- name;
60
- fn;
61
- constructor(fn, options = {}) {
62
- this.fn = fn;
63
- this.failureThreshold = options.failureThreshold ?? 5;
64
- this.resetTimeout = options.resetTimeout ?? 6e4;
65
- this.timeout = options.timeout ?? 1e4;
66
- this.successThreshold = options.successThreshold ?? 1;
67
- this.fallback = options.fallback;
68
- this.onStateChange = options.onStateChange;
69
- this.onError = options.onError;
70
- this.name = options.name ?? "CircuitBreaker";
71
- }
72
- /**
73
- * Call the wrapped function with circuit breaker protection
74
- */
75
- async call(...args) {
76
- this.totalCalls++;
77
- this.lastCallAt = Date.now();
78
- if (this.state === CircuitState.OPEN) {
79
- if (Date.now() < this.nextAttempt) {
80
- const error = new CircuitBreakerError(`Circuit breaker is OPEN for ${this.name}`, CircuitState.OPEN);
81
- if (this.fallback) return this.fallback(...args);
82
- throw error;
83
- }
84
- this.setState(CircuitState.HALF_OPEN);
85
- }
86
- try {
87
- const result = await this.executeWithTimeout(args);
88
- this.onSuccess();
89
- return result;
90
- } catch (err) {
91
- this.onFailure(err instanceof Error ? err : new Error(String(err)));
92
- throw err;
93
- }
94
- }
95
- /**
96
- * Execute function with timeout
97
- */
98
- async executeWithTimeout(args) {
99
- return new Promise((resolve, reject) => {
100
- const timeoutId = setTimeout(() => {
101
- reject(/* @__PURE__ */ new Error(`Request timeout after ${this.timeout}ms`));
102
- }, this.timeout);
103
- this.fn(...args).then((result) => {
104
- clearTimeout(timeoutId);
105
- resolve(result);
106
- }).catch((error) => {
107
- clearTimeout(timeoutId);
108
- reject(error);
109
- });
110
- });
111
- }
112
- /**
113
- * Handle successful call
114
- */
115
- onSuccess() {
116
- this.failures = 0;
117
- this.successes++;
118
- if (this.state === CircuitState.HALF_OPEN) {
119
- if (this.successes >= this.successThreshold) {
120
- this.setState(CircuitState.CLOSED);
121
- this.successes = 0;
122
- }
123
- }
124
- }
125
- /**
126
- * Handle failed call
127
- */
128
- onFailure(error) {
129
- this.failures++;
130
- this.successes = 0;
131
- if (this.onError) this.onError(error);
132
- if (this.state === CircuitState.HALF_OPEN || this.failures >= this.failureThreshold) {
133
- this.setState(CircuitState.OPEN);
134
- this.nextAttempt = Date.now() + this.resetTimeout;
135
- this.openedAt = Date.now();
136
- }
137
- }
138
- /**
139
- * Change circuit state
140
- */
141
- setState(newState) {
142
- const oldState = this.state;
143
- if (oldState !== newState) {
144
- this.state = newState;
145
- if (this.onStateChange) this.onStateChange(oldState, newState);
146
- }
147
- }
148
- /**
149
- * Manually open the circuit
150
- */
151
- open() {
152
- this.setState(CircuitState.OPEN);
153
- this.nextAttempt = Date.now() + this.resetTimeout;
154
- this.openedAt = Date.now();
155
- }
156
- /**
157
- * Manually close the circuit
158
- */
159
- close() {
160
- this.failures = 0;
161
- this.successes = 0;
162
- this.setState(CircuitState.CLOSED);
163
- this.openedAt = null;
164
- }
165
- /**
166
- * Get current statistics
167
- */
168
- getStats() {
169
- return {
170
- name: this.name,
171
- state: this.state,
172
- failures: this.failures,
173
- successes: this.successes,
174
- totalCalls: this.totalCalls,
175
- openedAt: this.openedAt,
176
- lastCallAt: this.lastCallAt
177
- };
178
- }
179
- /**
180
- * Get current state
181
- */
182
- getState() {
183
- return this.state;
184
- }
185
- /**
186
- * Check if circuit is open
187
- */
188
- isOpen() {
189
- return this.state === CircuitState.OPEN;
190
- }
191
- /**
192
- * Check if circuit is closed
193
- */
194
- isClosed() {
195
- return this.state === CircuitState.CLOSED;
196
- }
197
- /**
198
- * Reset statistics
199
- */
200
- reset() {
201
- this.failures = 0;
202
- this.successes = 0;
203
- this.totalCalls = 0;
204
- this.lastCallAt = null;
205
- this.openedAt = null;
206
- this.setState(CircuitState.CLOSED);
207
- }
208
- };
209
- /**
210
- * Create a circuit breaker with sensible defaults
211
- *
212
- * @example
213
- * const emailBreaker = createCircuitBreaker(
214
- * async (to, subject, body) => sendEmail(to, subject, body),
215
- * { name: 'email-service' }
216
- * );
217
- */
218
- function createCircuitBreaker(fn, options) {
219
- return new CircuitBreaker(fn, options);
220
- }
221
- /**
222
- * Circuit breaker registry for managing multiple breakers
223
- */
224
- var CircuitBreakerRegistry = class {
225
- breakers = /* @__PURE__ */ new Map();
226
- /**
227
- * Register a circuit breaker
228
- */
229
- register(name, fn, options) {
230
- const breaker = new CircuitBreaker(fn, {
231
- ...options,
232
- name
233
- });
234
- this.breakers.set(name, breaker);
235
- return breaker;
236
- }
237
- /**
238
- * Get a circuit breaker by name
239
- */
240
- get(name) {
241
- return this.breakers.get(name);
242
- }
243
- /**
244
- * Get all breakers
245
- */
246
- getAll() {
247
- return this.breakers;
248
- }
249
- /**
250
- * Get statistics for all breakers
251
- */
252
- getAllStats() {
253
- const stats = {};
254
- for (const [name, breaker] of this.breakers.entries()) stats[name] = breaker.getStats();
255
- return stats;
256
- }
257
- /**
258
- * Reset all breakers
259
- */
260
- resetAll() {
261
- for (const breaker of this.breakers.values()) breaker.reset();
262
- }
263
- /**
264
- * Open all breakers
265
- */
266
- openAll() {
267
- for (const breaker of this.breakers.values()) breaker.open();
268
- }
269
- /**
270
- * Close all breakers
271
- */
272
- closeAll() {
273
- for (const breaker of this.breakers.values()) breaker.close();
274
- }
275
- };
276
- /**
277
- * Create a new CircuitBreakerRegistry instance.
278
- * Use this instead of a global singleton — attach to fastify.arc or pass explicitly.
279
- */
280
- function createCircuitBreakerRegistry() {
281
- return new CircuitBreakerRegistry();
282
- }
283
- //#endregion
284
- export { createCircuitBreaker as a, CircuitState as i, CircuitBreakerError as n, createCircuitBreakerRegistry as o, CircuitBreakerRegistry as r, CircuitBreaker as t };
@@ -1,34 +0,0 @@
1
- import { n as defineResource } from "./defineResource-C__jkwvs.mjs";
2
- //#region src/core/defineResourceVariants.ts
3
- /**
4
- * Define multiple resources from a shared base config and per-variant overrides.
5
- *
6
- * Each variant is independently passed through `defineResource()` — the
7
- * returned `ResourceDefinition`s are real, fully-registered resources.
8
- * Register each one's plugin in your app:
9
- *
10
- * ```typescript
11
- * await app.register(articlePublic.toPlugin());
12
- * await app.register(articleAdmin.toPlugin());
13
- * ```
14
- *
15
- * @param base Shared config — adapter, queryParser, schemaOptions, hooks, etc.
16
- * Must NOT include `name` or `prefix` (those are per-variant).
17
- * @param variants Map of variant key → override. Each variant must declare
18
- * its own `name` and `prefix`. Other fields override the base.
19
- * @returns A record where each key from `variants` maps to a real
20
- * `ResourceDefinition` ready for `.toPlugin()` registration.
21
- */
22
- function defineResourceVariants(base, variants) {
23
- const out = {};
24
- for (const key of Object.keys(variants)) {
25
- const override = variants[key];
26
- out[key] = defineResource({
27
- ...base,
28
- ...override
29
- });
30
- }
31
- return out;
32
- }
33
- //#endregion
34
- export { defineResourceVariants as t };
@@ -1,93 +0,0 @@
1
- import { Kt as ResourceDefinition, r as DataAdapter } from "../interface-YrWsmKqE.mjs";
2
- import { t as PermissionCheck } from "../types-DZi1aYhm.mjs";
3
-
4
- //#region src/dynamic/ArcDynamicLoader.d.ts
5
- interface ArcArchitectureSchema {
6
- /** Application name */
7
- app: string;
8
- /** Resources to provision */
9
- resources: ArcResourceSchema[];
10
- }
11
- /** Field type — maps to JSON Schema / Zod types */
12
- type ArcFieldType = "string" | "number" | "boolean" | "date" | "object" | "array";
13
- /** Per-field definition — matches Arc's FieldRuleEntry for MCP compatibility */
14
- interface ArcFieldSchema {
15
- type: ArcFieldType;
16
- required?: boolean;
17
- description?: string;
18
- enum?: string[];
19
- min?: number;
20
- max?: number;
21
- minLength?: number;
22
- maxLength?: number;
23
- /** System-managed fields (createdAt, updatedAt) — excluded from create/update schemas */
24
- systemManaged?: boolean;
25
- /** Immutable after creation (e.g. slug, organizationId) */
26
- immutable?: boolean;
27
- }
28
- /** Permission preset name — matches Arc's built-in presets */
29
- type ArcPermissionPreset = "publicRead" | "publicReadAdminWrite" | "authenticated" | "adminOnly" | "ownerWithAdminBypass" | "fullPublic" | "readOnly";
30
- /** Fine-grained per-operation permission */
31
- interface ArcPermissionMap {
32
- list?: "public" | "auth" | "admin";
33
- get?: "public" | "auth" | "admin";
34
- create?: "auth" | "admin";
35
- update?: "auth" | "admin" | "owner";
36
- delete?: "auth" | "admin" | "owner";
37
- }
38
- interface ArcResourceSchema {
39
- /** Resource name (e.g., 'product', 'user') — used for URL prefix and tool names */
40
- name: string;
41
- /** Display name for docs and MCP descriptions (defaults to capitalized name) */
42
- displayName?: string;
43
- /** Custom URL prefix (defaults to `/${name}s`) */
44
- prefix?: string;
45
- /** Adapter resolution key — passed to adapterResolver */
46
- adapterPattern?: string;
47
- /** Permission preset name or fine-grained per-operation map */
48
- permissions: ArcPermissionPreset | ArcPermissionMap;
49
- /** Presets to apply (e.g., 'softDelete', 'slugLookup', 'bulk') */
50
- presets?: string[];
51
- /** Field definitions — drives schemaOptions.fieldRules for validation and MCP tool schemas */
52
- fields?: Record<string, ArcFieldSchema | ArcFieldType>;
53
- /** Fields allowed for filtering in list operations (drives queryParser + MCP) */
54
- filterable?: string[];
55
- /** Fields allowed for sorting (drives queryParser + MCP) */
56
- sortable?: string[];
57
- /** CRUD operations to disable (e.g., ['delete'] for append-only resources) */
58
- disabledRoutes?: string[];
59
- /** Tenant field name for multi-tenant resources */
60
- tenantField?: string;
61
- }
62
- interface DynamicLoaderContext {
63
- /** Resolve a data adapter for a resource — receives name and optional pattern key */
64
- adapterResolver: (resourceName: string, pattern?: string) => DataAdapter;
65
- /** Resolve custom permission checks beyond built-in presets */
66
- permissionResolver?: (policy: string) => PermissionCheck;
67
- }
68
- /**
69
- * Load an Arc Architecture Schema (JSON) and produce fully configured ResourceDefinitions.
70
- *
71
- * Each resource gets:
72
- * - Adapter from the resolver
73
- * - Permissions from presets or fine-grained map
74
- * - schemaOptions.fieldRules for validation and MCP tool schemas
75
- * - ArcQueryParser with allowedFilterFields/allowedSortFields for MCP auto-derive
76
- * - Presets applied
77
- */
78
- declare class ArcDynamicLoader {
79
- private context;
80
- constructor(context: DynamicLoaderContext);
81
- /**
82
- * Load an AAS definition and return fully constructed ResourceDefinitions.
83
- * Validates the schema before processing — throws on malformed input.
84
- */
85
- load(schema: ArcArchitectureSchema): ResourceDefinition<unknown>[];
86
- private buildFieldRules;
87
- private buildQueryParser;
88
- private resolvePermissions;
89
- private resolvePreset;
90
- private resolveFinGrained;
91
- }
92
- //#endregion
93
- export { ArcArchitectureSchema, ArcDynamicLoader, ArcFieldSchema, ArcFieldType, ArcPermissionMap, ArcPermissionPreset, ArcResourceSchema, DynamicLoaderContext };
@@ -1,122 +0,0 @@
1
- import { t as ArcQueryParser } from "../queryParser-Cs-6SHQK.mjs";
2
- import { n as defineResource } from "../defineResource-C__jkwvs.mjs";
3
- import { C as publicRead, T as readOnly, b as fullPublic, v as adminOnly, w as publicReadAdminWrite, x as ownerWithAdminBypass, y as authenticated } from "../permissions-oNZawnkR.mjs";
4
- //#region src/dynamic/ArcDynamicLoader.ts
5
- const VALID_FIELD_TYPES = new Set([
6
- "string",
7
- "number",
8
- "boolean",
9
- "date",
10
- "object",
11
- "array"
12
- ]);
13
- function validateSchema(schema) {
14
- if (!schema.app || typeof schema.app !== "string") throw new Error("AAS: 'app' name is required");
15
- if (!Array.isArray(schema.resources) || schema.resources.length === 0) throw new Error("AAS: 'resources' must be a non-empty array");
16
- for (const r of schema.resources) {
17
- if (!r.name || typeof r.name !== "string") throw new Error("AAS: each resource must have a 'name' string");
18
- if (!r.permissions) throw new Error(`AAS: resource "${r.name}" must have 'permissions'`);
19
- if (r.fields) for (const [fieldName, fieldDef] of Object.entries(r.fields)) {
20
- const type = typeof fieldDef === "string" ? fieldDef : fieldDef.type;
21
- if (!VALID_FIELD_TYPES.has(type)) throw new Error(`AAS: resource "${r.name}" field "${fieldName}" has invalid type "${type}". Valid types: ${[...VALID_FIELD_TYPES].join(", ")}`);
22
- }
23
- }
24
- }
25
- /**
26
- * Load an Arc Architecture Schema (JSON) and produce fully configured ResourceDefinitions.
27
- *
28
- * Each resource gets:
29
- * - Adapter from the resolver
30
- * - Permissions from presets or fine-grained map
31
- * - schemaOptions.fieldRules for validation and MCP tool schemas
32
- * - ArcQueryParser with allowedFilterFields/allowedSortFields for MCP auto-derive
33
- * - Presets applied
34
- */
35
- var ArcDynamicLoader = class {
36
- context;
37
- constructor(context) {
38
- this.context = context;
39
- }
40
- /**
41
- * Load an AAS definition and return fully constructed ResourceDefinitions.
42
- * Validates the schema before processing — throws on malformed input.
43
- */
44
- load(schema) {
45
- validateSchema(schema);
46
- return schema.resources.map((r) => {
47
- const adapter = this.context.adapterResolver(r.name, r.adapterPattern);
48
- const fieldRules = this.buildFieldRules(r.fields);
49
- const queryParser = this.buildQueryParser(r);
50
- return defineResource({
51
- name: r.name,
52
- displayName: r.displayName,
53
- prefix: r.prefix,
54
- adapter,
55
- queryParser,
56
- presets: r.presets,
57
- permissions: this.resolvePermissions(r.permissions),
58
- disabledRoutes: r.disabledRoutes,
59
- tenantField: r.tenantField,
60
- schemaOptions: fieldRules ? {
61
- fieldRules,
62
- filterableFields: r.filterable
63
- } : void 0
64
- });
65
- });
66
- }
67
- buildFieldRules(fields) {
68
- if (!fields) return void 0;
69
- const rules = {};
70
- for (const [name, def] of Object.entries(fields)) rules[name] = typeof def === "string" ? { type: def } : def;
71
- return rules;
72
- }
73
- buildQueryParser(r) {
74
- if (!r.filterable && !r.sortable) return void 0;
75
- return new ArcQueryParser({
76
- allowedFilterFields: r.filterable,
77
- allowedSortFields: r.sortable
78
- });
79
- }
80
- resolvePermissions(policy) {
81
- if (typeof policy === "string") return this.resolvePreset(policy);
82
- return this.resolveFinGrained(policy);
83
- }
84
- resolvePreset(preset) {
85
- switch (preset) {
86
- case "publicRead": return publicRead();
87
- case "publicReadAdminWrite": return publicReadAdminWrite();
88
- case "authenticated": return authenticated();
89
- case "adminOnly": return adminOnly();
90
- case "ownerWithAdminBypass": return ownerWithAdminBypass();
91
- case "fullPublic": return fullPublic();
92
- case "readOnly": return readOnly();
93
- default:
94
- if (this.context.permissionResolver) {
95
- const resolved = this.context.permissionResolver(preset);
96
- if (resolved) return resolved;
97
- }
98
- throw new Error(`Unknown permission preset: "${preset}"`);
99
- }
100
- }
101
- resolveFinGrained(policy) {
102
- const pick = (preset, op) => preset[op] ?? authenticated()[op];
103
- const map = {
104
- public: (op) => pick(publicRead(), op),
105
- auth: (op) => pick(authenticated(), op),
106
- admin: (op) => pick(adminOnly(), op),
107
- owner: (op) => pick(ownerWithAdminBypass(), op)
108
- };
109
- const permissions = {};
110
- const ops = {
111
- list: policy.list,
112
- get: policy.get,
113
- create: policy.create,
114
- update: policy.update,
115
- delete: policy.delete
116
- };
117
- for (const [op, level] of Object.entries(ops)) if (level && map[level]) permissions[op] = map[level](op);
118
- return permissions;
119
- }
120
- };
121
- //#endregion
122
- export { ArcDynamicLoader };