@classytic/arc 2.18.4 → 2.18.5

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 (158) hide show
  1. package/dist/{BaseController-B-uXzf6I.mjs → BaseController-Dy6EQHjM.mjs} +7 -7
  2. package/dist/{QueryCache-Dsyv2mLS.d.mts → QueryCache-TRfXau3W.d.mts} +1 -1
  3. package/dist/{ResourceRegistry-CWmOggxS.mjs → ResourceRegistry-5fKZwhK_.mjs} +1 -1
  4. package/dist/{pipeline-D4sqiokR.mjs → actionPermissions-h7DYDNMg.mjs} +28 -5
  5. package/dist/audit/index.d.mts +1 -1
  6. package/dist/auth/index.d.mts +4 -4
  7. package/dist/auth/index.mjs +252 -5
  8. package/dist/auth/redis-session.d.mts +1 -1
  9. package/dist/betterAuthOpenApi-CV1lxpRX.mjs +2 -0
  10. package/dist/{buildHandler-Cvrc2p7r.mjs → buildHandler-B0qvAguf.mjs} +1 -1
  11. package/dist/cache/index.d.mts +3 -3
  12. package/dist/cache/index.mjs +3 -3
  13. package/dist/{caching-C0DdKiYB.mjs → caching-_NJeDd1_.mjs} +1 -1
  14. package/dist/cli/commands/describe.d.mts +1 -1
  15. package/dist/cli/commands/describe.mjs +2 -2
  16. package/dist/cli/commands/docs.mjs +2 -2
  17. package/dist/cli/commands/generate.d.mts +2 -2
  18. package/dist/cli/commands/generate.mjs +1 -1
  19. package/dist/cli/commands/init.d.mts +2 -2
  20. package/dist/cli/commands/init.mjs +1 -1
  21. package/dist/cli/commands/introspect.mjs +1 -1
  22. package/dist/cli/index.d.mts +2 -2
  23. package/dist/cli/index.mjs +2 -2
  24. package/dist/context/index.mjs +1 -1
  25. package/dist/core/index.d.mts +3 -3
  26. package/dist/core/index.mjs +4 -4
  27. package/dist/{core-C88uIwd3.mjs → core-ZnQBa5rh.mjs} +55 -56
  28. package/dist/{createActionRouter-DGCCp-kP.mjs → createActionRouter-CagItpxI.mjs} +6 -7
  29. package/dist/{createAggregationRouter-Ca77b8iK.mjs → createAggregationRouter-DVKroXhC.mjs} +4 -4
  30. package/dist/{createApp-J1iPXY9p.mjs → createApp--703hQE1.mjs} +14 -14
  31. package/dist/docs/index.d.mts +2 -2
  32. package/dist/docs/index.mjs +2 -2
  33. package/dist/{elevation-BzhyVWfn.mjs → elevation-COpYKt2h.mjs} +2 -2
  34. package/dist/{errorHandler-Bua97SEt.mjs → errorHandler-Dxf6P_kV.mjs} +2 -2
  35. package/dist/{eventPlugin-Bw4bUDEO.mjs → eventPlugin-DJG2D7sy.mjs} +106 -5
  36. package/dist/{eventPlugin-C1W1CRbf.d.mts → eventPlugin-DbBFd3x_.d.mts} +1 -1
  37. package/dist/events/index.d.mts +3 -3
  38. package/dist/events/index.mjs +189 -5
  39. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  40. package/dist/events/transports/redis.d.mts +1 -1
  41. package/dist/factory/index.d.mts +1 -1
  42. package/dist/factory/index.mjs +3 -3
  43. package/dist/{fastify-augmentation-BdCl_eNo.d.mts → fastify-augmentation-Cxb0ROIw.d.mts} +2 -2
  44. package/dist/{fields-CKLrhyOb.d.mts → fields-C7ahdGYf.d.mts} +1 -1
  45. package/dist/{generate-BaxDdmJ8.mjs → generate-Brans3fW.mjs} +1 -1
  46. package/dist/hooks/index.d.mts +1 -1
  47. package/dist/hooks/index.mjs +1 -1
  48. package/dist/idempotency/index.d.mts +2 -2
  49. package/dist/idempotency/index.mjs +1 -1
  50. package/dist/idempotency/redis.d.mts +1 -1
  51. package/dist/{index-QYma8mdC.d.mts → index-CHNQIhcb.d.mts} +5 -6
  52. package/dist/{index-vcWUGkwf.d.mts → index-CRKiiP5o.d.mts} +3 -3
  53. package/dist/{index-Cvo1u9n6.d.mts → index-Dh0_RSTd.d.mts} +3 -3
  54. package/dist/index.d.mts +5 -5
  55. package/dist/index.mjs +7 -7
  56. package/dist/{init-DSsdRfk9.mjs → init-Bqpt1Hxf.mjs} +274 -130
  57. package/dist/integrations/event-gateway.d.mts +2 -2
  58. package/dist/integrations/event-gateway.mjs +1 -1
  59. package/dist/integrations/index.d.mts +3 -3
  60. package/dist/integrations/mcp/index.d.mts +4 -4
  61. package/dist/integrations/mcp/index.mjs +1 -1
  62. package/dist/integrations/mcp/testing.d.mts +1 -1
  63. package/dist/integrations/mcp/testing.mjs +1 -1
  64. package/dist/integrations/streamline.mjs +7 -3
  65. package/dist/integrations/websocket-pushref-redis.d.mts +1 -1
  66. package/dist/integrations/websocket-redis.d.mts +1 -1
  67. package/dist/integrations/websocket.d.mts +3 -3
  68. package/dist/{loadResources-CwXt9MCh.mjs → loadResources-B8UmpITt.mjs} +1 -1
  69. package/dist/{loadResourcesFromEntry-XHNeUWpu.mjs → loadResourcesFromEntry-BTlFEx05.mjs} +1 -1
  70. package/dist/{mcpPlugin-CzKdt3B8.mjs → mcpPlugin-D1wuRD2c.mjs} +10 -11
  71. package/dist/{memory-TdTHCS9-.mjs → memory-CLXA2VeJ.mjs} +1 -1
  72. package/dist/{metrics-Da2EUPi9.mjs → metrics-fdxI5mn_.mjs} +1 -1
  73. package/dist/middleware/index.d.mts +1 -1
  74. package/dist/middleware/index.mjs +2 -2
  75. package/dist/{openapi-ButnRyOM.mjs → openapi-xVJibapr.mjs} +5 -5
  76. package/dist/permissions/index.d.mts +3 -3
  77. package/dist/permissions/index.mjs +2 -2
  78. package/dist/{permissions-3uzwkbQt.mjs → permissions-BPB1xqGf.mjs} +4 -4
  79. package/dist/{pipe-9Tl-OAus.mjs → pipe-BOLmGIxa.mjs} +1 -1
  80. package/dist/pipeline/index.d.mts +1 -1
  81. package/dist/pipeline/index.mjs +1 -1
  82. package/dist/plugins/index.d.mts +6 -7
  83. package/dist/plugins/index.mjs +12 -12
  84. package/dist/plugins/response-cache.mjs +1 -1
  85. package/dist/plugins/tracing-entry.d.mts +1 -1
  86. package/dist/plugins/tracing-entry.mjs +1 -1
  87. package/dist/presets/filesUpload.d.mts +4 -4
  88. package/dist/presets/filesUpload.mjs +4 -4
  89. package/dist/presets/index.d.mts +1 -1
  90. package/dist/presets/index.mjs +1 -1
  91. package/dist/presets/multiTenant.d.mts +1 -1
  92. package/dist/presets/multiTenant.mjs +2 -2
  93. package/dist/presets/search.d.mts +2 -2
  94. package/dist/presets/search.mjs +1 -1
  95. package/dist/{presets-CF79RHEo.mjs → presets-BtyFwTO4.mjs} +2 -2
  96. package/dist/{queryCachePlugin-CnAeFqju.mjs → queryCachePlugin-emHb0CuX.mjs} +4 -4
  97. package/dist/{queryCachePlugin-Bd2tYgh5.d.mts → queryCachePlugin-xzFyKAjT.d.mts} +2 -2
  98. package/dist/{redis-3hqH_Qk_.d.mts → redis-C3W0qbz8.d.mts} +1 -1
  99. package/dist/{redis-stream-BtEUtjxZ.d.mts → redis-stream-DsP1vqZB.d.mts} +1 -1
  100. package/dist/{rateLimit-yKvxWAky.mjs → registerRoute-CPmdkZGu.mjs} +109 -2
  101. package/dist/registry/index.d.mts +1 -1
  102. package/dist/registry/index.mjs +2 -2
  103. package/dist/{registry-Br15xdGM.mjs → registry-Bm9LjWKs.mjs} +1 -1
  104. package/dist/{replyHelpers-DXHVxrrj.mjs → replyHelpers-67tRawQZ.mjs} +1 -1
  105. package/dist/{schemaIR-CE6USIRi.mjs → schemaIR-D1MJwqmp.mjs} +1 -1
  106. package/dist/schemas/index.d.mts +64 -65
  107. package/dist/scope/index.d.mts +2 -2
  108. package/dist/scope/index.mjs +3 -3
  109. package/dist/{sse-BrY1W6U8.mjs → sse-CfUjwjDk.mjs} +7 -4
  110. package/dist/streaming-BQcW6_Kq.mjs +162 -0
  111. package/dist/testing/index.d.mts +7 -7
  112. package/dist/testing/index.mjs +3 -3
  113. package/dist/testing/storageContract.d.mts +1 -1
  114. package/dist/types/index.d.mts +5 -5
  115. package/dist/types/storage.d.mts +1 -1
  116. package/dist/{types-WVlAVp8T.d.mts → types-CmkknLzI.d.mts} +10 -10
  117. package/dist/{types-BWBcb88c.d.mts → types-D60PFwfG.d.mts} +1 -1
  118. package/dist/{types-Bi0r0vjG.mjs → types-bHblZ9YN.mjs} +1 -1
  119. package/dist/utils/index.d.mts +42 -4
  120. package/dist/utils/index.mjs +6 -5
  121. package/dist/{utils-xAQeDyU_.mjs → utils-C6QQ9-hd.mjs} +1415 -1524
  122. package/dist/{validate-0__MuUsK.mjs → validate-CRcaWzp2.mjs} +1 -1
  123. package/dist/{versioning-BSEDGXKC.d.mts → versioning-D_eBCfNr.d.mts} +8 -1
  124. package/dist/{versioning-C0K8KQLx.mjs → versioning-Dk-71iIz.mjs} +1 -1
  125. package/dist/{websocket-BFBT5rH-.d.mts → websocket-MlYlrYq0.d.mts} +1 -1
  126. package/package.json +36 -30
  127. package/dist/EventTransport-7LPXLEUX.mjs +0 -103
  128. package/dist/actionPermissions-CX9QIMTd.mjs +0 -24
  129. package/dist/betterAuthOpenApi-DAAhMZff.mjs +0 -251
  130. package/dist/defineEvent-DC981g-o.mjs +0 -188
  131. package/dist/registerRoute-BEYn0ylk.mjs +0 -108
  132. /package/dist/{EventTransport-CaaXM5Y1.d.mts → EventTransport-IEn7Tn-Q.d.mts} +0 -0
  133. /package/dist/{HookSystem-BfCpWbwM.mjs → HookSystem-C1vB_Gc9.mjs} +0 -0
  134. /package/dist/{constants-TrJVIJl0.mjs → constants-gaEeMlz-.mjs} +0 -0
  135. /package/dist/{elevation-DW90z5bT.d.mts → elevation-xGUBq6p_.d.mts} +0 -0
  136. /package/dist/{errorHandler-_Lp2k9M3.d.mts → errorHandler-BtUUDPEa.d.mts} +0 -0
  137. /package/dist/{errors-DZOemeGa.d.mts → errors-DOHkjQlD.d.mts} +0 -0
  138. /package/dist/{errors-j4aJm1Wg.mjs → errors-DkO8Nk6-.mjs} +0 -0
  139. /package/dist/{externalPaths-DLle0R07.d.mts → externalPaths-BE6wFpYv.d.mts} +0 -0
  140. /package/dist/{generate-Dmk8cfvX.d.mts → generate-BnsL9GBm.d.mts} +0 -0
  141. /package/dist/{init-BS4Daqnv.d.mts → init-BPEu8cs-.d.mts} +0 -0
  142. /package/dist/{interface-DL7LlWS5.d.mts → interface-C1_WLTMK.d.mts} +0 -0
  143. /package/dist/{interface-CsrGR8LF.d.mts → interface-Uk8ONJv7.d.mts} +0 -0
  144. /package/dist/{keys-B3yyBEyH.mjs → keys-Cd316u_y.mjs} +0 -0
  145. /package/dist/{multipartBody-709YcXi1.mjs → multipartBody-CHEQSZ6G.mjs} +0 -0
  146. /package/dist/{pluralize-BxdUl2P4.mjs → pluralize-DccFV9R7.mjs} +0 -0
  147. /package/dist/{preloadResources-B-j-iqo-.mjs → preloadResources-CHw3_oA_.mjs} +0 -0
  148. /package/dist/{pushref-registry-Dqclzjy7.d.mts → pushref-registry-DnCqL3aa.d.mts} +0 -0
  149. /package/dist/{requestContext-DDLS3NVU.mjs → requestContext-BZKOr13H.mjs} +0 -0
  150. /package/dist/{chunk-BpYLSNr0.mjs → rolldown-runtime-8H4AJuhK.mjs} +0 -0
  151. /package/dist/{schemaConverter-DatAaVNj.mjs → schemaConverter-U0MnO9vd.mjs} +0 -0
  152. /package/dist/{sessionManager-CyHpYXoB.d.mts → sessionManager-BXG-HGwG.d.mts} +0 -0
  153. /package/dist/{storage-C5q8fuEt.d.mts → storage-Co_PQpeQ.d.mts} +0 -0
  154. /package/dist/{store-helpers-DjSYI2uP.mjs → store-helpers-DY6xq4sM.mjs} +0 -0
  155. /package/dist/{tracing-Bnb1-YVd.d.mts → tracing-D8jlGXP7.d.mts} +0 -0
  156. /package/dist/{typeGuards-CcFZXgU7.mjs → typeGuards-C9KXUly6.mjs} +0 -0
  157. /package/dist/{types-BJwJN2Pg.d.mts → types-LNebCoJx.d.mts} +0 -0
  158. /package/dist/{types-D57iXYb8.mjs → types-XTApa8b6.mjs} +0 -0
