@classytic/arc 2.9.1 → 2.10.3

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 (139) hide show
  1. package/README.md +19 -90
  2. package/dist/{BaseController-Vu2yc56T.mjs → BaseController-CbKKIflT.mjs} +8 -44
  3. package/dist/{ResourceRegistry-Dq3_zBQP.mjs → ResourceRegistry-BPd6NQDm.mjs} +1 -1
  4. package/dist/adapters/index.d.mts +3 -3
  5. package/dist/adapters/index.mjs +2 -2
  6. package/dist/{adapters-BBqAVvPK.mjs → adapters-BXY4i-hw.mjs} +210 -41
  7. package/dist/audit/index.d.mts +38 -3
  8. package/dist/audit/index.mjs +41 -7
  9. package/dist/auth/index.d.mts +4 -4
  10. package/dist/auth/index.mjs +5 -5
  11. package/dist/auth/redis-session.d.mts +1 -1
  12. package/dist/cache/index.d.mts +17 -15
  13. package/dist/cache/index.mjs +15 -14
  14. package/dist/{caching-CjybdRwx.mjs → caching-CBpK_SCM.mjs} +8 -3
  15. package/dist/cli/commands/describe.mjs +1 -1
  16. package/dist/cli/commands/docs.mjs +2 -2
  17. package/dist/cli/commands/generate.mjs +1 -1
  18. package/dist/cli/commands/init.mjs +1 -1
  19. package/dist/cli/commands/introspect.mjs +1 -1
  20. package/dist/core/index.d.mts +2 -2
  21. package/dist/core/index.mjs +3 -4
  22. package/dist/{defineResource-C__jkwvs.mjs → core-CcR01lup.mjs} +44 -12
  23. package/dist/{createActionRouter-DH1YFL9m.mjs → createActionRouter-Bp_5c_2b.mjs} +1 -1
  24. package/dist/{createApp-CBJUJKGP.mjs → createApp-BuvPma24.mjs} +14 -14
  25. package/dist/docs/index.d.mts +2 -2
  26. package/dist/docs/index.mjs +2 -2
  27. package/dist/{elevation-DxQ6ACbt.mjs → elevation-C7hgL_aI.mjs} +2 -2
  28. package/dist/{errorHandler-CZDW4EXS.mjs → errorHandler-Bb49BvPD.mjs} +1 -1
  29. package/dist/{errorHandler-DixGcttC.d.mts → errorHandler-DRQ3EqfL.d.mts} +1 -1
  30. package/dist/{eventPlugin-BxvaCIZF.d.mts → eventPlugin-CxWgpd6K.d.mts} +1 -1
  31. package/dist/{eventPlugin-Dl7MoVWH.mjs → eventPlugin-DCUjuiQT.mjs} +1 -1
  32. package/dist/events/index.d.mts +8 -5
  33. package/dist/events/index.mjs +34 -17
  34. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  35. package/dist/events/transports/redis.d.mts +1 -1
  36. package/dist/factory/index.d.mts +1 -1
  37. package/dist/factory/index.mjs +2 -2
  38. package/dist/{types-DZi1aYhm.d.mts → fields-Lo1VUDpt.d.mts} +121 -1
  39. package/dist/{filesUpload-q8oHt--L.mjs → filesUpload-t21LS-py.mjs} +2 -2
  40. package/dist/hooks/index.d.mts +1 -1
  41. package/dist/hooks/index.mjs +1 -1
  42. package/dist/idempotency/index.d.mts +7 -4
  43. package/dist/idempotency/index.mjs +9 -11
  44. package/dist/idempotency/redis.d.mts +1 -1
  45. package/dist/{index-Cibkchnx.d.mts → index-8qw4y6ff.d.mts} +2 -2
  46. package/dist/{index-C-xjcA6F.d.mts → index-ChIw3776.d.mts} +283 -408
  47. package/dist/{interface-YrWsmKqE.d.mts → index-Cl0uoKd5.d.mts} +1885 -2741
  48. package/dist/{index-CtGKT0lf.d.mts → index-DStwgFUK.d.mts} +81 -7
  49. package/dist/index.d.mts +7 -8
  50. package/dist/index.mjs +11 -12
  51. package/dist/integrations/event-gateway.d.mts +1 -1
  52. package/dist/integrations/event-gateway.mjs +1 -1
  53. package/dist/integrations/index.d.mts +1 -1
  54. package/dist/integrations/mcp/index.d.mts +2 -2
  55. package/dist/integrations/mcp/index.mjs +1 -1
  56. package/dist/integrations/mcp/testing.d.mts +1 -1
  57. package/dist/integrations/mcp/testing.mjs +1 -1
  58. package/dist/interface-D218ikEo.d.mts +77 -0
  59. package/dist/{memory-BFAYkf8H.mjs → memory-B5Amv9A1.mjs} +23 -8
  60. package/dist/{openapi-CXuTG1M9.mjs → openapi-B5F8AddX.mjs} +2 -2
  61. package/dist/org/index.d.mts +2 -2
  62. package/dist/permissions/index.d.mts +3 -4
  63. package/dist/permissions/index.mjs +5 -5
  64. package/dist/{permissions-oNZawnkR.mjs → permissions-Dk6mshja.mjs} +315 -397
  65. package/dist/plugins/index.d.mts +4 -4
  66. package/dist/plugins/index.mjs +12 -14
  67. package/dist/plugins/response-cache.mjs +1 -1
  68. package/dist/plugins/tracing-entry.d.mts +1 -1
  69. package/dist/plugins/tracing-entry.mjs +1 -1
  70. package/dist/presets/filesUpload.d.mts +3 -3
  71. package/dist/presets/filesUpload.mjs +1 -1
  72. package/dist/presets/index.d.mts +1 -1
  73. package/dist/presets/index.mjs +2 -2
  74. package/dist/presets/multiTenant.d.mts +1 -1
  75. package/dist/presets/multiTenant.mjs +1 -1
  76. package/dist/presets/search.d.mts +91 -4
  77. package/dist/presets/search.mjs +1 -1
  78. package/dist/{presets-hM4WhNWY.mjs → presets-fLJVXdVn.mjs} +1 -1
  79. package/dist/{queryCachePlugin-CnTZZTC5.d.mts → queryCachePlugin-BKbWjgDG.d.mts} +1 -1
  80. package/dist/{queryCachePlugin-DbUVroUG.mjs → queryCachePlugin-DQCEfJis.mjs} +8 -8
  81. package/dist/{queryParser-Cs-6SHQK.mjs → queryParser-DBqBB6AC.mjs} +1 -1
  82. package/dist/{redis-MXLp1oOf.d.mts → redis-DqyeggCa.d.mts} +1 -1
  83. package/dist/{redis-stream-Bz-4q96t.d.mts → redis-stream-CakIQmwR.d.mts} +1 -1
  84. package/dist/registry/index.d.mts +1 -1
  85. package/dist/registry/index.mjs +2 -2
  86. package/dist/{resourceToTools-C3cWymnW.mjs → resourceToTools-BElv3xPT.mjs} +3 -3
  87. package/dist/scope/index.d.mts +1 -1
  88. package/dist/scope/index.mjs +2 -2
  89. package/dist/{sse-CJpt7LGI.mjs → sse-yBCgOLGu.mjs} +1 -1
  90. package/dist/testing/index.d.mts +6 -5
  91. package/dist/testing/index.mjs +8 -10
  92. package/dist/testing/storageContract.d.mts +1 -1
  93. package/dist/types/index.d.mts +4 -4
  94. package/dist/types/index.mjs +1 -31
  95. package/dist/types/storage.d.mts +1 -1
  96. package/dist/{types-CoSzA-s-.d.mts → types-Btdda02s.d.mts} +1 -1
  97. package/dist/{types-CunEX4UX.d.mts → types-Co8k3NyS.d.mts} +9 -9
  98. package/dist/types-Csi3FLfq.mjs +27 -0
  99. package/dist/utils/index.d.mts +207 -3
  100. package/dist/utils/index.mjs +3 -4
  101. package/dist/{utils-B7FuRr9w.mjs → utils-B2fNOD_i.mjs} +285 -2
  102. package/dist/{versioning-Cm8qoFDg.mjs → versioning-C2U_bLY0.mjs} +3 -5
  103. package/package.json +15 -18
  104. package/skills/arc/SKILL.md +7 -11
  105. package/skills/arc/references/production.md +0 -41
  106. package/dist/circuitBreaker-CvXkjfrW.d.mts +0 -206
  107. package/dist/circuitBreaker-l18oRgL5.mjs +0 -284
  108. package/dist/core-DNncu0xF.mjs +0 -34
  109. package/dist/dynamic/index.d.mts +0 -93
  110. package/dist/dynamic/index.mjs +0 -122
  111. package/dist/fields-BC7zcmI9.d.mts +0 -121
  112. package/dist/interface-DplgQO2e.d.mts +0 -54
  113. package/dist/policies/index.d.mts +0 -425
  114. package/dist/policies/index.mjs +0 -318
  115. package/dist/rpc/index.d.mts +0 -90
  116. package/dist/rpc/index.mjs +0 -248
  117. /package/dist/{EventTransport-CqZ8FyM_.d.mts → EventTransport-CUw5NNWe.d.mts} +0 -0
  118. /package/dist/{HookSystem-BjFu7zf1.mjs → HookSystem-BNYKnrXF.mjs} +0 -0
  119. /package/dist/{applyPermissionResult-bqGpo9ML.mjs → applyPermissionResult-QhV1Pa-g.mjs} +0 -0
  120. /package/dist/{betterAuthOpenApi--rdY15Ld.mjs → betterAuthOpenApi-BBRVhjQN.mjs} +0 -0
  121. /package/dist/{constants-Cxde4rpC.mjs → constants-BhY1OHoH.mjs} +0 -0
  122. /package/dist/{elevation-B6S5csVA.d.mts → elevation-C5SwtkAn.d.mts} +0 -0
  123. /package/dist/{errors-BI8kEKsO.d.mts → errors-CCSsMpXE.d.mts} +0 -0
  124. /package/dist/{errors-CqWnSqM-.mjs → errors-D5c-5BJL.mjs} +0 -0
  125. /package/dist/{externalPaths-Bapitwvd.d.mts → externalPaths-BQ8QijNH.d.mts} +0 -0
  126. /package/dist/{fields-CU6FlaDV.mjs → fields-bxkeltzz.mjs} +0 -0
  127. /package/dist/{interface-B-pe8fhj.d.mts → interface-CSbZdv_3.d.mts} +0 -0
  128. /package/dist/{loadResources-Bksk8ydA.mjs → loadResources-BAzJItAJ.mjs} +0 -0
  129. /package/dist/{logger-CDjpjySd.mjs → logger-DLg8-Ueg.mjs} +0 -0
  130. /package/dist/{metrics-TuOmguhi.mjs → metrics-DuhiSEZI.mjs} +0 -0
  131. /package/dist/{pluralize-CWP6MB39.mjs → pluralize-A0tWEl1K.mjs} +0 -0
  132. /package/dist/{registry-B0Wl7uVV.mjs → registry-B3lRFBWo.mjs} +0 -0
  133. /package/dist/{replyHelpers-BLojtuvR.mjs → replyHelpers-CXtJDAZ0.mjs} +0 -0
  134. /package/dist/{requestContext-DYtmNpm5.mjs → requestContext-xHIKedG6.mjs} +0 -0
  135. /package/dist/{sessionManager-D-oNWHz3.d.mts → sessionManager-BkzVU8h2.d.mts} +0 -0
  136. /package/dist/{storage-BwGQXUpd.d.mts → storage-CVk_SEn2.d.mts} +0 -0
  137. /package/dist/{store-helpers-DFiZl5TL.mjs → store-helpers-ZCSMJJAX.mjs} +0 -0
  138. /package/dist/{tracing-xqXzWeaf.d.mts → tracing-65B51Dw3.d.mts} +0 -0
  139. /package/dist/{types-ZUu_h0jp.mjs → types-DV9WDfeg.mjs} +0 -0
