@classytic/arc 2.28.0 → 2.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{BaseController-B65zbz9m.mjs → BaseController-B5DwufbB.mjs} +12 -10
- package/dist/EventTransport-C6YA8xY9.mjs +103 -0
- package/dist/{HookSystem-C1vB_Gc9.mjs → HookSystem-WkIougo6.mjs} +15 -35
- package/dist/applyPermissionResult-Cf6zUCvb.mjs +257 -0
- package/dist/audit/index.d.mts +2 -2
- package/dist/audit/index.mjs +1 -1
- package/dist/auth/index.d.mts +2 -2
- package/dist/auth/index.mjs +1 -1
- package/dist/{buildHandler-Dtwd8fdz.mjs → buildHandler-BYS3Vkfz.mjs} +32 -6
- package/dist/cleanup/index.d.mts +2 -2
- package/dist/cleanup/index.mjs +1 -1
- package/dist/cli/commands/describe.d.mts +1 -1
- package/dist/cli/commands/docs.mjs +1 -1
- package/dist/core/index.d.mts +2 -2
- package/dist/core/index.mjs +5 -4
- package/dist/{core-BGa8TXJR.mjs → core-poalJLvp.mjs} +2 -48
- package/dist/{createActionRouter-C-N7z2EL.mjs → createActionRouter-BxuywVRB.mjs} +2 -2
- package/dist/{createAggregationRouter-wzwFa_dW.mjs → createAggregationRouter-BiY-lGdY.mjs} +7 -20
- package/dist/{createApp-Du5G54TM.mjs → createApp-CXrKFciH.mjs} +24 -3
- package/dist/defineAggregation-ufWjUwml.mjs +47 -0
- package/dist/{defineResource-2zvVVpxg.mjs → defineResource-CxWqDCAy.mjs} +35 -42
- package/dist/docs/index.d.mts +1 -1
- package/dist/docs/index.mjs +1 -1
- package/dist/{eventPlugin-DrQ_FesK.mjs → eventPlugin-D2NNR4py.mjs} +2 -103
- package/dist/events/index.mjs +4 -339
- package/dist/factory/index.d.mts +4 -4
- package/dist/factory/index.mjs +1 -1
- package/dist/{fastify-augmentation-OzYGIiU1.d.mts → fastify-augmentation-0WhPnUH7.d.mts} +3 -3
- package/dist/{applyPermissionResult-BnyVE9eD.mjs → fields-CQ_7KQWw.mjs} +1 -107
- package/dist/hooks/index.d.mts +1 -1
- package/dist/hooks/index.mjs +1 -1
- package/dist/idempotency/index.mjs +1 -1
- package/dist/{index-CZY4EGga.d.mts → index-CCzVR-N3.d.mts} +1 -1
- package/dist/{index-BMnbzvtO.d.mts → index-Ch16aAah.d.mts} +201 -21
- package/dist/{index-CjVg-Epg.d.mts → index-Cx7bro4R.d.mts} +4 -4
- package/dist/{index-DPRH0Cme.d.mts → index-Q5gzEIWY.d.mts} +97 -66
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +8 -7
- package/dist/integrations/index.d.mts +1 -1
- package/dist/integrations/mcp/index.d.mts +6 -6
- 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/{mcpPlugin-Cs6nRGCt.mjs → mcpPlugin-nRzm5g2s.mjs} +36 -43
- package/dist/middleware/index.d.mts +1 -1
- package/dist/migrations/index.d.mts +0 -3
- package/dist/migrations/index.mjs +0 -3
- package/dist/{openapi-BLV4OMXb.mjs → openapi-B8Vkbxbn.mjs} +1 -1
- package/dist/permissions/index.d.mts +3 -3
- package/dist/permissions/index.mjs +4 -3
- package/dist/{permissions-BrtiBKGs.mjs → permissions-Bfu_8y1U.mjs} +318 -289
- package/dist/pipeline/index.d.mts +1 -1
- package/dist/{pipeline-BGRnV-To.mjs → pipeline-BJnpkY9i.mjs} +4 -18
- package/dist/plugins/index.d.mts +4 -4
- package/dist/plugins/index.mjs +2 -2
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/{preloadResources-CM4uUaFv.d.mts → preloadResources-DCfa2egz.d.mts} +3 -3
- package/dist/presets/filesUpload.d.mts +2 -2
- package/dist/presets/filesUpload.mjs +1 -1
- package/dist/presets/index.d.mts +14 -2
- package/dist/presets/index.mjs +1 -1
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/presets/search.d.mts +2 -2
- package/dist/presets/search.mjs +1 -1
- package/dist/{presets-DwFDVKP0.mjs → presets-CJOEXLuk.mjs} +25 -9
- package/dist/projection-UBDgfMwu.mjs +17 -0
- package/dist/{realtime-DEuDu9io.mjs → realtime-B9nmIY5V.mjs} +2 -1
- package/dist/{registerRoute-DTp18Ah_.mjs → registerRoute-JkxIEBJq.mjs} +3 -1
- package/dist/registry/index.d.mts +2 -2
- package/dist/registry/index.mjs +1 -1
- package/dist/{registry-9km_w1aP.mjs → registry-BYXUUg21.mjs} +1 -1
- package/dist/repositoryFilter-Dz8k3S4P.mjs +44 -0
- package/dist/subscribe-helpers-DfzsivM6.mjs +339 -0
- package/dist/testing/index.d.mts +34 -6
- package/dist/testing/index.mjs +314 -211
- package/dist/types/index.d.mts +3 -3
- package/dist/{types-QFGc3Cjv.d.mts → types-Bmmn-fO0.d.mts} +1 -1
- package/dist/{types-Dmw-6Qeo.d.mts → types-ChvvVNP8.d.mts} +93 -88
- package/dist/{types-Cu6vVJmh.d.mts → types-D_n8L6VY.d.mts} +32 -1
- package/dist/usage/index.d.mts +1 -1
- package/dist/usage/index.mjs +0 -0
- package/dist/utils/index.d.mts +2 -5
- package/package.json +539 -539
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Ct as PipelineStep, Rt as IControllerResponse, St as PipelineContext, _t as Guard, bt as OperationFilter, vt as Interceptor, wt as Transform, xt as PipelineConfig, yt as NextFunction } from "../index-
|
|
1
|
+
import { Ct as PipelineStep, Rt as IControllerResponse, St as PipelineContext, _t as Guard, bt as OperationFilter, vt as Interceptor, wt as Transform, xt as PipelineConfig, yt as NextFunction } from "../index-Q5gzEIWY.mjs";
|
|
2
2
|
//#region src/pipeline/guard.d.ts
|
|
3
3
|
interface GuardOptions {
|
|
4
4
|
operations?: OperationFilter;
|
|
@@ -1,23 +1,9 @@
|
|
|
1
1
|
import { n as getUserRoles } from "./userHelpers-Cg_y3fBz.mjs";
|
|
2
|
-
import { b as isElevated,
|
|
3
|
-
import { i as
|
|
2
|
+
import { b as isElevated, n as PUBLIC_SCOPE, x as isMember } from "./types-CSyCxl2V.mjs";
|
|
3
|
+
import { i as resolveEffectiveRoles, t as applyFieldReadPermissions } from "./fields-CQ_7KQWw.mjs";
|
|
4
4
|
import { t as executePipeline } from "./pipe-BOLmGIxa.mjs";
|
|
5
|
+
import { t as buildRequestScopeProjection } from "./projection-UBDgfMwu.mjs";
|
|
5
6
|
import { isPaginatedResult, toCanonicalList } from "@classytic/repo-core/pagination";
|
|
6
|
-
//#region src/scope/projection.ts
|
|
7
|
-
/**
|
|
8
|
-
* Compute the request-scope projection. Returns `undefined` when no
|
|
9
|
-
* scope is attached (public / unscoped routes) so hosts can idiomatically
|
|
10
|
-
* write `ctx.scope?.organizationId` without a double-null check.
|
|
11
|
-
*/
|
|
12
|
-
function buildRequestScopeProjection(scope) {
|
|
13
|
-
if (!scope) return void 0;
|
|
14
|
-
return {
|
|
15
|
-
organizationId: getOrgId(scope),
|
|
16
|
-
userId: getUserId(scope),
|
|
17
|
-
orgRoles: isMember(scope) ? scope.orgRoles : void 0
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
//#endregion
|
|
21
7
|
//#region src/core/fastifyAdapter.ts
|
|
22
8
|
/** Type guard for Mongoose-like documents with toObject() */
|
|
23
9
|
function isMongooseDoc(obj) {
|
|
@@ -334,4 +320,4 @@ function buildActionPipelineHandler(handler, steps, operation, resourceName) {
|
|
|
334
320
|
};
|
|
335
321
|
}
|
|
336
322
|
//#endregion
|
|
337
|
-
export { createFastifyHandler as a, getControllerScope as c, createCrudHandlers as i, sendControllerResponse as l, buildPipelineHandler as n, createRequestContext as o, resolvePipelineSteps as r, getControllerContext as s, buildActionPipelineHandler as t
|
|
323
|
+
export { createFastifyHandler as a, getControllerScope as c, createCrudHandlers as i, sendControllerResponse as l, buildPipelineHandler as n, createRequestContext as o, resolvePipelineSteps as r, getControllerContext as s, buildActionPipelineHandler as t };
|
package/dist/plugins/index.d.mts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { At as RouteDefinition, J as PresetHook, Q as MiddlewareConfig, et as RouteSchemaOptions } from "../index-
|
|
2
|
-
import {
|
|
1
|
+
import { At as RouteDefinition, J as PresetHook, Q as MiddlewareConfig, et as RouteSchemaOptions } from "../index-Q5gzEIWY.mjs";
|
|
2
|
+
import { l as AnyRecord } from "../types-ChvvVNP8.mjs";
|
|
3
3
|
import { i as errorHandlerPlugin, n as ErrorMapper, r as defaultIsDuplicateKeyError, t as ErrorHandlerOptions } from "../errorHandler-C6yv4ZTW.mjs";
|
|
4
|
-
import { _ as _default$3, d as ScheduleStats, f as SchedulesPluginOptions, g as HealthOptions, h as HealthCheck, m as schedulesPlugin, p as _default$7, u as ScheduleDefinition, v as healthPlugin } from "../types-
|
|
5
|
-
import { a as arcCorePlugin, i as _default, n as ArcCorePluginOptions, r as PluginMeta, t as ArcCore } from "../fastify-augmentation-
|
|
4
|
+
import { _ as _default$3, d as ScheduleStats, f as SchedulesPluginOptions, g as HealthOptions, h as HealthCheck, m as schedulesPlugin, p as _default$7, u as ScheduleDefinition, v as healthPlugin } from "../types-D_n8L6VY.mjs";
|
|
5
|
+
import { a as arcCorePlugin, i as _default, n as ArcCorePluginOptions, r as PluginMeta, t as ArcCore } from "../fastify-augmentation-0WhPnUH7.mjs";
|
|
6
6
|
import { _ as CachingRule, a as MetricsCollector, c as metricsPlugin, d as _default$5, f as realtimePlugin, g as CachingOptions, h as ssePlugin, i as MetricEntry, l as ChangeOperation, m as _default$8, n as _default$9, o as MetricsOptions, p as SSEOptions, r as versioningPlugin, s as _default$4, t as VersioningOptions, u as RealtimeOptions, v as _default$1, y as cachingPlugin } from "../versioning-DXgY5BUm.mjs";
|
|
7
7
|
import { t as TracingOptions } from "../tracing-CsGKQJGg.mjs";
|
|
8
8
|
import { PaginatedResult } from "@classytic/repo-core/pagination";
|
package/dist/plugins/index.mjs
CHANGED
|
@@ -2,13 +2,13 @@ import { p as MUTATION_OPERATIONS } from "../constants-DNre0wRg.mjs";
|
|
|
2
2
|
import { c as getOrgId } from "../types-CSyCxl2V.mjs";
|
|
3
3
|
import { n as requestContext } from "../requestContext-MrlJwECf.mjs";
|
|
4
4
|
import { t as hasEvents } from "../typeGuards-C9KXUly6.mjs";
|
|
5
|
-
import { t as HookSystem } from "../HookSystem-
|
|
5
|
+
import { t as HookSystem } from "../HookSystem-WkIougo6.mjs";
|
|
6
6
|
import { t as ResourceRegistry } from "../ResourceRegistry-y9Hnypus.mjs";
|
|
7
7
|
import { a as requestIdPlugin, i as createRequestIdGenerator, n as health_default, o as requestId_default, s as sanitizeRequestId, t as healthPlugin } from "../health-CB_m4S32.mjs";
|
|
8
8
|
import { n as caching_default, t as cachingPlugin } from "../caching-_NJeDd1_.mjs";
|
|
9
9
|
import { n as errorHandlerPlugin, t as defaultIsDuplicateKeyError } from "../errorHandler-Bq2OeEQL.mjs";
|
|
10
10
|
import { n as metrics_default, t as metricsPlugin } from "../metrics-fdxI5mn_.mjs";
|
|
11
|
-
import { n as realtime_default, t as realtimePlugin } from "../realtime-
|
|
11
|
+
import { n as realtime_default, t as realtimePlugin } from "../realtime-B9nmIY5V.mjs";
|
|
12
12
|
import { t as replyHelpersPlugin } from "../replyHelpers-67tRawQZ.mjs";
|
|
13
13
|
import { n as schedules_default, t as schedulesPlugin } from "../schedules-CjOd2MG9.mjs";
|
|
14
14
|
import { n as sse_default, t as ssePlugin } from "../sse-BQ1w0dfl.mjs";
|
|
@@ -58,7 +58,7 @@ try {
|
|
|
58
58
|
function createTracerProvider(options) {
|
|
59
59
|
if (!isAvailable || !NodeTracerProvider || !BatchSpanProcessor || !OTLPTraceExporter) return null;
|
|
60
60
|
const { serviceName = "@classytic/arc", serviceVersion, exporterUrl = "http://localhost:4318/v1/traces" } = options;
|
|
61
|
-
const resolvedVersion = serviceVersion ?? "2.
|
|
61
|
+
const resolvedVersion = serviceVersion ?? "2.30.0";
|
|
62
62
|
const exporter = new OTLPTraceExporter({ url: exporterUrl });
|
|
63
63
|
const provider = new NodeTracerProvider({ resource: { attributes: {
|
|
64
64
|
"service.name": serviceName,
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { Wt as Authenticator } from "./index-
|
|
1
|
+
import { Wt as Authenticator } from "./index-Q5gzEIWY.mjs";
|
|
2
2
|
import { r as CacheStore } from "./interface-BGZCzOGL.mjs";
|
|
3
3
|
import { n as ElevationOptions } from "./elevation-C9s5hFP_.mjs";
|
|
4
4
|
import { a as EventTransport } from "./EventTransport-QmY7A258.mjs";
|
|
5
5
|
import { t as ExternalOpenApiPaths } from "./externalPaths-BE6wFpYv.mjs";
|
|
6
6
|
import { r as QueryCachePluginOptions } from "./queryCachePlugin-br4otiqF.mjs";
|
|
7
7
|
import { t as ErrorHandlerOptions } from "./errorHandler-C6yv4ZTW.mjs";
|
|
8
|
-
import { f as SchedulesPluginOptions, g as HealthOptions, n as ArcModuleInput, s as ResourceLike } from "./types-
|
|
9
|
-
import "./index-
|
|
8
|
+
import { f as SchedulesPluginOptions, g as HealthOptions, n as ArcModuleInput, s as ResourceLike } from "./types-D_n8L6VY.mjs";
|
|
9
|
+
import "./index-CCzVR-N3.mjs";
|
|
10
10
|
import { t as EventPluginOptions } from "./eventPlugin-Bg3cP2_u.mjs";
|
|
11
11
|
import { g as CachingOptions, o as MetricsOptions, p as SSEOptions, t as VersioningOptions, u as RealtimeOptions } from "./versioning-DXgY5BUm.mjs";
|
|
12
12
|
import { r as IdempotencyStore } from "./interface-Uk8ONJv7.mjs";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Y as PresetResult } from "../index-
|
|
1
|
+
import { Y as PresetResult } from "../index-Q5gzEIWY.mjs";
|
|
2
2
|
import { i as RequestScope } from "../types-DjC-KUCz.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { r as PermissionCheck } from "../types-ChvvVNP8.mjs";
|
|
4
4
|
import { a as StorageReadResult, i as StorageReadRange, n as StorageContext, o as StorageUploadInput, r as StorageFile, t as Storage } from "../storage-DLUZ04kK.mjs";
|
|
5
5
|
//#region src/presets/filesUpload.d.ts
|
|
6
6
|
interface FilesUploadPresetRoutes {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { i as NotFoundError, u as ValidationError } from "../errors-DkO8Nk6-.mjs";
|
|
2
2
|
import { c as getOrgId, g as getUserId } from "../types-CSyCxl2V.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { I as requireAuth, j as allowPublic } from "../permissions-Bfu_8y1U.mjs";
|
|
4
4
|
import { t as multipartBody } from "../multipartBody-D0eBvkeq.mjs";
|
|
5
5
|
//#region src/presets/filesUpload.ts
|
|
6
6
|
const DEFAULT_FIELD_NAME = "file";
|
package/dist/presets/index.d.mts
CHANGED
|
@@ -1,11 +1,23 @@
|
|
|
1
|
-
import { Rt as IControllerResponse, U as ResourceConfig, Y as PresetResult, d as PaginationResult, zt as IRequestContext } from "../index-
|
|
2
|
-
import {
|
|
1
|
+
import { Rt as IControllerResponse, U as ResourceConfig, Y as PresetResult, d as PaginationResult, zt as IRequestContext } from "../index-Q5gzEIWY.mjs";
|
|
2
|
+
import { l as AnyRecord } from "../types-ChvvVNP8.mjs";
|
|
3
3
|
import { FilesUploadPresetOptions, FilesUploadPresetPermissions, FilesUploadPresetRoutes, filesUploadPreset } from "./filesUpload.mjs";
|
|
4
4
|
import { MultiTenantOptions, TenantFieldSpec, multiTenantPreset } from "./multiTenant.mjs";
|
|
5
5
|
import { SearchHandler, SearchPresetOptions, SearchRouteConfig, searchPreset } from "./search.mjs";
|
|
6
6
|
//#region src/presets/ownedByUser.d.ts
|
|
7
7
|
interface OwnedByUserOptions {
|
|
8
8
|
ownerField?: string;
|
|
9
|
+
/**
|
|
10
|
+
* What to do when a target record has NO value in `ownerField` (legacy /
|
|
11
|
+
* unowned records).
|
|
12
|
+
*
|
|
13
|
+
* - `"deny"` (default): fail closed — an unowned record is NOT modifiable
|
|
14
|
+
* through an ownership-gated route. This is the secure default; ownership
|
|
15
|
+
* that silently passes for records missing the owner is not an ownership
|
|
16
|
+
* primitive.
|
|
17
|
+
* - `"allow"`: legacy compatibility — permit modifying records that predate
|
|
18
|
+
* the owner field. Visibly unsafe; opt in only for a bounded migration.
|
|
19
|
+
*/
|
|
20
|
+
missingOwner?: "deny" | "allow";
|
|
9
21
|
}
|
|
10
22
|
declare function ownedByUserPreset(options?: OwnedByUserOptions): PresetResult;
|
|
11
23
|
//#endregion
|
package/dist/presets/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { multiTenantPreset } from "./multiTenant.mjs";
|
|
2
|
-
import { a as registerPreset, c as auditedPreset, d as ownedByUserPreset, i as getPreset, l as softDeletePreset, n as flexibleMultiTenantPreset, o as treePreset, r as getAvailablePresets, s as bulkPreset, t as applyPresets, u as slugLookupPreset } from "../presets-
|
|
2
|
+
import { a as registerPreset, c as auditedPreset, d as ownedByUserPreset, i as getPreset, l as softDeletePreset, n as flexibleMultiTenantPreset, o as treePreset, r as getAvailablePresets, s as bulkPreset, t as applyPresets, u as slugLookupPreset } from "../presets-CJOEXLuk.mjs";
|
|
3
3
|
import { filesUploadPreset } from "./filesUpload.mjs";
|
|
4
4
|
import { searchPreset } from "./search.mjs";
|
|
5
5
|
export { applyPresets, auditedPreset, bulkPreset, filesUploadPreset, flexibleMultiTenantPreset, getAvailablePresets, getPreset, multiTenantPreset, ownedByUserPreset, registerPreset, searchPreset, slugLookupPreset, softDeletePreset, treePreset };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { X as CrudRouteKey, Y as PresetResult } from "../index-
|
|
1
|
+
import { X as CrudRouteKey, Y as PresetResult } from "../index-Q5gzEIWY.mjs";
|
|
2
2
|
//#region src/presets/multiTenant.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* One tenant dimension for multi-field filtering. Discriminated by source:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { At as RouteDefinition, Pt as ControllerHandler, Y as PresetResult, jt as RouteMcpConfig } from "../index-
|
|
2
|
-
import {
|
|
1
|
+
import { At as RouteDefinition, Pt as ControllerHandler, Y as PresetResult, jt as RouteMcpConfig } from "../index-Q5gzEIWY.mjs";
|
|
2
|
+
import { r as PermissionCheck } from "../types-ChvvVNP8.mjs";
|
|
3
3
|
//#region src/presets/search.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* Search Preset — backend-agnostic search / vector / embed routes
|
package/dist/presets/search.mjs
CHANGED
|
@@ -1,29 +1,40 @@
|
|
|
1
|
+
import { l as UnauthorizedError } from "./errors-DkO8Nk6-.mjs";
|
|
1
2
|
import { b as isElevated, n as PUBLIC_SCOPE } from "./types-CSyCxl2V.mjs";
|
|
2
|
-
import {
|
|
3
|
+
import { I as requireAuth, R as requireRoles, j as allowPublic } from "./permissions-Bfu_8y1U.mjs";
|
|
3
4
|
import { multiTenantPreset } from "./presets/multiTenant.mjs";
|
|
4
5
|
//#region src/presets/ownedByUser.ts
|
|
5
6
|
/**
|
|
6
7
|
* Create ownership check middleware.
|
|
7
|
-
*
|
|
8
|
+
*
|
|
9
|
+
* FAIL-CLOSED: ownership is meaningless without an authenticated identity, so a
|
|
10
|
+
* request with no user (or a user with no id) is DENIED here rather than sliding
|
|
11
|
+
* through with no ownership check installed. Elevated scope (platform admin)
|
|
12
|
+
* bypasses the check by design.
|
|
8
13
|
*/
|
|
9
|
-
function createOwnershipCheck(ownerField) {
|
|
14
|
+
function createOwnershipCheck(ownerField, missingOwner) {
|
|
10
15
|
return async (request, _reply) => {
|
|
11
|
-
const user = request.user;
|
|
12
|
-
if (!user) return;
|
|
13
16
|
if (isElevated(request.scope ?? PUBLIC_SCOPE)) return;
|
|
17
|
+
const user = request.user;
|
|
18
|
+
if (!user) throw new UnauthorizedError("Authentication required for this operation");
|
|
14
19
|
const userWithId = user;
|
|
15
20
|
const userId = userWithId._id ?? userWithId.id;
|
|
16
|
-
if (userId)
|
|
21
|
+
if (!userId) throw new UnauthorizedError("Authenticated identity has no usable id");
|
|
22
|
+
request._ownershipCheck = {
|
|
17
23
|
field: ownerField,
|
|
18
|
-
userId
|
|
24
|
+
userId,
|
|
25
|
+
missingOwner
|
|
19
26
|
};
|
|
20
27
|
};
|
|
21
28
|
}
|
|
22
29
|
function ownedByUserPreset(options = {}) {
|
|
23
|
-
const { ownerField = "userId" } = options;
|
|
24
|
-
const ownershipMiddleware = createOwnershipCheck(ownerField);
|
|
30
|
+
const { ownerField = "userId", missingOwner = "deny" } = options;
|
|
31
|
+
const ownershipMiddleware = createOwnershipCheck(ownerField, missingOwner);
|
|
25
32
|
return {
|
|
26
33
|
name: "ownedByUser",
|
|
34
|
+
permissions: {
|
|
35
|
+
update: requireAuth(),
|
|
36
|
+
delete: requireAuth()
|
|
37
|
+
},
|
|
27
38
|
middlewares: {
|
|
28
39
|
update: [ownershipMiddleware],
|
|
29
40
|
delete: [ownershipMiddleware]
|
|
@@ -366,6 +377,11 @@ function mergePreset(config, preset) {
|
|
|
366
377
|
result.middlewares[key] = [...result.middlewares[key] ?? [], ...mws ?? []];
|
|
367
378
|
}
|
|
368
379
|
}
|
|
380
|
+
if (preset.permissions) {
|
|
381
|
+
const merged = { ...result.permissions };
|
|
382
|
+
for (const [op, check] of Object.entries(preset.permissions)) if (merged[op] === void 0 && check !== void 0) merged[op] = check;
|
|
383
|
+
result.permissions = merged;
|
|
384
|
+
}
|
|
369
385
|
if (preset.schemaOptions) result.schemaOptions = {
|
|
370
386
|
...result.schemaOptions,
|
|
371
387
|
...preset.schemaOptions,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { c as getOrgId, g as getUserId, x as isMember } from "./types-CSyCxl2V.mjs";
|
|
2
|
+
//#region src/scope/projection.ts
|
|
3
|
+
/**
|
|
4
|
+
* Compute the request-scope projection. Returns `undefined` when no
|
|
5
|
+
* scope is attached (public / unscoped routes) so hosts can idiomatically
|
|
6
|
+
* write `ctx.scope?.organizationId` without a double-null check.
|
|
7
|
+
*/
|
|
8
|
+
function buildRequestScopeProjection(scope) {
|
|
9
|
+
if (!scope) return void 0;
|
|
10
|
+
return {
|
|
11
|
+
organizationId: getOrgId(scope),
|
|
12
|
+
userId: getUserId(scope),
|
|
13
|
+
orgRoles: isMember(scope) ? scope.orgRoles : void 0
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { buildRequestScopeProjection as t };
|
|
@@ -3,7 +3,8 @@ import { arcLog } from "./logger/index.mjs";
|
|
|
3
3
|
import { n as getUserRoles } from "./userHelpers-Cg_y3fBz.mjs";
|
|
4
4
|
import { c as getOrgId } from "./types-CSyCxl2V.mjs";
|
|
5
5
|
import { t as simpleEqualityMatcher } from "./simpleEqualityMatcher-Cg05HPsn.mjs";
|
|
6
|
-
import {
|
|
6
|
+
import { r as evaluateAndApplyPermission } from "./applyPermissionResult-Cf6zUCvb.mjs";
|
|
7
|
+
import { t as applyFieldReadPermissions } from "./fields-CQ_7KQWw.mjs";
|
|
7
8
|
import { a as promoteStreamTokenToHeader } from "./streaming-BQcW6_Kq.mjs";
|
|
8
9
|
import { t as openSseStream } from "./sseStream-BQ7Qaynp.mjs";
|
|
9
10
|
import fp from "fastify-plugin";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { f as createError } from "./errors-DkO8Nk6-.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { u as getRequestScope } from "./types-CSyCxl2V.mjs";
|
|
3
|
+
import { r as evaluateAndApplyPermission } from "./applyPermissionResult-Cf6zUCvb.mjs";
|
|
3
4
|
//#region src/core/middlewares/permissions.ts
|
|
4
5
|
/**
|
|
5
6
|
* Build a PermissionContext from a Fastify request. Extracted so the CRUD
|
|
@@ -11,6 +12,7 @@ function buildPermissionContext(req, opts) {
|
|
|
11
12
|
const params = req.params;
|
|
12
13
|
return {
|
|
13
14
|
user: reqWithExtras.user ?? null,
|
|
15
|
+
scope: getRequestScope(req),
|
|
14
16
|
request: req,
|
|
15
17
|
resource: opts.resource,
|
|
16
18
|
action: opts.action,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { K as ResolvedTenantPurge, R as RegisterOptions, V as ResourceDefinition, X as CrudRouteKey, k as IntrospectionPluginOptions, p as RegistryEntry, z as ResourceRegistry } from "../index-
|
|
2
|
-
import "../fastify-augmentation-
|
|
1
|
+
import { K as ResolvedTenantPurge, R as RegisterOptions, V as ResourceDefinition, X as CrudRouteKey, k as IntrospectionPluginOptions, p as RegistryEntry, z as ResourceRegistry } from "../index-Q5gzEIWY.mjs";
|
|
2
|
+
import "../fastify-augmentation-0WhPnUH7.mjs";
|
|
3
3
|
import { FastifyPluginAsync } from "fastify";
|
|
4
4
|
import { TenantPurgeProgress, TenantPurgeStrategy } from "@classytic/repo-core/repository";
|
|
5
5
|
//#region src/registry/assertNoTenantData.d.ts
|
package/dist/registry/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as cascadeDeleteForOrganization, c as assertNoTenantData, i as introspectionPlugin_default, n as buildResourceManifestFromRegistry, o as getCascadingResources, r as introspectionPlugin, s as getCascadingResourcesWithMetadata, t as buildResourceManifest } from "../registry-
|
|
1
|
+
import { a as cascadeDeleteForOrganization, c as assertNoTenantData, i as introspectionPlugin_default, n as buildResourceManifestFromRegistry, o as getCascadingResources, r as introspectionPlugin, s as getCascadingResourcesWithMetadata, t as buildResourceManifest } from "../registry-BYXUUg21.mjs";
|
|
2
2
|
import { t as ResourceRegistry } from "../ResourceRegistry-y9Hnypus.mjs";
|
|
3
3
|
export { ResourceRegistry, assertNoTenantData, buildResourceManifest, buildResourceManifestFromRegistry, cascadeDeleteForOrganization, getCascadingResources, getCascadingResourcesWithMetadata, introspectionPlugin_default as introspectionPlugin, introspectionPlugin as introspectionPluginFn };
|
|
@@ -440,7 +440,7 @@ var introspectionPlugin_default = fp(introspectionPlugin, { name: "arc-introspec
|
|
|
440
440
|
//#endregion
|
|
441
441
|
//#region src/registry/manifest.ts
|
|
442
442
|
/**
|
|
443
|
-
* Resource manifest for frontend code generators
|
|
443
|
+
* Resource manifest for frontend code generators.
|
|
444
444
|
*
|
|
445
445
|
* Every host that hand-rolls a `createCrudApi('foo')` helper on the frontend
|
|
446
446
|
* ends up rewriting the same shim for declarative actions: `postAction(id,
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { arcLog } from "./logger/index.mjs";
|
|
2
|
+
import { policyRecordToFilter } from "@classytic/repo-core/filter";
|
|
3
|
+
//#region src/core/repositoryFilter.ts
|
|
4
|
+
const log = arcLog("repository-filter");
|
|
5
|
+
let warnedUnconvertible = false;
|
|
6
|
+
/** True for a `{ $op: ... }` operator object (all keys `$`-prefixed). */
|
|
7
|
+
function isOperatorObject(value) {
|
|
8
|
+
if (value === null || typeof value !== "object") return false;
|
|
9
|
+
if (Array.isArray(value) || value instanceof Date) return false;
|
|
10
|
+
const keys = Object.keys(value);
|
|
11
|
+
return keys.length > 0 && keys.some((k) => k.startsWith("$"));
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Does this compound filter contain any `$`-operator (top-level logical like
|
|
15
|
+
* `$and`/`$or`, or a field operator object like `{ $in: [...] }`)? If not, it is
|
|
16
|
+
* pure flat equality and portable as-is.
|
|
17
|
+
*/
|
|
18
|
+
function filterHasDollarOperator(record) {
|
|
19
|
+
for (const [key, value] of Object.entries(record)) {
|
|
20
|
+
if (key.startsWith("$")) return true;
|
|
21
|
+
if (isOperatorObject(value)) return true;
|
|
22
|
+
}
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Normalize a compound query/policy filter for the repository layer. Flat
|
|
27
|
+
* equality records pass through unchanged; anything carrying `$`-operators is
|
|
28
|
+
* converted to the portable repo-core {@link Filter} IR so it compiles
|
|
29
|
+
* identically on Mongo, SQLite, Postgres, and custom adapters.
|
|
30
|
+
*/
|
|
31
|
+
function toRepositoryFilter(record) {
|
|
32
|
+
if (!filterHasDollarOperator(record)) return record;
|
|
33
|
+
try {
|
|
34
|
+
return policyRecordToFilter(record);
|
|
35
|
+
} catch (err) {
|
|
36
|
+
if (!warnedUnconvertible) {
|
|
37
|
+
warnedUnconvertible = true;
|
|
38
|
+
log.warn(`A \`\$\`-operator filter could not be normalized to portable Filter IR (operator outside arc's policy dialect). Passing the raw record to the repository — MongoKit handles it; non-Mongo kits may not. (${err instanceof Error ? err.message : String(err)})`);
|
|
39
|
+
}
|
|
40
|
+
return record;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
export { toRepositoryFilter as t };
|