@classytic/arc 2.6.3 → 2.7.3
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 +98 -3
- package/dist/{BaseController-DzRtluEF.mjs → BaseController-CpMfCXdn.mjs} +134 -16
- package/dist/adapters/index.d.mts +2 -2
- package/dist/adapters/index.mjs +1 -1
- package/dist/{adapters-gM-WYjNe.mjs → adapters-BxGgSHjj.mjs} +1 -9
- package/dist/applyPermissionResult-D6GPMsvh.mjs +37 -0
- package/dist/audit/index.d.mts +1 -1
- package/dist/audit/index.mjs +1 -1
- package/dist/audit/mongodb.d.mts +1 -1
- package/dist/audit/mongodb.mjs +1 -1
- package/dist/auth/index.d.mts +4 -4
- package/dist/auth/index.mjs +7 -6
- package/dist/auth/mongoose.d.mts +191 -0
- package/dist/auth/mongoose.mjs +73 -0
- package/dist/auth/redis-session.d.mts +1 -1
- package/dist/{betterAuthOpenApi-lz0IRbXJ.mjs → betterAuthOpenApi-CCw3YX0g.mjs} +1 -1
- package/dist/cache/index.d.mts +2 -2
- package/dist/cache/index.mjs +2 -2
- package/dist/cli/commands/docs.mjs +2 -2
- package/dist/cli/commands/generate.mjs +1 -1
- package/dist/cli/commands/init.mjs +7 -5
- package/dist/cli/commands/introspect.mjs +1 -1
- package/dist/core/index.d.mts +3 -3
- package/dist/core/index.mjs +4 -4
- package/dist/{core-C1XCMtqM.mjs → core-BWekSEju.mjs} +41 -13
- package/dist/{createApp-D2w0LdYJ.mjs → createApp-D7e77m8C.mjs} +25 -14
- package/dist/{defineResource-wWMBB4GP.mjs → defineResource-DZzyl4a4.mjs} +42 -37
- package/dist/docs/index.d.mts +2 -2
- package/dist/docs/index.mjs +1 -1
- package/dist/dynamic/index.d.mts +2 -2
- package/dist/dynamic/index.mjs +2 -2
- package/dist/{elevation-BEdACOLB.mjs → elevation-By_p2lnn.mjs} +1 -1
- package/dist/elevation-D7WK0RXq.d.mts +23 -0
- package/dist/{errorHandler-r2595m8T.mjs → errorHandler-CH8wk1eD.mjs} +17 -2
- package/dist/{errorHandler-Do4vVQ1f.d.mts → errorHandler-pCpEtNd7.d.mts} +46 -2
- package/dist/{eventPlugin-Ba00swHF.mjs → eventPlugin-B6U_nCFU.mjs} +4 -3
- package/dist/{eventPlugin-DW45v4V5.d.mts → eventPlugin-CdvUoUna.d.mts} +1 -1
- package/dist/events/index.d.mts +3 -3
- package/dist/events/index.mjs +1 -1
- 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 +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/mongodb.d.mts +1 -1
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/index-B0extFr4.d.mts +640 -0
- package/dist/{index-gz6iuzCp.d.mts → index-BjShrzoj.d.mts} +47 -4
- package/dist/{index-CHeJa4Zd.d.mts → index-C9eYNjGR.d.mts} +1 -1
- package/dist/index.d.mts +9 -8
- package/dist/index.mjs +10 -9
- 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 +8 -5
- package/dist/integrations/mcp/testing.d.mts +1 -1
- package/dist/integrations/mcp/testing.mjs +1 -1
- package/dist/integrations/webhooks.d.mts +58 -1
- package/dist/integrations/webhooks.mjs +78 -7
- package/dist/integrations/websocket.d.mts +7 -1
- package/dist/integrations/websocket.mjs +7 -1
- package/dist/{interface-DYH8AXGe.d.mts → interface-B91alUzq.d.mts} +151 -15
- package/dist/{mongodb-pMvOlR5_.d.mts → mongodb-B7zupyck.d.mts} +1 -1
- package/dist/{mongodb-kltrBPa1.d.mts → mongodb-Cgu9F1Nd.d.mts} +1 -1
- package/dist/{openapi-CBmZ6EQN.mjs → openapi-BBSTVcMm.mjs} +1 -1
- package/dist/org/index.d.mts +2 -2
- package/dist/org/index.mjs +1 -1
- package/dist/permissions/index.d.mts +4 -4
- package/dist/permissions/index.mjs +3 -2
- package/dist/{permissions-C8ImI8gC.mjs → permissions-CH4cNwJi.mjs} +358 -64
- package/dist/plugins/index.d.mts +52 -5
- package/dist/plugins/index.mjs +12 -11
- package/dist/plugins/response-cache.mjs +1 -1
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/policies/index.d.mts +1 -1
- package/dist/presets/index.d.mts +3 -3
- package/dist/presets/index.mjs +1 -1
- package/dist/presets/multiTenant.d.mts +53 -3
- package/dist/presets/multiTenant.mjs +89 -47
- package/dist/{presets-BMfdy34e.mjs → presets-BFrGvvjL.mjs} +2 -2
- package/dist/{queryCachePlugin-DcmETvcB.d.mts → queryCachePlugin-Ckl71mkc.d.mts} +1 -1
- package/dist/{queryCachePlugin-XtFplYO9.mjs → queryCachePlugin-CwTpR04-.mjs} +2 -2
- package/dist/{redis-D0Qc-9EW.d.mts → redis-3TQxm2VZ.d.mts} +1 -1
- package/dist/{redis-stream-BW9UKLZM.d.mts → redis-stream-Dag5LFa9.d.mts} +1 -1
- package/dist/registry/index.d.mts +1 -1
- package/dist/registry/index.mjs +2 -2
- package/dist/replyHelpers-uDUIYh7u.mjs +40 -0
- package/dist/{resourceToTools-nCJWnG1r.mjs → resourceToTools-BJkoQoUP.mjs} +74 -25
- package/dist/rpc/index.d.mts +1 -1
- package/dist/rpc/index.mjs +1 -1
- package/dist/scope/index.d.mts +3 -2
- package/dist/scope/index.mjs +4 -3
- package/dist/{sse-BF7GR7IB.mjs → sse-6W0hjVS_.mjs} +2 -2
- package/dist/testing/index.d.mts +2 -2
- package/dist/testing/index.mjs +1 -1
- package/dist/types/index.d.mts +4 -3
- package/dist/types/index.mjs +1 -1
- package/dist/types--D3vvfdt.d.mts +286 -0
- package/dist/{types-By-5mIfn.d.mts → types-2FlNl0mL.d.mts} +44 -9
- package/dist/types-AOD8fxIw.mjs +229 -0
- package/dist/types-B4BNthET.d.mts +178 -0
- package/dist/{types-B4_TDdPe.d.mts → types-C5g2oRC7.d.mts} +18 -2
- package/dist/utils/index.d.mts +3 -3
- package/dist/utils/index.mjs +5 -5
- package/package.json +21 -6
- package/skills/arc/SKILL.md +314 -6
- package/skills/arc/references/integrations.md +32 -7
- package/skills/arc/references/mcp.md +31 -7
- package/skills/arc/references/multi-tenancy.md +208 -0
- package/skills/arc/references/production.md +69 -0
- package/dist/elevation-C_taLQrM.d.mts +0 -147
- package/dist/index-NGZksqM5.d.mts +0 -398
- package/dist/types-BNUccdcf.d.mts +0 -101
- package/dist/types-BhtYdxZU.mjs +0 -91
- /package/dist/{EventTransport-wc5hSLik.d.mts → EventTransport-C4VheKeC.d.mts} +0 -0
- /package/dist/{HookSystem-COkyWztM.mjs → HookSystem-D7lfx--K.mjs} +0 -0
- /package/dist/{ResourceRegistry-C6ngvOnn.mjs → ResourceRegistry-DsHiG9cL.mjs} +0 -0
- /package/dist/{caching-BSXB-Xr7.mjs → caching-5DtLwIqb.mjs} +0 -0
- /package/dist/{circuitBreaker-JP2GdJ4b.d.mts → circuitBreaker-BBPDt-J_.d.mts} +0 -0
- /package/dist/{circuitBreaker-BOBOpN2w.mjs → circuitBreaker-l18oRgL5.mjs} +0 -0
- /package/dist/{errors-CcVbl1-T.d.mts → errors-BS6lZvWy.d.mts} +0 -0
- /package/dist/{errors-NoQKsbAT.mjs → errors-Cg58SLNi.mjs} +0 -0
- /package/dist/{externalPaths-DpO-s7r8.d.mts → externalPaths-iba7jD3d.d.mts} +0 -0
- /package/dist/{fields-DFwdaWCq.d.mts → fields-D4nMDqnK.d.mts} +0 -0
- /package/dist/{interface-D_BWALyZ.d.mts → interface-CG7oRZjX.d.mts} +0 -0
- /package/dist/{interface-gr-7qo9j.d.mts → interface-CSbZdv_3.d.mts} +0 -0
- /package/dist/{logger-Dz3j1ItV.mjs → logger-DLg8-Ueg.mjs} +0 -0
- /package/dist/{memory-BFAYkf8H.mjs → memory-Cp7_cAko.mjs} +0 -0
- /package/dist/{metrics-Csh4nsvv.mjs → metrics-Qnvwc-LQ.mjs} +0 -0
- /package/dist/{mongodb-BuQ7fNTg.mjs → mongodb-B7X7P1P8.mjs} +0 -0
- /package/dist/{pluralize-CcT6qF0a.mjs → pluralize-Dckfq6US.mjs} +0 -0
- /package/dist/{registry-I-ogLgL9.mjs → registry-B3lRFBWo.mjs} +0 -0
- /package/dist/{requestContext-DYtmNpm5.mjs → requestContext-xHIKedG6.mjs} +0 -0
- /package/dist/{schemaConverter-DjzHpFam.mjs → schemaConverter-0TyONAwM.mjs} +0 -0
- /package/dist/{sessionManager-wbkYj2HL.d.mts → sessionManager-CEo9jwPI.d.mts} +0 -0
- /package/dist/{tracing-bz_U4EM1.d.mts → tracing-DEqdGkr-.d.mts} +0 -0
- /package/dist/{typeGuards-Cj5Rgvlg.mjs → typeGuards-CcFZXgU7.mjs} +0 -0
- /package/dist/{utils-Dc0WhlIl.mjs → utils-B-l6410F.mjs} +0 -0
- /package/dist/{versioning-BzfeHmhj.mjs → versioning-CdBbFefk.mjs} +0 -0
package/dist/scope/index.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { _ as
|
|
1
|
+
import { _ as isAuthenticated, a as getClientId, b as isOrgInScope, c as getOrgRoles, d as getScopeContextMap, f as getServiceScopes, g as hasOrgAccess, h as getUserRoles, i as getAncestorOrgIds, l as getRequestScope, m as getUserId, n as PUBLIC_SCOPE, o as getOrgContext, p as getTeamId, r as RequestScope, s as getOrgId, t as AUTHENTICATED_SCOPE, u as getScopeContext, v as isElevated, x as isService, y as isMember } from "../types--D3vvfdt.mjs";
|
|
2
|
+
import { i as elevationPlugin, n as ElevationOptions, r as _default, t as ElevationEvent } from "../elevation-D7WK0RXq.mjs";
|
|
2
3
|
import { FastifyReply, FastifyRequest } from "fastify";
|
|
3
4
|
|
|
4
5
|
//#region src/scope/rateLimitKey.d.ts
|
|
@@ -29,4 +30,4 @@ interface ResolveOrgFromHeaderOptions {
|
|
|
29
30
|
*/
|
|
30
31
|
declare function resolveOrgFromHeader(options: ResolveOrgFromHeaderOptions): (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
|
|
31
32
|
//#endregion
|
|
32
|
-
export { AUTHENTICATED_SCOPE, type ElevationEvent, type ElevationOptions, PUBLIC_SCOPE, type RateLimitKeyContext, type RequestScope, type ResolveOrgFromHeaderOptions, type TenantKeyGeneratorOptions, createTenantKeyGenerator, _default as elevationPlugin, elevationPlugin as elevationPluginFn, getOrgContext, getOrgId, getOrgRoles, getTeamId, getUserId, getUserRoles, hasOrgAccess, isAuthenticated, isElevated, isMember, resolveOrgFromHeader };
|
|
33
|
+
export { AUTHENTICATED_SCOPE, type ElevationEvent, type ElevationOptions, PUBLIC_SCOPE, type RateLimitKeyContext, type RequestScope, type ResolveOrgFromHeaderOptions, type TenantKeyGeneratorOptions, createTenantKeyGenerator, _default as elevationPlugin, elevationPlugin as elevationPluginFn, getAncestorOrgIds, getClientId, getOrgContext, getOrgId, getOrgRoles, getRequestScope, getScopeContext, getScopeContextMap, getServiceScopes, getTeamId, getUserId, getUserRoles, hasOrgAccess, isAuthenticated, isElevated, isMember, isOrgInScope, isService, resolveOrgFromHeader };
|
package/dist/scope/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { _ as isElevated, a as getOrgContext, b as isService, c as getRequestScope, d as getServiceScopes, f as getTeamId, g as isAuthenticated, h as hasOrgAccess, i as getClientId, l as getScopeContext, m as getUserRoles, n as PUBLIC_SCOPE, o as getOrgId, p as getUserId, r as getAncestorOrgIds, s as getOrgRoles, t as AUTHENTICATED_SCOPE, u as getScopeContextMap, v as isMember, y as isOrgInScope } from "../types-AOD8fxIw.mjs";
|
|
2
2
|
import { n as normalizeRoles } from "../types-ZUu_h0jp.mjs";
|
|
3
|
-
import { n as elevation_default, t as elevationPlugin } from "../elevation-
|
|
3
|
+
import { n as elevation_default, t as elevationPlugin } from "../elevation-By_p2lnn.mjs";
|
|
4
4
|
//#region src/scope/rateLimitKey.ts
|
|
5
5
|
function createTenantKeyGenerator(opts) {
|
|
6
6
|
if (opts?.strategy) return opts.strategy;
|
|
@@ -8,6 +8,7 @@ function createTenantKeyGenerator(opts) {
|
|
|
8
8
|
const scope = ctx.scope;
|
|
9
9
|
if (!scope || scope.kind === "public") return ctx.ip;
|
|
10
10
|
if (scope.kind === "member") return scope.organizationId;
|
|
11
|
+
if (scope.kind === "service") return scope.organizationId;
|
|
11
12
|
if (scope.kind === "elevated") return scope.organizationId ?? scope.userId ?? ctx.ip;
|
|
12
13
|
return scope.userId ?? ctx.ip;
|
|
13
14
|
};
|
|
@@ -75,4 +76,4 @@ function resolveOrgFromHeader(options) {
|
|
|
75
76
|
};
|
|
76
77
|
}
|
|
77
78
|
//#endregion
|
|
78
|
-
export { AUTHENTICATED_SCOPE, PUBLIC_SCOPE, createTenantKeyGenerator, elevation_default as elevationPlugin, elevationPlugin as elevationPluginFn, getOrgContext, getOrgId, getOrgRoles, getTeamId, getUserId, getUserRoles, hasOrgAccess, isAuthenticated, isElevated, isMember, resolveOrgFromHeader };
|
|
79
|
+
export { AUTHENTICATED_SCOPE, PUBLIC_SCOPE, createTenantKeyGenerator, elevation_default as elevationPlugin, elevationPlugin as elevationPluginFn, getAncestorOrgIds, getClientId, getOrgContext, getOrgId, getOrgRoles, getRequestScope, getScopeContext, getScopeContextMap, getServiceScopes, getTeamId, getUserId, getUserRoles, hasOrgAccess, isAuthenticated, isElevated, isMember, isOrgInScope, isService, resolveOrgFromHeader };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { t as arcLog } from "./logger-
|
|
2
|
+
import { n as PUBLIC_SCOPE, o as getOrgId } from "./types-AOD8fxIw.mjs";
|
|
3
|
+
import { t as arcLog } from "./logger-DLg8-Ueg.mjs";
|
|
4
4
|
import fp from "fastify-plugin";
|
|
5
5
|
//#region src/plugins/sse.ts
|
|
6
6
|
var sse_exports = /* @__PURE__ */ __exportAll({
|
package/dist/testing/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Ut as CrudRepository, Vt as ResourceDefinition, u as AnyRecord } from "../interface-
|
|
2
|
-
import { d as ResourceLike, r as CreateAppOptions } from "../types-
|
|
1
|
+
import { Ut as CrudRepository, Vt as ResourceDefinition, u as AnyRecord } from "../interface-B91alUzq.mjs";
|
|
2
|
+
import { d as ResourceLike, r as CreateAppOptions } from "../types-2FlNl0mL.mjs";
|
|
3
3
|
import Fastify, { FastifyInstance, FastifyServerOptions } from "fastify";
|
|
4
4
|
import { Connection } from "mongoose";
|
|
5
5
|
import { Mock } from "vitest";
|
package/dist/testing/index.mjs
CHANGED
|
@@ -1796,7 +1796,7 @@ function runEventTests(resourceName, displayName, events) {
|
|
|
1796
1796
|
* ```
|
|
1797
1797
|
*/
|
|
1798
1798
|
async function createTestApp(options = {}) {
|
|
1799
|
-
const { createApp } = await import("../createApp-
|
|
1799
|
+
const { createApp } = await import("../createApp-D7e77m8C.mjs").then((n) => n.r);
|
|
1800
1800
|
const { useInMemoryDb = true, mongoUri: providedMongoUri, ...appOptions } = options;
|
|
1801
1801
|
const defaultAuth = {
|
|
1802
1802
|
type: "jwt",
|
package/dist/types/index.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { _ as
|
|
2
|
-
import { $ as RateLimitConfig, A as FieldRule, B as JwtContext, C as CrudRouterOptions, Ct as getUserId, D as FastifyRequestExtras, E as EventsDecorator, F as InferDocType, Ft as IController, G as OpenApiSchemas, Gt as PaginatedResult, H as MiddlewareConfig, I as InferResourceDoc, It as IControllerResponse, J as PopulateOption, K as OwnershipCheck, Kt as PaginationParams, L as IntrospectionData, Lt as IRequestContext, M as HealthCheck, Mt as ControllerHandler, N as HealthOptions, Nt as ControllerLike, O as FastifyWithAuth, P as InferAdapterDoc, Pt as FastifyHandler, Q as QueryParserInterface, R as IntrospectionPluginOptions, Rt as RouteHandler, S as CrudRouteKey, St as envelope, T as EventDefinition, Tt as BaseControllerOptions, U as MiddlewareHandler, Ut as CrudRepository, V as LookupOption, W as ObjectId, Wt as InferDoc, X as PresetHook, Y as PresetFunction, Z as PresetResult, _ as Authenticator, _t as TypedResourceConfig, at as ResourceCacheConfig, b as ControllerQueryOptions, bt as ValidateOptions, ct as ResourceHooks, d as ApiResponse, dt as RouteHandlerMethod, et as RegistryEntry, f as ArcDecorator, ft as RouteSchemaOptions, g as AuthPluginOptions, gt as TypedRepository, h as AuthHelpers, ht as TypedController, it as RequestWithExtras, j as GracefulShutdownOptions, k as FastifyWithDecorators, l as AdditionalRoute, lt as ResourceMetadata, m as ArcRequest, mt as TokenPair, nt as RequestContext, ot as ResourceConfig, p as ArcInternalMetadata, pt as ServiceContext, q as ParsedQuery, qt as QueryOptions, rt as RequestIdOptions, st as ResourceHookContext, tt as RegistryStats, u as AnyRecord, ut as ResourcePermissions, v as AuthenticatorContext, vt as UserLike, w as CrudSchemas, x as CrudController, xt as ValidationResult, y as ConfigError, yt as UserOrganization, z as JWTPayload } from "../interface-
|
|
3
|
-
import { i as UserBase, n as PermissionContext, r as PermissionResult, t as PermissionCheck } from "../types-
|
|
1
|
+
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--D3vvfdt.mjs";
|
|
2
|
+
import { $ as RateLimitConfig, A as FieldRule, B as JwtContext, C as CrudRouterOptions, Ct as getUserId, D as FastifyRequestExtras, E as EventsDecorator, F as InferDocType, Ft as IController, G as OpenApiSchemas, Gt as PaginatedResult, H as MiddlewareConfig, I as InferResourceDoc, It as IControllerResponse, J as PopulateOption, K as OwnershipCheck, Kt as PaginationParams, L as IntrospectionData, Lt as IRequestContext, M as HealthCheck, Mt as ControllerHandler, N as HealthOptions, Nt as ControllerLike, O as FastifyWithAuth, P as InferAdapterDoc, Pt as FastifyHandler, Q as QueryParserInterface, R as IntrospectionPluginOptions, Rt as RouteHandler, S as CrudRouteKey, St as envelope, T as EventDefinition, Tt as BaseControllerOptions, U as MiddlewareHandler, Ut as CrudRepository, V as LookupOption, W as ObjectId, Wt as InferDoc, X as PresetHook, Y as PresetFunction, Z as PresetResult, _ as Authenticator, _t as TypedResourceConfig, at as ResourceCacheConfig, b as ControllerQueryOptions, bt as ValidateOptions, ct as ResourceHooks, d as ApiResponse, dt as RouteHandlerMethod, et as RegistryEntry, f as ArcDecorator, ft as RouteSchemaOptions, g as AuthPluginOptions, gt as TypedRepository, h as AuthHelpers, ht as TypedController, it as RequestWithExtras, j as GracefulShutdownOptions, k as FastifyWithDecorators, l as AdditionalRoute, lt as ResourceMetadata, m as ArcRequest, mt as TokenPair, nt as RequestContext, ot as ResourceConfig, p as ArcInternalMetadata, pt as ServiceContext, q as ParsedQuery, qt as QueryOptions, rt as RequestIdOptions, st as ResourceHookContext, tt as RegistryStats, u as AnyRecord, ut as ResourcePermissions, v as AuthenticatorContext, vt as UserLike, w as CrudSchemas, x as CrudController, xt as ValidationResult, y as ConfigError, yt as UserOrganization, z as JWTPayload } from "../interface-B91alUzq.mjs";
|
|
3
|
+
import { i as UserBase, n as PermissionContext, r as PermissionResult, t as PermissionCheck } from "../types-B4BNthET.mjs";
|
|
4
|
+
import { n as ElevationOptions, t as ElevationEvent } from "../elevation-D7WK0RXq.mjs";
|
|
4
5
|
export { AUTHENTICATED_SCOPE, AdditionalRoute, AnyRecord, ApiResponse, ArcDecorator, ArcInternalMetadata, ArcRequest, AuthHelpers, AuthPluginOptions, Authenticator, AuthenticatorContext, BaseControllerOptions, ConfigError, ControllerHandler, ControllerLike, ControllerQueryOptions, CrudController, CrudRepository, CrudRouteKey, CrudRouterOptions, CrudSchemas, ElevationEvent, ElevationOptions, EventDefinition, EventsDecorator, FastifyHandler, FastifyRequestExtras, FastifyWithAuth, FastifyWithDecorators, FieldRule, GracefulShutdownOptions, HealthCheck, HealthOptions, IController, IControllerResponse, IRequestContext, InferAdapterDoc, InferDoc, InferDocType, InferResourceDoc, IntrospectionData, IntrospectionPluginOptions, JWTPayload, JwtContext, LookupOption, MiddlewareConfig, MiddlewareHandler, ObjectId, OpenApiSchemas, OwnershipCheck, PUBLIC_SCOPE, PaginatedResult, PaginationParams, ParsedQuery, PermissionCheck, PermissionContext, PermissionResult, PopulateOption, PresetFunction, PresetHook, PresetResult, QueryOptions, QueryParserInterface, RateLimitConfig, RegistryEntry, RegistryStats, RequestContext, RequestIdOptions, RequestScope, RequestWithExtras, ResourceCacheConfig, ResourceConfig, ResourceHookContext, ResourceHooks, ResourceMetadata, ResourcePermissions, RouteHandler, RouteHandlerMethod, 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,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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
2
|
//#region src/types/index.ts
|
|
3
3
|
/**
|
|
4
4
|
* Response envelope helper — wraps data in Arc's standard `{ success, data }` format.
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
//#region src/scope/types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Request Scope — The One Standard
|
|
4
|
+
*
|
|
5
|
+
* Discriminated union representing the access context of every request.
|
|
6
|
+
* Replaces scattered orgScope/orgRoles/organizationId/bypassRoles.
|
|
7
|
+
*
|
|
8
|
+
* Set once by auth adapters, read everywhere by permissions/presets/guards.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* // In a permission check
|
|
13
|
+
* const scope = request.scope;
|
|
14
|
+
* if (isElevated(scope)) return true;
|
|
15
|
+
* if (isMember(scope) && scope.orgRoles.includes('admin')) return true;
|
|
16
|
+
*
|
|
17
|
+
* // Get user identity from scope
|
|
18
|
+
* const userId = getUserId(scope);
|
|
19
|
+
* const globalRoles = getUserRoles(scope);
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Request scope — 5 kinds, no ambiguity.
|
|
24
|
+
*
|
|
25
|
+
* | Kind | Meaning |
|
|
26
|
+
* |---------------|--------------------------------------------------|
|
|
27
|
+
* | public | No authentication |
|
|
28
|
+
* | authenticated | Logged-in user, no org context |
|
|
29
|
+
* | member | User in an org with specific roles |
|
|
30
|
+
* | service | Machine-to-machine (API key, service account) |
|
|
31
|
+
* | elevated | Platform admin, explicit elevation |
|
|
32
|
+
*
|
|
33
|
+
* **Identity fields by kind:**
|
|
34
|
+
* - `userId` / `userRoles` — available on `authenticated`, `member`, `elevated` (a real human)
|
|
35
|
+
* - `clientId` — available on `service` (a machine identity, NOT a user)
|
|
36
|
+
* - `organizationId` — required on `member` and `service`, optional on `elevated`
|
|
37
|
+
* - `orgRoles` — org-level roles, only on `member` (from membership records)
|
|
38
|
+
* - `scopes` — optional OAuth-style scope strings on `service` (e.g. `['jobs:write', 'memories:read']`)
|
|
39
|
+
*
|
|
40
|
+
* Use `getUserId(scope)` / `getClientId(scope)` / `getOrgId(scope)` instead of
|
|
41
|
+
* narrowing manually — helpers return `undefined` when the field isn't present.
|
|
42
|
+
*/
|
|
43
|
+
type RequestScope = {
|
|
44
|
+
kind: "public";
|
|
45
|
+
} | {
|
|
46
|
+
kind: "authenticated";
|
|
47
|
+
userId?: string;
|
|
48
|
+
userRoles?: string[];
|
|
49
|
+
} | {
|
|
50
|
+
kind: "member";
|
|
51
|
+
userId?: string;
|
|
52
|
+
userRoles: string[];
|
|
53
|
+
organizationId: string;
|
|
54
|
+
orgRoles: string[];
|
|
55
|
+
teamId?: string;
|
|
56
|
+
/**
|
|
57
|
+
* App-defined scope dimensions beyond org and team. Use this to carry
|
|
58
|
+
* branch / project / department / region / workspace identifiers that
|
|
59
|
+
* arc itself shouldn't take a position on.
|
|
60
|
+
*
|
|
61
|
+
* Read with `getScopeContext(scope, key)`. Filtered by
|
|
62
|
+
* `multiTenantPreset({ tenantFields: [...] })` and gated by
|
|
63
|
+
* `requireScopeContext(...)`. Populated by your auth function or
|
|
64
|
+
* adapter (e.g. from JWT claims, BA session fields, or request headers).
|
|
65
|
+
*
|
|
66
|
+
* Treat as immutable — `Readonly` enforces that at the type level.
|
|
67
|
+
*/
|
|
68
|
+
context?: Readonly<Record<string, string>>;
|
|
69
|
+
/**
|
|
70
|
+
* Parent organizations the caller has access to, ordered closest-first
|
|
71
|
+
* (immediate parent → … → root). Used for explicit hierarchy checks
|
|
72
|
+
* via `isOrgInScope` and `requireOrgInScope` — there's no automatic
|
|
73
|
+
* inheritance, every check is opt-in.
|
|
74
|
+
*
|
|
75
|
+
* Arc takes no position on the source — your auth function loads the
|
|
76
|
+
* chain from your own org table during sign-in or middleware. Empty
|
|
77
|
+
* or absent = caller has no parent orgs (the common case).
|
|
78
|
+
*/
|
|
79
|
+
ancestorOrgIds?: readonly string[];
|
|
80
|
+
} | {
|
|
81
|
+
kind: "service";
|
|
82
|
+
clientId: string;
|
|
83
|
+
organizationId: string;
|
|
84
|
+
scopes?: readonly string[]; /** App-defined scope dimensions — see `member.context` for details. */
|
|
85
|
+
context?: Readonly<Record<string, string>>; /** Parent organizations — see `member.ancestorOrgIds` for details. */
|
|
86
|
+
ancestorOrgIds?: readonly string[];
|
|
87
|
+
} | {
|
|
88
|
+
kind: "elevated";
|
|
89
|
+
userId?: string;
|
|
90
|
+
organizationId?: string;
|
|
91
|
+
elevatedBy: string; /** App-defined scope dimensions — see `member.context` for details. */
|
|
92
|
+
context?: Readonly<Record<string, string>>; /** Parent organizations — see `member.ancestorOrgIds` for details. */
|
|
93
|
+
ancestorOrgIds?: readonly string[];
|
|
94
|
+
};
|
|
95
|
+
/** Check if scope is `member` kind */
|
|
96
|
+
declare function isMember(scope: RequestScope): scope is Extract<RequestScope, {
|
|
97
|
+
kind: "member";
|
|
98
|
+
}>;
|
|
99
|
+
/** Check if scope is `elevated` kind */
|
|
100
|
+
declare function isElevated(scope: RequestScope): scope is Extract<RequestScope, {
|
|
101
|
+
kind: "elevated";
|
|
102
|
+
}>;
|
|
103
|
+
/** Check if scope is `service` kind (machine-to-machine auth) */
|
|
104
|
+
declare function isService(scope: RequestScope): scope is Extract<RequestScope, {
|
|
105
|
+
kind: "service";
|
|
106
|
+
}>;
|
|
107
|
+
/** Check if scope has org access (member, service, or elevated) */
|
|
108
|
+
declare function hasOrgAccess(scope: RequestScope): boolean;
|
|
109
|
+
/** Check if request is authenticated (any kind except public) */
|
|
110
|
+
declare function isAuthenticated(scope: RequestScope): boolean;
|
|
111
|
+
/** Get organizationId from scope (member, service, or elevated — undefined otherwise) */
|
|
112
|
+
declare function getOrgId(scope: RequestScope): string | undefined;
|
|
113
|
+
/**
|
|
114
|
+
* Get stable client identity from a service scope.
|
|
115
|
+
*
|
|
116
|
+
* Returns the `clientId` for machine-to-machine auth (API keys, service accounts),
|
|
117
|
+
* or `undefined` for any other scope kind. Use this for audit logging, rate limiting,
|
|
118
|
+
* and anywhere you need to distinguish "this specific API client" from "this user".
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```typescript
|
|
122
|
+
* const clientId = getClientId(request.scope);
|
|
123
|
+
* if (clientId) {
|
|
124
|
+
* auditLog.record({ actor: clientId, action: 'create' });
|
|
125
|
+
* }
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
declare function getClientId(scope: RequestScope): string | undefined;
|
|
129
|
+
/**
|
|
130
|
+
* Get OAuth-style scope strings from a service scope (e.g. `['jobs:write']`).
|
|
131
|
+
* Returns an empty array for any non-service kind.
|
|
132
|
+
*/
|
|
133
|
+
declare function getServiceScopes(scope: RequestScope): readonly string[];
|
|
134
|
+
/** Get org roles from scope (empty array if not a member) */
|
|
135
|
+
declare function getOrgRoles(scope: RequestScope): string[];
|
|
136
|
+
/** Get team ID from scope (only available on member kind) */
|
|
137
|
+
declare function getTeamId(scope: RequestScope): string | undefined;
|
|
138
|
+
/**
|
|
139
|
+
* Get an app-defined scope dimension by key (e.g. `branchId`, `projectId`).
|
|
140
|
+
*
|
|
141
|
+
* Returns the value when the scope is `member`/`service`/`elevated` AND has
|
|
142
|
+
* `context` set AND the key exists; `undefined` otherwise. Designed to be
|
|
143
|
+
* the single read path for any custom tenancy dimension your app cares about
|
|
144
|
+
* — branch, project, department, region, workspace, etc.
|
|
145
|
+
*
|
|
146
|
+
* Arc itself takes no position on what keys you use — that's your domain.
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```typescript
|
|
150
|
+
* import { getScopeContext } from '@classytic/arc/scope';
|
|
151
|
+
*
|
|
152
|
+
* const branchId = getScopeContext(request.scope, 'branchId');
|
|
153
|
+
* if (!branchId) return reply.code(403).send({ error: 'Branch context required' });
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
declare function getScopeContext(scope: RequestScope, key: string): string | undefined;
|
|
157
|
+
/**
|
|
158
|
+
* Get the full scope context map (read-only). Returns `undefined` for scope
|
|
159
|
+
* kinds that don't carry context (`public`, `authenticated`).
|
|
160
|
+
*/
|
|
161
|
+
declare function getScopeContextMap(scope: RequestScope): Readonly<Record<string, string>> | undefined;
|
|
162
|
+
/**
|
|
163
|
+
* Get the parent-organization chain for a scope (closest-first, root-last).
|
|
164
|
+
*
|
|
165
|
+
* Returns the `ancestorOrgIds` array when the scope is `member`/`service`/
|
|
166
|
+
* `elevated` and has it set; an empty array otherwise (including for kinds
|
|
167
|
+
* that can't carry org context).
|
|
168
|
+
*
|
|
169
|
+
* Arc takes no position on what the chain represents — your auth function
|
|
170
|
+
* loads it from your own data model. Common use cases: holding company →
|
|
171
|
+
* subsidiaries, MSP → managed tenants, white-label parent → child accounts.
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```typescript
|
|
175
|
+
* import { getAncestorOrgIds } from '@classytic/arc/scope';
|
|
176
|
+
*
|
|
177
|
+
* const ancestors = getAncestorOrgIds(request.scope);
|
|
178
|
+
* if (ancestors.includes('acme-holding')) {
|
|
179
|
+
* // caller has access to a path that includes Acme Holding
|
|
180
|
+
* }
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
declare function getAncestorOrgIds(scope: RequestScope): readonly string[];
|
|
184
|
+
/**
|
|
185
|
+
* Pure predicate: does this scope grant access to `targetOrgId`?
|
|
186
|
+
*
|
|
187
|
+
* Returns `true` if `targetOrgId` equals the scope's `organizationId` OR
|
|
188
|
+
* appears in `ancestorOrgIds`. Returns `false` otherwise — including for
|
|
189
|
+
* elevated scopes (this is a pure data query, not a permission check; the
|
|
190
|
+
* elevated bypass lives in `requireOrgInScope`, not here).
|
|
191
|
+
*
|
|
192
|
+
* Designed to be the building block for any custom hierarchy logic in your
|
|
193
|
+
* own permission checks. Use `requireOrgInScope` for the route-gating
|
|
194
|
+
* version that includes the elevated bypass.
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* ```typescript
|
|
198
|
+
* import { isOrgInScope } from '@classytic/arc/scope';
|
|
199
|
+
*
|
|
200
|
+
* // Inside a custom permission check
|
|
201
|
+
* if (!isOrgInScope(request.scope, request.params.orgId)) {
|
|
202
|
+
* return { granted: false, reason: 'Not in your org hierarchy' };
|
|
203
|
+
* }
|
|
204
|
+
* ```
|
|
205
|
+
*/
|
|
206
|
+
declare function isOrgInScope(scope: RequestScope, targetOrgId: string): boolean;
|
|
207
|
+
/**
|
|
208
|
+
* Get userId from scope (available on authenticated, member, elevated).
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* ```typescript
|
|
212
|
+
* import { getUserId } from '@classytic/arc/scope';
|
|
213
|
+
* const userId = getUserId(request.scope);
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
216
|
+
declare function getUserId(scope: RequestScope): string | undefined;
|
|
217
|
+
/**
|
|
218
|
+
* Get global user roles from scope (available on authenticated and member).
|
|
219
|
+
* These are user-level roles (e.g. superadmin, finance-admin) distinct from
|
|
220
|
+
* org-level roles (scope.orgRoles).
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```typescript
|
|
224
|
+
* import { getUserRoles } from '@classytic/arc/scope';
|
|
225
|
+
* const globalRoles = getUserRoles(request.scope);
|
|
226
|
+
* ```
|
|
227
|
+
*/
|
|
228
|
+
declare function getUserRoles(scope: RequestScope): string[];
|
|
229
|
+
/**
|
|
230
|
+
* Org context — canonical extraction from a Fastify request.
|
|
231
|
+
*
|
|
232
|
+
* Works regardless of auth type (JWT, Better Auth, custom) by reading
|
|
233
|
+
* `request.scope` and `request.user`. Eliminates the need for each resource
|
|
234
|
+
* to re-invent org extraction from headers/user/scope.
|
|
235
|
+
*
|
|
236
|
+
* @example
|
|
237
|
+
* ```typescript
|
|
238
|
+
* import { getOrgContext } from '@classytic/arc/scope';
|
|
239
|
+
*
|
|
240
|
+
* handler: async (request, reply) => {
|
|
241
|
+
* const { userId, organizationId, roles, orgRoles } = getOrgContext(request);
|
|
242
|
+
* }
|
|
243
|
+
* ```
|
|
244
|
+
*/
|
|
245
|
+
declare function getOrgContext(request: {
|
|
246
|
+
scope?: RequestScope;
|
|
247
|
+
user?: Record<string, unknown> | null;
|
|
248
|
+
headers?: Record<string, string | string[] | undefined>;
|
|
249
|
+
}): {
|
|
250
|
+
userId: string | undefined;
|
|
251
|
+
organizationId: string | undefined;
|
|
252
|
+
roles: string[];
|
|
253
|
+
orgRoles: string[];
|
|
254
|
+
};
|
|
255
|
+
/**
|
|
256
|
+
* Read `request.scope` safely from any object that *might* have one.
|
|
257
|
+
* Falls back to `PUBLIC_SCOPE` when the field is absent or undefined.
|
|
258
|
+
*
|
|
259
|
+
* This is the canonical way for permission checks, presets, and middleware
|
|
260
|
+
* to read scope — never access `request.scope` directly because it can be
|
|
261
|
+
* `undefined` on requests that haven't been touched by an auth adapter yet.
|
|
262
|
+
*
|
|
263
|
+
* Accepts a structural shape (`{ scope?: RequestScope }`) instead of the
|
|
264
|
+
* full Fastify request type so it can be called from any layer without
|
|
265
|
+
* dragging in the Fastify type. The actual runtime is identical.
|
|
266
|
+
*
|
|
267
|
+
* @example
|
|
268
|
+
* ```typescript
|
|
269
|
+
* import { getRequestScope } from '@classytic/arc/scope';
|
|
270
|
+
*
|
|
271
|
+
* function myCheck(ctx: PermissionContext) {
|
|
272
|
+
* const scope = getRequestScope(ctx.request);
|
|
273
|
+
* if (isElevated(scope)) return true;
|
|
274
|
+
* // ...
|
|
275
|
+
* }
|
|
276
|
+
* ```
|
|
277
|
+
*/
|
|
278
|
+
declare function getRequestScope(request: {
|
|
279
|
+
scope?: RequestScope;
|
|
280
|
+
}): RequestScope;
|
|
281
|
+
/** Default public scope — used as initial decoration value */
|
|
282
|
+
declare const PUBLIC_SCOPE: Readonly<RequestScope>;
|
|
283
|
+
/** Default authenticated scope — used when user is logged in but no org */
|
|
284
|
+
declare const AUTHENTICATED_SCOPE: Readonly<RequestScope>;
|
|
285
|
+
//#endregion
|
|
286
|
+
export { isAuthenticated as _, getClientId as a, isOrgInScope as b, getOrgRoles as c, getScopeContextMap as d, getServiceScopes as f, hasOrgAccess as g, getUserRoles as h, getAncestorOrgIds as i, getRequestScope as l, getUserId as m, PUBLIC_SCOPE as n, getOrgContext as o, getTeamId as p, RequestScope as r, getOrgId as s, AUTHENTICATED_SCOPE as t, getScopeContext as u, isElevated as v, isService as x, isMember as y };
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { t as ExternalOpenApiPaths } from "./externalPaths-
|
|
4
|
-
import { i as CacheStore } from "./interface-
|
|
5
|
-
import { r as QueryCachePluginOptions } from "./queryCachePlugin-
|
|
6
|
-
import { i as EventTransport } from "./EventTransport-
|
|
7
|
-
import { t as EventPluginOptions } from "./eventPlugin-
|
|
8
|
-
import { c as MetricsOptions, d as SSEOptions, m as CachingOptions, r as VersioningOptions, t as ErrorHandlerOptions } from "./errorHandler-
|
|
9
|
-
import { r as IdempotencyStore } from "./interface-
|
|
1
|
+
import { _ as Authenticator } from "./interface-B91alUzq.mjs";
|
|
2
|
+
import { n as ElevationOptions } from "./elevation-D7WK0RXq.mjs";
|
|
3
|
+
import { t as ExternalOpenApiPaths } from "./externalPaths-iba7jD3d.mjs";
|
|
4
|
+
import { i as CacheStore } from "./interface-CG7oRZjX.mjs";
|
|
5
|
+
import { r as QueryCachePluginOptions } from "./queryCachePlugin-Ckl71mkc.mjs";
|
|
6
|
+
import { i as EventTransport } from "./EventTransport-C4VheKeC.mjs";
|
|
7
|
+
import { t as EventPluginOptions } from "./eventPlugin-CdvUoUna.mjs";
|
|
8
|
+
import { c as MetricsOptions, d as SSEOptions, m as CachingOptions, r as VersioningOptions, t as ErrorHandlerOptions } from "./errorHandler-pCpEtNd7.mjs";
|
|
9
|
+
import { r as IdempotencyStore } from "./interface-CSbZdv_3.mjs";
|
|
10
10
|
import { FastifyInstance, FastifyPluginAsync, FastifyReply, FastifyRequest, FastifyServerOptions } from "fastify";
|
|
11
11
|
|
|
12
12
|
//#region src/factory/loadResources.d.ts
|
|
@@ -598,6 +598,41 @@ interface CreateAppOptions {
|
|
|
598
598
|
ajv?: {
|
|
599
599
|
keywords?: string[];
|
|
600
600
|
};
|
|
601
|
+
/**
|
|
602
|
+
* Enable `reply.ok()`, `reply.fail()`, `reply.paginated()` response helpers.
|
|
603
|
+
*
|
|
604
|
+
* Default: `false` (opt-in).
|
|
605
|
+
*
|
|
606
|
+
* @example
|
|
607
|
+
* ```typescript
|
|
608
|
+
* const app = await createApp({ replyHelpers: true });
|
|
609
|
+
*
|
|
610
|
+
* // Then in any handler:
|
|
611
|
+
* return reply.ok({ name: 'MacBook' }); // → 200 { success: true, data: { ... } }
|
|
612
|
+
* return reply.ok(product, 201); // → 201 { success: true, data: { ... } }
|
|
613
|
+
* return reply.fail('Not found', 404); // → 404 { success: false, error: '...' }
|
|
614
|
+
* return reply.fail(['err1', 'err2'], 422); // → 422 { success: false, errors: [...] }
|
|
615
|
+
* return reply.paginated({ docs, total, page, limit });
|
|
616
|
+
* ```
|
|
617
|
+
*/
|
|
618
|
+
replyHelpers?: boolean;
|
|
619
|
+
/**
|
|
620
|
+
* Auto-convert BigInt values to Number in all JSON responses.
|
|
621
|
+
*
|
|
622
|
+
* When `true`, Arc adds a `preSerialization` hook that converts BigInt values
|
|
623
|
+
* to Number before JSON serialization. Without this, `JSON.stringify` throws
|
|
624
|
+
* on BigInt values (e.g., from financial libraries like fin-io).
|
|
625
|
+
*
|
|
626
|
+
* Default: `false` (opt-in — most apps don't use BigInt).
|
|
627
|
+
*
|
|
628
|
+
* @example
|
|
629
|
+
* ```typescript
|
|
630
|
+
* const app = await createApp({
|
|
631
|
+
* serializeBigInt: true,
|
|
632
|
+
* });
|
|
633
|
+
* ```
|
|
634
|
+
*/
|
|
635
|
+
serializeBigInt?: boolean;
|
|
601
636
|
/**
|
|
602
637
|
* Resources to register automatically.
|
|
603
638
|
* Each resource's `.toPlugin()` is called and registered for you.
|