@classytic/arc 2.10.3 → 2.10.8
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/README.md +1 -1
- package/dist/{BaseController-CbKKIflT.mjs → BaseController-DVNKvoX4.mjs} +151 -131
- package/dist/actionPermissions-TUVR3uiZ.mjs +22 -0
- package/dist/adapters/index.d.mts +2 -2
- package/dist/audit/index.d.mts +2 -2
- package/dist/audit/index.mjs +15 -17
- package/dist/auth/index.d.mts +4 -4
- package/dist/auth/index.mjs +5 -5
- package/dist/auth/redis-session.d.mts +1 -1
- package/dist/cache/index.d.mts +2 -2
- package/dist/cache/index.mjs +3 -3
- package/dist/cli/commands/docs.mjs +2 -2
- package/dist/cli/commands/generate.mjs +1 -1
- package/dist/cli/commands/init.mjs +1 -1
- package/dist/cli/commands/introspect.mjs +1 -1
- package/dist/context/index.d.mts +58 -0
- package/dist/context/index.mjs +2 -0
- package/dist/core/index.d.mts +2 -2
- package/dist/core/index.mjs +2 -2
- package/dist/{core-CcR01lup.mjs → core-3MWJosCH.mjs} +139 -91
- package/dist/{createApp-BuvPma24.mjs → createApp-BwnEAO2h.mjs} +54 -20
- package/dist/docs/index.d.mts +2 -2
- package/dist/docs/index.mjs +2 -2
- package/dist/{elevation-C7hgL_aI.mjs → elevation-Dci0AYLT.mjs} +2 -2
- package/dist/errorHandler-2ii4RIYr.d.mts +114 -0
- package/dist/{errorHandler-Bb49BvPD.mjs → errorHandler-CSxe7KIM.mjs} +1 -1
- package/dist/{eventPlugin-DCUjuiQT.mjs → eventPlugin-ByU4Cv0e.mjs} +1 -1
- package/dist/{eventPlugin-CxWgpd6K.d.mts → eventPlugin-D1ThQ1Pp.d.mts} +1 -1
- package/dist/events/index.d.mts +4 -4
- package/dist/events/index.mjs +69 -51
- 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 +2 -2
- package/dist/{fields-Lo1VUDpt.d.mts → fields-C8Y0XLAu.d.mts} +1 -1
- package/dist/hooks/index.d.mts +1 -1
- package/dist/hooks/index.mjs +1 -1
- package/dist/idempotency/index.d.mts +3 -3
- package/dist/idempotency/index.mjs +38 -27
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/{index-Cl0uoKd5.d.mts → index-BGbpGVyM.d.mts} +2362 -2155
- package/dist/{index-DStwgFUK.d.mts → index-BziRPS4H.d.mts} +1 -1
- package/dist/{index-ChIw3776.d.mts → index-C_Noptz-.d.mts} +3 -3
- package/dist/{index-8qw4y6ff.d.mts → index-EqQN6p0W.d.mts} +3 -3
- package/dist/index.d.mts +7 -219
- package/dist/index.mjs +8 -128
- package/dist/integrations/event-gateway.d.mts +1 -1
- package/dist/integrations/event-gateway.mjs +1 -1
- package/dist/integrations/index.d.mts +1 -1
- package/dist/integrations/mcp/index.d.mts +2 -2
- 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/logger/index.d.mts +81 -0
- package/dist/{logger-DLg8-Ueg.mjs → logger/index.mjs} +1 -6
- package/dist/middleware/index.d.mts +109 -0
- package/dist/middleware/index.mjs +70 -0
- package/dist/multipartBody-CUQGVlM_.mjs +123 -0
- package/dist/{openapi-B5F8AddX.mjs → openapi-DpNpqBmo.mjs} +9 -7
- package/dist/org/index.d.mts +2 -2
- package/dist/permissions/index.d.mts +2 -2
- package/dist/permissions/index.mjs +3 -3
- package/dist/{permissions-Dk6mshja.mjs → permissions-wkqRwicB.mjs} +2 -2
- package/dist/pipe-CGJxqDGx.mjs +62 -0
- package/dist/pipeline/index.d.mts +62 -0
- package/dist/pipeline/index.mjs +53 -0
- package/dist/plugins/index.d.mts +25 -5
- package/dist/plugins/index.mjs +9 -9
- 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 +255 -1
- package/dist/presets/index.d.mts +1 -1
- package/dist/presets/index.mjs +2 -2
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/presets/multiTenant.mjs +42 -8
- package/dist/presets/search.d.mts +2 -2
- package/dist/presets/search.mjs +1 -1
- package/dist/{presets-fLJVXdVn.mjs → presets-CrwOvuXI.mjs} +1 -1
- package/dist/{queryCachePlugin-DQCEfJis.mjs → queryCachePlugin-ChLNZvFT.mjs} +2 -2
- package/dist/{queryCachePlugin-BKbWjgDG.d.mts → queryCachePlugin-Dumka73q.d.mts} +1 -1
- package/dist/{queryParser-DBqBB6AC.mjs → queryParser-NR__Qiju.mjs} +68 -1
- package/dist/{redis-DqyeggCa.d.mts → redis-MXLp1oOf.d.mts} +1 -1
- package/dist/{redis-stream-CakIQmwR.d.mts → redis-stream-bkO88VHx.d.mts} +1 -1
- package/dist/registry/index.d.mts +1 -1
- package/dist/registry/index.mjs +2 -2
- package/dist/{requestContext-xHIKedG6.mjs → requestContext-C38GskNt.mjs} +1 -1
- package/dist/{resourceToTools-BElv3xPT.mjs → resourceToTools-BhF3JV5p.mjs} +8 -3
- package/dist/scope/index.d.mts +2 -2
- package/dist/scope/index.mjs +2 -2
- package/dist/{sse-yBCgOLGu.mjs → sse-D8UeDwis.mjs} +1 -1
- package/dist/{store-helpers-ZCSMJJAX.mjs → store-helpers-DYYUQbQN.mjs} +4 -0
- package/dist/testing/index.d.mts +2 -2
- package/dist/testing/index.mjs +11 -2
- package/dist/testing/storageContract.d.mts +1 -1
- package/dist/types/index.d.mts +4 -4
- package/dist/types/index.mjs +1 -1
- package/dist/types/storage.d.mts +1 -1
- package/dist/{types-Btdda02s.d.mts → types-CVKBssX5.d.mts} +1 -1
- package/dist/{types-Co8k3NyS.d.mts → types-CVdgPXBW.d.mts} +22 -9
- package/dist/utils/index.d.mts +73 -3
- package/dist/utils/index.mjs +4 -4
- package/dist/{utils-B2fNOD_i.mjs → utils-LMwVidKy.mjs} +20 -2
- package/dist/versioning-CeUXHfjw.d.mts +117 -0
- package/package.json +22 -6
- package/skills/arc/SKILL.md +1 -1
- package/dist/errorHandler-DRQ3EqfL.d.mts +0 -218
- package/dist/filesUpload-t21LS-py.mjs +0 -377
- /package/dist/{EventTransport-CUw5NNWe.d.mts → EventTransport-CfVEGaEl.d.mts} +0 -0
- /package/dist/{HookSystem-BNYKnrXF.mjs → HookSystem-BjFu7zf1.mjs} +0 -0
- /package/dist/{ResourceRegistry-BPd6NQDm.mjs → ResourceRegistry-CcN2LVrc.mjs} +0 -0
- /package/dist/{betterAuthOpenApi-BBRVhjQN.mjs → betterAuthOpenApi--rdY15Ld.mjs} +0 -0
- /package/dist/{caching-CBpK_SCM.mjs → caching-3h93rkJM.mjs} +0 -0
- /package/dist/{createActionRouter-Bp_5c_2b.mjs → createActionRouter-C8UUB3Px.mjs} +0 -0
- /package/dist/{elevation-C5SwtkAn.d.mts → elevation-s5ykdNHr.d.mts} +0 -0
- /package/dist/{errors-CCSsMpXE.d.mts → errors-BI8kEKsO.d.mts} +0 -0
- /package/dist/{errors-D5c-5BJL.mjs → errors-BqdUDja_.mjs} +0 -0
- /package/dist/{externalPaths-BQ8QijNH.d.mts → externalPaths-Bapitwvd.d.mts} +0 -0
- /package/dist/{fields-bxkeltzz.mjs → fields-CTMWOUDt.mjs} +0 -0
- /package/dist/{interface-CSbZdv_3.d.mts → interface-B-pe8fhj.d.mts} +0 -0
- /package/dist/{interface-D218ikEo.d.mts → interface-yhyb_pLY.d.mts} +0 -0
- /package/dist/{keys-qcD-TVJl.mjs → keys-nWQGUTu1.mjs} +0 -0
- /package/dist/{loadResources-BAzJItAJ.mjs → loadResources-Bksk8ydA.mjs} +0 -0
- /package/dist/{memory-B5Amv9A1.mjs → memory-DqI-449b.mjs} +0 -0
- /package/dist/{metrics-DuhiSEZI.mjs → metrics-TuOmguhi.mjs} +0 -0
- /package/dist/{pluralize-A0tWEl1K.mjs → pluralize-CWP6MB39.mjs} +0 -0
- /package/dist/{registry-B3lRFBWo.mjs → registry-B0Wl7uVV.mjs} +0 -0
- /package/dist/{replyHelpers-CXtJDAZ0.mjs → replyHelpers-BLojtuvR.mjs} +0 -0
- /package/dist/{sessionManager-BkzVU8h2.d.mts → sessionManager-D-oNWHz3.d.mts} +0 -0
- /package/dist/{storage-CVk_SEn2.d.mts → storage-BwGQXUpd.d.mts} +0 -0
- /package/dist/{tracing-65B51Dw3.d.mts → tracing-xqXzWeaf.d.mts} +0 -0
- /package/dist/{types-Csi3FLfq.mjs → types-CDnTEpga.mjs} +0 -0
- /package/dist/{types-DV9WDfeg.mjs → types-D57iXYb8.mjs} +0 -0
- /package/dist/{types-BD85MlEK.d.mts → types-tgR4Pt8F.d.mts} +0 -0
- /package/dist/{versioning-C2U_bLY0.mjs → versioning-B6mimogM.mjs} +0 -0
package/dist/types/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as
|
|
2
|
-
import { _ as isAuthenticated, c as getOrgRoles, g as hasOrgAccess, n as PUBLIC_SCOPE, p as getTeamId, r as RequestScope, s as getOrgId, t as AUTHENTICATED_SCOPE, v as isElevated, y as isMember } from "../types-
|
|
3
|
-
import { c as PermissionCheck, d as UserBase, l as PermissionContext, u as PermissionResult } from "../fields-
|
|
4
|
-
import {
|
|
1
|
+
import { $t as ObjectId, A as RequestIdOptions, At as FastifyHandler, C as RequestContext, Ct as ResourcePermissions, D as HealthCheck, Dt as RouteSchemaOptions, E as GracefulShutdownOptions, Et as RouteMethod, F as FastifyWithDecorators, Gt as Authenticator, I as MiddlewareHandler, Jt as TokenPair, Kt as AuthenticatorContext, L as RequestWithExtras, M as EventsDecorator, Mt as IControllerResponse, N as FastifyRequestExtras, Nt as IRequestContext, O as HealthOptions, Ot as ControllerHandler, P as FastifyWithAuth, Pt as RouteHandler, Qt as JWTPayload, S as QueryParserInterface, St as ResourceHooks, T as CrudRouterOptions, Tt as RouteMcpConfig, Ut as AuthHelpers, Wt as AuthPluginOptions, Xt as ApiResponse, Yt as AnyRecord, Zt as ArcRequest, _ as ControllerQueryOptions, _t as PresetResult, a as InferAdapterDoc, an as BaseControllerOptions, at as ActionEntry, b as ParsedQuery, bt as ResourceConfig, c as TypedController, ct as CrudController, d as PaginationResult, dt as EventDefinition, en as UserLike, f as IntrospectionData, ft as FieldRule, g as ArcInternalMetadata, gt as PresetHook, h as ResourceMetadata, ht as PresetFunction, i as ValidationResult, it as ActionDefinition, j as ArcDecorator, jt as IController, k as IntrospectionPluginOptions, kt as ControllerLike, l as TypedRepository, lt as CrudRouteKey, m as RegistryStats, mt as OpenApiSchemas, n as ConfigError, nn as envelope, o as InferDocType, ot as ActionHandlerFn, p as RegistryEntry, pt as MiddlewareConfig, qt as JwtContext, r as ValidateOptions, rn as getUserId, s as InferResourceDoc, st as ActionsMap, t as RouteHandlerMethod, tn as UserOrganization, u as TypedResourceConfig, ut as CrudSchemas, v as LookupOption, vt as RateLimitConfig, w as ServiceContext, wt as RouteDefinition, x as PopulateOption, xt as ResourceHookContext, y as OwnershipCheck, yt as ResourceCacheConfig } from "../index-BGbpGVyM.mjs";
|
|
2
|
+
import { _ as isAuthenticated, c as getOrgRoles, g as hasOrgAccess, n as PUBLIC_SCOPE, p as getTeamId, r as RequestScope, s as getOrgId, t as AUTHENTICATED_SCOPE, v as isElevated, y as isMember } from "../types-tgR4Pt8F.mjs";
|
|
3
|
+
import { c as PermissionCheck, d as UserBase, l as PermissionContext, u as PermissionResult } from "../fields-C8Y0XLAu.mjs";
|
|
4
|
+
import { n as ElevationOptions, t as ElevationEvent } from "../elevation-s5ykdNHr.mjs";
|
|
5
5
|
export { AUTHENTICATED_SCOPE, ActionDefinition, ActionEntry, ActionHandlerFn, ActionsMap, AnyRecord, ApiResponse, ArcDecorator, ArcInternalMetadata, ArcRequest, AuthHelpers, AuthPluginOptions, Authenticator, AuthenticatorContext, BaseControllerOptions, ConfigError, ControllerHandler, ControllerLike, ControllerQueryOptions, CrudController, CrudRouteKey, CrudRouterOptions, CrudSchemas, ElevationEvent, ElevationOptions, EventDefinition, EventsDecorator, FastifyHandler, FastifyRequestExtras, FastifyWithAuth, FastifyWithDecorators, FieldRule, GracefulShutdownOptions, HealthCheck, HealthOptions, IController, IControllerResponse, IRequestContext, InferAdapterDoc, InferDocType, InferResourceDoc, IntrospectionData, IntrospectionPluginOptions, JWTPayload, JwtContext, LookupOption, MiddlewareConfig, MiddlewareHandler, ObjectId, OpenApiSchemas, OwnershipCheck, PUBLIC_SCOPE, PaginationResult, ParsedQuery, PermissionCheck, PermissionContext, PermissionResult, PopulateOption, PresetFunction, PresetHook, PresetResult, QueryParserInterface, RateLimitConfig, RegistryEntry, RegistryStats, RequestContext, RequestIdOptions, RequestScope, RequestWithExtras, ResourceCacheConfig, ResourceConfig, ResourceHookContext, ResourceHooks, ResourceMetadata, ResourcePermissions, RouteDefinition, RouteHandler, RouteHandlerMethod, RouteMcpConfig, RouteMethod, RouteSchemaOptions, ServiceContext, TokenPair, TypedController, TypedRepository, TypedResourceConfig, UserBase, UserLike, UserOrganization, ValidateOptions, ValidationResult, envelope, getOrgId, getOrgRoles, getTeamId, getUserId, hasOrgAccess, isAuthenticated, isElevated, isMember };
|
package/dist/types/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { _ as isElevated, f as getTeamId, g as isAuthenticated, h as hasOrgAccess, n as PUBLIC_SCOPE, o as getOrgId, s as getOrgRoles, t as AUTHENTICATED_SCOPE, v as isMember } from "../types-AOD8fxIw.mjs";
|
|
2
|
-
import { n as getUserId, t as envelope } from "../types-
|
|
2
|
+
import { n as getUserId, t as envelope } from "../types-CDnTEpga.mjs";
|
|
3
3
|
export { AUTHENTICATED_SCOPE, PUBLIC_SCOPE, envelope, getOrgId, getOrgRoles, getTeamId, getUserId, hasOrgAccess, isAuthenticated, isElevated, isMember };
|
package/dist/types/storage.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as StorageReadResult, i as StorageReadRange, n as StorageContext, o as StorageUploadInput, r as StorageFile, t as Storage } from "../storage-
|
|
1
|
+
import { a as StorageReadResult, i as StorageReadRange, n as StorageContext, o as StorageUploadInput, r as StorageFile, t as Storage } from "../storage-BwGQXUpd.mjs";
|
|
2
2
|
export { Storage, StorageContext, StorageFile, StorageReadRange, StorageReadResult, StorageUploadInput };
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { o as EventTransport } from "./EventTransport-
|
|
4
|
-
import { t as ExternalOpenApiPaths } from "./externalPaths-
|
|
5
|
-
import { r as CacheStore } from "./interface-
|
|
6
|
-
import { r as QueryCachePluginOptions } from "./queryCachePlugin-
|
|
7
|
-
import { t as EventPluginOptions } from "./eventPlugin-
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
1
|
+
import { Gt as Authenticator } from "./index-BGbpGVyM.mjs";
|
|
2
|
+
import { n as ElevationOptions } from "./elevation-s5ykdNHr.mjs";
|
|
3
|
+
import { o as EventTransport } from "./EventTransport-CfVEGaEl.mjs";
|
|
4
|
+
import { t as ExternalOpenApiPaths } from "./externalPaths-Bapitwvd.mjs";
|
|
5
|
+
import { r as CacheStore } from "./interface-yhyb_pLY.mjs";
|
|
6
|
+
import { r as QueryCachePluginOptions } from "./queryCachePlugin-Dumka73q.mjs";
|
|
7
|
+
import { t as EventPluginOptions } from "./eventPlugin-D1ThQ1Pp.mjs";
|
|
8
|
+
import { f as CachingOptions, l as SSEOptions, o as MetricsOptions, t as VersioningOptions } from "./versioning-CeUXHfjw.mjs";
|
|
9
|
+
import { t as ErrorHandlerOptions } from "./errorHandler-2ii4RIYr.mjs";
|
|
10
|
+
import { r as IdempotencyStore } from "./interface-B-pe8fhj.mjs";
|
|
10
11
|
import { FastifyInstance, FastifyPluginAsync, FastifyReply, FastifyRequest, FastifyServerOptions } from "fastify";
|
|
11
12
|
|
|
12
13
|
//#region src/factory/loadResources.d.ts
|
|
@@ -149,6 +150,18 @@ type HelmetOptions = Record<string, unknown>;
|
|
|
149
150
|
type RateLimitOpts = Record<string, unknown> & {
|
|
150
151
|
max?: number;
|
|
151
152
|
timeWindow?: string | number;
|
|
153
|
+
/**
|
|
154
|
+
* Path patterns to exempt from rate limiting. Supports exact match
|
|
155
|
+
* (`/health`) or prefix match with trailing `*` (`/api/auth/*`).
|
|
156
|
+
*
|
|
157
|
+
* Implemented by synthesising a `@fastify/rate-limit` `allowList`
|
|
158
|
+
* function. When combined with a user-supplied `allowList`, both
|
|
159
|
+
* are OR-ed together (path OR ip/custom match skips the limit).
|
|
160
|
+
*
|
|
161
|
+
* Use this for endpoints that are hit frequently but independently
|
|
162
|
+
* of user traffic — session heartbeat, webhooks, health probes.
|
|
163
|
+
*/
|
|
164
|
+
skipPaths?: string[];
|
|
152
165
|
};
|
|
153
166
|
/**
|
|
154
167
|
* Arc's built-in JWT auth
|
package/dist/utils/index.d.mts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { S as QueryParserInterface, Yt as AnyRecord, b as ParsedQuery, mt as OpenApiSchemas } from "../index-BGbpGVyM.mjs";
|
|
2
|
+
import { n as ErrorMapper } from "../errorHandler-2ii4RIYr.mjs";
|
|
3
|
+
import { a as NotFoundError, c as RateLimitError, d as ValidationError, f as createDomainError, i as ForbiddenError, l as ServiceUnavailableError, m as isArcError, n as ConflictError, o as OrgAccessDeniedError, p as createError, r as ErrorDetails, s as OrgRequiredError, t as ArcError, u as UnauthorizedError } from "../errors-BI8kEKsO.mjs";
|
|
3
4
|
import { FastifyInstance, FastifyReply, FastifyRequest, RouteHandlerMethod } from "fastify";
|
|
4
5
|
|
|
5
6
|
//#region src/utils/circuitBreaker.d.ts
|
|
@@ -296,6 +297,22 @@ interface CompensationDefinition<TCtx extends Record<string, unknown> = Record<s
|
|
|
296
297
|
}
|
|
297
298
|
declare function defineCompensation<TCtx extends Record<string, unknown> = Record<string, unknown>>(name: string, steps: readonly CompensationStep<TCtx>[]): CompensationDefinition<TCtx>;
|
|
298
299
|
//#endregion
|
|
300
|
+
//#region src/utils/defineErrorMapper.d.ts
|
|
301
|
+
/**
|
|
302
|
+
* Register an `ErrorMapper` with its domain-specific generic argument and
|
|
303
|
+
* have it assign cleanly into `ErrorMapper[]` (no `as unknown as ErrorMapper`).
|
|
304
|
+
*
|
|
305
|
+
* The returned mapper is identical at runtime — `type` and `toResponse` are
|
|
306
|
+
* passed through untouched. Only the declared type widens from
|
|
307
|
+
* `ErrorMapper<T>` to `ErrorMapper` so the array inference works.
|
|
308
|
+
*
|
|
309
|
+
* Safety: the `errorHandlerPlugin` dispatches via `error instanceof mapper.type`
|
|
310
|
+
* before invoking `toResponse`, so the widened callback signature is never
|
|
311
|
+
* called with a non-`T` error at runtime. This helper codifies that invariant
|
|
312
|
+
* in one place.
|
|
313
|
+
*/
|
|
314
|
+
declare function defineErrorMapper<T extends Error>(mapper: ErrorMapper<T>): ErrorMapper;
|
|
315
|
+
//#endregion
|
|
299
316
|
//#region src/utils/defineGuard.d.ts
|
|
300
317
|
interface GuardConfig<T> {
|
|
301
318
|
/** Unique name — used as the storage key on the request. */
|
|
@@ -765,6 +782,59 @@ declare function convertOpenApiSchemas(schemas: OpenApiSchemas, target?: JsonSch
|
|
|
765
782
|
*/
|
|
766
783
|
declare function convertRouteSchema(schema: Record<string, unknown>, target?: JsonSchemaTarget): Record<string, unknown>;
|
|
767
784
|
//#endregion
|
|
785
|
+
//#region src/utils/simpleEqualityMatcher.d.ts
|
|
786
|
+
/**
|
|
787
|
+
* `simpleEqualityMatcher` — a minimal, dialect-agnostic flat-key equality
|
|
788
|
+
* matcher for `DataAdapter.matchesFilter` / `BaseController({ matchesFilter })`.
|
|
789
|
+
*
|
|
790
|
+
* **What it does:** for each `[key, expected]` in the filter, compares
|
|
791
|
+
* `item[key]` to `expected` via string coercion (so Mongo `ObjectId` values
|
|
792
|
+
* match their string representation) and returns `true` only if every
|
|
793
|
+
* filter entry matches. Array item values are matched implicitly (contains).
|
|
794
|
+
*
|
|
795
|
+
* **What it does NOT do:**
|
|
796
|
+
* - No `$eq` / `$ne` / `$in` / `$nin` / `$gt` / `$lt` / `$regex` / `$exists`
|
|
797
|
+
* - No `$and` / `$or`
|
|
798
|
+
* - No dot-path traversal (`"owner.id"`)
|
|
799
|
+
* - No schema-specific coercion
|
|
800
|
+
*
|
|
801
|
+
* **Why it exists:** 95%+ of arc's `_policyFilters` are produced by built-in
|
|
802
|
+
* permission helpers and are shaped like `{ ownerId: "u1" }` or
|
|
803
|
+
* `{ organizationId: "org_x" }` — flat equality. For that common shape,
|
|
804
|
+
* this helper is a safe, tested, 15-line defense-in-depth matcher that
|
|
805
|
+
* hosts using minimal repos (no `getOne(compoundFilter)` DB path) can opt
|
|
806
|
+
* into without arc shipping a full Mongo-syntax engine.
|
|
807
|
+
*
|
|
808
|
+
* **When to use:**
|
|
809
|
+
* - Your adapter/repo doesn't natively filter on `getOne(compoundFilter)`
|
|
810
|
+
* - Your `_policyFilters` are flat equality (from arc's built-in permission helpers)
|
|
811
|
+
* - You want defense-in-depth on `validateItemAccess` / `fetchDetailed`'s `getById` fallback
|
|
812
|
+
*
|
|
813
|
+
* **When NOT to use:**
|
|
814
|
+
* - Your `_policyFilters` use operators (`$in`, `$ne`, etc.) — supply a
|
|
815
|
+
* native matcher (mongokit's repo does the filter at the DB layer; for
|
|
816
|
+
* custom repos, wrap the kit's own predicate engine).
|
|
817
|
+
* - You're a mongokit / sqlitekit / Prisma user — the DB-level filter
|
|
818
|
+
* applied by `getOne(compoundFilter)` already covers this.
|
|
819
|
+
*
|
|
820
|
+
* @example
|
|
821
|
+
* ```ts
|
|
822
|
+
* import { simpleEqualityMatcher } from '@classytic/arc/utils';
|
|
823
|
+
*
|
|
824
|
+
* // On a custom adapter
|
|
825
|
+
* const adapter: DataAdapter = {
|
|
826
|
+
* repository,
|
|
827
|
+
* type: 'custom',
|
|
828
|
+
* name: 'in-memory',
|
|
829
|
+
* matchesFilter: simpleEqualityMatcher,
|
|
830
|
+
* };
|
|
831
|
+
*
|
|
832
|
+
* // Or directly on BaseController for ad-hoc controllers
|
|
833
|
+
* new BaseController(repo, { matchesFilter: simpleEqualityMatcher });
|
|
834
|
+
* ```
|
|
835
|
+
*/
|
|
836
|
+
declare function simpleEqualityMatcher(item: unknown, filters: Record<string, unknown>): boolean;
|
|
837
|
+
//#endregion
|
|
768
838
|
//#region src/utils/stateMachine.d.ts
|
|
769
839
|
/**
|
|
770
840
|
* State Machine Utility
|
|
@@ -895,4 +965,4 @@ declare function hasEvents(instance: FastifyInstance): instance is FastifyInstan
|
|
|
895
965
|
events: EventsDecorator;
|
|
896
966
|
};
|
|
897
967
|
//#endregion
|
|
898
|
-
export { ArcError, ArcQueryParser, type ArcQueryParserOptions, CircuitBreaker, CircuitBreakerError, type CircuitBreakerOptions, CircuitBreakerRegistry, type CircuitBreakerStats, CircuitState, type CompensationDefinition, type CompensationError, type CompensationHooks, type CompensationResult, type CompensationStep, ConflictError, type ErrorDetails, type EventsDecorator, ForbiddenError, type Guard, type GuardConfig, type JsonSchema, type JsonSchemaTarget, NotFoundError, OrgAccessDeniedError, OrgRequiredError, RateLimitError, ServiceUnavailableError, type StateMachine, type TransitionConfig, UnauthorizedError, ValidationError, convertOpenApiSchemas, convertRouteSchema, createCircuitBreaker, createCircuitBreakerRegistry, createDomainError, createError, createQueryParser, createStateMachine, defineCompensation, defineGuard, deleteResponse, errorResponseSchema, getDefaultCrudSchemas, getListQueryParams, handleRaw, hasEvents, isArcError, isJsonSchema, isZodSchema, itemResponse, listResponse, mutationResponse, paginationSchema, queryParams, responses, successResponseSchema, toJsonSchema, withCompensation, wrapResponse };
|
|
968
|
+
export { ArcError, ArcQueryParser, type ArcQueryParserOptions, CircuitBreaker, CircuitBreakerError, type CircuitBreakerOptions, CircuitBreakerRegistry, type CircuitBreakerStats, CircuitState, type CompensationDefinition, type CompensationError, type CompensationHooks, type CompensationResult, type CompensationStep, ConflictError, type ErrorDetails, type EventsDecorator, ForbiddenError, type Guard, type GuardConfig, type JsonSchema, type JsonSchemaTarget, NotFoundError, OrgAccessDeniedError, OrgRequiredError, RateLimitError, ServiceUnavailableError, type StateMachine, type TransitionConfig, UnauthorizedError, ValidationError, convertOpenApiSchemas, convertRouteSchema, createCircuitBreaker, createCircuitBreakerRegistry, createDomainError, createError, createQueryParser, createStateMachine, defineCompensation, defineErrorMapper, defineGuard, deleteResponse, errorResponseSchema, getDefaultCrudSchemas, getListQueryParams, handleRaw, hasEvents, isArcError, isJsonSchema, isZodSchema, itemResponse, listResponse, mutationResponse, paginationSchema, queryParams, responses, simpleEqualityMatcher, successResponseSchema, toJsonSchema, withCompensation, wrapResponse };
|
package/dist/utils/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as
|
|
3
|
-
import { C as
|
|
1
|
+
import { n as createQueryParser, r as simpleEqualityMatcher, t as ArcQueryParser } from "../queryParser-NR__Qiju.mjs";
|
|
2
|
+
import { a as OrgAccessDeniedError, c as ServiceUnavailableError, d as createDomainError, f as createError, i as NotFoundError, l as UnauthorizedError, n as ConflictError, o as OrgRequiredError, p as isArcError, r as ForbiddenError, s as RateLimitError, t as ArcError, u as ValidationError } from "../errors-BqdUDja_.mjs";
|
|
3
|
+
import { C as createCircuitBreaker, S as CircuitState, _ as defineCompensation, a as getListQueryParams, b as CircuitBreakerError, c as mutationResponse, d as responses, f as successResponseSchema, g as defineErrorMapper, h as defineGuard, i as getDefaultCrudSchemas, l as paginationSchema, m as handleRaw, n as deleteResponse, o as itemResponse, p as wrapResponse, r as errorResponseSchema, s as listResponse, t as createStateMachine, u as queryParams, v as withCompensation, w as createCircuitBreakerRegistry, x as CircuitBreakerRegistry, y as CircuitBreaker } from "../utils-LMwVidKy.mjs";
|
|
4
4
|
import { a as toJsonSchema, i as isZodSchema, n as convertRouteSchema, r as isJsonSchema, t as convertOpenApiSchemas } from "../schemaConverter-BxFDdtXu.mjs";
|
|
5
5
|
import { t as hasEvents } from "../typeGuards-Cj5Rgvlg.mjs";
|
|
6
|
-
export { ArcError, ArcQueryParser, CircuitBreaker, CircuitBreakerError, CircuitBreakerRegistry, CircuitState, ConflictError, ForbiddenError, NotFoundError, OrgAccessDeniedError, OrgRequiredError, RateLimitError, ServiceUnavailableError, UnauthorizedError, ValidationError, convertOpenApiSchemas, convertRouteSchema, createCircuitBreaker, createCircuitBreakerRegistry, createDomainError, createError, createQueryParser, createStateMachine, defineCompensation, defineGuard, deleteResponse, errorResponseSchema, getDefaultCrudSchemas, getListQueryParams, handleRaw, hasEvents, isArcError, isJsonSchema, isZodSchema, itemResponse, listResponse, mutationResponse, paginationSchema, queryParams, responses, successResponseSchema, toJsonSchema, withCompensation, wrapResponse };
|
|
6
|
+
export { ArcError, ArcQueryParser, CircuitBreaker, CircuitBreakerError, CircuitBreakerRegistry, CircuitState, ConflictError, ForbiddenError, NotFoundError, OrgAccessDeniedError, OrgRequiredError, RateLimitError, ServiceUnavailableError, UnauthorizedError, ValidationError, convertOpenApiSchemas, convertRouteSchema, createCircuitBreaker, createCircuitBreakerRegistry, createDomainError, createError, createQueryParser, createStateMachine, defineCompensation, defineErrorMapper, defineGuard, deleteResponse, errorResponseSchema, getDefaultCrudSchemas, getListQueryParams, handleRaw, hasEvents, isArcError, isJsonSchema, isZodSchema, itemResponse, listResponse, mutationResponse, paginationSchema, queryParams, responses, simpleEqualityMatcher, successResponseSchema, toJsonSchema, withCompensation, wrapResponse };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as ArcError } from "./errors-
|
|
1
|
+
import { t as ArcError } from "./errors-BqdUDja_.mjs";
|
|
2
2
|
//#region src/utils/circuitBreaker.ts
|
|
3
3
|
/**
|
|
4
4
|
* Circuit Breaker Pattern
|
|
@@ -353,6 +353,24 @@ function defineCompensation(name, steps) {
|
|
|
353
353
|
};
|
|
354
354
|
}
|
|
355
355
|
//#endregion
|
|
356
|
+
//#region src/utils/defineErrorMapper.ts
|
|
357
|
+
/**
|
|
358
|
+
* Register an `ErrorMapper` with its domain-specific generic argument and
|
|
359
|
+
* have it assign cleanly into `ErrorMapper[]` (no `as unknown as ErrorMapper`).
|
|
360
|
+
*
|
|
361
|
+
* The returned mapper is identical at runtime — `type` and `toResponse` are
|
|
362
|
+
* passed through untouched. Only the declared type widens from
|
|
363
|
+
* `ErrorMapper<T>` to `ErrorMapper` so the array inference works.
|
|
364
|
+
*
|
|
365
|
+
* Safety: the `errorHandlerPlugin` dispatches via `error instanceof mapper.type`
|
|
366
|
+
* before invoking `toResponse`, so the widened callback signature is never
|
|
367
|
+
* called with a non-`T` error at runtime. This helper codifies that invariant
|
|
368
|
+
* in one place.
|
|
369
|
+
*/
|
|
370
|
+
function defineErrorMapper(mapper) {
|
|
371
|
+
return mapper;
|
|
372
|
+
}
|
|
373
|
+
//#endregion
|
|
356
374
|
//#region src/utils/defineGuard.ts
|
|
357
375
|
/** Hidden property key for guard context storage on the request object. */
|
|
358
376
|
const GUARD_STORE_KEY = "__arcGuardContext";
|
|
@@ -926,4 +944,4 @@ function createStateMachine(name, transitions = {}, options = {}) {
|
|
|
926
944
|
};
|
|
927
945
|
}
|
|
928
946
|
//#endregion
|
|
929
|
-
export {
|
|
947
|
+
export { createCircuitBreaker as C, CircuitState as S, defineCompensation as _, getListQueryParams as a, CircuitBreakerError as b, mutationResponse as c, responses as d, successResponseSchema as f, defineErrorMapper as g, defineGuard as h, getDefaultCrudSchemas as i, paginationSchema as l, handleRaw as m, deleteResponse as n, itemResponse as o, wrapResponse as p, errorResponseSchema as r, listResponse as s, createStateMachine as t, queryParams as u, withCompensation as v, createCircuitBreakerRegistry as w, CircuitBreakerRegistry as x, CircuitBreaker as y };
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { n as DomainEvent } from "./EventTransport-CfVEGaEl.mjs";
|
|
2
|
+
import { FastifyPluginAsync, FastifyRequest } from "fastify";
|
|
3
|
+
|
|
4
|
+
//#region src/plugins/caching.d.ts
|
|
5
|
+
interface CachingRule {
|
|
6
|
+
/** Path prefix to match (e.g., '/api/products') */
|
|
7
|
+
match: string;
|
|
8
|
+
/** Cache-Control max-age in seconds */
|
|
9
|
+
maxAge: number;
|
|
10
|
+
/** Cache-Control: private vs public (default: public) */
|
|
11
|
+
private?: boolean;
|
|
12
|
+
/** stale-while-revalidate directive in seconds */
|
|
13
|
+
staleWhileRevalidate?: number;
|
|
14
|
+
}
|
|
15
|
+
interface CachingOptions {
|
|
16
|
+
/** Default max-age in seconds for Cache-Control (default: 0 = no-cache) */
|
|
17
|
+
maxAge?: number;
|
|
18
|
+
/** Enable ETag generation (default: true) */
|
|
19
|
+
etag?: boolean;
|
|
20
|
+
/** Enable conditional requests — 304 Not Modified (default: true) */
|
|
21
|
+
conditional?: boolean;
|
|
22
|
+
/** HTTP methods to cache (default: ['GET', 'HEAD']) */
|
|
23
|
+
methods?: string[];
|
|
24
|
+
/** Paths to exclude from caching (prefix match) */
|
|
25
|
+
exclude?: string[];
|
|
26
|
+
/** Custom cache rules per path prefix */
|
|
27
|
+
rules?: CachingRule[];
|
|
28
|
+
}
|
|
29
|
+
declare const cachingPlugin: FastifyPluginAsync<CachingOptions>;
|
|
30
|
+
declare const _default$3: FastifyPluginAsync<CachingOptions>;
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/plugins/sse.d.ts
|
|
33
|
+
interface SSEOptions {
|
|
34
|
+
/** SSE endpoint path (default: '/events/stream') */
|
|
35
|
+
path?: string;
|
|
36
|
+
/** Require authentication (default: true) */
|
|
37
|
+
requireAuth?: boolean;
|
|
38
|
+
/** Event patterns to stream (default: ['*'] = all) */
|
|
39
|
+
patterns?: string[];
|
|
40
|
+
/** Heartbeat interval in ms (default: 30000) */
|
|
41
|
+
heartbeat?: number;
|
|
42
|
+
/** Filter events by organizationId from request.scope (default: false) */
|
|
43
|
+
orgScoped?: boolean;
|
|
44
|
+
/** Custom event filter function */
|
|
45
|
+
filter?: (event: DomainEvent<unknown>, request: FastifyRequest) => boolean;
|
|
46
|
+
}
|
|
47
|
+
declare const ssePlugin: FastifyPluginAsync<SSEOptions>;
|
|
48
|
+
declare const _default$2: FastifyPluginAsync<SSEOptions>;
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/plugins/metrics.d.ts
|
|
51
|
+
interface MetricsOptions {
|
|
52
|
+
/** Endpoint path (default: '/_metrics') */
|
|
53
|
+
path?: string;
|
|
54
|
+
/** Prefix for all metric names (default: 'arc') */
|
|
55
|
+
prefix?: string;
|
|
56
|
+
/** Called after metrics are collected (for OTLP push, etc.) */
|
|
57
|
+
onCollect?: (metrics: MetricEntry[]) => void;
|
|
58
|
+
}
|
|
59
|
+
interface MetricEntry {
|
|
60
|
+
name: string;
|
|
61
|
+
type: "counter" | "histogram" | "gauge";
|
|
62
|
+
help: string;
|
|
63
|
+
values: Array<{
|
|
64
|
+
labels: Record<string, string>;
|
|
65
|
+
value: number;
|
|
66
|
+
}>;
|
|
67
|
+
}
|
|
68
|
+
interface MetricsCollector {
|
|
69
|
+
/** Get all metrics as structured data */
|
|
70
|
+
collect(): MetricEntry[];
|
|
71
|
+
/** Reset all metrics */
|
|
72
|
+
reset(): void;
|
|
73
|
+
/** Record a CRUD operation */
|
|
74
|
+
recordOperation(resource: string, operation: string, status: number, durationMs: number): void;
|
|
75
|
+
/** Record a cache hit */
|
|
76
|
+
recordCacheHit(resource: string): void;
|
|
77
|
+
/** Record a cache miss */
|
|
78
|
+
recordCacheMiss(resource: string): void;
|
|
79
|
+
/** Record an event publish */
|
|
80
|
+
recordEventPublish(eventType: string): void;
|
|
81
|
+
/** Record an event consume */
|
|
82
|
+
recordEventConsume(eventType: string): void;
|
|
83
|
+
/** Record a circuit breaker state change */
|
|
84
|
+
recordCircuitBreakerState(service: string, state: string): void;
|
|
85
|
+
}
|
|
86
|
+
declare module "fastify" {
|
|
87
|
+
interface FastifyInstance {
|
|
88
|
+
metrics: MetricsCollector;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
declare const metricsPlugin: FastifyPluginAsync<MetricsOptions>;
|
|
92
|
+
declare const _default$1: FastifyPluginAsync<MetricsOptions>;
|
|
93
|
+
//#endregion
|
|
94
|
+
//#region src/plugins/versioning.d.ts
|
|
95
|
+
interface VersioningOptions {
|
|
96
|
+
/** Versioning strategy */
|
|
97
|
+
type: "header" | "prefix";
|
|
98
|
+
/** Default version when none specified (default: '1') */
|
|
99
|
+
defaultVersion?: string;
|
|
100
|
+
/** Header name to read (default: 'accept-version') */
|
|
101
|
+
headerName?: string;
|
|
102
|
+
/** Response header name (default: 'x-api-version') */
|
|
103
|
+
responseHeader?: string;
|
|
104
|
+
/** Deprecated versions — adds Deprecation + Sunset headers */
|
|
105
|
+
deprecated?: string[];
|
|
106
|
+
/** Sunset date for deprecated versions (ISO 8601) */
|
|
107
|
+
sunset?: string;
|
|
108
|
+
}
|
|
109
|
+
declare module "fastify" {
|
|
110
|
+
interface FastifyRequest {
|
|
111
|
+
apiVersion: string;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
declare const versioningPlugin: FastifyPluginAsync<VersioningOptions>;
|
|
115
|
+
declare const _default: FastifyPluginAsync<VersioningOptions>;
|
|
116
|
+
//#endregion
|
|
117
|
+
export { MetricsCollector as a, metricsPlugin as c, ssePlugin as d, CachingOptions as f, cachingPlugin as h, MetricEntry as i, SSEOptions as l, _default$3 as m, _default as n, MetricsOptions as o, CachingRule as p, versioningPlugin as r, _default$1 as s, VersioningOptions as t, _default$2 as u };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@classytic/arc",
|
|
3
|
-
"version": "2.10.
|
|
3
|
+
"version": "2.10.8",
|
|
4
4
|
"description": "Resource-oriented backend framework for Fastify — clean, minimal, powerful, tree-shakable",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -64,6 +64,22 @@
|
|
|
64
64
|
"types": "./dist/hooks/index.d.mts",
|
|
65
65
|
"default": "./dist/hooks/index.mjs"
|
|
66
66
|
},
|
|
67
|
+
"./middleware": {
|
|
68
|
+
"types": "./dist/middleware/index.d.mts",
|
|
69
|
+
"default": "./dist/middleware/index.mjs"
|
|
70
|
+
},
|
|
71
|
+
"./pipeline": {
|
|
72
|
+
"types": "./dist/pipeline/index.d.mts",
|
|
73
|
+
"default": "./dist/pipeline/index.mjs"
|
|
74
|
+
},
|
|
75
|
+
"./context": {
|
|
76
|
+
"types": "./dist/context/index.d.mts",
|
|
77
|
+
"default": "./dist/context/index.mjs"
|
|
78
|
+
},
|
|
79
|
+
"./logger": {
|
|
80
|
+
"types": "./dist/logger/index.d.mts",
|
|
81
|
+
"default": "./dist/logger/index.mjs"
|
|
82
|
+
},
|
|
67
83
|
"./registry": {
|
|
68
84
|
"types": "./dist/registry/index.d.mts",
|
|
69
85
|
"default": "./dist/registry/index.mjs"
|
|
@@ -223,8 +239,8 @@
|
|
|
223
239
|
"node": ">=22"
|
|
224
240
|
},
|
|
225
241
|
"peerDependencies": {
|
|
226
|
-
"@classytic/mongokit": ">=3.
|
|
227
|
-
"@classytic/repo-core": ">=0.
|
|
242
|
+
"@classytic/mongokit": ">=3.11.0",
|
|
243
|
+
"@classytic/repo-core": ">=0.2.0",
|
|
228
244
|
"@classytic/streamline": ">=2.1.0",
|
|
229
245
|
"@fastify/cors": ">=11.0.0",
|
|
230
246
|
"@fastify/helmet": ">=13.0.0",
|
|
@@ -347,9 +363,9 @@
|
|
|
347
363
|
"@better-auth/drizzle-adapter": "^1.6.2",
|
|
348
364
|
"@better-auth/mongo-adapter": "^1.6.2",
|
|
349
365
|
"@biomejs/biome": "^2.4.11",
|
|
350
|
-
"@classytic/mongokit": "^3.
|
|
351
|
-
"@classytic/repo-core": "^0.
|
|
352
|
-
"@classytic/sqlitekit": "^0.
|
|
366
|
+
"@classytic/mongokit": "^3.11.0",
|
|
367
|
+
"@classytic/repo-core": "^0.2.0",
|
|
368
|
+
"@classytic/sqlitekit": "^0.2.0",
|
|
353
369
|
"@classytic/streamline": "^2.1.0",
|
|
354
370
|
"@fastify/cors": "^11.2.0",
|
|
355
371
|
"@fastify/helmet": "^13.0.2",
|
package/skills/arc/SKILL.md
CHANGED
|
@@ -787,7 +787,7 @@ afterUpdate(hooks, 'product', async (ctx) => { await invalidateCache(ctx.result.
|
|
|
787
787
|
## Pipeline
|
|
788
788
|
|
|
789
789
|
```typescript
|
|
790
|
-
import { guard, transform, intercept } from '@classytic/arc';
|
|
790
|
+
import { guard, transform, intercept } from '@classytic/arc/pipeline';
|
|
791
791
|
|
|
792
792
|
defineResource({
|
|
793
793
|
pipe: {
|
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
import { n as DomainEvent } from "./EventTransport-CUw5NNWe.mjs";
|
|
2
|
-
import { FastifyInstance, FastifyPluginAsync, FastifyRequest } from "fastify";
|
|
3
|
-
|
|
4
|
-
//#region src/plugins/caching.d.ts
|
|
5
|
-
interface CachingRule {
|
|
6
|
-
/** Path prefix to match (e.g., '/api/products') */
|
|
7
|
-
match: string;
|
|
8
|
-
/** Cache-Control max-age in seconds */
|
|
9
|
-
maxAge: number;
|
|
10
|
-
/** Cache-Control: private vs public (default: public) */
|
|
11
|
-
private?: boolean;
|
|
12
|
-
/** stale-while-revalidate directive in seconds */
|
|
13
|
-
staleWhileRevalidate?: number;
|
|
14
|
-
}
|
|
15
|
-
interface CachingOptions {
|
|
16
|
-
/** Default max-age in seconds for Cache-Control (default: 0 = no-cache) */
|
|
17
|
-
maxAge?: number;
|
|
18
|
-
/** Enable ETag generation (default: true) */
|
|
19
|
-
etag?: boolean;
|
|
20
|
-
/** Enable conditional requests — 304 Not Modified (default: true) */
|
|
21
|
-
conditional?: boolean;
|
|
22
|
-
/** HTTP methods to cache (default: ['GET', 'HEAD']) */
|
|
23
|
-
methods?: string[];
|
|
24
|
-
/** Paths to exclude from caching (prefix match) */
|
|
25
|
-
exclude?: string[];
|
|
26
|
-
/** Custom cache rules per path prefix */
|
|
27
|
-
rules?: CachingRule[];
|
|
28
|
-
}
|
|
29
|
-
declare const cachingPlugin: FastifyPluginAsync<CachingOptions>;
|
|
30
|
-
declare const _default$3: FastifyPluginAsync<CachingOptions>;
|
|
31
|
-
//#endregion
|
|
32
|
-
//#region src/plugins/sse.d.ts
|
|
33
|
-
interface SSEOptions {
|
|
34
|
-
/** SSE endpoint path (default: '/events/stream') */
|
|
35
|
-
path?: string;
|
|
36
|
-
/** Require authentication (default: true) */
|
|
37
|
-
requireAuth?: boolean;
|
|
38
|
-
/** Event patterns to stream (default: ['*'] = all) */
|
|
39
|
-
patterns?: string[];
|
|
40
|
-
/** Heartbeat interval in ms (default: 30000) */
|
|
41
|
-
heartbeat?: number;
|
|
42
|
-
/** Filter events by organizationId from request.scope (default: false) */
|
|
43
|
-
orgScoped?: boolean;
|
|
44
|
-
/** Custom event filter function */
|
|
45
|
-
filter?: (event: DomainEvent<unknown>, request: FastifyRequest) => boolean;
|
|
46
|
-
}
|
|
47
|
-
declare const ssePlugin: FastifyPluginAsync<SSEOptions>;
|
|
48
|
-
declare const _default$2: FastifyPluginAsync<SSEOptions>;
|
|
49
|
-
//#endregion
|
|
50
|
-
//#region src/plugins/metrics.d.ts
|
|
51
|
-
interface MetricsOptions {
|
|
52
|
-
/** Endpoint path (default: '/_metrics') */
|
|
53
|
-
path?: string;
|
|
54
|
-
/** Prefix for all metric names (default: 'arc') */
|
|
55
|
-
prefix?: string;
|
|
56
|
-
/** Called after metrics are collected (for OTLP push, etc.) */
|
|
57
|
-
onCollect?: (metrics: MetricEntry[]) => void;
|
|
58
|
-
}
|
|
59
|
-
interface MetricEntry {
|
|
60
|
-
name: string;
|
|
61
|
-
type: "counter" | "histogram" | "gauge";
|
|
62
|
-
help: string;
|
|
63
|
-
values: Array<{
|
|
64
|
-
labels: Record<string, string>;
|
|
65
|
-
value: number;
|
|
66
|
-
}>;
|
|
67
|
-
}
|
|
68
|
-
interface MetricsCollector {
|
|
69
|
-
/** Get all metrics as structured data */
|
|
70
|
-
collect(): MetricEntry[];
|
|
71
|
-
/** Reset all metrics */
|
|
72
|
-
reset(): void;
|
|
73
|
-
/** Record a CRUD operation */
|
|
74
|
-
recordOperation(resource: string, operation: string, status: number, durationMs: number): void;
|
|
75
|
-
/** Record a cache hit */
|
|
76
|
-
recordCacheHit(resource: string): void;
|
|
77
|
-
/** Record a cache miss */
|
|
78
|
-
recordCacheMiss(resource: string): void;
|
|
79
|
-
/** Record an event publish */
|
|
80
|
-
recordEventPublish(eventType: string): void;
|
|
81
|
-
/** Record an event consume */
|
|
82
|
-
recordEventConsume(eventType: string): void;
|
|
83
|
-
/** Record a circuit breaker state change */
|
|
84
|
-
recordCircuitBreakerState(service: string, state: string): void;
|
|
85
|
-
}
|
|
86
|
-
declare module "fastify" {
|
|
87
|
-
interface FastifyInstance {
|
|
88
|
-
metrics: MetricsCollector;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
declare const metricsPlugin: FastifyPluginAsync<MetricsOptions>;
|
|
92
|
-
declare const _default$1: FastifyPluginAsync<MetricsOptions>;
|
|
93
|
-
//#endregion
|
|
94
|
-
//#region src/plugins/versioning.d.ts
|
|
95
|
-
interface VersioningOptions {
|
|
96
|
-
/** Versioning strategy */
|
|
97
|
-
type: "header" | "prefix";
|
|
98
|
-
/** Default version when none specified (default: '1') */
|
|
99
|
-
defaultVersion?: string;
|
|
100
|
-
/** Header name to read (default: 'accept-version') */
|
|
101
|
-
headerName?: string;
|
|
102
|
-
/** Response header name (default: 'x-api-version') */
|
|
103
|
-
responseHeader?: string;
|
|
104
|
-
/** Deprecated versions — adds Deprecation + Sunset headers */
|
|
105
|
-
deprecated?: string[];
|
|
106
|
-
/** Sunset date for deprecated versions (ISO 8601) */
|
|
107
|
-
sunset?: string;
|
|
108
|
-
}
|
|
109
|
-
declare module "fastify" {
|
|
110
|
-
interface FastifyRequest {
|
|
111
|
-
apiVersion: string;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
declare const versioningPlugin: FastifyPluginAsync<VersioningOptions>;
|
|
115
|
-
declare const _default: FastifyPluginAsync<VersioningOptions>;
|
|
116
|
-
//#endregion
|
|
117
|
-
//#region src/plugins/errorHandler.d.ts
|
|
118
|
-
/** Class-based error mapper — maps thrown error instances to HTTP responses */
|
|
119
|
-
interface ErrorMapper<T extends Error = Error> {
|
|
120
|
-
/** Error class to match (uses instanceof) */
|
|
121
|
-
type: new (...args: unknown[]) => T;
|
|
122
|
-
/** Convert the error to an HTTP response shape */
|
|
123
|
-
toResponse: (error: T) => {
|
|
124
|
-
status: number;
|
|
125
|
-
code?: string;
|
|
126
|
-
message?: string;
|
|
127
|
-
details?: Record<string, unknown>;
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
interface ErrorHandlerOptions {
|
|
131
|
-
/**
|
|
132
|
-
* Include stack trace in error responses (default: false in production)
|
|
133
|
-
*/
|
|
134
|
-
includeStack?: boolean;
|
|
135
|
-
/**
|
|
136
|
-
* Custom error callback for logging to external services
|
|
137
|
-
*/
|
|
138
|
-
onError?: (error: Error, request: FastifyRequest) => void | Promise<void>;
|
|
139
|
-
/**
|
|
140
|
-
* Map specific error types to custom responses (by error.name string)
|
|
141
|
-
*/
|
|
142
|
-
errorMap?: Record<string, {
|
|
143
|
-
statusCode: number;
|
|
144
|
-
code: string;
|
|
145
|
-
message?: string;
|
|
146
|
-
}>;
|
|
147
|
-
/**
|
|
148
|
-
* Class-based error mappers — checked via `instanceof`, highest priority.
|
|
149
|
-
*
|
|
150
|
-
* Register your domain error classes once; Arc auto-catches and maps them
|
|
151
|
-
* in every handler. Handlers just `throw` — no try/catch needed.
|
|
152
|
-
*
|
|
153
|
-
* @example
|
|
154
|
-
* ```typescript
|
|
155
|
-
* class AccountingError extends Error {
|
|
156
|
-
* constructor(message: string, public status: number, public code: string) {
|
|
157
|
-
* super(message);
|
|
158
|
-
* }
|
|
159
|
-
* }
|
|
160
|
-
*
|
|
161
|
-
* const app = await createApp({
|
|
162
|
-
* errorHandler: {
|
|
163
|
-
* errorMappers: [
|
|
164
|
-
* {
|
|
165
|
-
* type: AccountingError,
|
|
166
|
-
* toResponse: (err) => ({ status: err.status, code: err.code, message: err.message }),
|
|
167
|
-
* },
|
|
168
|
-
* ],
|
|
169
|
-
* },
|
|
170
|
-
* });
|
|
171
|
-
*
|
|
172
|
-
* // Now handlers just throw:
|
|
173
|
-
* handler: async (req) => {
|
|
174
|
-
* await ledger.post(id); // throws AccountingError → Arc maps to proper HTTP response
|
|
175
|
-
* }
|
|
176
|
-
* ```
|
|
177
|
-
*/
|
|
178
|
-
errorMappers?: ErrorMapper[];
|
|
179
|
-
/**
|
|
180
|
-
* Classify an error as a duplicate-key / unique-constraint violation →
|
|
181
|
-
* mapped to `409 Conflict` with `code: "DUPLICATE_KEY"`.
|
|
182
|
-
*
|
|
183
|
-
* Mirrors `RepositoryLike.isDuplicateKeyError` for the Fastify layer: errors
|
|
184
|
-
* that escape a controller (custom routes, user hooks, raw driver calls)
|
|
185
|
-
* still land here, so the classifier is duplicated at the edge. Defaults
|
|
186
|
-
* cover MongoDB (`code 11000` / `codeName "DuplicateKey"`), Prisma
|
|
187
|
-
* (`code "P2002"`), and Postgres (`code "23505"`). Override to add other
|
|
188
|
-
* backends (DynamoDB `ConditionalCheckFailedException`, etc.) or to disable
|
|
189
|
-
* the built-in detection.
|
|
190
|
-
*/
|
|
191
|
-
isDuplicateKeyError?: (err: unknown) => boolean;
|
|
192
|
-
}
|
|
193
|
-
/**
|
|
194
|
-
* Default duplicate-key detector covering the mainstream drivers arc sees
|
|
195
|
-
* most. Detection is strictly by known driver codes — never by message
|
|
196
|
-
* string matching — because false positives on dup-key silently mask real
|
|
197
|
-
* errors (WriteConflict, NotWritablePrimary, etc.) as 409s. For long-tail
|
|
198
|
-
* drivers (Neo4j, MSSQL, DynamoDB, custom kits), compose rather than
|
|
199
|
-
* replace:
|
|
200
|
-
*
|
|
201
|
-
* ```ts
|
|
202
|
-
* import { defaultIsDuplicateKeyError } from '@classytic/arc/plugins';
|
|
203
|
-
*
|
|
204
|
-
* errorHandler: {
|
|
205
|
-
* isDuplicateKeyError: (err) =>
|
|
206
|
-
* defaultIsDuplicateKeyError(err) || isNeo4jDupKey(err),
|
|
207
|
-
* }
|
|
208
|
-
* ```
|
|
209
|
-
*
|
|
210
|
-
* Drizzle apps get coverage transitively (Drizzle doesn't wrap driver
|
|
211
|
-
* errors — pg/mysql2/better-sqlite3 codes propagate as-is). Neon is
|
|
212
|
-
* Postgres-wire-compatible → `23505` covers `@neondatabase/serverless`.
|
|
213
|
-
*/
|
|
214
|
-
declare function defaultIsDuplicateKeyError(err: unknown): boolean;
|
|
215
|
-
declare function errorHandlerPluginFn(fastify: FastifyInstance, options?: ErrorHandlerOptions): Promise<void>;
|
|
216
|
-
declare const errorHandlerPlugin: typeof errorHandlerPluginFn;
|
|
217
|
-
//#endregion
|
|
218
|
-
export { CachingRule as _, VersioningOptions as a, MetricEntry as c, _default$1 as d, metricsPlugin as f, CachingOptions as g, ssePlugin as h, errorHandlerPlugin as i, MetricsCollector as l, _default$2 as m, ErrorMapper as n, _default as o, SSEOptions as p, defaultIsDuplicateKeyError as r, versioningPlugin as s, ErrorHandlerOptions as t, MetricsOptions as u, _default$3 as v, cachingPlugin as y };
|