@classytic/arc 2.20.0 → 2.22.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 (143) hide show
  1. package/dist/{BaseController-D-MHZ27_.mjs → BaseController-C6FlRWxF.mjs} +2 -2
  2. package/dist/{EventTransport-IEn7Tn-Q.d.mts → EventTransport-QmY7A258.d.mts} +0 -1
  3. package/dist/{QueryCache-TRfXau3W.d.mts → QueryCache-Z1B38koh.d.mts} +0 -1
  4. package/dist/{actionPermissions-C9RMiIpc.mjs → actionPermissions-ze70xXJi.mjs} +1 -1
  5. package/dist/audit/index.d.mts +9 -5
  6. package/dist/auth/audit.d.mts +7 -4
  7. package/dist/auth/audit.mjs +5 -0
  8. package/dist/auth/index.d.mts +35 -14
  9. package/dist/auth/index.mjs +6 -3
  10. package/dist/auth/redis-session.d.mts +1 -2
  11. package/dist/cache/index.d.mts +2 -3
  12. package/dist/cli/commands/describe.d.mts +1 -2
  13. package/dist/cli/commands/docs.mjs +1 -1
  14. package/dist/cli/commands/init.mjs +1 -1
  15. package/dist/cli/index.mjs +1 -1
  16. package/dist/context/index.d.mts +2 -2
  17. package/dist/core/index.d.mts +3 -3
  18. package/dist/core/index.mjs +4 -4
  19. package/dist/{core-CWhyGkiM.mjs → core-b6fgFgnd.mjs} +129 -17
  20. package/dist/{createActionRouter-HlQso0jO.mjs → createActionRouter-h1cEEaEX.mjs} +10 -6
  21. package/dist/{createAggregationRouter-5LzPzgw1.mjs → createAggregationRouter-B1C0kvTL.mjs} +3 -3
  22. package/dist/{createApp-D6uwzCKu.mjs → createApp-Ci7yG5gv.mjs} +390 -192
  23. package/dist/discovery/index.d.mts +0 -1
  24. package/dist/docs/index.d.mts +1 -2
  25. package/dist/docs/index.mjs +1 -1
  26. package/dist/{elevation-xGUBq6p_.d.mts → elevation-C9s5hFP_.d.mts} +0 -1
  27. package/dist/encryption/index.d.mts +2 -144
  28. package/dist/encryption/index.mjs +9 -5
  29. package/dist/{errorHandler-Dxf6P_kV.mjs → errorHandler-BTzXSwIg.mjs} +24 -3
  30. package/dist/{errorHandler-BtUUDPEa.d.mts → errorHandler-C6yv4ZTW.d.mts} +13 -1
  31. package/dist/{errors-DOHkjQlD.d.mts → errors-DHcHVAgk.d.mts} +0 -1
  32. package/dist/{eventPlugin-DbBFd3x_.d.mts → eventPlugin-A6EbthXR.d.mts} +10 -6
  33. package/dist/events/index.d.mts +9 -6
  34. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  35. package/dist/events/transports/redis.d.mts +1 -2
  36. package/dist/factory/index.d.mts +30 -9
  37. package/dist/factory/index.mjs +35 -4
  38. package/dist/{fastify-augmentation-CCQJEDgh.d.mts → fastify-augmentation-9_fuetB4.d.mts} +2 -3
  39. package/dist/fields-D3lhgzhD.d.mts +121 -0
  40. package/dist/health-ScyjIVo5.mjs +202 -0
  41. package/dist/hooks/index.d.mts +1 -1
  42. package/dist/idempotency/index.d.mts +4 -3
  43. package/dist/idempotency/index.mjs +2 -0
  44. package/dist/idempotency/redis.d.mts +1 -1
  45. package/dist/{types-BHMKlMBU.d.mts → index-BEu4wjbL.d.mts} +241 -80
  46. package/dist/{index-DUa8WHz3.d.mts → index-D8MKYGDa.d.mts} +88 -7
  47. package/dist/{index-_--GyzcO.d.mts → index-DbtgCOCj.d.mts} +1324 -1228
  48. package/dist/{index-CdFkIMEd.d.mts → index-ogIHvOjo.d.mts} +36 -7
  49. package/dist/index.d.mts +8 -7
  50. package/dist/index.mjs +6 -6
  51. package/dist/{init-YH_nslQR.mjs → init-DleK3p9f.mjs} +272 -139
  52. package/dist/integrations/event-gateway.d.mts +2 -3
  53. package/dist/integrations/index.d.mts +2 -2
  54. package/dist/integrations/jobs.d.mts +0 -1
  55. package/dist/integrations/mcp/index.d.mts +6 -7
  56. package/dist/integrations/mcp/index.mjs +1 -1
  57. package/dist/integrations/mcp/testing.d.mts +1 -2
  58. package/dist/integrations/mcp/testing.mjs +1 -1
  59. package/dist/integrations/streamline.d.mts +2 -2
  60. package/dist/integrations/webhooks.d.mts +8 -5
  61. package/dist/integrations/webhooks.mjs +9 -5
  62. package/dist/integrations/websocket-pushref-redis.d.mts +1 -2
  63. package/dist/integrations/websocket-redis.d.mts +1 -2
  64. package/dist/integrations/websocket.d.mts +2 -2
  65. package/dist/jsonBody-BlzAoGCe.mjs +43 -0
  66. package/dist/{loadResources-B8UmpITt.mjs → loadResources-DpU8pfjV.mjs} +4 -3
  67. package/dist/logger/index.d.mts +26 -1
  68. package/dist/logger/index.mjs +39 -1
  69. package/dist/{mcpPlugin-CuW6L_uD.mjs → mcpPlugin-ByA2tf6D.mjs} +8 -4
  70. package/dist/middleware/index.d.mts +1 -2
  71. package/dist/{module-JYH9V0I8.d.mts → module-B4u10iOJ.d.mts} +71 -1
  72. package/dist/{openapi-Dq6RbEGK.mjs → openapi-BRpMZD7C.mjs} +3 -3
  73. package/dist/permissions/index.d.mts +4 -3
  74. package/dist/permissions/index.mjs +2 -2
  75. package/dist/{permissions-CgbOLJZG.mjs → permissions-BJMuKMl7.mjs} +33 -1
  76. package/dist/pipeline/index.d.mts +1 -2
  77. package/dist/plugins/index.d.mts +96 -7
  78. package/dist/plugins/index.mjs +86 -268
  79. package/dist/plugins/response-cache.d.mts +5 -3
  80. package/dist/plugins/response-cache.mjs +1 -0
  81. package/dist/plugins/tracing-entry.d.mts +1 -1
  82. package/dist/plugins/tracing-entry.mjs +7 -4
  83. package/dist/presets/filesUpload.d.mts +4 -5
  84. package/dist/presets/filesUpload.mjs +1 -1
  85. package/dist/presets/index.d.mts +1 -2
  86. package/dist/presets/index.mjs +1 -1
  87. package/dist/presets/multiTenant.d.mts +1 -2
  88. package/dist/presets/search.d.mts +2 -3
  89. package/dist/presets/search.mjs +1 -1
  90. package/dist/{presets-DWsYQdbV.mjs → presets-gw0ciIUD.mjs} +1 -1
  91. package/dist/{pushref-registry-DnCqL3aa.d.mts → pushref-registry-BbcnpNTm.d.mts} +4 -2
  92. package/dist/{queryCachePlugin-xzFyKAjT.d.mts → queryCachePlugin-CfYWq-Ak.d.mts} +1 -2
  93. package/dist/rateLimitKey-BoWRH3e7.mjs +14 -0
  94. package/dist/{redis-C3W0qbz8.d.mts → redis-UDtLaNj6.d.mts} +0 -1
  95. package/dist/{redis-stream-DsP1vqZB.d.mts → redis-stream-iVR2l7aS.d.mts} +1 -2
  96. package/dist/{registerRoute-DGSREwPw.mjs → registerRoute-xHc42fwB.mjs} +38 -18
  97. package/dist/registry/index.d.mts +2 -2
  98. package/dist/requestId-5BhTVzBv.mjs +113 -0
  99. package/dist/schemaConverter-Ds5reSGs.mjs +168 -0
  100. package/dist/{schemaIR-ajetw3Fv.mjs → schemaIR-B-6SPe7g.mjs} +2 -2
  101. package/dist/schemas/index.d.mts +0 -1
  102. package/dist/scim/index.d.mts +0 -1
  103. package/dist/scim/index.mjs +6 -7
  104. package/dist/scope/index.d.mts +2 -3
  105. package/dist/scope/index.mjs +2 -76
  106. package/dist/scope-k15RXfcq.mjs +64 -0
  107. package/dist/{sessionManager-BXG-HGwG.d.mts → sessionManager-BHOM3N_0.d.mts} +10 -6
  108. package/dist/{storage-Co_PQpeQ.d.mts → storage-DLUZ04kK.d.mts} +8 -4
  109. package/dist/testing/index.d.mts +83 -4
  110. package/dist/testing/index.mjs +74 -4
  111. package/dist/testing/storageContract.d.mts +1 -2
  112. package/dist/{tracing-D8jlGXP7.d.mts → tracing-CsGKQJGg.d.mts} +0 -1
  113. package/dist/types/index.d.mts +4 -4
  114. package/dist/types/storage.d.mts +1 -1
  115. package/dist/{types-C9b2HR5W.d.mts → types-Bc42CUyk.d.mts} +1 -2
  116. package/dist/types-Cc91nXuA.d.mts +132 -0
  117. package/dist/{fields-C7ahdGYf.d.mts → types-Csxga7d3.d.mts} +2 -123
  118. package/dist/{types-LNebCoJx.d.mts → types-DH0GupI7.d.mts} +8 -4
  119. package/dist/usage/index.d.mts +142 -0
  120. package/dist/usage/index.mjs +0 -0
  121. package/dist/utils/index.d.mts +220 -144
  122. package/dist/utils/index.mjs +3 -3
  123. package/dist/{utils-ChjYQpjn.mjs → utils-FhJ88TJE.mjs} +129 -39
  124. package/dist/{versioning-D_eBCfNr.d.mts → versioning-DLwklPlG.d.mts} +1 -7
  125. package/dist/{websocket-MlYlrYq0.d.mts → websocket-uuWqM6UY.d.mts} +5 -4
  126. package/llms.txt +39 -0
  127. package/package.json +453 -447
  128. package/skills/arc/SKILL.md +14 -8
  129. package/skills/arc/references/api-reference.md +34 -0
  130. package/skills/arc/references/auth.md +21 -4
  131. package/skills/arc/references/mcp.md +1 -1
  132. package/skills/arc/references/production.md +44 -2
  133. package/skills/arc-code-review/SKILL.md +1 -1
  134. package/skills/arc-code-review/references/anti-patterns.md +71 -18
  135. package/skills/arc-code-review/references/arc-cheatsheet.md +15 -2
  136. package/skills/arc-code-review/references/migration-recipes.md +7 -7
  137. package/skills/arc-code-review/references/mongokit-migration.md +4 -3
  138. package/skills/arc-module-publishing/SKILL.md +243 -0
  139. package/skills/arc-module-publishing/references/authoring-modules.md +327 -0
  140. package/skills/arc-module-publishing/references/package-manifest.md +157 -0
  141. package/skills/arc-module-publishing/references/publishing-workflow.md +182 -0
  142. package/dist/preloadResources-CHw3_oA_.mjs +0 -45
  143. package/dist/schemaConverter-U0MnO9vd.mjs +0 -110