@@ -1,4 +1,4 @@
1
- import { i as EventLogger, n as DomainEvent, o as EventTransport, r as EventHandler } from "./EventTransport-CqZ8FyM_.mjs";
1
+ import { i as EventLogger, n as DomainEvent, o as EventTransport, r as EventHandler } from "./EventTransport-CUw5NNWe.mjs";
2
2
  import { FastifyPluginAsync } from "fastify";
3
3
 
4
4
  //#region src/events/defineEvent.d.ts
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
2
- import { t as requestContext } from "./requestContext-DYtmNpm5.mjs";
2
+ import { t as requestContext } from "./requestContext-xHIKedG6.mjs";
3
3
  import fp from "fastify-plugin";
4
4
  //#region src/events/EventTransport.ts
5
5
  /**
@@ -1,8 +1,8 @@
1
- import { o as RepositoryLike } from "../interface-YrWsmKqE.mjs";
2
- import { a as EventMeta, c as MemoryEventTransportOptions, d as createEvent, i as EventLogger, l as PublishManyResult, n as DomainEvent, o as EventTransport, r as EventHandler, s as MemoryEventTransport, t as DeadLetteredEvent, u as createChildEvent } from "../EventTransport-CqZ8FyM_.mjs";
3
- import { a as withRetry, c as EventDefinitionOutput, d as EventSchema, f as ValidationResult, i as createDeadLetterPublisher, l as EventRegistry, m as defineEvent, n as eventPlugin, o as CustomValidator, p as createEventRegistry, r as RetryOptions, s as EventDefinitionInput, t as EventPluginOptions, u as EventRegistryOptions } from "../eventPlugin-BxvaCIZF.mjs";
1
+ import { kt as RepositoryLike } from "../index-Cl0uoKd5.mjs";
2
+ import { a as EventMeta, c as MemoryEventTransportOptions, d as createEvent, i as EventLogger, l as PublishManyResult, n as DomainEvent, o as EventTransport, r as EventHandler, s as MemoryEventTransport, t as DeadLetteredEvent, u as createChildEvent } from "../EventTransport-CUw5NNWe.mjs";
3
+ import { a as withRetry, c as EventDefinitionOutput, d as EventSchema, f as ValidationResult, i as createDeadLetterPublisher, l as EventRegistry, m as defineEvent, n as eventPlugin, o as CustomValidator, p as createEventRegistry, r as RetryOptions, s as EventDefinitionInput, t as EventPluginOptions, u as EventRegistryOptions } from "../eventPlugin-CxWgpd6K.mjs";
4
4
  import { RedisEventTransportOptions, RedisLike } from "./transports/redis.mjs";
5
- import { r as RedisStreamTransportOptions, t as RedisStreamLike } from "../redis-stream-Bz-4q96t.mjs";
5
+ import { r as RedisStreamTransportOptions, t as RedisStreamLike } from "../redis-stream-CakIQmwR.mjs";
6
6
 
7
7
  //#region src/events/eventTypes.d.ts
8
8
  /**
@@ -597,4 +597,7 @@ interface ExponentialBackoffOptions {
597
597
  */
