@classytic/arc 2.18.4 → 2.19.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 (160) 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-D7NGwcAR.mjs} +29 -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 +262 -6
  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-Ba-6Sue6.mjs} +67 -63
  28. package/dist/{createActionRouter-DGCCp-kP.mjs → createActionRouter-B_WzBFyf.mjs} +10 -10
  29. package/dist/{createAggregationRouter-Ca77b8iK.mjs → createAggregationRouter-B_G_nIjm.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/encryption/index.d.mts +222 -0
  35. package/dist/encryption/index.mjs +270 -0
  36. package/dist/{errorHandler-Bua97SEt.mjs → errorHandler-Dxf6P_kV.mjs} +2 -2
  37. package/dist/{eventPlugin-Bw4bUDEO.mjs → eventPlugin-DJG2D7sy.mjs} +106 -5
  38. package/dist/{eventPlugin-C1W1CRbf.d.mts → eventPlugin-DbBFd3x_.d.mts} +1 -1
  39. package/dist/events/index.d.mts +3 -3
  40. package/dist/events/index.mjs +189 -5
  41. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  42. package/dist/events/transports/redis.d.mts +1 -1
  43. package/dist/factory/index.d.mts +1 -1
  44. package/dist/factory/index.mjs +3 -3
  45. package/dist/{fastify-augmentation-BdCl_eNo.d.mts → fastify-augmentation-D-5_yQJi.d.mts} +2 -2
  46. package/dist/{fields-CKLrhyOb.d.mts → fields-C7ahdGYf.d.mts} +1 -1
  47. package/dist/{generate-BaxDdmJ8.mjs → generate-Brans3fW.mjs} +1 -1
  48. package/dist/hooks/index.d.mts +1 -1
  49. package/dist/hooks/index.mjs +1 -1
  50. package/dist/idempotency/index.d.mts +2 -2
  51. package/dist/idempotency/index.mjs +1 -1
  52. package/dist/idempotency/redis.d.mts +1 -1
  53. package/dist/{index-Cvo1u9n6.d.mts → index-CP6A1Ffj.d.mts} +9 -9
  54. package/dist/{index-vcWUGkwf.d.mts → index-CRKiiP5o.d.mts} +3 -3
  55. package/dist/{index-QYma8mdC.d.mts → index-CUTG2Cuo.d.mts} +88 -7
  56. package/dist/index.d.mts +5 -5
  57. package/dist/index.mjs +7 -7
  58. package/dist/{init-DSsdRfk9.mjs → init-Bqpt1Hxf.mjs} +274 -130
  59. package/dist/integrations/event-gateway.d.mts +2 -2
  60. package/dist/integrations/event-gateway.mjs +1 -1
  61. package/dist/integrations/index.d.mts +3 -3
  62. package/dist/integrations/mcp/index.d.mts +4 -4
  63. package/dist/integrations/mcp/index.mjs +1 -1
  64. package/dist/integrations/mcp/testing.d.mts +1 -1
  65. package/dist/integrations/mcp/testing.mjs +1 -1
  66. package/dist/integrations/streamline.mjs +7 -3
  67. package/dist/integrations/websocket-pushref-redis.d.mts +1 -1
  68. package/dist/integrations/websocket-redis.d.mts +1 -1
  69. package/dist/integrations/websocket.d.mts +3 -3
  70. package/dist/{loadResources-CwXt9MCh.mjs → loadResources-B8UmpITt.mjs} +1 -1
  71. package/dist/{loadResourcesFromEntry-XHNeUWpu.mjs → loadResourcesFromEntry-BTlFEx05.mjs} +1 -1
  72. package/dist/{mcpPlugin-CzKdt3B8.mjs → mcpPlugin-C088Nd-G.mjs} +10 -11
  73. package/dist/{memory-TdTHCS9-.mjs → memory-CLXA2VeJ.mjs} +1 -1
  74. package/dist/{metrics-Da2EUPi9.mjs → metrics-fdxI5mn_.mjs} +1 -1
  75. package/dist/middleware/index.d.mts +1 -1
  76. package/dist/middleware/index.mjs +2 -2
  77. package/dist/{openapi-ButnRyOM.mjs → openapi-DZ-5a5Op.mjs} +5 -5
  78. package/dist/permissions/index.d.mts +3 -3
  79. package/dist/permissions/index.mjs +2 -2
  80. package/dist/{permissions-3uzwkbQt.mjs → permissions-BPB1xqGf.mjs} +4 -4
  81. package/dist/{pipe-9Tl-OAus.mjs → pipe-BOLmGIxa.mjs} +1 -1
  82. package/dist/pipeline/index.d.mts +1 -1
  83. package/dist/pipeline/index.mjs +1 -1
  84. package/dist/plugins/index.d.mts +6 -7
  85. package/dist/plugins/index.mjs +12 -12
  86. package/dist/plugins/response-cache.mjs +1 -1
  87. package/dist/plugins/tracing-entry.d.mts +1 -1
  88. package/dist/plugins/tracing-entry.mjs +1 -1
  89. package/dist/presets/filesUpload.d.mts +4 -4
  90. package/dist/presets/filesUpload.mjs +4 -4
  91. package/dist/presets/index.d.mts +1 -1
  92. package/dist/presets/index.mjs +1 -1
  93. package/dist/presets/multiTenant.d.mts +1 -1
  94. package/dist/presets/multiTenant.mjs +2 -2
  95. package/dist/presets/search.d.mts +2 -2
  96. package/dist/presets/search.mjs +1 -1
  97. package/dist/{presets-CF79RHEo.mjs → presets-BtyFwTO4.mjs} +2 -2
  98. package/dist/{queryCachePlugin-CnAeFqju.mjs → queryCachePlugin-emHb0CuX.mjs} +4 -4
  99. package/dist/{queryCachePlugin-Bd2tYgh5.d.mts → queryCachePlugin-xzFyKAjT.d.mts} +2 -2
  100. package/dist/{redis-3hqH_Qk_.d.mts → redis-C3W0qbz8.d.mts} +1 -1
  101. package/dist/{redis-stream-BtEUtjxZ.d.mts → redis-stream-DsP1vqZB.d.mts} +1 -1
  102. package/dist/{rateLimit-yKvxWAky.mjs → registerRoute-BdV8DDwU.mjs} +127 -2
  103. package/dist/registry/index.d.mts +1 -1
  104. package/dist/registry/index.mjs +2 -2
  105. package/dist/{registry-Br15xdGM.mjs → registry-Bm9LjWKs.mjs} +1 -1
  106. package/dist/{replyHelpers-DXHVxrrj.mjs → replyHelpers-67tRawQZ.mjs} +1 -1
  107. package/dist/{schemaIR-CE6USIRi.mjs → schemaIR-D1MJwqmp.mjs} +1 -1
  108. package/dist/schemas/index.d.mts +64 -65
  109. package/dist/scope/index.d.mts +2 -2
  110. package/dist/scope/index.mjs +3 -3
  111. package/dist/{sse-BrY1W6U8.mjs → sse-CfUjwjDk.mjs} +7 -4
  112. package/dist/streaming-BQcW6_Kq.mjs +162 -0
  113. package/dist/testing/index.d.mts +7 -7
  114. package/dist/testing/index.mjs +3 -3
  115. package/dist/testing/storageContract.d.mts +1 -1
  116. package/dist/types/index.d.mts +5 -5
  117. package/dist/types/storage.d.mts +1 -1
  118. package/dist/{types-WVlAVp8T.d.mts → types-9_wtNPsI.d.mts} +10 -10
  119. package/dist/{types-BWBcb88c.d.mts → types-DpvSF5Hh.d.mts} +1 -1
  120. package/dist/{types-Bi0r0vjG.mjs → types-bHblZ9YN.mjs} +1 -1
  121. package/dist/utils/index.d.mts +42 -4
  122. package/dist/utils/index.mjs +6 -5
  123. package/dist/{utils-xAQeDyU_.mjs → utils-C6QQ9-hd.mjs} +1415 -1524
  124. package/dist/{validate-0__MuUsK.mjs → validate-CRcaWzp2.mjs} +1 -1
  125. package/dist/{versioning-BSEDGXKC.d.mts → versioning-D_eBCfNr.d.mts} +8 -1
  126. package/dist/{versioning-C0K8KQLx.mjs → versioning-Dk-71iIz.mjs} +1 -1
  127. package/dist/{websocket-BFBT5rH-.d.mts → websocket-MlYlrYq0.d.mts} +1 -1
  128. package/package.json +45 -30
  129. package/dist/EventTransport-7LPXLEUX.mjs +0 -103
  130. package/dist/actionPermissions-CX9QIMTd.mjs +0 -24
  131. package/dist/betterAuthOpenApi-DAAhMZff.mjs +0 -251
  132. package/dist/defineEvent-DC981g-o.mjs +0 -188
  133. package/dist/registerRoute-BEYn0ylk.mjs +0 -108
  134. /package/dist/{EventTransport-CaaXM5Y1.d.mts → EventTransport-IEn7Tn-Q.d.mts} +0 -0
  135. /package/dist/{HookSystem-BfCpWbwM.mjs → HookSystem-C1vB_Gc9.mjs} +0 -0
  136. /package/dist/{constants-TrJVIJl0.mjs → constants-gaEeMlz-.mjs} +0 -0
  137. /package/dist/{elevation-DW90z5bT.d.mts → elevation-xGUBq6p_.d.mts} +0 -0
  138. /package/dist/{errorHandler-_Lp2k9M3.d.mts → errorHandler-BtUUDPEa.d.mts} +0 -0
  139. /package/dist/{errors-DZOemeGa.d.mts → errors-DOHkjQlD.d.mts} +0 -0
  140. /package/dist/{errors-j4aJm1Wg.mjs → errors-DkO8Nk6-.mjs} +0 -0
  141. /package/dist/{externalPaths-DLle0R07.d.mts → externalPaths-BE6wFpYv.d.mts} +0 -0
  142. /package/dist/{generate-Dmk8cfvX.d.mts → generate-BnsL9GBm.d.mts} +0 -0
  143. /package/dist/{init-BS4Daqnv.d.mts → init-BPEu8cs-.d.mts} +0 -0
  144. /package/dist/{interface-DL7LlWS5.d.mts → interface-C1_WLTMK.d.mts} +0 -0
  145. /package/dist/{interface-CsrGR8LF.d.mts → interface-Uk8ONJv7.d.mts} +0 -0
  146. /package/dist/{keys-B3yyBEyH.mjs → keys-Cd316u_y.mjs} +0 -0
  147. /package/dist/{multipartBody-709YcXi1.mjs → multipartBody-CHEQSZ6G.mjs} +0 -0
  148. /package/dist/{pluralize-BxdUl2P4.mjs → pluralize-DccFV9R7.mjs} +0 -0
  149. /package/dist/{preloadResources-B-j-iqo-.mjs → preloadResources-CHw3_oA_.mjs} +0 -0
  150. /package/dist/{pushref-registry-Dqclzjy7.d.mts → pushref-registry-DnCqL3aa.d.mts} +0 -0
  151. /package/dist/{requestContext-DDLS3NVU.mjs → requestContext-BZKOr13H.mjs} +0 -0
  152. /package/dist/{chunk-BpYLSNr0.mjs → rolldown-runtime-8H4AJuhK.mjs} +0 -0
  153. /package/dist/{schemaConverter-DatAaVNj.mjs → schemaConverter-U0MnO9vd.mjs} +0 -0
  154. /package/dist/{sessionManager-CyHpYXoB.d.mts → sessionManager-BXG-HGwG.d.mts} +0 -0
  155. /package/dist/{storage-C5q8fuEt.d.mts → storage-Co_PQpeQ.d.mts} +0 -0
  156. /package/dist/{store-helpers-DjSYI2uP.mjs → store-helpers-DY6xq4sM.mjs} +0 -0
  157. /package/dist/{tracing-Bnb1-YVd.d.mts → tracing-D8jlGXP7.d.mts} +0 -0
  158. /package/dist/{typeGuards-CcFZXgU7.mjs → typeGuards-C9KXUly6.mjs} +0 -0
  159. /package/dist/{types-BJwJN2Pg.d.mts → types-LNebCoJx.d.mts} +0 -0
  160. /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.19.0",
4
4
  "description": "Resource-oriented backend framework for Fastify - clean, minimal, powerful, tree-shakable",
5
5
  "type": "module",
6
6
  "exports": {
@@ -96,6 +96,10 @@
96
96
  "types": "./dist/docs/index.d.mts",
97
97
  "default": "./dist/docs/index.mjs"
98
98
  },
99
+ "./encryption": {
100
+ "types": "./dist/encryption/index.d.mts",
101
+ "default": "./dist/encryption/index.mjs"
102
+ },
99
103
  "./idempotency": {
100
104
  "types": "./dist/idempotency/index.d.mts",
101
105
  "default": "./dist/idempotency/index.mjs"
@@ -224,6 +228,7 @@
224
228
  "lint:all": "biome check src/ tests/",
225
229
  "test": "vitest run",
226
230
  "test:main": "vitest run --no-file-parallelism",
231
+ "test:fast": "vitest run --exclude \"**/tests/integrations/websocket/**\" && vitest run tests/integrations/websocket/ --no-file-parallelism",
227
232
  "test:perf": "node --expose-gc ./node_modules/vitest/vitest.mjs run --config vitest.perf.config.ts --no-file-parallelism",
228
233
  "test:ci": "npm run test:main && npm run test:perf",
229
234
  "test:watch": "vitest",
@@ -269,6 +274,7 @@
269
274
  "fastify-raw-body": ">=5.0.0",
270
275
  "h3-js": ">=4.0.0",
271
276
  "ioredis": ">=5.0.0",
277
+ "jose": ">=5.0.0",
272
278
  "pino-pretty": ">=13.0.0",
273
279
  "zod": ">=4.0.0"
274
280
  },
@@ -330,6 +336,9 @@
330
336
  "ioredis": {
331
337
  "optional": true
332
338
  },
339
+ "jose": {
340
+ "optional": true
341
+ },
333
342
  "@sinclair/typebox": {
334
343
  "optional": true
335
344
  },
@@ -350,56 +359,62 @@
350
359
  }
