@classytic/arc 2.18.1 → 2.18.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/dist/{BaseController-DPwe89qs.mjs → BaseController-B-uXzf6I.mjs} +403 -216
  2. package/dist/{QueryCache-8YmAQ-zW.d.mts → QueryCache-Dsyv2mLS.d.mts} +1 -1
  3. package/dist/audit/index.d.mts +1 -1
  4. package/dist/auth/index.d.mts +4 -4
  5. package/dist/auth/index.mjs +4 -4
  6. package/dist/auth/redis-session.d.mts +1 -1
  7. package/dist/{betterAuthOpenApi-ClWxaceA.mjs → betterAuthOpenApi-DAAhMZff.mjs} +1 -1
  8. package/dist/{buildHandler-C_SkBNF3.mjs → buildHandler-Cvrc2p7r.mjs} +1 -1
  9. package/dist/cache/index.d.mts +3 -3
  10. package/dist/cache/index.mjs +3 -3
  11. package/dist/cli/commands/describe.d.mts +1 -1
  12. package/dist/cli/commands/describe.mjs +1 -1
  13. package/dist/cli/commands/docs.mjs +2 -2
  14. package/dist/cli/commands/generate.d.mts +1 -1
  15. package/dist/cli/commands/generate.mjs +1 -1
  16. package/dist/cli/commands/init.d.mts +1 -1
  17. package/dist/cli/commands/init.mjs +1 -1
  18. package/dist/cli/commands/introspect.mjs +1 -1
  19. package/dist/cli/index.d.mts +2 -2
  20. package/dist/cli/index.mjs +2 -2
  21. package/dist/core/index.d.mts +2 -2
  22. package/dist/core/index.mjs +3 -3
  23. package/dist/{core-B41eZxyM.mjs → core-C88uIwd3.mjs} +161 -103
  24. package/dist/{createActionRouter-CRaIwB5S.mjs → createActionRouter-DGCCp-kP.mjs} +4 -2
  25. package/dist/{createAggregationRouter-n3O6WdLO.mjs → createAggregationRouter-Ca77b8iK.mjs} +3 -3
  26. package/dist/{createApp-DZvrb587.mjs → createApp-DLuUGVZQ.mjs} +11 -11
  27. package/dist/{defineEvent-NPKUJRt8.mjs → defineEvent-DC981g-o.mjs} +1 -1
  28. package/dist/docs/index.d.mts +2 -2
  29. package/dist/docs/index.mjs +2 -2
  30. package/dist/{elevation-6mfTLBC-.mjs → elevation-BzhyVWfn.mjs} +1 -1
  31. package/dist/{eventPlugin-Dxp9JlKK.mjs → eventPlugin-Bw4bUDEO.mjs} +2 -2
  32. package/dist/{eventPlugin-DjEx_J3j.d.mts → eventPlugin-C1W1CRbf.d.mts} +1 -1
  33. package/dist/events/index.d.mts +8 -5
  34. package/dist/events/index.mjs +26 -7
  35. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  36. package/dist/events/transports/redis-stream-entry.mjs +52 -5
  37. package/dist/events/transports/redis.d.mts +1 -1
  38. package/dist/factory/index.d.mts +1 -1
  39. package/dist/factory/index.mjs +3 -3
  40. package/dist/{fastify-augmentation-CL48B6gW.d.mts → fastify-augmentation-BdCl_eNo.d.mts} +2 -2
  41. package/dist/{fields-DqZLp5d6.d.mts → fields-CKLrhyOb.d.mts} +1 -1
  42. package/dist/{generate-CcM24hoq.mjs → generate-BaxDdmJ8.mjs} +1 -1
  43. package/dist/hooks/index.d.mts +1 -1
  44. package/dist/hooks/index.mjs +1 -1
  45. package/dist/idempotency/index.d.mts +2 -2
  46. package/dist/idempotency/index.mjs +1 -1
  47. package/dist/idempotency/redis.d.mts +1 -1
  48. package/dist/{index-CNiryUMN.d.mts → index-Cvo1u9n6.d.mts} +3 -3
  49. package/dist/{index-C000faom.d.mts → index-QYma8mdC.d.mts} +215 -241
  50. package/dist/{index-3L-adFJO.d.mts → index-vcWUGkwf.d.mts} +3 -3
  51. package/dist/index.d.mts +5 -5
  52. package/dist/index.mjs +5 -5
  53. package/dist/{init-DQ_rY1J7.mjs → init-DSsdRfk9.mjs} +3 -3
  54. package/dist/integrations/event-gateway.d.mts +2 -2
  55. package/dist/integrations/event-gateway.mjs +1 -1
  56. package/dist/integrations/index.d.mts +2 -2
  57. package/dist/integrations/jobs.mjs +66 -1
  58. package/dist/integrations/mcp/index.d.mts +4 -4
  59. package/dist/integrations/mcp/index.mjs +1 -1
  60. package/dist/integrations/mcp/testing.d.mts +1 -1
  61. package/dist/integrations/mcp/testing.mjs +1 -1
  62. package/dist/integrations/streamline.d.mts +16 -1
  63. package/dist/integrations/streamline.mjs +35 -4
  64. package/dist/integrations/websocket-pushref-redis.d.mts +1 -1
  65. package/dist/integrations/websocket-redis.d.mts +1 -1
  66. package/dist/integrations/websocket.d.mts +2 -2
  67. package/dist/{loadResourcesFromEntry-DCjYMgfC.mjs → loadResourcesFromEntry-XHNeUWpu.mjs} +1 -1
  68. package/dist/{mcpPlugin-BrepZ0cV.mjs → mcpPlugin-CzKdt3B8.mjs} +9 -9
  69. package/dist/middleware/index.d.mts +1 -1
  70. package/dist/middleware/index.mjs +1 -1
  71. package/dist/{openapi-CLZx9bwS.mjs → openapi-ButnRyOM.mjs} +5 -5
  72. package/dist/permissions/index.d.mts +2 -2
  73. package/dist/permissions/index.mjs +2 -2
  74. package/dist/{permissions-B1Qy55fg.mjs → permissions-3uzwkbQt.mjs} +99 -99
  75. package/dist/pipeline/index.d.mts +1 -1
  76. package/dist/pipeline/index.mjs +1 -1
  77. package/dist/pipeline-D4sqiokR.mjs +336 -0
  78. package/dist/plugins/index.d.mts +5 -5
  79. package/dist/plugins/index.mjs +9 -9
  80. package/dist/plugins/response-cache.mjs +1 -1
  81. package/dist/plugins/tracing-entry.d.mts +1 -1
  82. package/dist/plugins/tracing-entry.mjs +1 -1
  83. package/dist/presets/filesUpload.d.mts +4 -4
  84. package/dist/presets/filesUpload.mjs +2 -2
  85. package/dist/presets/index.d.mts +1 -1
  86. package/dist/presets/index.mjs +1 -1
  87. package/dist/presets/multiTenant.d.mts +1 -1
  88. package/dist/presets/search.d.mts +2 -2
  89. package/dist/presets/search.mjs +1 -1
  90. package/dist/{presets-BYbPobbF.mjs → presets-CF79RHEo.mjs} +1 -1
  91. package/dist/{queryCachePlugin-Do4P_WBC.d.mts → queryCachePlugin-Bd2tYgh5.d.mts} +2 -2
  92. package/dist/{queryCachePlugin-B4XMSSe7.mjs → queryCachePlugin-CnAeFqju.mjs} +3 -3
  93. package/dist/rateLimit-yKvxWAky.mjs +207 -0
  94. package/dist/{redis-cpqVb85w.d.mts → redis-3hqH_Qk_.d.mts} +1 -1
  95. package/dist/{redis-stream-BuiAS3aE.d.mts → redis-stream-BtEUtjxZ.d.mts} +5 -4
  96. package/dist/registerRoute-BEYn0ylk.mjs +108 -0
  97. package/dist/registry/index.d.mts +1 -1
  98. package/dist/registry/index.mjs +2 -2
  99. package/dist/{schemaIR-Bk6Tns82.mjs → schemaIR-CE6USIRi.mjs} +1 -1
  100. package/dist/scope/index.d.mts +2 -2
  101. package/dist/scope/index.mjs +2 -2
  102. package/dist/testing/index.d.mts +2 -2
  103. package/dist/testing/index.mjs +12 -2
  104. package/dist/testing/storageContract.d.mts +1 -1
  105. package/dist/types/index.d.mts +4 -4
  106. package/dist/types/storage.d.mts +1 -1
  107. package/dist/{types-DH-7WO64.d.mts → types-BWBcb88c.d.mts} +1 -1
  108. package/dist/{types-DEEWwQFR.d.mts → types-WVlAVp8T.d.mts} +10 -10
  109. package/dist/utils/index.d.mts +3 -3
  110. package/dist/utils/index.mjs +3 -3
  111. package/dist/{utils-BMQK8mRl.mjs → utils-xAQeDyU_.mjs} +1 -1
  112. package/dist/{validate-DFIP2VrM.mjs → validate-0__MuUsK.mjs} +201 -190
  113. package/dist/{versioning-5H4930tj.d.mts → versioning-BSEDGXKC.d.mts} +1 -1
  114. package/dist/{websocket-BZMUP7Gr.d.mts → websocket-BFBT5rH-.d.mts} +1 -1
  115. package/package.json +5 -5
  116. package/skills/arc/references/api-reference.md +1 -1
  117. package/dist/routerShared-Dl0A77Ba.mjs +0 -724
  118. /package/dist/{EventTransport-ClEDfiMS.mjs → EventTransport-7LPXLEUX.mjs} +0 -0
  119. /package/dist/{EventTransport-B1GFiYUy.d.mts → EventTransport-CaaXM5Y1.d.mts} +0 -0
  120. /package/dist/{HookSystem-Cmf7-Etp.mjs → HookSystem-BfCpWbwM.mjs} +0 -0
  121. /package/dist/{ResourceRegistry-CzSzVK1m.mjs → ResourceRegistry-CWmOggxS.mjs} +0 -0
  122. /package/dist/{actionPermissions-Bjmvn7Eb.mjs → actionPermissions-CX9QIMTd.mjs} +0 -0
  123. /package/dist/{caching-8MfrrUYU.mjs → caching-C0DdKiYB.mjs} +0 -0
  124. /package/dist/{elevation-DvwtjDwu.d.mts → elevation-DW90z5bT.d.mts} +0 -0
  125. /package/dist/{errorHandler-wQejMBT3.mjs → errorHandler-Bua97SEt.mjs} +0 -0
  126. /package/dist/{errorHandler-DuqTqeqn.d.mts → errorHandler-_Lp2k9M3.d.mts} +0 -0
  127. /package/dist/{errors-4ZloYFvm.d.mts → errors-DZOemeGa.d.mts} +0 -0
  128. /package/dist/{externalPaths-ClykOQqa.d.mts → externalPaths-DLle0R07.d.mts} +0 -0
  129. /package/dist/{generate-cRnsafMS.d.mts → generate-Dmk8cfvX.d.mts} +0 -0
  130. /package/dist/{init-D-vrTZ1G.d.mts → init-BS4Daqnv.d.mts} +0 -0
  131. /package/dist/{interface-DoE6UoC2.d.mts → interface-CsrGR8LF.d.mts} +0 -0
  132. /package/dist/{interface-BVkZsvEe.d.mts → interface-DL7LlWS5.d.mts} +0 -0
  133. /package/dist/{keys-DopsCuyQ.mjs → keys-B3yyBEyH.mjs} +0 -0
  134. /package/dist/{loadResources-fol6JuvW.mjs → loadResources-CwXt9MCh.mjs} +0 -0
  135. /package/dist/{memory-QOLe11D5.mjs → memory-TdTHCS9-.mjs} +0 -0
  136. /package/dist/{metrics-B-PU4-Yu.mjs → metrics-Da2EUPi9.mjs} +0 -0
  137. /package/dist/{multipartBody-VjVWmZl8.mjs → multipartBody-709YcXi1.mjs} +0 -0
  138. /package/dist/{pipe-DiCyvyPN.mjs → pipe-9Tl-OAus.mjs} +0 -0
  139. /package/dist/{pluralize-B9M8xvy-.mjs → pluralize-BxdUl2P4.mjs} +0 -0
  140. /package/dist/{preloadResources-BOXzPhKU.mjs → preloadResources-B-j-iqo-.mjs} +0 -0
  141. /package/dist/{pushref-registry-Bq_-EVsC.d.mts → pushref-registry-Dqclzjy7.d.mts} +0 -0
  142. /package/dist/{registry-BrlHkrRS.mjs → registry-Br15xdGM.mjs} +0 -0
  143. /package/dist/{replyHelpers-boS5Rx26.mjs → replyHelpers-DXHVxrrj.mjs} +0 -0
  144. /package/dist/{schemaConverter-De34B1ZG.mjs → schemaConverter-DatAaVNj.mjs} +0 -0
  145. /package/dist/{sessionManager-DlmaHUAl.d.mts → sessionManager-CyHpYXoB.d.mts} +0 -0
  146. /package/dist/{sse-jh5OqFjR.mjs → sse-Xq8UtuQx.mjs} +0 -0
  147. /package/dist/{storage-BFmamN5m.d.mts → storage-C5q8fuEt.d.mts} +0 -0
  148. /package/dist/{store-helpers-5JgaxieH.mjs → store-helpers-DjSYI2uP.mjs} +0 -0
  149. /package/dist/{tracing-BYQ3hsbM.d.mts → tracing-Bnb1-YVd.d.mts} +0 -0
  150. /package/dist/{typeGuards-BzkXkvVv.mjs → typeGuards-CcFZXgU7.mjs} +0 -0
  151. /package/dist/{types-CfapW2t8.d.mts → types-BJwJN2Pg.d.mts} +0 -0
  152. /package/dist/{types-DV9WDfeg.mjs → types-D57iXYb8.mjs} +0 -0
  153. /package/dist/{versioning-CuIwUQZ2.mjs → versioning-C0K8KQLx.mjs} +0 -0
