@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.
- package/README.md +20 -91
- package/dist/{BaseController-Vu2yc56T.mjs → BaseController-DVNKvoX4.mjs} +154 -170
- package/dist/{ResourceRegistry-Dq3_zBQP.mjs → ResourceRegistry-CcN2LVrc.mjs} +1 -1
- package/dist/actionPermissions-TUVR3uiZ.mjs +22 -0
- package/dist/adapters/index.d.mts +3 -3
- package/dist/adapters/index.mjs +2 -2
- package/dist/{adapters-BBqAVvPK.mjs → adapters-BXY4i-hw.mjs} +210 -41
- package/dist/audit/index.d.mts +38 -3
- package/dist/audit/index.mjs +54 -22
- package/dist/auth/index.d.mts +2 -2
- package/dist/auth/index.mjs +3 -3
- package/dist/cache/index.d.mts +17 -15
- package/dist/cache/index.mjs +16 -15
- package/dist/{caching-CjybdRwx.mjs → caching-3h93rkJM.mjs} +8 -3
- package/dist/cli/commands/describe.mjs +1 -1
- package/dist/cli/commands/docs.mjs +2 -2
- package/dist/cli/commands/init.mjs +1 -1
- package/dist/cli/commands/introspect.mjs +1 -1
- package/dist/context/index.d.mts +58 -0
- package/dist/context/index.mjs +2 -0
- package/dist/core/index.d.mts +2 -2
- package/dist/core/index.mjs +3 -4
- package/dist/{defineResource-C__jkwvs.mjs → core-3MWJosCH.mjs} +174 -94
- package/dist/{createActionRouter-DH1YFL9m.mjs → createActionRouter-C8UUB3Px.mjs} +1 -1
- package/dist/{createApp-CBJUJKGP.mjs → createApp-BwnEAO2h.mjs} +53 -19
- package/dist/docs/index.d.mts +1 -1
- package/dist/docs/index.mjs +2 -2
- package/dist/{elevation-DxQ6ACbt.mjs → elevation-Dci0AYLT.mjs} +2 -2
- package/dist/errorHandler-2ii4RIYr.d.mts +114 -0
- package/dist/{errorHandler-CZDW4EXS.mjs → errorHandler-CSxe7KIM.mjs} +1 -1
- package/dist/{eventPlugin-Dl7MoVWH.mjs → eventPlugin-ByU4Cv0e.mjs} +1 -1
- package/dist/{eventPlugin-BxvaCIZF.d.mts → eventPlugin-D1ThQ1Pp.d.mts} +1 -1
- package/dist/events/index.d.mts +8 -5
- package/dist/events/index.mjs +87 -52
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis.d.mts +1 -1
- package/dist/factory/index.d.mts +1 -1
- package/dist/factory/index.mjs +1 -1
- package/dist/{types-DZi1aYhm.d.mts → fields-C8Y0XLAu.d.mts} +122 -2
- package/dist/hooks/index.d.mts +1 -1
- package/dist/idempotency/index.d.mts +5 -2
- package/dist/idempotency/index.mjs +46 -37
- package/dist/{interface-YrWsmKqE.d.mts → index-BGbpGVyM.d.mts} +2107 -2756
- package/dist/{index-CtGKT0lf.d.mts → index-BziRPS4H.d.mts} +81 -7
- package/dist/{index-C-xjcA6F.d.mts → index-C_Noptz-.d.mts} +284 -409
- package/dist/{index-Cibkchnx.d.mts → index-EqQN6p0W.d.mts} +3 -3
- package/dist/index.d.mts +6 -219
- package/dist/index.mjs +10 -131
- package/dist/integrations/event-gateway.d.mts +1 -1
- package/dist/integrations/event-gateway.mjs +1 -1
- package/dist/integrations/index.d.mts +1 -1
- package/dist/integrations/mcp/index.d.mts +2 -2
- package/dist/integrations/mcp/index.mjs +1 -1
- package/dist/integrations/mcp/testing.d.mts +1 -1
- package/dist/integrations/mcp/testing.mjs +1 -1
- package/dist/interface-yhyb_pLY.d.mts +77 -0
- package/dist/logger/index.d.mts +81 -0
- package/dist/{logger-CDjpjySd.mjs → logger/index.mjs} +1 -6
- package/dist/{memory-BFAYkf8H.mjs → memory-DqI-449b.mjs} +23 -8
- package/dist/middleware/index.d.mts +109 -0
- package/dist/middleware/index.mjs +70 -0
- package/dist/multipartBody-CUQGVlM_.mjs +123 -0
- package/dist/{openapi-CXuTG1M9.mjs → openapi-DpNpqBmo.mjs} +9 -7
- package/dist/org/index.d.mts +2 -2
- package/dist/permissions/index.d.mts +3 -4
- package/dist/permissions/index.mjs +5 -5
- package/dist/{permissions-oNZawnkR.mjs → permissions-wkqRwicB.mjs} +315 -397
- package/dist/pipe-CGJxqDGx.mjs +62 -0
- package/dist/pipeline/index.d.mts +62 -0
- package/dist/pipeline/index.mjs +53 -0
- package/dist/plugins/index.d.mts +23 -3
- package/dist/plugins/index.mjs +9 -11
- package/dist/plugins/response-cache.mjs +1 -1
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/presets/filesUpload.d.mts +3 -3
- package/dist/presets/filesUpload.mjs +255 -1
- package/dist/presets/index.d.mts +1 -1
- package/dist/presets/index.mjs +2 -2
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/presets/multiTenant.mjs +43 -9
- package/dist/presets/search.d.mts +91 -4
- package/dist/presets/search.mjs +1 -1
- package/dist/{presets-hM4WhNWY.mjs → presets-CrwOvuXI.mjs} +1 -1
- package/dist/{queryCachePlugin-DbUVroUG.mjs → queryCachePlugin-ChLNZvFT.mjs} +9 -9
- package/dist/{queryCachePlugin-CnTZZTC5.d.mts → queryCachePlugin-Dumka73q.d.mts} +1 -1
- package/dist/{queryParser-Cs-6SHQK.mjs → queryParser-NR__Qiju.mjs} +69 -2
- package/dist/{redis-stream-Bz-4q96t.d.mts → redis-stream-bkO88VHx.d.mts} +1 -1
- package/dist/registry/index.d.mts +1 -1
- package/dist/registry/index.mjs +1 -1
- package/dist/{requestContext-DYtmNpm5.mjs → requestContext-C38GskNt.mjs} +1 -1
- package/dist/{resourceToTools-C3cWymnW.mjs → resourceToTools-BhF3JV5p.mjs} +8 -3
- package/dist/scope/index.d.mts +2 -2
- package/dist/scope/index.mjs +2 -2
- package/dist/{sse-CJpt7LGI.mjs → sse-D8UeDwis.mjs} +1 -1
- package/dist/{store-helpers-DFiZl5TL.mjs → store-helpers-DYYUQbQN.mjs} +4 -0
- package/dist/testing/index.d.mts +6 -5
- package/dist/testing/index.mjs +17 -10
- package/dist/types/index.d.mts +5 -5
- package/dist/types/index.mjs +1 -31
- package/dist/types-CDnTEpga.mjs +27 -0
- package/dist/{types-CoSzA-s-.d.mts → types-CVKBssX5.d.mts} +1 -1
- package/dist/{types-CunEX4UX.d.mts → types-CVdgPXBW.d.mts} +20 -7
- package/dist/utils/index.d.mts +277 -3
- package/dist/utils/index.mjs +4 -5
- package/dist/{utils-B7FuRr9w.mjs → utils-LMwVidKy.mjs} +303 -2
- package/dist/{versioning-Cm8qoFDg.mjs → versioning-B6mimogM.mjs} +3 -5
- package/dist/versioning-CeUXHfjw.d.mts +117 -0
- package/package.json +31 -18
- package/skills/arc/SKILL.md +8 -12
- package/skills/arc/references/production.md +0 -41
- package/dist/circuitBreaker-CvXkjfrW.d.mts +0 -206
- package/dist/circuitBreaker-l18oRgL5.mjs +0 -284
- package/dist/core-DNncu0xF.mjs +0 -34
- package/dist/dynamic/index.d.mts +0 -93
- package/dist/dynamic/index.mjs +0 -122
- package/dist/errorHandler-DixGcttC.d.mts +0 -218
- package/dist/fields-BC7zcmI9.d.mts +0 -121
- package/dist/filesUpload-q8oHt--L.mjs +0 -377
- package/dist/interface-DplgQO2e.d.mts +0 -54
- package/dist/policies/index.d.mts +0 -425
- package/dist/policies/index.mjs +0 -318
- package/dist/rpc/index.d.mts +0 -90
- package/dist/rpc/index.mjs +0 -248
- /package/dist/{EventTransport-CqZ8FyM_.d.mts → EventTransport-CfVEGaEl.d.mts} +0 -0
- /package/dist/{applyPermissionResult-bqGpo9ML.mjs → applyPermissionResult-QhV1Pa-g.mjs} +0 -0
- /package/dist/{constants-Cxde4rpC.mjs → constants-BhY1OHoH.mjs} +0 -0
- /package/dist/{elevation-B6S5csVA.d.mts → elevation-s5ykdNHr.d.mts} +0 -0
- /package/dist/{errors-CqWnSqM-.mjs → errors-BqdUDja_.mjs} +0 -0
- /package/dist/{fields-CU6FlaDV.mjs → fields-CTMWOUDt.mjs} +0 -0
- /package/dist/{keys-qcD-TVJl.mjs → keys-nWQGUTu1.mjs} +0 -0
- /package/dist/{types-ZUu_h0jp.mjs → types-D57iXYb8.mjs} +0 -0
- /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 };
|
package/dist/core-DNncu0xF.mjs
DELETED
|
@@ -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 };
|
package/dist/dynamic/index.d.mts
DELETED
|
@@ -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 };
|
package/dist/dynamic/index.mjs
DELETED
|
@@ -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 };
|