598
598
  declare function exponentialBackoff(options: ExponentialBackoffOptions): Date;
599
599
  //#endregion
600
- export { ARC_LIFECYCLE_EVENTS, type ArcLifecycleEvent, CACHE_EVENTS, CRUD_EVENT_SUFFIXES, type CacheEvent, type CrudEventSuffix, type CustomValidator, type DeadLetteredEvent, type DomainEvent, type EventDefinitionInput, type EventDefinitionOutput, type EventHandler, type EventLogger, type EventMeta, EventOutbox, type EventOutboxOptions, type EventPluginOptions, type EventRegistry, type EventRegistryOptions, type EventSchema, type EventTransport, type ExponentialBackoffOptions, InvalidOutboxEventError, MemoryEventTransport, type MemoryEventTransportOptions, MemoryOutboxStore, type OutboxAcknowledgeOptions, type OutboxClaimOptions, type OutboxErrorInfo, type OutboxFailOptions, type OutboxFailureContext, type OutboxFailureDecision, type OutboxFailurePolicy, OutboxOwnershipError, type OutboxRelayErrorHandler, type OutboxRelayErrorKind, type OutboxStore, type OutboxWriteOptions, type PublishManyResult, type RedisEventTransportOptions, type RedisLike, type RedisStreamLike, type RedisStreamTransportOptions, type RelayResult, type RetryOptions, type ValidationResult, createChildEvent, createDeadLetterPublisher, createEvent, createEventRegistry, crudEventType, defineEvent, eventPlugin, exponentialBackoff, withRetry };
600
+ //#region src/events/repository-outbox-adapter.d.ts
601
+ declare function repositoryAsOutboxStore(repository: RepositoryLike): OutboxStore;
602
+ //#endregion
603
+ export { ARC_LIFECYCLE_EVENTS, type ArcLifecycleEvent, CACHE_EVENTS, CRUD_EVENT_SUFFIXES, type CacheEvent, type CrudEventSuffix, type CustomValidator, type DeadLetteredEvent, type DomainEvent, type EventDefinitionInput, type EventDefinitionOutput, type EventHandler, type EventLogger, type EventMeta, EventOutbox, type EventOutboxOptions, type EventPluginOptions, type EventRegistry, type EventRegistryOptions, type EventSchema, type EventTransport, type ExponentialBackoffOptions, InvalidOutboxEventError, MemoryEventTransport, type MemoryEventTransportOptions, MemoryOutboxStore, type OutboxAcknowledgeOptions, type OutboxClaimOptions, type OutboxErrorInfo, type OutboxFailOptions, type OutboxFailureContext, type OutboxFailureDecision, type OutboxFailurePolicy, OutboxOwnershipError, type OutboxRelayErrorHandler, type OutboxRelayErrorKind, type OutboxStore, type OutboxWriteOptions, type PublishManyResult, type RedisEventTransportOptions, type RedisLike, type RedisStreamLike, type RedisStreamTransportOptions, type RelayResult, type RetryOptions, type ValidationResult, createChildEvent, createDeadLetterPublisher, createEvent, createEventRegistry, crudEventType, defineEvent, eventPlugin, exponentialBackoff, repositoryAsOutboxStore, withRetry };
@@ -1,5 +1,5 @@
1
- import { a as MemoryEventTransport, i as withRetry, o as createChildEvent, r as createDeadLetterPublisher, s as createEvent, t as eventPlugin } from "../eventPlugin-Dl7MoVWH.mjs";
2
- import { n as createSafeGetOne, t as createIsDuplicateKeyError } from "../store-helpers-DFiZl5TL.mjs";
1
+ import { a as MemoryEventTransport, i as withRetry, o as createChildEvent, r as createDeadLetterPublisher, s as createEvent, t as eventPlugin } from "../eventPlugin-DCUjuiQT.mjs";
2
+ import { n as createSafeGetOne, t as createIsDuplicateKeyError } from "../store-helpers-ZCSMJJAX.mjs";
3
3
  //#region src/events/defineEvent.ts
