@classytic/arc 2.8.0 → 2.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +10 -1
  2. package/dist/{BaseController-CpMfCXdn.mjs → BaseController-DAGGc5Xn.mjs} +76 -25
  3. package/dist/{EventTransport-n1KBxC_N.d.mts → EventTransport-CLXJUzyT.d.mts} +37 -1
  4. package/dist/{ResourceRegistry-BOtJuRCs.mjs → ResourceRegistry-Dtcojmu8.mjs} +14 -2
  5. package/dist/adapters/index.d.mts +2 -2
  6. package/dist/adapters/index.mjs +1 -1
  7. package/dist/{adapters-BxGgSHjj.mjs → adapters-BBqAVvPK.mjs} +11 -0
  8. package/dist/auth/index.d.mts +1 -1
  9. package/dist/auth/index.mjs +3 -3
  10. package/dist/{betterAuthOpenApi-CHCIuA-p.mjs → betterAuthOpenApi-C5lDyRH2.mjs} +1 -1
  11. package/dist/cli/commands/docs.mjs +2 -2
  12. package/dist/cli/commands/introspect.mjs +1 -1
  13. package/dist/core/index.d.mts +2 -2
  14. package/dist/core/index.mjs +4 -4
  15. package/dist/{core-BfrfxNqO.mjs → core-CrLDuqoT.mjs} +1 -1
  16. package/dist/{createActionRouter-CbkIAaGh.mjs → createActionRouter-Df1BuawX.mjs} +87 -21
  17. package/dist/{createApp-Cy8eUNKQ.mjs → createApp-p2OThysU.mjs} +2 -2
  18. package/dist/{defineResource-CovBXvTB.mjs → defineResource-CqeUltrW.mjs} +19 -7
  19. package/dist/docs/index.d.mts +1 -1
  20. package/dist/docs/index.mjs +1 -1
  21. package/dist/dynamic/index.d.mts +1 -1
  22. package/dist/dynamic/index.mjs +1 -1
  23. package/dist/{errorHandler-BW08lEiy.mjs → errorHandler-Cw34h_om.mjs} +1 -1
  24. package/dist/{errorHandler-BeN-ERN7.d.mts → errorHandler-DJ7OAB2V.d.mts} +1 -1
  25. package/dist/{eventPlugin-CAOWMQS8.d.mts → eventPlugin-Cdjwo0Gv.d.mts} +1 -1
  26. package/dist/{eventPlugin-x4jo3sG0.mjs → eventPlugin-XijlQmlL.mjs} +19 -1
  27. package/dist/events/index.d.mts +399 -28
  28. package/dist/events/index.mjs +345 -29
  29. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  30. package/dist/events/transports/redis.d.mts +1 -1
  31. package/dist/factory/index.d.mts +1 -1
  32. package/dist/factory/index.mjs +1 -1
  33. package/dist/hooks/index.d.mts +1 -1
  34. package/dist/{index-BpMhrFgn.d.mts → index-0zj73o2U.d.mts} +1 -1
  35. package/dist/{index-qct60lnl.d.mts → index-DadoLP51.d.mts} +35 -3
  36. package/dist/index.d.mts +4 -4
  37. package/dist/index.mjs +7 -7
  38. package/dist/integrations/event-gateway.d.mts +1 -1
  39. package/dist/integrations/index.d.mts +1 -1
  40. package/dist/integrations/mcp/index.d.mts +2 -2
  41. package/dist/integrations/mcp/index.mjs +1 -1
  42. package/dist/integrations/mcp/testing.d.mts +1 -1
  43. package/dist/integrations/mcp/testing.mjs +1 -1
  44. package/dist/{interface-IJqN3pXK.d.mts → interface-CS6d7HiB.d.mts} +549 -107
  45. package/dist/{openapi-AYLVjqVe.mjs → openapi-q6rNKfZy.mjs} +49 -2
  46. package/dist/org/index.d.mts +1 -1
  47. package/dist/plugins/index.d.mts +2 -2
  48. package/dist/plugins/index.mjs +3 -3
  49. package/dist/plugins/tracing-entry.mjs +1 -1
  50. package/dist/presets/index.d.mts +3 -3
  51. package/dist/presets/multiTenant.d.mts +1 -1
  52. package/dist/{redis-stream-CF1lrKVk.d.mts → redis-stream-BgrYzpeq.d.mts} +1 -1
  53. package/dist/registry/index.d.mts +1 -1
  54. package/dist/registry/index.mjs +1 -1
  55. package/dist/{resourceToTools-C_1SMiCz.mjs → resourceToTools-DNNWnZtx.mjs} +193 -63
  56. package/dist/rpc/index.mjs +1 -1
  57. package/dist/testing/index.d.mts +2 -2
  58. package/dist/testing/index.mjs +1 -1
  59. package/dist/types/index.d.mts +2 -2
  60. package/dist/{types-gUxAIZHp.d.mts → types-BlOuKTPw.d.mts} +4 -4
  61. package/dist/{types-Ct0PUUSp.d.mts → types-D3b7hA00.d.mts} +1 -1
  62. package/dist/utils/index.d.mts +2 -14
  63. package/dist/utils/index.mjs +5 -5
  64. package/dist/{utils-B-l6410F.mjs → utils-7sJ8X83I.mjs} +1 -13
  65. package/package.json +4 -3
  66. /package/dist/{circuitBreaker-l18oRgL5.mjs → circuitBreaker-cmi5XDv5.mjs} +0 -0
  67. /package/dist/{errors-Cg58SLNi.mjs → errors-BF2bIOIS.mjs} +0 -0
  68. /package/dist/{requestContext-xHIKedG6.mjs → requestContext-DYvHl113.mjs} +0 -0
  69. /package/dist/{schemaConverter-Y5EejTnJ.mjs → schemaConverter-OxfCshus.mjs} +0 -0
@@ -1,4 +1,4 @@
1
- import { a as MemoryEventTransport, i as withRetry, o as createEvent, r as createDeadLetterPublisher, t as eventPlugin } from "../eventPlugin-x4jo3sG0.mjs";
1
+ import { a as MemoryEventTransport, i as withRetry, o as createEvent, r as createDeadLetterPublisher, t as eventPlugin } from "../eventPlugin-XijlQmlL.mjs";
2
2
  //#region src/events/defineEvent.ts
3
3
  /**
4
4
  * defineEvent — Typed Event Definitions with Optional Schema Validation
@@ -224,52 +224,235 @@ const CACHE_EVENTS = Object.freeze({
224
224
  });
225
225
  //#endregion
226
226
  //#region src/events/outbox.ts
227
- /** Default outbox retention — acknowledged events older than this are eligible for purge */
227
+ /** Default outbox retention — delivered events older than this are eligible for purge */
228
228
  const DEFAULT_OUTBOX_RETENTION_MS = 10080 * 60 * 1e3;
