@classytic/arc 2.9.1 → 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 +20 -91
- package/dist/{BaseController-Vu2yc56T.mjs → BaseController-DVNKvoX4.mjs} +154 -170
- package/dist/{ResourceRegistry-Dq3_zBQP.mjs → ResourceRegistry-CcN2LVrc.mjs} +1 -1
- package/dist/actionPermissions-TUVR3uiZ.mjs +22 -0
- package/dist/adapters/index.d.mts +3 -3
- package/dist/adapters/index.mjs +2 -2
- package/dist/{adapters-BBqAVvPK.mjs → adapters-BXY4i-hw.mjs} +210 -41
- package/dist/audit/index.d.mts +38 -3
- package/dist/audit/index.mjs +54 -22
- package/dist/auth/index.d.mts +2 -2
- package/dist/auth/index.mjs +3 -3
- package/dist/cache/index.d.mts +17 -15
- package/dist/cache/index.mjs +16 -15
- package/dist/{caching-CjybdRwx.mjs → caching-3h93rkJM.mjs} +8 -3
- package/dist/cli/commands/describe.mjs +1 -1
- package/dist/cli/commands/docs.mjs +2 -2
- 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 +3 -4
- package/dist/{defineResource-C__jkwvs.mjs → core-3MWJosCH.mjs} +174 -94
- package/dist/{createActionRouter-DH1YFL9m.mjs → createActionRouter-C8UUB3Px.mjs} +1 -1
- package/dist/{createApp-CBJUJKGP.mjs → createApp-BwnEAO2h.mjs} +53 -19
- package/dist/docs/index.d.mts +1 -1
- package/dist/docs/index.mjs +2 -2
- package/dist/{elevation-DxQ6ACbt.mjs → elevation-Dci0AYLT.mjs} +2 -2
- package/dist/errorHandler-2ii4RIYr.d.mts +114 -0
- package/dist/{errorHandler-CZDW4EXS.mjs → errorHandler-CSxe7KIM.mjs} +1 -1
- package/dist/{eventPlugin-Dl7MoVWH.mjs → eventPlugin-ByU4Cv0e.mjs} +1 -1
- package/dist/{eventPlugin-BxvaCIZF.d.mts → eventPlugin-D1ThQ1Pp.d.mts} +1 -1
- package/dist/events/index.d.mts +8 -5
- package/dist/events/index.mjs +87 -52
- 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/{types-DZi1aYhm.d.mts → fields-C8Y0XLAu.d.mts} +122 -2
- package/dist/hooks/index.d.mts +1 -1
- package/dist/idempotency/index.d.mts +5 -2
- package/dist/idempotency/index.mjs +46 -37
- package/dist/{interface-YrWsmKqE.d.mts → index-BGbpGVyM.d.mts} +2107 -2756
- package/dist/{index-CtGKT0lf.d.mts → index-BziRPS4H.d.mts} +81 -7
- package/dist/{index-C-xjcA6F.d.mts → index-C_Noptz-.d.mts} +284 -409
- package/dist/{index-Cibkchnx.d.mts → index-EqQN6p0W.d.mts} +3 -3
- package/dist/index.d.mts +6 -219
- package/dist/index.mjs +10 -131
- 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/interface-yhyb_pLY.d.mts +77 -0
- package/dist/logger/index.d.mts +81 -0
- package/dist/{logger-CDjpjySd.mjs → logger/index.mjs} +1 -6
- package/dist/{memory-BFAYkf8H.mjs → memory-DqI-449b.mjs} +23 -8
- 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-CXuTG1M9.mjs → openapi-DpNpqBmo.mjs} +9 -7
- package/dist/org/index.d.mts +2 -2
- package/dist/permissions/index.d.mts +3 -4
- package/dist/permissions/index.mjs +5 -5
- package/dist/{permissions-oNZawnkR.mjs → permissions-wkqRwicB.mjs} +315 -397
- 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 +23 -3
- package/dist/plugins/index.mjs +9 -11
- package/dist/plugins/response-cache.mjs +1 -1
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/presets/filesUpload.d.mts +3 -3
- 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 +43 -9
- package/dist/presets/search.d.mts +91 -4
- package/dist/presets/search.mjs +1 -1
- package/dist/{presets-hM4WhNWY.mjs → presets-CrwOvuXI.mjs} +1 -1
- package/dist/{queryCachePlugin-DbUVroUG.mjs → queryCachePlugin-ChLNZvFT.mjs} +9 -9
- package/dist/{queryCachePlugin-CnTZZTC5.d.mts → queryCachePlugin-Dumka73q.d.mts} +1 -1
- package/dist/{queryParser-Cs-6SHQK.mjs → queryParser-NR__Qiju.mjs} +69 -2
- package/dist/{redis-stream-Bz-4q96t.d.mts → redis-stream-bkO88VHx.d.mts} +1 -1
- package/dist/registry/index.d.mts +1 -1
- package/dist/registry/index.mjs +1 -1
- package/dist/{requestContext-DYtmNpm5.mjs → requestContext-C38GskNt.mjs} +1 -1
- package/dist/{resourceToTools-C3cWymnW.mjs → resourceToTools-BhF3JV5p.mjs} +8 -3
- package/dist/scope/index.d.mts +2 -2
- package/dist/scope/index.mjs +2 -2
- package/dist/{sse-CJpt7LGI.mjs → sse-D8UeDwis.mjs} +1 -1
- package/dist/{store-helpers-DFiZl5TL.mjs → store-helpers-DYYUQbQN.mjs} +4 -0
- package/dist/testing/index.d.mts +6 -5
- package/dist/testing/index.mjs +17 -10
- package/dist/types/index.d.mts +5 -5
- package/dist/types/index.mjs +1 -31
- package/dist/types-CDnTEpga.mjs +27 -0
- package/dist/{types-CoSzA-s-.d.mts → types-CVKBssX5.d.mts} +1 -1
- package/dist/{types-CunEX4UX.d.mts → types-CVdgPXBW.d.mts} +20 -7
- package/dist/utils/index.d.mts +277 -3
- package/dist/utils/index.mjs +4 -5
- package/dist/{utils-B7FuRr9w.mjs → utils-LMwVidKy.mjs} +303 -2
- package/dist/{versioning-Cm8qoFDg.mjs → versioning-B6mimogM.mjs} +3 -5
- package/dist/versioning-CeUXHfjw.d.mts +117 -0
- package/package.json +31 -18
- package/skills/arc/SKILL.md +8 -12
- package/skills/arc/references/production.md +0 -41
- package/dist/circuitBreaker-CvXkjfrW.d.mts +0 -206
- package/dist/circuitBreaker-l18oRgL5.mjs +0 -284
- package/dist/core-DNncu0xF.mjs +0 -34
- package/dist/dynamic/index.d.mts +0 -93
- package/dist/dynamic/index.mjs +0 -122
- package/dist/errorHandler-DixGcttC.d.mts +0 -218
- package/dist/fields-BC7zcmI9.d.mts +0 -121
- package/dist/filesUpload-q8oHt--L.mjs +0 -377
- package/dist/interface-DplgQO2e.d.mts +0 -54
- package/dist/policies/index.d.mts +0 -425
- package/dist/policies/index.mjs +0 -318
- package/dist/rpc/index.d.mts +0 -90
- package/dist/rpc/index.mjs +0 -248
- /package/dist/{EventTransport-CqZ8FyM_.d.mts → EventTransport-CfVEGaEl.d.mts} +0 -0
- /package/dist/{applyPermissionResult-bqGpo9ML.mjs → applyPermissionResult-QhV1Pa-g.mjs} +0 -0
- /package/dist/{constants-Cxde4rpC.mjs → constants-BhY1OHoH.mjs} +0 -0
- /package/dist/{elevation-B6S5csVA.d.mts → elevation-s5ykdNHr.d.mts} +0 -0
- /package/dist/{errors-CqWnSqM-.mjs → errors-BqdUDja_.mjs} +0 -0
- /package/dist/{fields-CU6FlaDV.mjs → fields-CTMWOUDt.mjs} +0 -0
- /package/dist/{keys-qcD-TVJl.mjs → keys-nWQGUTu1.mjs} +0 -0
- /package/dist/{types-ZUu_h0jp.mjs → types-D57iXYb8.mjs} +0 -0
- /package/dist/{types-BD85MlEK.d.mts → types-tgR4Pt8F.d.mts} +0 -0
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
import { n as DomainEvent } from "./EventTransport-CqZ8FyM_.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 };
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
//#region src/permissions/fields.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* Field-Level Permissions
|
|
4
|
-
*
|
|
5
|
-
* Control field visibility and writability per role.
|
|
6
|
-
* Integrated into the response path (read) and sanitization path (write).
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* ```typescript
|
|
10
|
-
* import { fields, defineResource } from '@classytic/arc';
|
|
11
|
-
*
|
|
12
|
-
* const userResource = defineResource({
|
|
13
|
-
* name: 'user',
|
|
14
|
-
* adapter: userAdapter,
|
|
15
|
-
* fields: {
|
|
16
|
-
* salary: fields.visibleTo(['admin', 'hr']),
|
|
17
|
-
* internalNotes: fields.writableBy(['admin']),
|
|
18
|
-
* email: fields.redactFor(['viewer']),
|
|
19
|
-
* password: fields.hidden(),
|
|
20
|
-
* },
|
|
21
|
-
* });
|
|
22
|
-
* ```
|
|
23
|
-
*/
|
|
24
|
-
type FieldPermissionType = "hidden" | "visibleTo" | "writableBy" | "redactFor";
|
|
25
|
-
interface FieldPermission {
|
|
26
|
-
readonly _type: FieldPermissionType;
|
|
27
|
-
readonly roles?: readonly string[];
|
|
28
|
-
readonly redactValue?: unknown;
|
|
29
|
-
}
|
|
30
|
-
type FieldPermissionMap = Record<string, FieldPermission>;
|
|
31
|
-
declare const fields: {
|
|
32
|
-
/**
|
|
33
|
-
* Field is never included in responses. Not writable via API.
|
|
34
|
-
*
|
|
35
|
-
* @example
|
|
36
|
-
* ```typescript
|
|
37
|
-
* fields: { password: fields.hidden() }
|
|
38
|
-
* ```
|
|
39
|
-
*/
|
|
40
|
-
hidden(): FieldPermission;
|
|
41
|
-
/**
|
|
42
|
-
* Field is only visible to users with specified roles.
|
|
43
|
-
* Other users don't see the field at all.
|
|
44
|
-
*
|
|
45
|
-
* @example
|
|
46
|
-
* ```typescript
|
|
47
|
-
* fields: { salary: fields.visibleTo(['admin', 'hr']) }
|
|
48
|
-
* ```
|
|
49
|
-
*/
|
|
50
|
-
visibleTo(roles: readonly string[]): FieldPermission;
|
|
51
|
-
/**
|
|
52
|
-
* Field is only writable by users with specified roles.
|
|
53
|
-
* All users can still read the field. Users without the role
|
|
54
|
-
* have the field silently stripped from write operations.
|
|
55
|
-
*
|
|
56
|
-
* @example
|
|
57
|
-
* ```typescript
|
|
58
|
-
* fields: { role: fields.writableBy(['admin']) }
|
|
59
|
-
* ```
|
|
60
|
-
*/
|
|
61
|
-
writableBy(roles: readonly string[]): FieldPermission;
|
|
62
|
-
/**
|
|
63
|
-
* Field is redacted (replaced with a placeholder) for specified roles.
|
|
64
|
-
* Other users see the real value.
|
|
65
|
-
*
|
|
66
|
-
* @param roles - Roles that see the redacted value
|
|
67
|
-
* @param redactValue - Replacement value (default: '***')
|
|
68
|
-
*
|
|
69
|
-
* @example
|
|
70
|
-
* ```typescript
|
|
71
|
-
* fields: {
|
|
72
|
-
* email: fields.redactFor(['viewer']),
|
|
73
|
-
* ssn: fields.redactFor(['basic'], '***-**-****'),
|
|
74
|
-
* }
|
|
75
|
-
* ```
|
|
76
|
-
*/
|
|
77
|
-
redactFor(roles: readonly string[], redactValue?: unknown): FieldPermission;
|
|
78
|
-
};
|
|
79
|
-
/**
|
|
80
|
-
* Apply field-level READ permissions to a response object.
|
|
81
|
-
* Strips hidden fields, enforces visibility, and applies redaction.
|
|
82
|
-
*
|
|
83
|
-
* @param data - The response object (mutated in place for performance)
|
|
84
|
-
* @param fieldPermissions - Field permission map from resource config
|
|
85
|
-
* @param userRoles - Current user's roles (empty array for unauthenticated)
|
|
86
|
-
* @returns The filtered object
|
|
87
|
-
*/
|
|
88
|
-
declare function applyFieldReadPermissions<T extends Record<string, unknown>>(data: T, fieldPermissions: FieldPermissionMap, userRoles: readonly string[]): T;
|
|
89
|
-
/**
|
|
90
|
-
* Result of applying write permissions — includes both the filtered body
|
|
91
|
-
* and the list of fields that were stripped so callers can decide whether
|
|
92
|
-
* to reject the request (secure default) or silently strip (legacy).
|
|
93
|
-
*/
|
|
94
|
-
interface FieldWritePermissionResult<T extends Record<string, unknown>> {
|
|
95
|
-
readonly body: T;
|
|
96
|
-
readonly deniedFields: readonly string[];
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Apply field-level WRITE permissions to request body.
|
|
100
|
-
*
|
|
101
|
-
* Returns both the filtered body and the list of denied fields. Callers are
|
|
102
|
-
* expected to reject the request when `deniedFields.length > 0` — silently
|
|
103
|
-
* stripping fields hides misconfigurations and real attacks. See
|
|
104
|
-
* `BodySanitizer` for the default policy.
|
|
105
|
-
*
|
|
106
|
-
* @param body - The request body (returns a new filtered copy)
|
|
107
|
-
* @param fieldPermissions - Field permission map from resource config
|
|
108
|
-
* @param userRoles - Current user's roles
|
|
109
|
-
*/
|
|
110
|
-
declare function applyFieldWritePermissions<T extends Record<string, unknown>>(body: T, fieldPermissions: FieldPermissionMap, userRoles: readonly string[]): FieldWritePermissionResult<T>;
|
|
111
|
-
/**
|
|
112
|
-
* Resolve effective roles by merging global user roles with org-level roles.
|
|
113
|
-
*
|
|
114
|
-
* Global roles come from `req.user.role` (normalized via getUserRoles()).
|
|
115
|
-
* Org roles come from `req.context.orgRoles` (set by BA adapter's org bridge).
|
|
116
|
-
*
|
|
117
|
-
* When no org context exists, returns global roles only — backward compatible.
|
|
118
|
-
*/
|
|
119
|
-
declare function resolveEffectiveRoles(userRoles: readonly string[], orgRoles: readonly string[]): string[];
|
|
120
|
-
//#endregion
|
|
121
|
-
export { applyFieldWritePermissions as a, applyFieldReadPermissions as i, FieldPermissionMap as n, fields as o, FieldPermissionType as r, resolveEffectiveRoles as s, FieldPermission as t };
|