@classytic/arc 2.28.0 → 2.31.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/LICENSE +1 -1
- package/README.md +7 -0
- package/TRADEMARK.md +22 -0
- package/dist/{BaseController-B65zbz9m.mjs → BaseController-De7GqHck.mjs} +25 -24
- package/dist/{EventTransport-QmY7A258.d.mts → EventTransport-2uVV34WU.d.mts} +1 -0
- package/dist/EventTransport-9mlTgqzE.mjs +104 -0
- package/dist/{HookSystem-C1vB_Gc9.mjs → HookSystem-BcmPyq5I.mjs} +16 -35
- package/dist/{QueryCache-DOMT_iq7.d.mts → QueryCache-DFA-QrU9.d.mts} +2 -1
- package/dist/{ResourceRegistry-y9Hnypus.mjs → ResourceRegistry-qq0mn2s9.mjs} +3 -2
- package/dist/{actionPermissions-CAphcmUG.mjs → actionPermissions-BE5NwaQk.mjs} +1 -0
- package/dist/audit/index.d.mts +3 -2
- package/dist/audit/index.mjs +3 -2
- package/dist/auth/audit.d.mts +1 -0
- package/dist/auth/audit.mjs +1 -0
- package/dist/auth/index.d.mts +5 -4
- package/dist/auth/index.mjs +6 -5
- package/dist/auth/redis-session.d.mts +2 -1
- package/dist/auth/redis-session.mjs +1 -0
- package/dist/authorizationDecision-ChvUQGG1.mjs +266 -0
- package/dist/{buildHandler-Dtwd8fdz.mjs → buildHandler-CDrCJzmB.mjs} +34 -7
- package/dist/cache/index.d.mts +4 -3
- package/dist/cache/index.mjs +4 -3
- package/dist/{caching-_NJeDd1_.mjs → caching-BFHA6Scf.mjs} +2 -1
- package/dist/cleanup/index.d.mts +4 -3
- package/dist/cleanup/index.mjs +9 -13
- package/dist/cli/commands/describe.d.mts +2 -1
- package/dist/cli/commands/describe.mjs +3 -2
- package/dist/cli/commands/docs.d.mts +1 -0
- package/dist/cli/commands/docs.mjs +3 -2
- package/dist/cli/commands/doctor.d.mts +1 -0
- package/dist/cli/commands/doctor.mjs +1 -0
- package/dist/cli/commands/generate.d.mts +2 -1
- package/dist/cli/commands/generate.mjs +2 -1
- package/dist/cli/commands/init.d.mts +2 -1
- package/dist/cli/commands/init.mjs +2 -1
- package/dist/cli/commands/introspect.d.mts +1 -0
- package/dist/cli/commands/introspect.mjs +2 -1
- package/dist/cli/index.d.mts +3 -2
- package/dist/cli/index.mjs +3 -2
- package/dist/{constants-DNre0wRg.mjs → constants-D3Dv4LAV.mjs} +1 -0
- package/dist/context/index.d.mts +1 -0
- package/dist/context/index.mjs +3 -2
- package/dist/core/index.d.mts +3 -2
- package/dist/core/index.mjs +7 -5
- package/dist/{core-BGa8TXJR.mjs → core-BGpIxINN.mjs} +4 -49
- package/dist/{createActionRouter-C-N7z2EL.mjs → createActionRouter-CDXEdasl.mjs} +8 -7
- package/dist/{createAggregationRouter-wzwFa_dW.mjs → createAggregationRouter-KrQDzx-k.mjs} +10 -22
- package/dist/{createApp-Du5G54TM.mjs → createApp-Df89BEni.mjs} +505 -209
- package/dist/defineAggregation-DbPPS8RI.mjs +48 -0
- package/dist/{defineResource-2zvVVpxg.mjs → defineResource-Bv6EtN1x.mjs} +90 -72
- package/dist/discovery/index.d.mts +1 -0
- package/dist/discovery/index.mjs +1 -0
- package/dist/docs/index.d.mts +3 -2
- package/dist/docs/index.mjs +3 -2
- package/dist/{elevation-C9s5hFP_.d.mts → elevation-BXCfVcNG.d.mts} +1 -0
- package/dist/{elevation-CIz1GjGm.mjs → elevation-D2l1mh4g.mjs} +4 -3
- package/dist/encryption/index.d.mts +2 -1
- package/dist/encryption/index.mjs +3 -2
- package/dist/{errorHandler-Bq2OeEQL.mjs → errorHandler-C5NeD6bT.mjs} +3 -2
- package/dist/{errorHandler-C6yv4ZTW.d.mts → errorHandler-CpYUJmPA.d.mts} +1 -0
- package/dist/{errors-DHcHVAgk.d.mts → errors-BGdVwP25.d.mts} +1 -0
- package/dist/{errors-DkO8Nk6-.mjs → errors-Cj42AntO.mjs} +1 -0
- package/dist/{eventPlugin-DrQ_FesK.mjs → eventPlugin-CkffEihm.mjs} +6 -106
- package/dist/{eventPlugin-Bg3cP2_u.d.mts → eventPlugin-GF5nnBIq.d.mts} +2 -1
- package/dist/events/index.d.mts +4 -3
- package/dist/events/index.mjs +17 -340
- package/dist/events/transports/redis-stream-entry.d.mts +2 -1
- package/dist/events/transports/redis-stream-entry.mjs +1 -0
- package/dist/events/transports/redis.d.mts +2 -1
- package/dist/events/transports/redis.mjs +1 -0
- package/dist/{externalPaths-BE6wFpYv.d.mts → externalPaths-CmGOxOtD.d.mts} +1 -0
- package/dist/factory/index.d.mts +9 -5
- package/dist/factory/index.mjs +7 -6
- package/dist/{fastify-augmentation-OzYGIiU1.d.mts → fastify-augmentation-zh0_AYHa.d.mts} +13 -4
- package/dist/{applyPermissionResult-BnyVE9eD.mjs → fields-CB5Cuzk9.mjs} +2 -107
- package/dist/{fields-D3lhgzhD.d.mts → fields-I_EeRWND.d.mts} +1 -0
- package/dist/{generate-BnsL9GBm.d.mts → generate-DCGuEbqI.d.mts} +1 -0
- package/dist/{generate-D0wZupBg.mjs → generate-EcA6ui4i.mjs} +2 -1
- package/dist/{headers-BvlQSDMB.mjs → headers-3zvE0rM3.mjs} +2 -1
- package/dist/{health-CB_m4S32.mjs → health-DjZYjM7H.mjs} +1 -0
- package/dist/hooks/index.d.mts +2 -1
- package/dist/hooks/index.mjs +2 -1
- package/dist/idempotency/index.d.mts +3 -2
- package/dist/idempotency/index.mjs +5 -4
- package/dist/idempotency/redis.d.mts +2 -1
- package/dist/idempotency/redis.mjs +1 -0
- package/dist/{index-CjVg-Epg.d.mts → index-Bc2ox8_U.d.mts} +6 -5
- package/dist/{index-CG4yqMDB.d.mts → index-C-481Zf2.d.mts} +74 -18
- package/dist/{index-BMnbzvtO.d.mts → index-CEJNZFtX.d.mts} +242 -24
- package/dist/index-CFThn1K9.d.mts +224 -0
- package/dist/{index-DPRH0Cme.d.mts → index-CpzxqePp.d.mts} +203 -97
- package/dist/index.d.mts +9 -8
- package/dist/index.mjs +11 -9
- package/dist/{init-tlRSt667.mjs → init-BEiNZBsJ.mjs} +19 -23
- package/dist/{init-BPEu8cs-.d.mts → init-Cscs4lab.d.mts} +1 -0
- package/dist/integrations/event-gateway.d.mts +3 -2
- package/dist/integrations/event-gateway.mjs +2 -1
- package/dist/integrations/index.d.mts +4 -3
- package/dist/integrations/index.mjs +1 -0
- package/dist/integrations/jobs/index.d.mts +2 -1
- package/dist/integrations/jobs/index.mjs +108 -32
- package/dist/integrations/mcp/index.d.mts +9 -9
- package/dist/integrations/mcp/index.mjs +2 -1
- package/dist/integrations/mcp/testing.d.mts +3 -2
- package/dist/integrations/mcp/testing.mjs +2 -2
- package/dist/integrations/streamline.d.mts +1 -0
- package/dist/integrations/streamline.mjs +3 -2
- package/dist/integrations/webhooks.d.mts +1 -0
- package/dist/integrations/webhooks.mjs +1 -0
- package/dist/integrations/websocket-pushref-redis.d.mts +2 -1
- package/dist/integrations/websocket-pushref-redis.mjs +1 -0
- package/dist/integrations/websocket-redis.d.mts +2 -1
- package/dist/integrations/websocket-redis.mjs +1 -0
- package/dist/integrations/websocket.d.mts +3 -2
- package/dist/integrations/websocket.mjs +1 -0
- package/dist/{interface-BGZCzOGL.d.mts → interface-BOk3YnTz.d.mts} +1 -0
- package/dist/{interface-Uk8ONJv7.d.mts → interface-DEWNOMza.d.mts} +1 -0
- package/dist/{interface-n5hpKg1d.mjs → interface-DYzM0q-u.mjs} +1 -0
- package/dist/{jsonBody-BlzAoGCe.mjs → jsonBody-BYbLDi5D.mjs} +2 -1
- package/dist/{keys-Cd316u_y.mjs → keys-C0_pa1tY.mjs} +1 -0
- package/dist/{loadResources-DpU8pfjV.mjs → loadResources-yawi9tAE.mjs} +2 -1
- package/dist/{loadResourcesFromEntry-kvGT6EcO.mjs → loadResourcesFromEntry-BAjYZonx.mjs} +2 -1
- package/dist/logger/index.d.mts +1 -0
- package/dist/logger/index.mjs +1 -0
- package/dist/{mcpPlugin-Cs6nRGCt.mjs → mcpPlugin-B_es0hiF.mjs} +52 -60
- package/dist/{memory-CmnzXE5Z.mjs → memory-DR6wpa9F.mjs} +2 -1
- package/dist/{metrics-fdxI5mn_.mjs → metrics-CUdw_wLB.mjs} +2 -1
- package/dist/middleware/index.d.mts +2 -1
- package/dist/middleware/index.mjs +3 -2
- package/dist/migrations/index.d.mts +1 -3
- package/dist/migrations/index.mjs +2 -4
- package/dist/module-0pFJA6YW.mjs +78 -0
- package/dist/{multipartBody-D0eBvkeq.mjs → multipartBody-wOgj_fnj.mjs} +1 -0
- package/dist/{openapi-BLV4OMXb.mjs → openapi-B2L4js1v.mjs} +6 -5
- package/dist/permissions/index.d.mts +5 -4
- package/dist/permissions/index.mjs +6 -4
- package/dist/{permissions-BrtiBKGs.mjs → permissions-L--QDAir.mjs} +518 -316
- package/dist/{pipe-BOLmGIxa.mjs → pipe-DRDNsI2T.mjs} +2 -1
- package/dist/pipeline/index.d.mts +2 -1
- package/dist/pipeline/index.mjs +2 -1
- package/dist/{pipeline-BGRnV-To.mjs → pipeline-UPQFatit.mjs} +7 -20
- package/dist/plugins/index.d.mts +8 -7
- package/dist/plugins/index.mjs +16 -15
- package/dist/plugins/response-cache.d.mts +1 -0
- package/dist/plugins/response-cache.mjs +2 -1
- package/dist/plugins/tracing-entry.d.mts +2 -1
- package/dist/plugins/tracing-entry.mjs +2 -1
- package/dist/{pluralize-BhrgwZb9.mjs → pluralize-O0FZgESl.mjs} +1 -0
- package/dist/{preloadResources-CM4uUaFv.d.mts → preloadResources-CyoJMSiO.d.mts} +117 -12
- package/dist/{preloadResources-DSY5HGpS.mjs → preloadResources-Dz6BjzM6.mjs} +1 -0
- package/dist/presets/filesUpload.d.mts +6 -5
- package/dist/presets/filesUpload.mjs +9 -11
- package/dist/presets/index.d.mts +15 -2
- package/dist/presets/index.mjs +2 -1
- package/dist/presets/multiTenant.d.mts +2 -1
- package/dist/presets/multiTenant.mjs +3 -2
- package/dist/presets/search.d.mts +3 -2
- package/dist/presets/search.mjs +2 -1
- package/dist/{presets-DwFDVKP0.mjs → presets-C4-g4_4P.mjs} +27 -10
- package/dist/projection-BHw6xlOQ.mjs +18 -0
- package/dist/{pushref-registry-BbcnpNTm.d.mts → pushref-registry-Dov9l4qE.d.mts} +1 -0
- package/dist/{queryCachePlugin-DSGuSVLW.mjs → queryCachePlugin-BZr8v46E.mjs} +5 -4
- package/dist/{queryCachePlugin-br4otiqF.d.mts → queryCachePlugin-BzqxconG.d.mts} +3 -2
- package/dist/{rateLimit-DrED-C4v.mjs → rateLimit-CMPY5Qms.mjs} +7 -3
- package/dist/{rateLimitKey-BoWRH3e7.mjs → rateLimitKey-Dn5JNmkj.mjs} +1 -0
- package/dist/{realtime-DEuDu9io.mjs → realtime-C5NoxWFY.mjs} +20 -8
- package/dist/{redis-UDtLaNj6.d.mts → redis-CduhKsJi.d.mts} +2 -1
- package/dist/{redis-stream-uIaauNpZ.d.mts → redis-stream-qN6A-RFv.d.mts} +2 -1
- package/dist/{registerRoute-DTp18Ah_.mjs → registerRoute-CBN84fc7.mjs} +5 -2
- package/dist/registry/index.d.mts +3 -2
- package/dist/registry/index.mjs +3 -2
- package/dist/{registry-9km_w1aP.mjs → registry-4213U4zb.mjs} +3 -2
- package/dist/{renewingLease-3cuQH7h8.mjs → renewingLease-Dll8mGgc.mjs} +1 -0
- package/dist/{replyHelpers-67tRawQZ.mjs → replyHelpers-DIiZKGUt.mjs} +2 -1
- package/dist/repositoryFilter-f9eAfq_l.mjs +45 -0
- package/dist/{requestContext-MrlJwECf.mjs → requestContext-2TxXOJ7T.mjs} +1 -0
- package/dist/{rolldown-runtime-8H4AJuhK.mjs → rolldown-runtime-CUsjNX9R.mjs} +1 -0
- package/dist/{schedules-CjOd2MG9.mjs → schedules-DdtlICTf.mjs} +3 -2
- package/dist/{schemaConverter-DJvodiHj.mjs → schemaConverter-D--wdJM-.mjs} +70 -17
- package/dist/{schemaIR-Ca7ySNPx.mjs → schemaIR-Bm2enbnh.mjs} +2 -1
- package/dist/schemas/index.d.mts +1 -0
- package/dist/schemas/index.mjs +1 -0
- package/dist/scim/index.d.mts +1 -0
- package/dist/scim/index.mjs +2 -1
- package/dist/scope/index.d.mts +3 -2
- package/dist/scope/index.mjs +5 -4
- package/dist/{scope-DfaPntpo.mjs → scope-DHx5Fous.mjs} +4 -3
- package/dist/{sessionManager-BHOM3N_0.d.mts → sessionManager-qimlKV0P.d.mts} +1 -0
- package/dist/{simpleEqualityMatcher-Cg05HPsn.mjs → simpleEqualityMatcher-DjQJ7FKA.mjs} +1 -0
- package/dist/{sse-BQ1w0dfl.mjs → sse-CUTo9y0X.mjs} +5 -4
- package/dist/{sseStream-BQ7Qaynp.mjs → sseStream-B_5XcVVd.mjs} +2 -1
- package/dist/{storage-DLUZ04kK.d.mts → storage-Cx9Sz3Ou.d.mts} +1 -0
- package/dist/{store-helpers-DY6xq4sM.mjs → store-helpers-D1MP_gRG.mjs} +1 -0
- package/dist/{streaming-BQcW6_Kq.mjs → streaming-PSZwi8JV.mjs} +1 -0
- package/dist/subscribe-helpers-C0Tb2aUp.mjs +340 -0
- package/dist/sync/changelog.d.mts +1 -0
- package/dist/sync/changelog.mjs +1 -0
- package/dist/testing/cleanupStoreContract.d.mts +2 -1
- package/dist/testing/cleanupStoreContract.mjs +1 -0
- package/dist/testing/index.d.mts +167 -12
- package/dist/testing/index.mjs +522 -205
- package/dist/testing/outboxStoreContract.d.mts +1 -0
- package/dist/testing/outboxStoreContract.mjs +1 -0
- package/dist/testing/storageContract.d.mts +2 -1
- package/dist/testing/storageContract.mjs +1 -0
- package/dist/{tracing-CsGKQJGg.d.mts → tracing-Dro5eH6j.d.mts} +1 -0
- package/dist/{transactionContext-PNdoyLLm.mjs → transactionContext-dAfBVUrk.mjs} +1 -0
- package/dist/{typeGuards-C9KXUly6.mjs → typeGuards-B0ryPo3I.mjs} +1 -0
- package/dist/types/index.d.mts +6 -5
- package/dist/types/index.mjs +1 -0
- package/dist/types/storage.d.mts +2 -1
- package/dist/types/storage.mjs +1 -0
- package/dist/{types-Dmw-6Qeo.d.mts → types-B7XeLEgK.d.mts} +127 -90
- package/dist/{types-Cc91nXuA.d.mts → types-ByHn9rEO.d.mts} +1 -0
- package/dist/{types-C_ZZRcD6.d.mts → types-C4QE8qnm.d.mts} +1 -0
- package/dist/{types-Cu6vVJmh.d.mts → types-CBgvkp8O.d.mts} +82 -12
- package/dist/{types-DjC-KUCz.d.mts → types-ChuShpCP.d.mts} +1 -0
- package/dist/{types-QFGc3Cjv.d.mts → types-CwcUQ610.d.mts} +2 -6
- package/dist/{types-CSyCxl2V.mjs → types-Cys0ko9Z.mjs} +4 -3
- package/dist/usage/index.d.mts +3 -2
- package/dist/usage/index.mjs +0 -0
- package/dist/{userHelpers-Cg_y3fBz.mjs → userHelpers-ChYJ6CdK.mjs} +1 -0
- package/dist/utils/index.d.mts +16 -10
- package/dist/utils/index.mjs +10 -9
- package/dist/{utils-taUVD4p3.mjs → utils-vL8BrDE2.mjs} +3 -2
- package/dist/{validate-Bk44F2yT.mjs → validate-_KbifpHF.mjs} +2 -1
- package/dist/{versioning-gKWyryT3.mjs → versioning-CHDTor3P.mjs} +3 -2
- package/dist/{versioning-DXgY5BUm.d.mts → versioning-D_rhHfZm.d.mts} +5 -2
- package/dist/{websocket-_Pd0CgR0.d.mts → websocket-BOXVggMf.d.mts} +2 -1
- package/package.json +15 -7
- package/skills/arc/SKILL.md +22 -8
- package/skills/arc/references/api-reference.md +4 -0
- package/skills/arc/references/auth.md +3 -0
- package/skills/arc/references/integrations.md +33 -0
- package/skills/arc/references/mcp.md +6 -7
- package/skills/arc/references/production.md +24 -25
- package/skills/arc-code-review/references/anti-patterns.md +3 -3
- package/dist/index-CZY4EGga.d.mts +0 -107
- package/dist/module-_-M7C5ES.mjs +0 -29
package/dist/events/index.mjs
CHANGED
|
@@ -1,192 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
/*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
|
|
2
|
+
import { t as MemoryEventTransport } from "../EventTransport-9mlTgqzE.mjs";
|
|
3
|
+
import { a as createEventRegistry, i as wrapWithSchema, n as subscribeWithSchema, o as defineEvent, r as wrapWithBoundary, t as subscribeWithBoundary } from "../subscribe-helpers-C0Tb2aUp.mjs";
|
|
4
|
+
import { i as withRetry, r as createDeadLetterPublisher, t as eventPlugin } from "../eventPlugin-CkffEihm.mjs";
|
|
5
|
+
import { n as createSafeGetOne, t as createIsDuplicateKeyError } from "../store-helpers-D1MP_gRG.mjs";
|
|
4
6
|
import { and, anyOf, eq, lte, ne, or } from "@classytic/repo-core/filter";
|
|
7
|
+
import { InvalidOutboxEventError, OutboxOwnershipError } from "@classytic/primitives/outbox";
|
|
5
8
|
import { update } from "@classytic/repo-core/update";
|
|
6
|
-
//#region src/events/defineEvent.ts
|
|
7
|
-
/**
|
|
8
|
-
* defineEvent — Typed Event Definitions with Optional Schema Validation
|
|
9
|
-
*
|
|
10
|
-
* Provides:
|
|
11
|
-
* 1. defineEvent() — declare an event with name, schema, version, description
|
|
12
|
-
* 2. EventRegistry — catalog of all known events + payload validation
|
|
13
|
-
* 3. .create() helper — build DomainEvent with auto-generated metadata
|
|
14
|
-
*
|
|
15
|
-
* The built-in validator checks: object type, required fields, and top-level
|
|
16
|
-
* property types. It does NOT recurse into nested objects, validate arrays,
|
|
17
|
-
* enums, patterns, formats, or $ref. This is intentional — it's a lightweight
|
|
18
|
-
* guard, not a full JSON Schema engine.
|
|
19
|
-
*
|
|
20
|
-
* For full validation, pass a custom `validate` function to `createEventRegistry()`:
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* ```typescript
|
|
24
|
-
* import Ajv from 'ajv';
|
|
25
|
-
* const ajv = new Ajv();
|
|
26
|
-
*
|
|
27
|
-
* const registry = createEventRegistry({
|
|
28
|
-
* validate: (schema, payload) => {
|
|
29
|
-
* const valid = ajv.validate(schema, payload);
|
|
30
|
-
* return valid
|
|
31
|
-
* ? { valid: true }
|
|
32
|
-
* : { valid: false, errors: ajv.errorsText().split(', ') };
|
|
33
|
-
* },
|
|
34
|
-
* });
|
|
35
|
-
* ```
|
|
36
|
-
*
|
|
37
|
-
* @example
|
|
38
|
-
* ```typescript
|
|
39
|
-
* import { defineEvent, createEventRegistry } from '@classytic/arc/events';
|
|
40
|
-
*
|
|
41
|
-
* const OrderCreated = defineEvent({
|
|
42
|
-
* name: 'order.created',
|
|
43
|
-
* version: 1,
|
|
44
|
-
* schema: {
|
|
45
|
-
* type: 'object',
|
|
46
|
-
* properties: {
|
|
47
|
-
* orderId: { type: 'string' },
|
|
48
|
-
* total: { type: 'number' },
|
|
49
|
-
* },
|
|
50
|
-
* required: ['orderId', 'total'],
|
|
51
|
-
* },
|
|
52
|
-
* });
|
|
53
|
-
*
|
|
54
|
-
* // Type-safe event creation
|
|
55
|
-
* const event = OrderCreated.create({ orderId: 'o-1', total: 100 });
|
|
56
|
-
* await fastify.events.publish(event.type, event.payload, event.meta);
|
|
57
|
-
*
|
|
58
|
-
* // Registry for introspection + validation
|
|
59
|
-
* const registry = createEventRegistry();
|
|
60
|
-
* registry.register(OrderCreated);
|
|
61
|
-
* const result = registry.validate('order.created', payload);
|
|
62
|
-
* ```
|
|
63
|
-
*/
|
|
64
|
-
/**
|
|
65
|
-
* Define a typed event with optional schema validation.
|
|
66
|
-
*
|
|
67
|
-
* @example
|
|
68
|
-
* const OrderCreated = defineEvent({
|
|
69
|
-
* name: 'order.created',
|
|
70
|
-
* schema: { type: 'object', properties: { orderId: { type: 'string' } }, required: ['orderId'] },
|
|
71
|
-
* });
|
|
72
|
-
*
|
|
73
|
-
* const event = OrderCreated.create({ orderId: '123' });
|
|
74
|
-
*/
|
|
75
|
-
function defineEvent(input) {
|
|
76
|
-
const { name, schema, version = 1, description } = input;
|
|
77
|
-
return {
|
|
78
|
-
name,
|
|
79
|
-
schema,
|
|
80
|
-
version,
|
|
81
|
-
description,
|
|
82
|
-
create(payload, meta) {
|
|
83
|
-
return createEvent(name, payload, {
|
|
84
|
-
schemaVersion: version,
|
|
85
|
-
...meta
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Create an event registry for cataloging and validating events.
|
|
92
|
-
*
|
|
93
|
-
* The registry is opt-in — unregistered events pass validation.
|
|
94
|
-
* This allows gradual adoption without breaking existing code.
|
|
95
|
-
*
|
|
96
|
-
* @param options.validate - Custom validator replacing the built-in minimal validator.
|
|
97
|
-
* The built-in validator only checks top-level object structure (type, required, property types).
|
|
98
|
-
* For nested objects, arrays, enums, patterns, or $ref, provide AJV or similar.
|
|
99
|
-
*/
|
|
100
|
-
function createEventRegistry(options) {
|
|
101
|
-
const customValidator = options?.validate;
|
|
102
|
-
const definitions = /* @__PURE__ */ new Map();
|
|
103
|
-
function registryKey(name, version) {
|
|
104
|
-
return `${name}:v${version}`;
|
|
105
|
-
}
|
|
106
|
-
return {
|
|
107
|
-
register(definition) {
|
|
108
|
-
const key = registryKey(definition.name, definition.version);
|
|
109
|
-
if (definitions.has(key)) throw new Error(`Event '${definition.name}' v${definition.version} is already registered. Use a different version number for schema evolution.`);
|
|
110
|
-
definitions.set(key, definition);
|
|
111
|
-
},
|
|
112
|
-
get(name, version) {
|
|
113
|
-
if (version !== void 0) return definitions.get(registryKey(name, version));
|
|
114
|
-
let latest;
|
|
115
|
-
let latestVersion = -1;
|
|
116
|
-
for (const def of definitions.values()) if (def.name === name && def.version > latestVersion) {
|
|
117
|
-
latest = def;
|
|
118
|
-
latestVersion = def.version;
|
|
119
|
-
}
|
|
120
|
-
return latest;
|
|
121
|
-
},
|
|
122
|
-
catalog() {
|
|
123
|
-
return Array.from(definitions.values()).map((def) => ({
|
|
124
|
-
name: def.name,
|
|
125
|
-
version: def.version,
|
|
126
|
-
description: def.description,
|
|
127
|
-
schema: def.schema
|
|
128
|
-
}));
|
|
129
|
-
},
|
|
130
|
-
validate(name, payload, version) {
|
|
131
|
-
let target = version !== void 0 ? definitions.get(registryKey(name, version)) : void 0;
|
|
132
|
-
if (!target && version === void 0) {
|
|
133
|
-
let latestVersion = -1;
|
|
134
|
-
for (const candidate of definitions.values()) if (candidate.name === name && candidate.version > latestVersion) {
|
|
135
|
-
target = candidate;
|
|
136
|
-
latestVersion = candidate.version;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
if (!target) return { valid: true };
|
|
140
|
-
if (!target.schema) return { valid: true };
|
|
141
|
-
return customValidator ? customValidator(target.schema, payload) : validatePayload(payload, target.schema);
|
|
142
|
-
}
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* Built-in minimal validator — lightweight guard, NOT a full JSON Schema engine.
|
|
147
|
-
*
|
|
148
|
-
* Checks:
|
|
149
|
-
* - payload is an object (not null, not array)
|
|
150
|
-
* - required fields are present
|
|
151
|
-
* - top-level property types match (string, number, boolean, array, object)
|
|
152
|
-
*
|
|
153
|
-
* Does NOT check:
|
|
154
|
-
* - nested object properties
|
|
155
|
-
* - array item types
|
|
156
|
-
* - enum, pattern, format, minLength, minimum, $ref
|
|
157
|
-
*
|
|
158
|
-
* For full validation, pass a custom `validate` function to `createEventRegistry()`.
|
|
159
|
-
*/
|
|
160
|
-
function validatePayload(payload, schema) {
|
|
161
|
-
const errors = [];
|
|
162
|
-
if (schema.type === "object") {
|
|
163
|
-
if (payload === null || payload === void 0 || typeof payload !== "object" || Array.isArray(payload)) return {
|
|
164
|
-
valid: false,
|
|
165
|
-
errors: ["Payload must be an object"]
|
|
166
|
-
};
|
|
167
|
-
const record = payload;
|
|
168
|
-
if (schema.required) {
|
|
169
|
-
for (const field of schema.required) if (!(field in record) || record[field] === void 0) errors.push(`Missing required field: '${field}'`);
|
|
170
|
-
}
|
|
171
|
-
if (schema.properties) {
|
|
172
|
-
for (const [key, propSchema] of Object.entries(schema.properties)) if (key in record && record[key] !== void 0 && record[key] !== null) {
|
|
173
|
-
const expectedType = propSchema.type;
|
|
174
|
-
if (expectedType) {
|
|
175
|
-
const value = record[key];
|
|
176
|
-
const actualType = Array.isArray(value) ? "array" : typeof value;
|
|
177
|
-
if (expectedType === "integer") {
|
|
178
|
-
if (actualType !== "number" || !Number.isInteger(value)) errors.push(`Field '${key}': expected integer, got ${actualType}`);
|
|
179
|
-
} else if (expectedType !== actualType) errors.push(`Field '${key}': expected ${expectedType}, got ${actualType}`);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
return errors.length === 0 ? { valid: true } : {
|
|
185
|
-
valid: false,
|
|
186
|
-
errors
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
//#endregion
|
|
190
9
|
//#region src/events/eventTypes.ts
|
|
191
10
|
/**
|
|
192
11
|
* Event Type Constants and Helpers
|
|
@@ -512,6 +331,17 @@ function repositoryAsOutboxStore(repository, options) {
|
|
|
512
331
|
*/
|
|
513
332
|
const claimableFilter = (now) => and(eq("status", "pending"), lte(visibleAtField, now), or(eq("leaseOwner", null), lte("leaseExpiresAt", now)));
|
|
514
333
|
return {
|
|
334
|
+
/**
|
|
335
|
+
* Transactional: `save` forwards `options.session` to the backing
|
|
336
|
+
* repository's `create`, so the event row joins the caller's transaction on
|
|
337
|
+
* the SAME connection and commits or rolls back with the domain write.
|
|
338
|
+
*
|
|
339
|
+
* Declared explicitly because `OutboxWriteOptions.session` is best-effort by
|
|
340
|
+
* contract — a caller cannot infer atomicity from the presence of an outbox,
|
|
341
|
+
* only from this flag. See `OutboxStore.transactionalSave` in
|
|
342
|
+
* `@classytic/primitives/outbox`.
|
|
343
|
+
*/
|
|
344
|
+
transactionalSave: true,
|
|
515
345
|
async save(event, options) {
|
|
516
346
|
if (!event?.type || typeof event.type !== "string") throw new InvalidOutboxEventError("event.type is required");
|
|
517
347
|
if (!event.meta?.id || typeof event.meta.id !== "string") throw new InvalidOutboxEventError("event.meta.id is required");
|
|
@@ -976,157 +806,4 @@ function normalizeError(err) {
|
|
|
976
806
|
return { message: String(err) };
|
|
977
807
|
}
|
|
978
808
|
//#endregion
|
|
979
|
-
//#region src/events/subscribe-helpers.ts
|
|
980
|
-
/**
|
|
981
|
-
* Subscribe-side helpers — close the symmetry that arc's publish-side
|
|
982
|
-
* already has via [`eventPlugin({ registry, validateMode: 'reject' })`](./eventPlugin.ts).
|
|
983
|
-
*
|
|
984
|
-
* Two wrapper pairs, both transport-agnostic:
|
|
985
|
-
*
|
|
986
|
-
* - `wrapWithSchema` / `subscribeWithSchema` — read the schema from a
|
|
987
|
-
* typed `EventDefinitionOutput<T>` and validate `event.payload` before
|
|
988
|
-
* the handler runs. Single source of truth for event shape: declare
|
|
989
|
-
* once at `defineEvent`, enforced on BOTH sides without parallel Zod
|
|
990
|
-
* schemas in subscriber files.
|
|
991
|
-
*
|
|
992
|
-
* - `wrapWithBoundary` / `subscribeWithBoundary` — catch + log + swallow
|
|
993
|
-
* handler errors, for projection / cache-invalidation / fire-and-forget
|
|
994
|
-
* handlers where retry would just delay the next-event resync. Lighter
|
|
995
|
-
* than `withRetry` (no DLQ, no exponential backoff) and avoids the
|
|
996
|
-
* "single bad event poisons the bus" hazard.
|
|
997
|
-
*
|
|
998
|
-
* Both pairs compose with `withRetry` and with each other:
|
|
999
|
-
*
|
|
1000
|
-
* ```ts
|
|
1001
|
-
* await subscribeWithSchema(
|
|
1002
|
-
* fastify,
|
|
1003
|
-
* OrderPaid,
|
|
1004
|
-
* withRetry(handler, { maxRetries: 3 }),
|
|
1005
|
-
* );
|
|
1006
|
-
* ```
|
|
1007
|
-
*
|
|
1008
|
-
* @see [retry.ts](./retry.ts) for the retry + DLQ wrapper.
|
|
1009
|
-
* @see [defineEvent.ts](./defineEvent.ts) for `defineEvent` / `EventDefinitionOutput`.
|
|
1010
|
-
*/
|
|
1011
|
-
/**
|
|
1012
|
-
* Pure handler wrapper — returns a new `EventHandler` that validates
|
|
1013
|
-
* `event.payload` against the definition's schema before invoking the handler.
|
|
1014
|
-
*
|
|
1015
|
-
* The returned handler's input is `DomainEvent<unknown>` (since the transport
|
|
1016
|
-
* delivers untyped events) but the inner `handler` receives `DomainEvent<T>`.
|
|
1017
|
-
* No cast at the call site.
|
|
1018
|
-
*
|
|
1019
|
-
* @example
|
|
1020
|
-
* ```ts
|
|
1021
|
-
* await fastify.events.subscribe(
|
|
1022
|
-
* OrderPaid.name,
|
|
1023
|
-
* wrapWithSchema(OrderPaid, async (event) => {
|
|
1024
|
-
* // event.payload is typed via the registered schema — no cast.
|
|
1025
|
-
* await postSalesEntry(event.payload.orderId, event.payload.total);
|
|
1026
|
-
* }),
|
|
1027
|
-
* );
|
|
1028
|
-
* ```
|
|
1029
|
-
*/
|
|
1030
|
-
function wrapWithSchema(definition, handler, options = {}) {
|
|
1031
|
-
const { validate, registry, onInvalid, logger = console, name } = options;
|
|
1032
|
-
const label = name ?? definition.name;
|
|
1033
|
-
return async (event) => {
|
|
1034
|
-
const eventVersion = typeof event.meta?.schemaVersion === "number" ? event.meta.schemaVersion : definition.version;
|
|
1035
|
-
let result;
|
|
1036
|
-
if (validate && definition.schema) result = validate(definition.schema, event.payload);
|
|
1037
|
-
else if (registry) result = registry.validate(definition.name, event.payload, eventVersion);
|
|
1038
|
-
else if (definition.schema) {
|
|
1039
|
-
const adhoc = createEventRegistry();
|
|
1040
|
-
adhoc.register(definition);
|
|
1041
|
-
result = adhoc.validate(definition.name, event.payload);
|
|
1042
|
-
} else result = { valid: true };
|
|
1043
|
-
if (!result.valid) {
|
|
1044
|
-
const errors = result.errors ?? ["payload failed validation"];
|
|
1045
|
-
if (onInvalid) try {
|
|
1046
|
-
await onInvalid(event, errors);
|
|
1047
|
-
} catch (cbErr) {
|
|
1048
|
-
logger.error(`[Arc Events] '${label}' onInvalid callback threw:`, cbErr);
|
|
1049
|
-
}
|
|
1050
|
-
else logger.warn(`[Arc Events] '${label}' skipped event ${event.meta?.id ?? "<no-id>"} — payload failed validation: ${errors.join("; ")}`);
|
|
1051
|
-
return;
|
|
1052
|
-
}
|
|
1053
|
-
await handler(event);
|
|
1054
|
-
};
|
|
1055
|
-
}
|
|
1056
|
-
/**
|
|
1057
|
-
* Convenience: validate + subscribe in one call. Equivalent to
|
|
1058
|
-
* `fastify.events.subscribe(definition.name, wrapWithSchema(definition, handler, options))`.
|
|
1059
|
-
*
|
|
1060
|
-
* Returns the unsubscribe function from the underlying transport.
|
|
1061
|
-
*
|
|
1062
|
-
* @example
|
|
1063
|
-
* ```ts
|
|
1064
|
-
* await subscribeWithSchema(fastify, OrderPaid, async (event) => {
|
|
1065
|
-
* await postSalesEntry(event.payload.orderId, event.payload.total);
|
|
1066
|
-
* });
|
|
1067
|
-
*
|
|
1068
|
-
* // Compose with withRetry — schema validation runs FIRST, then retry on
|
|
1069
|
-
* // handler failure. Invalid payloads skip without burning retry attempts.
|
|
1070
|
-
* await subscribeWithSchema(
|
|
1071
|
-
* fastify,
|
|
1072
|
-
* OrderPaid,
|
|
1073
|
-
* withRetry(handler, { maxRetries: 3 }),
|
|
1074
|
-
* );
|
|
1075
|
-
* ```
|
|
1076
|
-
*/
|
|
1077
|
-
async function subscribeWithSchema(fastify, definition, handler, options) {
|
|
1078
|
-
return fastify.events.subscribe(definition.name, wrapWithSchema(definition, handler, options));
|
|
1079
|
-
}
|
|
1080
|
-
/**
|
|
1081
|
-
* Pure handler wrapper — returns a new `EventHandler` that catches handler
|
|
1082
|
-
* exceptions and routes them to `onError` (or logs and swallows). For
|
|
1083
|
-
* projection / cache-invalidation / fire-and-forget handlers where retry
|
|
1084
|
-
* would just delay the next-event resync, and where one bad event must NOT
|
|
1085
|
-
* stop processing of subsequent events.
|
|
1086
|
-
*
|
|
1087
|
-
* Lighter than `withRetry`: no exponential backoff, no DLQ. Composes with
|
|
1088
|
-
* `withRetry` if you want both ("retry, then log if exhausted, never throw").
|
|
1089
|
-
*
|
|
1090
|
-
* @example
|
|
1091
|
-
* ```ts
|
|
1092
|
-
* await fastify.events.subscribe(
|
|
1093
|
-
* 'product:variants.changed',
|
|
1094
|
-
* wrapWithBoundary(async (event) => {
|
|
1095
|
-
* cache.invalidate(event.payload.productId);
|
|
1096
|
-
* }),
|
|
1097
|
-
* );
|
|
1098
|
-
* ```
|
|
1099
|
-
*/
|
|
1100
|
-
function wrapWithBoundary(handler, options = {}) {
|
|
1101
|
-
const { onError, logger = console, name } = options;
|
|
1102
|
-
const label = name ?? handler.name ?? "anonymous";
|
|
1103
|
-
return async (event) => {
|
|
1104
|
-
try {
|
|
1105
|
-
await handler(event);
|
|
1106
|
-
} catch (err) {
|
|
1107
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
1108
|
-
if (onError) try {
|
|
1109
|
-
await onError(error, event);
|
|
1110
|
-
} catch (cbErr) {
|
|
1111
|
-
logger.error(`[Arc Events] '${label}' onError callback threw:`, cbErr);
|
|
1112
|
-
}
|
|
1113
|
-
else logger.error(`[Arc Events] '${label}' threw on ${event.type} — swallowed (boundary): ${error.message}`, {
|
|
1114
|
-
err: error,
|
|
1115
|
-
event: event.type,
|
|
1116
|
-
eventId: event.meta?.id,
|
|
1117
|
-
handler: label
|
|
1118
|
-
});
|
|
1119
|
-
}
|
|
1120
|
-
};
|
|
1121
|
-
}
|
|
1122
|
-
/**
|
|
1123
|
-
* Convenience: subscribe + error-boundary in one call. Equivalent to
|
|
1124
|
-
* `fastify.events.subscribe(pattern, wrapWithBoundary(handler, options))`.
|
|
1125
|
-
*
|
|
1126
|
-
* Returns the unsubscribe function from the underlying transport.
|
|
1127
|
-
*/
|
|
1128
|
-
async function subscribeWithBoundary(fastify, pattern, handler, options) {
|
|
1129
|
-
return fastify.events.subscribe(pattern, wrapWithBoundary(handler, options));
|
|
1130
|
-
}
|
|
1131
|
-
//#endregion
|
|
1132
809
|
export { ARC_LIFECYCLE_EVENTS, CACHE_EVENTS, CRUD_EVENT_SUFFIXES, EventOutbox, MemoryEventTransport, MemoryOutboxStore, createDeadLetterPublisher, createEventRegistry, crudEventType, defineEvent, eventPlugin, exponentialBackoff, repositoryAsOutboxStore, subscribeWithBoundary, subscribeWithSchema, withRetry, wrapWithBoundary, wrapWithSchema };
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
|
+
import { n as RedisStreamTransport, r as RedisStreamTransportOptions, t as RedisStreamLike } from "../../redis-stream-qN6A-RFv.mjs";
|
|
2
3
|
export { type RedisStreamLike, RedisStreamTransport, type RedisStreamTransportOptions };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
|
+
import { a as EventTransport, i as EventLogger, n as DomainEvent, r as EventHandler } from "../../EventTransport-2uVV34WU.mjs";
|
|
2
3
|
//#region src/events/transports/redis.d.ts
|
|
3
4
|
interface RedisLike {
|
|
4
5
|
publish(channel: string, message: string): Promise<number>;
|
package/dist/factory/index.d.mts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
import { a as
|
|
3
|
-
import "../
|
|
4
|
-
import
|
|
1
|
+
|
|
2
|
+
import { a as ModuleContribution, c as ResourceModule, h as HealthCheck, i as EventHandlerDefinition, l as loadResources, n as ArcModuleInput, o as LoadResourcesOptions, r as ArcModuleRegistry, s as ResourceLike, t as ArcModule } from "../types-CBgvkp8O.mjs";
|
|
3
|
+
import { a as lazyModuleExports, c as getModuleState, d as resolveModule, f as orderModules, g as collectModuleWorkflows, h as collectModuleScheduledJobs, i as hasModuleExports, l as hasModule, m as collectModuleHealthChecks, n as getModuleExports, o as lazyRequiredModuleExports, p as subscribeModuleEventHandlers, r as getOptionalModuleExports, s as ModuleState, t as defineModule, u as resolveContribution } from "../index-CFThn1K9.mjs";
|
|
4
|
+
import "../fastify-augmentation-zh0_AYHa.mjs";
|
|
5
|
+
import { a as RawBodyOptions, c as BetterAuthOption, d as JwtAuthOption, i as MultipartOptions, l as CustomAuthenticatorOption, n as preloadResourcesAsync, o as UnderPressureOptions, r as CreateAppOptions, s as AuthOption, t as preloadResources, u as CustomPluginAuthOption } from "../preloadResources-CyoJMSiO.mjs";
|
|
5
6
|
import { FastifyInstance, FastifyServerOptions } from "fastify";
|
|
6
7
|
//#region src/factory/createApp.d.ts
|
|
7
8
|
/**
|
|
@@ -22,6 +23,9 @@ import { FastifyInstance, FastifyServerOptions } from "fastify";
|
|
|
22
23
|
* 10. afterResources() — post-registration wiring
|
|
23
24
|
* 11. onReady/onClose — lifecycle hooks
|
|
24
25
|
* ```
|
|
26
|
+
*
|
|
27
|
+
* **Boot is all-or-nothing.** If any phase throws, the partially-built
|
|
28
|
+
* instance is closed before the error propagates — see the wrapper below.
|
|
25
29
|
*/
|
|
26
30
|
declare function createApp(options: CreateAppOptions): Promise<FastifyInstance>;
|
|
27
31
|
/**
|
|
@@ -133,4 +137,4 @@ declare const testingPreset: Partial<CreateAppOptions>;
|
|
|
133
137
|
declare const edgePreset: Partial<CreateAppOptions>;
|
|
134
138
|
declare function getPreset(name: "production" | "development" | "testing" | "edge" | "worker"): Partial<CreateAppOptions>;
|
|
135
139
|
//#endregion
|
|
136
|
-
export { ArcFactory, type ArcModule, type ArcModuleInput, type ArcModuleRegistry, type ArcWorker, type AuthOption, type BetterAuthOption, type CreateAppOptions, type CreateWorkerOptions, type CustomAuthenticatorOption, type CustomPluginAuthOption, type EventHandlerDefinition, type FetchHandlerOptions, type JwtAuthOption, type LoadResourcesOptions, type ModuleContribution, type MultipartOptions, type RawBodyOptions, type ResourceLike, type ResourceModule, type UnderPressureOptions, type WorkerHealthOptions, collectModuleHealthChecks, collectModuleScheduledJobs, collectModuleWorkflows, createApp, createWorker, defineModule, developmentPreset, edgePreset, getModuleExports, getPreset, loadResources, orderModules, preloadResources, preloadResourcesAsync, productionPreset, resolveContribution, resolveModule, subscribeModuleEventHandlers, testingPreset, toFetchHandler };
|
|
140
|
+
export { ArcFactory, type ArcModule, type ArcModuleInput, type ArcModuleRegistry, type ArcWorker, type AuthOption, type BetterAuthOption, type CreateAppOptions, type CreateWorkerOptions, type CustomAuthenticatorOption, type CustomPluginAuthOption, type EventHandlerDefinition, type FetchHandlerOptions, type JwtAuthOption, type LoadResourcesOptions, type ModuleContribution, type ModuleState, type MultipartOptions, type RawBodyOptions, type ResourceLike, type ResourceModule, type UnderPressureOptions, type WorkerHealthOptions, collectModuleHealthChecks, collectModuleScheduledJobs, collectModuleWorkflows, createApp, createWorker, defineModule, developmentPreset, edgePreset, getModuleExports, getModuleState, getOptionalModuleExports, getPreset, hasModule, hasModuleExports, lazyModuleExports, lazyRequiredModuleExports, loadResources, orderModules, preloadResources, preloadResourcesAsync, productionPreset, resolveContribution, resolveModule, subscribeModuleEventHandlers, testingPreset, toFetchHandler };
|
package/dist/factory/index.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import { n as
|
|
4
|
-
import { t as
|
|
5
|
-
import {
|
|
1
|
+
/*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
|
|
2
|
+
import { r as mergeHealthChecks, t as healthPlugin } from "../health-DjZYjM7H.mjs";
|
|
3
|
+
import { _ as resolveContribution, a as edgePreset, c as testingPreset, d as hasModule, f as orderModules, g as collectModuleWorkflows, h as collectModuleScheduledJobs, i as developmentPreset, l as workerPreset, m as collectModuleHealthChecks, n as createApp, o as getPreset, p as subscribeModuleEventHandlers, s as productionPreset, t as ArcFactory, u as getModuleState, v as resolveModule } from "../createApp-Df89BEni.mjs";
|
|
4
|
+
import { a as lazyModuleExports, i as hasModuleExports, n as getModuleExports, o as lazyRequiredModuleExports, r as getOptionalModuleExports, t as defineModule } from "../module-0pFJA6YW.mjs";
|
|
5
|
+
import { t as loadResources } from "../loadResources-yawi9tAE.mjs";
|
|
6
|
+
import { n as preloadResourcesAsync, t as preloadResources } from "../preloadResources-Dz6BjzM6.mjs";
|
|
6
7
|
//#region src/factory/createWorker.ts
|
|
7
8
|
async function createWorker(options, workerOptions = {}) {
|
|
8
9
|
const { auth: _auth, helmet: _helmet, cors: _cors, rateLimit: _rateLimit, multipart: _multipart, rawBody: _rawBody, sensible: _sensible, underPressure: _underPressure, replyHelpers: _replyHelpers, ...runtimeOptions } = options;
|
|
@@ -120,4 +121,4 @@ function payloadTooLarge(limit) {
|
|
|
120
121
|
});
|
|
121
122
|
}
|
|
122
123
|
//#endregion
|
|
123
|
-
export { ArcFactory, collectModuleHealthChecks, collectModuleScheduledJobs, collectModuleWorkflows, createApp, createWorker, defineModule, developmentPreset, edgePreset, getModuleExports, getPreset, loadResources, orderModules, preloadResources, preloadResourcesAsync, productionPreset, resolveContribution, resolveModule, subscribeModuleEventHandlers, testingPreset, toFetchHandler };
|
|
124
|
+
export { ArcFactory, collectModuleHealthChecks, collectModuleScheduledJobs, collectModuleWorkflows, createApp, createWorker, defineModule, developmentPreset, edgePreset, getModuleExports, getModuleState, getOptionalModuleExports, getPreset, hasModule, hasModuleExports, lazyModuleExports, lazyRequiredModuleExports, loadResources, orderModules, preloadResources, preloadResourcesAsync, productionPreset, resolveContribution, resolveModule, subscribeModuleEventHandlers, testingPreset, toFetchHandler };
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import "./
|
|
1
|
+
|
|
2
|
+
import { hn as HookSystem, z as ResourceRegistry } from "./index-CpzxqePp.mjs";
|
|
3
|
+
import { t as ExternalOpenApiPaths } from "./externalPaths-CmGOxOtD.mjs";
|
|
4
|
+
import { h as HealthCheck, r as ArcModuleRegistry, t as ArcModule, u as ScheduleDefinition } from "./types-CBgvkp8O.mjs";
|
|
5
|
+
import { s as ModuleState } from "./index-CFThn1K9.mjs";
|
|
5
6
|
import { FastifyPluginAsync } from "fastify";
|
|
6
7
|
//#region src/core/arcCorePlugin.d.ts
|
|
7
8
|
interface ArcCorePluginOptions {
|
|
@@ -39,6 +40,14 @@ interface ArcCore {
|
|
|
39
40
|
* Populated lazily by `registerResources` — absent until a module exports.
|
|
40
41
|
*/
|
|
41
42
|
modules?: Partial<ArcModuleRegistry> & Record<string, unknown>;
|
|
43
|
+
/**
|
|
44
|
+
* Lifecycle state per composed module (null-proto map, populated by
|
|
45
|
+
* `registerResources` the moment the graph is validated — so it answers
|
|
46
|
+
* "is this module composed?" even for resource-only modules that never
|
|
47
|
+
* record an export). Read via `hasModule(fastify, name)` /
|
|
48
|
+
* `getModuleState(fastify, name)`; the map itself is internal.
|
|
49
|
+
*/
|
|
50
|
+
moduleStates?: Record<string, ModuleState>;
|
|
42
51
|
/**
|
|
43
52
|
* Module-contributed readiness checks, collected in dependency order and
|
|
44
53
|
* frozen by `createApp`. The API role merges these into its `healthPlugin`;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
/*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
|
|
2
2
|
//#region src/permissions/fields.ts
|
|
3
3
|
/**
|
|
4
4
|
* Field-Level Permissions
|
|
@@ -166,109 +166,4 @@ function resolveEffectiveRoles(userRoles, orgRoles) {
|
|
|
166
166
|
return [.../* @__PURE__ */ new Set([...userRoles, ...orgRoles])];
|
|
167
167
|
}
|
|
168
168
|
//#endregion
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Normalize a permission check return value (`boolean | PermissionResult`)
|
|
172
|
-
* into a concrete `PermissionResult`. This is the only place in Arc that
|
|
173
|
-
* promotes booleans to results — keeps the type narrowing honest everywhere.
|
|
174
|
-
*/
|
|
175
|
-
function normalizePermissionResult(result) {
|
|
176
|
-
if (typeof result === "boolean") return { granted: result };
|
|
177
|
-
return result;
|
|
178
|
-
}
|
|
179
|
-
/**
|
|
180
|
-
* Apply a granted `PermissionResult` to a Fastify request — merges row-level
|
|
181
|
-
* filters into `_policyFilters` and conditionally installs the scope.
|
|
182
|
-
*
|
|
183
|
-
* **Scope install rule:** only writes `scope` when the current request scope
|
|
184
|
-
* is absent or `public`. This prevents downgrading an already-authenticated
|
|
185
|
-
* request (e.g. Better Auth set `member`, then a permission check returns a
|
|
186
|
-
* narrower `service` scope — the original `member` wins because it came from
|
|
187
|
-
* a more authoritative source).
|
|
188
|
-
*
|
|
189
|
-
* Safe to call with a non-granted result — it simply no-ops. Callers should
|
|
190
|
-
* still check `result.granted` and send an error response before reaching here,
|
|
191
|
-
* but this function tolerates the misuse defensively.
|
|
192
|
-
*/
|
|
193
|
-
function applyPermissionResult(result, request) {
|
|
194
|
-
if (!result.granted) return;
|
|
195
|
-
if (result.filters) request._policyFilters = {
|
|
196
|
-
...request._policyFilters ?? {},
|
|
197
|
-
...result.filters
|
|
198
|
-
};
|
|
199
|
-
if (result.scope) {
|
|
200
|
-
const current = request.scope;
|
|
201
|
-
if (!current || current.kind === "public") request.scope = result.scope;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
/**
|
|
205
|
-
* Max length of a `PermissionResult.reason` string before we fall back to the
|
|
206
|
-
* generic default message. Upstream checks can return arbitrary strings; we
|
|
207
|
-
* clamp to prevent accidental leakage of internal diagnostics or oversized
|
|
208
|
-
* payloads via the 4xx response body.
|
|
209
|
-
*/
|
|
210
|
-
const MAX_DENIAL_REASON_LENGTH = 100;
|
|
211
|
-
/**
|
|
212
|
-
* End-to-end evaluator: runs the permission check, catches throws, normalizes
|
|
213
|
-
* the result, sends a 401/403 response on denial, and applies side-effects on
|
|
214
|
-
* grant. Returns `true` if the caller should continue, `false` if a response
|
|
215
|
-
* has been sent and the caller should return.
|
|
216
|
-
*
|
|
217
|
-
* This is the single source of truth for the 5-step sequence shared by the
|
|
218
|
-
* CRUD router, action router, and MCP tool handlers:
|
|
219
|
-
*
|
|
220
|
-
* 1. `try { await check(ctx) } catch { reply 403 }`
|
|
221
|
-
* 2. `normalizePermissionResult(result)`
|
|
222
|
-
* 3. If denied → 401 (no user) or 403 (user) with clamped reason
|
|
223
|
-
* 4. If granted → `applyPermissionResult` (filters + scope)
|
|
224
|
-
* 5. Return true/false so the caller knows whether to keep going
|
|
225
|
-
*
|
|
226
|
-
* Context construction, pre-check auth gating, and success-path handler
|
|
227
|
-
* invocation stay at the callsite — those are genuinely different per router
|
|
228
|
-
* and don't belong here.
|
|
229
|
-
*
|
|
230
|
-
* @returns `true` if authorized (caller continues), `false` if a response was sent
|
|
231
|
-
*/
|
|
232
|
-
async function evaluateAndApplyPermission(check, context, request, reply, opts) {
|
|
233
|
-
let result;
|
|
234
|
-
try {
|
|
235
|
-
result = await check(context);
|
|
236
|
-
} catch (err) {
|
|
237
|
-
request.log?.warn?.({
|
|
238
|
-
err,
|
|
239
|
-
resource: context.resource,
|
|
240
|
-
action: context.action
|
|
241
|
-
}, "Permission check threw");
|
|
242
|
-
if (err instanceof ArcError) {
|
|
243
|
-
reply.code(err.status).send({
|
|
244
|
-
code: err.code,
|
|
245
|
-
message: err.message,
|
|
246
|
-
status: err.status,
|
|
247
|
-
...err.meta ? { meta: err.meta } : {}
|
|
248
|
-
});
|
|
249
|
-
return false;
|
|
250
|
-
}
|
|
251
|
-
reply.code(403).send({
|
|
252
|
-
code: "arc.forbidden",
|
|
253
|
-
message: "Permission denied",
|
|
254
|
-
status: 403
|
|
255
|
-
});
|
|
256
|
-
return false;
|
|
257
|
-
}
|
|
258
|
-
const permResult = normalizePermissionResult(result);
|
|
259
|
-
if (!permResult.granted) {
|
|
260
|
-
const defaultMsg = opts?.defaultDenialMessage?.(context.user) ?? (context.user ? "Permission denied" : "Authentication required");
|
|
261
|
-
const reason = permResult.reason && permResult.reason.length <= MAX_DENIAL_REASON_LENGTH ? permResult.reason : defaultMsg;
|
|
262
|
-
const status = context.user ? 403 : 401;
|
|
263
|
-
reply.code(status).send({
|
|
264
|
-
code: context.user ? "arc.forbidden" : "arc.unauthorized",
|
|
265
|
-
message: reason,
|
|
266
|
-
status
|
|
267
|
-
});
|
|
268
|
-
return false;
|
|
269
|
-
}
|
|
270
|
-
applyPermissionResult(permResult, request);
|
|
271
|
-
return true;
|
|
272
|
-
}
|
|
273
|
-
//#endregion
|
|
274
|
-
export { applyFieldWritePermissions as a, applyFieldReadPermissions as i, evaluateAndApplyPermission as n, fields as o, normalizePermissionResult as r, resolveEffectiveRoles as s, applyPermissionResult as t };
|
|
169
|
+
export { resolveEffectiveRoles as i, applyFieldWritePermissions as n, fields as r, applyFieldReadPermissions as t };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
/*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
|
|
2
|
+
import { t as pluralize } from "./pluralize-O0FZgESl.mjs";
|
|
2
3
|
import { join } from "node:path";
|
|
3
4
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
5
|
//#region src/cli/commands/generate/name-helpers.ts
|
package/dist/hooks/index.d.mts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
|
+
import { Cn as createHookSystem, Sn as beforeUpdate, _n as afterCreate, bn as beforeCreate, dn as HookHandler, fn as HookOperation, gn as HookSystemOptions, hn as HookSystem, ln as DefineHookOptions, mn as HookRegistration, pn as HookPhase, un as HookContext, vn as afterDelete, wn as defineHook, xn as beforeDelete, yn as afterUpdate } from "../index-CpzxqePp.mjs";
|
|
2
3
|
export { type DefineHookOptions, type HookContext, type HookHandler, type HookOperation, type HookPhase, type HookRegistration, HookSystem, type HookSystemOptions, afterCreate, afterDelete, afterUpdate, beforeCreate, beforeDelete, beforeUpdate, createHookSystem, defineHook };
|
package/dist/hooks/index.mjs
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
|
|
1
|
+
/*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
|
|
2
|
+
import { a as beforeCreate, c as createHookSystem, i as afterUpdate, l as defineHook, n as afterCreate, o as beforeDelete, r as afterDelete, s as beforeUpdate, t as HookSystem } from "../HookSystem-BcmPyq5I.mjs";
|
|
2
3
|
export { HookSystem, afterCreate, afterDelete, afterUpdate, beforeCreate, beforeDelete, beforeUpdate, createHookSystem, defineHook };
|