@classytic/arc 2.28.0 → 2.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/dist/{BaseController-B65zbz9m.mjs → BaseController-B5DwufbB.mjs} +12 -10
  2. package/dist/EventTransport-C6YA8xY9.mjs +103 -0
  3. package/dist/{HookSystem-C1vB_Gc9.mjs → HookSystem-WkIougo6.mjs} +15 -35
  4. package/dist/applyPermissionResult-Cf6zUCvb.mjs +257 -0
  5. package/dist/audit/index.d.mts +2 -2
  6. package/dist/audit/index.mjs +1 -1
  7. package/dist/auth/index.d.mts +2 -2
  8. package/dist/auth/index.mjs +1 -1
  9. package/dist/{buildHandler-Dtwd8fdz.mjs → buildHandler-BYS3Vkfz.mjs} +32 -6
  10. package/dist/cleanup/index.d.mts +2 -2
  11. package/dist/cleanup/index.mjs +1 -1
  12. package/dist/cli/commands/describe.d.mts +1 -1
  13. package/dist/cli/commands/docs.mjs +1 -1
  14. package/dist/core/index.d.mts +2 -2
  15. package/dist/core/index.mjs +5 -4
  16. package/dist/{core-BGa8TXJR.mjs → core-poalJLvp.mjs} +2 -48
  17. package/dist/{createActionRouter-C-N7z2EL.mjs → createActionRouter-BxuywVRB.mjs} +2 -2
  18. package/dist/{createAggregationRouter-wzwFa_dW.mjs → createAggregationRouter-BiY-lGdY.mjs} +7 -20
  19. package/dist/{createApp-Du5G54TM.mjs → createApp-CXrKFciH.mjs} +24 -3
  20. package/dist/defineAggregation-ufWjUwml.mjs +47 -0
  21. package/dist/{defineResource-2zvVVpxg.mjs → defineResource-CxWqDCAy.mjs} +35 -42
  22. package/dist/docs/index.d.mts +1 -1
  23. package/dist/docs/index.mjs +1 -1
  24. package/dist/{eventPlugin-DrQ_FesK.mjs → eventPlugin-D2NNR4py.mjs} +2 -103
  25. package/dist/events/index.mjs +4 -339
  26. package/dist/factory/index.d.mts +4 -4
  27. package/dist/factory/index.mjs +1 -1
  28. package/dist/{fastify-augmentation-OzYGIiU1.d.mts → fastify-augmentation-0WhPnUH7.d.mts} +3 -3
  29. package/dist/{applyPermissionResult-BnyVE9eD.mjs → fields-CQ_7KQWw.mjs} +1 -107
  30. package/dist/hooks/index.d.mts +1 -1
  31. package/dist/hooks/index.mjs +1 -1
  32. package/dist/idempotency/index.mjs +1 -1
  33. package/dist/{index-CZY4EGga.d.mts → index-CCzVR-N3.d.mts} +1 -1
  34. package/dist/{index-BMnbzvtO.d.mts → index-Ch16aAah.d.mts} +201 -21
  35. package/dist/{index-CjVg-Epg.d.mts → index-Cx7bro4R.d.mts} +4 -4
  36. package/dist/{index-DPRH0Cme.d.mts → index-Q5gzEIWY.d.mts} +97 -66
  37. package/dist/index.d.mts +6 -6
  38. package/dist/index.mjs +8 -7
  39. package/dist/integrations/index.d.mts +1 -1
  40. package/dist/integrations/mcp/index.d.mts +6 -6
  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/{mcpPlugin-Cs6nRGCt.mjs → mcpPlugin-nRzm5g2s.mjs} +36 -43
  45. package/dist/middleware/index.d.mts +1 -1
  46. package/dist/migrations/index.d.mts +0 -3
  47. package/dist/migrations/index.mjs +0 -3
  48. package/dist/{openapi-BLV4OMXb.mjs → openapi-B8Vkbxbn.mjs} +1 -1
  49. package/dist/permissions/index.d.mts +3 -3
  50. package/dist/permissions/index.mjs +4 -3
  51. package/dist/{permissions-BrtiBKGs.mjs → permissions-Bfu_8y1U.mjs} +318 -289
  52. package/dist/pipeline/index.d.mts +1 -1
  53. package/dist/{pipeline-BGRnV-To.mjs → pipeline-BJnpkY9i.mjs} +4 -18
  54. package/dist/plugins/index.d.mts +4 -4
  55. package/dist/plugins/index.mjs +2 -2
  56. package/dist/plugins/tracing-entry.mjs +1 -1
  57. package/dist/{preloadResources-CM4uUaFv.d.mts → preloadResources-DCfa2egz.d.mts} +3 -3
  58. package/dist/presets/filesUpload.d.mts +2 -2
  59. package/dist/presets/filesUpload.mjs +1 -1
  60. package/dist/presets/index.d.mts +14 -2
  61. package/dist/presets/index.mjs +1 -1
  62. package/dist/presets/multiTenant.d.mts +1 -1
  63. package/dist/presets/search.d.mts +2 -2
  64. package/dist/presets/search.mjs +1 -1
  65. package/dist/{presets-DwFDVKP0.mjs → presets-CJOEXLuk.mjs} +25 -9
  66. package/dist/projection-UBDgfMwu.mjs +17 -0
  67. package/dist/{realtime-DEuDu9io.mjs → realtime-B9nmIY5V.mjs} +2 -1
  68. package/dist/{registerRoute-DTp18Ah_.mjs → registerRoute-JkxIEBJq.mjs} +3 -1
  69. package/dist/registry/index.d.mts +2 -2
  70. package/dist/registry/index.mjs +1 -1
  71. package/dist/{registry-9km_w1aP.mjs → registry-BYXUUg21.mjs} +1 -1
  72. package/dist/repositoryFilter-Dz8k3S4P.mjs +44 -0
  73. package/dist/subscribe-helpers-DfzsivM6.mjs +339 -0
  74. package/dist/testing/index.d.mts +34 -6
  75. package/dist/testing/index.mjs +314 -211
  76. package/dist/types/index.d.mts +3 -3
  77. package/dist/{types-QFGc3Cjv.d.mts → types-Bmmn-fO0.d.mts} +1 -1
  78. package/dist/{types-Dmw-6Qeo.d.mts → types-ChvvVNP8.d.mts} +93 -88
  79. package/dist/{types-Cu6vVJmh.d.mts → types-D_n8L6VY.d.mts} +32 -1
  80. package/dist/usage/index.d.mts +1 -1
  81. package/dist/usage/index.mjs +0 -0
  82. package/dist/utils/index.d.mts +2 -5
  83. package/package.json +539 -539