@@ -1,4 +1,4 @@
1
- import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
1
+ import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.mjs";
2
2
  //#region src/core/aggregation/normalize.ts
3
3
  /**
4
4
  * Framework cap on URL-driven aggregation limits when the host opts
@@ -1,4 +1,4 @@
1
- import { n as DomainEvent } from "./EventTransport-CaaXM5Y1.mjs";
1
+ import { n as DomainEvent } from "./EventTransport-IEn7Tn-Q.mjs";
2
2
  import { FastifyPluginAsync, FastifyRequest } from "fastify";
3
3
 
4
4
  //#region src/plugins/health.d.ts
@@ -76,6 +76,13 @@ interface SSEOptions {
76
76
  orgScoped?: boolean;
77
77
  /** Custom event filter function */
78
78
  filter?: (event: DomainEvent<unknown>, request: FastifyRequest) => boolean;
79
+ /**
80
+ * Query parameter that carries the bearer token for browser `EventSource`
81
+ * clients (which cannot send an `Authorization` header). Promoted into the
82
+ * header before auth. Default `'token'` — matches arc-next's `buildStreamUrl`.
83
+ * Set `null` to disable promotion (e.g. cookie-only auth).
84
+ */
85
+ tokenQueryParam?: string | null;
79
86
  }
80
87
  declare const ssePlugin: FastifyPluginAsync<SSEOptions>;
