@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
package/dist/cleanup/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { L as RequestWithExtras } from "../index-
|
|
1
|
+
import { L as RequestWithExtras } from "../index-Q5gzEIWY.mjs";
|
|
2
2
|
import { A as CleanupWriteFence, C as CleanupResult, D as CleanupRunStore, E as CleanupRunStatus, F as PurgeStrategyKind, I as PurgeVerificationSummary, L as VerificationCheck, M as PurgeActor, N as PurgeEvidence, O as CleanupRunTransitionPatch, P as PurgeResourceResult, R as VerificationResult, S as CleanupRecipe, T as CleanupRunCreateResult, _ as CleanupPermissions, a as CleanupEvidenceStore, b as CleanupPlanItem, c as CleanupInput, d as CleanupLease, f as CleanupLimits, g as CleanupPermissionCheck, h as CleanupOutcomeStatus, i as CleanupContext, j as DEFAULT_CLEANUP_LIMITS, k as CleanupStepResult, l as CleanupJob, m as CleanupManifest, n as CLEANUP_TERMINAL_STATUSES, o as CleanupExecutionContext, p as CleanupLogger, r as CleanupCancelRequest, s as CleanupFinalizationPayload, t as Availability, u as CleanupJobQueue, v as CleanupPlan, w as CleanupRun, x as CleanupProgressSummary, y as CleanupPlanDraft } from "../types-C_ZZRcD6.mjs";
|
|
3
|
-
import { t as ArcModule } from "../types-
|
|
3
|
+
import { t as ArcModule } from "../types-D_n8L6VY.mjs";
|
|
4
4
|
import { PurgeStrategyKind as PurgeStrategyKind$1 } from "@classytic/primitives/retention";
|
|
5
5
|
import { canonicalJson } from "@classytic/primitives/canonical";
|
|
6
6
|
import { CleanupStep } from "@classytic/repo-core/cleanup";
|
package/dist/cleanup/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { g as getUserId } from "../types-CSyCxl2V.mjs";
|
|
2
|
-
import { t as defineResource } from "../defineResource-
|
|
2
|
+
import { t as defineResource } from "../defineResource-CxWqDCAy.mjs";
|
|
3
3
|
import { t as defineModule } from "../module-_-M7C5ES.mjs";
|
|
4
4
|
import { createPurgeEvidence } from "@classytic/primitives/retention";
|
|
5
5
|
import { canonicalJson, sha256Hex } from "@classytic/primitives/canonical";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Nt as RateLimitConfig, V as ResourceDefinition, et as RouteSchemaOptions } from "../../index-
|
|
1
|
+
import { Nt as RateLimitConfig, V as ResourceDefinition, et as RouteSchemaOptions } from "../../index-Q5gzEIWY.mjs";
|
|
2
2
|
//#region src/cli/commands/describe.d.ts
|
|
3
3
|
interface DescribedResource {
|
|
4
4
|
name: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as buildOpenApiSpec } from "../../openapi-
|
|
1
|
+
import { t as buildOpenApiSpec } from "../../openapi-B8Vkbxbn.mjs";
|
|
2
2
|
import { t as loadResourcesFromEntry } from "../../loadResourcesFromEntry-kvGT6EcO.mjs";
|
|
3
3
|
import { dirname, resolve } from "node:path";
|
|
4
4
|
import { mkdirSync, writeFileSync } from "node:fs";
|
package/dist/core/index.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { $t as SlugExt, An as ControllerConfigurableOptions, B as defineResource, Jt as BaseController, Mn as ListResult, Nn as BodySanitizer, Pn as BodySanitizerConfig, Qt as TreeMixin, V as ResourceDefinition, Xt as SoftDeleteMixin, Yt as SoftDeleteExt, Zt as TreeExt, an as QueryResolverConfig, ct as AggMeasureShorthand, dt as AggregationDateRangeRequirement, en as SlugMixin, ft as AggregationIndexHint, gt as AggregationsMap, ht as AggregationRateLimit, in as QueryResolver, jn as ControllerConstructionOptions, kn as BaseControllerOptions, lt as AggregationCacheConfig, mt as AggregationMaterializedResult, nn as BulkMixin, on as AccessControl, pt as AggregationMaterializedContext, rn as BaseCrudController, sn as AccessControlConfig, st as AggMeasureInput, tn as BulkExt, ut as AggregationConfig } from "../index-
|
|
2
|
-
import { A as DEFAULT_ID_FIELD, B as MAX_FILTER_DEPTH, C as DefineActionConfig, D as defineAggregation, E as createPermissionMiddleware, F as DEFAULT_UPDATE_METHOD, G as RESERVED_QUERY_PARAMS, H as MAX_SEARCH_LENGTH, I as HOOK_OPERATIONS, K as SYSTEM_FIELDS, L as HOOK_PHASES, M as DEFAULT_MAX_LIMIT, N as DEFAULT_SORT, O as CRUD_OPERATIONS, P as DEFAULT_TENANT_FIELD, R as HookOperation, S as mergeResourceConfig, T as createCrudRouter, U as MUTATION_OPERATIONS, V as MAX_REGEX_LENGTH, W as MutationOperation, _ as getEntityQuery, a as formatValidationErrors, b as ResourceSeams, c as isFieldReadable, d as createRequestContext, f as getControllerContext, g as getEntityIdField, h as getEntityId, i as assertValidConfig, j as DEFAULT_LIMIT, k as CrudOperation, l as createCrudHandlers, m as sendControllerResponse, n as ValidateOptions, o as validateResourceConfig, p as getControllerScope, r as ValidationResult, s as collectReadBlockedFields, t as ConfigError, u as createFastifyHandler, v as defineResourceVariants, w as defineAction, x as SeamedResourceConfig, y as AdapterLike, z as HookPhase } from "../index-
|
|
1
|
+
import { $t as SlugExt, An as ControllerConfigurableOptions, B as defineResource, Jt as BaseController, Mn as ListResult, Nn as BodySanitizer, Pn as BodySanitizerConfig, Qt as TreeMixin, V as ResourceDefinition, Xt as SoftDeleteMixin, Yt as SoftDeleteExt, Zt as TreeExt, an as QueryResolverConfig, ct as AggMeasureShorthand, dt as AggregationDateRangeRequirement, en as SlugMixin, ft as AggregationIndexHint, gt as AggregationsMap, ht as AggregationRateLimit, in as QueryResolver, jn as ControllerConstructionOptions, kn as BaseControllerOptions, lt as AggregationCacheConfig, mt as AggregationMaterializedResult, nn as BulkMixin, on as AccessControl, pt as AggregationMaterializedContext, rn as BaseCrudController, sn as AccessControlConfig, st as AggMeasureInput, tn as BulkExt, ut as AggregationConfig } from "../index-Q5gzEIWY.mjs";
|
|
2
|
+
import { A as DEFAULT_ID_FIELD, B as MAX_FILTER_DEPTH, C as DefineActionConfig, D as defineAggregation, E as createPermissionMiddleware, F as DEFAULT_UPDATE_METHOD, G as RESERVED_QUERY_PARAMS, H as MAX_SEARCH_LENGTH, I as HOOK_OPERATIONS, K as SYSTEM_FIELDS, L as HOOK_PHASES, M as DEFAULT_MAX_LIMIT, N as DEFAULT_SORT, O as CRUD_OPERATIONS, P as DEFAULT_TENANT_FIELD, R as HookOperation, S as mergeResourceConfig, T as createCrudRouter, U as MUTATION_OPERATIONS, V as MAX_REGEX_LENGTH, W as MutationOperation, _ as getEntityQuery, a as formatValidationErrors, b as ResourceSeams, c as isFieldReadable, d as createRequestContext, f as getControllerContext, g as getEntityIdField, h as getEntityId, i as assertValidConfig, j as DEFAULT_LIMIT, k as CrudOperation, l as createCrudHandlers, m as sendControllerResponse, n as ValidateOptions, o as validateResourceConfig, p as getControllerScope, r as ValidationResult, s as collectReadBlockedFields, t as ConfigError, u as createFastifyHandler, v as defineResourceVariants, w as defineAction, x as SeamedResourceConfig, y as AdapterLike, z as HookPhase } from "../index-Cx7bro4R.mjs";
|
|
3
3
|
export { AccessControl, type AccessControlConfig, type AdapterLike, type AggMeasureInput, type AggMeasureShorthand, type AggregationCacheConfig, type AggregationConfig, type AggregationDateRangeRequirement, type AggregationIndexHint, type AggregationMaterializedContext, type AggregationMaterializedResult, type AggregationRateLimit, type AggregationsMap, BaseController, type BaseControllerOptions, BaseCrudController, BodySanitizer, type BodySanitizerConfig, type BulkExt, BulkMixin, CRUD_OPERATIONS, type ConfigError, type ControllerConfigurableOptions, type ControllerConstructionOptions, CrudOperation, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, type DefineActionConfig, HOOK_OPERATIONS, HOOK_PHASES, HookOperation, HookPhase, type ListResult, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, MutationOperation, QueryResolver, type QueryResolverConfig, RESERVED_QUERY_PARAMS, ResourceDefinition, type ResourceSeams, SYSTEM_FIELDS, type SeamedResourceConfig, type SlugExt, SlugMixin, type SoftDeleteExt, SoftDeleteMixin, type TreeExt, TreeMixin, type ValidateOptions, type ValidationResult, assertValidConfig, collectReadBlockedFields, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineAction, defineAggregation, defineResource, defineResourceVariants, formatValidationErrors, getControllerContext, getControllerScope, getEntityId, getEntityIdField, getEntityQuery, isFieldReadable, mergeResourceConfig, sendControllerResponse, validateResourceConfig };
|
package/dist/core/index.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { a as DEFAULT_SORT, c as HOOK_OPERATIONS, d as MAX_REGEX_LENGTH, f as MAX_SEARCH_LENGTH, h as SYSTEM_FIELDS, i as DEFAULT_MAX_LIMIT, l as HOOK_PHASES, m as RESERVED_QUERY_PARAMS, n as DEFAULT_ID_FIELD, o as DEFAULT_TENANT_FIELD, p as MUTATION_OPERATIONS, r as DEFAULT_LIMIT, s as DEFAULT_UPDATE_METHOD, t as CRUD_OPERATIONS, u as MAX_FILTER_DEPTH } from "../constants-DNre0wRg.mjs";
|
|
2
|
-
import { a as BulkMixin, c as collectReadBlockedFields, f as AccessControl, i as SlugMixin, l as isFieldReadable, n as TreeMixin, o as BaseCrudController, r as SoftDeleteMixin, s as QueryResolver, t as BaseController, u as BodySanitizer } from "../BaseController-
|
|
3
|
-
import { a as ResourceDefinition, i as validateResourceConfig, n as assertValidConfig, o as createCrudRouter, r as formatValidationErrors, s as createPermissionMiddleware, t as defineResource } from "../defineResource-
|
|
4
|
-
import { a as createFastifyHandler, c as getControllerScope, i as createCrudHandlers, l as sendControllerResponse, o as createRequestContext, s as getControllerContext } from "../pipeline-
|
|
5
|
-
import {
|
|
2
|
+
import { a as BulkMixin, c as collectReadBlockedFields, f as AccessControl, i as SlugMixin, l as isFieldReadable, n as TreeMixin, o as BaseCrudController, r as SoftDeleteMixin, s as QueryResolver, t as BaseController, u as BodySanitizer } from "../BaseController-B5DwufbB.mjs";
|
|
3
|
+
import { a as ResourceDefinition, i as validateResourceConfig, n as assertValidConfig, o as createCrudRouter, r as formatValidationErrors, s as createPermissionMiddleware, t as defineResource } from "../defineResource-CxWqDCAy.mjs";
|
|
4
|
+
import { a as createFastifyHandler, c as getControllerScope, i as createCrudHandlers, l as sendControllerResponse, o as createRequestContext, s as getControllerContext } from "../pipeline-BJnpkY9i.mjs";
|
|
5
|
+
import { t as defineAggregation } from "../defineAggregation-ufWjUwml.mjs";
|
|
6
|
+
import { a as mergeResourceConfig, i as defineResourceVariants, n as getEntityIdField, o as defineAction, r as getEntityQuery, t as getEntityId } from "../core-poalJLvp.mjs";
|
|
6
7
|
export { AccessControl, BaseController, BaseCrudController, BodySanitizer, BulkMixin, CRUD_OPERATIONS, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, HOOK_OPERATIONS, HOOK_PHASES, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, QueryResolver, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, SlugMixin, SoftDeleteMixin, TreeMixin, assertValidConfig, collectReadBlockedFields, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineAction, defineAggregation, defineResource, defineResourceVariants, formatValidationErrors, getControllerContext, getControllerScope, getEntityId, getEntityIdField, getEntityQuery, isFieldReadable, mergeResourceConfig, sendControllerResponse, validateResourceConfig };
|
|
@@ -1,51 +1,5 @@
|
|
|
1
1
|
import "./constants-DNre0wRg.mjs";
|
|
2
|
-
import { t as defineResource } from "./defineResource-
|
|
3
|
-
//#region src/core/aggregation/defineAggregation.ts
|
|
4
|
-
/**
|
|
5
|
-
* Declare a single resource aggregation. Exported configs flow into
|
|
6
|
-
* `defineResource({ aggregations: { ... } })` either as named keys or
|
|
7
|
-
* via auto-discovery patterns (loadAggregations — future).
|
|
8
|
-
*
|
|
9
|
-
* @example Inline
|
|
10
|
-
* ```ts
|
|
11
|
-
* defineResource({
|
|
12
|
-
* name: 'order',
|
|
13
|
-
* aggregations: {
|
|
14
|
-
* revenueByStatus: defineAggregation({
|
|
15
|
-
* groupBy: 'status',
|
|
16
|
-
* measures: { count: 'count', revenue: 'sum:totalPrice' },
|
|
17
|
-
* permissions: requireRoles(['admin']),
|
|
18
|
-
* }),
|
|
19
|
-
* },
|
|
20
|
-
* });
|
|
21
|
-
* ```
|
|
22
|
-
*
|
|
23
|
-
* @example Multi-file
|
|
24
|
-
* ```ts
|
|
25
|
-
* // orders/aggregations/revenue-by-status.ts
|
|
26
|
-
* import { defineAggregation } from '@classytic/arc';
|
|
27
|
-
*
|
|
28
|
-
* export const revenueByStatus = defineAggregation({
|
|
29
|
-
* groupBy: 'status',
|
|
30
|
-
* measures: { count: 'count', revenue: 'sum:totalPrice' },
|
|
31
|
-
* permissions: requireRoles(['admin']),
|
|
32
|
-
* timeout: 5000,
|
|
33
|
-
* cache: { staleTime: 60 },
|
|
34
|
-
* });
|
|
35
|
-
*
|
|
36
|
-
* // orders/order.resource.ts
|
|
37
|
-
* import * as aggregations from './aggregations/index.js';
|
|
38
|
-
*
|
|
39
|
-
* defineResource({
|
|
40
|
-
* name: 'order',
|
|
41
|
-
* aggregations, // 30+ entries flow in
|
|
42
|
-
* });
|
|
43
|
-
* ```
|
|
44
|
-
*/
|
|
45
|
-
function defineAggregation(config) {
|
|
46
|
-
return config;
|
|
47
|
-
}
|
|
48
|
-
//#endregion
|
|
2
|
+
import { t as defineResource } from "./defineResource-CxWqDCAy.mjs";
|
|
49
3
|
//#region src/core/defineAction.ts
|
|
50
4
|
/**
|
|
51
5
|
* Build an `ActionDefinition` with a typed handler. The literal schema
|
|
@@ -218,4 +172,4 @@ function getEntityQuery(req) {
|
|
|
218
172
|
return { [getEntityIdField(req)]: id };
|
|
219
173
|
}
|
|
220
174
|
//#endregion
|
|
221
|
-
export { mergeResourceConfig as a, defineResourceVariants as i, getEntityIdField as n, defineAction as o, getEntityQuery as r,
|
|
175
|
+
export { mergeResourceConfig as a, defineResourceVariants as i, getEntityIdField as n, defineAction as o, getEntityQuery as r, getEntityId as t };
|
|
@@ -2,8 +2,8 @@ import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.mjs";
|
|
|
2
2
|
import "./constants-DNre0wRg.mjs";
|
|
3
3
|
import { f as createError } from "./errors-DkO8Nk6-.mjs";
|
|
4
4
|
import { a as buildRouteHooks, i as selectPluginMw, l as buildAuthMiddlewareForPermissions, n as buildRouteConfig, r as resolveRouterPluginMw, s as routeHookOptions, t as buildRateLimitConfig, u as buildArcDecorator } from "./rateLimit-DrED-C4v.mjs";
|
|
5
|
-
import { n as buildActionPermissionMw, t as tryRegisterRoute } from "./registerRoute-
|
|
6
|
-
import { l as sendControllerResponse, r as resolvePipelineSteps, t as buildActionPipelineHandler } from "./pipeline-
|
|
5
|
+
import { n as buildActionPermissionMw, t as tryRegisterRoute } from "./registerRoute-JkxIEBJq.mjs";
|
|
6
|
+
import { l as sendControllerResponse, r as resolvePipelineSteps, t as buildActionPipelineHandler } from "./pipeline-BJnpkY9i.mjs";
|
|
7
7
|
import { n as schemaIRToJsonSchemaBranch, t as normalizeSchemaIR } from "./schemaIR-Ca7ySNPx.mjs";
|
|
8
8
|
//#region src/core/createActionRouter.ts
|
|
9
9
|
var createActionRouter_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { f as createError
|
|
1
|
+
import { f as createError } from "./errors-DkO8Nk6-.mjs";
|
|
2
|
+
import { u as getRequestScope } from "./types-CSyCxl2V.mjs";
|
|
3
|
+
import { r as evaluateAndApplyPermission } from "./applyPermissionResult-Cf6zUCvb.mjs";
|
|
2
4
|
import { a as buildRouteHooks, c as buildAuthMiddleware, i as selectPluginMw, r as resolveRouterPluginMw, s as routeHookOptions, t as buildRateLimitConfig, u as buildArcDecorator } from "./rateLimit-DrED-C4v.mjs";
|
|
3
5
|
import { n as validateAggregations } from "./validate-Bk44F2yT.mjs";
|
|
4
|
-
import { t as buildAggregationHandler } from "./buildHandler-
|
|
6
|
+
import { t as buildAggregationHandler } from "./buildHandler-BYS3Vkfz.mjs";
|
|
5
7
|
//#region src/core/aggregation/createAggregationRouter.ts
|
|
6
8
|
/**
|
|
7
9
|
* Register one Fastify route per aggregation. No-op when the map is
|
|
@@ -38,15 +40,9 @@ function registerOne(fastify, normalized, ctx) {
|
|
|
38
40
|
const config = normalized.base;
|
|
39
41
|
const authMw = buildAuthMiddleware(fastify, config.permissions);
|
|
40
42
|
const permissionFn = config.permissions;
|
|
41
|
-
const permissionMw = async (req,
|
|
43
|
+
const permissionMw = async (req, reply) => {
|
|
42
44
|
const ctx = buildPermissionContextLite(req, normalized.name);
|
|
43
|
-
|
|
44
|
-
if (!normalizePermissionGranted(raw)) {
|
|
45
|
-
const status = req.user ? 403 : 401;
|
|
46
|
-
const reason = normalizePermissionReason(raw);
|
|
47
|
-
if (status === 401) throw new UnauthorizedError(reason ?? "Authentication required to access this aggregation.");
|
|
48
|
-
throw new ForbiddenError(reason ?? "You do not have permission to access this aggregation.");
|
|
49
|
-
}
|
|
45
|
+
await evaluateAndApplyPermission(permissionFn, ctx, req, reply, { defaultDenialMessage: (user) => user ? "You do not have permission to access this aggregation." : "Authentication required to access this aggregation." });
|
|
50
46
|
};
|
|
51
47
|
const hooks = buildRouteHooks({
|
|
52
48
|
arcDecorator,
|
|
@@ -99,20 +95,11 @@ function buildPermissionContextLite(req, aggregationName) {
|
|
|
99
95
|
const reqWithExtras = req;
|
|
100
96
|
return {
|
|
101
97
|
user: reqWithExtras.user ?? null,
|
|
98
|
+
scope: getRequestScope(req),
|
|
102
99
|
request: req,
|
|
103
100
|
resource: reqWithExtras.arc?.resource ?? "aggregation",
|
|
104
101
|
action: `aggregation:${aggregationName}`
|
|
105
102
|
};
|
|
106
103
|
}
|
|
107
|
-
/** PermissionCheck returns `boolean | PermissionResult`. Pull `granted`. */
|
|
108
|
-
function normalizePermissionGranted(raw) {
|
|
109
|
-
if (typeof raw === "boolean") return raw;
|
|
110
|
-
return raw.granted;
|
|
111
|
-
}
|
|
112
|
-
/** Pull `reason` when the check returned a structured `PermissionResult`. */
|
|
113
|
-
function normalizePermissionReason(raw) {
|
|
114
|
-
if (typeof raw === "boolean") return void 0;
|
|
115
|
-
return raw.reason;
|
|
116
|
-
}
|
|
117
104
|
//#endregion
|
|
118
105
|
export { createAggregationRouter };
|
|
@@ -4,6 +4,7 @@ import { n as PUBLIC_SCOPE } from "./types-CSyCxl2V.mjs";
|
|
|
4
4
|
import { t as createTenantKeyGenerator } from "./rateLimitKey-BoWRH3e7.mjs";
|
|
5
5
|
import { i as createRequestIdGenerator, r as mergeHealthChecks } from "./health-CB_m4S32.mjs";
|
|
6
6
|
import { t as parseJsonBody } from "./jsonBody-BlzAoGCe.mjs";
|
|
7
|
+
import { r as wrapWithBoundary } from "./subscribe-helpers-DfzsivM6.mjs";
|
|
7
8
|
import Fastify from "fastify";
|
|
8
9
|
import qs from "qs";
|
|
9
10
|
//#region src/factory/module/resolve.ts
|
|
@@ -100,8 +101,9 @@ async function subscribeModuleEventHandlers(fastify, modules) {
|
|
|
100
101
|
if (prior !== void 0) throw new Error(`[arc] duplicate event-handler name "${def.name}" — declared by module "${prior}" and module "${m.name}". Named event handlers must be unique across the module graph; prefix names with the owning module.`);
|
|
101
102
|
owner.set(def.name, m.name);
|
|
102
103
|
}
|
|
104
|
+
const handler = applyBoundary(def, m.name, fastify);
|
|
103
105
|
const patterns = Array.isArray(def.event) ? def.event : [def.event];
|
|
104
|
-
for (const pattern of patterns) unsubscribes.push(await bus.subscribe(pattern,
|
|
106
|
+
for (const pattern of patterns) unsubscribes.push(await bus.subscribe(pattern, handler));
|
|
105
107
|
}
|
|
106
108
|
}
|
|
107
109
|
return unsubscribes;
|
|
@@ -111,6 +113,25 @@ async function subscribeModuleEventHandlers(fastify, modules) {
|
|
|
111
113
|
throw err;
|
|
112
114
|
}
|
|
113
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* Apply the declaration's opt-in error boundary. Without `boundary`, the raw
|
|
118
|
+
* handler is subscribed and a throw reaches the transport — which is what makes
|
|
119
|
+
* the durable path work (unacked → redelivered → DLQ). With it, failures are
|
|
120
|
+
* logged through `fastify.log` and swallowed, for handlers whose retry would
|
|
121
|
+
* only delay the next event's resync.
|
|
122
|
+
*
|
|
123
|
+
* The boundary label falls back to `<module>.<pattern>` so an unnamed handler
|
|
124
|
+
* still produces an attributable log line instead of "anonymous".
|
|
125
|
+
*/
|
|
126
|
+
function applyBoundary(def, moduleName, fastify) {
|
|
127
|
+
if (!def.boundary) return def.handler;
|
|
128
|
+
const onError = typeof def.boundary === "object" ? def.boundary.onError : void 0;
|
|
129
|
+
return wrapWithBoundary(def.handler, {
|
|
130
|
+
logger: fastify.log,
|
|
131
|
+
name: def.name ?? `${moduleName}.${String(def.event)}`,
|
|
132
|
+
...onError ? { onError } : {}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
114
135
|
/** Best-effort reverse-order teardown; every unsubscribe is attempted. */
|
|
115
136
|
async function unsubscribeModuleEventHandlers(unsubscribes) {
|
|
116
137
|
const errors = [];
|
|
@@ -439,7 +460,7 @@ async function registerArcCore(fastify, config, trackPlugin) {
|
|
|
439
460
|
await fastify.register(arcCorePlugin, { emitEvents: config.arcPlugins?.emitEvents !== false });
|
|
440
461
|
trackPlugin("arc-core");
|
|
441
462
|
if (config.arcPlugins?.events !== false) {
|
|
442
|
-
const { default: eventPlugin } = await import("./eventPlugin-
|
|
463
|
+
const { default: eventPlugin } = await import("./eventPlugin-D2NNR4py.mjs").then((n) => n.n);
|
|
443
464
|
const eventOpts = typeof config.arcPlugins?.events === "object" ? config.arcPlugins.events : {};
|
|
444
465
|
await fastify.register(eventPlugin, {
|
|
445
466
|
...eventOpts,
|
|
@@ -511,7 +532,7 @@ async function registerArcPlugins(fastify, config, trackPlugin, modules, moduleH
|
|
|
511
532
|
}
|
|
512
533
|
if (config.arcPlugins?.realtime) if (config.arcPlugins?.events === false) fastify.log.warn("Realtime plugin requires events plugin (arcPlugins.events). Realtime disabled.");
|
|
513
534
|
else {
|
|
514
|
-
const { default: realtimePlugin } = await import("./realtime-
|
|
535
|
+
const { default: realtimePlugin } = await import("./realtime-B9nmIY5V.mjs").then((n) => n.r);
|
|
515
536
|
const opts = config.arcPlugins.realtime === true ? {} : config.arcPlugins.realtime;
|
|
516
537
|
await fastify.register(realtimePlugin, opts);
|
|
517
538
|
trackPlugin("arc-realtime", opts);
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
//#region src/core/aggregation/defineAggregation.ts
|
|
2
|
+
/**
|
|
3
|
+
* Declare a single resource aggregation. Exported configs flow into
|
|
4
|
+
* `defineResource({ aggregations: { ... } })` either as named keys or
|
|
5
|
+
* via auto-discovery patterns (loadAggregations — future).
|
|
6
|
+
*
|
|
7
|
+
* @example Inline
|
|
8
|
+
* ```ts
|
|
9
|
+
* defineResource({
|
|
10
|
+
* name: 'order',
|
|
11
|
+
* aggregations: {
|
|
12
|
+
* revenueByStatus: defineAggregation({
|
|
13
|
+
* groupBy: 'status',
|
|
14
|
+
* measures: { count: 'count', revenue: 'sum:totalPrice' },
|
|
15
|
+
* permissions: requireRoles(['admin']),
|
|
16
|
+
* }),
|
|
17
|
+
* },
|
|
18
|
+
* });
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @example Multi-file
|
|
22
|
+
* ```ts
|
|
23
|
+
* // orders/aggregations/revenue-by-status.ts
|
|
24
|
+
* import { defineAggregation } from '@classytic/arc';
|
|
25
|
+
*
|
|
26
|
+
* export const revenueByStatus = defineAggregation({
|
|
27
|
+
* groupBy: 'status',
|
|
28
|
+
* measures: { count: 'count', revenue: 'sum:totalPrice' },
|
|
29
|
+
* permissions: requireRoles(['admin']),
|
|
30
|
+
* timeout: 5000,
|
|
31
|
+
* cache: { staleTime: 60 },
|
|
32
|
+
* });
|
|
33
|
+
*
|
|
34
|
+
* // orders/order.resource.ts
|
|
35
|
+
* import * as aggregations from './aggregations/index.js';
|
|
36
|
+
*
|
|
37
|
+
* defineResource({
|
|
38
|
+
* name: 'order',
|
|
39
|
+
* aggregations, // 30+ entries flow in
|
|
40
|
+
* });
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
function defineAggregation(config) {
|
|
44
|
+
return config;
|
|
45
|
+
}
|
|
46
|
+
//#endregion
|
|
47
|
+
export { defineAggregation as t };
|
|
@@ -3,17 +3,17 @@ import { arcLog } from "./logger/index.mjs";
|
|
|
3
3
|
import { r as ForbiddenError } from "./errors-DkO8Nk6-.mjs";
|
|
4
4
|
import { n as getUserRoles } from "./userHelpers-Cg_y3fBz.mjs";
|
|
5
5
|
import { b as isElevated, n as PUBLIC_SCOPE, x as isMember } from "./types-CSyCxl2V.mjs";
|
|
6
|
-
import { d as DEFAULT_FIELD_WRITE_DENIAL_POLICY, t as BaseController } from "./BaseController-
|
|
6
|
+
import { d as DEFAULT_FIELD_WRITE_DENIAL_POLICY, t as BaseController } from "./BaseController-B5DwufbB.mjs";
|
|
7
7
|
import { a as buildRouteHooks, c as buildAuthMiddleware, i as selectPluginMw, n as buildRouteConfig, o as resolveRoutePreHandlers, r as resolveRouterPluginMw, s as routeHookOptions, t as buildRateLimitConfig, u as buildArcDecorator } from "./rateLimit-DrED-C4v.mjs";
|
|
8
|
-
import {
|
|
9
|
-
import { r as buildCrudPermissionMw, t as tryRegisterRoute } from "./registerRoute-
|
|
8
|
+
import { i as resolveEffectiveRoles, n as applyFieldWritePermissions } from "./fields-CQ_7KQWw.mjs";
|
|
9
|
+
import { r as buildCrudPermissionMw, t as tryRegisterRoute } from "./registerRoute-JkxIEBJq.mjs";
|
|
10
10
|
import { c as getDefaultCrudSchemas } from "./utils-taUVD4p3.mjs";
|
|
11
11
|
import { n as convertRouteSchema, r as ensureSchemaConverter, t as convertOpenApiSchemas } from "./schemaConverter-DJvodiHj.mjs";
|
|
12
12
|
import { i as pipeUIMessageStreamToReply, r as isReadableStream } from "./streaming-BQcW6_Kq.mjs";
|
|
13
13
|
import { t as hasEvents } from "./typeGuards-C9KXUly6.mjs";
|
|
14
|
-
import { a as createFastifyHandler, i as createCrudHandlers, n as buildPipelineHandler, o as createRequestContext, r as resolvePipelineSteps
|
|
15
|
-
import {
|
|
16
|
-
import { r as getAvailablePresets, t as applyPresets } from "./presets-
|
|
14
|
+
import { a as createFastifyHandler, i as createCrudHandlers, n as buildPipelineHandler, o as createRequestContext, r as resolvePipelineSteps } from "./pipeline-BJnpkY9i.mjs";
|
|
15
|
+
import { I as requireAuth } from "./permissions-Bfu_8y1U.mjs";
|
|
16
|
+
import { r as getAvailablePresets, t as applyPresets } from "./presets-CJOEXLuk.mjs";
|
|
17
17
|
import { t as pluralize } from "./pluralize-BhrgwZb9.mjs";
|
|
18
18
|
import { t as resolveActionPermission } from "./actionPermissions-CAphcmUG.mjs";
|
|
19
19
|
//#region src/core/middlewares/fieldWrite.ts
|
|
@@ -462,26 +462,6 @@ function buildBaseController(resolvedConfig, adapter, repository) {
|
|
|
462
462
|
//#endregion
|
|
463
463
|
//#region src/core/defineResource/hooks.ts
|
|
464
464
|
/**
|
|
465
|
-
* Phase 6 — wire preset hooks + inline `config.hooks` onto the
|
|
466
|
-
* resource's `_pendingHooks`.
|
|
467
|
-
*
|
|
468
|
-
* Two sources feed the same array:
|
|
469
|
-
* 1. Preset hooks collected during `applyPresets()` (raw `_hooks`
|
|
470
|
-
* on the internal config). Already in the canonical
|
|
471
|
-
* `{ operation, phase, handler, priority }` shape — copied
|
|
472
|
-
* verbatim (priority defaults to 10).
|
|
473
|
-
* 2. Inline `config.hooks.beforeCreate` / `afterCreate` / etc.
|
|
474
|
-
* Authored by the user on the original `ResourceConfig`.
|
|
475
|
-
* Wrapped in a `ResourceHookContext` projection (v2.10.8) so
|
|
476
|
-
* authors can read `scope` / `context` without reaching into
|
|
477
|
-
* internal request fields.
|
|
478
|
-
*
|
|
479
|
-
* The 6 inline hook keys (before/after × create/update/delete) used
|
|
480
|
-
* to be 6 nearly-identical blocks; collapsed into a table + loop so
|
|
481
|
-
* a future hook (e.g. `beforeRead`) is one row, not seven scattered
|
|
482
|
-
* edits.
|
|
483
|
-
*/
|
|
484
|
-
/**
|
|
485
465
|
* Combined entry-point for Phase 6. Pushes preset-collected hooks
|
|
486
466
|
* first, then inline `config.hooks` (so hosts can rely on
|
|
487
467
|
* registration order if priorities tie).
|
|
@@ -544,19 +524,17 @@ const INLINE_HOOK_SPECS = [
|
|
|
544
524
|
}
|
|
545
525
|
];
|
|
546
526
|
/**
|
|
547
|
-
* Project a raw HookSystem context into a `ResourceHookContext` for
|
|
548
|
-
*
|
|
549
|
-
*
|
|
550
|
-
* fields.
|
|
527
|
+
* Project a raw HookSystem context into a `ResourceHookContext` for inline
|
|
528
|
+
* `config.hooks.*` handlers. `scope` rides in already computed — `HookContext`
|
|
529
|
+
* carries the same projection — so the two surfaces cannot drift.
|
|
551
530
|
*/
|
|
552
531
|
function buildHookContext(ctx) {
|
|
553
532
|
const context = ctx.context;
|
|
554
|
-
const rawScope = context?._scope;
|
|
555
533
|
return {
|
|
556
534
|
data: ctx.data ?? ctx.result ?? {},
|
|
557
535
|
user: ctx.user,
|
|
558
536
|
context,
|
|
559
|
-
scope:
|
|
537
|
+
scope: ctx.scope,
|
|
560
538
|
meta: ctx.meta
|
|
561
539
|
};
|
|
562
540
|
}
|
|
@@ -802,7 +780,7 @@ function stripFromRequired(schema, fieldName) {
|
|
|
802
780
|
}
|
|
803
781
|
/**
|
|
804
782
|
* Strip framework-injected fields from the `required[]` list of every
|
|
805
|
-
* body-shaped slot in an adapter's generated schemas
|
|
783
|
+
* body-shaped slot in an adapter's generated schemas.
|
|
806
784
|
*
|
|
807
785
|
* A "framework-injected field" is any field marked `systemManaged: true`
|
|
808
786
|
* in `schemaOptions.fieldRules`. Arc populates those fields from the
|
|
@@ -957,22 +935,32 @@ const WRITE_OPERATIONS = /* @__PURE__ */ new Set([
|
|
|
957
935
|
* wiring, ...) count as gates and don't false-positive.
|
|
958
936
|
*
|
|
959
937
|
* Severity ladder:
|
|
960
|
-
* - `
|
|
961
|
-
*
|
|
938
|
+
* - `error` when any enabled WRITE op is ungated AND `strict` is on — the
|
|
939
|
+
* resource fails boot (`defineResource()` throws). This is the fail-closed
|
|
940
|
+
* production invariant: an unauthenticated write must never ship silently.
|
|
941
|
+
* - `warn` (default) when any enabled WRITE op (create/update/delete) is
|
|
942
|
+
* ungated — real exposure the host must acknowledge, but non-fatal so
|
|
943
|
+
* existing hosts are not broken.
|
|
962
944
|
* - `info` when only reads are ungated — public catalogs
|
|
963
945
|
* (`referenceData: true`) are a legitimate shape, but the host should
|
|
964
946
|
* still state intent with `permissions.fullPublic()` / `allowPublic()`.
|
|
947
|
+
*
|
|
948
|
+
* `strict` is opt-in (resource `strictPermissions: true` or the
|
|
949
|
+
* `ARC_STRICT_PERMISSIONS` env), so the default behavior is unchanged.
|
|
965
950
|
*/
|
|
966
|
-
function collectUngatedCrudDiagnostics(config) {
|
|
951
|
+
function collectUngatedCrudDiagnostics(config, strict = false) {
|
|
967
952
|
if (config.disableDefaultRoutes) return [];
|
|
968
953
|
const disabled = new Set(config.disabledRoutes ?? []);
|
|
969
954
|
const permissions = config.permissions ?? {};
|
|
970
955
|
const ungated = CRUD_OPERATIONS.filter((op) => !disabled.has(op) && typeof permissions[op] !== "function");
|
|
971
956
|
if (ungated.length === 0) return [];
|
|
957
|
+
const severity = ungated.some((op) => WRITE_OPERATIONS.has(op)) ? strict ? "error" : "warn" : "info";
|
|
972
958
|
return [{
|
|
973
|
-
severity
|
|
959
|
+
severity,
|
|
974
960
|
code: "crud-public-by-omission",
|
|
975
|
-
message: `[Arc] Resource '${config.name}' mounts ${ungated.length} CRUD route(s) with no permission gate: ${ungated.join(", ")}.\
|
|
961
|
+
message: `[Arc] Resource '${config.name}' mounts ${ungated.length} CRUD route(s) with no permission gate: ${ungated.join(", ")}.\n` + (severity === "error" ? "strictPermissions is on and an ungated WRITE is fatal. State intent explicitly:\n" : "An omitted permission mounts the route WITHOUT auth. State intent explicitly:\n") + ` permissions: permissions.fullPublic() // intentionally public
|
|
962
|
+
permissions: permissions.authenticated() // require auth on every op
|
|
963
|
+
permissions: { ${ungated[0]}: requireAuth(), ... } // per-operation`
|
|
976
964
|
}];
|
|
977
965
|
}
|
|
978
966
|
//#endregion
|
|
@@ -1217,7 +1205,7 @@ function buildResourcePlugin(resource) {
|
|
|
1217
1205
|
const isFirstMount = !resource._sharedStateRegisteredOn.has(sharedRoot);
|
|
1218
1206
|
if (isFirstMount) resource._sharedStateRegisteredOn.add(sharedRoot);
|
|
1219
1207
|
if (isFirstMount && resource._diagnostics?.length) for (const diagnostic of resource._diagnostics) {
|
|
1220
|
-
const level = diagnostic.severity === "info" ? "info" : "warn";
|
|
1208
|
+
const level = diagnostic.severity === "info" ? "info" : diagnostic.severity === "error" ? "error" : "warn";
|
|
1221
1209
|
fastify.log?.[level]?.(diagnostic.message);
|
|
1222
1210
|
}
|
|
1223
1211
|
const arc = fastify.arc;
|
|
@@ -1278,7 +1266,7 @@ function buildResourcePlugin(resource) {
|
|
|
1278
1266
|
extensions: resource.extensions
|
|
1279
1267
|
});
|
|
1280
1268
|
if (resource.actions && Object.keys(resource.actions).length > 0) {
|
|
1281
|
-
const { createActionRouter } = await import("./createActionRouter-
|
|
1269
|
+
const { createActionRouter } = await import("./createActionRouter-BxuywVRB.mjs").then((n) => n.n);
|
|
1282
1270
|
createActionRouter(typedInstance, {
|
|
1283
1271
|
...normalizeActionsToRouterConfig(resource.actions, resource.actionPermissions, resource.tag, resource.permissions, resource.name, typedInstance.log),
|
|
1284
1272
|
resourceName: resource.name,
|
|
@@ -1293,7 +1281,7 @@ function buildResourcePlugin(resource) {
|
|
|
1293
1281
|
});
|
|
1294
1282
|
}
|
|
1295
1283
|
if (resource.aggregations && Object.keys(resource.aggregations).length > 0) {
|
|
1296
|
-
const [{ createAggregationRouter }, { adapterSupportsAggregate, ArcAggregationConfigError }] = await Promise.all([import("./createAggregationRouter-
|
|
1284
|
+
const [{ createAggregationRouter }, { adapterSupportsAggregate, ArcAggregationConfigError }] = await Promise.all([import("./createAggregationRouter-BiY-lGdY.mjs"), import("./validate-Bk44F2yT.mjs").then((n) => n.r)]);
|
|
1297
1285
|
const repoForAgg = resource.controller?.repository ?? resource.repository;
|
|
1298
1286
|
if (!adapterSupportsAggregate(repoForAgg)) {
|
|
1299
1287
|
const undispatchable = Object.entries(resource.aggregations).filter(([, cfg]) => !cfg.materialized).map(([name]) => name);
|
|
@@ -2169,7 +2157,12 @@ function defineResource(config) {
|
|
|
2169
2157
|
const configWithId = resolveIdField(normalisedConfig, repository);
|
|
2170
2158
|
const resolvedConfig = applyPresetsAndAutoInject(configWithId);
|
|
2171
2159
|
const hasCrudRoutes = computeHasCrudRoutes(resolvedConfig);
|
|
2172
|
-
if (!normalisedConfig.skipValidation)
|
|
2160
|
+
if (!normalisedConfig.skipValidation) {
|
|
2161
|
+
const strict = resolvedConfig.strictPermissions ?? process.env.ARC_STRICT_PERMISSIONS === "true";
|
|
2162
|
+
diagnostics = diagnostics.concat(collectUngatedCrudDiagnostics(resolvedConfig, strict));
|
|
2163
|
+
}
|
|
2164
|
+
const fatal = diagnostics.filter((d) => d.severity === "error");
|
|
2165
|
+
if (fatal.length > 0) throw new Error(fatal.map((d) => d.message).join("\n\n"));
|
|
2173
2166
|
const narrowedConfig = resolvedConfig;
|
|
2174
2167
|
const narrowedAdapter = configWithId.adapter;
|
|
2175
2168
|
const controller = resolveOrAutoCreateController(narrowedConfig, narrowedAdapter, repository, hasCrudRoutes);
|
package/dist/docs/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { p as RegistryEntry } from "../index-
|
|
1
|
+
import { p as RegistryEntry } from "../index-Q5gzEIWY.mjs";
|
|
2
2
|
import { t as ExternalOpenApiPaths } from "../externalPaths-BE6wFpYv.mjs";
|
|
3
3
|
import { FastifyPluginAsync } from "fastify";
|
|
4
4
|
//#region src/docs/openapi/types.d.ts
|
package/dist/docs/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as getUserRoles } from "../userHelpers-Cg_y3fBz.mjs";
|
|
2
|
-
import { n as openApiPlugin, r as openapi_default, t as buildOpenApiSpec } from "../openapi-
|
|
2
|
+
import { n as openApiPlugin, r as openapi_default, t as buildOpenApiSpec } from "../openapi-B8Vkbxbn.mjs";
|
|
3
3
|
import fp from "fastify-plugin";
|
|
4
4
|
//#region src/docs/scalar.ts
|
|
5
5
|
const scalarPlugin = async (fastify, opts = {}) => {
|
|
@@ -2,109 +2,8 @@ import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.mjs";
|
|
|
2
2
|
import { arcLog } from "./logger/index.mjs";
|
|
3
3
|
import { d as createDomainError } from "./errors-DkO8Nk6-.mjs";
|
|
4
4
|
import { n as requestContext } from "./requestContext-MrlJwECf.mjs";
|
|
5
|
+
import { n as createEvent, t as MemoryEventTransport } from "./EventTransport-C6YA8xY9.mjs";
|
|
5
6
|
import fp from "fastify-plugin";
|
|
6
|
-
import { createEvent, matchEventPattern } from "@classytic/primitives/events";
|
|
7
|
-
//#region src/events/EventTransport.ts
|
|
8
|
-
/**
|
|
9
|
-
* Internal arc events module — concrete in-memory transport.
|
|
10
|
-
*
|
|
11
|
-
* **Public type contracts moved out (arc 2.12).** `EventMeta`, `DomainEvent`,
|
|
12
|
-
* `EventHandler`, `EventLogger`, `EventTransport`, `DeadLetteredEvent`,
|
|
13
|
-
* `PublishManyResult`, plus the `createEvent` / `createChildEvent` /
|
|
14
|
-
* `matchEventPattern` helpers, are now owned by `@classytic/primitives/events`.
|
|
15
|
-
* Two reasons:
|
|
16
|
-
*
|
|
17
|
-
* 1. The shapes ARE the cross-package contract. arc, arc-next, mongokit's
|
|
18
|
-
* audit-log plugin, future kits and downstream services all share them.
|
|
19
|
-
* Owning them in `primitives` (pure types, zero runtime, zero deps)
|
|
20
|
-
* eliminates the "manually mirror in two places" problem the previous
|
|
21
|
-
* `primitives/src/events.ts` header explicitly called out.
|
|
22
|
-
* 2. Inverting the dependency direction lets future packages (sqlitekit
|
|
23
|
-
* audit, billing services) consume the contract without depending on
|
|
24
|
-
* arc's HTTP-coupled stack.
|
|
25
|
-
*
|
|
26
|
-
* Hosts MUST import the types from primitives directly:
|
|
27
|
-
*
|
|
28
|
-
* ```typescript
|
|
29
|
-
* import type {
|
|
30
|
-
* EventMeta, DomainEvent, EventHandler, EventTransport,
|
|
31
|
-
* DeadLetteredEvent, PublishManyResult,
|
|
32
|
-
* } from '@classytic/primitives/events';
|
|
33
|
-
* import { createEvent, createChildEvent } from '@classytic/primitives/events';
|
|
34
|
-
* ```
|
|
35
|
-
*
|
|
36
|
-
* arc's `events/index.ts` barrel does NOT re-export these — by design, so
|
|
37
|
-
* that consumer code is forced into the canonical import path and the org's
|
|
38
|
-
* "no re-exports" rule holds at every public surface.
|
|
39
|
-
*
|
|
40
|
-
* What stays here:
|
|
41
|
-
* - `MemoryEventTransport` — the in-memory `EventTransport` implementation
|
|
42
|
-
* used as arc's default transport. Its handler-set state is process-local;
|
|
43
|
-
* wrong layer for primitives.
|
|
44
|
-
* - `MemoryEventTransportOptions` — its options shape.
|
|
45
|
-
*
|
|
46
|
-
* Inside arc, files that previously imported types from `./EventTransport.js`
|
|
47
|
-
* keep working: this file re-exports them from primitives for arc's own
|
|
48
|
-
* call sites. That re-export is an internal refactor convenience — the
|
|
49
|
-
* public `events/index.ts` barrel stays clean.
|
|
50
|
-
*/
|
|
51
|
-
/**
|
|
52
|
-
* In-memory event transport (default).
|
|
53
|
-
*
|
|
54
|
-
* Events are delivered synchronously within the process. Not suitable for
|
|
55
|
-
* multi-instance deployments — pair with `RedisEventTransport` /
|
|
56
|
-
* `RedisStreamTransport` (subpath imports) for those.
|
|
57
|
-
*/
|
|
58
|
-
var MemoryEventTransport = class {
|
|
59
|
-
name = "memory";
|
|
60
|
-
handlers = /* @__PURE__ */ new Map();
|
|
61
|
-
logger;
|
|
62
|
-
constructor(options) {
|
|
63
|
-
this.logger = options?.logger ?? console;
|
|
64
|
-
}
|
|
65
|
-
async publish(event) {
|
|
66
|
-
const allHandlers = /* @__PURE__ */ new Set();
|
|
67
|
-
for (const [pattern, handlers] of this.handlers) if (matchEventPattern(pattern, event.type)) for (const h of handlers) allHandlers.add(h);
|
|
68
|
-
for (const handler of allHandlers) try {
|
|
69
|
-
await handler(event);
|
|
70
|
-
} catch (err) {
|
|
71
|
-
this.logger.error(`[EventTransport] Handler error for ${event.type}:`, err);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Reference `publishMany` implementation — delegates to `publish()` in order.
|
|
76
|
-
*
|
|
77
|
-
* Production transports (Kafka, Redis pipeline, SQS batch) should override
|
|
78
|
-
* this with a single batched network call. Memory transport has nothing to
|
|
79
|
-
* batch, so we just loop — the loop still returns a proper result map so
|
|
80
|
-
* `EventOutbox.relay` can exercise the batched code path in tests.
|
|
81
|
-
*/
|
|
82
|
-
async publishMany(events) {
|
|
83
|
-
const results = /* @__PURE__ */ new Map();
|
|
84
|
-
for (const event of events) try {
|
|
85
|
-
await this.publish(event);
|
|
86
|
-
results.set(event.meta.id, null);
|
|
87
|
-
} catch (err) {
|
|
88
|
-
results.set(event.meta.id, err instanceof Error ? err : new Error(String(err)));
|
|
89
|
-
}
|
|
90
|
-
return results;
|
|
91
|
-
}
|
|
92
|
-
async subscribe(pattern, handler) {
|
|
93
|
-
if (!this.handlers.has(pattern)) this.handlers.set(pattern, /* @__PURE__ */ new Set());
|
|
94
|
-
this.handlers.get(pattern)?.add(handler);
|
|
95
|
-
return () => {
|
|
96
|
-
const set = this.handlers.get(pattern);
|
|
97
|
-
if (set) {
|
|
98
|
-
set.delete(handler);
|
|
99
|
-
if (set.size === 0) this.handlers.delete(pattern);
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
async close() {
|
|
104
|
-
this.handlers.clear();
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
//#endregion
|
|
108
7
|
//#region src/events/retry.ts
|
|
109
8
|
/**
|
|
110
9
|
* Wrap an event handler with retry logic and dead letter support.
|
|
@@ -338,4 +237,4 @@ var eventPlugin_default = fp(eventPlugin, {
|
|
|
338
237
|
fastify: "5.x"
|
|
339
238
|
});
|
|
340
239
|
//#endregion
|
|
341
|
-
export {
|
|
240
|
+
export { withRetry as i, eventPlugin_exports as n, createDeadLetterPublisher as r, eventPlugin as t };
|