@@ -1,6 +1,6 @@
1
- import { L as RequestWithExtras } from "../index-DPRH0Cme.mjs";
1
+ import { L as RequestWithExtras } from "../index-Q5gzEIWY.mjs";
2
2
  import { A as CleanupWriteFence, C as CleanupResult, D as CleanupRunStore, E as CleanupRunStatus, F as PurgeStrategyKind, I as PurgeVerificationSummary, L as VerificationCheck, M as PurgeActor, N as PurgeEvidence, O as CleanupRunTransitionPatch, P as PurgeResourceResult, R as VerificationResult, S as CleanupRecipe, T as CleanupRunCreateResult, _ as CleanupPermissions, a as CleanupEvidenceStore, b as CleanupPlanItem, c as CleanupInput, d as CleanupLease, f as CleanupLimits, g as CleanupPermissionCheck, h as CleanupOutcomeStatus, i as CleanupContext, j as DEFAULT_CLEANUP_LIMITS, k as CleanupStepResult, l as CleanupJob, m as CleanupManifest, n as CLEANUP_TERMINAL_STATUSES, o as CleanupExecutionContext, p as CleanupLogger, r as CleanupCancelRequest, s as CleanupFinalizationPayload, t as Availability, u as CleanupJobQueue, v as CleanupPlan, w as CleanupRun, x as CleanupProgressSummary, y as CleanupPlanDraft } from "../types-C_ZZRcD6.mjs";
3
- import { t as ArcModule } from "../types-Cu6vVJmh.mjs";
3
+ import { t as ArcModule } from "../types-D_n8L6VY.mjs";
4
4
  import { PurgeStrategyKind as PurgeStrategyKind$1 } from "@classytic/primitives/retention";
5
5
  import { canonicalJson } from "@classytic/primitives/canonical";
6
6
  import { CleanupStep } from "@classytic/repo-core/cleanup";
@@ -1,5 +1,5 @@
1
1
  import { g as getUserId } from "../types-CSyCxl2V.mjs";
2
- import { t as defineResource } from "../defineResource-2zvVVpxg.mjs";
2
+ import { t as defineResource } from "../defineResource-CxWqDCAy.mjs";
3
3
  import { t as defineModule } from "../module-_-M7C5ES.mjs";
4
4
  import { createPurgeEvidence } from "@classytic/primitives/retention";
5
5
  import { canonicalJson, sha256Hex } from "@classytic/primitives/canonical";
@@ -1,4 +1,4 @@
1
- import { Nt as RateLimitConfig, V as ResourceDefinition, et as RouteSchemaOptions } from "../../index-DPRH0Cme.mjs";
1
+ import { Nt as RateLimitConfig, V as ResourceDefinition, et as RouteSchemaOptions } from "../../index-Q5gzEIWY.mjs";
2
2
  //#region src/cli/commands/describe.d.ts