229
+ const DEFAULT_LEASE_MS = 3e4;
230
+ /**
231
+ * Thrown by a store when `acknowledge` / `fail` is called by a consumer that
232
+ * does not own the event's current lease.
233
+ *
234
+ * Stores that enforce lease ownership MUST throw this (not silently return)
235
+ * so {@link EventOutbox} can detect the mismatch and avoid over-counting
236
+ * successful deliveries. {@link EventOutbox.relay} catches it and reports
237
+ * via {@link EventOutboxOptions.onError} instead of counting as relayed.
238
+ */
239
+ var OutboxOwnershipError = class extends Error {
240
+ eventId;
241
+ attemptedBy;
242
+ currentOwner;
243
+ constructor(eventId, attemptedBy, currentOwner) {
244
+ super(`Outbox ownership mismatch for event "${eventId}": attempted by "${attemptedBy}", current owner is "${currentOwner ?? "none"}". The lease may have expired and been reclaimed by another worker.`);
245
+ this.name = "OutboxOwnershipError";
246
+ this.eventId = eventId;
247
+ this.attemptedBy = attemptedBy;
248
+ this.currentOwner = currentOwner;
249
+ }
250
+ };
251
+ /** Thrown by {@link EventOutbox.store} when an event is missing `type` or `meta.id`. */
252
+ var InvalidOutboxEventError = class extends Error {
253
+ constructor(reason) {
254
+ super(`Invalid outbox event: ${reason}`);
255
+ this.name = "InvalidOutboxEventError";
256
+ }
257
+ };
229
258
  var EventOutbox = class {
230
259
  _store;
231
260
  _transport;
232
261
  _batchSize;
262
+ _consumerId;
263
+ _leaseMs;
264
+ _onError;
265
+ _usePublishMany;
233
266
  constructor(opts) {
234
267
  this._store = opts.store;
235
268
  this._transport = opts.transport;
236
269
  this._batchSize = opts.batchSize ?? 100;
270
+ this._consumerId = opts.consumerId ?? `relay-${Math.random().toString(36).slice(2, 10)}`;
271
+ this._leaseMs = opts.leaseMs ?? DEFAULT_LEASE_MS;
272
+ this._onError = opts.onError;
273
+ this._usePublishMany = opts.usePublishMany ?? true;
274
+ }
275
+ /** Unique consumer ID used for lease ownership when the store supports claims */
276
+ get consumerId() {
277
+ return this._consumerId;
237
278
  }
238
- /** Store event in outbox (call within your DB transaction) */
239
- async store(event) {
240
- await this._store.save(event);
279
+ /**
280
+ * Store event in outbox.
281
+ *
282
+ * Validates that `event.type` and `event.meta.id` are present — throws
283
+ * {@link InvalidOutboxEventError} otherwise, so corrupt rows can never
284
+ * be persisted via this API.
285
+ *
286
+ * Pass `options.session` to participate in a host-managed DB transaction
287
+ * (store must support session-aware writes). Other options (`visibleAt`,
288
+ * `dedupeKey`, `partitionKey`, `headers`) are forwarded to stores that
289
+ * implement them and ignored otherwise.
290
+ */
291
+ async store(event, options) {
292
+ if (!event || typeof event !== "object") throw new InvalidOutboxEventError("event is not an object");
293
+ if (!event.type || typeof event.type !== "string") throw new InvalidOutboxEventError("event.type is required");
294
+ if (!event.meta?.id || typeof event.meta.id !== "string") throw new InvalidOutboxEventError("event.meta.id is required");
295
+ await this._store.save(event, options);
296
+ }
297
+ _reportError(kind, error, event) {
298
+ if (!this._onError) return;
299
+ const err = error instanceof Error ? error : new Error(String(error));
300
+ try {
301
+ this._onError({
302
+ kind,
303
+ event,
304
+ error: err
305
+ });
306
+ } catch {}
241
307
  }
242
308
  /**
243
- * Relay pending events to transport.
309
+ * Relay pending events to transport and return the number of successful
310
+ * publish+acknowledge pairs.
244
311
  *
245
- * Processes events in FIFO order up to `batchSize`. Stops on the first
246
- * transport failure remaining events stay pending for the next relay call.
312
+ * For richer observability (per-kind counts, publishMany detection, etc.)
313
+ * use {@link relayBatch} which returns a {@link RelayResult}. This method
314
+ * is the backward-compatible shortcut that returns just the count.
247
315
  *
248
- * @returns Number of successfully published events in this batch
316
+ * @returns Number of successfully published AND acknowledged events
249
317
  */
250
318
  async relay() {
251
- if (!this._transport) return 0;
252
- const pending = await this._store.getPending(this._batchSize);
253
- let relayed = 0;
319
+ return (await this.relayBatch()).relayed;
320
+ }
321
+ /**
322
+ * Relay a batch of pending events to the transport and return a rich
323
+ * {@link RelayResult} describing the outcome of each event.
324
+ *
325
+ * Behavior summary:
326
+ *
327
+ * - **Claim path**: uses {@link OutboxStore.claimPending} when the store
328
+ * supports it (safe for multi-worker relay) or falls back to
329
+ * {@link OutboxStore.getPending} (single-worker only).
330
+ *
331
+ * - **Publish path**: if the transport implements
332
+ * {@link EventTransport.publishMany} and `usePublishMany` is not disabled,
333
+ * the entire batch is sent in one call. Otherwise each event is published
334
+ * individually. Either way, per-event outcomes are tracked.
335
+ *
336
+ * - **Failure path**: if the store implements `fail`, per-event failures
337
+ * are reported via `store.fail(...)` and the batch continues. Without
338
+ * `fail`, the batch stops on the first failure (legacy behavior).
339
+ *
340
+ * - **Malformed events**: events missing `type` or `meta.id` abort the
341
+ * batch — a well-behaved store must never return them (see
342
+ * {@link OutboxStore} semantics #6). The error is reported via `onError`.
343
+ *
344
+ * - **Ownership mismatches**: if `acknowledge`/`fail` throws
345
+ * {@link OutboxOwnershipError} (our lease expired and another worker
346
+ * claimed the event), the event is NOT counted as relayed. The other
347
+ * worker will re-publish — at-least-once semantics preserved.
348
+ *
349
+ * @returns Per-kind outcome counts for the batch
350
+ */
351
+ async relayBatch() {
352
+ const empty = {
353
+ relayed: 0,
354
+ attempted: 0,
355
+ publishFailed: 0,
356
+ ackFailed: 0,
357
+ ownershipMismatches: 0,
358
+ malformed: 0,
359
+ failHookErrors: 0,
360
+ usedPublishMany: false
361
+ };
362
+ if (!this._transport) return empty;
363
+ const pending = this._store.claimPending ? await this._store.claimPending({
364
+ limit: this._batchSize,
365
+ consumerId: this._consumerId,
366
+ leaseMs: this._leaseMs
367
+ }) : await this._store.getPending(this._batchSize);
368
+ const valid = [];
369
+ let malformed = 0;
254
370
  for (const event of pending) {
255
- if (!event.type || !event.meta?.id) {
256
- if (event.meta?.id) await this._store.acknowledge(event.meta.id);
371
+ if (!event || !event.type || !event.meta?.id) {
372
+ this._reportError("malformed_event", new InvalidOutboxEventError("store returned event missing type or meta.id — batch aborted"), event);
373
+ malformed++;
374
+ break;
375
+ }
376
+ valid.push(event);
377
+ }
378
+ const counts = {
379
+ relayed: 0,
380
+ publishFailed: 0,
381
+ ackFailed: 0,
382
+ ownershipMismatches: 0,
383
+ failHookErrors: 0
384
+ };
385
+ const canPublishMany = this._usePublishMany && typeof this._transport.publishMany === "function";
386
+ const canFail = typeof this._store.fail === "function";
387
+ let publishOutcomes;
388
+ if (canPublishMany && valid.length > 0) try {
389
+ const result = await this._transport.publishMany(valid);
390
+ publishOutcomes = new Map(result);
391
+ } catch (batchErr) {
392
+ publishOutcomes = /* @__PURE__ */ new Map();
393
+ const err = batchErr instanceof Error ? batchErr : new Error(String(batchErr));
394
+ for (const ev of valid) publishOutcomes.set(ev.meta.id, err);
395
+ }
396
+ else {
397
+ publishOutcomes = /* @__PURE__ */ new Map();
398
+ for (const event of valid) try {
399
+ await this._transport.publish(event);
400
+ publishOutcomes.set(event.meta.id, null);
401
+ } catch (err) {
402
+ publishOutcomes.set(event.meta.id, err instanceof Error ? err : new Error(String(err)));
403
+ if (!canFail) break;
404
+ }
405
+ }
406
+ let stopBatch = false;
407
+ for (const event of valid) {
408
+ if (stopBatch) break;
409
+ const publishErr = publishOutcomes.get(event.meta.id);
410
+ if (publishErr instanceof Error) {
411
+ counts.publishFailed++;
412
+ this._reportError("publish_failed", publishErr, event);
413
+ if (!canFail) {
414
+ stopBatch = true;
415
+ continue;
416
+ }
417
+ try {
418
+ await this._store.fail(event.meta.id, normalizeError(publishErr), { consumerId: this._consumerId });
419
+ } catch (failErr) {
420
+ if (failErr instanceof OutboxOwnershipError) {
421
+ counts.ownershipMismatches++;
422
+ this._reportError("ownership_mismatch", failErr, event);
423
+ } else {
424
+ counts.failHookErrors++;
425
+ this._reportError("fail_failed", failErr, event);
426
+ }
427
+ }
257
428
  continue;
258
429
  }
259
430
  try {
260
- await this._transport.publish(event);
261
- await this._store.acknowledge(event.meta.id);
262
- relayed++;
263
- } catch {
264
- break;
431
+ await this._store.acknowledge(event.meta.id, { consumerId: this._consumerId });
432
+ counts.relayed++;
433
+ } catch (ackErr) {
434
+ counts.ackFailed++;
435
+ if (ackErr instanceof OutboxOwnershipError) {
436
+ counts.ownershipMismatches++;
437
+ this._reportError("ownership_mismatch", ackErr, event);
438
+ } else this._reportError("acknowledge_failed", ackErr, event);
265
439
  }
266
440
  }
267
- return relayed;
441
+ return {
442
+ relayed: counts.relayed,
443
+ attempted: valid.length,
444
+ publishFailed: counts.publishFailed,
445
+ ackFailed: counts.ackFailed,
446
+ ownershipMismatches: counts.ownershipMismatches,
447
+ malformed,
448
+ failHookErrors: counts.failHookErrors,
449
+ usedPublishMany: canPublishMany && valid.length > 0
450
+ };
268
451
  }
269
452
  /**
270
- * Purge old acknowledged events from the outbox store.
453
+ * Purge old **delivered** events from the outbox store.
271
454
  * Delegates to `store.purge()` if implemented; no-op otherwise.
272
- * @param olderThanMs - Remove events acknowledged more than this many ms ago (default: 7 days)
455
+ * @param olderThanMs - Remove events delivered more than this many ms ago (default: 7 days)
273
456
  * @returns Number of purged events, or 0 if store doesn't support purge
274
457
  */
275
458
  async purge(olderThanMs = DEFAULT_OUTBOX_RETENTION_MS) {
@@ -277,17 +460,150 @@ var EventOutbox = class {
277
460
  return this._store.purge(olderThanMs);
278
461
  }
279
462
  };
463
+ function normalizeError(err) {
464
+ if (err instanceof Error) return {
465
+ message: err.message,
466
+ code: err.code
467
+ };
468
+ return { message: String(err) };
469
+ }
470
+ /**
471
+ * In-memory outbox store — reference implementation supporting the full
472
+ * capability set (claim/lease, fail/retry, dedupe, visibleAt).
473
+ *
474
+ * For dev/testing only. Production deployments should use a durable store
475
+ * backed by the app's database.
476
+ */
280
477
  var MemoryOutboxStore = class {
281
- events = [];
282
- async save(event) {
283
- this.events.push(event);
478
+ entries = [];
479
+ seenDedupeKeys = /* @__PURE__ */ new Set();
480
+ async save(event, options) {
481
+ if (!event?.type || typeof event.type !== "string") throw new InvalidOutboxEventError("event.type is required");
482
+ if (!event.meta?.id || typeof event.meta.id !== "string") throw new InvalidOutboxEventError("event.meta.id is required");
483
+ if (options?.dedupeKey) {
484
+ if (this.seenDedupeKeys.has(options.dedupeKey)) return;
485
+ this.seenDedupeKeys.add(options.dedupeKey);
486
+ }
487
+ this.entries.push({
488
+ event,
489
+ status: "pending",
490
+ attempts: 0,
491
+ visibleAt: options?.visibleAt?.getTime() ?? 0,
492
+ leaseOwner: null,
493
+ leaseExpiresAt: 0,
494
+ deliveredAt: null,
495
+ lastError: null,
496
+ dedupeKey: options?.dedupeKey
497
+ });
284
498
  }
285
499
  async getPending(limit) {
286
- return this.events.slice(0, limit);
500
+ const now = Date.now();
501
+ return this.entries.filter((e) => e.status === "pending" && e.visibleAt <= now && (e.leaseOwner === null || e.leaseExpiresAt <= now)).slice(0, limit).map((e) => e.event);
287
502
  }
288
- async acknowledge(eventId) {
289
- this.events = this.events.filter((e) => e.meta.id !== eventId);
503
+ async claimPending(options) {
504
+ const now = Date.now();
505
+ const limit = options?.limit ?? 100;
506
+ const leaseMs = options?.leaseMs ?? DEFAULT_LEASE_MS;
507
+ const consumerId = options?.consumerId ?? "anonymous";
508
+ const typeFilter = options?.types ? new Set(options.types) : null;
509
+ const claimed = [];
510
+ for (const entry of this.entries) {
511
+ if (claimed.length >= limit) break;
512
+ if (entry.status !== "pending") continue;
513
+ if (entry.visibleAt > now) continue;
514
+ if (entry.leaseOwner !== null && entry.leaseExpiresAt > now) continue;
515
+ if (typeFilter && !typeFilter.has(entry.event.type)) continue;
516
+ entry.leaseOwner = consumerId;
517
+ entry.leaseExpiresAt = now + leaseMs;
518
+ entry.attempts++;
519
+ claimed.push(entry.event);
520
+ }
521
+ return claimed;
522
+ }
523
+ async acknowledge(eventId, options) {
524
+ const entry = this.entries.find((e) => e.event.meta.id === eventId);
525
+ if (!entry) return;
526
+ if (entry.status === "delivered") return;
527
+ if (options?.consumerId && entry.leaseOwner && entry.leaseOwner !== options.consumerId) throw new OutboxOwnershipError(eventId, options.consumerId, entry.leaseOwner);
528
+ entry.status = "delivered";
529
+ entry.deliveredAt = Date.now();
530
+ entry.leaseOwner = null;
531
+ }
532
+ async fail(eventId, error, options) {
533
+ const entry = this.entries.find((e) => e.event.meta.id === eventId);
534
+ if (!entry) return;
535
+ if (options?.consumerId && entry.leaseOwner && entry.leaseOwner !== options.consumerId) throw new OutboxOwnershipError(eventId, options.consumerId, entry.leaseOwner);
536
+ entry.lastError = error;
537
+ entry.leaseOwner = null;
538
+ entry.leaseExpiresAt = 0;
539
+ if (options?.deadLetter) {
540
+ entry.status = "dead_letter";
541
+ return;
542
+ }
543
+ entry.status = "pending";
544
+ entry.visibleAt = options?.retryAt ? options.retryAt.getTime() : 0;
545
+ }
546
+ async purge(olderThanMs) {
547
+ const cutoff = Date.now() - olderThanMs;
548
+ let purged = 0;
549
+ for (let i = this.entries.length - 1; i >= 0; i--) {
550
+ const entry = this.entries[i];
551
+ if (!entry) continue;
552
+ if (entry.status === "delivered" && entry.deliveredAt !== null && entry.deliveredAt < cutoff) {
553
+ if (entry.dedupeKey) this.seenDedupeKeys.delete(entry.dedupeKey);
554
+ this.entries.splice(i, 1);
555
+ purged++;
556
+ }
557
+ }
558
+ return purged;
559
+ }
560
+ /** Test helper: inspect entry by id */
561
+ _getEntry(eventId) {
562
+ return this.entries.find((e) => e.event.meta.id === eventId);
290
563
  }
291
564
  };
565
+ /**
566
+ * Compute a `retryAt` `Date` using exponential backoff with jitter.
567
+ *
568
+ * This is a convenience helper for store authors implementing
569
+ * {@link OutboxStore.fail}: call it to compute the retry visibility window
570
+ * based on the event's current attempt count.
571
+ *
572
+ * Formula: `delay = min(maxMs, baseMs * 2^(attempt - 1)) * (1 + random * jitter)`
573
+ *
574
+ * @example Basic usage inside a store's `fail()` method
575
+ * ```typescript
576
+ * async fail(eventId, error, options) {
577
+ * const entry = await this.findById(eventId);
578
+ * entry.attempts++;
579
+ * if (entry.attempts >= MAX_ATTEMPTS) {
580
+ * return this.deadLetter(eventId, error);
581
+ * }
582
+ * const retryAt = exponentialBackoff({ attempt: entry.attempts });
583
+ * entry.visibleAt = retryAt;
584
+ * await this.update(entry);
585
+ * }
586
+ * ```
587
+ *
588
+ * @example Tuning for a faster transport
589
+ * ```typescript
590
+ * exponentialBackoff({ attempt: 3, baseMs: 250, maxMs: 10_000, jitter: 0.3 });
591
+ * // attempt=1 → ~250ms ±30%
592
+ * // attempt=2 → ~500ms ±30%
593
+ * // attempt=3 → ~1000ms ±30%
594
+ * // attempt=10 → capped at 10_000ms
595
+ * ```
596
+ */
597
+ function exponentialBackoff(options) {
598
+ const attempt = Math.max(1, Math.floor(options.attempt));
599
+ const baseMs = options.baseMs ?? 1e3;
600
+ const maxMs = options.maxMs ?? 6e4;
601
+ const jitter = Math.max(0, Math.min(1, options.jitter ?? .2));
602
+ const now = options.now ?? Date.now();
603
+ const exp = baseMs * 2 ** (attempt - 1);
604
+ const capped = Math.min(maxMs, exp);
605
+ const jittered = jitter > 0 ? capped * (1 + Math.random() * jitter) : capped;
606
+ return new Date(now + jittered);
607
+ }
292
608
  //#endregion
293
- export { ARC_LIFECYCLE_EVENTS, CACHE_EVENTS, CRUD_EVENT_SUFFIXES, EventOutbox, MemoryEventTransport, MemoryOutboxStore, createDeadLetterPublisher, createEvent, createEventRegistry, crudEventType, defineEvent, eventPlugin, withRetry };
609
+ export { ARC_LIFECYCLE_EVENTS, CACHE_EVENTS, CRUD_EVENT_SUFFIXES, EventOutbox, InvalidOutboxEventError, MemoryEventTransport, MemoryOutboxStore, OutboxOwnershipError, createDeadLetterPublisher, createEvent, createEventRegistry, crudEventType, defineEvent, eventPlugin, exponentialBackoff, withRetry };
@@ -1,2 +1,2 @@
1
- import { n as RedisStreamTransport, r as RedisStreamTransportOptions, t as RedisStreamLike } from "../../redis-stream-CF1lrKVk.mjs";
1
+ import { n as RedisStreamTransport, r as RedisStreamTransportOptions, t as RedisStreamLike } from "../../redis-stream-BgrYzpeq.mjs";
2
2
  export { type RedisStreamLike, RedisStreamTransport, type RedisStreamTransportOptions };
@@ -1,4 +1,4 @@
1
- import { i as EventTransport, n as EventHandler, r as EventLogger, t as DomainEvent } from "../../EventTransport-n1KBxC_N.mjs";
1
+ import { i as EventTransport, n as EventHandler, r as EventLogger, t as DomainEvent } from "../../EventTransport-CLXJUzyT.mjs";
2
2
 
3
3
  //#region src/events/transports/redis.d.ts
4
4
  interface RedisLike {
@@ -1,4 +1,4 @@
1
- import { a as CustomPluginAuthOption, c as RawBodyOptions, d as ResourceLike, f as loadResources, i as CustomAuthenticatorOption, l as UnderPressureOptions, n as BetterAuthOption, o as JwtAuthOption, r as CreateAppOptions, s as MultipartOptions, t as AuthOption, u as LoadResourcesOptions } from "../types-gUxAIZHp.mjs";
1
+ import { a as CustomPluginAuthOption, c as RawBodyOptions, d as ResourceLike, f as loadResources, i as CustomAuthenticatorOption, l as UnderPressureOptions, n as BetterAuthOption, o as JwtAuthOption, r as CreateAppOptions, s as MultipartOptions, t as AuthOption, u as LoadResourcesOptions } from "../types-BlOuKTPw.mjs";
2
2
  import { FastifyInstance } from "fastify";
3
3
 
4
4
  //#region src/factory/createApp.d.ts
@@ -1,4 +1,4 @@
1
- import { a as edgePreset, c as testingPreset, i as developmentPreset, n as createApp, o as getPreset, s as productionPreset, t as ArcFactory } from "../createApp-Cy8eUNKQ.mjs";
1
+ import { a as edgePreset, c as testingPreset, i as developmentPreset, n as createApp, o as getPreset, s as productionPreset, t as ArcFactory } from "../createApp-p2OThysU.mjs";
2
2
  import { readdir } from "node:fs/promises";
3
3
  import { dirname, join, resolve } from "node:path";
4
4
  import { fileURLToPath, pathToFileURL } from "node:url";
@@ -1,2 +1,2 @@
1
- import { Cn as defineHook, Sn as createHookSystem, _n as afterDelete, bn as beforeDelete, cn as DefineHookOptions, dn as HookOperation, fn as HookPhase, gn as afterCreate, hn as HookSystemOptions, ln as HookContext, mn as HookSystem, pn as HookRegistration, un as HookHandler, vn as afterUpdate, xn as beforeUpdate, yn as beforeCreate } from "../interface-IJqN3pXK.mjs";
1
+ import { An as beforeCreate, Cn as HookPhase, Dn as afterCreate, En as HookSystemOptions, Mn as beforeUpdate, Nn as createHookSystem, On as afterDelete, Pn as defineHook, Sn as HookOperation, Tn as HookSystem, bn as HookContext, jn as beforeDelete, kn as afterUpdate, wn as HookRegistration, xn as HookHandler, yn as DefineHookOptions } from "../interface-CS6d7HiB.mjs";
2
2
  export { type DefineHookOptions, type HookContext, type HookHandler, type HookOperation, type HookPhase, type HookRegistration, HookSystem, type HookSystemOptions, afterCreate, afterDelete, afterUpdate, beforeCreate, beforeDelete, beforeUpdate, createHookSystem, defineHook };
@@ -1,4 +1,4 @@
1
- import { Y as OpenApiSchemas, Yt as CrudRepository, Z as ParsedQuery, c as ValidationResult, n as AdapterSchemaContext, nt as QueryParserInterface, o as RepositoryLike, r as DataAdapter, s as SchemaMetadata, vt as RouteSchemaOptions } from "./interface-IJqN3pXK.mjs";
1
+ import { Y as OpenApiSchemas, Z as ParsedQuery, Zt as CrudRepository, c as ValidationResult, n as AdapterSchemaContext, nt as QueryParserInterface, o as RepositoryLike, r as DataAdapter, s as SchemaMetadata, vt as RouteSchemaOptions } from "./interface-CS6d7HiB.mjs";
2
2
  import { Model } from "mongoose";
3
3
 
4
4
  //#region src/adapters/mongoose.d.ts
@@ -1,5 +1,5 @@
1
1
  import { r as RequestScope } from "./types-CN6JvmYz.mjs";
2
- import { D as CrudRouterOptions, Ht as IControllerResponse, N as FastifyWithDecorators, T as CrudController, Ut as IRequestContext, Vt as IController, ct as RequestWithExtras, m as AnyRecord, ot as RequestContext, qt as ResourceDefinition, ut as ResourceConfig } from "./interface-IJqN3pXK.mjs";
2
+ import { D as CrudRouterOptions, Ht as IControllerResponse, N as FastifyWithDecorators, T as CrudController, Ut as IRequestContext, Vt as IController, ct as RequestWithExtras, m as AnyRecord, ot as RequestContext, qt as ResourceDefinition, ut as ResourceConfig } from "./interface-CS6d7HiB.mjs";
3
3
  import { t as PermissionCheck } from "./types-BoaZHr-2.mjs";
4
4
  import { FastifyInstance, FastifyReply, FastifyRequest, RouteHandlerMethod } from "fastify";
5
5
 
@@ -80,8 +80,40 @@ interface ActionRouterConfig {
80
80
  */
81
81
  readonly actionPermissions?: Record<string, PermissionCheck>;
82
82
  /**
83
- * Per-action JSON schema for body validation
84
- * @example { dispatch: { transport: { type: 'object' } } }
83
+ * Per-action schema for body validation.
84
+ *
85
+ * Accepted shapes per action:
86
+ *
87
+ * 1. **Full JSON Schema object** with `type: 'object'`, `properties`, `required` —
88
+ * used verbatim. Required fields ARE enforced by Fastify's AJV.
89
+ *
90
+ * 2. **Zod v4 schema** — auto-converted via `z.toJSONSchema()`. Required fields
91
+ * ARE enforced.
92
+ *
93
+ * 3. **Legacy field map** `{ fieldName: { type: 'string' } }` — each key becomes
94
+ * a property and is treated as REQUIRED unless the property schema has
95
+ * `nullable: true` or Arc's sentinel `required: false`. Kept for back-compat.
96
+ *
97
+ * All shapes are compiled into a single `oneOf` discriminator body schema
98
+ * so AJV can validate action-specific required fields at the HTTP layer.
99
+ *
100
+ * @example JSON Schema
101
+ * ```ts
102
+ * actionSchemas: {
103
+ * dispatch: {
104
+ * type: 'object',
105
+ * properties: { carrier: { type: 'string' } },
106
+ * required: ['carrier'],
107
+ * },
108
+ * }
109
+ * ```
110
+ *
111
+ * @example Zod v4
112
+ * ```ts
113
+ * actionSchemas: {
114
+ * dispatch: z.object({ carrier: z.string() }),
115
+ * }
116
+ * ```
85
117
  */
86
118
  readonly actionSchemas?: Record<string, Record<string, unknown>>;
87
119
  /**
package/dist/index.d.mts CHANGED
@@ -1,8 +1,8 @@
1
- import { $ as PresetFunction, $t as QueryOptions, At as BaseController, B as InferResourceDoc, C as ConfigError, Ct as TypedResourceConfig, D as CrudRouterOptions, Dt as ValidationResult$1, E as CrudRouteKey, Et as ValidateOptions, F as GracefulShutdownOptions, H as IntrospectionPluginOptions, Ht as IControllerResponse, I as HealthCheck, Jt as defineResource, K as MiddlewareConfig, L as HealthOptions, M as FastifyWithAuth, N as FastifyWithDecorators, O as CrudSchemas, Ot as envelope, P as FieldRule, R as InferAdapterDoc, St as TypedRepository, T as CrudController, Tt as UserOrganization, U as JWTPayload, Ut as IRequestContext, V as IntrospectionData, Vt as IController, Wt as RouteHandler, X as OwnershipCheck, Yt as CrudRepository, Zt as PaginatedResult, _ as ArcInternalMetadata, a as RelationMetadata, an as PipelineContext, at as RegistryStats, b as AuthPluginOptions, c as ValidationResult, ct as RequestWithExtras, en as Guard, gt as RouteHandlerMethod, h as ApiResponse, i as FieldMetadata, in as PipelineConfig, it as RegistryEntry, j as FastifyRequestExtras, jt as BaseControllerOptions, k as EventDefinition, m as AnyRecord, nn as NextFunction, o as RepositoryLike, on as PipelineStep, ot as RequestContext, p as AdditionalRoute, pt as ResourceMetadata, q as MiddlewareHandler, qt as ResourceDefinition, r as DataAdapter, rn as OperationFilter, rt as RateLimitConfig, s as SchemaMetadata, sn as Transform, st as RequestIdOptions, tn as Interceptor, tt as PresetResult, ut as ResourceConfig, v as ArcRequest, vt as RouteSchemaOptions, xt as TypedController, yt as ServiceContext, z as InferDocType, zt as ControllerLike } from "./interface-IJqN3pXK.mjs";
1
+ import { $ as PresetFunction, $t as DeleteOptions, At as BaseController, B as InferResourceDoc, C as ConfigError, Ct as TypedResourceConfig, D as CrudRouterOptions, Dt as ValidationResult$1, E as CrudRouteKey, Et as ValidateOptions, F as GracefulShutdownOptions, H as IntrospectionPluginOptions, Ht as IControllerResponse, I as HealthCheck, Jt as defineResource, K as MiddlewareConfig, L as HealthOptions, M as FastifyWithAuth, N as FastifyWithDecorators, O as CrudSchemas, Ot as envelope, P as FieldRule, Qt as DeleteManyResult, R as InferAdapterDoc, St as TypedRepository, T as CrudController, Tt as UserOrganization, U as JWTPayload, Ut as IRequestContext, V as IntrospectionData, Vt as IController, Wt as RouteHandler, X as OwnershipCheck, Xt as BulkWriteResult, Yt as BulkWriteOperation, Zt as CrudRepository, _ as ArcInternalMetadata, _n as PipelineStep, a as RelationMetadata, an as PaginationParams, at as RegistryStats, b as AuthPluginOptions, c as ValidationResult, cn as RepositorySession, ct as RequestWithExtras, dn as Guard, en as DeleteResult, fn as Interceptor, gn as PipelineContext, gt as RouteHandlerMethod, h as ApiResponse, hn as PipelineConfig, i as FieldMetadata, in as PaginatedResult, it as RegistryEntry, j as FastifyRequestExtras, jt as BaseControllerOptions, k as EventDefinition, ln as UpdateManyResult, m as AnyRecord, mn as OperationFilter, nn as KeysetPaginatedResult, o as RepositoryLike, on as PaginationResult, ot as RequestContext, p as AdditionalRoute, pn as NextFunction, pt as ResourceMetadata, q as MiddlewareHandler, qt as ResourceDefinition, r as DataAdapter, rn as OffsetPaginatedResult, rt as RateLimitConfig, s as SchemaMetadata, sn as QueryOptions, st as RequestIdOptions, tt as PresetResult, un as WriteOptions, ut as ResourceConfig, v as ArcRequest, vn as Transform, vt as RouteSchemaOptions, xt as TypedController, yt as ServiceContext, z as InferDocType, zt as ControllerLike } from "./interface-CS6d7HiB.mjs";
2
2
  import { a as applyFieldWritePermissions, i as applyFieldReadPermissions, n as FieldPermissionMap, o as fields, t as FieldPermission } from "./fields-DoeDgh2b.mjs";
3
3
  import { i as UserBase, n as PermissionContext, r as PermissionResult, t as PermissionCheck } from "./types-BoaZHr-2.mjs";
4
- import { l as createMongooseAdapter, o as createPrismaAdapter, s as MongooseAdapter, t as PrismaAdapter } from "./index-BpMhrFgn.mjs";
5
- import { A as MutationOperation, C as HOOK_PHASES, D as MAX_REGEX_LENGTH, E as MAX_FILTER_DEPTH, M as SYSTEM_FIELDS, O as MAX_SEARCH_LENGTH, S as HOOK_OPERATIONS, T as HookPhase, _ as DEFAULT_LIMIT, a as getControllerScope, b as DEFAULT_TENANT_FIELD, g as DEFAULT_ID_FIELD, h as CrudOperation, j as RESERVED_QUERY_PARAMS, k as MUTATION_OPERATIONS, m as CRUD_OPERATIONS, s as defineResourceVariants, v as DEFAULT_MAX_LIMIT, w as HookOperation, x as DEFAULT_UPDATE_METHOD, y as DEFAULT_SORT } from "./index-qct60lnl.mjs";
4
+ import { l as createMongooseAdapter, o as createPrismaAdapter, s as MongooseAdapter, t as PrismaAdapter } from "./index-0zj73o2U.mjs";
5
+ import { A as MutationOperation, C as HOOK_PHASES, D as MAX_REGEX_LENGTH, E as MAX_FILTER_DEPTH, M as SYSTEM_FIELDS, O as MAX_SEARCH_LENGTH, S as HOOK_OPERATIONS, T as HookPhase, _ as DEFAULT_LIMIT, a as getControllerScope, b as DEFAULT_TENANT_FIELD, g as DEFAULT_ID_FIELD, h as CrudOperation, j as RESERVED_QUERY_PARAMS, k as MUTATION_OPERATIONS, m as CRUD_OPERATIONS, s as defineResourceVariants, v as DEFAULT_MAX_LIMIT, w as HookOperation, x as DEFAULT_UPDATE_METHOD, y as DEFAULT_SORT } from "./index-DadoLP51.mjs";
6
6
  import { C as authenticated, D as publicRead, E as presets_d_exports, O as publicReadAdminWrite, S as adminOnly, T as ownerWithAdminBypass, _ as requireScopeContext, a as allOf, c as createDynamicPermissionMatrix, d as requireAuth, f as requireOrgInScope, g as requireRoles, h as requireOwnership, k as readOnly, l as createOrgPermissions, m as requireOrgRole, n as DynamicPermissionMatrix, o as allowPublic, p as requireOrgMembership, r as DynamicPermissionMatrixConfig, s as anyOf, u as denyAll, v as requireServiceScope, w as fullPublic, x as when, y as requireTeamMembership } from "./index-CBru2y5Y.mjs";
7
7
  import { a as NotFoundError, d as ValidationError, f as createDomainError, i as ForbiddenError, t as ArcError, u as UnauthorizedError } from "./errors-BI8kEKsO.mjs";
8
8
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -253,4 +253,4 @@ declare function arcLog(module: string): ArcLogger;
253
253
  //#region src/index.d.ts
254
254
  declare const version: string;
255
255
  //#endregion
256
- export { type ValidationResult as AdapterValidationResult, type AdditionalRoute, type AnyRecord, type ApiResponse, ArcError, type ArcInternalMetadata, type ArcLogWriter, type ArcLogger, type ArcLoggerOptions, type ArcRequest, type AuthPluginOptions, BaseController, type BaseControllerOptions, CRUD_OPERATIONS, type ConfigError, type ControllerLike, type CrudController, CrudOperation, type CrudRepository, type CrudRouteKey, type CrudRouterOptions, type CrudSchemas, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, type DataAdapter, type DynamicPermissionMatrix, type DynamicPermissionMatrixConfig, type EventDefinition, type FastifyRequestExtras, type FastifyWithAuth, type FastifyWithDecorators, type FieldMetadata, type FieldPermission, type FieldPermissionMap, type FieldRule, ForbiddenError, type GracefulShutdownOptions, type Guard, HOOK_OPERATIONS, HOOK_PHASES, type HealthCheck, type HealthOptions, HookOperation, HookPhase, type IController, type IControllerResponse, type IRequestContext, type InferAdapterDoc, type InferDocType, type InferResourceDoc, type Interceptor, type IntrospectionData, type IntrospectionPluginOptions, type JWTPayload, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, type MiddlewareConfig, MongooseAdapter, MutationOperation, type NamedMiddleware, NotFoundError, type OwnershipCheck, type PaginatedResult, type PermissionCheck, type PermissionContext, type PermissionResult, type PipelineConfig, type PipelineContext, type PipelineStep, type PresetFunction, type PresetResult, PrismaAdapter, type QueryOptions, RESERVED_QUERY_PARAMS, type RateLimitConfig, type RegistryEntry, type RegistryStats, type RelationMetadata, type RepositoryLike, type RequestContext, type RequestIdOptions, type RequestStore, type RequestWithExtras, type ResourceConfig, ResourceDefinition, type ResourceMetadata, type RouteHandler, type RouteHandlerMethod, type RouteSchemaOptions, SYSTEM_FIELDS, type SchemaMetadata, type ServiceContext, type Transform, type TypedController, type TypedRepository, type TypedResourceConfig, UnauthorizedError, type UserBase, type UserOrganization, type ValidateOptions, ValidationError, type ValidationResult$1 as ValidationResult, adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, arcLog, assertValidConfig, authenticated, configureArcLogger, createDomainError, createDynamicPermissionMatrix, createMongooseAdapter, createOrgPermissions, createPrismaAdapter, defineResource, defineResourceVariants, denyAll, envelope, fields, formatValidationErrors, fullPublic, getControllerScope, guard, intercept, middleware, ownerWithAdminBypass, presets_d_exports as permissions, pipe, publicRead, publicReadAdminWrite, readOnly, requestContext, requireAuth, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, sortMiddlewares, transform, validateResourceConfig, version, when };
256
+ export { type ValidationResult as AdapterValidationResult, type AdditionalRoute, type AnyRecord, type ApiResponse, ArcError, type ArcInternalMetadata, type ArcLogWriter, type ArcLogger, type ArcLoggerOptions, type ArcRequest, type AuthPluginOptions, BaseController, type BaseControllerOptions, type BulkWriteOperation, type BulkWriteResult, CRUD_OPERATIONS, type ConfigError, type ControllerLike, type CrudController, CrudOperation, type CrudRepository, type CrudRouteKey, type CrudRouterOptions, type CrudSchemas, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, type DataAdapter, type DeleteManyResult, type DeleteOptions, type DeleteResult, type DynamicPermissionMatrix, type DynamicPermissionMatrixConfig, type EventDefinition, type FastifyRequestExtras, type FastifyWithAuth, type FastifyWithDecorators, type FieldMetadata, type FieldPermission, type FieldPermissionMap, type FieldRule, ForbiddenError, type GracefulShutdownOptions, type Guard, HOOK_OPERATIONS, HOOK_PHASES, type HealthCheck, type HealthOptions, HookOperation, HookPhase, type IController, type IControllerResponse, type IRequestContext, type InferAdapterDoc, type InferDocType, type InferResourceDoc, type Interceptor, type IntrospectionData, type IntrospectionPluginOptions, type JWTPayload, type KeysetPaginatedResult, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, type MiddlewareConfig, MongooseAdapter, MutationOperation, type NamedMiddleware, NotFoundError, type OffsetPaginatedResult, type OwnershipCheck, type PaginatedResult, type PaginationParams, type PaginationResult, type PermissionCheck, type PermissionContext, type PermissionResult, type PipelineConfig, type PipelineContext, type PipelineStep, type PresetFunction, type PresetResult, PrismaAdapter, type QueryOptions, RESERVED_QUERY_PARAMS, type RateLimitConfig, type RegistryEntry, type RegistryStats, type RelationMetadata, type RepositoryLike, type RepositorySession, type RequestContext, type RequestIdOptions, type RequestStore, type RequestWithExtras, type ResourceConfig, ResourceDefinition, type ResourceMetadata, type RouteHandler, type RouteHandlerMethod, type RouteSchemaOptions, SYSTEM_FIELDS, type SchemaMetadata, type ServiceContext, type Transform, type TypedController, type TypedRepository, type TypedResourceConfig, UnauthorizedError, type UpdateManyResult, type UserBase, type UserOrganization, type ValidateOptions, ValidationError, type ValidationResult$1 as ValidationResult, type WriteOptions, adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, arcLog, assertValidConfig, authenticated, configureArcLogger, createDomainError, createDynamicPermissionMatrix, createMongooseAdapter, createOrgPermissions, createPrismaAdapter, defineResource, defineResourceVariants, denyAll, envelope, fields, formatValidationErrors, fullPublic, getControllerScope, guard, intercept, middleware, ownerWithAdminBypass, presets_d_exports as permissions, pipe, publicRead, publicReadAdminWrite, readOnly, requestContext, requireAuth, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, sortMiddlewares, transform, validateResourceConfig, version, when };
package/dist/index.mjs CHANGED
@@ -1,13 +1,13 @@
1
1
  import { a as DEFAULT_SORT, c as HOOK_OPERATIONS, d as MAX_REGEX_LENGTH, f as MAX_SEARCH_LENGTH, h as SYSTEM_FIELDS, i as DEFAULT_MAX_LIMIT, l as HOOK_PHASES, m as RESERVED_QUERY_PARAMS, n as DEFAULT_ID_FIELD, o as DEFAULT_TENANT_FIELD, p as MUTATION_OPERATIONS, r as DEFAULT_LIMIT, s as DEFAULT_UPDATE_METHOD, t as CRUD_OPERATIONS, u as MAX_FILTER_DEPTH } from "./constants-Cxde4rpC.mjs";
2
- import { a as createMongooseAdapter, i as MongooseAdapter, r as createPrismaAdapter, t as PrismaAdapter } from "./adapters-BxGgSHjj.mjs";
3
- import { t as BaseController } from "./BaseController-CpMfCXdn.mjs";
2
+ import { a as createMongooseAdapter, i as MongooseAdapter, r as createPrismaAdapter, t as PrismaAdapter } from "./adapters-BBqAVvPK.mjs";
3
+ import { t as BaseController } from "./BaseController-DAGGc5Xn.mjs";
4
4
  import { envelope } from "./types/index.mjs";
5
5
  import { n as applyFieldWritePermissions, r as fields, t as applyFieldReadPermissions } from "./fields-ipsbIRPK.mjs";
6
- import { t as requestContext } from "./requestContext-xHIKedG6.mjs";
7
- import { d as createDomainError, i as NotFoundError, l as UnauthorizedError, r as ForbiddenError, t as ArcError, u as ValidationError } from "./errors-Cg58SLNi.mjs";
8
- import { a as validateResourceConfig, f as getControllerScope, i as formatValidationErrors, m as pipe, n as defineResource, r as assertValidConfig, t as ResourceDefinition } from "./defineResource-CovBXvTB.mjs";
6
+ import { t as requestContext } from "./requestContext-DYvHl113.mjs";
7
+ import { d as createDomainError, i as NotFoundError, l as UnauthorizedError, r as ForbiddenError, t as ArcError, u as ValidationError } from "./errors-BF2bIOIS.mjs";
8
+ import { a as validateResourceConfig, f as getControllerScope, i as formatValidationErrors, m as pipe, n as defineResource, r as assertValidConfig, t as ResourceDefinition } from "./defineResource-CqeUltrW.mjs";
9
9
  import { C as publicRead, S as presets_exports, T as readOnly, _ as when, a as createOrgPermissions, b as fullPublic, c as requireOrgInScope, d as requireOwnership, f as requireRoles, h as requireTeamMembership, i as createDynamicPermissionMatrix, l as requireOrgMembership, m as requireServiceScope, n as allowPublic, o as denyAll, p as requireScopeContext, r as anyOf, s as requireAuth, t as allOf, u as requireOrgRole, v as adminOnly, w as publicReadAdminWrite, x as ownerWithAdminBypass, y as authenticated } from "./permissions-CH4cNwJi.mjs";
10
- import { t as defineResourceVariants } from "./core-BfrfxNqO.mjs";
10
+ import { t as defineResourceVariants } from "./core-CrLDuqoT.mjs";
11
11
  import { n as configureArcLogger, t as arcLog } from "./logger-CDjpjySd.mjs";
12
12
  //#region src/middleware/middleware.ts
13
13
  /**
@@ -128,6 +128,6 @@ function transform(name, handlerOrOptions) {
128
128
  }
129
129
  //#endregion
130
130
  //#region src/index.ts
131
- const version = "2.8.0";
131
+ const version = "2.8.1";
132
132
  //#endregion
133
133
  export { ArcError, BaseController, CRUD_OPERATIONS, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, ForbiddenError, HOOK_OPERATIONS, HOOK_PHASES, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, MongooseAdapter, NotFoundError, PrismaAdapter, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, UnauthorizedError, ValidationError, adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, arcLog, assertValidConfig, authenticated, configureArcLogger, createDomainError, createDynamicPermissionMatrix, createMongooseAdapter, createOrgPermissions, createPrismaAdapter, defineResource, defineResourceVariants, denyAll, envelope, fields, formatValidationErrors, fullPublic, getControllerScope, guard, intercept, middleware, ownerWithAdminBypass, presets_exports as permissions, pipe, publicRead, publicReadAdminWrite, readOnly, requestContext, requireAuth, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, sortMiddlewares, transform, validateResourceConfig, version, when };
@@ -1,4 +1,4 @@
1
- import { t as DomainEvent } from "../EventTransport-n1KBxC_N.mjs";
1
+ import { t as DomainEvent } from "../EventTransport-CLXJUzyT.mjs";
2
2
  import { WebSocketClient, WebSocketMessage } from "./websocket.mjs";
3
3
  import { FastifyPluginAsync, FastifyRequest } from "fastify";
4
4
 
@@ -1,7 +1,7 @@
1
1
  import { WebSocketClient, WebSocketMessage, WebSocketPluginOptions } from "./websocket.mjs";
2
2
  import { EventGatewayOptions } from "./event-gateway.mjs";
3
3
  import { JobDefinition, JobDispatchOptions, JobDispatcher, JobMeta, JobsPluginOptions, QueueStats } from "./jobs.mjs";
4
- import { c as McpResourceConfig, f as ToolAnnotations, i as CrudOperation, l as PromptDefinition, m as ToolDefinition, n as CallToolResult, o as McpAuthResult, p as ToolContext, r as CreateMcpServerConfig, s as McpPluginOptions, t as BetterAuthHandler } from "../types-Ct0PUUSp.mjs";
4
+ import { c as McpResourceConfig, f as ToolAnnotations, i as CrudOperation, l as PromptDefinition, m as ToolDefinition, n as CallToolResult, o as McpAuthResult, p as ToolContext, r as CreateMcpServerConfig, s as McpPluginOptions, t as BetterAuthHandler } from "../types-D3b7hA00.mjs";
5
5
  import { StreamlinePluginOptions, WorkflowLike, WorkflowRunLike } from "./streamline.mjs";
6
6
  import { WebhookDeliveryRecord, WebhookManager, WebhookPluginOptions, WebhookStore, WebhookSubscription } from "./webhooks.mjs";
7
7
  export { type BetterAuthHandler, type CallToolResult, type CreateMcpServerConfig, type CrudOperation, type EventGatewayOptions, type JobDefinition, type JobDispatchOptions, type JobDispatcher, type JobMeta, type JobsPluginOptions, type McpAuthResult, type McpPluginOptions, type McpResourceConfig, type PromptDefinition, type QueueStats, type StreamlinePluginOptions, type ToolAnnotations, type ToolContext, type ToolDefinition, type WebSocketClient, type WebSocketMessage, type WebSocketPluginOptions, type WebhookDeliveryRecord, type WebhookManager, type WebhookPluginOptions, type WebhookStore, type WebhookSubscription, type WorkflowLike, type WorkflowRunLike };
@@ -1,5 +1,5 @@
1
- import { qt as ResourceDefinition } from "../../interface-IJqN3pXK.mjs";
2
- import { a as McpAuthResolver, c as McpResourceConfig, d as SessionEntry, f as ToolAnnotations, i as CrudOperation, l as PromptDefinition, m as ToolDefinition, n as CallToolResult, o as McpAuthResult, p as ToolContext, r as CreateMcpServerConfig, s as McpPluginOptions, t as BetterAuthHandler, u as PromptResult } from "../../types-Ct0PUUSp.mjs";
1
+ import { qt as ResourceDefinition } from "../../interface-CS6d7HiB.mjs";
2
+ import { a as McpAuthResolver, c as McpResourceConfig, d as SessionEntry, f as ToolAnnotations, i as CrudOperation, l as PromptDefinition, m as ToolDefinition, n as CallToolResult, o as McpAuthResult, p as ToolContext, r as CreateMcpServerConfig, s as McpPluginOptions, t as BetterAuthHandler, u as PromptResult } from "../../types-D3b7hA00.mjs";
3
3
  import { FastifyPluginAsync } from "fastify";
4
4
  import { z } from "zod";
5
5
 
@@ -1,4 +1,4 @@
1
- import { n as fieldRulesToZod, r as createMcpServer, t as resourceToTools } from "../../resourceToTools-C_1SMiCz.mjs";
1
+ import { n as fieldRulesToZod, r as createMcpServer, t as resourceToTools } from "../../resourceToTools-DNNWnZtx.mjs";
2
2
  import { createHash } from "node:crypto";
3
3
  import fp from "fastify-plugin";
4
4
  //#region src/integrations/mcp/definePrompt.ts
@@ -1,4 +1,4 @@
1
- import { o as McpAuthResult, s as McpPluginOptions } from "../../types-Ct0PUUSp.mjs";
1
+ import { o as McpAuthResult, s as McpPluginOptions } from "../../types-D3b7hA00.mjs";
2
2
 
3
3
  //#region src/integrations/mcp/testing.d.ts
4
4
  interface TestMcpClientOptions {
@@ -1,4 +1,4 @@
1
- import { r as createMcpServer, t as resourceToTools } from "../../resourceToTools-C_1SMiCz.mjs";
1
+ import { r as createMcpServer, t as resourceToTools } from "../../resourceToTools-DNNWnZtx.mjs";
2
2
  //#region src/integrations/mcp/testing.ts
3
3
  /**
4
4
  * @classytic/arc/mcp/testing — MCP Test Utilities