@@ -1,5 +1,4 @@
1
1
  import { FastifyPluginAsync } from "fastify";
2
-
3
2
  //#region src/integrations/jobs.d.ts
4
3
  /** Repeat schedule — cron pattern or fixed interval. Explicit timezone is required. */
5
4
  interface JobRepeatOptions {
@@ -1,11 +1,10 @@
1
- import { V as ResourceDefinition, bt as IControllerResponse, xt as IRequestContext } from "../../index-_--GyzcO.mjs";
2
- import { i as RequestScope } from "../../types-LNebCoJx.mjs";
3
- import { c as PermissionCheck } from "../../fields-C7ahdGYf.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-C9b2HR5W.mjs";
1
+ import { Rt as IControllerResponse, V as ResourceDefinition, zt as IRequestContext } from "../../index-DbtgCOCj.mjs";
2
+ import { i as RequestScope } from "../../types-DH0GupI7.mjs";
3
+ import { t as PermissionCheck } from "../../types-Csxga7d3.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-Bc42CUyk.mjs";
5
5
  import { ErrorContract } from "@classytic/repo-core/errors";
6
6
  import { FastifyPluginAsync } from "fastify";
7
7
  import { z } from "zod";
8
-
9
8
  //#region src/integrations/mcp/aiSdkBridge.d.ts
10
9
  /** Minimal AI SDK tool shape we need to invoke. */
11
10
  interface AiSdkExecutable {
@@ -170,7 +169,7 @@ interface DefinePromptConfig<TArgs extends Record<string, z.ZodTypeAny>> {
170
169
  title?: string;
171
170
  /** Flat Zod shape for prompt arguments */
172
171
  args?: TArgs;
173
- handler: (args: { [K in keyof TArgs]: z.infer<TArgs[K]> }) => PromptResult;
172
+ handler: (args: { [K in keyof TArgs]: z.infer<TArgs[K]>; }) => PromptResult;
174
173
  }
175
174
  /**
176
175
  * Define a type-safe MCP prompt.
@@ -197,7 +196,7 @@ interface DefineToolConfig<TInput extends Record<string, z.ZodTypeAny>, TSession
197
196
  /** Flat Zod shape for structured output */
198
197
  output?: Record<string, z.ZodTypeAny>;
199
198
  annotations?: ToolAnnotations;
200
- handler: (input: { [K in keyof TInput]: z.infer<TInput[K]> }, ctx: ToolContext<TSession>) => Promise<CallToolResult>;
199
+ handler: (input: { [K in keyof TInput]: z.infer<TInput[K]>; }, ctx: ToolContext<TSession>) => Promise<CallToolResult>;
201
200
  }
202
201
  /**
203
202
  * Define a type-safe MCP tool.
@@ -1,4 +1,4 @@
1
- import { a as defaultCrudDescription, c as mcpHandlerAdapter, d as toCallToolResult, f as toCallToolSuccess, h as resolveToolCollisions, i as fieldRulesToZod, l as permissionDeniedResult, m as createMcpServer, n as mcpPlugin, o as resolveCrudDescription, p as buildRequestContext, r as resourceToTools, s as invokeController, t as filterResourcesForMcp, u as toCallToolError } from "../../mcpPlugin-CuW6L_uD.mjs";
1
+ import { a as defaultCrudDescription, c as mcpHandlerAdapter, d as toCallToolResult, f as toCallToolSuccess, h as resolveToolCollisions, i as fieldRulesToZod, l as permissionDeniedResult, m as createMcpServer, n as mcpPlugin, o as resolveCrudDescription, p as buildRequestContext, r as resourceToTools, s as invokeController, t as filterResourcesForMcp, u as toCallToolError } from "../../mcpPlugin-ByA2tf6D.mjs";
2
2
  //#region src/integrations/mcp/defineTool.ts
3
3
  /**
4
4
  * Define a type-safe MCP tool.
@@ -1,5 +1,4 @@
1
- import { c as McpAuthResult, l as McpPluginOptions } from "../../types-C9b2HR5W.mjs";
2
-
1
+ import { c as McpAuthResult, l as McpPluginOptions } from "../../types-Bc42CUyk.mjs";
3
2
  //#region src/integrations/mcp/testing.d.ts
4
3
  interface TestMcpClientOptions {
5
4
  /** MCP plugin options (resources, overrides, etc.) — same as mcpPlugin config */
@@ -1,4 +1,4 @@
1
- import { m as createMcpServer, r as resourceToTools, t as filterResourcesForMcp } from "../../mcpPlugin-CuW6L_uD.mjs";
1
+ import { m as createMcpServer, r as resourceToTools, t as filterResourcesForMcp } from "../../mcpPlugin-ByA2tf6D.mjs";
2
2
  //#region src/integrations/mcp/testing.ts
3
3
  /**
4
4
  * @classytic/arc/mcp/testing — MCP Test Utilities
@@ -1,5 +1,4 @@
1
1
  import { FastifyPluginAsync, FastifyRequest } from "fastify";
2
-
3
2
  //#region src/integrations/streamline.d.ts
4
3
  /**
5
4
  * Start options — matches @classytic/streamline v2.3+ `StartOptions`.
@@ -53,7 +52,8 @@ interface WorkflowLike {
53
52
  eventBus: {
54
53
  on(event: string, listener: (...args: unknown[]) => void): void;
55
54
  off(event: string, listener: (...args: unknown[]) => void): void;
56
- }; /** Repository — used by the list-runs endpoint to query workflow_runs. */
55
+ };
56
+ /** Repository — used by the list-runs endpoint to query workflow_runs. */
57
57
  repository?: {
58
58
  getAll(params: Record<string, unknown>, options?: Record<string, unknown>): Promise<unknown>;
59
59
  /**
@@ -1,5 +1,4 @@
1
1
  import { FastifyPluginAsync } from "fastify";
2
-
3
2
  //#region src/integrations/webhooks.d.ts
4
3
  interface WebhookSubscription {
5
4
  /** Unique subscription ID */
@@ -78,8 +77,9 @@ interface VerifySignatureOptions {
78
77
  *
79
78
  * ⚠ The `body` argument must be the exact bytes the sender signed. Fastify
80
79
  * parses JSON bodies by default and the re-serialised object will NOT match
81
- * the original signature. Register `@fastify/raw-body` or use `preParsing`
82
- * to capture `req.rawBody`, then pass that here.
80
+ * the original signature. Register `fastify-raw-body` (arc's createApp does
81
+ * this automatically with `global: false`) and opt the route in via
82
+ * `config: { rawBody: true }`, then pass `req.rawBody` here.
83
83
  *
84
84
  * @param body - Raw request body (string or Buffer — must be the exact bytes the sender signed)
85
85
  * @param secret - Shared secret between sender and receiver
@@ -91,8 +91,11 @@ interface VerifySignatureOptions {
91
91
  * ```typescript
92
92
  * import { verifySignature } from '@classytic/arc/integrations/webhooks';
93
93
  *
94
- * // Arc-to-Arc (default headers + format)
95
- * fastify.post('/webhooks/incoming', async (req, reply) => {
94
+ * // Arc-to-Arc (default headers + format). `config: { rawBody: true }` is
95
+ * // REQUIRED — arc registers fastify-raw-body with `global: false`, so
96
+ * // routes opt in per-route; without it `req.rawBody` is undefined and
97
+ * // verifySignature throws a TypeError.
98
+ * fastify.post('/webhooks/incoming', { config: { rawBody: true } }, async (req, reply) => {
96
99
  * const sig = req.headers['x-webhook-signature'] as string;
97
100
  * if (!verifySignature(req.rawBody, secret, sig)) {
98
101
  * return reply.status(401).send({ error: 'Invalid signature' });
@@ -48,8 +48,9 @@ function signPayload(payload, secret) {
48
48
  *
49
49
  * ⚠ The `body` argument must be the exact bytes the sender signed. Fastify
50
50
  * parses JSON bodies by default and the re-serialised object will NOT match
51
- * the original signature. Register `@fastify/raw-body` or use `preParsing`
52
- * to capture `req.rawBody`, then pass that here.
51
+ * the original signature. Register `fastify-raw-body` (arc's createApp does
52
+ * this automatically with `global: false`) and opt the route in via
53
+ * `config: { rawBody: true }`, then pass `req.rawBody` here.
53
54
  *
54
55
  * @param body - Raw request body (string or Buffer — must be the exact bytes the sender signed)
55
56
  * @param secret - Shared secret between sender and receiver
@@ -61,8 +62,11 @@ function signPayload(payload, secret) {
61
62
  * ```typescript
62
63
  * import { verifySignature } from '@classytic/arc/integrations/webhooks';
63
64
  *
64
- * // Arc-to-Arc (default headers + format)
65
- * fastify.post('/webhooks/incoming', async (req, reply) => {
65
+ * // Arc-to-Arc (default headers + format). `config: { rawBody: true }` is
66
+ * // REQUIRED — arc registers fastify-raw-body with `global: false`, so
67
+ * // routes opt in per-route; without it `req.rawBody` is undefined and
68
+ * // verifySignature throws a TypeError.
69
+ * fastify.post('/webhooks/incoming', { config: { rawBody: true } }, async (req, reply) => {
66
70
  * const sig = req.headers['x-webhook-signature'] as string;
67
71
  * if (!verifySignature(req.rawBody, secret, sig)) {
68
72
  * return reply.status(401).send({ error: 'Invalid signature' });
@@ -82,7 +86,7 @@ function signPayload(payload, secret) {
82
86
  * ```
83
87
  */
84
88
  function verifySignature(body, secret, signature, options) {
85
- if (typeof body !== "string" && !Buffer.isBuffer(body)) throw new TypeError("verifySignature: body must be a string or Buffer (the exact bytes the sender signed). Register @fastify/raw-body and pass req.rawBody — not req.body.");
89
+ if (typeof body !== "string" && !Buffer.isBuffer(body)) throw new TypeError("verifySignature: body must be a string or Buffer (the exact bytes the sender signed). Add `config: { rawBody: true }` to the route (arc registers fastify-raw-body with global: false) and pass req.rawBody — not req.body.");
86
90
  if (!signature) return false;
87
91
  const prefix = options?.prefix ?? "sha256=";
88
92
  const algorithm = options?.algorithm ?? "sha256";
@@ -1,5 +1,4 @@
1
- import { c as SerializedEntry, i as Principal, n as FencedWriteOutcome, s as PushRefStore, t as EnvelopeSnapshot } from "../pushref-registry-DnCqL3aa.mjs";
2
-
1
+ import { c as SerializedEntry, i as Principal, n as FencedWriteOutcome, s as PushRefStore, t as EnvelopeSnapshot } from "../pushref-registry-BbcnpNTm.mjs";
3
2
  //#region src/integrations/websocket-pushref-redis.d.ts
4
3
  /**
5
4
  * Minimal `ioredis` shape — typed structurally so this file doesn't
@@ -1,5 +1,4 @@
1
- import { f as WebSocketAdapter } from "../websocket-MlYlrYq0.mjs";
2
-
1
+ import { f as WebSocketAdapter } from "../websocket-uuWqM6UY.mjs";
3
2
  //#region src/integrations/websocket-redis.d.ts
4
3
  interface RedisLike {
5
4
  publish(channel: string, message: string): Promise<number>;
@@ -1,3 +1,3 @@
1
- import { a as GeoRoomOptions, c as WebSocketClient, d as LocalWebSocketAdapter, f as WebSocketAdapter, i as GeoRoom, l as WebSocketMessage, n as GeoPoint, o as RoomManager, r as GeoPublishOpts, s as AuthResult, t as websocketPlugin, u as WebSocketPluginOptions } from "../websocket-MlYlrYq0.mjs";
2
- import { a as PushRefRegistry, c as SerializedEntry, i as Principal, o as PushRefRegistryOptions, r as MemoryPushRefStore, s as PushRefStore } from "../pushref-registry-DnCqL3aa.mjs";
1
+ import { a as GeoRoomOptions, c as WebSocketClient, d as LocalWebSocketAdapter, f as WebSocketAdapter, i as GeoRoom, l as WebSocketMessage, n as GeoPoint, o as RoomManager, r as GeoPublishOpts, s as AuthResult, t as websocketPlugin, u as WebSocketPluginOptions } from "../websocket-uuWqM6UY.mjs";
2
+ import { a as PushRefRegistry, c as SerializedEntry, i as Principal, o as PushRefRegistryOptions, r as MemoryPushRefStore, s as PushRefStore } from "../pushref-registry-BbcnpNTm.mjs";
3
3
  export { type AuthResult, type GeoPoint, type GeoPublishOpts, GeoRoom, type GeoRoomOptions, LocalWebSocketAdapter, MemoryPushRefStore, type Principal, PushRefRegistry, type PushRefRegistryOptions, type PushRefStore, RoomManager, type SerializedEntry, type WebSocketAdapter, type WebSocketClient, type WebSocketMessage, type WebSocketPluginOptions, websocketPlugin };
@@ -0,0 +1,43 @@
1
+ import { t as ArcError } from "./errors-DkO8Nk6-.mjs";
2
+ import sjson from "secure-json-parse";
3
+ //#region src/utils/jsonBody.ts
4
+ /**
5
+ * Shared JSON request-body parsing for every arc content-type parser
6
+ * (`application/json`, `application/scim+json`, decrypted `application/jose`).
7
+ *
8
+ * One primitive, one contract:
9
+ * - empty body → `undefined` (DELETE/GET with `Content-Type: application/json`
10
+ * must not crash — the original reason arc replaces Fastify's parser)
11
+ * - prototype-poisoning payloads (`__proto__`, `constructor.prototype`)
12
+ * rejected via `secure-json-parse`, same protection Fastify's stock
13
+ * parser has
14
+ * - ANY parse failure → `ArcError` with `statusCode: 400` /
15
+ * `code: 'arc.bad_request'`. Client-sent bytes can never produce a 500:
16
+ * Fastify forwards parser errors to the error handler as-is, so an
17
+ * undecorated `SyntaxError` would fall through to the
18
+ * `arc.internal_error` fallback. The raw parser message stays on
19
+ * `cause` (logged, never on the wire).
20
+ */
21
+ /**
22
+ * Parse a JSON request body with prototype-poisoning protection and the
23
+ * arc 400 error contract.
24
+ *
25
+ * @param raw - Body text (string or Buffer). Empty/absent → `undefined`.
26
+ * @param message - Wire-safe error message for parse failures
27
+ * (default: `"Invalid JSON payload"`).
28
+ */
29
+ function parseJsonBody(raw, message = "Invalid JSON payload") {
30
+ const text = typeof raw === "string" ? raw : raw ? raw.toString("utf8") : "";
31
+ if (text.length === 0) return void 0;
32
+ try {
33
+ return sjson.parse(text);
34
+ } catch (cause) {
35
+ throw new ArcError(message, {
36
+ code: "arc.bad_request",
37
+ statusCode: 400,
38
+ cause
39
+ });
40
+ }
41
+ }
42
+ //#endregion
43
+ export { parseJsonBody as t };
@@ -59,10 +59,11 @@ var loadResources_exports = /* @__PURE__ */ __exportAll({ loadResources: () => l
59
59
  * ```
60
60
  */
61
61
  async function loadResources(dir, options = {}) {
62
- const { suffix = ".resource", recursive = true, exclude, include } = options;
62
+ const { suffix = ".resource", recursive = true, exclude, include, filter } = options;
63
63
  const absDir = resolve(dir.startsWith("file://") ? dirname(fileURLToPath(dir)) : dir);
64
- const files = await collectFiles(absDir, new RegExp(`${escapeRegex(suffix)}\\.(ts|js|mts|mjs)$`), recursive);
65
- files.sort();
64
+ const discovered = await collectFiles(absDir, new RegExp(`${escapeRegex(suffix)}\\.(ts|js|mts|mjs)$`), recursive);
65
+ discovered.sort();
66
+ const files = filter ? discovered.filter((f) => filter(f)) : discovered;
66
67
  const includeSet = include ? new Set(include) : null;
67
68
  const excludeSet = exclude ? new Set(exclude) : null;
68
69
  const skipped = [];
@@ -77,5 +77,30 @@ declare function configureArcLogger(options: ArcLoggerOptions): void;
77
77
  * ```
78
78
  */
79
79
  declare function arcLog(module: string): ArcLogger;
80
+ /**
81
+ * Minimal structural slice of a pino-style logger (`fastify.log`). Each
82
+ * level accepts `(msg)` or `(mergeObject, msg)` — the pino calling
83
+ * convention, which differs from console's variadic `(...args)`.
84
+ */
85
+ interface PinoLike {
86
+ debug: (obj: unknown, msg?: string) => void;
87
+ info: (obj: unknown, msg?: string) => void;
88
+ warn: (obj: unknown, msg?: string) => void;
89
+ error: (obj: unknown, msg?: string) => void;
90
+ }
91
+ /**
92
+ * Bridge an `ArcLogWriter` onto a pino-style logger (`fastify.log`).
93
+ *
94
+ * arcLog call sites use the console convention — positional args like
95
+ * `log.warn("message", { userId })` — which pino would silently drop
96
+ * (extra args are printf interpolation values there). The bridge folds
97
+ * string args into the message, merges object args into the pino merge
98
+ * object, and maps `Error` instances to `{ err }` so pino's error
99
+ * serializer applies.
100
+ *
101
+ * `createApp` installs this automatically so arc-internal warnings flow
102
+ * through the host's transports, level, and redaction config.
103
+ */
104
+ declare function createPinoWriter(logger: PinoLike): ArcLogWriter;
80
105
  //#endregion
81
- export { ArcLogWriter, ArcLogger, ArcLoggerOptions, arcLog, configureArcLogger };
106
+ export { ArcLogWriter, ArcLogger, ArcLoggerOptions, PinoLike, arcLog, configureArcLogger, createPinoWriter };
@@ -44,6 +44,44 @@ function arcLog(module) {
44
44
  }
45
45
  };
46
46
  }
47
+ /**
48
+ * Bridge an `ArcLogWriter` onto a pino-style logger (`fastify.log`).
49
+ *
50
+ * arcLog call sites use the console convention — positional args like
51
+ * `log.warn("message", { userId })` — which pino would silently drop
52
+ * (extra args are printf interpolation values there). The bridge folds
53
+ * string args into the message, merges object args into the pino merge
54
+ * object, and maps `Error` instances to `{ err }` so pino's error
55
+ * serializer applies.
56
+ *
57
+ * `createApp` installs this automatically so arc-internal warnings flow
58
+ * through the host's transports, level, and redaction config.
59
+ */
60
+ function createPinoWriter(logger) {
61
+ const emit = (level) => (...args) => {
62
+ const parts = [];
63
+ let merge;
64
+ for (const arg of args) if (typeof arg === "string") parts.push(arg);
65
+ else if (arg instanceof Error) merge = {
66
+ ...merge ?? {},
67
+ err: arg
68
+ };
69
+ else if (arg !== null && typeof arg === "object") merge = {
70
+ ...merge ?? {},
71
+ ...arg
72
+ };
73
+ else parts.push(String(arg));
74
+ const msg = parts.join(" ");
75
+ if (merge) logger[level](merge, msg);
76
+ else logger[level](msg);
77
+ };
78
+ return {
79
+ debug: emit("debug"),
80
+ info: emit("info"),
81
+ warn: emit("warn"),
82
+ error: emit("error")
83
+ };
84
+ }
47
85
  function getWriter() {
48
86
  return globalOptions.writer ?? console;
49
87
  }
@@ -68,4 +106,4 @@ function isSuppressed() {
68
106
  return env === "1" || env === "true";
69
107
  }
70
108
  //#endregion
71
- export { arcLog, configureArcLogger };
109
+ export { arcLog, configureArcLogger, createPinoWriter };
@@ -1,13 +1,13 @@
1
1
  import { p as isArcError, t as ArcError } from "./errors-DkO8Nk6-.mjs";
2
2
  import { c as getOrgId, g as getUserId } from "./types-bHblZ9YN.mjs";
3
- import { t as BaseController } from "./BaseController-D-MHZ27_.mjs";
4
- import { N as normalizePermissionResult } from "./permissions-CgbOLJZG.mjs";
3
+ import { t as BaseController } from "./BaseController-C6FlRWxF.mjs";
4
+ import { P as normalizePermissionResult } from "./permissions-BJMuKMl7.mjs";
5
5
  import { t as executePipeline } from "./pipe-BOLmGIxa.mjs";
6
- import { i as resolvePipelineSteps, t as resolveActionPermission } from "./actionPermissions-C9RMiIpc.mjs";
6
+ import { i as resolvePipelineSteps, t as resolveActionPermission } from "./actionPermissions-ze70xXJi.mjs";
7
7
  import { n as validateAggregations } from "./validate-C2mGgSXg.mjs";
8
8
  import { n as executeAggregation } from "./buildHandler-D_2ULWxZ.mjs";
9
9
  import { t as pluralize } from "./pluralize-BhrgwZb9.mjs";
10
- import { r as shouldRejectAdditionalProperties, t as normalizeSchemaIR } from "./schemaIR-ajetw3Fv.mjs";
10
+ import { r as shouldRejectAdditionalProperties, t as normalizeSchemaIR } from "./schemaIR-B-6SPe7g.mjs";
11
11
  import { createHash, randomUUID } from "node:crypto";
12
12
  import { isHttpError, toErrorContract } from "@classytic/repo-core/errors";
13
13
  import fp from "fastify-plugin";
@@ -630,6 +630,7 @@ function defaultCrudDescription(op, displayName, softDelete, queryMeta) {
630
630
  if (queryMeta?.filterableFields?.length) parts.push(`Filterable fields: ${queryMeta.filterableFields.join(", ")}.`);
631
631
  if (queryMeta?.allowedOperators?.length) parts.push(`Filter operators: ${queryMeta.allowedOperators.join(", ")} (use field[op]=value syntax).`);
632
632
  if (queryMeta?.sortableFields?.length) parts.push(`Sortable fields: ${queryMeta.sortableFields.join(", ")}.`);
633
+ parts.push("Set _count: true for a count-only result, _exists: true for a boolean existence check, or _distinct: '<field>' for distinct values — all honor the same filters.");
633
634
  return parts.join(" ");
634
635
  }
635
636
  case "get": return `Get a single ${singular} by ID`;
@@ -772,6 +773,9 @@ function buildListShape(fieldRules, options) {
772
773
  const { filterableFields = [], hiddenFields = [], extraHideFields = [], allowedOperators } = options;
773
774
  const allHidden = /* @__PURE__ */ new Set([...hiddenFields, ...extraHideFields]);
774
775
  const shape = { ...PAGINATION_SHAPE };
776
+ shape._count = z.boolean().optional().describe("Return only { count } of records matching the filters — no documents fetched. Cheapest way to answer 'how many'.");
777
+ shape._exists = z.boolean().optional().describe("Return only whether ANY record matches the filters (boolean existence check).");
778
+ shape._distinct = z.string().optional().describe("Return the distinct values of this field across records matching the filters.");
775
779
  if (!fieldRules) return shape;
776
780
  for (const name of filterableFields) {
777
781
  if (allHidden.has(name)) continue;
@@ -1,6 +1,5 @@
1
- import { I as MiddlewareHandler, L as RequestWithExtras, Q as MiddlewareConfig } from "../index-_--GyzcO.mjs";
1
+ import { I as MiddlewareHandler, L as RequestWithExtras, Q as MiddlewareConfig } from "../index-DbtgCOCj.mjs";
2
2
  import { RouteHandlerMethod } from "fastify";
3
-
4
3
  //#region src/middleware/middleware.d.ts
5
4
  interface NamedMiddleware {
6
5
  /** Unique name for debugging/introspection */
@@ -1,5 +1,5 @@
1
+ import { n as ErrorMapper } from "./errorHandler-C6yv4ZTW.mjs";
1
2
  import { FastifyInstance } from "fastify";
2
-
3
3
  //#region src/factory/loadResources.d.ts
4
4
  /**
5
5
  * loadResources — Auto-discover resource files from a directory.
@@ -142,6 +142,31 @@ interface LoadResourcesOptions<TContext = unknown> {
142
142
  * ```
143
143
  */
144
144
  include?: string[];
145
+ /**
146
+ * Path-level gate, called for every discovered file BEFORE it is imported.
147
+ * Return `false` to skip the file entirely — its module never evaluates,
148
+ * so top-level side effects (engine construction, model registration) of
149
+ * gated-off features never fire. That's the difference from
150
+ * `include`/`exclude`, which match resource NAMES after import.
151
+ *
152
+ * The feature-flag → resource-dir manifest every tiered SaaS host carries
153
+ * becomes one callback:
154
+ *
155
+ * ```ts
156
+ * await loadResources(import.meta.url, {
157
+ * filter: (path) => {
158
+ * if (path.includes(`${sep}loyalty${sep}`)) return isFeatureEnabled('loyalty');
159
+ * if (path.includes(`${sep}pos${sep}`)) return isFeatureEnabled('pos');
160
+ * return true;
161
+ * },
162
+ * });
163
+ * ```
164
+ *
165
+ * Receives the ABSOLUTE file path. Gating everything is legitimate — the
166
+ * result is an empty array (interacts with `strictResourceDir` like any
167
+ * other empty discovery).
168
+ */
169
+ filter?: (absolutePath: string) => boolean;
145
170
  /**
146
171
  * Optional logger override for diagnostics. When omitted, warnings flow
147
172
  * through arc's standard logger (`arcLog('loadResources')`) — same path
@@ -243,6 +268,26 @@ interface ArcModule<TExports = unknown> {
243
268
  * inside `bootstrap` still works — this slot just makes the two distinct.
244
269
  */
245
270
  plugins?: (fastify: FastifyInstance) => void | Promise<void>;
271
+ /**
272
+ * Domain error mappers this module ships (see `defineErrorMapper`). Merged
273
+ * into the app's error handler at boot, AFTER any host-declared mappers —
274
+ * host config keeps priority; module mappers follow in composition order.
275
+ *
276
+ * Closes the "composition root must know every domain's error classes"
277
+ * coupling: before this slot, adding `@classytic/arc-shipping` meant
278
+ * remembering to also register its `ShippingError` mapper in the host's
279
+ * `errorHandler.errorMappers` — forget it and the domain error crossed the
280
+ * wire as an opaque 500. Now the module carries its own mapper:
281
+ *
282
+ * ```ts
283
+ * defineModule({
284
+ * name: 'shipping',
285
+ * errorMappers: [shippingErrorMapper],
286
+ * ...
287
+ * })
288
+ * ```
289
+ */
290
+ readonly errorMappers?: readonly ErrorMapper[];
246
291
  /**
247
292
  * Domain init — runs in the `bootstrap` phase (after all `plugins`, before
248
293
  * resources). Initialize engines / singletons / event subscriptions here so
@@ -261,6 +306,31 @@ interface ArcModule<TExports = unknown> {
261
306
  * ```
262
307
  */
263
308
  bootstrap?: (fastify: FastifyInstance) => TExports | Promise<TExports>;
309
+ /**
310
+ * App-level resource NAMES this module authoritatively SUPERSEDES. When the
311
+ * host also lists (or `resourceDir`-discovers) a resource of the same name,
312
+ * arc DROPS the app copy and registers THIS module's version instead — so the
313
+ * host keeps NO hand-maintained "which resources did modules take over" filter
314
+ * set. Ownership lives on the atom that provides it (colocated, drift-proof):
315
+ *
316
+ * ```ts
317
+ * defineModule({ name: "order", owns: ["order", "quotation", "rfq"], resources: () => [...] })
318
+ * ```
319
+ *
320
+ * Semantics:
321
+ * - Purely a supersede-the-app-fork switch — it filters the *app* resource
322
+ * list, never the module's own `resources` (those always register).
323
+ * - Static + declarative: read at compose time, so it works regardless of
324
+ * whether `resources` is an array or a post-bootstrap factory (no early
325
+ * factory resolution, no boot-order coupling).
326
+ * - Idempotent + tolerant: an `owns` entry with no matching app resource is
327
+ * a silent no-op — a module may pre-declare a name before any fork exists.
328
+ * - Collected across ALL modules; the app-side supersession is their union.
329
+ *
330
+ * Contract: if you `owns` a name, PROVIDE it (in this module's `resources`).
331
+ * Dropping the app fork without supplying a replacement removes the route.
332
+ */
333
+ readonly owns?: readonly string[];
264
334
  /**
265
335
  * The module's resources. Array or factory — the factory form runs AFTER all
266
336
  * bootstraps, so `defineResource(...)` receives fully-booted engines. Flows
@@ -1,8 +1,8 @@
1
1
  import { t as getUserRoles } from "./types-XTApa8b6.mjs";
2
- import { n as convertRouteSchema } from "./schemaConverter-U0MnO9vd.mjs";
3
- import { t as resolveActionPermission } from "./actionPermissions-C9RMiIpc.mjs";
2
+ import { n as convertRouteSchema } from "./schemaConverter-Ds5reSGs.mjs";
3
+ import { t as resolveActionPermission } from "./actionPermissions-ze70xXJi.mjs";
4
4
  import { t as pluralize } from "./pluralize-BhrgwZb9.mjs";
5
- import { t as buildActionBodySchema } from "./createActionRouter-HlQso0jO.mjs";
5
+ import { t as buildActionBodySchema } from "./createActionRouter-h1cEEaEX.mjs";
6
6
  import fp from "fastify-plugin";
7
7
  //#region src/docs/openapi/canonical-schemas.ts
8
8
  /**
@@ -1,3 +1,4 @@
1
- import { a as applyFieldWritePermissions, c as PermissionCheck, d as UserBase, f as getUserRoles, i as applyFieldReadPermissions, l as PermissionContext, n as FieldPermissionMap, o as fields, p as normalizeRoles, r as FieldPermissionType, s as resolveEffectiveRoles, t as FieldPermission, u as PermissionResult } from "../fields-C7ahdGYf.mjs";
2
- import { A as requireRoles, C as allOf, D as not, E as denyAll, F as RequireAgentScopeOptions, I as RequireMandateOptions, L as requireAgentScope, M as when, N as applyPermissionResult, O as requireAuth, P as normalizePermissionResult, R as requireDPoP, S as createOrgPermissions, T as anyOf, _ as ConnectEventsOptions, a as presets_d_exports, b as PermissionEventBus, c as readOnly, d as requireOrgRole, f as requireScopeContext, g as createRoleHierarchy, h as RoleHierarchy, i as ownerWithAdminBypass, j as roles, k as requireOwnership, l as requireOrgInScope, m as requireTeamMembership, n as authenticated, o as publicRead, p as requireServiceScope, r as fullPublic, s as publicReadAdminWrite, t as adminOnly, u as requireOrgMembership, v as DynamicPermissionMatrix, w as allowPublic, x as createDynamicPermissionMatrix, y as DynamicPermissionMatrixConfig, z as requireMandate } from "../index-CdFkIMEd.mjs";
3
- export { type ConnectEventsOptions, type DynamicPermissionMatrix, type DynamicPermissionMatrixConfig, type FieldPermission, type FieldPermissionMap, type FieldPermissionType, type PermissionCheck, type PermissionContext, type PermissionEventBus, type PermissionResult, type RequireAgentScopeOptions, type RequireMandateOptions, type RoleHierarchy, type UserBase, adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, applyPermissionResult, authenticated, createDynamicPermissionMatrix, createOrgPermissions, createRoleHierarchy, denyAll, fields, fullPublic, getUserRoles, normalizePermissionResult, normalizeRoles, not, ownerWithAdminBypass, presets_d_exports as permissions, publicRead, publicReadAdminWrite, readOnly, requireAgentScope, requireAuth, requireDPoP, requireMandate, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, resolveEffectiveRoles, roles, when };
1
+ import { a as getUserRoles, i as UserBase, n as PermissionContext, o as normalizeRoles, r as PermissionResult, t as PermissionCheck } from "../types-Csxga7d3.mjs";
2
+ import { a as applyFieldWritePermissions, i as applyFieldReadPermissions, n as FieldPermissionMap, o as fields, r as FieldPermissionType, s as resolveEffectiveRoles, t as FieldPermission } from "../fields-D3lhgzhD.mjs";
3
+ import { A as requireOwnership, B as requireMandate, C as createOrgPermissions, D as denyAll, E as anyOf, F as normalizePermissionResult, I as RequireAgentScopeOptions, L as RequireMandateOptions, M as roles, N as when, O as not, P as applyPermissionResult, R as requireAgentScope, S as createDynamicPermissionMatrix, T as allowPublic, _ as createRoleHierarchy, a as permissionMatrix, b as DynamicPermissionMatrixConfig, c as publicReadAdminWrite, d as requireOrgMembership, f as requireOrgRole, g as RoleHierarchy, h as requireTeamMembership, i as ownerWithAdminBypass, j as requireRoles, k as requireAuth, l as readOnly, m as requireServiceScope, n as authenticated, o as presets_d_exports, p as requireScopeContext, r as fullPublic, s as publicRead, t as adminOnly, u as requireOrgInScope, v as ConnectEventsOptions, w as allOf, x as PermissionEventBus, y as DynamicPermissionMatrix, z as requireDPoP } from "../index-ogIHvOjo.mjs";
4
+ export { type ConnectEventsOptions, type DynamicPermissionMatrix, type DynamicPermissionMatrixConfig, type FieldPermission, type FieldPermissionMap, type FieldPermissionType, type PermissionCheck, type PermissionContext, type PermissionEventBus, type PermissionResult, type RequireAgentScopeOptions, type RequireMandateOptions, type RoleHierarchy, type UserBase, adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, applyPermissionResult, authenticated, createDynamicPermissionMatrix, createOrgPermissions, createRoleHierarchy, denyAll, fields, fullPublic, getUserRoles, normalizePermissionResult, normalizeRoles, not, ownerWithAdminBypass, permissionMatrix, presets_d_exports as permissions, publicRead, publicReadAdminWrite, readOnly, requireAgentScope, requireAuth, requireDPoP, requireMandate, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, resolveEffectiveRoles, roles, when };
@@ -1,3 +1,3 @@
1
- import { A as requireMandate, C as requireAuth, D as when, E as roles, F as applyFieldWritePermissions, I as fields, L as resolveEffectiveRoles, N as normalizePermissionResult, O as requireAgentScope, P as applyFieldReadPermissions, S as not, 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 applyPermissionResult, k as requireDPoP, l as createRoleHierarchy, 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-CgbOLJZG.mjs";
1
+ import { A as requireDPoP, C as not, D as roles, E as requireRoles, F as applyFieldReadPermissions, I as applyFieldWritePermissions, L as fields, M as applyPermissionResult, O as when, P as normalizePermissionResult, R as resolveEffectiveRoles, S as denyAll, T as requireOwnership, _ as requireServiceScope, a as permissionMatrix, b as allowPublic, c as publicReadAdminWrite, d as createDynamicPermissionMatrix, f as createOrgPermissions, g as requireScopeContext, h as requireOrgRole, i as ownerWithAdminBypass, j as requireMandate, k as requireAgentScope, l as readOnly, m as requireOrgMembership, n as authenticated, o as presets_exports, p as requireOrgInScope, r as fullPublic, s as publicRead, t as adminOnly, u as createRoleHierarchy, v as requireTeamMembership, w as requireAuth, x as anyOf, y as allOf } from "../permissions-BJMuKMl7.mjs";
2
2
  import { n as normalizeRoles, t as getUserRoles } from "../types-XTApa8b6.mjs";
3
- export { adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, applyPermissionResult, authenticated, createDynamicPermissionMatrix, createOrgPermissions, createRoleHierarchy, denyAll, fields, fullPublic, getUserRoles, normalizePermissionResult, normalizeRoles, not, ownerWithAdminBypass, presets_exports as permissions, publicRead, publicReadAdminWrite, readOnly, requireAgentScope, requireAuth, requireDPoP, requireMandate, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, resolveEffectiveRoles, roles, when };
3
+ export { adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, applyPermissionResult, authenticated, createDynamicPermissionMatrix, createOrgPermissions, createRoleHierarchy, denyAll, fields, fullPublic, getUserRoles, normalizePermissionResult, normalizeRoles, not, ownerWithAdminBypass, permissionMatrix, presets_exports as permissions, publicRead, publicReadAdminWrite, readOnly, requireAgentScope, requireAuth, requireDPoP, requireMandate, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, resolveEffectiveRoles, roles, when };
@@ -1382,6 +1382,7 @@ var presets_exports = /* @__PURE__ */ __exportAll({
1382
1382
  authenticated: () => authenticated,
1383
1383
  fullPublic: () => fullPublic,
1384
1384
  ownerWithAdminBypass: () => ownerWithAdminBypass,
1385
+ permissionMatrix: () => permissionMatrix,
1385
1386
  publicRead: () => publicRead,
1386
1387
  publicReadAdminWrite: () => publicReadAdminWrite,
1387
1388
  readOnly: () => readOnly
@@ -1450,6 +1451,37 @@ function adminOnly(roles = ["admin"], overrides) {
1450
1451
  }, overrides);
1451
1452
  }
1452
1453
  /**
1454
+ * Arbitrary-gate CRUD matrix — the generalization every host and arc-*
1455
+ * module hand-rolls as `{ list: view, get: view, create: manage, ... }`.
1456
+ *
1457
+ * Unlike the fixed presets above, the gates are caller-supplied
1458
+ * `PermissionCheck`s, so ANY combinator plugs in — org roles, ownership,
1459
+ * `anyOf(...)`, service scopes, custom async checks. `delete` defaults to
1460
+ * the `write` gate.
1461
+ *
1462
+ * @example
1463
+ * ```typescript
1464
+ * // Two-gate (view/manage) — the arc-* module convention:
1465
+ * permissionMatrix({ read: requireAuth(), write: requireOrgRole('manager') })
1466
+ *
1467
+ * // Three-gate with a stricter delete:
1468
+ * permissionMatrix({
1469
+ * read: allowPublic(),
1470
+ * write: requireOrgRole('manager'),
1471
+ * delete: requireOrgRole('owner'),
1472
+ * })
1473
+ * ```
1474
+ */
1475
+ function permissionMatrix(gates, overrides) {
1476
+ return withOverrides({
1477
+ list: gates.read,
1478
+ get: gates.read,
1479
+ create: gates.write,
1480
+ update: gates.write,
1481
+ delete: gates.delete ?? gates.write
1482
+ }, overrides);
1483
+ }
1484
+ /**
1453
1485
  * Owner-scoped with admin bypass.
1454
1486
  * list = auth (scoped to owner), get = auth, create = auth,
1455
1487
  * update + delete = ownership check with admin bypass.
@@ -1498,4 +1530,4 @@ function readOnly(overrides) {
1498
1530
  }, overrides);
1499
1531
  }
1500
1532
  //#endregion
1501
- export { requireMandate as A, requireAuth as C, when as D, roles as E, applyFieldWritePermissions as F, fields as I, resolveEffectiveRoles as L, evaluateAndApplyPermission as M, normalizePermissionResult as N, requireAgentScope as O, applyFieldReadPermissions as P, not as S, requireRoles as T, requireTeamMembership as _, presets_exports as a, anyOf as b, readOnly as c, createOrgPermissions as d, requireOrgInScope as f, requireServiceScope as g, requireScopeContext as h, ownerWithAdminBypass as i, applyPermissionResult as j, requireDPoP as k, createRoleHierarchy as l, requireOrgRole as m, authenticated as n, publicRead as o, requireOrgMembership as p, fullPublic as r, publicReadAdminWrite as s, adminOnly as t, createDynamicPermissionMatrix as u, allOf as v, requireOwnership as w, denyAll as x, allowPublic as y };
1533
+ export { requireDPoP as A, not as C, roles as D, requireRoles as E, applyFieldReadPermissions as F, applyFieldWritePermissions as I, fields as L, applyPermissionResult as M, evaluateAndApplyPermission as N, when as O, normalizePermissionResult as P, resolveEffectiveRoles as R, denyAll as S, requireOwnership as T, requireServiceScope as _, permissionMatrix as a, allowPublic as b, publicReadAdminWrite as c, createDynamicPermissionMatrix as d, createOrgPermissions as f, requireScopeContext as g, requireOrgRole as h, ownerWithAdminBypass as i, requireMandate as j, requireAgentScope as k, readOnly as l, requireOrgMembership as m, authenticated as n, presets_exports as o, requireOrgInScope as p, fullPublic as r, publicRead as s, adminOnly as t, createRoleHierarchy as u, requireTeamMembership as v, requireAuth as w, anyOf as x, allOf as y };
@@ -1,5 +1,4 @@
1
- import { Bt as Transform, Ft as NextFunction, It as OperationFilter, Lt as PipelineConfig, Nt as Guard, Pt as Interceptor, Rt as PipelineContext, bt as IControllerResponse, zt as PipelineStep } from "../index-_--GyzcO.mjs";
2
-
1
+ import { Ct as PipelineStep, Rt as IControllerResponse, St as PipelineContext, _t as Guard, bt as OperationFilter, vt as Interceptor, wt as Transform, xt as PipelineConfig, yt as NextFunction } from "../index-DbtgCOCj.mjs";
3
2
  //#region src/pipeline/guard.d.ts
4
3
  interface GuardOptions {
5
4
  operations?: OperationFilter;