3
3
  interface DescribedResource {
4
4
  name: string;
@@ -1,4 +1,4 @@
1
- import { t as buildOpenApiSpec } from "../../openapi-BLV4OMXb.mjs";
1
+ import { t as buildOpenApiSpec } from "../../openapi-B8Vkbxbn.mjs";
2
2
  import { t as loadResourcesFromEntry } from "../../loadResourcesFromEntry-kvGT6EcO.mjs";
3
3
  import { dirname, resolve } from "node:path";
4
4
  import { mkdirSync, writeFileSync } from "node:fs";
@@ -1,3 +1,3 @@
1
- import { $t as SlugExt, An as ControllerConfigurableOptions, B as defineResource, Jt as BaseController, Mn as ListResult, Nn as BodySanitizer, Pn as BodySanitizerConfig, Qt as TreeMixin, V as ResourceDefinition, Xt as SoftDeleteMixin, Yt as SoftDeleteExt, Zt as TreeExt, an as QueryResolverConfig, ct as AggMeasureShorthand, dt as AggregationDateRangeRequirement, en as SlugMixin, ft as AggregationIndexHint, gt as AggregationsMap, ht as AggregationRateLimit, in as QueryResolver, jn as ControllerConstructionOptions, kn as BaseControllerOptions, lt as AggregationCacheConfig, mt as AggregationMaterializedResult, nn as BulkMixin, on as AccessControl, pt as AggregationMaterializedContext, rn as BaseCrudController, sn as AccessControlConfig, st as AggMeasureInput, tn as BulkExt, ut as AggregationConfig } from "../index-DPRH0Cme.mjs";
2
- import { A as DEFAULT_ID_FIELD, B as MAX_FILTER_DEPTH, C as DefineActionConfig, D as defineAggregation, E as createPermissionMiddleware, F as DEFAULT_UPDATE_METHOD, G as RESERVED_QUERY_PARAMS, H as MAX_SEARCH_LENGTH, I as HOOK_OPERATIONS, K as SYSTEM_FIELDS, L as HOOK_PHASES, M as DEFAULT_MAX_LIMIT, N as DEFAULT_SORT, O as CRUD_OPERATIONS, P as DEFAULT_TENANT_FIELD, R as HookOperation, S as mergeResourceConfig, T as createCrudRouter, U as MUTATION_OPERATIONS, V as MAX_REGEX_LENGTH, W as MutationOperation, _ as getEntityQuery, a as formatValidationErrors, b as ResourceSeams, c as isFieldReadable, d as createRequestContext, f as getControllerContext, g as getEntityIdField, h as getEntityId, i as assertValidConfig, j as DEFAULT_LIMIT, k as CrudOperation, l as createCrudHandlers, m as sendControllerResponse, n as ValidateOptions, o as validateResourceConfig, p as getControllerScope, r as ValidationResult, s as collectReadBlockedFields, t as ConfigError, u as createFastifyHandler, v as defineResourceVariants, w as defineAction, x as SeamedResourceConfig, y as AdapterLike, z as HookPhase } from "../index-CjVg-Epg.mjs";
1
+ import { $t as SlugExt, An as ControllerConfigurableOptions, B as defineResource, Jt as BaseController, Mn as ListResult, Nn as BodySanitizer, Pn as BodySanitizerConfig, Qt as TreeMixin, V as ResourceDefinition, Xt as SoftDeleteMixin, Yt as SoftDeleteExt, Zt as TreeExt, an as QueryResolverConfig, ct as AggMeasureShorthand, dt as AggregationDateRangeRequirement, en as SlugMixin, ft as AggregationIndexHint, gt as AggregationsMap, ht as AggregationRateLimit, in as QueryResolver, jn as ControllerConstructionOptions, kn as BaseControllerOptions, lt as AggregationCacheConfig, mt as AggregationMaterializedResult, nn as BulkMixin, on as AccessControl, pt as AggregationMaterializedContext, rn as BaseCrudController, sn as AccessControlConfig, st as AggMeasureInput, tn as BulkExt, ut as AggregationConfig } from "../index-Q5gzEIWY.mjs";
2
+ import { A as DEFAULT_ID_FIELD, B as MAX_FILTER_DEPTH, C as DefineActionConfig, D as defineAggregation, E as createPermissionMiddleware, F as DEFAULT_UPDATE_METHOD, G as RESERVED_QUERY_PARAMS, H as MAX_SEARCH_LENGTH, I as HOOK_OPERATIONS, K as SYSTEM_FIELDS, L as HOOK_PHASES, M as DEFAULT_MAX_LIMIT, N as DEFAULT_SORT, O as CRUD_OPERATIONS, P as DEFAULT_TENANT_FIELD, R as HookOperation, S as mergeResourceConfig, T as createCrudRouter, U as MUTATION_OPERATIONS, V as MAX_REGEX_LENGTH, W as MutationOperation, _ as getEntityQuery, a as formatValidationErrors, b as ResourceSeams, c as isFieldReadable, d as createRequestContext, f as getControllerContext, g as getEntityIdField, h as getEntityId, i as assertValidConfig, j as DEFAULT_LIMIT, k as CrudOperation, l as createCrudHandlers, m as sendControllerResponse, n as ValidateOptions, o as validateResourceConfig, p as getControllerScope, r as ValidationResult, s as collectReadBlockedFields, t as ConfigError, u as createFastifyHandler, v as defineResourceVariants, w as defineAction, x as SeamedResourceConfig, y as AdapterLike, z as HookPhase } from "../index-Cx7bro4R.mjs";
3
3
  export { AccessControl, type AccessControlConfig, type AdapterLike, type AggMeasureInput, type AggMeasureShorthand, type AggregationCacheConfig, type AggregationConfig, type AggregationDateRangeRequirement, type AggregationIndexHint, type AggregationMaterializedContext, type AggregationMaterializedResult, type AggregationRateLimit, type AggregationsMap, BaseController, type BaseControllerOptions, BaseCrudController, BodySanitizer, type BodySanitizerConfig, type BulkExt, BulkMixin, CRUD_OPERATIONS, type ConfigError, type ControllerConfigurableOptions, type ControllerConstructionOptions, CrudOperation, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, type DefineActionConfig, HOOK_OPERATIONS, HOOK_PHASES, HookOperation, HookPhase, type ListResult, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, MutationOperation, QueryResolver, type QueryResolverConfig, RESERVED_QUERY_PARAMS, ResourceDefinition, type ResourceSeams, SYSTEM_FIELDS, type SeamedResourceConfig, type SlugExt, SlugMixin, type SoftDeleteExt, SoftDeleteMixin, type TreeExt, TreeMixin, type ValidateOptions, type ValidationResult, assertValidConfig, collectReadBlockedFields, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineAction, defineAggregation, defineResource, defineResourceVariants, formatValidationErrors, getControllerContext, getControllerScope, getEntityId, getEntityIdField, getEntityQuery, isFieldReadable, mergeResourceConfig, sendControllerResponse, validateResourceConfig };
@@ -1,6 +1,7 @@
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-DNre0wRg.mjs";
2
- import { a as BulkMixin, c as collectReadBlockedFields, f as AccessControl, i as SlugMixin, l as isFieldReadable, n as TreeMixin, o as BaseCrudController, r as SoftDeleteMixin, s as QueryResolver, t as BaseController, u as BodySanitizer } from "../BaseController-B65zbz9m.mjs";
3
- import { a as ResourceDefinition, i as validateResourceConfig, n as assertValidConfig, o as createCrudRouter, r as formatValidationErrors, s as createPermissionMiddleware, t as defineResource } from "../defineResource-2zvVVpxg.mjs";
4
- import { a as createFastifyHandler, c as getControllerScope, i as createCrudHandlers, l as sendControllerResponse, o as createRequestContext, s as getControllerContext } from "../pipeline-BGRnV-To.mjs";
5
- import { a as mergeResourceConfig, i as defineResourceVariants, n as getEntityIdField, o as defineAction, r as getEntityQuery, s as defineAggregation, t as getEntityId } from "../core-BGa8TXJR.mjs";
2
+ import { a as BulkMixin, c as collectReadBlockedFields, f as AccessControl, i as SlugMixin, l as isFieldReadable, n as TreeMixin, o as BaseCrudController, r as SoftDeleteMixin, s as QueryResolver, t as BaseController, u as BodySanitizer } from "../BaseController-B5DwufbB.mjs";
3
+ import { a as ResourceDefinition, i as validateResourceConfig, n as assertValidConfig, o as createCrudRouter, r as formatValidationErrors, s as createPermissionMiddleware, t as defineResource } from "../defineResource-CxWqDCAy.mjs";
4
+ import { a as createFastifyHandler, c as getControllerScope, i as createCrudHandlers, l as sendControllerResponse, o as createRequestContext, s as getControllerContext } from "../pipeline-BJnpkY9i.mjs";
5
+ import { t as defineAggregation } from "../defineAggregation-ufWjUwml.mjs";
6
+ import { a as mergeResourceConfig, i as defineResourceVariants, n as getEntityIdField, o as defineAction, r as getEntityQuery, t as getEntityId } from "../core-poalJLvp.mjs";
6
7
  export { AccessControl, BaseController, BaseCrudController, BodySanitizer, BulkMixin, CRUD_OPERATIONS, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, HOOK_OPERATIONS, HOOK_PHASES, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, QueryResolver, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, SlugMixin, SoftDeleteMixin, TreeMixin, assertValidConfig, collectReadBlockedFields, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineAction, defineAggregation, defineResource, defineResourceVariants, formatValidationErrors, getControllerContext, getControllerScope, getEntityId, getEntityIdField, getEntityQuery, isFieldReadable, mergeResourceConfig, sendControllerResponse, validateResourceConfig };
@@ -1,51 +1,5 @@
1
1
  import "./constants-DNre0wRg.mjs";
2
- import { t as defineResource } from "./defineResource-2zvVVpxg.mjs";
3
- //#region src/core/aggregation/defineAggregation.ts
4
- /**
5
- * Declare a single resource aggregation. Exported configs flow into
6
- * `defineResource({ aggregations: { ... } })` either as named keys or
7
- * via auto-discovery patterns (loadAggregations — future).
8
- *
9
- * @example Inline
10
- * ```ts
11
- * defineResource({
12
- * name: 'order',
13
- * aggregations: {
14
- * revenueByStatus: defineAggregation({
15
- * groupBy: 'status',
16
- * measures: { count: 'count', revenue: 'sum:totalPrice' },
17
- * permissions: requireRoles(['admin']),
18
- * }),
19
- * },
20
- * });
21
- * ```
22
- *
23
- * @example Multi-file
24
- * ```ts
25
- * // orders/aggregations/revenue-by-status.ts
26
- * import { defineAggregation } from '@classytic/arc';
27
- *
28
- * export const revenueByStatus = defineAggregation({
29
- * groupBy: 'status',
30
- * measures: { count: 'count', revenue: 'sum:totalPrice' },
31
- * permissions: requireRoles(['admin']),
32
- * timeout: 5000,
33
- * cache: { staleTime: 60 },
34
- * });
35
- *
36
- * // orders/order.resource.ts
37
- * import * as aggregations from './aggregations/index.js';
38
- *
39
- * defineResource({
40
- * name: 'order',
41
- * aggregations, // 30+ entries flow in
42
- * });
43
- * ```
44
- */
45
- function defineAggregation(config) {
46
- return config;
47
- }
48
- //#endregion
2
+ import { t as defineResource } from "./defineResource-CxWqDCAy.mjs";
49
3
  //#region src/core/defineAction.ts
50
4
  /**
51
5
  * Build an `ActionDefinition` with a typed handler. The literal schema
@@ -218,4 +172,4 @@ function getEntityQuery(req) {
218
172
  return { [getEntityIdField(req)]: id };
219
173
  }
220
174
  //#endregion
221
- export { mergeResourceConfig as a, defineResourceVariants as i, getEntityIdField as n, defineAction as o, getEntityQuery as r, defineAggregation as s, getEntityId as t };
175
+ export { mergeResourceConfig as a, defineResourceVariants as i, getEntityIdField as n, defineAction as o, getEntityQuery as r, getEntityId as t };
@@ -2,8 +2,8 @@ import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.mjs";
2
2
  import "./constants-DNre0wRg.mjs";
3
3
  import { f as createError } from "./errors-DkO8Nk6-.mjs";
4
4
  import { a as buildRouteHooks, i as selectPluginMw, l as buildAuthMiddlewareForPermissions, n as buildRouteConfig, r as resolveRouterPluginMw, s as routeHookOptions, t as buildRateLimitConfig, u as buildArcDecorator } from "./rateLimit-DrED-C4v.mjs";
5
- import { n as buildActionPermissionMw, t as tryRegisterRoute } from "./registerRoute-DTp18Ah_.mjs";
6
- import { l as sendControllerResponse, r as resolvePipelineSteps, t as buildActionPipelineHandler } from "./pipeline-BGRnV-To.mjs";
5
+ import { n as buildActionPermissionMw, t as tryRegisterRoute } from "./registerRoute-JkxIEBJq.mjs";
6
+ import { l as sendControllerResponse, r as resolvePipelineSteps, t as buildActionPipelineHandler } from "./pipeline-BJnpkY9i.mjs";
7
7
  import { n as schemaIRToJsonSchemaBranch, t as normalizeSchemaIR } from "./schemaIR-Ca7ySNPx.mjs";
8
8
  //#region src/core/createActionRouter.ts
9
9
  var createActionRouter_exports = /* @__PURE__ */ __exportAll({
@@ -1,7 +1,9 @@
1
- import { f as createError, l as UnauthorizedError, r as ForbiddenError } from "./errors-DkO8Nk6-.mjs";
1
+ import { f as createError } from "./errors-DkO8Nk6-.mjs";
2
+ import { u as getRequestScope } from "./types-CSyCxl2V.mjs";
3
+ import { r as evaluateAndApplyPermission } from "./applyPermissionResult-Cf6zUCvb.mjs";
2
4
  import { a as buildRouteHooks, c as buildAuthMiddleware, i as selectPluginMw, r as resolveRouterPluginMw, s as routeHookOptions, t as buildRateLimitConfig, u as buildArcDecorator } from "./rateLimit-DrED-C4v.mjs";
3
5
  import { n as validateAggregations } from "./validate-Bk44F2yT.mjs";
4
- import { t as buildAggregationHandler } from "./buildHandler-Dtwd8fdz.mjs";
6
+ import { t as buildAggregationHandler } from "./buildHandler-BYS3Vkfz.mjs";
5
7
  //#region src/core/aggregation/createAggregationRouter.ts
6
8
  /**
7
9
  * Register one Fastify route per aggregation. No-op when the map is
@@ -38,15 +40,9 @@ function registerOne(fastify, normalized, ctx) {
38
40
  const config = normalized.base;
39
41
  const authMw = buildAuthMiddleware(fastify, config.permissions);
40
42
  const permissionFn = config.permissions;
41
- const permissionMw = async (req, _reply) => {
43
+ const permissionMw = async (req, reply) => {
42
44
  const ctx = buildPermissionContextLite(req, normalized.name);
43
- const raw = await permissionFn(ctx);
44
- if (!normalizePermissionGranted(raw)) {
45
- const status = req.user ? 403 : 401;
46
- const reason = normalizePermissionReason(raw);
47
- if (status === 401) throw new UnauthorizedError(reason ?? "Authentication required to access this aggregation.");
48
- throw new ForbiddenError(reason ?? "You do not have permission to access this aggregation.");
49
- }
45
+ await evaluateAndApplyPermission(permissionFn, ctx, req, reply, { defaultDenialMessage: (user) => user ? "You do not have permission to access this aggregation." : "Authentication required to access this aggregation." });
50
46
  };
51
47
  const hooks = buildRouteHooks({
52
48
  arcDecorator,
@@ -99,20 +95,11 @@ function buildPermissionContextLite(req, aggregationName) {
99
95
  const reqWithExtras = req;
100
96
  return {
101
97
  user: reqWithExtras.user ?? null,
98
+ scope: getRequestScope(req),
102
99
  request: req,
103
100
  resource: reqWithExtras.arc?.resource ?? "aggregation",
104
101
  action: `aggregation:${aggregationName}`
105
102
  };
106
103
  }
107
- /** PermissionCheck returns `boolean | PermissionResult`. Pull `granted`. */
108
- function normalizePermissionGranted(raw) {
109
- if (typeof raw === "boolean") return raw;
110
- return raw.granted;
111
- }
112
- /** Pull `reason` when the check returned a structured `PermissionResult`. */
113
- function normalizePermissionReason(raw) {
114
- if (typeof raw === "boolean") return void 0;
115
- return raw.reason;
116
- }
117
104
  //#endregion
118
105
  export { createAggregationRouter };
@@ -4,6 +4,7 @@ import { n as PUBLIC_SCOPE } from "./types-CSyCxl2V.mjs";
4
4
  import { t as createTenantKeyGenerator } from "./rateLimitKey-BoWRH3e7.mjs";
5
5
  import { i as createRequestIdGenerator, r as mergeHealthChecks } from "./health-CB_m4S32.mjs";
6
6
  import { t as parseJsonBody } from "./jsonBody-BlzAoGCe.mjs";
7
+ import { r as wrapWithBoundary } from "./subscribe-helpers-DfzsivM6.mjs";
7
8
  import Fastify from "fastify";
8
9
  import qs from "qs";
9
10
  //#region src/factory/module/resolve.ts
@@ -100,8 +101,9 @@ async function subscribeModuleEventHandlers(fastify, modules) {
100
101
  if (prior !== void 0) throw new Error(`[arc] duplicate event-handler name "${def.name}" — declared by module "${prior}" and module "${m.name}". Named event handlers must be unique across the module graph; prefix names with the owning module.`);
101
102
  owner.set(def.name, m.name);
102
103
  }
104
+ const handler = applyBoundary(def, m.name, fastify);
103
105
  const patterns = Array.isArray(def.event) ? def.event : [def.event];
104
- for (const pattern of patterns) unsubscribes.push(await bus.subscribe(pattern, def.handler));
106
+ for (const pattern of patterns) unsubscribes.push(await bus.subscribe(pattern, handler));
105
107
  }
106
108
  }
107
109
  return unsubscribes;
@@ -111,6 +113,25 @@ async function subscribeModuleEventHandlers(fastify, modules) {
111
113
  throw err;
112
114
  }
113
115
  }
