@classytic/arc 2.3.0 → 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.
- package/README.md +187 -18
- package/bin/arc.js +11 -3
- package/dist/BaseController-CkM5dUh_.mjs +1031 -0
- package/dist/{EventTransport-BkUDYZEb.d.mts → EventTransport-wc5hSLik.d.mts} +1 -1
- package/dist/{HookSystem-BsGV-j2l.mjs → HookSystem-COkyWztM.mjs} +2 -3
- package/dist/{ResourceRegistry-7Ic20ZMw.mjs → ResourceRegistry-DeCIFlix.mjs} +8 -5
- package/dist/adapters/index.d.mts +3 -5
- package/dist/adapters/index.mjs +2 -3
- package/dist/{prisma-DJbMt3yf.mjs → adapters-DTC4Ug66.mjs} +45 -12
- package/dist/audit/index.d.mts +4 -7
- package/dist/audit/index.mjs +2 -29
- package/dist/audit/mongodb.d.mts +1 -4
- package/dist/audit/mongodb.mjs +2 -3
- package/dist/auth/index.d.mts +7 -9
- package/dist/auth/index.mjs +65 -63
- package/dist/auth/redis-session.d.mts +1 -1
- package/dist/auth/redis-session.mjs +1 -2
- package/dist/{betterAuthOpenApi-DjWDddNc.mjs → betterAuthOpenApi-lz0IRbXJ.mjs} +4 -6
- package/dist/cache/index.d.mts +23 -23
- package/dist/cache/index.mjs +4 -6
- package/dist/{caching-GSDJcA6-.mjs → caching-BSXB-Xr7.mjs} +2 -24
- package/dist/chunk-BpYLSNr0.mjs +14 -0
- package/dist/circuitBreaker-BOBOpN2w.mjs +284 -0
- package/dist/circuitBreaker-JP2GdJ4b.d.mts +206 -0
- package/dist/cli/commands/describe.mjs +24 -7
- package/dist/cli/commands/docs.mjs +6 -7
- package/dist/cli/commands/doctor.d.mts +10 -0
- package/dist/cli/commands/doctor.mjs +156 -0
- package/dist/cli/commands/generate.mjs +66 -17
- package/dist/cli/commands/init.mjs +315 -45
- package/dist/cli/commands/introspect.mjs +2 -4
- package/dist/cli/index.d.mts +1 -10
- package/dist/cli/index.mjs +4 -153
- package/dist/{constants-DdXFXQtN.mjs → constants-Cxde4rpC.mjs} +1 -2
- package/dist/core/index.d.mts +3 -5
- package/dist/core/index.mjs +5 -4
- package/dist/core-C1XCMtqM.mjs +185 -0
- package/dist/{createApp-CgKOPhA4.mjs → createApp-ByWNRsZj.mjs} +64 -35
- package/dist/{defineResource-DWbpJYtm.mjs → defineResource-D9aY5Cy6.mjs} +108 -1157
- package/dist/discovery/index.mjs +37 -5
- package/dist/docs/index.d.mts +6 -9
- package/dist/docs/index.mjs +3 -21
- package/dist/dynamic/index.d.mts +93 -0
- package/dist/dynamic/index.mjs +122 -0
- package/dist/{elevation-DSTbVvYj.mjs → elevation-BEdACOLB.mjs} +5 -36
- package/dist/{elevation-DGo5shaX.d.mts → elevation-Ca_yveIO.d.mts} +41 -7
- package/dist/{errorHandler-C3GY3_ow.mjs → errorHandler--zp54tGc.mjs} +3 -5
- package/dist/errorHandler-Do4vVQ1f.d.mts +139 -0
- package/dist/{errors-DBANPbGr.mjs → errors-rxhfP7Hf.mjs} +1 -2
- package/dist/{eventPlugin-BEOvaDqo.mjs → eventPlugin-Ba00swHF.mjs} +25 -27
- package/dist/{eventPlugin-H6wDDjGO.d.mts → eventPlugin-iGrSEmwJ.d.mts} +105 -5
- package/dist/events/index.d.mts +72 -7
- package/dist/events/index.mjs +216 -4
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis-stream-entry.mjs +19 -7
- package/dist/events/transports/redis.d.mts +1 -1
- package/dist/events/transports/redis.mjs +3 -4
- package/dist/factory/index.d.mts +23 -9
- package/dist/factory/index.mjs +48 -3
- package/dist/{fields-Bi_AVKSo.d.mts → fields-DFwdaWCq.d.mts} +1 -1
- package/dist/{fields-CTd_CrKr.mjs → fields-ipsbIRPK.mjs} +1 -2
- package/dist/hooks/index.d.mts +1 -3
- package/dist/hooks/index.mjs +2 -3
- package/dist/idempotency/index.d.mts +5 -5
- package/dist/idempotency/index.mjs +3 -7
- package/dist/idempotency/mongodb.d.mts +1 -1
- package/dist/idempotency/mongodb.mjs +4 -5
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/idempotency/redis.mjs +2 -5
- package/dist/{fastifyAdapter-6b_eRDBw.d.mts → index-BL8CaQih.d.mts} +56 -57
- package/dist/index-Diqcm14c.d.mts +369 -0
- package/dist/{prisma-Dy5S5F5i.d.mts → index-yhxyjqNb.d.mts} +4 -5
- package/dist/index.d.mts +100 -105
- package/dist/index.mjs +85 -58
- package/dist/integrations/event-gateway.d.mts +1 -1
- package/dist/integrations/event-gateway.mjs +8 -4
- package/dist/integrations/index.d.mts +4 -2
- package/dist/integrations/index.mjs +1 -1
- package/dist/integrations/jobs.d.mts +2 -2
- package/dist/integrations/jobs.mjs +63 -14
- package/dist/integrations/mcp/index.d.mts +219 -0
- package/dist/integrations/mcp/index.mjs +572 -0
- package/dist/integrations/mcp/testing.d.mts +53 -0
- package/dist/integrations/mcp/testing.mjs +104 -0
- package/dist/integrations/streamline.mjs +39 -19
- package/dist/integrations/webhooks.d.mts +56 -0
- package/dist/integrations/webhooks.mjs +139 -0
- package/dist/integrations/websocket-redis.d.mts +46 -0
- package/dist/integrations/websocket-redis.mjs +50 -0
- package/dist/integrations/websocket.d.mts +68 -2
- package/dist/integrations/websocket.mjs +96 -13
- package/dist/{interface-CSNjltAc.d.mts → interface-B4awm1RJ.d.mts} +2 -2
- package/dist/interface-DGmPxakH.d.mts +2213 -0
- package/dist/{keys-DhqDRxv3.mjs → keys-qcD-TVJl.mjs} +3 -4
- package/dist/{logger-ByrvQWZO.mjs → logger-Dz3j1ItV.mjs} +2 -4
- package/dist/{memory-B2v7KrCB.mjs → memory-Cb_7iy9e.mjs} +2 -4
- package/dist/metrics-Csh4nsvv.mjs +224 -0
- package/dist/migrations/index.mjs +3 -7
- package/dist/{mongodb-DNKEExbf.mjs → mongodb-BuQ7fNTg.mjs} +1 -4
- package/dist/{mongodb-ClykrfGo.d.mts → mongodb-CUpYfxfD.d.mts} +2 -3
- package/dist/{mongodb-Dg8O_gvd.d.mts → mongodb-bga9AbkD.d.mts} +2 -2
- package/dist/{openapi-9nB_kiuR.mjs → openapi-CBmZ6EQN.mjs} +4 -21
- package/dist/org/index.d.mts +12 -14
- package/dist/org/index.mjs +92 -119
- package/dist/org/types.d.mts +2 -2
- package/dist/org/types.mjs +1 -1
- package/dist/permissions/index.d.mts +4 -278
- package/dist/permissions/index.mjs +4 -579
- package/dist/permissions-CA5zg0yK.mjs +751 -0
- package/dist/plugins/index.d.mts +104 -107
- package/dist/plugins/index.mjs +203 -313
- package/dist/plugins/response-cache.mjs +4 -69
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +24 -11
- package/dist/{pluralize-CM-jZg7p.mjs → pluralize-CcT6qF0a.mjs} +12 -13
- package/dist/policies/index.d.mts +2 -2
- package/dist/policies/index.mjs +80 -83
- package/dist/presets/index.d.mts +26 -19
- package/dist/presets/index.mjs +2 -142
- package/dist/presets/multiTenant.d.mts +1 -4
- package/dist/presets/multiTenant.mjs +4 -6
- package/dist/presets-C9QXJV1u.mjs +422 -0
- package/dist/{queryCachePlugin-B6R0d4av.mjs → queryCachePlugin-ClosZdNS.mjs} +6 -27
- package/dist/{queryCachePlugin-Q6SYuHZ6.d.mts → queryCachePlugin-DcmETvcB.d.mts} +3 -3
- package/dist/queryParser-CgCtsjti.mjs +352 -0
- package/dist/{redis-UwjEp8Ea.d.mts → redis-CQ5YxMC5.d.mts} +2 -2
- package/dist/{redis-stream-CBg0upHI.d.mts → redis-stream-BW9UKLZM.d.mts} +9 -2
- package/dist/registry/index.d.mts +1 -4
- package/dist/registry/index.mjs +3 -4
- package/dist/{introspectionPlugin-B3JkrjwU.mjs → registry-I-ogLgL9.mjs} +1 -8
- package/dist/{requestContext-xi6OKBL-.mjs → requestContext-DYtmNpm5.mjs} +1 -3
- package/dist/resourceToTools-B6ZN9Ing.mjs +489 -0
- package/dist/rpc/index.d.mts +90 -0
- package/dist/rpc/index.mjs +248 -0
- package/dist/{schemaConverter-Dtg0Kt9T.mjs → schemaConverter-DjzHpFam.mjs} +1 -2
- package/dist/schemas/index.d.mts +30 -30
- package/dist/schemas/index.mjs +2 -4
- package/dist/scope/index.d.mts +13 -2
- package/dist/scope/index.mjs +18 -5
- package/dist/{sessionManager-D_iEHjQl.d.mts → sessionManager-wbkYj2HL.d.mts} +2 -2
- package/dist/{sse-DkqQ1uxb.mjs → sse-BkViJPlT.mjs} +4 -25
- package/dist/testing/index.d.mts +551 -567
- package/dist/testing/index.mjs +1744 -1799
- package/dist/{tracing-8CEbhF0w.d.mts → tracing-bz_U4EM1.d.mts} +6 -1
- package/dist/{typeGuards-DwxA1t_L.mjs → typeGuards-Cj5Rgvlg.mjs} +1 -2
- package/dist/types/index.d.mts +4 -946
- package/dist/types/index.mjs +2 -4
- package/dist/types-BJmgxNbF.d.mts +275 -0
- package/dist/{types-RLkFVgaw.d.mts → types-BNUccdcf.d.mts} +2 -2
- package/dist/{types-Beqn1Un7.mjs → types-C6TQjtdi.mjs} +30 -2
- package/dist/{types-tKwaViYB.d.mts → types-Dt0-AI6E.d.mts} +68 -27
- package/dist/{types-DelU6kln.mjs → types-ZUu_h0jp.mjs} +1 -2
- package/dist/utils/index.d.mts +254 -351
- package/dist/utils/index.mjs +7 -6
- package/dist/utils-Dc0WhlIl.mjs +594 -0
- package/dist/versioning-BzfeHmhj.mjs +37 -0
- package/package.json +44 -10
- package/skills/arc/SKILL.md +506 -0
- package/skills/arc/references/auth.md +250 -0
- package/skills/arc/references/events.md +272 -0
- package/skills/arc/references/integrations.md +385 -0
- package/skills/arc/references/mcp.md +386 -0
- package/skills/arc/references/production.md +610 -0
- package/skills/arc/references/testing.md +183 -0
- package/dist/audited-CGdLiSlE.mjs +0 -140
- package/dist/chunk-C7Uep-_p.mjs +0 -20
- package/dist/circuitBreaker-CSS2VvL6.mjs +0 -1109
- package/dist/errorHandler-CW3OOeYq.d.mts +0 -72
- package/dist/interface-BtdYtQUA.d.mts +0 -1114
- package/dist/presets-BTeYbw7h.d.mts +0 -57
- package/dist/presets-CeFtfDR8.mjs +0 -119
- /package/dist/{errors-DAWRdiYP.d.mts → errors-CPpvPHT0.d.mts} +0 -0
- /package/dist/{externalPaths-SyPF2tgK.d.mts → externalPaths-DpO-s7r8.d.mts} +0 -0
- /package/dist/{interface-DTbsvIWe.d.mts → interface-D_BWALyZ.d.mts} +0 -0
package/README.md
CHANGED
|
@@ -81,6 +81,23 @@ auth: false
|
|
|
81
81
|
|
|
82
82
|
**Decorates:** `app.authenticate`, `app.optionalAuthenticate`, `app.authorize`
|
|
83
83
|
|
|
84
|
+
### Token Revocation
|
|
85
|
+
|
|
86
|
+
Arc provides the `isRevoked` primitive — you implement the store (Redis, DB, Better Auth):
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
auth: {
|
|
90
|
+
type: 'jwt',
|
|
91
|
+
jwt: { secret: process.env.JWT_SECRET },
|
|
92
|
+
isRevoked: async (decoded) => {
|
|
93
|
+
// Redis set, DB lookup, or any async check
|
|
94
|
+
return await redis.sismember('revoked-tokens', decoded.jti ?? decoded.id);
|
|
95
|
+
},
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Fail-closed: if the revocation check throws, the token is rejected.
|
|
100
|
+
|
|
84
101
|
## Permissions
|
|
85
102
|
|
|
86
103
|
Function-based, composable:
|
|
@@ -221,6 +238,114 @@ await app.events.subscribe('order.*', async (event) => { ... });
|
|
|
221
238
|
|
|
222
239
|
CRUD events (`product.created`, `product.updated`, `product.deleted`) emit automatically.
|
|
223
240
|
|
|
241
|
+
### defineEvent — Typed Events with Schema Validation
|
|
242
|
+
|
|
243
|
+
Declare events with schemas for runtime validation and introspection:
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
import { defineEvent, createEventRegistry } from '@classytic/arc/events';
|
|
247
|
+
|
|
248
|
+
// Define typed events
|
|
249
|
+
const OrderCreated = defineEvent({
|
|
250
|
+
name: 'order.created',
|
|
251
|
+
version: 1,
|
|
252
|
+
description: 'Emitted when an order is placed',
|
|
253
|
+
schema: {
|
|
254
|
+
type: 'object',
|
|
255
|
+
properties: {
|
|
256
|
+
orderId: { type: 'string' },
|
|
257
|
+
total: { type: 'number' },
|
|
258
|
+
currency: { type: 'string' },
|
|
259
|
+
},
|
|
260
|
+
required: ['orderId', 'total'],
|
|
261
|
+
},
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// Type-safe event creation
|
|
265
|
+
const event = OrderCreated.create({ orderId: 'o-1', total: 100 }, { userId: 'user-1' });
|
|
266
|
+
await app.events.publish(event.type, event.payload, event.meta);
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
**Event Registry** — catalog + auto-validation on publish:
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
const registry = createEventRegistry();
|
|
273
|
+
registry.register(OrderCreated);
|
|
274
|
+
registry.register(OrderShipped);
|
|
275
|
+
|
|
276
|
+
// Wire into eventPlugin — validates payloads on publish
|
|
277
|
+
const app = await createApp({
|
|
278
|
+
arcPlugins: {
|
|
279
|
+
events: { registry, validateMode: 'warn' },
|
|
280
|
+
// 'warn' (default): log warning, still publish
|
|
281
|
+
// 'reject': throw error, do NOT publish
|
|
282
|
+
// 'off': registry is introspection-only
|
|
283
|
+
},
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
// Introspect at runtime
|
|
287
|
+
app.events.registry?.catalog();
|
|
288
|
+
// → [{ name: 'order.created', version: 1, schema: {...} }, ...]
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
Export the registry alongside resources for `arc describe` to auto-detect:
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
// src/events.ts
|
|
295
|
+
export const eventRegistry = createEventRegistry();
|
|
296
|
+
eventRegistry.register(OrderCreated);
|
|
297
|
+
eventRegistry.register(OrderShipped);
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Event Transports
|
|
301
|
+
|
|
302
|
+
| Transport | Import | Use Case |
|
|
303
|
+
|-----------|--------|----------|
|
|
304
|
+
| `MemoryEventTransport` | `@classytic/arc/events` | Development, testing, single-instance |
|
|
305
|
+
| `RedisEventTransport` | `@classytic/arc/events/redis` | Multi-instance pub/sub (fan-out) |
|
|
306
|
+
| `RedisStreamTransport` | `@classytic/arc/events/redis-stream` | Ordered events with consumer groups |
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
// Redis Pub/Sub
|
|
310
|
+
import { RedisEventTransport } from '@classytic/arc/events/redis';
|
|
311
|
+
const transport = new RedisEventTransport(redis, { channel: 'arc-events' });
|
|
312
|
+
|
|
313
|
+
// Redis Streams (ordered, durable)
|
|
314
|
+
import { RedisStreamTransport } from '@classytic/arc/events/redis-stream';
|
|
315
|
+
const transport = new RedisStreamTransport(redis, { stream: 'arc-events' });
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
**Behavioral contract:**
|
|
319
|
+
- **Memory**: Handlers execute sequentially (ordered, awaited)
|
|
320
|
+
- **Redis Pub/Sub**: Handlers fire-and-forget (unordered, fan-out)
|
|
321
|
+
- **Redis Streams**: Ordered delivery with consumer group acknowledgment
|
|
322
|
+
|
|
323
|
+
### Retry & Dead Letter Queue
|
|
324
|
+
|
|
325
|
+
```typescript
|
|
326
|
+
import { withRetry, createDeadLetterPublisher } from '@classytic/arc/events';
|
|
327
|
+
|
|
328
|
+
// Per-handler retry with exponential backoff
|
|
329
|
+
await app.events.subscribe('order.created', withRetry(
|
|
330
|
+
async (event) => { await sendConfirmationEmail(event.payload); },
|
|
331
|
+
{
|
|
332
|
+
maxRetries: 3,
|
|
333
|
+
backoffMs: 1000,
|
|
334
|
+
onDead: createDeadLetterPublisher(app.events), // publishes to $deadLetter channel
|
|
335
|
+
},
|
|
336
|
+
));
|
|
337
|
+
|
|
338
|
+
// Or configure auto-retry for ALL handlers via plugin
|
|
339
|
+
const app = await createApp({
|
|
340
|
+
arcPlugins: {
|
|
341
|
+
events: {
|
|
342
|
+
retry: { maxRetries: 3, backoffMs: 1000 },
|
|
343
|
+
deadLetterQueue: { store: async (event, errors) => { /* custom DLQ */ } },
|
|
344
|
+
},
|
|
345
|
+
},
|
|
346
|
+
});
|
|
347
|
+
```
|
|
348
|
+
|
|
224
349
|
## Factory — createApp()
|
|
225
350
|
|
|
226
351
|
```typescript
|
|
@@ -282,6 +407,7 @@ await app.register(websocketPlugin, {
|
|
|
282
407
|
auth: true, // fail-closed: throws if authenticate not registered
|
|
283
408
|
resources: ['product', 'order'],
|
|
284
409
|
roomPolicy: (client, room) => ['product', 'order'].includes(room),
|
|
410
|
+
reauthInterval: 300000, // re-validate token every 5 min (0 = disabled)
|
|
285
411
|
maxMessageBytes: 16384, // 16KB message size cap
|
|
286
412
|
maxSubscriptionsPerClient: 100, // prevent resource exhaustion
|
|
287
413
|
});
|
|
@@ -296,6 +422,49 @@ await app.register(eventGatewayPlugin, {
|
|
|
296
422
|
});
|
|
297
423
|
```
|
|
298
424
|
|
|
425
|
+
## Pipeline — Guards, Transforms, Interceptors
|
|
426
|
+
|
|
427
|
+
Functional composition for cross-cutting concerns:
|
|
428
|
+
|
|
429
|
+
```typescript
|
|
430
|
+
import { pipe, guard, transform, intercept } from '@classytic/arc';
|
|
431
|
+
|
|
432
|
+
const isActive = guard('isActive', (ctx) => ctx.query?.filters?.isActive !== false);
|
|
433
|
+
const slugify = transform('slugify', (ctx) => ({ ...ctx, body: { ...ctx.body, slug: toSlug(ctx.body.name) } }));
|
|
434
|
+
const timing = intercept('timing', async (ctx, next) => {
|
|
435
|
+
const start = Date.now();
|
|
436
|
+
const result = await next();
|
|
437
|
+
console.log(`${ctx.resource}.${ctx.operation}: ${Date.now() - start}ms`);
|
|
438
|
+
return result;
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
defineResource({
|
|
442
|
+
name: 'product',
|
|
443
|
+
pipe: pipe(isActive, slugify, timing),
|
|
444
|
+
// or per-operation: pipe: { create: pipe(slugify), list: pipe(timing) }
|
|
445
|
+
});
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
## Utilities
|
|
449
|
+
|
|
450
|
+
```typescript
|
|
451
|
+
// Circuit Breaker — fault tolerance for external service calls
|
|
452
|
+
import { createCircuitBreaker } from '@classytic/arc/utils';
|
|
453
|
+
const paymentBreaker = createCircuitBreaker(
|
|
454
|
+
async (amount) => stripe.charges.create({ amount }),
|
|
455
|
+
{ name: 'stripe', failureThreshold: 5, resetTimeout: 30000, fallback: async () => cached },
|
|
456
|
+
);
|
|
457
|
+
|
|
458
|
+
// State Machine — workflow validation
|
|
459
|
+
import { createStateMachine } from '@classytic/arc/utils';
|
|
460
|
+
const orderState = createStateMachine('Order', {
|
|
461
|
+
approve: ['pending', 'draft'],
|
|
462
|
+
cancel: ['pending', 'approved'],
|
|
463
|
+
fulfill: { from: ['approved'], to: 'fulfilled', guard: ({ data }) => data.paid },
|
|
464
|
+
});
|
|
465
|
+
orderState.assert('approve', currentStatus); // throws if invalid transition
|
|
466
|
+
```
|
|
467
|
+
|
|
299
468
|
## Integrations
|
|
300
469
|
|
|
301
470
|
All separate subpath imports — only loaded when used:
|
|
@@ -334,6 +503,19 @@ npx @classytic/arc introspect --entry ./dist/index.js # Show resources
|
|
|
334
503
|
npx @classytic/arc doctor # Health check
|
|
335
504
|
```
|
|
336
505
|
|
|
506
|
+
`arc describe` auto-detects exported `EventRegistry` and includes the event catalog in output:
|
|
507
|
+
|
|
508
|
+
```json
|
|
509
|
+
{
|
|
510
|
+
"$schema": "arc-describe/v1",
|
|
511
|
+
"resources": [...],
|
|
512
|
+
"eventCatalog": [
|
|
513
|
+
{ "name": "order.created", "version": 1, "hasSchema": true, "schemaFields": ["orderId", "total"], "requiredFields": ["orderId", "total"] }
|
|
514
|
+
],
|
|
515
|
+
"stats": { "totalResources": 5, "totalRoutes": 28, "totalCatalogedEvents": 3 }
|
|
516
|
+
}
|
|
517
|
+
```
|
|
518
|
+
|
|
337
519
|
## Subpath Imports
|
|
338
520
|
|
|
339
521
|
| Import | Purpose |
|
|
@@ -342,12 +524,12 @@ npx @classytic/arc doctor # Health check
|
|
|
342
524
|
| `@classytic/arc/factory` | `createApp()`, presets |
|
|
343
525
|
| `@classytic/arc/cache` | `MemoryCacheStore`, `RedisCacheStore`, `QueryCache` |
|
|
344
526
|
| `@classytic/arc/auth` | Auth plugin, Better Auth adapter, session manager |
|
|
345
|
-
| `@classytic/arc/events` | Event plugin,
|
|
346
|
-
| `@classytic/arc/events/redis` | Redis event transport |
|
|
347
|
-
| `@classytic/arc/events/redis-stream` | Redis Streams transport |
|
|
527
|
+
| `@classytic/arc/events` | Event plugin, transports, `defineEvent`, `createEventRegistry` |
|
|
528
|
+
| `@classytic/arc/events/redis` | Redis Pub/Sub event transport |
|
|
529
|
+
| `@classytic/arc/events/redis-stream` | Redis Streams event transport |
|
|
348
530
|
| `@classytic/arc/plugins` | Health, graceful shutdown, request ID, SSE, caching |
|
|
349
531
|
| `@classytic/arc/plugins/tracing` | OpenTelemetry |
|
|
350
|
-
| `@classytic/arc/permissions` | All permission functions |
|
|
532
|
+
| `@classytic/arc/permissions` | All permission functions, role hierarchy |
|
|
351
533
|
| `@classytic/arc/scope` | Request scope helpers (`isMember`, `isElevated`, `getOrgId`) |
|
|
352
534
|
| `@classytic/arc/org` | Organization module |
|
|
353
535
|
| `@classytic/arc/hooks` | Lifecycle hooks |
|
|
@@ -364,20 +546,7 @@ npx @classytic/arc doctor # Health check
|
|
|
364
546
|
| `@classytic/arc/integrations/event-gateway` | Unified SSE + WebSocket gateway |
|
|
365
547
|
| `@classytic/arc/integrations/streamline` | Workflow orchestration |
|
|
366
548
|
| `@classytic/arc/docs` | OpenAPI generation |
|
|
367
|
-
| `@classytic/arc/cli` | CLI commands |
|
|
368
|
-
|
|
369
|
-
## Documentation
|
|
370
|
-
|
|
371
|
-
- [Setup](docs/getting-started/setup.md) — Project setup
|
|
372
|
-
- [Core Concepts](docs/getting-started/core.md) — Resources, controllers, adapters
|
|
373
|
-
- [Authentication](docs/getting-started/auth.md) — JWT, Better Auth, custom auth
|
|
374
|
-
- [Permissions](docs/getting-started/permissions.md) — RBAC, ABAC, field-level
|
|
375
|
-
- [Presets](docs/getting-started/presets.md) — softDelete, multiTenant, tree, etc.
|
|
376
|
-
- [Organizations](docs/getting-started/org.md) — Multi-tenant SaaS
|
|
377
|
-
- [Factory](docs/production-ops/factory.md) — createApp() and environment presets
|
|
378
|
-
- [Events](docs/production-ops/events.md) — Domain events and transports
|
|
379
|
-
- [Plugins](docs/production-ops/plugins.md) — Health, caching, SSE, tracing
|
|
380
|
-
- [Hooks](docs/framework-extension/hooks.md) — Lifecycle hooks
|
|
549
|
+
| `@classytic/arc/cli` | CLI commands (programmatic) |
|
|
381
550
|
|
|
382
551
|
## License
|
|
383
552
|
|
package/bin/arc.js
CHANGED
|
@@ -98,9 +98,10 @@ async function main() {
|
|
|
98
98
|
process.exit(1);
|
|
99
99
|
}
|
|
100
100
|
} catch (err) {
|
|
101
|
-
|
|
101
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
102
|
+
console.error(`Error: ${message}`);
|
|
102
103
|
if (process.env.DEBUG) {
|
|
103
|
-
console.error(err.stack);
|
|
104
|
+
console.error(err instanceof Error ? err.stack : err);
|
|
104
105
|
}
|
|
105
106
|
process.exit(1);
|
|
106
107
|
}
|
|
@@ -119,9 +120,11 @@ async function handleInit(args) {
|
|
|
119
120
|
async function handleGenerate(type, args) {
|
|
120
121
|
if (!type) {
|
|
121
122
|
console.error('Missing type argument');
|
|
122
|
-
console.log('\nUsage: arc generate <resource|controller|model|repository|schemas> <name>');
|
|
123
|
+
console.log('\nUsage: arc generate <resource|controller|model|repository|schemas|mcp> <name>');
|
|
123
124
|
console.log('\nExamples:');
|
|
124
125
|
console.log(' arc generate resource product');
|
|
126
|
+
console.log(' arc generate resource product --mcp');
|
|
127
|
+
console.log(' arc generate mcp product');
|
|
125
128
|
console.log(' arc g r invoice');
|
|
126
129
|
process.exit(1);
|
|
127
130
|
}
|
|
@@ -133,6 +136,7 @@ async function handleGenerate(type, args) {
|
|
|
133
136
|
m: 'model',
|
|
134
137
|
repo: 'repository',
|
|
135
138
|
s: 'schemas',
|
|
139
|
+
mcp: 'mcp',
|
|
136
140
|
resource: 'resource',
|
|
137
141
|
controller: 'controller',
|
|
138
142
|
model: 'model',
|
|
@@ -185,6 +189,7 @@ async function handleDoctor(rawArgs) {
|
|
|
185
189
|
await doctor(rawArgs);
|
|
186
190
|
}
|
|
187
191
|
|
|
192
|
+
|
|
188
193
|
// ============================================================================
|
|
189
194
|
// Option Parsing
|
|
190
195
|
// ============================================================================
|
|
@@ -346,11 +351,14 @@ GENERATE SUBCOMMANDS
|
|
|
346
351
|
model, m Generate model only
|
|
347
352
|
repository, repo Generate repository only
|
|
348
353
|
schemas, s Generate schemas only
|
|
354
|
+
mcp Generate MCP tools file only
|
|
349
355
|
|
|
350
356
|
GENERATE NOTES
|
|
351
357
|
- Auto-detects TypeScript/JavaScript from tsconfig.json
|
|
352
358
|
- Files are created in src/resources/<name>/ directory
|
|
353
359
|
- Uses prefixed filenames: <name>.model.ts, <name>.repository.ts, etc.
|
|
360
|
+
- Use --mcp flag with resource to include MCP tools file: arc g r product --mcp
|
|
361
|
+
- Set "mcp": true in .arcrc to always generate MCP tools
|
|
354
362
|
|
|
355
363
|
EXAMPLES
|
|
356
364
|
# Initialize a new project (interactive prompts)
|