@classytic/arc 2.17.0 → 2.18.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 (51) hide show
  1. package/dist/{BaseController-Dmeh4Y_y.mjs → BaseController-DPwe89qs.mjs} +2 -2
  2. package/dist/cli/commands/docs.mjs +1 -1
  3. package/dist/cli/commands/init.mjs +1 -1
  4. package/dist/cli/index.mjs +1 -1
  5. package/dist/context/index.d.mts +54 -1
  6. package/dist/context/index.mjs +65 -2
  7. package/dist/core/index.mjs +3 -3
  8. package/dist/{core-DYJvu7aI.mjs → core-B41eZxyM.mjs} +9 -6
  9. package/dist/{createActionRouter-BHUMb1-y.mjs → createActionRouter-CRaIwB5S.mjs} +2 -2
  10. package/dist/{createAggregationRouter-BYVvhfc5.mjs → createAggregationRouter-n3O6WdLO.mjs} +1 -1
  11. package/dist/{createApp-CzCEEsEm.mjs → createApp-D56t2Dsj.mjs} +7 -2
  12. package/dist/docs/index.mjs +1 -1
  13. package/dist/{eventPlugin-CnJCUyM0.mjs → eventPlugin-Dxp9JlKK.mjs} +1 -1
  14. package/dist/events/index.d.mts +48 -0
  15. package/dist/events/index.mjs +27 -5
  16. package/dist/factory/index.mjs +1 -1
  17. package/dist/index.mjs +4 -4
  18. package/dist/{init-DYzfniuX.mjs → init-DQ_rY1J7.mjs} +13 -13
  19. package/dist/integrations/event-gateway.d.mts +1 -1
  20. package/dist/integrations/index.d.mts +2 -2
  21. package/dist/integrations/mcp/index.d.mts +42 -2
  22. package/dist/integrations/mcp/index.mjs +102 -2
  23. package/dist/integrations/mcp/testing.d.mts +1 -1
  24. package/dist/integrations/mcp/testing.mjs +1 -1
  25. package/dist/integrations/websocket-pushref-redis.d.mts +71 -0
  26. package/dist/integrations/websocket-pushref-redis.mjs +205 -0
  27. package/dist/integrations/websocket-redis.d.mts +1 -1
  28. package/dist/integrations/websocket.d.mts +3 -2
  29. package/dist/integrations/websocket.mjs +1142 -23
  30. package/dist/{mcpPlugin-hZE00H74.mjs → mcpPlugin-BrepZ0cV.mjs} +3 -3
  31. package/dist/{openapi-DKDs9NfD.mjs → openapi-CLZx9bwS.mjs} +1 -1
  32. package/dist/plugins/index.d.mts +16 -2
  33. package/dist/plugins/index.mjs +44 -3
  34. package/dist/plugins/tracing-entry.d.mts +1 -1
  35. package/dist/plugins/tracing-entry.mjs +1 -1
  36. package/dist/presets/filesUpload.d.mts +1 -1
  37. package/dist/pushref-registry-Bq_-EVsC.d.mts +435 -0
  38. package/dist/{requestContext-SSaaTgW8.mjs → requestContext-DDLS3NVU.mjs} +26 -1
  39. package/dist/{routerShared-nCyJGOKX.mjs → routerShared-Dl0A77Ba.mjs} +1 -1
  40. package/dist/{schemaIR-DAOvBWgT.mjs → schemaIR-Bk6Tns82.mjs} +17 -5
  41. package/dist/testing/index.mjs +1 -1
  42. package/dist/testing/storageContract.d.mts +1 -1
  43. package/dist/types/storage.d.mts +1 -1
  44. package/dist/utils/index.mjs +1 -1
  45. package/dist/{utils-CvD3glpM.mjs → utils-BMQK8mRl.mjs} +37 -25
  46. package/dist/websocket-BZMUP7Gr.d.mts +456 -0
  47. package/package.json +12 -1
  48. package/dist/websocket-BJ0w-3Dt.d.mts +0 -186
  49. /package/dist/{storage-HcAgP5Ni.d.mts → storage-BFmamN5m.d.mts} +0 -0
  50. /package/dist/{tracing-bRqqUxFO.d.mts → tracing-BYQ3hsbM.d.mts} +0 -0
  51. /package/dist/{types-CoMjNmkF.d.mts → types-D3HV0r5L.d.mts} +0 -0
@@ -2,8 +2,8 @@ import { o as DEFAULT_TENANT_FIELD } from "./constants-TrJVIJl0.mjs";
2
2
  import { arcLog } from "./logger/index.mjs";
3
3
  import { d as createDomainError, f as createError, i as NotFoundError, r as ForbiddenError } from "./errors-j4aJm1Wg.mjs";
4
4
  import { b as isElevated, c as getOrgId } from "./types-Bi0r0vjG.mjs";
5
- import { I as simpleEqualityMatcher, b as ArcQueryParser, o as scheduleBackground, t as getUserId } from "./utils-CvD3glpM.mjs";
6
- import { w as BodySanitizer } from "./routerShared-nCyJGOKX.mjs";
5
+ import { I as simpleEqualityMatcher, b as ArcQueryParser, o as scheduleBackground, t as getUserId } from "./utils-BMQK8mRl.mjs";
6
+ import { w as BodySanitizer } from "./routerShared-Dl0A77Ba.mjs";
7
7
  import { t as buildQueryKey } from "./keys-DopsCuyQ.mjs";
8
8
  //#region src/core/AccessControl.ts
9
9
  const log = arcLog("access-control");
@@ -1,4 +1,4 @@
1
- import { t as buildOpenApiSpec } from "../../openapi-DKDs9NfD.mjs";
1
+ import { t as buildOpenApiSpec } from "../../openapi-CLZx9bwS.mjs";
2
2
  import { t as loadResourcesFromEntry } from "../../loadResourcesFromEntry-DCjYMgfC.mjs";