116
+ /**
117
+ * Apply the declaration's opt-in error boundary. Without `boundary`, the raw
118
+ * handler is subscribed and a throw reaches the transport — which is what makes
119
+ * the durable path work (unacked → redelivered → DLQ). With it, failures are
120
+ * logged through `fastify.log` and swallowed, for handlers whose retry would
121
+ * only delay the next event's resync.
122
+ *
123
+ * The boundary label falls back to `<module>.<pattern>` so an unnamed handler
124
+ * still produces an attributable log line instead of "anonymous".
125
+ */
126
+ function applyBoundary(def, moduleName, fastify) {
127
+ if (!def.boundary) return def.handler;
128
+ const onError = typeof def.boundary === "object" ? def.boundary.onError : void 0;
129
+ return wrapWithBoundary(def.handler, {
130
+ logger: fastify.log,
131
+ name: def.name ?? `${moduleName}.${String(def.event)}`,
132
+ ...onError ? { onError } : {}
133
+ });
134
+ }
114
135
  /** Best-effort reverse-order teardown; every unsubscribe is attempted. */
115
136
  async function unsubscribeModuleEventHandlers(unsubscribes) {
116
137
  const errors = [];
@@ -439,7 +460,7 @@ async function registerArcCore(fastify, config, trackPlugin) {
439
460
  await fastify.register(arcCorePlugin, { emitEvents: config.arcPlugins?.emitEvents !== false });
440
461
  trackPlugin("arc-core");
441
462
  if (config.arcPlugins?.events !== false) {
442
- const { default: eventPlugin } = await import("./eventPlugin-DrQ_FesK.mjs").then((n) => n.n);
463
+ const { default: eventPlugin } = await import("./eventPlugin-D2NNR4py.mjs").then((n) => n.n);
443
464
  const eventOpts = typeof config.arcPlugins?.events === "object" ? config.arcPlugins.events : {};
444
465
  await fastify.register(eventPlugin, {
445
466
  ...eventOpts,
@@ -511,7 +532,7 @@ async function registerArcPlugins(fastify, config, trackPlugin, modules, moduleH
511
532
  }
512
533
  if (config.arcPlugins?.realtime) if (config.arcPlugins?.events === false) fastify.log.warn("Realtime plugin requires events plugin (arcPlugins.events). Realtime disabled.");
513
534
  else {
514
- const { default: realtimePlugin } = await import("./realtime-DEuDu9io.mjs").then((n) => n.r);
535
+ const { default: realtimePlugin } = await import("./realtime-B9nmIY5V.mjs").then((n) => n.r);
515
536
  const opts = config.arcPlugins.realtime === true ? {} : config.arcPlugins.realtime;
516
537
  await fastify.register(realtimePlugin, opts);
517
538
  trackPlugin("arc-realtime", opts);
@@ -0,0 +1,47 @@
1
+ //#region src/core/aggregation/defineAggregation.ts
2
+ /**
3
+ * Declare a single resource aggregation. Exported configs flow into
4
+ * `defineResource({ aggregations: { ... } })` either as named keys or
5
+ * via auto-discovery patterns (loadAggregations — future).
6
+ *
7
+ * @example Inline
8
+ * ```ts
9
+ * defineResource({
10
+ * name: 'order',
11
+ * aggregations: {
12
+ * revenueByStatus: defineAggregation({
13
+ * groupBy: 'status',
14
+ * measures: { count: 'count', revenue: 'sum:totalPrice' },
15
+ * permissions: requireRoles(['admin']),
16
+ * }),
17
+ * },
18
+ * });
19
+ * ```
20
+ *
21
+ * @example Multi-file
22
+ * ```ts
23
+ * // orders/aggregations/revenue-by-status.ts
24
+ * import { defineAggregation } from '@classytic/arc';
25
+ *
26
+ * export const revenueByStatus = defineAggregation({
27
+ * groupBy: 'status',
28
+ * measures: { count: 'count', revenue: 'sum:totalPrice' },
29
+ * permissions: requireRoles(['admin']),
30
+ * timeout: 5000,
31
+ * cache: { staleTime: 60 },
32
+ * });
33
+ *
34
+ * // orders/order.resource.ts
35
+ * import * as aggregations from './aggregations/index.js';
36
+ *
37
+ * defineResource({
38
+ * name: 'order',
39
+ * aggregations, // 30+ entries flow in
40
+ * });
41
+ * ```
42
+ */
43
+ function defineAggregation(config) {
44
+ return config;
45
+ }
46
+ //#endregion
47
+ export { defineAggregation as t };
@@ -3,17 +3,17 @@ import { arcLog } from "./logger/index.mjs";
3
3
  import { r as ForbiddenError } from "./errors-DkO8Nk6-.mjs";
4
4
  import { n as getUserRoles } from "./userHelpers-Cg_y3fBz.mjs";
5
5
  import { b as isElevated, n as PUBLIC_SCOPE, x as isMember } from "./types-CSyCxl2V.mjs";
6
- import { d as DEFAULT_FIELD_WRITE_DENIAL_POLICY, t as BaseController } from "./BaseController-B65zbz9m.mjs";
6
+ import { d as DEFAULT_FIELD_WRITE_DENIAL_POLICY, t as BaseController } from "./BaseController-B5DwufbB.mjs";
7
7
  import { a as buildRouteHooks, c as buildAuthMiddleware, i as selectPluginMw, n as buildRouteConfig, o as resolveRoutePreHandlers, r as resolveRouterPluginMw, s as routeHookOptions, t as buildRateLimitConfig, u as buildArcDecorator } from "./rateLimit-DrED-C4v.mjs";
8
- import { a as applyFieldWritePermissions, s as resolveEffectiveRoles } from "./applyPermissionResult-BnyVE9eD.mjs";
9
- import { r as buildCrudPermissionMw, t as tryRegisterRoute } from "./registerRoute-DTp18Ah_.mjs";
8
+ import { i as resolveEffectiveRoles, n as applyFieldWritePermissions } from "./fields-CQ_7KQWw.mjs";
9
+ import { r as buildCrudPermissionMw, t as tryRegisterRoute } from "./registerRoute-JkxIEBJq.mjs";
10
10
  import { c as getDefaultCrudSchemas } from "./utils-taUVD4p3.mjs";
11
11
  import { n as convertRouteSchema, r as ensureSchemaConverter, t as convertOpenApiSchemas } from "./schemaConverter-DJvodiHj.mjs";
12
12
  import { i as pipeUIMessageStreamToReply, r as isReadableStream } from "./streaming-BQcW6_Kq.mjs";
13
13
  import { t as hasEvents } from "./typeGuards-C9KXUly6.mjs";
14
- import { a as createFastifyHandler, i as createCrudHandlers, n as buildPipelineHandler, o as createRequestContext, r as resolvePipelineSteps, u as buildRequestScopeProjection } from "./pipeline-BGRnV-To.mjs";
15
- import { A as requireAuth } from "./permissions-BrtiBKGs.mjs";
16
- import { r as getAvailablePresets, t as applyPresets } from "./presets-DwFDVKP0.mjs";
14
+ import { a as createFastifyHandler, i as createCrudHandlers, n as buildPipelineHandler, o as createRequestContext, r as resolvePipelineSteps } from "./pipeline-BJnpkY9i.mjs";
15
+ import { I as requireAuth } from "./permissions-Bfu_8y1U.mjs";
16
+ import { r as getAvailablePresets, t as applyPresets } from "./presets-CJOEXLuk.mjs";
17
17
  import { t as pluralize } from "./pluralize-BhrgwZb9.mjs";
18
18
  import { t as resolveActionPermission } from "./actionPermissions-CAphcmUG.mjs";
19
19
  //#region src/core/middlewares/fieldWrite.ts
@@ -462,26 +462,6 @@ function buildBaseController(resolvedConfig, adapter, repository) {
462
462
  //#endregion
463
463
  //#region src/core/defineResource/hooks.ts
464
464
  /**
465
- * Phase 6 — wire preset hooks + inline `config.hooks` onto the
466
- * resource's `_pendingHooks`.
467
- *
468
- * Two sources feed the same array:
469
- * 1. Preset hooks collected during `applyPresets()` (raw `_hooks`
470
- * on the internal config). Already in the canonical
471
- * `{ operation, phase, handler, priority }` shape — copied
472
- * verbatim (priority defaults to 10).
473
- * 2. Inline `config.hooks.beforeCreate` / `afterCreate` / etc.
474
- * Authored by the user on the original `ResourceConfig`.
475
- * Wrapped in a `ResourceHookContext` projection (v2.10.8) so
476
- * authors can read `scope` / `context` without reaching into
477
- * internal request fields.
478
- *
479
- * The 6 inline hook keys (before/after × create/update/delete) used
480
- * to be 6 nearly-identical blocks; collapsed into a table + loop so
481
- * a future hook (e.g. `beforeRead`) is one row, not seven scattered
482
- * edits.
483
- */
484
- /**
485
465
  * Combined entry-point for Phase 6. Pushes preset-collected hooks
486
466
  * first, then inline `config.hooks` (so hosts can rely on
487
467
  * registration order if priorities tie).
@@ -544,19 +524,17 @@ const INLINE_HOOK_SPECS = [
544
524
  }
545
525
  ];
546
526
  /**
547
- * Project a raw HookSystem context into a `ResourceHookContext` for
548
- * inline `config.hooks.*` handlers. The projection lifts `scope`
549
- * out of `context._scope` so authors don't reach into internal
550
- * fields.
527
+ * Project a raw HookSystem context into a `ResourceHookContext` for inline
528
+ * `config.hooks.*` handlers. `scope` rides in already computed — `HookContext`
529
+ * carries the same projection — so the two surfaces cannot drift.
551
530
  */
552
531
  function buildHookContext(ctx) {
553
532
  const context = ctx.context;
554
- const rawScope = context?._scope;
555
533
  return {
556
534
  data: ctx.data ?? ctx.result ?? {},
557
535
  user: ctx.user,
558
536
  context,
559
- scope: buildRequestScopeProjection(rawScope),
537
+ scope: ctx.scope,
560
538
  meta: ctx.meta
561
539
  };
562
540
  }
@@ -802,7 +780,7 @@ function stripFromRequired(schema, fieldName) {
802
780
  }
803
781
  /**
804
782
  * Strip framework-injected fields from the `required[]` list of every
805
- * body-shaped slot in an adapter's generated schemas (v2.11.0).
783
+ * body-shaped slot in an adapter's generated schemas.
806
784
  *
807
785
  * A "framework-injected field" is any field marked `systemManaged: true`
808
786
  * in `schemaOptions.fieldRules`. Arc populates those fields from the
@@ -957,22 +935,32 @@ const WRITE_OPERATIONS = /* @__PURE__ */ new Set([
957
935
  * wiring, ...) count as gates and don't false-positive.
958
936
  *
959
937
  * Severity ladder:
960
- * - `warn` when any enabled WRITE op (create/update/delete) is ungated —
961
- * this is real exposure the host must acknowledge.
938
+ * - `error` when any enabled WRITE op is ungated AND `strict` is on — the
939
+ * resource fails boot (`defineResource()` throws). This is the fail-closed
940
+ * production invariant: an unauthenticated write must never ship silently.
941
+ * - `warn` (default) when any enabled WRITE op (create/update/delete) is
942
+ * ungated — real exposure the host must acknowledge, but non-fatal so
943
+ * existing hosts are not broken.
962
944
  * - `info` when only reads are ungated — public catalogs
963
945
  * (`referenceData: true`) are a legitimate shape, but the host should
964
946
  * still state intent with `permissions.fullPublic()` / `allowPublic()`.
947
+ *
948
+ * `strict` is opt-in (resource `strictPermissions: true` or the
949
+ * `ARC_STRICT_PERMISSIONS` env), so the default behavior is unchanged.
965
950
  */
966
- function collectUngatedCrudDiagnostics(config) {
951
+ function collectUngatedCrudDiagnostics(config, strict = false) {
967
952
  if (config.disableDefaultRoutes) return [];
968
953
  const disabled = new Set(config.disabledRoutes ?? []);
969
954
  const permissions = config.permissions ?? {};
970
955
  const ungated = CRUD_OPERATIONS.filter((op) => !disabled.has(op) && typeof permissions[op] !== "function");
971
956
  if (ungated.length === 0) return [];
957
+ const severity = ungated.some((op) => WRITE_OPERATIONS.has(op)) ? strict ? "error" : "warn" : "info";
972
958
  return [{
973
- severity: ungated.some((op) => WRITE_OPERATIONS.has(op)) ? "warn" : "info",
959
+ severity,
974
960
  code: "crud-public-by-omission",
975
- message: `[Arc] Resource '${config.name}' mounts ${ungated.length} CRUD route(s) with no permission gate: ${ungated.join(", ")}.\nAn omitted permission mounts the route WITHOUT auth. State intent explicitly:\n permissions: permissions.fullPublic() // intentionally public\n permissions: permissions.authenticated() // require auth on every op\n permissions: { ${ungated[0]}: requireAuth(), ... } // per-operation`
961
+ message: `[Arc] Resource '${config.name}' mounts ${ungated.length} CRUD route(s) with no permission gate: ${ungated.join(", ")}.\n` + (severity === "error" ? "strictPermissions is on and an ungated WRITE is fatal. State intent explicitly:\n" : "An omitted permission mounts the route WITHOUT auth. State intent explicitly:\n") + ` permissions: permissions.fullPublic() // intentionally public
962
+ permissions: permissions.authenticated() // require auth on every op
963
+ permissions: { ${ungated[0]}: requireAuth(), ... } // per-operation`
976
964
  }];
977
965
  }
978
966
  //#endregion
@@ -1217,7 +1205,7 @@ function buildResourcePlugin(resource) {
1217
1205
  const isFirstMount = !resource._sharedStateRegisteredOn.has(sharedRoot);
1218
1206
  if (isFirstMount) resource._sharedStateRegisteredOn.add(sharedRoot);
1219
1207
  if (isFirstMount && resource._diagnostics?.length) for (const diagnostic of resource._diagnostics) {
1220
- const level = diagnostic.severity === "info" ? "info" : "warn";
1208
+ const level = diagnostic.severity === "info" ? "info" : diagnostic.severity === "error" ? "error" : "warn";
1221
1209
  fastify.log?.[level]?.(diagnostic.message);
1222
1210
  }
1223
1211
  const arc = fastify.arc;
@@ -1278,7 +1266,7 @@ function buildResourcePlugin(resource) {
1278
1266
  extensions: resource.extensions
1279
1267
  });
1280
1268
  if (resource.actions && Object.keys(resource.actions).length > 0) {
1281
- const { createActionRouter } = await import("./createActionRouter-C-N7z2EL.mjs").then((n) => n.n);
1269
+ const { createActionRouter } = await import("./createActionRouter-BxuywVRB.mjs").then((n) => n.n);
1282
1270
  createActionRouter(typedInstance, {
1283
1271
  ...normalizeActionsToRouterConfig(resource.actions, resource.actionPermissions, resource.tag, resource.permissions, resource.name, typedInstance.log),
1284
1272
  resourceName: resource.name,
@@ -1293,7 +1281,7 @@ function buildResourcePlugin(resource) {
1293
1281
  });
1294
1282
  }
1295
1283
  if (resource.aggregations && Object.keys(resource.aggregations).length > 0) {
1296
- const [{ createAggregationRouter }, { adapterSupportsAggregate, ArcAggregationConfigError }] = await Promise.all([import("./createAggregationRouter-wzwFa_dW.mjs"), import("./validate-Bk44F2yT.mjs").then((n) => n.r)]);
1284
+ const [{ createAggregationRouter }, { adapterSupportsAggregate, ArcAggregationConfigError }] = await Promise.all([import("./createAggregationRouter-BiY-lGdY.mjs"), import("./validate-Bk44F2yT.mjs").then((n) => n.r)]);
1297
1285
  const repoForAgg = resource.controller?.repository ?? resource.repository;
1298
1286
  if (!adapterSupportsAggregate(repoForAgg)) {
1299
1287
  const undispatchable = Object.entries(resource.aggregations).filter(([, cfg]) => !cfg.materialized).map(([name]) => name);
@@ -2169,7 +2157,12 @@ function defineResource(config) {
2169
2157
  const configWithId = resolveIdField(normalisedConfig, repository);
2170
2158
  const resolvedConfig = applyPresetsAndAutoInject(configWithId);
2171
2159
  const hasCrudRoutes = computeHasCrudRoutes(resolvedConfig);
2172
- if (!normalisedConfig.skipValidation) diagnostics = diagnostics.concat(collectUngatedCrudDiagnostics(resolvedConfig));
2160
+ if (!normalisedConfig.skipValidation) {
2161
+ const strict = resolvedConfig.strictPermissions ?? process.env.ARC_STRICT_PERMISSIONS === "true";
2162
+ diagnostics = diagnostics.concat(collectUngatedCrudDiagnostics(resolvedConfig, strict));
2163
+ }
2164
+ const fatal = diagnostics.filter((d) => d.severity === "error");
2165
+ if (fatal.length > 0) throw new Error(fatal.map((d) => d.message).join("\n\n"));
2173
2166
  const narrowedConfig = resolvedConfig;
2174
2167
  const narrowedAdapter = configWithId.adapter;
2175
2168
  const controller = resolveOrAutoCreateController(narrowedConfig, narrowedAdapter, repository, hasCrudRoutes);
@@ -1,4 +1,4 @@
1
- import { p as RegistryEntry } from "../index-DPRH0Cme.mjs";
1
+ import { p as RegistryEntry } from "../index-Q5gzEIWY.mjs";
2
2
  import { t as ExternalOpenApiPaths } from "../externalPaths-BE6wFpYv.mjs";
3
3
  import { FastifyPluginAsync } from "fastify";
4
4
  //#region src/docs/openapi/types.d.ts
@@ -1,5 +1,5 @@
1
1
  import { n as getUserRoles } from "../userHelpers-Cg_y3fBz.mjs";
2
- import { n as openApiPlugin, r as openapi_default, t as buildOpenApiSpec } from "../openapi-BLV4OMXb.mjs";
2
+ import { n as openApiPlugin, r as openapi_default, t as buildOpenApiSpec } from "../openapi-B8Vkbxbn.mjs";
3
3
  import fp from "fastify-plugin";
4
4
  //#region src/docs/scalar.ts
5
5
  const scalarPlugin = async (fastify, opts = {}) => {
@@ -2,109 +2,8 @@ import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.mjs";
2
2
  import { arcLog } from "./logger/index.mjs";
3
3
  import { d as createDomainError } from "./errors-DkO8Nk6-.mjs";
4
4
  import { n as requestContext } from "./requestContext-MrlJwECf.mjs";
5
+ import { n as createEvent, t as MemoryEventTransport } from "./EventTransport-C6YA8xY9.mjs";
5
6
  import fp from "fastify-plugin";
6
- import { createEvent, matchEventPattern } from "@classytic/primitives/events";
7
- //#region src/events/EventTransport.ts
8
- /**
9
- * Internal arc events module — concrete in-memory transport.
10
- *
11
- * **Public type contracts moved out (arc 2.12).** `EventMeta`, `DomainEvent`,
12
- * `EventHandler`, `EventLogger`, `EventTransport`, `DeadLetteredEvent`,
13
- * `PublishManyResult`, plus the `createEvent` / `createChildEvent` /
14
- * `matchEventPattern` helpers, are now owned by `@classytic/primitives/events`.
15
- * Two reasons:
16
- *
17
- * 1. The shapes ARE the cross-package contract. arc, arc-next, mongokit's
18
- * audit-log plugin, future kits and downstream services all share them.
19
- * Owning them in `primitives` (pure types, zero runtime, zero deps)
20
- * eliminates the "manually mirror in two places" problem the previous
21
- * `primitives/src/events.ts` header explicitly called out.
22
- * 2. Inverting the dependency direction lets future packages (sqlitekit
23
- * audit, billing services) consume the contract without depending on
24
- * arc's HTTP-coupled stack.
25
- *
26
- * Hosts MUST import the types from primitives directly:
27
- *
28
- * ```typescript
29
- * import type {
30
- * EventMeta, DomainEvent, EventHandler, EventTransport,
31
- * DeadLetteredEvent, PublishManyResult,
32
- * } from '@classytic/primitives/events';
33
- * import { createEvent, createChildEvent } from '@classytic/primitives/events';
34
- * ```
35
- *
36
- * arc's `events/index.ts` barrel does NOT re-export these — by design, so
37
- * that consumer code is forced into the canonical import path and the org's
38
- * "no re-exports" rule holds at every public surface.
39
- *
40
- * What stays here:
41
- * - `MemoryEventTransport` — the in-memory `EventTransport` implementation
42
- * used as arc's default transport. Its handler-set state is process-local;
43
- * wrong layer for primitives.
44
- * - `MemoryEventTransportOptions` — its options shape.
45
- *
46
- * Inside arc, files that previously imported types from `./EventTransport.js`
47
- * keep working: this file re-exports them from primitives for arc's own
48
- * call sites. That re-export is an internal refactor convenience — the
49
- * public `events/index.ts` barrel stays clean.
50
- */
51
- /**
52
- * In-memory event transport (default).
53
- *
54
- * Events are delivered synchronously within the process. Not suitable for
55
- * multi-instance deployments — pair with `RedisEventTransport` /
56
- * `RedisStreamTransport` (subpath imports) for those.
57
- */
58
- var MemoryEventTransport = class {
59
- name = "memory";
60
- handlers = /* @__PURE__ */ new Map();
61
- logger;
62
- constructor(options) {
63
- this.logger = options?.logger ?? console;
64
- }
65
- async publish(event) {
66
- const allHandlers = /* @__PURE__ */ new Set();
67
- for (const [pattern, handlers] of this.handlers) if (matchEventPattern(pattern, event.type)) for (const h of handlers) allHandlers.add(h);
68
- for (const handler of allHandlers) try {
69
- await handler(event);
70
- } catch (err) {
71
- this.logger.error(`[EventTransport] Handler error for ${event.type}:`, err);
72
- }
73
- }
74
- /**
75
- * Reference `publishMany` implementation — delegates to `publish()` in order.
76
- *
77
- * Production transports (Kafka, Redis pipeline, SQS batch) should override
78
- * this with a single batched network call. Memory transport has nothing to
79
- * batch, so we just loop — the loop still returns a proper result map so
80
- * `EventOutbox.relay` can exercise the batched code path in tests.
81
- */
82
- async publishMany(events) {
83
- const results = /* @__PURE__ */ new Map();
84
- for (const event of events) try {
85
- await this.publish(event);
86
- results.set(event.meta.id, null);
87
- } catch (err) {
88
- results.set(event.meta.id, err instanceof Error ? err : new Error(String(err)));
89
- }
90
- return results;
91
- }
92
- async subscribe(pattern, handler) {
93
- if (!this.handlers.has(pattern)) this.handlers.set(pattern, /* @__PURE__ */ new Set());
94
- this.handlers.get(pattern)?.add(handler);
95
- return () => {
96
- const set = this.handlers.get(pattern);
97
- if (set) {
98
- set.delete(handler);
99
- if (set.size === 0) this.handlers.delete(pattern);
100
- }
101
- };
102
- }
103
- async close() {
104
- this.handlers.clear();
105
- }
106
- };
107
- //#endregion
108
7
  //#region src/events/retry.ts
109
8
  /**
110
9
  * Wrap an event handler with retry logic and dead letter support.
@@ -338,4 +237,4 @@ var eventPlugin_default = fp(eventPlugin, {
338
237
  fastify: "5.x"
339
238
  });
340
239
  //#endregion
341
- export { MemoryEventTransport as a, withRetry as i, eventPlugin_exports as n, createEvent as o, createDeadLetterPublisher as r, eventPlugin as t };
240
+ export { withRetry as i, eventPlugin_exports as n, createDeadLetterPublisher as r, eventPlugin as t };