4
4
  /**
5
5
  * defineEvent — Typed Event Definitions with Optional Schema Validation
@@ -346,11 +346,19 @@ function repositoryAsOutboxStore(repository) {
346
346
  const missing = [];
347
347
  if (typeof repository.create !== "function") missing.push("create");
348
348
  if (typeof repository.getOne !== "function") missing.push("getOne");
349
- if (typeof repository.findAll !== "function") missing.push("findAll");
349
+ if (typeof repository.getAll !== "function") missing.push("getAll");
350
350
  if (typeof repository.deleteMany !== "function") missing.push("deleteMany");
351
351
  if (typeof repository.findOneAndUpdate !== "function") missing.push("findOneAndUpdate");
352
- if (missing.length > 0) throw new Error(`EventOutbox: repository is missing required methods: ${missing.join(", ")}. mongokit ≥3.8 satisfies all five; other kits must implement them to back the outbox.`);
352
+ if (missing.length > 0) throw new Error(`EventOutbox: repository is missing required methods: ${missing.join(", ")}. mongokit ≥3.10.2 satisfies all five; other kits must implement them to back the outbox.`);
353
353
  const r = repository;
354
+ /**
355
+ * Unwrap mongokit's pagination envelope ({ docs, total, ... }) — some
356
+ * kits may return a bare array when pagination is disabled. Handle both.
357
+ */
358
+ const unwrapDocs = (result) => {
359
+ if (Array.isArray(result)) return result;
360
+ return result?.docs ?? [];
361
+ };
354
362
  const isDuplicateKeyError = createIsDuplicateKeyError(repository);
355
363
  const safeGetOne = createSafeGetOne(repository);
356
364
  const isWellFormed = (event) => !!event && typeof event.type === "string" && !!event.meta?.id;
@@ -386,12 +394,14 @@ function repositoryAsOutboxStore(repository) {
386
394
  },