3
3
  import { dirname, resolve } from "node:path";
4
4
  import { mkdirSync, writeFileSync } from "node:fs";
@@ -1,2 +1,2 @@
1
- import { t as init } from "../../init-DYzfniuX.mjs";
1
+ import { t as init } from "../../init-DQ_rY1J7.mjs";
2
2
  export { init };
@@ -2,6 +2,6 @@ import { describe } from "./commands/describe.mjs";
2
2
  import { exportDocs } from "./commands/docs.mjs";
3
3
  import { doctor } from "./commands/doctor.mjs";
4
4
  import { t as generate } from "../generate-CcM24hoq.mjs";
5
- import { t as init } from "../init-DYzfniuX.mjs";
5
+ import { t as init } from "../init-DQ_rY1J7.mjs";
6
6
  import { introspect } from "./commands/introspect.mjs";
7
7
  export { describe, doctor, exportDocs, generate, init, introspect };
@@ -23,6 +23,18 @@ interface RequestStore {
23
23
  resourceName?: string;
24
24
  /** Request start time (for timing) */
25
25
  startTime: number;
26
+ /**
27
+ * W3C Trace Context traceparent header (RFC 9457 / W3C Recommendation).
28
+ * Format: `00-<trace-id>-<parent-id>-<flags>` (e.g. `00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01`).
29
+ * Populated by `requestIdPlugin` when the header is present and valid.
30
+ */
31
+ traceparent?: string;
32
+ /**
33
+ * W3C Trace Context tracestate header.
34
+ * Vendor-specific, comma-separated `key=value` pairs.
35
+ * Populated by `requestIdPlugin` when the header is present.
36
+ */
37
+ tracestate?: string;
26
38
  /** Additional context — extensible by app */
27
39
  [key: string]: unknown;
28
40
  }
@@ -54,5 +66,46 @@ declare const requestContext: {
54
66
  */
55
67
  storage: AsyncLocalStorage<RequestStore>;
56
68
  };
69
+ /**
70
+ * Returns the W3C Trace Context headers (`traceparent`, `tracestate`) from
71
+ * the current request context as a plain `Record<string, string>`, suitable
72
+ * for passing to `OutboxWriteOptions.headers` or forwarding to downstream
73
+ * HTTP clients.
74
+ *
75
+ * Returns `undefined` when called outside a request scope or when no trace
76
+ * context was propagated by the upstream caller.
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * // Propagate trace context through the outbox so downstream consumers
81
+ * // can stitch together distributed traces.
82
+ * const traceHeaders = getTraceHeaders();
83
+ * await outbox.store(event, { headers: traceHeaders });
84
+ * ```
85
+ */
86
+ declare function getTraceHeaders(): Record<string, string> | undefined;
87
+ //#endregion
88
+ //#region src/context/transactionContext.d.ts
89
+ /** DB session/transaction handle. Typed as unknown — arc is DB-agnostic. */
90
+ type DbSession = unknown;
91
+ /**
92
+ * Transaction context API.
93
+ *
94
+ * - `run(session, fn)` — install an active DB session for the duration of `fn`
95
+ * - `get()` — read the current session (undefined if outside a transaction scope)
96
+ */
97
+ declare const transactionContext: {
98
+ /**
99
+ * Run `fn` with `session` as the active DB transaction context.
100
+ * Any call to `get()` within `fn`'s async call stack returns `session`.
101
+ */
102
+ run<T>(session: DbSession, fn: () => T): T;
103
+ /**
104
+ * Get the current DB session, or `undefined` if not inside a
105
+ * `transactionContext.run(...)` scope.
106
+ */
107
+ get(): DbSession | undefined; /** The underlying AsyncLocalStorage instance. Exposed for advanced integrations. */
108
+ storage: AsyncLocalStorage<unknown>;
109
+ };
57
110
  //#endregion