351
360
  },
352
361
  "dependencies": {
353
- "fastify-plugin": "^5.0.1",
362
+ "fastify-plugin": "^6.0.0",
354
363
  "qs": "^6.15.2",
355
364
  "secure-json-parse": "^4.1.0"
356
365
  },
357
366
  "devDependencies": {
358
- "@better-auth/drizzle-adapter": "^1.6.9",
359
- "@better-auth/mongo-adapter": "^1.6.9",
360
- "@biomejs/biome": "^2.4.15",
367
+ "@better-auth/drizzle-adapter": "^1.6.19",
368
+ "@better-auth/mongo-adapter": "^1.6.19",
369
+ "@biomejs/biome": "^2.5.0",
361
370
  "@classytic/dev-tools": "^0.2.0",
362
- "@classytic/mongokit": "^3.16.0",
363
- "@classytic/primitives": "^0.6.0",
371
+ "@classytic/mongokit": "^3.16.1",
372
+ "@classytic/primitives": "^0.7.2",
364
373
  "@classytic/repo-core": "^0.6.0",
365
374
  "@classytic/sqlitekit": "^0.6.0",
366
- "@classytic/streamline": "^2.3.3",
375
+ "@classytic/streamline": "^2.6.0",
367
376
  "@fastify/cors": "^11.2.0",
368
377
  "@fastify/helmet": "^13.0.2",
369
- "@fastify/jwt": "^10.0.0",
378
+ "@fastify/jwt": "^10.1.0",
370
379
  "@fastify/multipart": "^10.0.0",
371
- "@fastify/rate-limit": "^10.3.0",
380
+ "@fastify/rate-limit": "^11.0.0",
372
381
  "@fastify/sensible": "^6.0.4",
373
- "@fastify/type-provider-typebox": "^6.0.0",
382
+ "@fastify/type-provider-typebox": "^6.1.0",
374
383
  "@fastify/under-pressure": "^9.0.3",
375
- "@fastify/websocket": "^11.0.0",
384
+ "@fastify/websocket": "^11.2.0",
376
385
  "@modelcontextprotocol/sdk": "^1.29.0",
377
386
  "@opentelemetry/api": "^1.9.1",
378
- "@sinclair/typebox": "^0.34.0",
379
- "@types/node": "^22.19.19",
387
+ "@sinclair/typebox": "^0.34.49",
388
+ "@types/node": "^22.19.21",
380
389
  "@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",
390
+ "@vitest/coverage-v8": "^4.1.9",
391
+ "ajv": "^8.20.0",
392
+ "better-auth": "^1.6.19",
393
+ "better-sqlite3": "^12.11.1",
394
+ "bullmq": "^5.79.0",
386
395
  "dotenv": "^17.4.2",
387
396
  "drizzle-orm": "^0.45.2",
388
397
  "fast-check": "^4.8.0",
389
398
  "fastify": "^5.8.5",
390
399
  "fastify-raw-body": "^5.0.0",
391
400
  "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"
401
+ "ioredis": "^5.11.1",
402
+ "jose": "^6.2.3",
403
+ "jsonwebtoken": "^9.0.3",
404
+ "knip": "^6.17.1",
405
+ "mongodb": "^7.3.0",
406
+ "mongodb-memory-server": "^11.2.0",
407
+ "mongoose": "^9.7.1",
408
+ "tsdown": "^0.22.3",
409
+ "typescript": "^6.0.3",
410
+ "vitest": "^4.1.9",
411
+ "ws": "^8.21.0",
412
+ "zod": "^4.4.3"
413
+ },
414
+ "config": {
415
+ "mongodbMemoryServer": {
416
+ "disablePostinstall": "1"
417
+ }
403
418
  },
404
419
  "keywords": [
405
420
  "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 };