387
395
  async getPending(limit) {
388
396
  const now = /* @__PURE__ */ new Date();
389
- return (await r.findAll({
390
- status: "pending",
391
- visibleAt: { $lte: now },
392
- $or: [{ leaseOwner: null }, { leaseExpiresAt: { $lte: now } }]
393
- }, {
397
+ return unwrapDocs(await r.getAll({
398
+ filters: {
399
+ status: "pending",
400
+ visibleAt: { $lte: now },
401
+ $or: [{ leaseOwner: null }, { leaseExpiresAt: { $lte: now } }]
402
+ },
394
403
  sort: { createdAt: 1 },
404
+ page: 1,
395
405
  limit
396
406
  })).map((d) => d.event).filter(isWellFormed);
397
407
  },
@@ -460,14 +470,19 @@ function repositoryAsOutboxStore(repository) {
460
470
  },
461
471
  firstFailedAt: { $ifNull: ["$firstFailedAt", now] }
462
472
  } }];
463
- if (await r.findOneAndUpdate(filter, pipeline, { returnDocument: "after" })) return;
473
+ if (await r.findOneAndUpdate(filter, pipeline, {
474
+ returnDocument: "after",
475
+ updatePipeline: true
476
+ })) return;
464
477
  const current = await safeGetOne({ _id: eventId });
465
478
  if (!current) return;
466
479
  if (options?.consumerId && current.leaseOwner !== options.consumerId) throw new OutboxOwnershipError(eventId, options.consumerId, current.leaseOwner);
467
480
  },