58
- export { type RequestStore, requestContext };
111
+ export { type DbSession, type RequestStore, getTraceHeaders, requestContext, transactionContext };
@@ -1,2 +1,65 @@
1
- import { t as requestContext } from "../requestContext-SSaaTgW8.mjs";
2
- export { requestContext };
1
+ import { n as requestContext, t as getTraceHeaders } from "../requestContext-DDLS3NVU.mjs";
2
+ import { AsyncLocalStorage } from "node:async_hooks";
3
+ //#region src/context/transactionContext.ts
4
+ /**
5
+ * Transaction Context via AsyncLocalStorage
6
+ *
7
+ * Provides a Unit-of-Work (UoW) hook so any code in the call stack can
8
+ * retrieve the active database session/transaction without it being threaded
9
+ * through every function parameter.
10
+ *
11
+ * Arc is DB-agnostic — the session type is `unknown` so any backend
12
+ * (Mongoose session, Prisma transaction, pg client, Drizzle client) can
13
+ * participate. Kit adapters call `runInTransaction(session, fn)` to install
14
+ * the active context; the outbox's `store()` reads it automatically when no
15
+ * explicit `options.session` is passed.
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * // In a Mongoose-backed service (mongokit adapter)
20
+ * import { transactionContext } from '@classytic/arc/context';
21
+ *
22
+ * await mongoose.connection.withSession(async (session) => {
23
+ * await session.withTransaction(async () => {
24
+ * await transactionContext.run(session, async () => {
25
+ * await orders.insertOne(order, { session });
26
+ * // outbox.store() auto-picks up `session` — no manual threading
27
+ * await outbox.store(orderCreatedEvent);
28
+ * });
29
+ * });
30
+ * });
31
+ * ```
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * // Opt-out: explicit session always wins over the ALS context
36
+ * await outbox.store(event, { session: explicitSession });
37
+ * ```
38
+ */
39
+ const storage = new AsyncLocalStorage();
40
+ /**
41
+ * Transaction context API.
42
+ *
43
+ * - `run(session, fn)` — install an active DB session for the duration of `fn`
44
+ * - `get()` — read the current session (undefined if outside a transaction scope)
45
+ */
46
+ const transactionContext = {
47
+ /**
48
+ * Run `fn` with `session` as the active DB transaction context.
49
+ * Any call to `get()` within `fn`'s async call stack returns `session`.
50
+ */
51
+ run(session, fn) {
52
+ return storage.run(session, fn);
53
+ },
54
+ /**
55
+ * Get the current DB session, or `undefined` if not inside a
56
+ * `transactionContext.run(...)` scope.
57
+ */
58
+ get() {
59
+ return storage.getStore();
60
+ },
61
+ /** The underlying AsyncLocalStorage instance. Exposed for advanced integrations. */
62
+ storage
63
+ };
64
+ //#endregion
65
+ export { getTraceHeaders, requestContext, transactionContext };
@@ -1,5 +1,5 @@
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-TrJVIJl0.mjs";
2
- import { a as BulkMixin, c as collectReadBlockedFields, i as SlugMixin, l as isFieldReadable, n as TreeMixin, o as BaseCrudController, r as SoftDeleteMixin, s as QueryResolver, t as BaseController, u as AccessControl } from "../BaseController-Dmeh4Y_y.mjs";
3
- import { S as sendControllerResponse, _ as createCrudHandlers, b as getControllerContext, v as createFastifyHandler, w as BodySanitizer, x as getControllerScope, y as createRequestContext } from "../routerShared-nCyJGOKX.mjs";
4
- import { a as defineResource, c as createCrudRouter, i as defineResourceVariants, l as createPermissionMiddleware, n as getEntityIdField, o as ResourceDefinition, r as getEntityQuery, s as defineAction, t as getEntityId, u as defineAggregation } from "../core-DYJvu7aI.mjs";
2
+ import { a as BulkMixin, c as collectReadBlockedFields, i as SlugMixin, l as isFieldReadable, n as TreeMixin, o as BaseCrudController, r as SoftDeleteMixin, s as QueryResolver, t as BaseController, u as AccessControl } from "../BaseController-DPwe89qs.mjs";
3
+ import { S as sendControllerResponse, _ as createCrudHandlers, b as getControllerContext, v as createFastifyHandler, w as BodySanitizer, x as getControllerScope, y as createRequestContext } from "../routerShared-Dl0A77Ba.mjs";
4
+ import { a as defineResource, c as createCrudRouter, i as defineResourceVariants, l as createPermissionMiddleware, n as getEntityIdField, o as ResourceDefinition, r as getEntityQuery, s as defineAction, t as getEntityId, u as defineAggregation } from "../core-B41eZxyM.mjs";
5
5
  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, collectReadBlockedFields, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineAction, defineAggregation, defineResource, defineResourceVariants, getControllerContext, getControllerScope, getEntityId, getEntityIdField, getEntityQuery, isFieldReadable, sendControllerResponse };
@@ -1,11 +1,11 @@
1
1
  import { s as DEFAULT_UPDATE_METHOD, t as CRUD_OPERATIONS } from "./constants-TrJVIJl0.mjs";
2
2
  import { arcLog } from "./logger/index.mjs";
3
- import { N as assertValidConfig, f as getDefaultCrudSchemas, i as pipeUIMessageStreamToReply, r as isReadableStream } from "./utils-CvD3glpM.mjs";
4
- import { t as BaseController } from "./BaseController-Dmeh4Y_y.mjs";
3
+ import { N as assertValidConfig, f as getDefaultCrudSchemas, i as pipeUIMessageStreamToReply, r as isReadableStream } from "./utils-BMQK8mRl.mjs";
4
+ import { t as BaseController } from "./BaseController-DPwe89qs.mjs";
5
5
  import { t as applyPresets } from "./presets-BYbPobbF.mjs";
6
6
  import { n as convertRouteSchema, t as convertOpenApiSchemas } from "./schemaConverter-De34B1ZG.mjs";
7
7
  import { t as hasEvents } from "./typeGuards-BzkXkvVv.mjs";
8
- import { C as buildRequestScopeProjection, _ as createCrudHandlers, c as buildPipelineHandler, d as methodCarriesBody, f as resolvePipelineSteps, g as tryRegisterRoute, h as selectPluginMw, i as buildAuthMiddleware, l as buildPreHandlerChain, m as resolveRouterPluginMw, o as buildCrudPermissionMw, p as resolveRoutePreHandlers, r as buildArcDecorator, s as buildFieldWritePreHandler, u as buildRateLimitConfig, v as createFastifyHandler, y as createRequestContext } from "./routerShared-nCyJGOKX.mjs";
8
+ import { C as buildRequestScopeProjection, _ as createCrudHandlers, c as buildPipelineHandler, d as methodCarriesBody, f as resolvePipelineSteps, g as tryRegisterRoute, h as selectPluginMw, i as buildAuthMiddleware, l as buildPreHandlerChain, m as resolveRouterPluginMw, o as buildCrudPermissionMw, p as resolveRoutePreHandlers, r as buildArcDecorator, s as buildFieldWritePreHandler, u as buildRateLimitConfig, v as createFastifyHandler, y as createRequestContext } from "./routerShared-Dl0A77Ba.mjs";
9
9
  import { t as pluralize } from "./pluralize-B9M8xvy-.mjs";
10
10
  import { t as resolveActionPermission } from "./actionPermissions-Bjmvn7Eb.mjs";
