@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.
- package/dist/{BaseController-B-uXzf6I.mjs → BaseController-Dy6EQHjM.mjs} +7 -7
- package/dist/{QueryCache-Dsyv2mLS.d.mts → QueryCache-TRfXau3W.d.mts} +1 -1
- package/dist/{ResourceRegistry-CWmOggxS.mjs → ResourceRegistry-5fKZwhK_.mjs} +1 -1
- package/dist/{pipeline-D4sqiokR.mjs → actionPermissions-D7NGwcAR.mjs} +29 -5
- package/dist/audit/index.d.mts +1 -1
- package/dist/auth/index.d.mts +4 -4
- package/dist/auth/index.mjs +262 -6
- package/dist/auth/redis-session.d.mts +1 -1
- package/dist/betterAuthOpenApi-CV1lxpRX.mjs +2 -0
- package/dist/{buildHandler-Cvrc2p7r.mjs → buildHandler-B0qvAguf.mjs} +1 -1
- package/dist/cache/index.d.mts +3 -3
- package/dist/cache/index.mjs +3 -3
- package/dist/{caching-C0DdKiYB.mjs → caching-_NJeDd1_.mjs} +1 -1
- package/dist/cli/commands/describe.d.mts +1 -1
- package/dist/cli/commands/describe.mjs +2 -2
- package/dist/cli/commands/docs.mjs +2 -2
- package/dist/cli/commands/generate.d.mts +2 -2
- package/dist/cli/commands/generate.mjs +1 -1
- package/dist/cli/commands/init.d.mts +2 -2
- package/dist/cli/commands/init.mjs +1 -1
- package/dist/cli/commands/introspect.mjs +1 -1
- package/dist/cli/index.d.mts +2 -2
- package/dist/cli/index.mjs +2 -2
- package/dist/context/index.mjs +1 -1
- package/dist/core/index.d.mts +3 -3
- package/dist/core/index.mjs +4 -4
- package/dist/{core-C88uIwd3.mjs → core-Ba-6Sue6.mjs} +67 -63
- package/dist/{createActionRouter-DGCCp-kP.mjs → createActionRouter-B_WzBFyf.mjs} +10 -10
- package/dist/{createAggregationRouter-Ca77b8iK.mjs → createAggregationRouter-B_G_nIjm.mjs} +4 -4
- package/dist/{createApp-J1iPXY9p.mjs → createApp--703hQE1.mjs} +14 -14
- package/dist/docs/index.d.mts +2 -2
- package/dist/docs/index.mjs +2 -2
- package/dist/{elevation-BzhyVWfn.mjs → elevation-COpYKt2h.mjs} +2 -2
- package/dist/encryption/index.d.mts +222 -0
- package/dist/encryption/index.mjs +270 -0
- package/dist/{errorHandler-Bua97SEt.mjs → errorHandler-Dxf6P_kV.mjs} +2 -2
- package/dist/{eventPlugin-Bw4bUDEO.mjs → eventPlugin-DJG2D7sy.mjs} +106 -5
- package/dist/{eventPlugin-C1W1CRbf.d.mts → eventPlugin-DbBFd3x_.d.mts} +1 -1
- package/dist/events/index.d.mts +3 -3
- package/dist/events/index.mjs +189 -5
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis.d.mts +1 -1
- package/dist/factory/index.d.mts +1 -1
- package/dist/factory/index.mjs +3 -3
- package/dist/{fastify-augmentation-BdCl_eNo.d.mts → fastify-augmentation-D-5_yQJi.d.mts} +2 -2
- package/dist/{fields-CKLrhyOb.d.mts → fields-C7ahdGYf.d.mts} +1 -1
- package/dist/{generate-BaxDdmJ8.mjs → generate-Brans3fW.mjs} +1 -1
- package/dist/hooks/index.d.mts +1 -1
- package/dist/hooks/index.mjs +1 -1
- package/dist/idempotency/index.d.mts +2 -2
- package/dist/idempotency/index.mjs +1 -1
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/{index-Cvo1u9n6.d.mts → index-CP6A1Ffj.d.mts} +9 -9
- package/dist/{index-vcWUGkwf.d.mts → index-CRKiiP5o.d.mts} +3 -3
- package/dist/{index-QYma8mdC.d.mts → index-CUTG2Cuo.d.mts} +88 -7
- package/dist/index.d.mts +5 -5
- package/dist/index.mjs +7 -7
- package/dist/{init-DSsdRfk9.mjs → init-Bqpt1Hxf.mjs} +274 -130
- package/dist/integrations/event-gateway.d.mts +2 -2
- package/dist/integrations/event-gateway.mjs +1 -1
- package/dist/integrations/index.d.mts +3 -3
- package/dist/integrations/mcp/index.d.mts +4 -4
- package/dist/integrations/mcp/index.mjs +1 -1
- package/dist/integrations/mcp/testing.d.mts +1 -1
- package/dist/integrations/mcp/testing.mjs +1 -1
- package/dist/integrations/streamline.mjs +7 -3
- package/dist/integrations/websocket-pushref-redis.d.mts +1 -1
- package/dist/integrations/websocket-redis.d.mts +1 -1
- package/dist/integrations/websocket.d.mts +3 -3
- package/dist/{loadResources-CwXt9MCh.mjs → loadResources-B8UmpITt.mjs} +1 -1
- package/dist/{loadResourcesFromEntry-XHNeUWpu.mjs → loadResourcesFromEntry-BTlFEx05.mjs} +1 -1
- package/dist/{mcpPlugin-CzKdt3B8.mjs → mcpPlugin-C088Nd-G.mjs} +10 -11
- package/dist/{memory-TdTHCS9-.mjs → memory-CLXA2VeJ.mjs} +1 -1
- package/dist/{metrics-Da2EUPi9.mjs → metrics-fdxI5mn_.mjs} +1 -1
- package/dist/middleware/index.d.mts +1 -1
- package/dist/middleware/index.mjs +2 -2
- package/dist/{openapi-ButnRyOM.mjs → openapi-DZ-5a5Op.mjs} +5 -5
- package/dist/permissions/index.d.mts +3 -3
- package/dist/permissions/index.mjs +2 -2
- package/dist/{permissions-3uzwkbQt.mjs → permissions-BPB1xqGf.mjs} +4 -4
- package/dist/{pipe-9Tl-OAus.mjs → pipe-BOLmGIxa.mjs} +1 -1
- package/dist/pipeline/index.d.mts +1 -1
- package/dist/pipeline/index.mjs +1 -1
- package/dist/plugins/index.d.mts +6 -7
- package/dist/plugins/index.mjs +12 -12
- package/dist/plugins/response-cache.mjs +1 -1
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/presets/filesUpload.d.mts +4 -4
- package/dist/presets/filesUpload.mjs +4 -4
- package/dist/presets/index.d.mts +1 -1
- package/dist/presets/index.mjs +1 -1
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/presets/multiTenant.mjs +2 -2
- package/dist/presets/search.d.mts +2 -2
- package/dist/presets/search.mjs +1 -1
- package/dist/{presets-CF79RHEo.mjs → presets-BtyFwTO4.mjs} +2 -2
- package/dist/{queryCachePlugin-CnAeFqju.mjs → queryCachePlugin-emHb0CuX.mjs} +4 -4
- package/dist/{queryCachePlugin-Bd2tYgh5.d.mts → queryCachePlugin-xzFyKAjT.d.mts} +2 -2
- package/dist/{redis-3hqH_Qk_.d.mts → redis-C3W0qbz8.d.mts} +1 -1
- package/dist/{redis-stream-BtEUtjxZ.d.mts → redis-stream-DsP1vqZB.d.mts} +1 -1
- package/dist/{rateLimit-yKvxWAky.mjs → registerRoute-BdV8DDwU.mjs} +127 -2
- package/dist/registry/index.d.mts +1 -1
- package/dist/registry/index.mjs +2 -2
- package/dist/{registry-Br15xdGM.mjs → registry-Bm9LjWKs.mjs} +1 -1
- package/dist/{replyHelpers-DXHVxrrj.mjs → replyHelpers-67tRawQZ.mjs} +1 -1
- package/dist/{schemaIR-CE6USIRi.mjs → schemaIR-D1MJwqmp.mjs} +1 -1
- package/dist/schemas/index.d.mts +64 -65
- package/dist/scope/index.d.mts +2 -2
- package/dist/scope/index.mjs +3 -3
- package/dist/{sse-BrY1W6U8.mjs → sse-CfUjwjDk.mjs} +7 -4
- package/dist/streaming-BQcW6_Kq.mjs +162 -0
- package/dist/testing/index.d.mts +7 -7
- package/dist/testing/index.mjs +3 -3
- package/dist/testing/storageContract.d.mts +1 -1
- package/dist/types/index.d.mts +5 -5
- package/dist/types/storage.d.mts +1 -1
- package/dist/{types-WVlAVp8T.d.mts → types-9_wtNPsI.d.mts} +10 -10
- package/dist/{types-BWBcb88c.d.mts → types-DpvSF5Hh.d.mts} +1 -1
- package/dist/{types-Bi0r0vjG.mjs → types-bHblZ9YN.mjs} +1 -1
- package/dist/utils/index.d.mts +42 -4
- package/dist/utils/index.mjs +6 -5
- package/dist/{utils-xAQeDyU_.mjs → utils-C6QQ9-hd.mjs} +1415 -1524
- package/dist/{validate-0__MuUsK.mjs → validate-CRcaWzp2.mjs} +1 -1
- package/dist/{versioning-BSEDGXKC.d.mts → versioning-D_eBCfNr.d.mts} +8 -1
- package/dist/{versioning-C0K8KQLx.mjs → versioning-Dk-71iIz.mjs} +1 -1
- package/dist/{websocket-BFBT5rH-.d.mts → websocket-MlYlrYq0.d.mts} +1 -1
- package/package.json +45 -30
- package/dist/EventTransport-7LPXLEUX.mjs +0 -103
- package/dist/actionPermissions-CX9QIMTd.mjs +0 -24
- package/dist/betterAuthOpenApi-DAAhMZff.mjs +0 -251
- package/dist/defineEvent-DC981g-o.mjs +0 -188
- package/dist/registerRoute-BEYn0ylk.mjs +0 -108
- /package/dist/{EventTransport-CaaXM5Y1.d.mts → EventTransport-IEn7Tn-Q.d.mts} +0 -0
- /package/dist/{HookSystem-BfCpWbwM.mjs → HookSystem-C1vB_Gc9.mjs} +0 -0
- /package/dist/{constants-TrJVIJl0.mjs → constants-gaEeMlz-.mjs} +0 -0
- /package/dist/{elevation-DW90z5bT.d.mts → elevation-xGUBq6p_.d.mts} +0 -0
- /package/dist/{errorHandler-_Lp2k9M3.d.mts → errorHandler-BtUUDPEa.d.mts} +0 -0
- /package/dist/{errors-DZOemeGa.d.mts → errors-DOHkjQlD.d.mts} +0 -0
- /package/dist/{errors-j4aJm1Wg.mjs → errors-DkO8Nk6-.mjs} +0 -0
- /package/dist/{externalPaths-DLle0R07.d.mts → externalPaths-BE6wFpYv.d.mts} +0 -0
- /package/dist/{generate-Dmk8cfvX.d.mts → generate-BnsL9GBm.d.mts} +0 -0
- /package/dist/{init-BS4Daqnv.d.mts → init-BPEu8cs-.d.mts} +0 -0
- /package/dist/{interface-DL7LlWS5.d.mts → interface-C1_WLTMK.d.mts} +0 -0
- /package/dist/{interface-CsrGR8LF.d.mts → interface-Uk8ONJv7.d.mts} +0 -0
- /package/dist/{keys-B3yyBEyH.mjs → keys-Cd316u_y.mjs} +0 -0
- /package/dist/{multipartBody-709YcXi1.mjs → multipartBody-CHEQSZ6G.mjs} +0 -0
- /package/dist/{pluralize-BxdUl2P4.mjs → pluralize-DccFV9R7.mjs} +0 -0
- /package/dist/{preloadResources-B-j-iqo-.mjs → preloadResources-CHw3_oA_.mjs} +0 -0
- /package/dist/{pushref-registry-Dqclzjy7.d.mts → pushref-registry-DnCqL3aa.d.mts} +0 -0
- /package/dist/{requestContext-DDLS3NVU.mjs → requestContext-BZKOr13H.mjs} +0 -0
- /package/dist/{chunk-BpYLSNr0.mjs → rolldown-runtime-8H4AJuhK.mjs} +0 -0
- /package/dist/{schemaConverter-DatAaVNj.mjs → schemaConverter-U0MnO9vd.mjs} +0 -0
- /package/dist/{sessionManager-CyHpYXoB.d.mts → sessionManager-BXG-HGwG.d.mts} +0 -0
- /package/dist/{storage-C5q8fuEt.d.mts → storage-Co_PQpeQ.d.mts} +0 -0
- /package/dist/{store-helpers-DjSYI2uP.mjs → store-helpers-DY6xq4sM.mjs} +0 -0
- /package/dist/{tracing-Bnb1-YVd.d.mts → tracing-D8jlGXP7.d.mts} +0 -0
- /package/dist/{typeGuards-CcFZXgU7.mjs → typeGuards-C9KXUly6.mjs} +0 -0
- /package/dist/{types-BJwJN2Pg.d.mts → types-LNebCoJx.d.mts} +0 -0
- /package/dist/{types-D57iXYb8.mjs → types-XTApa8b6.mjs} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as DomainEvent } from "./EventTransport-
|
|
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 { a as PushRefRegistry, l as EnvelopeWriter, s as PushRefStore } from "./pushref-registry-
|
|
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.
|
|
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": "^
|
|
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.
|
|
359
|
-
"@better-auth/mongo-adapter": "^1.6.
|
|
360
|
-
"@biomejs/biome": "^2.
|
|
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.
|
|
363
|
-
"@classytic/primitives": "^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.
|
|
375
|
+
"@classytic/streamline": "^2.6.0",
|
|
367
376
|
"@fastify/cors": "^11.2.0",
|
|
368
377
|
"@fastify/helmet": "^13.0.2",
|
|
369
|
-
"@fastify/jwt": "^10.
|
|
378
|
+
"@fastify/jwt": "^10.1.0",
|
|
370
379
|
"@fastify/multipart": "^10.0.0",
|
|
371
|
-
"@fastify/rate-limit": "^
|
|
380
|
+
"@fastify/rate-limit": "^11.0.0",
|
|
372
381
|
"@fastify/sensible": "^6.0.4",
|
|
373
|
-
"@fastify/type-provider-typebox": "^6.
|
|
382
|
+
"@fastify/type-provider-typebox": "^6.1.0",
|
|
374
383
|
"@fastify/under-pressure": "^9.0.3",
|
|
375
|
-
"@fastify/websocket": "^11.
|
|
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.
|
|
379
|
-
"@types/node": "^22.19.
|
|
387
|
+
"@sinclair/typebox": "^0.34.49",
|
|
388
|
+
"@types/node": "^22.19.21",
|
|
380
389
|
"@types/qs": "^6.15.1",
|
|
381
|
-
"@vitest/coverage-v8": "^
|
|
382
|
-
"ajv": "^8.
|
|
383
|
-
"better-auth": "^1.6.
|
|
384
|
-
"better-sqlite3": "^12.
|
|
385
|
-
"bullmq": "^5.
|
|
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.
|
|
393
|
-
"
|
|
394
|
-
"
|
|
395
|
-
"
|
|
396
|
-
"mongodb
|
|
397
|
-
"
|
|
398
|
-
"
|
|
399
|
-
"
|
|
400
|
-
"
|
|
401
|
-
"
|
|
402
|
-
"
|
|
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 };
|