@@ -1,7 +1,7 @@
1
- import { c as WebSocketClient, l as WebSocketMessage, u as WebSocketPluginOptions } from "../websocket-BZMUP7Gr.mjs";
1
+ import { c as WebSocketClient, l as WebSocketMessage, u as WebSocketPluginOptions } from "../websocket-BFBT5rH-.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-DH-7WO64.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-BWBcb88c.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 };
@@ -40,6 +40,68 @@ var Semaphore = class {
40
40
  else this.available++;
41
41
  }
42
42
  };
43
+ /**
44
+ * Whether an existing schedule matches the currently configured repeat spec.
45
+ *
46
+ * BullMQ keys repeatable schedules by `name:jobId:endDate:tz:(pattern|every)`
47
+ * — exactly these fields determine schedule identity, so they are exactly
48
+ * what we compare. `limit` is intentionally NOT compared: it isn't part of
49
+ * the key, so a changed limit upserts in place and never strands a stale
50
+ * schedule.
51
+ */
52
+ function repeatSpecMatches(record, spec) {
53
+ if ((record.pattern ?? void 0) !== spec.pattern) return false;
54
+ if ((record.every == null ? void 0 : Number(record.every)) !== spec.every) return false;
55
+ if ((record.tz ?? void 0) !== spec.tz) return false;
56
+ if ((record.endDate == null ? void 0 : record.endDate) !== (spec.endDate == null ? void 0 : new Date(spec.endDate).getTime())) return false;
57
+ return true;
58
+ }
59
+ /**
60
+ * Remove repeatable schedules left behind by a previous deploy whose repeat
61
+ * spec no longer matches the current `JobDefinition.repeat`.
62
+ *
63
+ * BullMQ keys repeatable schedules by a hash of their repeat options, so
64
+ * re-adding a job with a CHANGED pattern/every/tz/endDate creates a NEW
65
+ * schedule while the old one keeps firing — the job double-fires after every
66
+ * repeat-config change. This reconciles at plugin registration:
67
+ *
68
+ * - Only schedulers whose `name` equals the registered job's name are
69
+ * candidates — foreign/unknown schedulers are never touched.
70
+ * - A scheduler matching the current spec is kept (the subsequent
71
+ * `queue.add` upserts it in place, preserving its timing state).
72
+ * - Fail-open: any error logs a warning and never blocks boot — this is
73
+ * boot-time hygiene, not a correctness gate.
74
+ *
75
+ * Uses the modern `getJobSchedulers()` / `removeJobScheduler()` API (BullMQ
76
+ * 5.x job schedulers) and falls back to the deprecated `getRepeatableJobs()`
77
+ * / `removeRepeatableByKey()` pair on older clients. When neither API exists
78
+ * the step is skipped entirely.
79
+ */
80
+ async function removeStaleRepeatSchedulers(queue, jobName, spec, log) {
81
+ const q = queue;
82
+ const list = typeof q.getJobSchedulers === "function" ? q.getJobSchedulers.bind(q) : typeof q.getRepeatableJobs === "function" ? q.getRepeatableJobs.bind(q) : null;
83
+ const remove = typeof q.removeJobScheduler === "function" ? q.removeJobScheduler.bind(q) : typeof q.removeRepeatableByKey === "function" ? q.removeRepeatableByKey.bind(q) : null;
84
+ if (!list || !remove) return;
85
+ try {
86
+ const existing = await list();
87
+ for (const record of existing) {
88
+ if (!record || record.name !== jobName) continue;
89
+ if (repeatSpecMatches(record, spec)) continue;
90
+ await remove(record.key);
91
+ log.warn({
92
+ job: jobName,
93
+ schedulerKey: record.key,
94
+ stalePattern: record.pattern ?? void 0,
95
+ staleEvery: record.every ?? void 0
96
+ }, `[arc/jobs] Removed stale repeatable schedule for '${jobName}' — repeat config changed since last deploy`);
97
+ }
98
+ } catch (err) {
99
+ log.warn({
100
+ err,
101
+ job: jobName
102
+ }, `[arc/jobs] Failed to reconcile repeatable schedules for '${jobName}' — continuing (boot-time hygiene only)`);
103
+ }
104
+ }
43
105
  const jobsPluginImpl = async (fastify, options) => {
44
106
  const { connection, jobs, prefix = "/jobs", bridgeEvents = true, defaults = {} } = options;
45
107
  let Queue;
@@ -78,6 +140,7 @@ const jobsPluginImpl = async (fastify, options) => {
78
140
  ...job.repeat.endDate ? { endDate: job.repeat.endDate } : {},
79
141
  ...job.repeat.limit != null ? { limit: job.repeat.limit } : {}
80
142
  };
143
+ await removeStaleRepeatSchedulers(queue, queueName, repeatOpts, fastify.log);
81
144
  await queue.add(queueName, {}, {
82
145
  repeat: repeatOpts,
83
146
  removeOnComplete: defaults.removeOnComplete ?? 100,
@@ -193,6 +256,8 @@ const jobsPluginImpl = async (fastify, options) => {
193
256
  workers.set(queueName, worker);
194
257
  }
195
258
  const JOB_PAYLOAD_WARN_BYTES = 100 * 1024;
259
+ const jobDefsByName = /* @__PURE__ */ new Map();
260
+ for (const job of jobs) if (!jobDefsByName.has(job.name)) jobDefsByName.set(job.name, job);
196
261
  const dispatcher = {
197
262
  async dispatch(name, data, opts = {}) {
198
263
  const queue = queues.get(name);
@@ -205,7 +270,7 @@ const jobsPluginImpl = async (fastify, options) => {
205
270
  limit: JOB_PAYLOAD_WARN_BYTES
206
271
  }, `[arc/jobs] Large job payload — prefer passing IDs and reloading in the handler`);
207
272
  } catch {}
208
- const jobDef = jobs.find((j) => j.name === name);
273
+ const jobDef = jobDefsByName.get(name);
209
274
  return { jobId: (await queue.add(name, data, {
210
275
  delay: opts.delay,
211
276
  priority: opts.priority,
@@ -1,7 +1,7 @@
1
- import { V as ResourceDefinition, bt as IRequestContext, yt as IControllerResponse } from "../../index-C000faom.mjs";
2
- import { i as RequestScope } from "../../types-CfapW2t8.mjs";
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-DH-7WO64.mjs";
1
+ import { V as ResourceDefinition, bt as IRequestContext, yt as IControllerResponse } from "../../index-QYma8mdC.mjs";
2
+ import { i as RequestScope } from "../../types-BJwJN2Pg.mjs";
3
+ import { c as PermissionCheck } from "../../fields-CKLrhyOb.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-BWBcb88c.mjs";
5
5
  import { ErrorContract } from "@classytic/repo-core/errors";
6
6
  import { FastifyPluginAsync } from "fastify";
7
7
  import { z } from "zod";
@@ -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-BrepZ0cV.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-CzKdt3B8.mjs";
2
2
  //#region src/integrations/mcp/defineTool.ts
3
3
  /**
4
4
  * Define a type-safe MCP tool.
@@ -1,4 +1,4 @@
1
- import { c as McpAuthResult, l as McpPluginOptions } from "../../types-DH-7WO64.mjs";
1
+ import { c as McpAuthResult, l as McpPluginOptions } from "../../types-BWBcb88c.mjs";
2
2
 
3
3
  //#region src/integrations/mcp/testing.d.ts
4
4
  interface TestMcpClientOptions {
@@ -1,4 +1,4 @@
1
- import { m as createMcpServer, r as resourceToTools, t as filterResourcesForMcp } from "../../mcpPlugin-BrepZ0cV.mjs";
1
+ import { m as createMcpServer, r as resourceToTools, t as filterResourcesForMcp } from "../../mcpPlugin-CzKdt3B8.mjs";
2
2
  //#region src/integrations/mcp/testing.ts
3
3
  /**
4
4
  * @classytic/arc/mcp/testing — MCP Test Utilities
@@ -232,6 +232,21 @@ interface StreamlinePluginOptions {
232
232
  * because streamline extended its bus.
233
233
  */
234
234
  declare const STREAMLINE_BUS_EVENTS: readonly ["step:started", "step:completed", "step:failed", "step:waiting", "step:skipped", "step:retry-scheduled", "step:compensated", "workflow:started", "workflow:completed", "workflow:failed", "workflow:waiting", "workflow:resumed", "workflow:cancelled", "workflow:recovered", "workflow:retry", "workflow:compensating", "engine:error", "scheduler:error", "scheduler:circuit-open"];
235
+ /**
236
+ * Non-durable streaming frames from streamline >= 2.6's `ctx.stream(frame)`
237
+ * (LLM tokens, percent-complete, live previews).
238
+ *
239
+ * Delivered on the SSE endpoint ONLY — deliberately excluded from
240
+ * `STREAMLINE_BUS_EVENTS` / `bridgeBusEvents` because frames are
241
+ * high-frequency, at-most-once UI traffic, not domain events: republishing
242
+ * every token onto arc's Redis/Kafka transport would flood it. Subscribers
243
+ * that genuinely want frames on the transport can bridge
244
+ * `streamline:step.stream` from streamline's own arc-shape transport.
245
+ *
246
+ * On streamline < 2.6 the subscription is a structural no-op (the bus never
247
+ * emits the event) — no version gate needed.
248
+ */
249
+ declare const STREAMLINE_STREAM_EVENTS: readonly ["step:stream"];
235
250
  /**
236
251
  * Workflow events that should auto-close an SSE stream when observed.
237
252
  * Recovered / waiting / resumed / retry / compensating are NOT terminal —
@@ -255,4 +270,4 @@ declare const TERMINAL_RUN_STATUSES: Set<string>;
255
270
  */
256
271
  declare const streamlinePlugin: FastifyPluginAsync<StreamlinePluginOptions>;
257
272
  //#endregion
258
- export { STREAMLINE_BUS_EVENTS, STREAMLINE_FAILURE_CODES, STREAMLINE_TERMINAL_EVENTS, StreamlinePluginOptions, TERMINAL_RUN_STATUSES, WorkflowLike, WorkflowRunLike, WorkflowStartOptions, streamlinePlugin };
273
+ export { STREAMLINE_BUS_EVENTS, STREAMLINE_FAILURE_CODES, STREAMLINE_STREAM_EVENTS, STREAMLINE_TERMINAL_EVENTS, StreamlinePluginOptions, TERMINAL_RUN_STATUSES, WorkflowLike, WorkflowRunLike, WorkflowStartOptions, streamlinePlugin };
@@ -49,6 +49,21 @@ const STREAMLINE_BUS_EVENTS = [
49
49
  "scheduler:circuit-open"
50
50
  ];
51
51
  /**
52
+ * Non-durable streaming frames from streamline >= 2.6's `ctx.stream(frame)`
53
+ * (LLM tokens, percent-complete, live previews).
54
+ *
55
+ * Delivered on the SSE endpoint ONLY — deliberately excluded from
56
+ * `STREAMLINE_BUS_EVENTS` / `bridgeBusEvents` because frames are
57
+ * high-frequency, at-most-once UI traffic, not domain events: republishing
58
+ * every token onto arc's Redis/Kafka transport would flood it. Subscribers
59
+ * that genuinely want frames on the transport can bridge
60
+ * `streamline:step.stream` from streamline's own arc-shape transport.
61
+ *
62
+ * On streamline < 2.6 the subscription is a structural no-op (the bus never
63
+ * emits the event) — no version gate needed.
64
+ */
65
+ const STREAMLINE_STREAM_EVENTS = ["step:stream"];
66
+ /**
52
67
  * Workflow events that should auto-close an SSE stream when observed.
53
68
  * Recovered / waiting / resumed / retry / compensating are NOT terminal —
54
69
  * the run is still active after them.
@@ -99,6 +114,14 @@ const streamlinePluginImpl = async (fastify, options) => {
99
114
  };
100
115
  for (const [id, wf] of registry) {
101
116
  const routePrefix = `${routeScope}/${id}`;
117
+ const visibilityRepo = wf.container?.repository;
118
+ const visibilityGetById = visibilityRepo?.getById?.bind(visibilityRepo);
119
+ const assertRunVisible = async (request, runId) => {
120
+ if (!visibilityGetById) return;
121
+ const tenantOpts = resolveTenantOpts(request);
122
+ if (tenantOpts.bypassTenant || tenantOpts.tenantId === void 0) return;
123
+ if (!await visibilityGetById(runId, { tenantId: tenantOpts.tenantId })) throw new NotFoundError("Workflow run", runId);
124
+ };
102
125
  fastify.post(`${routePrefix}/start`, { preHandler: authPreHandler }, async (request, reply) => {
103
126
  if (!await checkPerm("start", request)) throw new ForbiddenError();
104
127
  const body = request.body;
@@ -170,6 +193,7 @@ const streamlinePluginImpl = async (fastify, options) => {
170
193
  fastify.get(`${routePrefix}/runs/:runId`, { preHandler: authPreHandler }, async (request, _reply) => {
171
194
  if (!await checkPerm("get", request)) throw new ForbiddenError();
172
195
  const { runId } = request.params;
196
+ await assertRunVisible(request, runId);
173
197
  const run = await wf.get(runId);
174
198
  if (!run) throw new NotFoundError("Workflow run", runId);
175
199
  return run;
@@ -177,6 +201,7 @@ const streamlinePluginImpl = async (fastify, options) => {
177
201
  fastify.post(`${routePrefix}/runs/:runId/resume`, { preHandler: authPreHandler }, async (request, _reply) => {
178
202
  if (!await checkPerm("resume", request)) throw new ForbiddenError();
179
203
  const { runId } = request.params;
204
+ await assertRunVisible(request, runId);
180
205
  const { payload } = request.body ?? {};
181
206
  const run = await wf.resume(runId, payload);
182
207
  if (bridgeEvents && fastify.events?.publish) try {
@@ -196,6 +221,7 @@ const streamlinePluginImpl = async (fastify, options) => {
196
221
  fastify.post(`${routePrefix}/runs/:runId/cancel`, { preHandler: authPreHandler }, async (request, _reply) => {
197
222
  if (!await checkPerm("cancel", request)) throw new ForbiddenError();
198
223
  const { runId } = request.params;
224
+ await assertRunVisible(request, runId);
199
225
  const run = await wf.cancel(runId);
200
226
  if (bridgeEvents && fastify.events?.publish) try {
201
227
  await fastify.events.publish(`workflow.${id}.cancelled`, {
@@ -212,11 +238,12 @@ const streamlinePluginImpl = async (fastify, options) => {
212
238
  });
213
239
  fastify.post(`${routePrefix}/runs/:runId/execute`, { preHandler: authPreHandler }, async (request, _reply) => {
214
240
  const { runId } = request.params;
241
+ await assertRunVisible(request, runId);
215
242
  return await wf.engine.execute(runId);
216
243
  });
217
244
  const deleteRepo = wf.container?.repository;
218
- const repoDeleteFn = deleteRepo?.delete;
219
- const repoGetByIdFn = deleteRepo?.getById;
245
+ const repoDeleteFn = deleteRepo?.delete?.bind(deleteRepo);
246
+ const repoGetByIdFn = deleteRepo?.getById?.bind(deleteRepo);
220
247
  if (repoDeleteFn && repoGetByIdFn) fastify.delete(`${routePrefix}/runs/:runId`, { preHandler: authPreHandler }, async (request, reply) => {
221
248
  if (!await checkPerm("cancel", request)) throw new ForbiddenError();
222
249
  const { runId } = request.params;
@@ -235,16 +262,19 @@ const streamlinePluginImpl = async (fastify, options) => {
235
262
  if (wf.engine.waitFor) fastify.get(`${routePrefix}/runs/:runId/wait`, { preHandler: authPreHandler }, async (request, _reply) => {
236
263
  if (!await checkPerm("get", request)) throw new ForbiddenError();
237
264
  const { runId } = request.params;
265
+ await assertRunVisible(request, runId);
238
266
  const { timeout } = request.query ?? {};
239
267
  const timeoutMs = timeout ? Number.parseInt(timeout, 10) : 3e4;
240
268
  return await wf.engine.waitFor?.(runId, { timeout: Math.min(timeoutMs, 12e4) });
241
269
  });
242
270
  if (wf.engine.pause) fastify.post(`${routePrefix}/runs/:runId/pause`, { preHandler: authPreHandler }, async (request, _reply) => {
243
271
  const { runId } = request.params;
272
+ await assertRunVisible(request, runId);
244
273
  return await wf.engine.pause?.(runId);
245
274
  });
246
275
  if (wf.engine.rewindTo) fastify.post(`${routePrefix}/runs/:runId/rewind`, { preHandler: authPreHandler }, async (request, _reply) => {
247
276
  const { runId } = request.params;
277
+ await assertRunVisible(request, runId);
248
278
  const { stepId } = request.body ?? {};
249
279
  if (!stepId) throw createError(400, "stepId is required");
250
280
  return await wf.engine.rewindTo?.(runId, stepId);
@@ -266,6 +296,7 @@ const streamlinePluginImpl = async (fastify, options) => {
266
296
  if (enableStreaming && wf.container?.eventBus) fastify.get(`${routePrefix}/runs/:runId/stream`, { preHandler: authPreHandler }, async (request, reply) => {
267
297
  if (!await checkPerm("get", request)) throw new ForbiddenError();
268
298
  const { runId } = request.params;
299
+ await assertRunVisible(request, runId);
269
300
  const run = await wf.get(runId);
270
301
  if (!run) throw new NotFoundError("Workflow run", runId);
271
302
  reply.raw.writeHead(200, {
@@ -312,7 +343,7 @@ const streamlinePluginImpl = async (fastify, options) => {
312
343
  }
313
344
  }, 15e3);
314
345
  heartbeat.unref?.();
315
- for (const eventName of STREAMLINE_BUS_EVENTS) {
346
+ for (const eventName of [...STREAMLINE_BUS_EVENTS, ...STREAMLINE_STREAM_EVENTS]) {
316
347
  const fn = (payload) => {
317
348
  const p = payload;
318
349
  if (typeof p?.runId === "string" && p.runId !== runId) return;
@@ -367,4 +398,4 @@ const streamlinePlugin = fp(streamlinePluginImpl, {
367
398
  fastify: "5.x"
368
399
  });
369
400
  //#endregion
370
- export { STREAMLINE_BUS_EVENTS, STREAMLINE_FAILURE_CODES, STREAMLINE_TERMINAL_EVENTS, TERMINAL_RUN_STATUSES, streamlinePlugin };
401
+ export { STREAMLINE_BUS_EVENTS, STREAMLINE_FAILURE_CODES, STREAMLINE_STREAM_EVENTS, STREAMLINE_TERMINAL_EVENTS, TERMINAL_RUN_STATUSES, streamlinePlugin };
@@ -1,4 +1,4 @@
1
- import { c as SerializedEntry, i as Principal, n as FencedWriteOutcome, s as PushRefStore, t as EnvelopeSnapshot } from "../pushref-registry-Bq_-EVsC.mjs";
1
+ import { c as SerializedEntry, i as Principal, n as FencedWriteOutcome, s as PushRefStore, t as EnvelopeSnapshot } from "../pushref-registry-Dqclzjy7.mjs";
2
2
 
3
3
  //#region src/integrations/websocket-pushref-redis.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { f as WebSocketAdapter } from "../websocket-BZMUP7Gr.mjs";
1
+ import { f as WebSocketAdapter } from "../websocket-BFBT5rH-.mjs";
2
2
 
3
3
  //#region src/integrations/websocket-redis.d.ts
4
4
  interface RedisLike {
@@ -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-BZMUP7Gr.mjs";
2
- import { a as PushRefRegistry, c as SerializedEntry, i as Principal, o as PushRefRegistryOptions, r as MemoryPushRefStore, s as PushRefStore } from "../pushref-registry-Bq_-EVsC.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-BFBT5rH-.mjs";
2
+ import { a as PushRefRegistry, c as SerializedEntry, i as Principal, o as PushRefRegistryOptions, r as MemoryPushRefStore, s as PushRefStore } from "../pushref-registry-Dqclzjy7.mjs";
3
3
  export { AuthResult, GeoPoint, GeoPublishOpts, GeoRoom, GeoRoomOptions, LocalWebSocketAdapter, MemoryPushRefStore, Principal, PushRefRegistry, PushRefRegistryOptions, PushRefStore, RoomManager, SerializedEntry, WebSocketAdapter, WebSocketClient, WebSocketMessage, WebSocketPluginOptions, websocketPlugin };
@@ -1,4 +1,4 @@
1
- import { t as ResourceRegistry } from "./ResourceRegistry-CzSzVK1m.mjs";
1
+ import { t as ResourceRegistry } from "./ResourceRegistry-CWmOggxS.mjs";
2
2
  import { resolve } from "node:path";
3
3
  import { pathToFileURL } from "node:url";
4
4
  //#region src/cli/utils/loadResourcesFromEntry.ts
@@ -1,13 +1,13 @@
1
1
  import { p as isArcError, t as ArcError } from "./errors-j4aJm1Wg.mjs";
2
- import { t as BaseController } from "./BaseController-DPwe89qs.mjs";
3
- import { L as normalizePermissionResult } from "./permissions-B1Qy55fg.mjs";
4
- import { t as executePipeline } from "./pipe-DiCyvyPN.mjs";
5
- import { f as resolvePipelineSteps } from "./routerShared-Dl0A77Ba.mjs";
6
- import { r as validateAggregations } from "./validate-DFIP2VrM.mjs";
7
- import { n as executeAggregation } from "./buildHandler-C_SkBNF3.mjs";
8
- import { t as pluralize } from "./pluralize-B9M8xvy-.mjs";
9
- import { t as resolveActionPermission } from "./actionPermissions-Bjmvn7Eb.mjs";
10
- import { i as shouldRejectAdditionalProperties, r as schemaIRToZodShape, t as normalizeSchemaIR } from "./schemaIR-Bk6Tns82.mjs";
2
+ import { t as BaseController } from "./BaseController-B-uXzf6I.mjs";
3
+ import { N as normalizePermissionResult } from "./permissions-3uzwkbQt.mjs";
4
+ import { t as executePipeline } from "./pipe-9Tl-OAus.mjs";
5
+ import { r as resolvePipelineSteps } from "./pipeline-D4sqiokR.mjs";
6
+ import { n as validateAggregations } from "./validate-0__MuUsK.mjs";
7
+ import { n as executeAggregation } from "./buildHandler-Cvrc2p7r.mjs";
8
+ import { t as pluralize } from "./pluralize-BxdUl2P4.mjs";
9
+ import { t as resolveActionPermission } from "./actionPermissions-CX9QIMTd.mjs";
10
+ import { i as shouldRejectAdditionalProperties, r as schemaIRToZodShape, t as normalizeSchemaIR } from "./schemaIR-CE6USIRi.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";
@@ -1,4 +1,4 @@
1
- import { I as MiddlewareHandler, L as RequestWithExtras, Q as MiddlewareConfig } from "../index-C000faom.mjs";
1
+ import { I as MiddlewareHandler, L as RequestWithExtras, Q as MiddlewareConfig } from "../index-QYma8mdC.mjs";
2
2
  import { RouteHandlerMethod } from "fastify";
3
3
 
4
4
  //#region src/middleware/middleware.d.ts
@@ -1,5 +1,5 @@
1
1
  import { t as CRUD_OPERATIONS } from "../constants-TrJVIJl0.mjs";
2
- import { t as multipartBody } from "../multipartBody-VjVWmZl8.mjs";
2
+ import { t as multipartBody } from "../multipartBody-709YcXi1.mjs";
3
3
  //#region src/middleware/middleware.ts
4
4
  /**
5
5
  * Named Middleware — Priority-based, conditional middleware execution.
@@ -1,8 +1,8 @@
1
- import { t as getUserRoles } from "./types-DV9WDfeg.mjs";
2
- import { n as convertRouteSchema } from "./schemaConverter-De34B1ZG.mjs";
3
- import { t as pluralize } from "./pluralize-B9M8xvy-.mjs";
4
- import { t as resolveActionPermission } from "./actionPermissions-Bjmvn7Eb.mjs";
5
- import { t as buildActionBodySchema } from "./createActionRouter-CRaIwB5S.mjs";
1
+ import { t as getUserRoles } from "./types-D57iXYb8.mjs";
2
+ import { n as convertRouteSchema } from "./schemaConverter-DatAaVNj.mjs";
3
+ import { t as pluralize } from "./pluralize-BxdUl2P4.mjs";
4
+ import { t as resolveActionPermission } from "./actionPermissions-CX9QIMTd.mjs";
5
+ import { t as buildActionBodySchema } from "./createActionRouter-DGCCp-kP.mjs";
6
6
  import fp from "fastify-plugin";
7
7
  //#region src/docs/openapi/canonical-schemas.ts
8
8
  /**
@@ -1,3 +1,3 @@
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-DqZLp5d6.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-3L-adFJO.mjs";
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-CKLrhyOb.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-vcWUGkwf.mjs";
3
3
  export { ConnectEventsOptions, DynamicPermissionMatrix, DynamicPermissionMatrixConfig, FieldPermission, FieldPermissionMap, FieldPermissionType, PermissionCheck, PermissionContext, PermissionEventBus, PermissionResult, RequireAgentScopeOptions, RequireMandateOptions, RoleHierarchy, 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,3 +1,3 @@
1
- import { A as requireMandate, C as requireAuth, D as when, E as roles, F as applyPermissionResult, L as normalizePermissionResult, M as applyFieldWritePermissions, N as fields, O as requireAgentScope, P as resolveEffectiveRoles, 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 applyFieldReadPermissions, 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-B1Qy55fg.mjs";
2
- import { n as normalizeRoles, t as getUserRoles } from "../types-DV9WDfeg.mjs";
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-3uzwkbQt.mjs";
2
+ import { n as normalizeRoles, t as getUserRoles } from "../types-D57iXYb8.mjs";
3
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 };
@@ -1,104 +1,8 @@
1
1
  import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
2
2
  import { C as isService, S as isOrgInScope, a as getDPoPJkt, b as isElevated, d as getScopeContext, f as getScopeContextMap, g as getUserId, m as getTeamId, o as getMandate, p as getServiceScopes, u as getRequestScope, v as hasOrgAccess, x as isMember } from "./types-Bi0r0vjG.mjs";
3
- import { t as getUserRoles } from "./types-DV9WDfeg.mjs";
4
- import { t as MemoryCacheStore } from "./memory-QOLe11D5.mjs";
3
+ import { t as getUserRoles } from "./types-D57iXYb8.mjs";
4
+ import { t as MemoryCacheStore } from "./memory-TdTHCS9-.mjs";
5
5
  import { randomUUID } from "node:crypto";
6
- //#region src/permissions/applyPermissionResult.ts
7
- /**
8
- * Normalize a permission check return value (`boolean | PermissionResult`)
9
- * into a concrete `PermissionResult`. This is the only place in Arc that
10
- * promotes booleans to results — keeps the type narrowing honest everywhere.
11
- */
12
- function normalizePermissionResult(result) {
13
- if (typeof result === "boolean") return { granted: result };
14
- return result;
15
- }
16
- /**
17
- * Apply a granted `PermissionResult` to a Fastify request — merges row-level
18
- * filters into `_policyFilters` and conditionally installs the scope.
19
- *
20
- * **Scope install rule:** only writes `scope` when the current request scope
21
- * is absent or `public`. This prevents downgrading an already-authenticated
22
- * request (e.g. Better Auth set `member`, then a permission check returns a
23
- * narrower `service` scope — the original `member` wins because it came from
24
- * a more authoritative source).
25
- *
26
- * Safe to call with a non-granted result — it simply no-ops. Callers should
27
- * still check `result.granted` and send an error response before reaching here,
28
- * but this function tolerates the misuse defensively.
29
- */
30
- function applyPermissionResult(result, request) {
31
- if (!result.granted) return;
32
- if (result.filters) request._policyFilters = {
33
- ...request._policyFilters ?? {},
34
- ...result.filters
35
- };
36
- if (result.scope) {
37
- const current = request.scope;
38
- if (!current || current.kind === "public") request.scope = result.scope;
39
- }
40
- }
41
- /**
42
- * Max length of a `PermissionResult.reason` string before we fall back to the
43
- * generic default message. Upstream checks can return arbitrary strings; we
44
- * clamp to prevent accidental leakage of internal diagnostics or oversized
45
- * payloads via the 4xx response body.
46
- */
47
- const MAX_DENIAL_REASON_LENGTH = 100;
48
- /**
49
- * End-to-end evaluator: runs the permission check, catches throws, normalizes
50
- * the result, sends a 401/403 response on denial, and applies side-effects on
51
- * grant. Returns `true` if the caller should continue, `false` if a response
52
- * has been sent and the caller should return.
53
- *
54
- * This is the single source of truth for the 5-step sequence shared by the
55
- * CRUD router, action router, and MCP tool handlers:
56
- *
57
- * 1. `try { await check(ctx) } catch { reply 403 }`
58
- * 2. `normalizePermissionResult(result)`
59
- * 3. If denied → 401 (no user) or 403 (user) with clamped reason
60
- * 4. If granted → `applyPermissionResult` (filters + scope)
61
- * 5. Return true/false so the caller knows whether to keep going
62
- *
63
- * Context construction, pre-check auth gating, and success-path handler
64
- * invocation stay at the callsite — those are genuinely different per router
65
- * and don't belong here.
66
- *
67
- * @returns `true` if authorized (caller continues), `false` if a response was sent
68
- */
69
- async function evaluateAndApplyPermission(check, context, request, reply, opts) {
70
- let result;
71
- try {
72
- result = await check(context);
73
- } catch (err) {
74
- request.log?.warn?.({
75
- err,
76
- resource: context.resource,
77
- action: context.action
78
- }, "Permission check threw");
79
- reply.code(403).send({
80
- code: "arc.forbidden",
81
- message: "Permission denied",
82
- status: 403
83
- });
84
- return false;
85
- }
86
- const permResult = normalizePermissionResult(result);
87
- if (!permResult.granted) {
88
- const defaultMsg = opts?.defaultDenialMessage?.(context.user) ?? (context.user ? "Permission denied" : "Authentication required");
89
- const reason = permResult.reason && permResult.reason.length <= MAX_DENIAL_REASON_LENGTH ? permResult.reason : defaultMsg;
90
- const status = context.user ? 403 : 401;
91
- reply.code(status).send({
92
- code: context.user ? "arc.forbidden" : "arc.unauthorized",
93
- message: reason,
94
- status
95
- });
96
- return false;
97
- }
98
- applyPermissionResult(permResult, request);
99
- return true;
100
- }
101
- //#endregion
102
6
  //#region src/permissions/fields.ts
103
7
  /**
104
8
  * Field-Level Permissions
@@ -266,6 +170,102 @@ function resolveEffectiveRoles(userRoles, orgRoles) {
266
170
  return [...new Set([...userRoles, ...orgRoles])];
267
171
  }
268
172
  //#endregion
173
+ //#region src/permissions/applyPermissionResult.ts
174
+ /**
175
+ * Normalize a permission check return value (`boolean | PermissionResult`)
176
+ * into a concrete `PermissionResult`. This is the only place in Arc that
177
+ * promotes booleans to results — keeps the type narrowing honest everywhere.
178
+ */
179
+ function normalizePermissionResult(result) {
180
+ if (typeof result === "boolean") return { granted: result };
181
+ return result;
182
+ }
183
+ /**
184
+ * Apply a granted `PermissionResult` to a Fastify request — merges row-level
185
+ * filters into `_policyFilters` and conditionally installs the scope.
186
+ *
187
+ * **Scope install rule:** only writes `scope` when the current request scope
188
+ * is absent or `public`. This prevents downgrading an already-authenticated
189
+ * request (e.g. Better Auth set `member`, then a permission check returns a
190
+ * narrower `service` scope — the original `member` wins because it came from
191
+ * a more authoritative source).
192
+ *
193
+ * Safe to call with a non-granted result — it simply no-ops. Callers should
194
+ * still check `result.granted` and send an error response before reaching here,
195
+ * but this function tolerates the misuse defensively.
196
+ */
197
+ function applyPermissionResult(result, request) {
198
+ if (!result.granted) return;
199
+ if (result.filters) request._policyFilters = {
200
+ ...request._policyFilters ?? {},
201
+ ...result.filters
202
+ };
203
+ if (result.scope) {
204
+ const current = request.scope;
205
+ if (!current || current.kind === "public") request.scope = result.scope;
206
+ }
207
+ }
208
+ /**
209
+ * Max length of a `PermissionResult.reason` string before we fall back to the
210
+ * generic default message. Upstream checks can return arbitrary strings; we
211
+ * clamp to prevent accidental leakage of internal diagnostics or oversized
212
+ * payloads via the 4xx response body.
213
+ */
214
+ const MAX_DENIAL_REASON_LENGTH = 100;
215
+ /**
216
+ * End-to-end evaluator: runs the permission check, catches throws, normalizes
217
+ * the result, sends a 401/403 response on denial, and applies side-effects on
218
+ * grant. Returns `true` if the caller should continue, `false` if a response
219
+ * has been sent and the caller should return.
220
+ *
221
+ * This is the single source of truth for the 5-step sequence shared by the
222
+ * CRUD router, action router, and MCP tool handlers:
223
+ *
224
+ * 1. `try { await check(ctx) } catch { reply 403 }`
225
+ * 2. `normalizePermissionResult(result)`
226
+ * 3. If denied → 401 (no user) or 403 (user) with clamped reason
227
+ * 4. If granted → `applyPermissionResult` (filters + scope)
228
+ * 5. Return true/false so the caller knows whether to keep going
229
+ *
230
+ * Context construction, pre-check auth gating, and success-path handler
231
+ * invocation stay at the callsite — those are genuinely different per router
232
+ * and don't belong here.
233
+ *
234
+ * @returns `true` if authorized (caller continues), `false` if a response was sent
235
+ */
236
+ async function evaluateAndApplyPermission(check, context, request, reply, opts) {
237
+ let result;
238
+ try {
239
+ result = await check(context);
240
+ } catch (err) {
241
+ request.log?.warn?.({
242
+ err,
243
+ resource: context.resource,
244
+ action: context.action
245
+ }, "Permission check threw");
246
+ reply.code(403).send({
247
+ code: "arc.forbidden",
248
+ message: "Permission denied",
249
+ status: 403
250
+ });
251
+ return false;
252
+ }
253
+ const permResult = normalizePermissionResult(result);
254
+ if (!permResult.granted) {
255
+ const defaultMsg = opts?.defaultDenialMessage?.(context.user) ?? (context.user ? "Permission denied" : "Authentication required");
256
+ const reason = permResult.reason && permResult.reason.length <= MAX_DENIAL_REASON_LENGTH ? permResult.reason : defaultMsg;
257
+ const status = context.user ? 403 : 401;
258
+ reply.code(status).send({
259
+ code: context.user ? "arc.forbidden" : "arc.unauthorized",
260
+ message: reason,
261
+ status
262
+ });
263
+ return false;
264
+ }
265
+ applyPermissionResult(permResult, request);
266
+ return true;
267
+ }
268
+ //#endregion
269
269
  //#region src/permissions/agent.ts
270
270
  /**
271
271
  * Agent-Auth Permission Helpers — DPoP + capability mandates for AI-agent flows
@@ -1490,4 +1490,4 @@ function readOnly(overrides) {
1490
1490
  }, overrides);
1491
1491
  }
1492
1492
  //#endregion
1493
- export { requireMandate as A, requireAuth as C, when as D, roles as E, applyPermissionResult as F, evaluateAndApplyPermission as I, normalizePermissionResult as L, applyFieldWritePermissions as M, fields as N, requireAgentScope as O, resolveEffectiveRoles 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, applyFieldReadPermissions 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 };
1493
+ 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 };
@@ -1,4 +1,4 @@
1
- import { Ft as OperationFilter, It as PipelineConfig, Lt as PipelineContext, Mt as Guard, Nt as Interceptor, Pt as NextFunction, Rt as PipelineStep, yt as IControllerResponse, zt as Transform } from "../index-C000faom.mjs";
1
+ import { Ft as OperationFilter, It as PipelineConfig, Lt as PipelineContext, Mt as Guard, Nt as Interceptor, Pt as NextFunction, Rt as PipelineStep, yt as IControllerResponse, zt as Transform } from "../index-QYma8mdC.mjs";
2
2
 
3
3
  //#region src/pipeline/guard.d.ts
4
4
  interface GuardOptions {
@@ -1,4 +1,4 @@
1
- import { n as pipe, t as executePipeline } from "../pipe-DiCyvyPN.mjs";
1
+ import { n as pipe, t as executePipeline } from "../pipe-9Tl-OAus.mjs";
2
2
  //#region src/pipeline/guard.ts
3
3
  /**
4
4
  * Create a named guard.