11
11
  //#region src/core/aggregation/defineAggregation.ts
@@ -127,7 +127,10 @@ function createCustomRoutes(fastify, routes, controller, options) {
127
127
  reply.raw.setHeader("Cache-Control", "no-cache");
128
128
  reply.raw.setHeader("Connection", "keep-alive");
129
129
  const result = await handler(request, reply);
130
- if (isReadableStream(result)) await pipeUIMessageStreamToReply(reply, result);
130
+ if (isReadableStream(result)) {
131
+ await pipeUIMessageStreamToReply(reply, result);
132
+ return reply;
133
+ }
131
134
  return result;
132
135
  } : handler,
133
136
  ...rateLimitConfig ? { config: rateLimitConfig } : {}
@@ -1093,7 +1096,7 @@ function buildResourcePlugin(resource) {
1093
1096
  idField: resource.idField
1094
1097
  });
1095
1098
  if (resource.actions && Object.keys(resource.actions).length > 0) {
1096
- const { createActionRouter } = await import("./createActionRouter-BHUMb1-y.mjs").then((n) => n.n);
1099
+ const { createActionRouter } = await import("./createActionRouter-CRaIwB5S.mjs").then((n) => n.n);
1097
1100
  createActionRouter(typedInstance, {
1098
1101
  ...normalizeActionsToRouterConfig(resource.actions, resource.actionPermissions, resource.tag, resource.permissions, resource.name, typedInstance.log),
1099
1102
  resourceName: resource.name,
@@ -1107,7 +1110,7 @@ function buildResourcePlugin(resource) {
1107
1110
  });
1108
1111
  }
1109
1112
  if (resource.aggregations && Object.keys(resource.aggregations).length > 0) {
1110
- const [{ createAggregationRouter }, { adapterSupportsAggregate, ArcAggregationConfigError }] = await Promise.all([import("./createAggregationRouter-BYVvhfc5.mjs"), import("./validate-DFIP2VrM.mjs").then((n) => n.i)]);
1113
+ const [{ createAggregationRouter }, { adapterSupportsAggregate, ArcAggregationConfigError }] = await Promise.all([import("./createAggregationRouter-n3O6WdLO.mjs"), import("./validate-DFIP2VrM.mjs").then((n) => n.i)]);
1111
1114
  const repoForAgg = resource.controller?.repository ?? resource.repository;
1112
1115
  if (!adapterSupportsAggregate(repoForAgg)) {
1113
1116
  const undispatchable = Object.entries(resource.aggregations).filter(([, cfg]) => !cfg.materialized).map(([name]) => name);
@@ -1,8 +1,8 @@
1
1
  import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
2
2
  import "./constants-TrJVIJl0.mjs";
3
3
  import { f as createError } from "./errors-j4aJm1Wg.mjs";
4
- import { S as sendControllerResponse, a as buildAuthMiddlewareForPermissions, f as resolvePipelineSteps, g as tryRegisterRoute, h as selectPluginMw, l as buildPreHandlerChain, m as resolveRouterPluginMw, n as buildActionPipelineHandler, r as buildArcDecorator, t as buildActionPermissionMw, u as buildRateLimitConfig } from "./routerShared-nCyJGOKX.mjs";
5
- import { n as schemaIRToJsonSchemaBranch, t as normalizeSchemaIR } from "./schemaIR-DAOvBWgT.mjs";
4
+ import { S as sendControllerResponse, a as buildAuthMiddlewareForPermissions, f as resolvePipelineSteps, g as tryRegisterRoute, h as selectPluginMw, l as buildPreHandlerChain, m as resolveRouterPluginMw, n as buildActionPipelineHandler, r as buildArcDecorator, t as buildActionPermissionMw, u as buildRateLimitConfig } from "./routerShared-Dl0A77Ba.mjs";
5
+ import { n as schemaIRToJsonSchemaBranch, t as normalizeSchemaIR } from "./schemaIR-Bk6Tns82.mjs";
6
6
  //#region src/core/createActionRouter.ts
7
7
  var createActionRouter_exports = /* @__PURE__ */ __exportAll({
8
8
  buildActionBodySchema: () => buildActionBodySchema,
@@ -1,5 +1,5 @@
1
1
  import { f as createError, l as UnauthorizedError, r as ForbiddenError } from "./errors-j4aJm1Wg.mjs";
2
- import { h as selectPluginMw, i as buildAuthMiddleware, l as buildPreHandlerChain, m as resolveRouterPluginMw, r as buildArcDecorator, u as buildRateLimitConfig } from "./routerShared-nCyJGOKX.mjs";
2
+ import { h as selectPluginMw, i as buildAuthMiddleware, l as buildPreHandlerChain, m as resolveRouterPluginMw, r as buildArcDecorator, u as buildRateLimitConfig } from "./routerShared-Dl0A77Ba.mjs";
3
3
  import { r as validateAggregations } from "./validate-DFIP2VrM.mjs";
4
4
  import { t as buildAggregationHandler } from "./buildHandler-C_SkBNF3.mjs";
5
5
  //#region src/core/aggregation/createAggregationRouter.ts
@@ -202,7 +202,7 @@ async function registerArcCore(fastify, config, trackPlugin) {
202
202
  await fastify.register(arcCorePlugin, { emitEvents: config.arcPlugins?.emitEvents !== false });
203
203
  trackPlugin("arc-core");
204
204
  if (config.arcPlugins?.events !== false) {
205
- const { default: eventPlugin } = await import("./eventPlugin-CnJCUyM0.mjs").then((n) => n.n);
205
+ const { default: eventPlugin } = await import("./eventPlugin-Dxp9JlKK.mjs").then((n) => n.n);
206
206
  const eventOpts = typeof config.arcPlugins?.events === "object" ? config.arcPlugins.events : {};
207
207
  await fastify.register(eventPlugin, {
208
208
  ...eventOpts,
@@ -828,7 +828,12 @@ async function createApp(options) {
828
828
  ...config.bodyLimit !== void 0 ? { bodyLimit: config.bodyLimit } : {},
829
829
  allowErrorHandlerOverride: true,
830
830
  routerOptions: {
831
- querystringParser: (str) => qs.parse(str),
831
+ querystringParser: (str) => qs.parse(str, {
832
+ depth: 5,
833
+ parameterLimit: 100,
834
+ arrayLimit: 20,
835
+ allowPrototypes: false
836
+ }),
832
837
  maxParamLength: config.maxParamLength ?? 400
833
838
  },
834
839
  ajv: { customOptions: {
@@ -1,5 +1,5 @@
1
1
  import { t as getUserRoles } from "../types-DV9WDfeg.mjs";
2
- import { n as openApiPlugin, r as openapi_default, t as buildOpenApiSpec } from "../openapi-DKDs9NfD.mjs";
2
+ import { n as openApiPlugin, r as openapi_default, t as buildOpenApiSpec } from "../openapi-CLZx9bwS.mjs";
3
3
  import fp from "fastify-plugin";
4
4
  //#region src/docs/scalar.ts
5
5
  const scalarPlugin = async (fastify, opts = {}) => {
@@ -1,7 +1,7 @@
1
1
  import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
2
2
  import { arcLog } from "./logger/index.mjs";
3
3
  import { d as createDomainError } from "./errors-j4aJm1Wg.mjs";
4
- import { t as requestContext } from "./requestContext-SSaaTgW8.mjs";
4
+ import { n as requestContext } from "./requestContext-DDLS3NVU.mjs";
5
5
  import { n as createEvent, t as MemoryEventTransport } from "./EventTransport-ClEDfiMS.mjs";
6
6
  import fp from "fastify-plugin";
7
7
  //#region src/events/retry.ts
@@ -450,6 +450,52 @@ interface EventOutboxOptions {
450
450
  * on next poll) — legacy behaviour, unchanged.
451
451
  */
452
452
  readonly failurePolicy?: OutboxFailurePolicy;
453
+ /**
454
+ * Unit-of-Work session provider (AsyncLocalStorage integration).
455
+ *
456
+ * When set, `store()` calls this to get the active DB session and uses
457
+ * it as `OutboxWriteOptions.session` — **only when the caller has not
458
+ * already passed an explicit `options.session`**. This eliminates the
459
+ * boilerplate of threading the transaction handle from the controller
460
+ * through every service layer down to the outbox call site.
461
+ *
462
+ * Wire up with arc's `transactionContext`:
463
+ * ```typescript
464
+ * import { transactionContext } from '@classytic/arc/context';
465
+ *
466
+ * const outbox = new EventOutbox({
467
+ * store: myOutboxStore,
468
+ * sessionProvider: () => transactionContext.get(),
469
+ * });
470
+ *
471
+ * // In your service layer — session is auto-picked up:
472
+ * await transactionContext.run(mongooseSession, async () => {
473
+ * await orders.insertOne(order, { session: mongooseSession });
474
+ * await outbox.store(orderCreatedEvent); // no session arg needed
475
+ * });
476
+ * ```
477
+ */
478
+ readonly sessionProvider?: () => unknown;
479
+ /**
480
+ * W3C Trace Context provider.
481
+ *
482
+ * When set, `store()` calls this and merges the returned headers into
483
+ * `OutboxWriteOptions.headers` — only when `traceparent` is not already
484
+ * present in the caller-supplied headers. Downstream relay workers can
485
+ * then forward the headers to the transport, preserving the distributed
486
+ * trace tree across service boundaries.
487
+ *
488
+ * Wire up with arc's `getTraceHeaders`:
489
+ * ```typescript
490
+ * import { getTraceHeaders } from '@classytic/arc/context';
491
+ *
492
+ * const outbox = new EventOutbox({
493
+ * store: myOutboxStore,
494
+ * traceContextProvider: getTraceHeaders,
495
+ * });
496
+ * ```
497
+ */
498
+ readonly traceContextProvider?: () => Record<string, string> | undefined;
453
499
  }
454
500
  declare class EventOutbox {
455
501
  private readonly _store;
@@ -459,6 +505,8 @@ declare class EventOutbox {
459
505
  private readonly _leaseMs;
460
506
  private readonly _onError?;
461
507
  private readonly _usePublishMany;
508
+ private readonly _sessionProvider?;
509
+ private readonly _traceContextProvider?;
462
510
  private readonly _failurePolicy?;
463
511
  /**
464
512
  * In-process attempt counter per event id. Accurate within this relay
@@ -1,6 +1,6 @@
1
1
  import { t as MemoryEventTransport } from "../EventTransport-ClEDfiMS.mjs";
2
2
  import { n as defineEvent, t as createEventRegistry } from "../defineEvent-NPKUJRt8.mjs";
3
- import { i as withRetry, r as createDeadLetterPublisher, t as eventPlugin } from "../eventPlugin-CnJCUyM0.mjs";
3
+ import { i as withRetry, r as createDeadLetterPublisher, t as eventPlugin } from "../eventPlugin-Dxp9JlKK.mjs";
4
4
  import { n as createSafeGetOne, t as createIsDuplicateKeyError } from "../store-helpers-5JgaxieH.mjs";
5
5
  import { and, anyOf, eq, lte, ne, or } from "@classytic/repo-core/filter";
6
6
  import { update } from "@classytic/repo-core/update";
@@ -387,6 +387,8 @@ var EventOutbox = class {
387
387
  _leaseMs;
388
388
  _onError;
389
389
  _usePublishMany;
390
+ _sessionProvider;
391
+ _traceContextProvider;
390
392
  _failurePolicy;
391
393
  /**
392
394
  * In-process attempt counter per event id. Accurate within this relay
@@ -406,6 +408,8 @@ var EventOutbox = class {
406
408
  this._onError = opts.onError;
407
409
  this._usePublishMany = opts.usePublishMany ?? true;
408
410
  this._failurePolicy = opts.failurePolicy;
411
+ this._sessionProvider = opts.sessionProvider;
412
+ this._traceContextProvider = opts.traceContextProvider;
409
413
  }
410
414
  /** Unique consumer ID used for lease ownership when the store supports claims */
411
415
  get consumerId() {
@@ -427,11 +431,29 @@ var EventOutbox = class {
427
431
  if (!event || typeof event !== "object") throw new InvalidOutboxEventError("event is not an object");
428
432
  if (!event.type || typeof event.type !== "string") throw new InvalidOutboxEventError("event.type is required");
429
433
  if (!event.meta?.id || typeof event.meta.id !== "string") throw new InvalidOutboxEventError("event.meta.id is required");
430
- const effectiveOptions = options?.dedupeKey === void 0 && event.meta.idempotencyKey ? {
431
- ...options ?? {},
434
+ let effective = options;
435
+ if (effective?.session === void 0 && this._sessionProvider) {
436
+ const autoSession = this._sessionProvider();
437
+ if (autoSession !== void 0) effective = {
438
+ ...effective ?? {},
439
+ session: autoSession
440
+ };
441
+ }
442
+ if (!effective?.headers?.["traceparent"] && this._traceContextProvider) {
443
+ const traceHeaders = this._traceContextProvider();
444
+ if (traceHeaders && Object.keys(traceHeaders).length > 0) effective = {
445
+ ...effective ?? {},
446
+ headers: {
447
+ ...traceHeaders,
448
+ ...effective?.headers ?? {}
449
+ }
450
+ };
451
+ }
452
+ if (effective?.dedupeKey === void 0 && event.meta.idempotencyKey) effective = {
453
+ ...effective ?? {},
432
454
  dedupeKey: event.meta.idempotencyKey
433
- } : options;
434
- await this._store.save(event, effectiveOptions);
455
+ };
456
+ await this._store.save(event, effective);
435
457
  }
436
458
  _reportError(kind, error, event) {
437
459
  if (!this._onError) return;
@@ -1,5 +1,5 @@
1
1
  import { n as preloadResourcesAsync, t as preloadResources } from "../preloadResources-BOXzPhKU.mjs";
2
- import { a as edgePreset, c as testingPreset, i as developmentPreset, n as createApp, o as getPreset, s as productionPreset, t as ArcFactory } from "../createApp-CzCEEsEm.mjs";
2
+ import { a as edgePreset, c as testingPreset, i as developmentPreset, n as createApp, o as getPreset, s as productionPreset, t as ArcFactory } from "../createApp-D56t2Dsj.mjs";
3
3
  import { t as loadResources } from "../loadResources-fol6JuvW.mjs";
4
4
  //#region src/factory/edge.ts
5
5
  /**
package/dist/index.mjs CHANGED
@@ -1,10 +1,10 @@
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-TrJVIJl0.mjs";
2
2
  import { d as createDomainError, i as NotFoundError, l as UnauthorizedError, r as ForbiddenError, t as ArcError, u as ValidationError } from "./errors-j4aJm1Wg.mjs";
3
- import { a as BulkMixin, i as SlugMixin, n as TreeMixin, o as BaseCrudController, r as SoftDeleteMixin, t as BaseController } from "./BaseController-Dmeh4Y_y.mjs";
3
+ import { a as BulkMixin, i as SlugMixin, n as TreeMixin, o as BaseCrudController, r as SoftDeleteMixin, t as BaseController } from "./BaseController-DPwe89qs.mjs";
4
4
  import { C as requireAuth, D as when, M as applyFieldWritePermissions, N as fields, T as requireRoles, _ as requireTeamMembership, a as presets_exports, b as anyOf, c as readOnly, d as createOrgPermissions, f as requireOrgInScope, g as requireServiceScope, h as requireScopeContext, i as ownerWithAdminBypass, j as applyFieldReadPermissions, m as requireOrgRole, n as authenticated, o as publicRead, p as requireOrgMembership, r as fullPublic, s as publicReadAdminWrite, t as adminOnly, u as createDynamicPermissionMatrix, v as allOf, w as requireOwnership, x as denyAll, y as allowPublic } from "./permissions-B1Qy55fg.mjs";
5
- import { x as getControllerScope } from "./routerShared-nCyJGOKX.mjs";
6
- import { a as defineResource, i as defineResourceVariants, o as ResourceDefinition, s as defineAction, u as defineAggregation } from "./core-DYJvu7aI.mjs";
5
+ import { x as getControllerScope } from "./routerShared-Dl0A77Ba.mjs";
6
+ import { a as defineResource, i as defineResourceVariants, o as ResourceDefinition, s as defineAction, u as defineAggregation } from "./core-B41eZxyM.mjs";
7
7
  //#region src/index.ts
8
- const version = "2.17.0";
8
+ const version = "2.18.0";
9
9
  //#endregion
10
10
  export { ArcError, BaseController, BaseCrudController, BulkMixin, 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, NotFoundError, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, SlugMixin, SoftDeleteMixin, TreeMixin, UnauthorizedError, ValidationError, adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, authenticated, createDomainError, createDynamicPermissionMatrix, createOrgPermissions, defineAction, defineAggregation, defineResource, defineResourceVariants, denyAll, fields, fullPublic, getControllerScope, ownerWithAdminBypass, presets_exports as permissions, publicRead, publicReadAdminWrite, readOnly, requireAuth, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, version, when };
@@ -917,9 +917,9 @@ ${config.adapter === "mongokit" ? ` await mongoose.connection.collection('use
917
917
  //#region src/cli/commands/init/dependency-plan.ts
918
918
  const SCAFFOLD_DEP_VERSIONS = {
919
919
  core: {
920
- "@classytic/arc": "^2.13.0",
920
+ "@classytic/arc": "^2.17.2",
921
921
  "@classytic/primitives": "^0.6.0",
922
- "@classytic/repo-core": "^0.4.2",
922
+ "@classytic/repo-core": "^0.5.0",
923
923
  "@fastify/cors": "^11.2.0",
924
924
  "@fastify/helmet": "^13.0.2",
925
925
  "@fastify/rate-limit": "^10.3.0",
@@ -929,27 +929,27 @@ const SCAFFOLD_DEP_VERSIONS = {
929
929
  fastify: "^5.8.5"
930
930
  },
931
931
  authJwt: {
932
- "@fastify/jwt": "^10.0.0",
933
- bcryptjs: "^3.0.0"
932
+ "@fastify/jwt": "^10.1.0",
933
+ bcryptjs: "^3.0.3"
934
934
  },
935
935
  authBetterAuth: {
936
- "better-auth": "^1.6.9",
937
- mongodb: "^7.1.0"
936
+ "better-auth": "^1.6.11",
937
+ mongodb: "^7.2.0"
938
938
  },
939
- authBetterAuthApiKey: { "@better-auth/api-key": "^1.6.9" },
939
+ authBetterAuthApiKey: { "@better-auth/api-key": "^1.6.11" },
940
940
  adapterMongokit: {
941
- "@classytic/mongokit": "^3.13.0",
942
- mongoose: "^9.6.1"
941
+ "@classytic/mongokit": "^3.14.0",
942
+ mongoose: "^9.6.2"
943
943
  },
944
944
  devCommon: {
945
945
  "mongodb-memory-server": "^11.1.0",
946
- "pino-pretty": "^13.0.0",
947
- vitest: "^4.1.5"
946
+ "pino-pretty": "^13.1.3",
947
+ vitest: "^4.1.7"
948
948
  },
949
949
  devTypescript: {
950
950
  "@types/node": "^22.10.0",
951
- tsx: "^4.21.0",
952
- typescript: "^5.7.2"
951
+ tsx: "^4.22.3",
952
+ typescript: "^6.0.3"
953
953
  },
954
954
  typesJwt: { "@types/bcryptjs": "^3.0.0" }
955
955
  };
@@ -1,5 +1,5 @@
1
1
  import { n as DomainEvent } from "../EventTransport-B1GFiYUy.mjs";
2
- import { a as WebSocketMessage, i as WebSocketClient } from "../websocket-BJ0w-3Dt.mjs";
2
+ import { c as WebSocketClient, l as WebSocketMessage } from "../websocket-BZMUP7Gr.mjs";
3
3
  import { FastifyPluginAsync, FastifyRequest } from "fastify";
4
4
 
5
5
  //#region src/integrations/event-gateway.d.ts
@@ -1,7 +1,7 @@
1
- import { a as WebSocketMessage, i as WebSocketClient, o as WebSocketPluginOptions } from "../websocket-BJ0w-3Dt.mjs";
1
+ import { c as WebSocketClient, l as WebSocketMessage, u as WebSocketPluginOptions } from "../websocket-BZMUP7Gr.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 McpAuthResult, d as PromptDefinition, g as ToolDefinition, h as ToolContext, l as McpPluginOptions, m as ToolAnnotations, n as CallToolResult, o as CrudOperation, r as CreateMcpServerConfig, t as BetterAuthHandler, u as McpResourceConfig } from "../types-CoMjNmkF.mjs";
4
+ import { c as McpAuthResult, d as PromptDefinition, g as ToolDefinition, h as ToolContext, l as McpPluginOptions, m as ToolAnnotations, n as CallToolResult, o as CrudOperation, r as CreateMcpServerConfig, t as BetterAuthHandler, u as McpResourceConfig } from "../types-D3HV0r5L.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,7 +1,7 @@
1
1
  import { V as ResourceDefinition, bt as IRequestContext, yt as IControllerResponse } from "../../index-C1JSBan-.mjs";
2
2
  import { i as RequestScope } from "../../types-CfapW2t8.mjs";
3
3
  import { c as PermissionCheck } from "../../fields-DqZLp5d6.mjs";
4
- import { a as CrudDescriptionOverride, c as McpAuthResult, d as PromptDefinition, f as PromptResult, g as ToolDefinition, h as ToolContext, i as CrudDescriptionMeta, l as McpPluginOptions, m as ToolAnnotations, n as CallToolResult, o as CrudOperation, p as SessionEntry, r as CreateMcpServerConfig, s as McpAuthResolver, t as BetterAuthHandler, u as McpResourceConfig } from "../../types-CoMjNmkF.mjs";
4
+ import { a as CrudDescriptionOverride, c as McpAuthResult, d as PromptDefinition, f as PromptResult, g as ToolDefinition, h as ToolContext, i as CrudDescriptionMeta, l as McpPluginOptions, m as ToolAnnotations, n as CallToolResult, o as CrudOperation, p as SessionEntry, r as CreateMcpServerConfig, s as McpAuthResolver, t as BetterAuthHandler, u as McpResourceConfig } from "../../types-D3HV0r5L.mjs";
5
5
  import { ErrorContract } from "@classytic/repo-core/errors";
6
6
  import { FastifyPluginAsync } from "fastify";
7
7
  import { z } from "zod";
@@ -505,6 +505,46 @@ declare function filterResourcesForMcp<T extends {
505
505
  }>(resources: readonly T[], inputs: ResourceFilterInputs): T[];
506
506
  declare const mcpPlugin: FastifyPluginAsync<McpPluginOptions>;
507
507
  //#endregion
508
+ //#region src/integrations/mcp/realtimeBridge.d.ts
509
+ /**
510
+ * Inbound tool-call shape — accepts both LiveKit Agents (`arguments`)
511
+ * and OpenAI Realtime (`arguments_json` string) variants. Other realtime
512
+ * vendors stay flexible because we only look at the canonical fields.
513
+ */
514
+ interface RealtimeToolCall {
515
+ id: string;
516
+ name: string;
517
+ /** Parsed object form. Preferred over `arguments_json`. */
518
+ arguments?: Record<string, unknown>;
519
+ /** JSON-string form (OpenAI Realtime tools). Parsed if `arguments` is absent. */
520
+ arguments_json?: string;
521
+ }
522
+ /** Outbound shape — mirrors js-genai's sendToolResponse. */
523
+ interface RealtimeToolResponse {
524
+ id: string;
525
+ name: string;
526
+ /** Tool result — `content` from the MCP CallToolResult, normalized to plain JSON. */
527
+ response: Record<string, unknown>;
528
+ /** Surfaces tool-side errors so the model can recover. */
529
+ isError?: boolean;
530
+ }
531
+ interface DispatchOptions<TSession = unknown> {
532
+ session?: TSession | null;
533
+ log?: ToolContext<TSession>["log"];
534
+ /** Forwarded into `ctx.extra` for advanced handlers. */
535
+ extra?: Record<string, unknown>;
536
+ }
537
+ /**
538
+ * Dispatch a batch of tool calls through the host's MCP tool registry.
539
+ *
540
+ * Returns the response array in the same order as the input. Each
541
+ * response carries either the tool's `content` (success path) or a
542
+ * `{isError:true, error:{message,...}}` shape (validation failure or
543
+ * handler throw). The realtime client uses the `id` to correlate
544
+ * responses to the original calls.
545
+ */
546
+ declare function dispatchRealtimeToolCall<TSession = unknown>(tools: readonly ToolDefinition[], calls: readonly RealtimeToolCall[], opts?: DispatchOptions<TSession>): Promise<RealtimeToolResponse[]>;
547
+ //#endregion
508
548
  //#region src/integrations/mcp/resourceToTools.d.ts
509
549
  interface ResourceToToolsConfig extends McpResourceConfig {
510
550
  toolNamePrefix?: string;
@@ -578,4 +618,4 @@ declare function permissionDeniedResult(args: {
578
618
  session: McpAuthResult | null;
579
619
  }): CallToolResult;
580
620
  //#endregion
581
- export { type AuthRef, type BetterAuthHandler, type BuildMcpToolsFromBridgesOptions, type CallToolResult, type CreateMcpAuthFromBetterAuthApiKeyOptions, type CreateMcpServerConfig, type CrudDescriptionMeta, type CrudDescriptionOverride, type CrudOperation, type DefinePromptConfig, type DefineToolConfig, type FieldRuleEntry, type FieldRulesToZodOptions, type InvokeControllerOptions, type McpAuthResolver, type McpAuthResult, type McpBridge, type McpGuard, type McpOperation, type McpPluginOptions, type McpResourceConfig, type McpServerInstance, type PromptDefinition, type PromptResult, type ResourceToToolsConfig, type ToolAnnotations, type ToolContext, type ToolDefinition, bridgeToMcp, buildMcpToolsFromBridges, buildRequestContext, createMcpAuthFromBetterAuthApiKey, createMcpServer, customGuard, defaultCrudDescription, definePrompt, defineTool, denied, fieldRulesToZod, filterResourcesForMcp, getOrgId, getUserId, guard, hasOrg, invokeController, isAuthenticated, isOrg, mcpHandlerAdapter, mcpPlugin, permissionDeniedResult, requireAuth, requireOrg, requireOrgId, requireRole, resolveCrudDescription, resolveToolCollisions, resourceToTools, toCallToolError, toCallToolResult, toCallToolSuccess };
621
+ export { type AuthRef, type BetterAuthHandler, type BuildMcpToolsFromBridgesOptions, type CallToolResult, type CreateMcpAuthFromBetterAuthApiKeyOptions, type CreateMcpServerConfig, type CrudDescriptionMeta, type CrudDescriptionOverride, type CrudOperation, type DefinePromptConfig, type DefineToolConfig, type DispatchOptions, type FieldRuleEntry, type FieldRulesToZodOptions, type InvokeControllerOptions, type McpAuthResolver, type McpAuthResult, type McpBridge, type McpGuard, type McpOperation, type McpPluginOptions, type McpResourceConfig, type McpServerInstance, type PromptDefinition, type PromptResult, type RealtimeToolCall, type RealtimeToolResponse, type ResourceToToolsConfig, type ToolAnnotations, type ToolContext, type ToolDefinition, bridgeToMcp, buildMcpToolsFromBridges, buildRequestContext, createMcpAuthFromBetterAuthApiKey, createMcpServer, customGuard, defaultCrudDescription, definePrompt, defineTool, denied, dispatchRealtimeToolCall, fieldRulesToZod, filterResourcesForMcp, getOrgId, getUserId, guard, hasOrg, invokeController, isAuthenticated, isOrg, mcpHandlerAdapter, mcpPlugin, permissionDeniedResult, requireAuth, requireOrg, requireOrgId, requireRole, resolveCrudDescription, resolveToolCollisions, resourceToTools, toCallToolError, toCallToolResult, toCallToolSuccess };