81
88
  declare const _default$2: FastifyPluginAsync<SSEOptions>;
@@ -1,4 +1,4 @@
1
- import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
1
+ import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.mjs";
2
2
  import fp from "fastify-plugin";
3
3
  //#region src/plugins/versioning.ts
4
4
  var versioning_exports = /* @__PURE__ */ __exportAll({
@@ -1,4 +1,4 @@
1
- import { a as PushRefRegistry, l as EnvelopeWriter, s as PushRefStore } from "./pushref-registry-Dqclzjy7.mjs";
1
+ import { a as PushRefRegistry, l as EnvelopeWriter, s as PushRefStore } from "./pushref-registry-DnCqL3aa.mjs";
2
2
  import { FastifyBaseLogger, FastifyPluginAsync } from "fastify";
3
3
 
4
4
  //#region src/integrations/websocket/adapter.d.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@classytic/arc",
3
- "version": "2.18.4",
3
+ "version": "2.18.5",
4
4
  "description": "Resource-oriented backend framework for Fastify - clean, minimal, powerful, tree-shakable",
5
5
  "type": "module",
6
6
  "exports": {
@@ -224,6 +224,7 @@
224
224
  "lint:all": "biome check src/ tests/",
225
225
  "test": "vitest run",
226
226
  "test:main": "vitest run --no-file-parallelism",
227
+ "test:fast": "vitest run --exclude \"**/tests/integrations/websocket/**\" && vitest run tests/integrations/websocket/ --no-file-parallelism",
227
228
  "test:perf": "node --expose-gc ./node_modules/vitest/vitest.mjs run --config vitest.perf.config.ts --no-file-parallelism",
228
229
  "test:ci": "npm run test:main && npm run test:perf",
229
230
  "test:watch": "vitest",
@@ -350,56 +351,61 @@
350
351
  }
351
352
  },
352
353
  "dependencies": {
353
- "fastify-plugin": "^5.0.1",
354
+ "fastify-plugin": "^6.0.0",
354
355
  "qs": "^6.15.2",
355
356
  "secure-json-parse": "^4.1.0"
356
357
  },
357
358
  "devDependencies": {
358
- "@better-auth/drizzle-adapter": "^1.6.9",
359
- "@better-auth/mongo-adapter": "^1.6.9",
360
- "@biomejs/biome": "^2.4.15",
359
+ "@better-auth/drizzle-adapter": "^1.6.19",
360
+ "@better-auth/mongo-adapter": "^1.6.19",
361
+ "@biomejs/biome": "^2.5.0",
361
362
  "@classytic/dev-tools": "^0.2.0",
362
- "@classytic/mongokit": "^3.16.0",
363
- "@classytic/primitives": "^0.6.0",
363
+ "@classytic/mongokit": "^3.16.1",
364
+ "@classytic/primitives": "^0.7.2",
364
365
  "@classytic/repo-core": "^0.6.0",
365
366
  "@classytic/sqlitekit": "^0.6.0",
366
- "@classytic/streamline": "^2.3.3",
367
+ "@classytic/streamline": "^2.6.0",
367
368
  "@fastify/cors": "^11.2.0",
368
369
  "@fastify/helmet": "^13.0.2",
369
- "@fastify/jwt": "^10.0.0",
370
+ "@fastify/jwt": "^10.1.0",
370
371
  "@fastify/multipart": "^10.0.0",
371
- "@fastify/rate-limit": "^10.3.0",
372
+ "@fastify/rate-limit": "^11.0.0",
372
373
  "@fastify/sensible": "^6.0.4",
373
- "@fastify/type-provider-typebox": "^6.0.0",
374
+ "@fastify/type-provider-typebox": "^6.1.0",
374
375
  "@fastify/under-pressure": "^9.0.3",
375
- "@fastify/websocket": "^11.0.0",
376
+ "@fastify/websocket": "^11.2.0",
376
377
  "@modelcontextprotocol/sdk": "^1.29.0",
377
378
  "@opentelemetry/api": "^1.9.1",
378
- "@sinclair/typebox": "^0.34.0",
379
- "@types/node": "^22.19.19",
379
+ "@sinclair/typebox": "^0.34.49",
380
+ "@types/node": "^22.19.21",
380
381
  "@types/qs": "^6.15.1",
381
- "@vitest/coverage-v8": "^3.2.4",
382
- "ajv": "^8.18.0",
383
- "better-auth": "^1.6.9",
384
- "better-sqlite3": "^12.10.0",
385
- "bullmq": "^5.76.9",
382
+ "@vitest/coverage-v8": "^4.1.9",
383
+ "ajv": "^8.20.0",
384
+ "better-auth": "^1.6.19",
385
+ "better-sqlite3": "^12.11.1",
386
+ "bullmq": "^5.79.0",
386
387
  "dotenv": "^17.4.2",
387
388
  "drizzle-orm": "^0.45.2",
388
389
  "fast-check": "^4.8.0",
389
390
  "fastify": "^5.8.5",
390
391
  "fastify-raw-body": "^5.0.0",
391
392
  "h3-js": "^4.4.0",
392
- "ioredis": "^5.10.1",
393
- "jsonwebtoken": "^9.0.0",
394
- "knip": "^6.14.1",
395
- "mongodb": "^7.1.0",
396
- "mongodb-memory-server": "^11.0.1",
397
- "mongoose": "^9.6.2",
398
- "tsdown": "^0.21.7",
399
- "typescript": "^6.0.2",
400
- "vitest": "^3.0.0",
401
- "ws": "^8.20.1",
402
- "zod": "^4.3.6"
393
+ "ioredis": "^5.11.1",
394
+ "jsonwebtoken": "^9.0.3",
395
+ "knip": "^6.17.1",
396
+ "mongodb": "^7.3.0",
397
+ "mongodb-memory-server": "^11.2.0",
398
+ "mongoose": "^9.7.1",
399
+ "tsdown": "^0.22.3",
400
+ "typescript": "^6.0.3",
401
+ "vitest": "^4.1.9",
402
+ "ws": "^8.21.0",
403
+ "zod": "^4.4.3"
404
+ },
405
+ "config": {
406
+ "mongodbMemoryServer": {
407
+ "disablePostinstall": "1"
408
+ }
403
409
  },
404
410
  "keywords": [
405
411
  "fastify",
@@ -1,103 +0,0 @@
1
- import { createEvent, matchEventPattern } from "@classytic/primitives/events";
2
- //#region src/events/EventTransport.ts
3
- /**
4
- * Internal arc events module — concrete in-memory transport.
5
- *
6
- * **Public type contracts moved out (arc 2.12).** `EventMeta`, `DomainEvent`,
7
- * `EventHandler`, `EventLogger`, `EventTransport`, `DeadLetteredEvent`,
8
- * `PublishManyResult`, plus the `createEvent` / `createChildEvent` /
9
- * `matchEventPattern` helpers, are now owned by `@classytic/primitives/events`.
10
- * Two reasons:
11
- *
12
- * 1. The shapes ARE the cross-package contract. arc, arc-next, mongokit's
13
- * audit-log plugin, future kits and downstream services all share them.
14
- * Owning them in `primitives` (pure types, zero runtime, zero deps)
15
- * eliminates the "manually mirror in two places" problem the previous
16
- * `primitives/src/events.ts` header explicitly called out.
17
- * 2. Inverting the dependency direction lets future packages (sqlitekit
18
- * audit, billing services) consume the contract without depending on
19
- * arc's HTTP-coupled stack.
20
- *
21
- * Hosts MUST import the types from primitives directly:
22
- *
23
- * ```typescript
24
- * import type {
25
- * EventMeta, DomainEvent, EventHandler, EventTransport,
26
- * DeadLetteredEvent, PublishManyResult,
27
- * } from '@classytic/primitives/events';
28
- * import { createEvent, createChildEvent } from '@classytic/primitives/events';
29
- * ```
30
- *
31
- * arc's `events/index.ts` barrel does NOT re-export these — by design, so
32
- * that consumer code is forced into the canonical import path and the org's
33
- * "no re-exports" rule holds at every public surface.
34
- *
35
- * What stays here:
36
- * - `MemoryEventTransport` — the in-memory `EventTransport` implementation
37
- * used as arc's default transport. Its handler-set state is process-local;
38
- * wrong layer for primitives.
39
- * - `MemoryEventTransportOptions` — its options shape.
40
- *
41
- * Inside arc, files that previously imported types from `./EventTransport.js`
42
- * keep working: this file re-exports them from primitives for arc's own
43
- * call sites. That re-export is an internal refactor convenience — the
44
- * public `events/index.ts` barrel stays clean.
45
- */
46
- /**
47
- * In-memory event transport (default).
48
- *
49
- * Events are delivered synchronously within the process. Not suitable for
50
- * multi-instance deployments — pair with `RedisEventTransport` /
51
- * `RedisStreamTransport` (subpath imports) for those.
52
- */
53
- var MemoryEventTransport = class {
54
- name = "memory";
55
- handlers = /* @__PURE__ */ new Map();
56
- logger;
57
- constructor(options) {
58
- this.logger = options?.logger ?? console;
59
- }
60
- async publish(event) {
61
- const allHandlers = /* @__PURE__ */ new Set();
62
- for (const [pattern, handlers] of this.handlers) if (matchEventPattern(pattern, event.type)) for (const h of handlers) allHandlers.add(h);
63
- for (const handler of allHandlers) try {
64
- await handler(event);
65
- } catch (err) {
66
- this.logger.error(`[EventTransport] Handler error for ${event.type}:`, err);
67
- }
68
- }
69
- /**
70
- * Reference `publishMany` implementation — delegates to `publish()` in order.
71
- *
72
- * Production transports (Kafka, Redis pipeline, SQS batch) should override
73
- * this with a single batched network call. Memory transport has nothing to
74
- * batch, so we just loop — the loop still returns a proper result map so
75
- * `EventOutbox.relay` can exercise the batched code path in tests.
76
- */
77
- async publishMany(events) {
78
- const results = /* @__PURE__ */ new Map();
79
- for (const event of events) try {
80
- await this.publish(event);
81
- results.set(event.meta.id, null);
82
- } catch (err) {
83
- results.set(event.meta.id, err instanceof Error ? err : new Error(String(err)));
84
- }
85
- return results;
86
- }
87
- async subscribe(pattern, handler) {
88
- if (!this.handlers.has(pattern)) this.handlers.set(pattern, /* @__PURE__ */ new Set());
89
- this.handlers.get(pattern)?.add(handler);
90
- return () => {
91
- const set = this.handlers.get(pattern);
92
- if (set) {
93
- set.delete(handler);
94
- if (set.size === 0) this.handlers.delete(pattern);
95
- }
96
- };
97
- }
98
- async close() {
99
- this.handlers.clear();
100
- }
101
- };
102
- //#endregion
103
- export { createEvent as n, MemoryEventTransport as t };
@@ -1,24 +0,0 @@
1
- //#region src/core/actionPermissions.ts
2
- /**
3
- * Return the effective `PermissionCheck` for a single action, or `undefined`
4
- * when the resource declares no gate at any level.
5
- *
6
- * Callers decide what "no gate" means:
7
- * - HTTP: boot-time throw in `normalizeActionsToRouterConfig`.
8
- * - MCP: tool-generation throw in `resourceToTools` (mirrors HTTP — the
9
- * two surfaces fail closed identically so MCP can't expose an
10
- * unauthenticated mutating tool when the HTTP plugin lifecycle hasn't
11
- * run).
12
- * - OpenAPI: docs advertise the endpoint as unauthenticated.
13
- */
14
- function resolveActionPermission(input) {
15
- const { action, resourcePermissions, resourceActionPermissions, globalAuth } = input;
16
- const explicit = typeof action !== "function" && action.permissions ? action.permissions : void 0;
17
- if (explicit) return explicit;
18
- if (resourceActionPermissions) return resourceActionPermissions;
19
- if (globalAuth) return globalAuth;
20
- const updateFallback = resourcePermissions?.update;
21
- if (updateFallback) return updateFallback;
22
- }
23
- //#endregion
24
- export { resolveActionPermission as t };
@@ -1,251 +0,0 @@
1
- import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
2
- import { a as toJsonSchema } from "./schemaConverter-DatAaVNj.mjs";
3
- //#region src/auth/betterAuthOpenApi.ts
4
- var betterAuthOpenApi_exports = /* @__PURE__ */ __exportAll({ extractBetterAuthOpenApi: () => extractBetterAuthOpenApi });
5
- /**
6
- * Check if a value looks like a Better Auth endpoint (has .path and .options)
7
- */
8
- function isBetterAuthEndpoint(value) {
9
- if (typeof value !== "function" && typeof value !== "object") return false;
10
- if (!value) return false;
11
- const v = value;
12
- return typeof v.path === "string" && typeof v.options === "object" && v.options !== null;
13
- }
14
- /**
15
- * Convert Fastify-style path params (/:id) to OpenAPI-style (/{id})
16
- */
17
- function toOpenApiPath(path) {
18
- return path.replace(/:([^/]+)/g, "{$1}");
19
- }
20
- /**
21
- * Extract path parameters from a path string
22
- */
23
- function extractPathParams(path) {
24
- const params = [];
25
- const matches = path.matchAll(/:(\w+)/g);
26
- for (const match of matches) {
27
- const name = match[1];
28
- if (!name) continue;
29
- params.push({
30
- name,
31
- in: "path",
32
- required: true,
33
- schema: { type: "string" }
34
- });
35
- }
36
- return params;
37
- }
38
- /**
39
- * Extract OpenAPI paths from a Better Auth instance's API object.
40
- *
41
- * Walks `authApi` (the `auth.api` object from Better Auth), discovers
42
- * endpoints, converts their Zod schemas to JSON Schema via `z.toJSONSchema()`,
43
- * and returns a complete `ExternalOpenApiPaths` object ready for Arc's spec builder.
44
- */
45
- function extractBetterAuthOpenApi(authApi, options = {}) {
46
- const { basePath = "/api/auth", tagName = "Authentication", tagDescription = "Better Auth authentication endpoints", excludePaths = [], excludeServerOnly = true, userFields } = options;
47
- const normalizedBase = basePath.replace(/\/+$/, "");
48
- const paths = {};
49
- const detectedPlugins = detectActivePlugins(authApi);
50
- const securityOptions = [{ cookieAuth: [] }, { bearerAuth: [] }];
51
- if (detectedPlugins.apiKey) securityOptions.push({ apiKeyAuth: [] });
52
- for (const [key, value] of Object.entries(authApi)) {
53
- if (!isBetterAuthEndpoint(value)) continue;
54
- const { path: endpointPath, options: endpointOpts } = value;
55
- if (excludePaths.includes(endpointPath)) continue;
56
- if (excludeServerOnly && endpointOpts.metadata?.SERVER_ONLY) continue;
57
- const fullPath = toOpenApiPath(`${normalizedBase}${endpointPath}`);
58
- const methods = [];
59
- if (endpointOpts.method) if (Array.isArray(endpointOpts.method)) methods.push(...endpointOpts.method.map((m) => m.toLowerCase()));
60
- else methods.push(endpointOpts.method.toLowerCase());
61
- else methods.push(endpointOpts.body ? "post" : "get");
62
- const openApiMeta = endpointOpts.metadata?.openapi;
63
- for (const method of methods) {
64
- const operation = {
65
- tags: openApiMeta?.tags ?? [tagName],
66
- operationId: openApiMeta?.operationId ?? key,
67
- summary: openApiMeta?.summary ?? formatOperationSummary(key),
68
- security: securityOptions
69
- };
70
- if (openApiMeta?.description) operation.description = openApiMeta.description;
71
- const parameters = [...extractPathParams(endpointPath)];
72
- if ((method === "get" || method === "delete") && endpointOpts.query) {
73
- const querySchema = toJsonSchema(endpointOpts.query);
74
- if (querySchema && querySchema.type === "object" && querySchema.properties) {
75
- const props = querySchema.properties;
76
- const required = querySchema.required ?? [];
77
- for (const [name, prop] of Object.entries(props)) {
78
- const paramEntry = {
79
- name,
80
- in: "query",
81
- required: required.includes(name),
82
- schema: prop
83
- };
84
- if (prop.description) paramEntry.description = prop.description;
85
- parameters.push(paramEntry);
86
- }
87
- }
88
- }
89
- if (parameters.length > 0) operation.parameters = parameters;
90
- if (method === "post" || method === "put" || method === "patch") {
91
- if (openApiMeta?.requestBody) operation.requestBody = structuredClone(openApiMeta.requestBody);
92
- else if (endpointOpts.body) {
93
- const bodySchema = toJsonSchema(endpointOpts.body);
94
- if (bodySchema) operation.requestBody = {
95
- required: true,
96
- content: { "application/json": { schema: bodySchema } }
97
- };
98
- }
99
- if (userFields && isUserFieldEndpoint(endpointPath) && operation.requestBody) mergeUserFieldsIntoRequestBody(operation.requestBody, userFields, endpointPath);
100
- }
101
- if (openApiMeta?.responses) operation.responses = openApiMeta.responses;
102
- else operation.responses = {
103
- "200": { description: "Success" },
104
- "400": { description: "Bad request" },
105
- "401": { description: "Unauthorized" }
106
- };
107
- if (!paths[fullPath]) paths[fullPath] = {};
108
- paths[fullPath][method] = operation;
109
- }
110
- }
111
- const schemas = {
112
- User: {
113
- type: "object",
114
- properties: {
115
- id: { type: "string" },
116
- name: { type: "string" },
117
- email: {
118
- type: "string",
119
- format: "email"
120
- },
121
- emailVerified: { type: "boolean" },
122
- image: {
123
- type: "string",
124
- nullable: true
125
- },
126
- createdAt: {
127
- type: "string",
128
- format: "date-time"
129
- },
130
- updatedAt: {
131
- type: "string",
132
- format: "date-time"
133
- }
134
- }
135
- },
136
- Session: {
137
- type: "object",
138
- properties: {
139
- id: { type: "string" },
140
- userId: { type: "string" },
141
- token: { type: "string" },
142
- expiresAt: {
143
- type: "string",
144
- format: "date-time"
145
- },
146
- ipAddress: {
147
- type: "string",
148
- nullable: true
149
- },
150
- userAgent: {
151
- type: "string",
152
- nullable: true
153
- },
154
- createdAt: {
155
- type: "string",
156
- format: "date-time"
157
- },
158
- updatedAt: {
159
- type: "string",
160
- format: "date-time"
161
- }
162
- }
163
- }
164
- };
165
- if (userFields) {
166
- const userProps = schemas.User?.properties;
167
- for (const [name, field] of Object.entries(userFields)) {
168
- const prop = { type: field.type };
169
- if (field.description) prop.description = field.description;
170
- userProps[name] = prop;
171
- }
172
- }
173
- const securitySchemes = { cookieAuth: {
174
- type: "apiKey",
175
- in: "cookie",
176
- name: "better-auth.session_token",
177
- description: "Session cookie set by Better Auth after sign-in"
178
- } };
179
- if (detectedPlugins.apiKey) securitySchemes.apiKeyAuth = {
180
- type: "apiKey",
181
- in: "header",
182
- name: "x-api-key",
183
- description: "API key for programmatic access. Pass org context via x-organization-id header."
184
- };
185
- const resourceSecurity = [];
186
- if (detectedPlugins.apiKey) resourceSecurity.push({
187
- apiKeyAuth: [],
188
- orgHeader: []
189
- });
190
- return {
191
- paths,
192
- schemas,
193
- securitySchemes,
194
- tags: [{
195
- name: tagName,
196
- description: tagDescription
197
- }],
198
- resourceSecurity: resourceSecurity.length > 0 ? resourceSecurity : void 0
199
- };
200
- }
201
- /**
202
- * Auto-detect active Better Auth plugins by inspecting the API object.
203
- *
204
- * Rather than hardcoding plugin-specific behavior, we check for known
205
- * endpoint signatures that each plugin registers. This way the OpenAPI
206
- * spec adapts automatically to whatever plugins the app has enabled —
207
- * no Arc update needed when adding/removing plugins.
208
- */
209
- function detectActivePlugins(authApi) {
210
- const endpointPaths = /* @__PURE__ */ new Set();
211
- for (const value of Object.values(authApi)) if (isBetterAuthEndpoint(value)) endpointPaths.add(value.path);
212
- return {
213
- apiKey: endpointPaths.has("/api-key/create"),
214
- organization: endpointPaths.has("/organization/create")
215
- };
216
- }
217
- /**
218
- * Convert a camelCase key like 'signInEmail' to a readable summary like 'Sign in email'
219
- */
220
- function formatOperationSummary(key) {
221
- return key.replace(/([A-Z])/g, " $1").replace(/^./, (s) => s.toUpperCase()).trim();
222
- }
223
- /**
224
- * Check if an endpoint path should have userFields merged into its request body.
225
- */
226
- function isUserFieldEndpoint(path) {
227
- return path === "/sign-up/email" || path === "/update-user";
228
- }
229
- /**
230
- * Merge user-defined fields into an existing requestBody schema.
231
- * For updateUser, all fields are treated as optional regardless of their `required` setting.
232
- */
233
- function mergeUserFieldsIntoRequestBody(requestBody, userFields, endpointPath) {
234
- const content = requestBody?.content?.["application/json"];
235
- if (!content?.schema) return;
236
- const schema = content.schema;
237
- if (!schema.properties) schema.properties = {};
238
- if (!schema.required) schema.required = [];
239
- const props = schema.properties;
240
- const required = schema.required;
241
- for (const [name, field] of Object.entries(userFields)) {
242
- if (field.input === false) continue;
243
- const isRequired = endpointPath === "/update-user" ? false : field.required ?? false;
244
- const prop = { type: field.type };
245
- if (field.description) prop.description = field.description;
246
- props[name] = prop;
247
- if (isRequired && !required.includes(name)) required.push(name);
248
- }
249
- }
250
- //#endregion
251
- export { extractBetterAuthOpenApi as n, betterAuthOpenApi_exports as t };