@classytic/arc 1.0.0

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 (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +900 -0
  3. package/bin/arc.js +344 -0
  4. package/dist/adapters/index.d.ts +237 -0
  5. package/dist/adapters/index.js +668 -0
  6. package/dist/arcCorePlugin-DTPWXcZN.d.ts +273 -0
  7. package/dist/audit/index.d.ts +195 -0
  8. package/dist/audit/index.js +319 -0
  9. package/dist/auth/index.d.ts +47 -0
  10. package/dist/auth/index.js +174 -0
  11. package/dist/cli/commands/docs.d.ts +11 -0
  12. package/dist/cli/commands/docs.js +474 -0
  13. package/dist/cli/commands/introspect.d.ts +8 -0
  14. package/dist/cli/commands/introspect.js +338 -0
  15. package/dist/cli/index.d.ts +43 -0
  16. package/dist/cli/index.js +520 -0
  17. package/dist/createApp-pzUAkzbz.d.ts +77 -0
  18. package/dist/docs/index.d.ts +166 -0
  19. package/dist/docs/index.js +650 -0
  20. package/dist/errors-8WIxGS_6.d.ts +122 -0
  21. package/dist/events/index.d.ts +117 -0
  22. package/dist/events/index.js +89 -0
  23. package/dist/factory/index.d.ts +38 -0
  24. package/dist/factory/index.js +1664 -0
  25. package/dist/hooks/index.d.ts +4 -0
  26. package/dist/hooks/index.js +199 -0
  27. package/dist/idempotency/index.d.ts +323 -0
  28. package/dist/idempotency/index.js +500 -0
  29. package/dist/index-DkAW8BXh.d.ts +1302 -0
  30. package/dist/index.d.ts +331 -0
  31. package/dist/index.js +4734 -0
  32. package/dist/migrations/index.d.ts +185 -0
  33. package/dist/migrations/index.js +274 -0
  34. package/dist/org/index.d.ts +129 -0
  35. package/dist/org/index.js +220 -0
  36. package/dist/permissions/index.d.ts +144 -0
  37. package/dist/permissions/index.js +100 -0
  38. package/dist/plugins/index.d.ts +46 -0
  39. package/dist/plugins/index.js +1069 -0
  40. package/dist/policies/index.d.ts +398 -0
  41. package/dist/policies/index.js +196 -0
  42. package/dist/presets/index.d.ts +336 -0
  43. package/dist/presets/index.js +382 -0
  44. package/dist/presets/multiTenant.d.ts +39 -0
  45. package/dist/presets/multiTenant.js +112 -0
  46. package/dist/registry/index.d.ts +16 -0
  47. package/dist/registry/index.js +253 -0
  48. package/dist/testing/index.d.ts +618 -0
  49. package/dist/testing/index.js +48032 -0
  50. package/dist/types/index.d.ts +4 -0
  51. package/dist/types/index.js +8 -0
  52. package/dist/types-0IPhH_NR.d.ts +143 -0
  53. package/dist/types-B99TBmFV.d.ts +76 -0
  54. package/dist/utils/index.d.ts +655 -0
  55. package/dist/utils/index.js +905 -0
  56. package/package.json +227 -0
@@ -0,0 +1,655 @@
1
+ export { A as ArcError, C as ConflictError, E as ErrorDetails, F as ForbiddenError, N as NotFoundError, a as OrgAccessDeniedError, O as OrgRequiredError, R as RateLimitError, S as ServiceUnavailableError, U as UnauthorizedError, V as ValidationError, c as createError, i as isArcError } from '../errors-8WIxGS_6.js';
2
+ import { d as AnyRecord, h as QueryParserInterface, ae as ParsedQuery } from '../index-DkAW8BXh.js';
3
+ import 'mongoose';
4
+ import 'fastify';
5
+ import '../types-B99TBmFV.js';
6
+
7
+ /**
8
+ * Response Schemas
9
+ *
10
+ * Standard JSON Schema definitions for API responses.
11
+ */
12
+
13
+ interface JsonSchema {
14
+ type: string;
15
+ properties?: Record<string, JsonSchema | AnyRecord>;
16
+ required?: string[];
17
+ items?: JsonSchema | AnyRecord;
18
+ additionalProperties?: boolean | JsonSchema;
19
+ description?: string;
20
+ example?: unknown;
21
+ [key: string]: unknown;
22
+ }
23
+ /**
24
+ * Base success response schema
25
+ */
26
+ declare const successResponseSchema: JsonSchema;
27
+ /**
28
+ * Error response schema
29
+ */
30
+ declare const errorResponseSchema: JsonSchema;
31
+ /**
32
+ * Pagination schema
33
+ */
34
+ declare const paginationSchema: JsonSchema;
35
+ /**
36
+ * Wrap a data schema in a success response
37
+ */
38
+ declare function wrapResponse(dataSchema: JsonSchema): JsonSchema;
39
+ /**
40
+ * Create a list response schema with pagination
41
+ */
42
+ declare function listResponse(itemSchema: JsonSchema): JsonSchema;
43
+ /**
44
+ * Create a single item response schema
45
+ */
46
+ declare function itemResponse(itemSchema: JsonSchema): JsonSchema;
47
+ /**
48
+ * Create a create/update response schema
49
+ */
50
+ declare function mutationResponse(itemSchema: JsonSchema): JsonSchema;
51
+ /**
52
+ * Create a delete response schema
53
+ */
54
+ declare function deleteResponse(): JsonSchema;
55
+ declare const responses: {
56
+ 200: (schema: JsonSchema) => {
57
+ description: string;
58
+ content: {
59
+ 'application/json': {
60
+ schema: JsonSchema;
61
+ };
62
+ };
63
+ };
64
+ 201: (schema: JsonSchema) => {
65
+ description: string;
66
+ content: {
67
+ 'application/json': {
68
+ schema: JsonSchema;
69
+ };
70
+ };
71
+ };
72
+ 400: {
73
+ description: string;
74
+ content: {
75
+ 'application/json': {
76
+ schema: {
77
+ properties: {
78
+ code: {
79
+ type: string;
80
+ example: string;
81
+ };
82
+ details: {
83
+ type: string;
84
+ properties: {
85
+ errors: {
86
+ type: string;
87
+ items: {
88
+ type: string;
89
+ properties: {
90
+ field: {
91
+ type: string;
92
+ };
93
+ message: {
94
+ type: string;
95
+ };
96
+ };
97
+ };
98
+ };
99
+ };
100
+ };
101
+ };
102
+ type: string;
103
+ required?: string[];
104
+ items?: JsonSchema | AnyRecord;
105
+ additionalProperties?: boolean | JsonSchema;
106
+ description?: string;
107
+ example?: unknown;
108
+ };
109
+ };
110
+ };
111
+ };
112
+ 401: {
113
+ description: string;
114
+ content: {
115
+ 'application/json': {
116
+ schema: {
117
+ properties: {
118
+ code: {
119
+ type: string;
120
+ example: string;
121
+ };
122
+ };
123
+ type: string;
124
+ required?: string[];
125
+ items?: JsonSchema | AnyRecord;
126
+ additionalProperties?: boolean | JsonSchema;
127
+ description?: string;
128
+ example?: unknown;
129
+ };
130
+ };
131
+ };
132
+ };
133
+ 403: {
134
+ description: string;
135
+ content: {
136
+ 'application/json': {
137
+ schema: {
138
+ properties: {
139
+ code: {
140
+ type: string;
141
+ example: string;
142
+ };
143
+ };
144
+ type: string;
145
+ required?: string[];
146
+ items?: JsonSchema | AnyRecord;
147
+ additionalProperties?: boolean | JsonSchema;
148
+ description?: string;
149
+ example?: unknown;
150
+ };
151
+ };
152
+ };
153
+ };
154
+ 404: {
155
+ description: string;
156
+ content: {
157
+ 'application/json': {
158
+ schema: {
159
+ properties: {
160
+ code: {
161
+ type: string;
162
+ example: string;
163
+ };
164
+ };
165
+ type: string;
166
+ required?: string[];
167
+ items?: JsonSchema | AnyRecord;
168
+ additionalProperties?: boolean | JsonSchema;
169
+ description?: string;
170
+ example?: unknown;
171
+ };
172
+ };
173
+ };
174
+ };
175
+ 409: {
176
+ description: string;
177
+ content: {
178
+ 'application/json': {
179
+ schema: {
180
+ properties: {
181
+ code: {
182
+ type: string;
183
+ example: string;
184
+ };
185
+ };
186
+ type: string;
187
+ required?: string[];
188
+ items?: JsonSchema | AnyRecord;
189
+ additionalProperties?: boolean | JsonSchema;
190
+ description?: string;
191
+ example?: unknown;
192
+ };
193
+ };
194
+ };
195
+ };
196
+ 500: {
197
+ description: string;
198
+ content: {
199
+ 'application/json': {
200
+ schema: {
201
+ properties: {
202
+ code: {
203
+ type: string;
204
+ example: string;
205
+ };
206
+ };
207
+ type: string;
208
+ required?: string[];
209
+ items?: JsonSchema | AnyRecord;
210
+ additionalProperties?: boolean | JsonSchema;
211
+ description?: string;
212
+ example?: unknown;
213
+ };
214
+ };
215
+ };
216
+ };
217
+ };
218
+ declare const queryParams: {
219
+ pagination: {
220
+ page: {
221
+ type: string;
222
+ minimum: number;
223
+ default: number;
224
+ description: string;
225
+ };
226
+ limit: {
227
+ type: string;
228
+ minimum: number;
229
+ maximum: number;
230
+ default: number;
231
+ description: string;
232
+ };
233
+ };
234
+ sorting: {
235
+ sort: {
236
+ type: string;
237
+ description: string;
238
+ example: string;
239
+ };
240
+ };
241
+ filtering: {
242
+ select: {
243
+ type: string;
244
+ description: string;
245
+ example: string;
246
+ };
247
+ populate: {
248
+ type: string;
249
+ description: string;
250
+ example: string;
251
+ };
252
+ };
253
+ };
254
+ /**
255
+ * Get standard list query parameters schema
256
+ */
257
+ declare function getListQueryParams(): AnyRecord;
258
+
259
+ /**
260
+ * State Machine Utility
261
+ *
262
+ * Pure utility for validating state transitions in workflow systems.
263
+ * Zero dependencies, framework-agnostic.
264
+ *
265
+ * @example
266
+ * const orderState = createStateMachine('Order', {
267
+ * approve: ['pending', 'draft'],
268
+ * cancel: ['pending', 'approved'],
269
+ * fulfill: ['approved'],
270
+ * });
271
+ *
272
+ * // Check if transition is allowed
273
+ * if (orderState.can('approve', currentStatus)) {
274
+ * // Perform approval
275
+ * }
276
+ *
277
+ * // Assert transition (throws if invalid)
278
+ * orderState.assert('approve', currentStatus, ValidationError);
279
+ */
280
+ interface StateMachine {
281
+ /**
282
+ * Check if action can be performed from current status
283
+ */
284
+ can(action: string, status: string | null | undefined, context?: any): boolean;
285
+ /**
286
+ * Assert action can be performed, throw error if invalid
287
+ * @param action - Action to perform
288
+ * @param status - Current status
289
+ * @param errorFactory - Optional error constructor
290
+ * @param message - Optional custom error message
291
+ */
292
+ assert(action: string, status: string | null | undefined, errorFactory?: (msg: string) => Error, message?: string): void;
293
+ /**
294
+ * Get transition history
295
+ */
296
+ getHistory?(): TransitionHistoryEntry[];
297
+ /**
298
+ * Record a transition
299
+ */
300
+ recordTransition?(from: string, to: string, action: string, metadata?: any): void;
301
+ /**
302
+ * Clear history
303
+ */
304
+ clearHistory?(): void;
305
+ /**
306
+ * Get available actions for current status
307
+ */
308
+ getAvailableActions?(status: string): string[];
309
+ }
310
+ interface TransitionHistoryEntry {
311
+ from: string;
312
+ to: string;
313
+ action: string;
314
+ timestamp: Date;
315
+ metadata?: any;
316
+ }
317
+ interface TransitionGuard {
318
+ (context: {
319
+ from: string;
320
+ to: string;
321
+ action: string;
322
+ data?: any;
323
+ }): boolean | Promise<boolean>;
324
+ }
325
+ interface TransitionAction {
326
+ (context: {
327
+ from: string;
328
+ to: string;
329
+ action: string;
330
+ data?: any;
331
+ }): void | Promise<void>;
332
+ }
333
+ type TransitionConfig = Record<string, string[] | {
334
+ from: string[];
335
+ to?: string;
336
+ guard?: TransitionGuard;
337
+ before?: TransitionAction;
338
+ after?: TransitionAction;
339
+ }>;
340
+ /**
341
+ * Create a state machine for validating transitions
342
+ *
343
+ * @param name - Name of the state machine (used in error messages)
344
+ * @param transitions - Map of actions to allowed source statuses
345
+ * @param options - Additional options (history, guards, actions)
346
+ * @returns State machine with can() and assert() methods
347
+ *
348
+ * @example
349
+ * // Basic usage
350
+ * const transferState = createStateMachine('Transfer', {
351
+ * approve: ['draft'],
352
+ * dispatch: ['approved'],
353
+ * receive: ['dispatched', 'in_transit'],
354
+ * cancel: ['draft', 'approved'],
355
+ * });
356
+ *
357
+ * @example
358
+ * // With guards and actions
359
+ * const orderState = createStateMachine('Order', {
360
+ * approve: {
361
+ * from: ['pending'],
362
+ * to: 'approved',
363
+ * guard: ({ data }) => data.paymentConfirmed,
364
+ * before: ({ from, to }) => console.log(`Approving order from ${from} to ${to}`),
365
+ * after: ({ data }) => sendApprovalEmail(data.customerId),
366
+ * },
367
+ * }, { trackHistory: true });
368
+ */
369
+ declare function createStateMachine(name: string, transitions?: TransitionConfig, options?: {
370
+ trackHistory?: boolean;
371
+ }): StateMachine;
372
+
373
+ /**
374
+ * Circuit Breaker Pattern
375
+ *
376
+ * Wraps external service calls with failure protection.
377
+ * Prevents cascading failures by "opening" the circuit when
378
+ * a service is failing, allowing it time to recover.
379
+ *
380
+ * States:
381
+ * - CLOSED: Normal operation, requests pass through
382
+ * - OPEN: Too many failures, all requests fail fast
383
+ * - HALF_OPEN: Testing if service recovered, limited requests
384
+ *
385
+ * @example
386
+ * import { CircuitBreaker } from '@classytic/arc/utils';
387
+ *
388
+ * const paymentBreaker = new CircuitBreaker(async (amount) => {
389
+ * return await stripe.charges.create({ amount });
390
+ * }, {
391
+ * failureThreshold: 5,
392
+ * resetTimeout: 30000,
393
+ * timeout: 5000,
394
+ * });
395
+ *
396
+ * try {
397
+ * const result = await paymentBreaker.call(100);
398
+ * } catch (error) {
399
+ * // Handle failure or circuit open
400
+ * }
401
+ */
402
+ declare enum CircuitState {
403
+ CLOSED = "CLOSED",
404
+ OPEN = "OPEN",
405
+ HALF_OPEN = "HALF_OPEN"
406
+ }
407
+ interface CircuitBreakerOptions {
408
+ /**
409
+ * Number of failures before opening circuit
410
+ * @default 5
411
+ */
412
+ failureThreshold?: number;
413
+ /**
414
+ * Time in ms before attempting to close circuit
415
+ * @default 60000 (60 seconds)
416
+ */
417
+ resetTimeout?: number;
418
+ /**
419
+ * Request timeout in ms
420
+ * @default 10000 (10 seconds)
421
+ */
422
+ timeout?: number;
423
+ /**
424
+ * Number of successful requests in HALF_OPEN before closing
425
+ * @default 1
426
+ */
427
+ successThreshold?: number;
428
+ /**
429
+ * Fallback function when circuit is open
430
+ */
431
+ fallback?: (...args: any[]) => Promise<any>;
432
+ /**
433
+ * Callback when state changes
434
+ */
435
+ onStateChange?: (from: CircuitState, to: CircuitState) => void;
436
+ /**
437
+ * Callback on error
438
+ */
439
+ onError?: (error: Error) => void;
440
+ /**
441
+ * Name for logging/monitoring
442
+ */
443
+ name?: string;
444
+ }
445
+ interface CircuitBreakerStats {
446
+ name?: string;
447
+ state: CircuitState;
448
+ failures: number;
449
+ successes: number;
450
+ totalCalls: number;
451
+ openedAt: number | null;
452
+ lastCallAt: number | null;
453
+ }
454
+ declare class CircuitBreakerError extends Error {
455
+ state: CircuitState;
456
+ constructor(message: string, state: CircuitState);
457
+ }
458
+ declare class CircuitBreaker<T extends (...args: any[]) => Promise<any>> {
459
+ private readonly fn;
460
+ private state;
461
+ private failures;
462
+ private successes;
463
+ private totalCalls;
464
+ private nextAttempt;
465
+ private lastCallAt;
466
+ private openedAt;
467
+ private readonly failureThreshold;
468
+ private readonly resetTimeout;
469
+ private readonly timeout;
470
+ private readonly successThreshold;
471
+ private readonly fallback?;
472
+ private readonly onStateChange?;
473
+ private readonly onError?;
474
+ private readonly name;
475
+ constructor(fn: T, options?: CircuitBreakerOptions);
476
+ /**
477
+ * Call the wrapped function with circuit breaker protection
478
+ */
479
+ call(...args: Parameters<T>): Promise<ReturnType<T>>;
480
+ /**
481
+ * Execute function with timeout
482
+ */
483
+ private executeWithTimeout;
484
+ /**
485
+ * Handle successful call
486
+ */
487
+ private onSuccess;
488
+ /**
489
+ * Handle failed call
490
+ */
491
+ private onFailure;
492
+ /**
493
+ * Change circuit state
494
+ */
495
+ private setState;
496
+ /**
497
+ * Manually open the circuit
498
+ */
499
+ open(): void;
500
+ /**
501
+ * Manually close the circuit
502
+ */
503
+ close(): void;
504
+ /**
505
+ * Get current statistics
506
+ */
507
+ getStats(): CircuitBreakerStats;
508
+ /**
509
+ * Get current state
510
+ */
511
+ getState(): CircuitState;
512
+ /**
513
+ * Check if circuit is open
514
+ */
515
+ isOpen(): boolean;
516
+ /**
517
+ * Check if circuit is closed
518
+ */
519
+ isClosed(): boolean;
520
+ /**
521
+ * Reset statistics
522
+ */
523
+ reset(): void;
524
+ }
525
+ /**
526
+ * Create a circuit breaker with sensible defaults
527
+ *
528
+ * @example
529
+ * const emailBreaker = createCircuitBreaker(
530
+ * async (to, subject, body) => sendEmail(to, subject, body),
531
+ * { name: 'email-service' }
532
+ * );
533
+ */
534
+ declare function createCircuitBreaker<T extends (...args: any[]) => Promise<any>>(fn: T, options?: CircuitBreakerOptions): CircuitBreaker<T>;
535
+ /**
536
+ * Circuit breaker registry for managing multiple breakers
537
+ */
538
+ declare class CircuitBreakerRegistry {
539
+ private breakers;
540
+ /**
541
+ * Register a circuit breaker
542
+ */
543
+ register<T extends (...args: any[]) => Promise<any>>(name: string, fn: T, options?: Omit<CircuitBreakerOptions, 'name'>): CircuitBreaker<T>;
544
+ /**
545
+ * Get a circuit breaker by name
546
+ */
547
+ get(name: string): CircuitBreaker<any> | undefined;
548
+ /**
549
+ * Get all breakers
550
+ */
551
+ getAll(): Map<string, CircuitBreaker<any>>;
552
+ /**
553
+ * Get statistics for all breakers
554
+ */
555
+ getAllStats(): Record<string, CircuitBreakerStats>;
556
+ /**
557
+ * Reset all breakers
558
+ */
559
+ resetAll(): void;
560
+ /**
561
+ * Open all breakers
562
+ */
563
+ openAll(): void;
564
+ /**
565
+ * Close all breakers
566
+ */
567
+ closeAll(): void;
568
+ }
569
+ /**
570
+ * Global circuit breaker registry
571
+ */
572
+ declare const circuitBreakerRegistry: CircuitBreakerRegistry;
573
+
574
+ /**
575
+ * Arc Query Parser - Default URL-to-Query Parser
576
+ *
577
+ * Framework-agnostic query parser that converts URL parameters to query options.
578
+ * This is Arc's built-in parser; users can swap in MongoKit's QueryParser,
579
+ * pgkit's parser, or any custom parser implementing QueryParserInterface.
580
+ *
581
+ * @example
582
+ * // Use Arc default parser (auto-applied if no queryParser option)
583
+ * defineResource({ name: 'product', adapter: ... });
584
+ *
585
+ * // Use MongoKit's QueryParser (recommended for MongoDB - has $lookup, aggregations, etc.)
586
+ * import { QueryParser } from '@classytic/mongokit';
587
+ * defineResource({
588
+ * name: 'product',
589
+ * adapter: ...,
590
+ * queryParser: new QueryParser(),
591
+ * });
592
+ *
593
+ * // Use custom parser for SQL databases
594
+ * defineResource({
595
+ * name: 'user',
596
+ * adapter: ...,
597
+ * queryParser: new PgQueryParser(),
598
+ * });
599
+ */
600
+
601
+ interface ArcQueryParserOptions {
602
+ /** Maximum allowed limit value (default: 1000) */
603
+ maxLimit?: number;
604
+ /** Default limit for pagination (default: 20) */
605
+ defaultLimit?: number;
606
+ /** Maximum regex pattern length (default: 500) */
607
+ maxRegexLength?: number;
608
+ /** Maximum search query length (default: 200) */
609
+ maxSearchLength?: number;
610
+ /** Maximum filter nesting depth (default: 10) */
611
+ maxFilterDepth?: number;
612
+ }
613
+ /**
614
+ * Arc's default query parser
615
+ *
616
+ * Converts URL query parameters to a structured query format:
617
+ * - Pagination: ?page=1&limit=20
618
+ * - Sorting: ?sort=-createdAt,name (- prefix = descending)
619
+ * - Filtering: ?status=active&price[gte]=100&price[lte]=500
620
+ * - Search: ?search=keyword
621
+ * - Populate: ?populate=author,category
622
+ * - Field selection: ?select=name,price,status
623
+ * - Keyset pagination: ?after=cursor_value
624
+ *
625
+ * For advanced MongoDB features ($lookup, aggregations), use MongoKit's QueryParser.
626
+ */
627
+ declare class ArcQueryParser implements QueryParserInterface {
628
+ private readonly maxLimit;
629
+ private readonly defaultLimit;
630
+ private readonly maxRegexLength;
631
+ private readonly maxSearchLength;
632
+ private readonly maxFilterDepth;
633
+ /** Supported filter operators */
634
+ private readonly operators;
635
+ constructor(options?: ArcQueryParserOptions);
636
+ /**
637
+ * Parse URL query parameters into structured query options
638
+ */
639
+ parse(query: Record<string, unknown> | null | undefined): ParsedQuery;
640
+ private parseNumber;
641
+ private parseString;
642
+ private parseSort;
643
+ private parseSearch;
644
+ private parseSelect;
645
+ private parseFilters;
646
+ private parseFilterValue;
647
+ private coerceValue;
648
+ private sanitizeRegex;
649
+ }
650
+ /**
651
+ * Create a new ArcQueryParser instance
652
+ */
653
+ declare function createQueryParser(options?: ArcQueryParserOptions): ArcQueryParser;
654
+
655
+ export { ArcQueryParser, type ArcQueryParserOptions, CircuitBreaker, CircuitBreakerError, type CircuitBreakerOptions, CircuitBreakerRegistry, type CircuitBreakerStats, CircuitState, type JsonSchema, type StateMachine, type TransitionConfig, circuitBreakerRegistry, createCircuitBreaker, createQueryParser, createStateMachine, deleteResponse, errorResponseSchema, getListQueryParams, itemResponse, listResponse, mutationResponse, paginationSchema, queryParams, responses, successResponseSchema, wrapResponse };