468
481
  async getDeadLettered(limit) {
469
- return (await r.findAll({ status: "dead_letter" }, {
482
+ return unwrapDocs(await r.getAll({
483
+ filters: { status: "dead_letter" },
470
484
  sort: { _id: 1 },
485
+ page: 1,
471
486
  limit
472
487
  })).filter((d) => isWellFormed(d.event)).map((d) => ({
473
488
  event: d.event,
@@ -484,14 +499,16 @@ function repositoryAsOutboxStore(repository) {
484
499
  const cutoff = new Date(Date.now() - olderThanMs);
485
500
  let totalDeleted = 0;
486
501
  for (;;) {
487
- const batch = await r.findAll({
488
- status: "delivered",
489
- deliveredAt: { $lte: cutoff }
490
- }, {
502
+ const batch = unwrapDocs(await r.getAll({
503
+ filters: {
504
+ status: "delivered",
505
+ deliveredAt: { $lte: cutoff }
506
+ },
491
507
  sort: { deliveredAt: 1 },
508
+ page: 1,
492
509
  limit: DEFAULT_PURGE_BATCH,
493
510
  select: "_id"
494
- });
511
+ }));
495
512
  if (batch.length === 0) break;
496
513
  const ids = batch.map((d) => d._id);
497
514
  const res = await r.deleteMany({ _id: { $in: ids } });
@@ -843,4 +860,4 @@ function exponentialBackoff(options) {
843
860
  return new Date(now + jittered);
844
861
  }
845
862
  //#endregion
846
- export { ARC_LIFECYCLE_EVENTS, CACHE_EVENTS, CRUD_EVENT_SUFFIXES, EventOutbox, InvalidOutboxEventError, MemoryEventTransport, MemoryOutboxStore, OutboxOwnershipError, createChildEvent, createDeadLetterPublisher, createEvent, createEventRegistry, crudEventType, defineEvent, eventPlugin, exponentialBackoff, withRetry };
863
+ export { ARC_LIFECYCLE_EVENTS, CACHE_EVENTS, CRUD_EVENT_SUFFIXES, EventOutbox, InvalidOutboxEventError, MemoryEventTransport, MemoryOutboxStore, OutboxOwnershipError, createChildEvent, createDeadLetterPublisher, createEvent, createEventRegistry, crudEventType, defineEvent, eventPlugin, exponentialBackoff, repositoryAsOutboxStore, withRetry };
@@ -1,2 +1,2 @@
1
- import { n as RedisStreamTransport, r as RedisStreamTransportOptions, t as RedisStreamLike } from "../../redis-stream-Bz-4q96t.mjs";
1
+ import { n as RedisStreamTransport, r as RedisStreamTransportOptions, t as RedisStreamLike } from "../../redis-stream-CakIQmwR.mjs";
2
2
  export { type RedisStreamLike, RedisStreamTransport, type RedisStreamTransportOptions };
@@ -1,4 +1,4 @@
1
- import { i as EventLogger, n as DomainEvent, o as EventTransport, r as EventHandler } from "../../EventTransport-CqZ8FyM_.mjs";
1
+ import { i as EventLogger, n as DomainEvent, o as EventTransport, r as EventHandler } from "../../EventTransport-CUw5NNWe.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-CunEX4UX.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-Co8k3NyS.mjs";
2
2
  import { FastifyInstance } from "fastify";
3
3
 
4
4
  //#region src/factory/createApp.d.ts
@@ -1,5 +1,5 @@
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-CBJUJKGP.mjs";
2
- import { t as loadResources } from "../loadResources-Bksk8ydA.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-BuvPma24.mjs";
2
+ import { t as loadResources } from "../loadResources-BAzJItAJ.mjs";
3
3
  //#region src/factory/edge.ts
4
4
  /**
5
5
  * Convert a Fastify app into a Web Standards fetch handler.
@@ -175,4 +175,124 @@ interface PermissionCheckMeta {
175
175
  _orgInScopeTarget?: string | ((ctx: PermissionContext) => string | undefined);
176
176
  }
177
177
  //#endregion
178
- export { getUserRoles as a, UserBase as i, PermissionContext as n, normalizeRoles as o, PermissionResult as r, PermissionCheck as t };
178
+ //#region src/permissions/fields.d.ts
179
+ /**
180
+ * Field-Level Permissions
181
+ *
182
+ * Control field visibility and writability per role.
183
+ * Integrated into the response path (read) and sanitization path (write).
184
+ *
185
+ * @example
186
+ * ```typescript
187
+ * import { fields, defineResource } from '@classytic/arc';
188
+ *
189
+ * const userResource = defineResource({
190
+ * name: 'user',
191
+ * adapter: userAdapter,
192
+ * fields: {
193
+ * salary: fields.visibleTo(['admin', 'hr']),
194
+ * internalNotes: fields.writableBy(['admin']),
195
+ * email: fields.redactFor(['viewer']),
196
+ * password: fields.hidden(),
197
+ * },
198
+ * });
199
+ * ```
200
+ */
201
+ type FieldPermissionType = "hidden" | "visibleTo" | "writableBy" | "redactFor";
202
+ interface FieldPermission {
203
+ readonly _type: FieldPermissionType;
204
+ readonly roles?: readonly string[];
205
+ readonly redactValue?: unknown;
206
+ }
207
+ type FieldPermissionMap = Record<string, FieldPermission>;
208
+ declare const fields: {
209
+ /**
210
+ * Field is never included in responses. Not writable via API.
211
+ *
212
+ * @example
213
+ * ```typescript
214
+ * fields: { password: fields.hidden() }
215
+ * ```
216
+ */
217
+ hidden(): FieldPermission;
218
+ /**
219
+ * Field is only visible to users with specified roles.
220
+ * Other users don't see the field at all.
221
+ *
222
+ * @example
223
+ * ```typescript
224
+ * fields: { salary: fields.visibleTo(['admin', 'hr']) }
225
+ * ```
226
+ */
227
+ visibleTo(roles: readonly string[]): FieldPermission;
228
+ /**
229
+ * Field is only writable by users with specified roles.
230
+ * All users can still read the field. Users without the role
231
+ * have the field silently stripped from write operations.
232
+ *
233
+ * @example
234
+ * ```typescript
235
+ * fields: { role: fields.writableBy(['admin']) }
236
+ * ```
237
+ */
238
+ writableBy(roles: readonly string[]): FieldPermission;
239
+ /**
240
+ * Field is redacted (replaced with a placeholder) for specified roles.
241
+ * Other users see the real value.
242
+ *
243
+ * @param roles - Roles that see the redacted value
244
+ * @param redactValue - Replacement value (default: '***')
245
+ *
246
+ * @example
247
+ * ```typescript
248
+ * fields: {
249
+ * email: fields.redactFor(['viewer']),
250
+ * ssn: fields.redactFor(['basic'], '***-**-****'),
251
+ * }
252
+ * ```
253
+ */
254
+ redactFor(roles: readonly string[], redactValue?: unknown): FieldPermission;
255
+ };
256
+ /**
257
+ * Apply field-level READ permissions to a response object.
258
+ * Strips hidden fields, enforces visibility, and applies redaction.
259
+ *
260
+ * @param data - The response object (mutated in place for performance)
261
+ * @param fieldPermissions - Field permission map from resource config
262
+ * @param userRoles - Current user's roles (empty array for unauthenticated)
263
+ * @returns The filtered object
264
+ */
265
+ declare function applyFieldReadPermissions<T extends Record<string, unknown>>(data: T, fieldPermissions: FieldPermissionMap, userRoles: readonly string[]): T;
266
+ /**
267
+ * Result of applying write permissions — includes both the filtered body
268
+ * and the list of fields that were stripped so callers can decide whether
269
+ * to reject the request (secure default) or silently strip (legacy).
270
+ */
271
+ interface FieldWritePermissionResult<T extends Record<string, unknown>> {
272
+ readonly body: T;
273
+ readonly deniedFields: readonly string[];
274
+ }
275
+ /**
276
+ * Apply field-level WRITE permissions to request body.
277
+ *
278
+ * Returns both the filtered body and the list of denied fields. Callers are
279
+ * expected to reject the request when `deniedFields.length > 0` — silently
280
+ * stripping fields hides misconfigurations and real attacks. See
281
+ * `BodySanitizer` for the default policy.
282
+ *
283
+ * @param body - The request body (returns a new filtered copy)
284
+ * @param fieldPermissions - Field permission map from resource config
285
+ * @param userRoles - Current user's roles
286
+ */
287
+ declare function applyFieldWritePermissions<T extends Record<string, unknown>>(body: T, fieldPermissions: FieldPermissionMap, userRoles: readonly string[]): FieldWritePermissionResult<T>;
288
+ /**
289
+ * Resolve effective roles by merging global user roles with org-level roles.
290
+ *
291
+ * Global roles come from `req.user.role` (normalized via getUserRoles()).
292
+ * Org roles come from `req.context.orgRoles` (set by BA adapter's org bridge).
293
+ *
294
+ * When no org context exists, returns global roles only — backward compatible.
295
+ */
296
+ declare function resolveEffectiveRoles(userRoles: readonly string[], orgRoles: readonly string[]): string[];
297
+ //#endregion
298
+ export { applyFieldWritePermissions as a, PermissionCheck as c, UserBase as d, getUserRoles as f, applyFieldReadPermissions as i, PermissionContext as l, FieldPermissionMap as n, fields as o, normalizeRoles as p, FieldPermissionType as r, resolveEffectiveRoles as s, FieldPermission as t, PermissionResult as u };
@@ -1,6 +1,6 @@
1
1
  import { o as getOrgId, p as getUserId } from "./types-AOD8fxIw.mjs";
2
- import { i as NotFoundError, u as ValidationError } from "./errors-CqWnSqM-.mjs";
3
- import { n as allowPublic, s as requireAuth } from "./permissions-oNZawnkR.mjs";
2
+ import { i as NotFoundError, u as ValidationError } from "./errors-D5c-5BJL.mjs";
3
+ import { C as requireAuth, y as allowPublic } from "./permissions-Dk6mshja.mjs";
4
4
  //#region src/middleware/multipartBody.ts
5
5
  const DEFAULT_MAX_FILE_SIZE$1 = 10 * 1024 * 1024;
6
6
  const DEFAULT_MAX_FILES = 5;
@@ -1,2 +1,2 @@
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-YrWsmKqE.mjs";
1
+ import { $t as HookPhase, Qt as HookOperation, Xt as HookContext, Yt as DefineHookOptions, Zt as HookHandler, an as afterUpdate, cn as beforeUpdate, en as HookRegistration, in as afterDelete, ln as createHookSystem, nn as HookSystemOptions, on as beforeCreate, rn as afterCreate, sn as beforeDelete, tn as HookSystem, un as defineHook } from "../index-Cl0uoKd5.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,2 +1,2 @@
1
- import { a as beforeCreate, c as createHookSystem, i as afterUpdate, l as defineHook, n as afterCreate, o as beforeDelete, r as afterDelete, s as beforeUpdate, t as HookSystem } from "../HookSystem-BjFu7zf1.mjs";
1
+ import { a as beforeCreate, c as createHookSystem, i as afterUpdate, l as defineHook, n as afterCreate, o as beforeDelete, r as afterDelete, s as beforeUpdate, t as HookSystem } from "../HookSystem-BNYKnrXF.mjs";
2
2
  export { HookSystem, afterCreate, afterDelete, afterUpdate, beforeCreate, beforeDelete, beforeUpdate, createHookSystem, defineHook };
@@ -1,6 +1,6 @@
1
- import { o as RepositoryLike } from "../interface-YrWsmKqE.mjs";
2
- import { i as createIdempotencyResult, n as IdempotencyResult, r as IdempotencyStore, t as IdempotencyLock } from "../interface-B-pe8fhj.mjs";
3
- import { i as RedisIdempotencyStoreOptions, n as RedisClient } from "../redis-MXLp1oOf.mjs";
1
+ import { kt as RepositoryLike } from "../index-Cl0uoKd5.mjs";
2
+ import { i as createIdempotencyResult, n as IdempotencyResult, r as IdempotencyStore, t as IdempotencyLock } from "../interface-CSbZdv_3.mjs";
3
+ import { i as RedisIdempotencyStoreOptions, n as RedisClient } from "../redis-DqyeggCa.mjs";
4
4
  import { FastifyPluginAsync } from "fastify";
5
5
 
6
6
  //#region src/idempotency/idempotencyPlugin.d.ts
@@ -82,6 +82,9 @@ declare module "fastify" {
82
82
  declare const idempotencyPlugin: FastifyPluginAsync<IdempotencyPluginOptions>;
83
83
  declare const _default: FastifyPluginAsync<IdempotencyPluginOptions>;
84
84
  //#endregion
85
+ //#region src/idempotency/repository-idempotency-adapter.d.ts
86
+ declare function repositoryAsIdempotencyStore(repository: RepositoryLike, defaultTtlMs: number): IdempotencyStore;
87
+ //#endregion
85
88
  //#region src/idempotency/stores/memory.d.ts
86
89
  interface MemoryIdempotencyStoreOptions {
87
90
  /** Default TTL in milliseconds (default: 86400000 = 24h) */
@@ -117,4 +120,4 @@ declare class MemoryIdempotencyStore implements IdempotencyStore {
117
120
  private evictOldest;
118
121
  }
119
122
  //#endregion
120
- export { type IdempotencyLock, type IdempotencyPluginOptions, type IdempotencyResult, type IdempotencyStore, MemoryIdempotencyStore, type MemoryIdempotencyStoreOptions, type RedisClient, type RedisIdempotencyStoreOptions, createIdempotencyResult, _default as idempotencyPlugin, idempotencyPlugin as idempotencyPluginFn };
123
+ export { type IdempotencyLock, type IdempotencyPluginOptions, type IdempotencyResult, type IdempotencyStore, MemoryIdempotencyStore, type MemoryIdempotencyStoreOptions, type RedisClient, type RedisIdempotencyStoreOptions, createIdempotencyResult, _default as idempotencyPlugin, idempotencyPlugin as idempotencyPluginFn, repositoryAsIdempotencyStore };
@@ -1,4 +1,4 @@
1
- import { n as createSafeGetOne, t as createIsDuplicateKeyError } from "../store-helpers-DFiZl5TL.mjs";
1
+ import { n as createSafeGetOne, t as createIsDuplicateKeyError } from "../store-helpers-ZCSMJJAX.mjs";
2
2
  import { createHash } from "node:crypto";
3
3
  import fp from "fastify-plugin";
4
4
  //#region src/idempotency/repository-idempotency-adapter.ts
@@ -361,6 +361,7 @@ const idempotencyPlugin = async (fastify, opts = {}) => {
361
361
  return;
362
362
  }
363
363
  request._idempotencyFullKey = fullKey;
364
+ reply.header(HEADER_IDEMPOTENCY_KEY, idempotencyKey);
364
365
  };
365
366
  fastify.decorate("idempotency", {
366
367
  invalidate: async (key) => {
@@ -371,15 +372,12 @@ const idempotencyPlugin = async (fastify, opts = {}) => {
371
372
  },
372
373
  middleware: idempotencyMiddleware
373
374
  });
374
- fastify.addHook("onSend", async (request, reply, payload) => {
375
+ fastify.addHook("preSerialization", async (request, reply, payload) => {
375
376
  if (request.idempotencyReplayed) return payload;
376
377
  const fullKey = request._idempotencyFullKey;
377
378
  if (!fullKey) return payload;
378
379
  const statusCode = reply.statusCode;
379
- if (statusCode < 200 || statusCode >= 300) {
380
- await store.unlock(fullKey, request.id);
381
- return payload;
382
- }
380
+ if (statusCode < 200 || statusCode >= 300) return payload;
383
381
  const headersToCache = {};
384
382
  const excludeHeaders = new Set([
385
383
  "content-length",
@@ -399,13 +397,13 @@ const idempotencyPlugin = async (fastify, opts = {}) => {
399
397
  }
400
398
  const result = createIdempotencyResult(statusCode, body, headersToCache, ttlMs);
401
399
  await store.set(fullKey, result);
402
- await store.unlock(fullKey, request.id);
403
- reply.header(HEADER_IDEMPOTENCY_KEY, request.idempotencyKey);
404
400
  return payload;
405
401
  });
406
- fastify.addHook("onError", async (request) => {
402
+ fastify.addHook("onResponse", async (request) => {
403
+ if (request.idempotencyReplayed) return;
407
404
  const fullKey = request._idempotencyFullKey;
408
- if (fullKey) await store.unlock(fullKey, request.id);
405
+ if (!fullKey) return;
406
+ await store.unlock(fullKey, request.id);
409
407
  });
410
408
  fastify.addHook("onClose", async () => {
411
409
  await store.close?.();
@@ -421,4 +419,4 @@ var idempotencyPlugin_default = fp(idempotencyPlugin, {
421
419
  fastify: "5.x"
422
420
  });
423
421
  //#endregion
424
- export { MemoryIdempotencyStore, createIdempotencyResult, idempotencyPlugin_default as idempotencyPlugin, idempotencyPlugin as idempotencyPluginFn };
422
+ export { MemoryIdempotencyStore, createIdempotencyResult, idempotencyPlugin_default as idempotencyPlugin, idempotencyPlugin as idempotencyPluginFn, repositoryAsIdempotencyStore };
@@ -1,2 +1,2 @@
1
- import { a as UpstashRedisLike, i as RedisIdempotencyStoreOptions, n as RedisClient, o as ioredisAsIdempotencyClient, r as RedisIdempotencyStore, s as upstashAsIdempotencyClient, t as IoredisLike } from "../redis-MXLp1oOf.mjs";
1
+ import { a as UpstashRedisLike, i as RedisIdempotencyStoreOptions, n as RedisClient, o as ioredisAsIdempotencyClient, r as RedisIdempotencyStore, s as upstashAsIdempotencyClient, t as IoredisLike } from "../redis-DqyeggCa.mjs";
2
2
  export { type IoredisLike, type RedisClient, RedisIdempotencyStore, type RedisIdempotencyStoreOptions, type UpstashRedisLike, ioredisAsIdempotencyClient, upstashAsIdempotencyClient };
@@ -1,6 +1,6 @@
1
1
  import { r as RequestScope } from "./types-BD85MlEK.mjs";
2
- import { Bt as IController, E as CrudRouterOptions, Ht as IRequestContext, Kt as ResourceDefinition, M as FastifyWithDecorators, Vt as IControllerResponse, at as RequestContext, lt as ResourceConfig, p as AnyRecord, w as CrudController } from "./interface-YrWsmKqE.mjs";
3
- import { t as PermissionCheck } from "./types-DZi1aYhm.mjs";
2
+ import { c as PermissionCheck } from "./fields-Lo1VUDpt.mjs";
3
+ import { B as FastifyWithDecorators, G as ResourceDefinition, St as IRequestContext, Z as CrudController, bt as IController, dn as AnyRecord, lt as ResourceConfig, qt as RequestContext, w as CrudRouterOptions, xt as IControllerResponse } from "./index-Cl0uoKd5.mjs";
4
4
  import { FastifyReply, FastifyRequest, RouteHandlerMethod } from "fastify";
5
5
 
6
6
  //#region src/constants.d.ts