@classytic/arc 2.37.1 → 2.40.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-Chkf0Aiw.mjs → BaseController-BqJtbiUA.mjs} +107 -23
- package/dist/{EventTransport-BEVP50ka.d.mts → EventTransport-BPOQsEer.d.mts} +45 -0
- package/dist/{EventTransport-CFdtK25P.mjs → EventTransport-BUkTwY_x.mjs} +51 -8
- package/dist/{HookSystem-Csy31WS-.mjs → HookSystem-96nzZLmk.mjs} +2 -2
- package/dist/{ResourceRegistry-OQA13slI.mjs → ResourceRegistry-B9WnuG2Q.mjs} +2 -2
- package/dist/{actionPermissions-DGGqqSIV.mjs → actionPermissions-4OGbe3Hf.mjs} +6 -6
- package/dist/audit/index.d.mts +1 -1
- package/dist/audit/index.mjs +2 -2
- package/dist/auth/audit.mjs +1 -1
- package/dist/auth/index.d.mts +1 -1
- package/dist/auth/index.mjs +6 -6
- package/dist/auth/redis-session.mjs +1 -1
- package/dist/{authorizationDecision-BzZi2bsf.mjs → authorizationDecision-D_LFvMlm.mjs} +2 -2
- package/dist/{buildHandler-CIz0NsGS.mjs → buildHandler-BG_CHXqQ.mjs} +4 -4
- package/dist/cache/index.mjs +4 -4
- package/dist/{caching-DldVgnC9.mjs → caching-Bqcn3Brl.mjs} +2 -2
- package/dist/cleanup/index.d.mts +2 -2
- package/dist/cleanup/index.mjs +21 -5
- package/dist/cli/commands/describe.d.mts +1 -1
- package/dist/cli/commands/describe.mjs +3 -3
- package/dist/cli/commands/docs.mjs +3 -3
- package/dist/cli/commands/doctor.mjs +1 -1
- package/dist/cli/commands/generate.mjs +2 -2
- package/dist/cli/commands/init.mjs +2 -2
- package/dist/cli/commands/introspect.mjs +2 -2
- package/dist/cli/index.mjs +3 -3
- package/dist/{constants-DDKf25s4.mjs → constants-BQ2FbhPB.mjs} +1 -1
- package/dist/context/index.d.mts +34 -6
- package/dist/context/index.mjs +12 -19
- package/dist/core/index.d.mts +2 -2
- package/dist/core/index.mjs +7 -7
- package/dist/{core-uHQonaHf.mjs → core-CsZR037F.mjs} +3 -3
- package/dist/{createActionRouter-C22Xn11N.mjs → createActionRouter-BR93gCKg.mjs} +7 -7
- package/dist/{createAggregationRouter-DgyksLHH.mjs → createAggregationRouter-CF40Aw95.mjs} +7 -7
- package/dist/createMcpServer-BVTs2S5G.d.mts +48 -0
- package/dist/{defineAggregation-B1m-45Fe.mjs → defineAggregation-BDA2Tw7v.mjs} +1 -1
- package/dist/{defineResource-DS3Uj2-8.mjs → defineResource-DaIySrQr.mjs} +20 -22
- package/dist/discovery/index.mjs +1 -1
- package/dist/docs/index.d.mts +1 -1
- package/dist/docs/index.mjs +3 -3
- package/dist/{elevation-9X0lGzTQ.mjs → elevation-CZy6n50b.mjs} +4 -4
- package/dist/encryption/index.mjs +3 -3
- package/dist/{errorHandler-DI5AN2b5.d.mts → errorHandler--4rSMMvq.d.mts} +7 -1
- package/dist/{errorHandler-BmEGKyO9.mjs → errorHandler-By9keRvX.mjs} +3 -3
- package/dist/{errors-CbxCF9M0.mjs → errors-BHD3L8of.mjs} +1 -1
- package/dist/{eventPlugin-B1ahehZH.mjs → eventPlugin-DB26V7uX.mjs} +6 -6
- package/dist/{eventPlugin-B47sfCJ8.d.mts → eventPlugin-DfHaKEWQ.d.mts} +10 -1
- package/dist/events/index.d.mts +4 -4
- package/dist/events/index.mjs +5 -5
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis-stream-entry.mjs +21 -20
- package/dist/events/transports/redis.d.mts +1 -1
- package/dist/events/transports/redis.mjs +11 -8
- package/dist/factory/index.d.mts +4 -4
- package/dist/factory/index.mjs +5 -5
- package/dist/{fastify-augmentation-CRsNNhuo.d.mts → fastify-augmentation-HncZMmze.d.mts} +3 -3
- package/dist/{fields-f_MdWDl_.mjs → fields-fA-Dkou5.mjs} +37 -2
- package/dist/{generate-DxWn-XnM.mjs → generate-BSSdtiOy.mjs} +4 -3
- package/dist/{headers-DivLPMHe.mjs → headers-BFEEshDS.mjs} +2 -2
- package/dist/{health-W_BjgWf0.mjs → health-BlGHjkqZ.mjs} +1 -1
- package/dist/hooks/index.d.mts +1 -1
- package/dist/hooks/index.mjs +2 -2
- package/dist/idempotency/index.mjs +4 -4
- package/dist/idempotency/redis.mjs +1 -1
- package/dist/{index-BqRfP1kT.d.mts → index-D3sIPcD4.d.mts} +47 -11
- package/dist/{index-DCxxRwLC.d.mts → index-DbMglURO.d.mts} +2 -2
- package/dist/{index-CEmPspAB.d.mts → index-SCsOJxWB.d.mts} +2 -2
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +11 -11
- package/dist/{init-BJ6fdYnp.mjs → init-pl88PHzb.mjs} +9 -9
- package/dist/integrations/event-gateway.d.mts +1 -1
- package/dist/integrations/event-gateway.mjs +2 -2
- package/dist/integrations/index.d.mts +1 -1
- package/dist/integrations/index.mjs +1 -1
- package/dist/integrations/jobs/index.mjs +2 -2
- package/dist/integrations/mcp/index.d.mts +3 -46
- package/dist/integrations/mcp/index.mjs +2 -2
- package/dist/integrations/mcp/testing.d.mts +22 -2
- package/dist/integrations/mcp/testing.mjs +55 -33
- package/dist/integrations/streamline.mjs +3 -3
- package/dist/integrations/webhooks.d.mts +2 -2
- package/dist/integrations/webhooks.mjs +3 -3
- package/dist/integrations/websocket-pushref-redis.mjs +1 -1
- package/dist/integrations/websocket-redis.mjs +1 -1
- package/dist/integrations/websocket.mjs +13 -6
- package/dist/{interface-DeLndJ8G.mjs → interface-DjtFnZxH.mjs} +1 -1
- package/dist/{jsonBody-kApktjTc.mjs → jsonBody-Dx6jH_Nb.mjs} +2 -2
- package/dist/{keys-B1MgfDWi.mjs → keys-Ds3ekBiu.mjs} +1 -1
- package/dist/{loadResources-ma-Aaxp1.mjs → loadResources-E5UFlRrT.mjs} +2 -2
- package/dist/{loadResourcesFromEntry-xszlyXTs.mjs → loadResourcesFromEntry-C2jrJbWG.mjs} +2 -2
- package/dist/logger/index.mjs +1 -1
- package/dist/{mcpPlugin-97HuFA46.mjs → mcpPlugin-D-3OLxNz.mjs} +75 -31
- package/dist/{memory-DvASzOn3.mjs → memory-CNvjxzB2.mjs} +2 -2
- package/dist/{metrics-Dx-nkDE5.mjs → metrics-P37sNV5H.mjs} +2 -2
- package/dist/middleware/index.d.mts +1 -1
- package/dist/middleware/index.mjs +3 -3
- package/dist/migrations/index.mjs +2 -2
- package/dist/{module-CNKk_twm.mjs → module-CNcwCKUJ.mjs} +1 -1
- package/dist/{multipartBody-TDaYOHGZ.mjs → multipartBody-Bl_gU3Wg.mjs} +1 -1
- package/dist/{openapi-473gZ-8x.mjs → openapi-BYrL8zvY.mjs} +6 -6
- package/dist/outbox-admin/index.d.mts +1 -1
- package/dist/outbox-admin/index.mjs +4 -4
- package/dist/{outbox-module-DOAmyXOb.mjs → outbox-module-6DMC_WNu.mjs} +40 -21
- package/dist/{outbox-module-BbdaMyqy.d.mts → outbox-module-CzsKRBvO.d.mts} +11 -2
- package/dist/permissions/index.mjs +5 -5
- package/dist/{permissions-DnAc6zoZ.mjs → permissions-C0GpDsB_.mjs} +6 -6
- package/dist/{pipe-BoV-z4db.mjs → pipe-4_XamfxI.mjs} +2 -2
- package/dist/pipeline/index.d.mts +1 -1
- package/dist/pipeline/index.mjs +2 -2
- package/dist/plugins/index.d.mts +5 -5
- package/dist/plugins/index.mjs +17 -16
- package/dist/plugins/response-cache.mjs +2 -2
- package/dist/plugins/tracing-entry.mjs +2 -2
- package/dist/{pluralize-BiU5ocWw.mjs → pluralize-BaQ62hOW.mjs} +1 -1
- package/dist/{preloadResources-DJ7Lli0a.mjs → preloadResources-BAx5s9EF.mjs} +70 -21
- package/dist/{preloadResources-DHkyk3QN.d.mts → preloadResources-DVgPCNcD.d.mts} +7 -7
- package/dist/presets/filesUpload.d.mts +1 -1
- package/dist/presets/filesUpload.mjs +5 -5
- 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 +3 -3
- package/dist/presets/search.d.mts +1 -1
- package/dist/presets/search.mjs +2 -2
- package/dist/{presets-BMxH-Bb7.mjs → presets-CAaqVVcW.mjs} +4 -4
- package/dist/{projection-CRCM5S9T.mjs → projection-qbCOEvsh.mjs} +2 -2
- package/dist/{queryCachePlugin-Cl3zLG7g.mjs → queryCachePlugin-2Pp9w-8D.mjs} +5 -5
- package/dist/rateLimitKey-umrS6-vu.mjs +41 -0
- package/dist/{realtime-BWuHi-UI.mjs → realtime-zzoNLDtj.mjs} +9 -9
- package/dist/{redis-stream-mwLWlfHG.d.mts → redis-stream-DSsPyYzd.d.mts} +7 -2
- package/dist/{registerRoute-mvm6zY2H.mjs → registerRoute-_6zHiz0x.mjs} +10 -6
- package/dist/registry/index.d.mts +2 -2
- package/dist/registry/index.mjs +3 -3
- package/dist/{registry-3maEt__c.mjs → registry-CEpoRpLP.mjs} +2 -2
- package/dist/{renewingLease-C1-GAUpr.mjs → renewingLease-B5Grm0pI.mjs} +1 -1
- package/dist/{replyHelpers-DVcUoled.mjs → replyHelpers-9h-a592u.mjs} +2 -2
- package/dist/{requestContext-KzIdSmN2.mjs → requestContext-D4PuGhEw.mjs} +1 -1
- package/dist/{rolldown-runtime-NVzJrC-o.mjs → rolldown-runtime-DzE6ikSH.mjs} +1 -1
- package/dist/{runtimeCapabilities-OrGatf7r.mjs → runtimeCapabilities-Bo7rSKjm.mjs} +1 -1
- package/dist/{schedules-DeRI03eo.mjs → schedules-Dm21pqHU.mjs} +8 -4
- package/dist/{schemaConverter-cXTayNOW.mjs → schemaConverter-DENbixyA.mjs} +1 -1
- package/dist/{schemaIR-Cc9ZPVs2.mjs → schemaIR-C2qUNzC6.mjs} +2 -2
- package/dist/schemas/index.mjs +1 -1
- package/dist/scim/index.mjs +2 -2
- package/dist/scope/index.mjs +5 -5
- package/dist/{scope-C2r7_WGs.mjs → scope-CdYxQVxt.mjs} +4 -4
- package/dist/{simpleEqualityMatcher-Cr1F8jKZ.mjs → simpleEqualityMatcher-Cldubvul.mjs} +1 -1
- package/dist/{sse-BmZCVRGH.mjs → sse-DbyXoQun.mjs} +5 -5
- package/dist/{sseStream-nNPqvOeK.mjs → sseStream-BfZtL5-m.mjs} +2 -2
- package/dist/{store-helpers-C1r3-6M0.mjs → store-helpers-BfyOd5i6.mjs} +1 -1
- package/dist/{streaming-BxZDlH01.mjs → streaming-CFwCzEvU.mjs} +1 -1
- package/dist/{subscribe-helpers-Dca7Fcz2.mjs → subscribe-helpers-KgVEcn8L.mjs} +2 -2
- package/dist/sync/changelog.mjs +1 -1
- package/dist/testing/cleanupStoreContract.mjs +1 -1
- package/dist/testing/index.d.mts +4 -4
- package/dist/testing/index.mjs +10 -10
- package/dist/testing/outboxStoreContract.mjs +14 -3
- package/dist/testing/storageContract.mjs +1 -1
- package/dist/{transactionContext-6F7Gkbxg.mjs → transactionContext-46KyUADP.mjs} +1 -1
- package/dist/{typeGuards-BrXgbFi-.mjs → typeGuards-t_CVgRXN.mjs} +1 -1
- package/dist/types/index.d.mts +1 -1
- package/dist/types/index.mjs +1 -1
- package/dist/types/storage.mjs +1 -1
- package/dist/{types-rzNprqbE.d.mts → types-9rvxn5Ym.d.mts} +46 -1
- package/dist/{types-BMa2EPtv.d.mts → types-BVlowlm7.d.mts} +2 -2
- package/dist/{types-khJmBErP.mjs → types-CNQyOrLk.mjs} +4 -4
- package/dist/usage/index.mjs +0 -0
- package/dist/{userHelpers-Bi97zMEl.mjs → userHelpers-DLueLQdQ.mjs} +1 -1
- package/dist/utils/index.d.mts +4 -4
- package/dist/utils/index.mjs +11 -11
- package/dist/{utils-WlLDIKuw.mjs → utils-CUFBrhq-.mjs} +14 -6
- package/dist/{validate-pMke_boy.mjs → validate-DV3hRbsz.mjs} +2 -2
- package/dist/{versioning-CFK3c04-.mjs → versioning-BXwmj5SD.mjs} +3 -3
- package/dist/{versioning-DEs-_hFi.d.mts → versioning-P3V6ATyC.d.mts} +1 -1
- package/dist/workScope-CoGpuzDX.mjs +42 -0
- package/package.json +48 -39
- package/skills/arc/references/mcp.md +20 -0
- package/skills/arc/references/testing.md +0 -12
- package/skills/arc-code-review/references/anti-patterns.md +1 -1
- package/skills/arc-code-review/references/migration-recipes.md +0 -60
- package/skills/arc-code-review/references/mongokit-migration.md +0 -27
- package/skills/arc-module-publishing/references/package-manifest.md +3 -1
- package/dist/rateLimitKey-D4_rjP1K.mjs +0 -15
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { h as SYSTEM_FIELDS, o as DEFAULT_TENANT_FIELD } from "./constants-
|
|
1
|
+
/*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
|
|
2
|
+
import { h as SYSTEM_FIELDS, o as DEFAULT_TENANT_FIELD } from "./constants-BQ2FbhPB.mjs";
|
|
3
3
|
import { arcLog } from "./logger/index.mjs";
|
|
4
|
-
import { a as conjoinPolicyFilters } from "./authorizationDecision-
|
|
5
|
-
import { d as createDomainError, f as createError, i as NotFoundError, p as isArcError, r as ForbiddenError } from "./errors-
|
|
6
|
-
import { n as getUserRoles, t as getUserId } from "./userHelpers-
|
|
7
|
-
import { b as isElevated, c as getOrgId, n as PUBLIC_SCOPE, x as isMember } from "./types-
|
|
8
|
-
import { t as simpleEqualityMatcher } from "./simpleEqualityMatcher-
|
|
9
|
-
import { t as buildQueryKey } from "./keys-
|
|
10
|
-
import { t as transactionContext } from "./transactionContext-
|
|
11
|
-
import { A as scheduleBackground, E as ArcQueryParser } from "./utils-
|
|
12
|
-
import {
|
|
4
|
+
import { a as conjoinPolicyFilters } from "./authorizationDecision-D_LFvMlm.mjs";
|
|
5
|
+
import { d as createDomainError, f as createError, i as NotFoundError, p as isArcError, r as ForbiddenError, u as ValidationError } from "./errors-BHD3L8of.mjs";
|
|
6
|
+
import { n as getUserRoles, t as getUserId } from "./userHelpers-DLueLQdQ.mjs";
|
|
7
|
+
import { b as isElevated, c as getOrgId, n as PUBLIC_SCOPE, x as isMember } from "./types-CNQyOrLk.mjs";
|
|
8
|
+
import { t as simpleEqualityMatcher } from "./simpleEqualityMatcher-Cldubvul.mjs";
|
|
9
|
+
import { t as buildQueryKey } from "./keys-Ds3ekBiu.mjs";
|
|
10
|
+
import { t as transactionContext } from "./transactionContext-46KyUADP.mjs";
|
|
11
|
+
import { A as scheduleBackground, E as ArcQueryParser } from "./utils-CUFBrhq-.mjs";
|
|
12
|
+
import { a as resolveEffectiveRoles, n as applyFieldWritePermissions } from "./fields-fA-Dkou5.mjs";
|
|
13
13
|
import { policyRecordToFilter } from "@classytic/repo-core/filter";
|
|
14
14
|
import { retryingTransaction } from "@classytic/repo-core/repository";
|
|
15
15
|
import { isProductionEnv } from "@classytic/primitives/environment";
|
|
@@ -650,7 +650,7 @@ async function executeAfterHook(ctx, op, data, meta) {
|
|
|
650
650
|
* Every mixin used to spell out its own narrowing cast inline:
|
|
651
651
|
*
|
|
652
652
|
* ```ts
|
|
653
|
-
* const repo = this.repository as
|
|
653
|
+
* const repo = this.repository as {
|
|
654
654
|
* getTree?: (options?: unknown) => Promise<AnyRecord[]>;
|
|
655
655
|
* };
|
|
656
656
|
* ```
|
|
@@ -717,7 +717,7 @@ async function runDistinctVerb(repository, field, resolveScope) {
|
|
|
717
717
|
const repo = withRepoFeatures(repository);
|
|
718
718
|
if (typeof repo.distinct !== "function") throw createError(501, "_distinct is not supported: the resource's storage adapter does not implement repo.distinct()");
|
|
719
719
|
const { filter, options } = resolveScope();
|
|
720
|
-
return await repo.distinct(field, filter, options);
|
|
720
|
+
return { values: await repo.distinct(field, filter, options) };
|
|
721
721
|
}
|
|
722
722
|
/**
|
|
723
723
|
* `?_exists=true` → `repo.exists(filter)`. Returns the RAW repo result —
|
|
@@ -789,6 +789,27 @@ function noteDeniedJoins(kind) {
|
|
|
789
789
|
notedDeniedJoins = true;
|
|
790
790
|
log.warn(`client requested ${kind} but no allowlist is configured — DENIED (2.24 default flip; it was allow-all). Set schemaOptions.query.allowedPopulate / allowedLookups to enable client-driven joins. (dev-only note, shown once)`);
|
|
791
791
|
}
|
|
792
|
+
/**
|
|
793
|
+
* A `$lookup` reaches ANOTHER collection, and the tenant filter arc conjoins applies to the
|
|
794
|
+
* BASE one only. The joined side carries whatever predicate the lookup itself names and
|
|
795
|
+
* nothing more — no tenant scope, no soft-delete filter — so a resource that opens
|
|
796
|
+
* `allowedLookups` can return rows from a collection the caller could not query directly.
|
|
797
|
+
*
|
|
798
|
+
* Unreachable by default (2.24 denies `lookup=` with no allowlist) and no resource in this
|
|
799
|
+
* fleet configures one, so this is a WARNING at the moment a deployment first opts in
|
|
800
|
+
* rather than machinery for a door nobody has opened. Warned once per collection set: the
|
|
801
|
+
* decision is made when the allowlist is written, not per request.
|
|
802
|
+
*
|
|
803
|
+
* Scope the join with the lookup's own `where`, which mongokit compiles into a `$match`
|
|
804
|
+
* inside the lookup pipeline.
|
|
805
|
+
*/
|
|
806
|
+
const notedUnscopedJoins = /* @__PURE__ */ new Set();
|
|
807
|
+
function noteUnscopedJoin(lookups) {
|
|
808
|
+
const key = lookups.map((l) => l.from).filter((f) => typeof f === "string").sort().join(",");
|
|
809
|
+
if (key.length === 0 || notedUnscopedJoins.has(key)) return;
|
|
810
|
+
notedUnscopedJoins.add(key);
|
|
811
|
+
log.warn(`client-driven $lookup on [${key}] — the JOINED side carries no tenant or soft-delete filter (arc scopes the base collection only). Narrow each lookup with its own \`where\`, or the join can surface rows the caller cannot query directly. (shown once)`);
|
|
812
|
+
}
|
|
792
813
|
var QueryResolver = class {
|
|
793
814
|
queryParser;
|
|
794
815
|
maxLimit;
|
|
@@ -912,6 +933,12 @@ var QueryResolver = class {
|
|
|
912
933
|
query = rest;
|
|
913
934
|
}
|
|
914
935
|
const parsed = this.queryParser.parse(query);
|
|
936
|
+
/**
|
|
937
|
+
* Client-supplied keys only, and BEFORE the policy conjunction below: trusted policy
|
|
938
|
+
* legitimately filters on hidden fields (`requireOwnership('userId')` emits exactly that),
|
|
939
|
+
* so checking the conjoined result would reject the framework's own restrictions.
|
|
940
|
+
*/
|
|
941
|
+
this.assertNoBlockedReadKeys(parsed.filters, parsed.sort);
|
|
915
942
|
const arcContext = meta ?? req.metadata;
|
|
916
943
|
const limit = Math.min(Math.max(1, parsed.limit || this.defaultLimit), this.maxLimit);
|
|
917
944
|
const page = parsed.after ? void 0 : parsed.page ? Math.max(1, parsed.page) : 1;
|
|
@@ -950,20 +977,14 @@ var QueryResolver = class {
|
|
|
950
977
|
if (!select) return exclusion();
|
|
951
978
|
if (typeof select === "object" && !Array.isArray(select)) {
|
|
952
979
|
const sanitized = {};
|
|
953
|
-
for (const [field, val] of Object.entries(select)) if (!
|
|
980
|
+
for (const [field, val] of Object.entries(select)) if (!this.isBlockedProjection(field, blockedFields)) sanitized[field] = val;
|
|
954
981
|
return Object.keys(sanitized).length > 0 ? sanitized : exclusion();
|
|
955
982
|
}
|
|
956
983
|
if (Array.isArray(select)) {
|
|
957
|
-
const sanitized = select.filter((f) =>
|
|
958
|
-
const fieldName = f.replace(/^-/, "");
|
|
959
|
-
return !blockedFields.includes(fieldName);
|
|
960
|
-
});
|
|
984
|
+
const sanitized = select.filter((f) => !this.isBlockedProjection(f, blockedFields));
|
|
961
985
|
return sanitized.length > 0 ? sanitized : exclusion();
|
|
962
986
|
}
|
|
963
|
-
const sanitized = select.split(/[\s,]+/).filter(Boolean).filter((f) =>
|
|
964
|
-
const fieldName = f.replace(/^-/, "");
|
|
965
|
-
return !blockedFields.includes(fieldName);
|
|
966
|
-
});
|
|
987
|
+
const sanitized = select.split(/[\s,]+/).filter(Boolean).filter((f) => !this.isBlockedProjection(f, blockedFields));
|
|
967
988
|
return sanitized.length > 0 ? sanitized.join(" ") : exclusion();
|
|
968
989
|
}
|
|
969
990
|
/** Sanitize populate fields */
|
|
@@ -1011,6 +1032,7 @@ var QueryResolver = class {
|
|
|
1011
1032
|
if (!allowedLookups.includes(lookup.from)) return false;
|
|
1012
1033
|
return true;
|
|
1013
1034
|
});
|
|
1035
|
+
if (sanitized.length > 0) noteUnscopedJoin(sanitized);
|
|
1014
1036
|
return sanitized.length > 0 ? sanitized : void 0;
|
|
1015
1037
|
}
|
|
1016
1038
|
/**
|
|
@@ -1023,6 +1045,68 @@ var QueryResolver = class {
|
|
|
1023
1045
|
const blocked = collectReadBlockedFields(schemaOptions);
|
|
1024
1046
|
return blocked ? Array.from(blocked) : [];
|
|
1025
1047
|
}
|
|
1048
|
+
/**
|
|
1049
|
+
* Is this projection path blocked — by its own name, or by a hidden ANCESTOR?
|
|
1050
|
+
*
|
|
1051
|
+
* `hidden: { secret: true }` hides the object, and an exact-name match left its children
|
|
1052
|
+
* reachable: `?select=secret.value` projected the very field the rule exists to withhold.
|
|
1053
|
+
* A rule on a parent covers everything under it, which is what "hidden" already means to
|
|
1054
|
+
* whoever wrote it.
|
|
1055
|
+
*/
|
|
1056
|
+
isBlockedProjection(path, blockedFields) {
|
|
1057
|
+
const field = path.replace(/^-/, "");
|
|
1058
|
+
return blockedFields.some((blocked) => field === blocked || field.startsWith(`${blocked}.`));
|
|
1059
|
+
}
|
|
1060
|
+
/**
|
|
1061
|
+
* Refuse a read that FILTERS or SORTS on a `hidden` field.
|
|
1062
|
+
*
|
|
1063
|
+
* `hidden` was enforced on the surfaces that RETURN a value — the response, `select=`,
|
|
1064
|
+
* `_distinct`, aggregations — but a filter key never returns the field, it INTERROGATES it:
|
|
1065
|
+
* `?passwordHash[like]=^ab` narrows the result set, so the row count answers a question about
|
|
1066
|
+
* a value the caller may not read. A resource with no `allowedFilterFields` was a blind
|
|
1067
|
+
* existence oracle over every hidden field it declared.
|
|
1068
|
+
*
|
|
1069
|
+
* Rejected rather than dropped, unlike `select`. Dropping a projection narrows what comes
|
|
1070
|
+
* back; dropping a filter WIDENS the rows, which is the silent-permissive shape this
|
|
1071
|
+
* framework fails loudly on everywhere else.
|
|
1072
|
+
*
|
|
1073
|
+
* Compound keys (`$or`, `$and`) are walked, because the offending key can be nested inside
|
|
1074
|
+
* one. A dotted path is blocked by its own name or by a hidden ancestor, so a rule on
|
|
1075
|
+
* `secret` also covers `secret.value`.
|
|
1076
|
+
*/
|
|
1077
|
+
assertNoBlockedReadKeys(filters, sort) {
|
|
1078
|
+
const blocked = collectReadBlockedFields(this.schemaOptions);
|
|
1079
|
+
if (!blocked) return;
|
|
1080
|
+
const offenders = /* @__PURE__ */ new Set();
|
|
1081
|
+
const isBlocked = (key) => {
|
|
1082
|
+
if (blocked.has(key)) return true;
|
|
1083
|
+
const dot = key.indexOf(".");
|
|
1084
|
+
return dot > 0 && blocked.has(key.slice(0, dot));
|
|
1085
|
+
};
|
|
1086
|
+
const walk = (node, depth) => {
|
|
1087
|
+
if (depth > 8 || !node || typeof node !== "object") return;
|
|
1088
|
+
if (Array.isArray(node)) {
|
|
1089
|
+
for (const item of node) walk(item, depth + 1);
|
|
1090
|
+
return;
|
|
1091
|
+
}
|
|
1092
|
+
for (const [key, value] of Object.entries(node)) {
|
|
1093
|
+
if (key.startsWith("$")) {
|
|
1094
|
+
walk(value, depth + 1);
|
|
1095
|
+
continue;
|
|
1096
|
+
}
|
|
1097
|
+
if (isBlocked(key)) offenders.add(key);
|
|
1098
|
+
}
|
|
1099
|
+
};
|
|
1100
|
+
walk(filters, 0);
|
|
1101
|
+
const sortKeys = typeof sort === "string" ? sort.split(",").map((s) => s.trim().replace(/^-/, "")).filter(Boolean) : Object.keys(sort ?? {});
|
|
1102
|
+
for (const key of sortKeys) if (isBlocked(key)) offenders.add(key);
|
|
1103
|
+
if (offenders.size === 0) return;
|
|
1104
|
+
const fields = [...offenders];
|
|
1105
|
+
throw new ValidationError(`Cannot filter or sort on hidden field(s): ${fields.join(", ")}`, fields.map((field) => ({
|
|
1106
|
+
field,
|
|
1107
|
+
message: "Field is not readable"
|
|
1108
|
+
})));
|
|
1109
|
+
}
|
|
1026
1110
|
};
|
|
1027
1111
|
//#endregion
|
|
1028
1112
|
//#region src/core/BaseCrudController.ts
|
|
@@ -1550,7 +1634,7 @@ var BaseCrudController = class {
|
|
|
1550
1634
|
}
|
|
1551
1635
|
async list(req) {
|
|
1552
1636
|
const dispatch = this.dispatchResourceVerb(req);
|
|
1553
|
-
if (dispatch) return dispatch;
|
|
1637
|
+
if (dispatch !== null) return dispatch;
|
|
1554
1638
|
const options = this.queryResolver.resolve(req, this.meta(req));
|
|
1555
1639
|
const cached = await this.withListCache(req, options);
|
|
1556
1640
|
if (cached) return cached;
|
|
@@ -19,6 +19,41 @@ interface MemoryEventTransportOptions {
|
|
|
19
19
|
* handlers must be idempotent. Every handler runs before the rejection.
|
|
20
20
|
*/
|
|
21
21
|
onHandlerError?: "log" | "throw";
|
|
22
|
+
/**
|
|
23
|
+
* Whether independent subscribers run one at a time or together.
|
|
24
|
+
*
|
|
25
|
+
* - `'sequential'` (default) — handler N+1 starts after handler N settles.
|
|
26
|
+
* - `'parallel'` — all matching handlers start together; `publish()` resolves
|
|
27
|
+
* when the last settles.
|
|
28
|
+
*
|
|
29
|
+
* Same delivery and the same failure semantics either way: every handler
|
|
30
|
+
* still receives the event, every failure is still collected, and `'throw'`
|
|
31
|
+
* still rejects with one `AggregateError` after all of them have run.
|
|
32
|
+
*
|
|
33
|
+
* **Opting in requires an AUDIT, not an assumption.** Every other transport
|
|
34
|
+
* in this package runs matching handlers sequentially in registration order
|
|
35
|
+
* (`redis-stream.ts` states it outright; `redis.ts` implements it), so an app
|
|
36
|
+
* relying on that order is relying on documented behaviour — switching this
|
|
37
|
+
* on is what breaks it, and swapping to a broker would not have surfaced it.
|
|
38
|
+
* Confirm no subscriber reads another subscriber's write before enabling.
|
|
39
|
+
*
|
|
40
|
+
* Measured on one order placement: 6 subscribers, each spending most of its
|
|
41
|
+
* time on its own round trips, cost 2.8s sequentially — the length of the
|
|
42
|
+
* QUEUE, not of the work.
|
|
43
|
+
*/
|
|
44
|
+
handlerDispatch?: "sequential" | "parallel";
|
|
45
|
+
/**
|
|
46
|
+
* Cap on handlers running at once under `'parallel'`. Default: unlimited.
|
|
47
|
+
*
|
|
48
|
+
* Sequential dispatch was an accidental per-publish rate limiter on whatever
|
|
49
|
+
* pool the handlers share; removing it converts a latency problem into a
|
|
50
|
+
* saturation one when several publishes overlap. `RedisStreamTransport`
|
|
51
|
+
* exposes `processingConcurrency` for the same reason — this is its peer, so
|
|
52
|
+
* an operator has a dial rather than only "queued" or "all at once".
|
|
53
|
+
*
|
|
54
|
+
* Ignored under `'sequential'`, which is already a concurrency of 1.
|
|
55
|
+
*/
|
|
56
|
+
handlerConcurrency?: number;
|
|
22
57
|
}
|
|
23
58
|
/**
|
|
24
59
|
* In-memory event transport (default).
|
|
@@ -32,8 +67,18 @@ declare class MemoryEventTransport implements EventTransport {
|
|
|
32
67
|
private handlers;
|
|
33
68
|
private logger;
|
|
34
69
|
private onHandlerError;
|
|
70
|
+
private handlerDispatch;
|
|
71
|
+
private handlerConcurrency;
|
|
35
72
|
constructor(options?: MemoryEventTransportOptions);
|
|
73
|
+
/**
|
|
74
|
+
* One work scope per publish, around the WHOLE handler set — so every
|
|
75
|
+
* handler of this event, parallel or not, shares one `requestScopedCache()`
|
|
76
|
+
* and one correlation id. Inherits an active request scope (a live
|
|
77
|
+
* in-request dispatch keeps the request's reads); a relay- or job-driven
|
|
78
|
+
* publish gets its own.
|
|
79
|
+
*/
|
|
36
80
|
publish(event: DomainEvent): Promise<void>;
|
|
81
|
+
private dispatch;
|
|
37
82
|
/**
|
|
38
83
|
* Reference `publishMany` implementation — delegates to `publish()` in order.
|
|
39
84
|
*
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
1
|
+
/*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
|
|
2
|
+
import { r as workSeedFromEvent, t as runWorkScope } from "./workScope-CoGpuzDX.mjs";
|
|
2
3
|
import { createEvent, matchEventPattern } from "@classytic/primitives/events";
|
|
3
4
|
//#region src/events/EventTransport.ts
|
|
4
5
|
/**
|
|
@@ -79,20 +80,62 @@ var MemoryEventTransport = class {
|
|
|
79
80
|
handlers = /* @__PURE__ */ new Map();
|
|
80
81
|
logger;
|
|
81
82
|
onHandlerError;
|
|
83
|
+
handlerDispatch;
|
|
84
|
+
handlerConcurrency;
|
|
82
85
|
constructor(options) {
|
|
83
86
|
this.logger = options?.logger ?? console;
|
|
84
87
|
this.onHandlerError = options?.onHandlerError ?? "log";
|
|
88
|
+
this.handlerDispatch = options?.handlerDispatch ?? "sequential";
|
|
89
|
+
const cap = options?.handlerConcurrency;
|
|
90
|
+
if (cap !== void 0 && (!Number.isInteger(cap) || cap < 1)) throw new TypeError(`MemoryEventTransport: handlerConcurrency must be a positive integer, received ${String(cap)}`);
|
|
91
|
+
this.handlerConcurrency = cap ?? Number.POSITIVE_INFINITY;
|
|
85
92
|
}
|
|
86
|
-
|
|
93
|
+
/**
|
|
94
|
+
* One work scope per publish, around the WHOLE handler set — so every
|
|
95
|
+
* handler of this event, parallel or not, shares one `requestScopedCache()`
|
|
96
|
+
* and one correlation id. Inherits an active request scope (a live
|
|
97
|
+
* in-request dispatch keeps the request's reads); a relay- or job-driven
|
|
98
|
+
* publish gets its own.
|
|
99
|
+
*/
|
|
100
|
+
publish(event) {
|
|
101
|
+
return runWorkScope(workSeedFromEvent(event), () => this.dispatch(event));
|
|
102
|
+
}
|
|
103
|
+
async dispatch(event) {
|
|
87
104
|
const allHandlers = /* @__PURE__ */ new Set();
|
|
88
105
|
for (const [pattern, handlers] of this.handlers) if (matchEventPattern(pattern, event.type)) for (const h of handlers) allHandlers.add(h);
|
|
89
106
|
const failures = [];
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
107
|
+
const run = async (handler) => {
|
|
108
|
+
try {
|
|
109
|
+
await handler(event);
|
|
110
|
+
} catch (err) {
|
|
111
|
+
failures.push(err);
|
|
112
|
+
try {
|
|
113
|
+
this.logger.error(`[EventTransport] Handler error for ${event.type}:`, err);
|
|
114
|
+
} catch {}
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
if (this.handlerDispatch === "parallel") {
|
|
118
|
+
/**
|
|
119
|
+
* `allSettled`, not `all`. Correctness must not rest on `run` never
|
|
120
|
+
* rejecting: `all` short-circuits on the first rejection and resolves
|
|
121
|
+
* `publish()` while the other handlers are still in flight — detached
|
|
122
|
+
* work racing the outbox relay's redelivery of the same event. `run` is
|
|
123
|
+
* written not to reject, and `allSettled` means the next person to add a
|
|
124
|
+
* timeout or a metric to it cannot silently break that.
|
|
125
|
+
*/
|
|
126
|
+
const pending = [...allHandlers];
|
|
127
|
+
if (this.handlerConcurrency >= pending.length) await Promise.allSettled(pending.map(run));
|
|
128
|
+
else {
|
|
129
|
+
let next = 0;
|
|
130
|
+
const worker = async () => {
|
|
131
|
+
while (next < pending.length) {
|
|
132
|
+
const handler = pending[next++];
|
|
133
|
+
if (handler) await run(handler);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
await Promise.allSettled(Array.from({ length: this.handlerConcurrency }, worker));
|
|
137
|
+
}
|
|
138
|
+
} else for (const handler of allHandlers) await run(handler);
|
|
96
139
|
/**
|
|
97
140
|
* Rejecting is what lets an OUTBOX see the failure. With this transport,
|
|
98
141
|
* `publish()` IS the handling — synchronous and in-process — so resolving
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { t as buildRequestScopeProjection } from "./projection-
|
|
1
|
+
/*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
|
|
2
|
+
import { t as buildRequestScopeProjection } from "./projection-qbCOEvsh.mjs";
|
|
3
3
|
//#region src/hooks/HookSystem.ts
|
|
4
4
|
/**
|
|
5
5
|
* Hook System
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import "./constants-
|
|
1
|
+
/*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
|
|
2
|
+
import "./constants-BQ2FbhPB.mjs";
|
|
3
3
|
//#region src/registry/ResourceRegistry.ts
|
|
4
4
|
/**
|
|
5
5
|
* Resource Registry
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { n as getUserRoles } from "./userHelpers-
|
|
3
|
-
import { b as isElevated, n as PUBLIC_SCOPE, x as isMember } from "./types-
|
|
4
|
-
import {
|
|
5
|
-
import { t as buildRequestScopeProjection } from "./projection-
|
|
6
|
-
import { t as executePipeline } from "./pipe-
|
|
1
|
+
/*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
|
|
2
|
+
import { n as getUserRoles } from "./userHelpers-DLueLQdQ.mjs";
|
|
3
|
+
import { b as isElevated, n as PUBLIC_SCOPE, x as isMember } from "./types-CNQyOrLk.mjs";
|
|
4
|
+
import { a as resolveEffectiveRoles, t as applyFieldReadPermissions } from "./fields-fA-Dkou5.mjs";
|
|
5
|
+
import { t as buildRequestScopeProjection } from "./projection-qbCOEvsh.mjs";
|
|
6
|
+
import { t as executePipeline } from "./pipe-4_XamfxI.mjs";
|
|
7
7
|
import { isPaginatedResult, toCanonicalList } from "@classytic/repo-core/pagination";
|
|
8
8
|
//#region src/core/fastifyAdapter.ts
|
|
9
9
|
/** Type guard for Mongoose-like documents with toObject() */
|
package/dist/audit/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
import { d as UserBase } from "../base-C-NL2fTi.mjs";
|
|
3
|
-
import "../index-
|
|
3
|
+
import "../index-D3sIPcD4.mjs";
|
|
4
4
|
import { FastifyPluginAsync } from "fastify";
|
|
5
5
|
import { RepositoryLike } from "@classytic/repo-core/adapter";
|
|
6
6
|
//#region src/audit/stores/interface.d.ts
|
package/dist/audit/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { t as transactionContext } from "../transactionContext-
|
|
1
|
+
/*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
|
|
2
|
+
import { t as transactionContext } from "../transactionContext-46KyUADP.mjs";
|
|
3
3
|
import { and, anyOf, eq, gte, lt, lte } from "@classytic/repo-core/filter";
|
|
4
4
|
import fp from "fastify-plugin";
|
|
5
5
|
//#region src/audit/repository-audit-adapter.ts
|
package/dist/auth/audit.mjs
CHANGED
package/dist/auth/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
import { l as PermissionCheck } from "../base-C-NL2fTi.mjs";
|
|
3
|
-
import { Ft as AuthPluginOptions, Pt as AuthHelpers } from "../index-
|
|
3
|
+
import { Ft as AuthPluginOptions, Pt as AuthHelpers } from "../index-D3sIPcD4.mjs";
|
|
4
4
|
import { t as ExternalOpenApiPaths } from "../externalPaths-CmGOxOtD.mjs";
|
|
5
5
|
import { a as SessionManagerOptions, c as createSessionManager, i as SessionData, n as MemorySessionStoreOptions, o as SessionManagerResult, r as SessionCookieOptions, s as SessionStore, t as MemorySessionStore } from "../sessionManager-qimlKV0P.mjs";
|
|
6
6
|
import { FastifyPluginAsync, FastifyReply as FastifyReply$1, FastifyRequest } from "fastify";
|
package/dist/auth/index.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { d as createDomainError, l as UnauthorizedError, p as isArcError, t as ArcError } from "../errors-
|
|
3
|
-
import { n as requireSingleHeaderValue } from "../headers-
|
|
4
|
-
import { n as getUserRoles, r as normalizeRoles } from "../userHelpers-
|
|
5
|
-
import { o as toJsonSchema } from "../schemaConverter-
|
|
6
|
-
import { E as requireOrgRole, T as requireOrgMembership, k as requireTeamMembership } from "../permissions-
|
|
1
|
+
/*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
|
|
2
|
+
import { d as createDomainError, l as UnauthorizedError, p as isArcError, t as ArcError } from "../errors-BHD3L8of.mjs";
|
|
3
|
+
import { n as requireSingleHeaderValue } from "../headers-BFEEshDS.mjs";
|
|
4
|
+
import { n as getUserRoles, r as normalizeRoles } from "../userHelpers-DLueLQdQ.mjs";
|
|
5
|
+
import { o as toJsonSchema } from "../schemaConverter-DENbixyA.mjs";
|
|
6
|
+
import { E as requireOrgRole, T as requireOrgMembership, k as requireTeamMembership } from "../permissions-C0GpDsB_.mjs";
|
|
7
7
|
import { isProductionEnv } from "@classytic/primitives/environment";
|
|
8
8
|
import { createHmac, randomUUID, timingSafeEqual } from "node:crypto";
|
|
9
9
|
import fp from "fastify-plugin";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
1
|
+
/*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
|
|
2
2
|
import { arcLog } from "./logger/index.mjs";
|
|
3
|
-
import { t as ArcError } from "./errors-
|
|
3
|
+
import { t as ArcError } from "./errors-BHD3L8of.mjs";
|
|
4
4
|
//#region src/permissions/filter-merge.ts
|
|
5
5
|
/**
|
|
6
6
|
* Policy-filter composition — logical AND, never last-writer-wins.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { a as conjoinPolicyFilters } from "./authorizationDecision-
|
|
3
|
-
import { g as toRepositoryFilter } from "./BaseController-
|
|
4
|
-
import { i as compileAggRequest, t as adapterSupportsAggregate } from "./validate-
|
|
1
|
+
/*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
|
|
2
|
+
import { a as conjoinPolicyFilters } from "./authorizationDecision-D_LFvMlm.mjs";
|
|
3
|
+
import { g as toRepositoryFilter } from "./BaseController-BqJtbiUA.mjs";
|
|
4
|
+
import { i as compileAggRequest, t as adapterSupportsAggregate } from "./validate-DV3hRbsz.mjs";
|
|
5
5
|
//#region src/core/aggregation/buildHandler.ts
|
|
6
6
|
/**
|
|
7
7
|
* Framework-agnostic aggregation execution. Runs safety guards,
|
package/dist/cache/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { i as versionKey, n as hashParams, r as tagVersionKey, t as buildQueryKey } from "../keys-
|
|
3
|
-
import { t as MemoryCacheStore } from "../memory-
|
|
4
|
-
import { r as QueryCache, t as queryCachePlugin } from "../queryCachePlugin-
|
|
1
|
+
/*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
|
|
2
|
+
import { i as versionKey, n as hashParams, r as tagVersionKey, t as buildQueryKey } from "../keys-Ds3ekBiu.mjs";
|
|
3
|
+
import { t as MemoryCacheStore } from "../memory-CNvjxzB2.mjs";
|
|
4
|
+
import { r as QueryCache, t as queryCachePlugin } from "../queryCachePlugin-2Pp9w-8D.mjs";
|
|
5
5
|
//#region src/cache/redis.ts
|
|
6
6
|
/**
|
|
7
7
|
* Redis-backed cache store.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { t as __exportAll } from "./rolldown-runtime-
|
|
1
|
+
/*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
|
|
2
|
+
import { t as __exportAll } from "./rolldown-runtime-DzE6ikSH.mjs";
|
|
3
3
|
import fp from "fastify-plugin";
|
|
4
4
|
//#region src/plugins/caching.ts
|
|
5
5
|
var caching_exports = /* @__PURE__ */ __exportAll({
|
package/dist/cleanup/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
|
-
import { L as RequestWithExtras } from "../index-
|
|
2
|
+
import { L as RequestWithExtras } from "../index-D3sIPcD4.mjs";
|
|
3
3
|
import { A as CleanupStepResult, B as VerificationResult, C as CleanupResult, D as CleanupRunStore, E as CleanupRunStatus, F as PurgeEvidence, I as PurgeResourceResult, L as PurgeStrategyKind, M as CleanupWriteFence, N as DEFAULT_CLEANUP_LIMITS, O as CleanupRunTransitionPatch, P as PurgeActor, R as PurgeVerificationSummary, 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 CleanupStepRunStatus, k as CleanupStepProgress, 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, z as VerificationCheck } from "../types-DVLddu2q.mjs";
|
|
4
|
-
import { t as ArcModule } from "../types-
|
|
4
|
+
import { t as ArcModule } from "../types-BVlowlm7.mjs";
|
|
5
5
|
import { PurgeStrategyKind as PurgeStrategyKind$1 } from "@classytic/primitives/retention";
|
|
6
6
|
import { canonicalJson } from "@classytic/primitives/canonical";
|
|
7
7
|
import { CleanupStep } from "@classytic/repo-core/cleanup";
|
package/dist/cleanup/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { g as getUserId } from "../types-
|
|
3
|
-
import { t as defineResource } from "../defineResource-
|
|
4
|
-
import { t as defineModule } from "../module-
|
|
1
|
+
/*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
|
|
2
|
+
import { g as getUserId } from "../types-CNQyOrLk.mjs";
|
|
3
|
+
import { t as defineResource } from "../defineResource-DaIySrQr.mjs";
|
|
4
|
+
import { t as defineModule } from "../module-CNcwCKUJ.mjs";
|
|
5
5
|
import { createPurgeEvidence } from "@classytic/primitives/retention";
|
|
6
6
|
import { canonicalJson, sha256Hex } from "@classytic/primitives/canonical";
|
|
7
7
|
//#region src/cleanup/errors.ts
|
|
@@ -723,9 +723,25 @@ function createCleanupService(deps) {
|
|
|
723
723
|
const logger = deps.logger;
|
|
724
724
|
const generateId = deps.generateId ?? (() => globalThis.crypto.randomUUID());
|
|
725
725
|
const now = deps.now ?? (() => /* @__PURE__ */ new Date());
|
|
726
|
+
/**
|
|
727
|
+
* Undefined-valued keys are DROPPED, not spread.
|
|
728
|
+
*
|
|
729
|
+
* `limits` is `Partial<CleanupLimits>`, which permits an EXPLICIT `undefined`
|
|
730
|
+
* — and a plain spread lets that overwrite the default rather than fall back
|
|
731
|
+
* to it. Every limit is then read in a comparison, and `n > undefined` is
|
|
732
|
+
* always `false`, so `{ limits: { maxPlanItems: undefined } }` did not raise
|
|
733
|
+
* the cap: it silently REMOVED it, on a framework whose whole job is deleting
|
|
734
|
+
* data. Same for `maxReasonLength` / `maxParamDepth`, and `maxResults` turned
|
|
735
|
+
* `slice(0, undefined)` into "keep everything".
|
|
736
|
+
*
|
|
737
|
+
* A host reaches this by forwarding an optional config through
|
|
738
|
+
* (`limits: { maxPlanItems: cfg.planCap }`) — no cast, no obvious mistake.
|
|
739
|
+
* `permissions/presets.ts` already filters for exactly this reason; this is
|
|
740
|
+
* the same rule applied to the destructive path.
|
|
741
|
+
*/
|
|
726
742
|
const limits = {
|
|
727
743
|
...DEFAULT_CLEANUP_LIMITS,
|
|
728
|
-
...deps.limits
|
|
744
|
+
...Object.fromEntries(Object.entries(deps.limits ?? {}).filter(([, v]) => v !== void 0))
|
|
729
745
|
};
|
|
730
746
|
const leaseMs = deps.leaseMs ?? 3e5;
|
|
731
747
|
const progressThrottleMs = deps.progressThrottleMs ?? 0;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import { Nt as RateLimitConfig, V as ResourceDefinition, et as RouteSchemaOptions } from "../../index-
|
|
2
|
+
import { Nt as RateLimitConfig, V as ResourceDefinition, et as RouteSchemaOptions } from "../../index-D3sIPcD4.mjs";
|
|
3
3
|
//#region src/cli/commands/describe.d.ts
|
|
4
4
|
interface DescribedResource {
|
|
5
5
|
name: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { t as CRUD_OPERATIONS } from "../../constants-
|
|
3
|
-
import { n as stringifyMeasureMap } from "../../ResourceRegistry-
|
|
1
|
+
/*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
|
|
2
|
+
import { t as CRUD_OPERATIONS } from "../../constants-BQ2FbhPB.mjs";
|
|
3
|
+
import { n as stringifyMeasureMap } from "../../ResourceRegistry-B9WnuG2Q.mjs";
|
|
4
4
|
import { resolve } from "node:path";
|
|
5
5
|
import { pathToFileURL } from "node:url";
|
|
6
6
|
//#region src/cli/commands/describe.ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { t as buildOpenApiSpec } from "../../openapi-
|
|
3
|
-
import { t as loadResourcesFromEntry } from "../../loadResourcesFromEntry-
|
|
1
|
+
/*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
|
|
2
|
+
import { t as buildOpenApiSpec } from "../../openapi-BYrL8zvY.mjs";
|
|
3
|
+
import { t as loadResourcesFromEntry } from "../../loadResourcesFromEntry-C2jrJbWG.mjs";
|
|
4
4
|
import { dirname, resolve } from "node:path";
|
|
5
5
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
6
6
|
//#region src/cli/commands/docs.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
1
|
+
/*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
|
|
2
2
|
import { dirname, join, parse, resolve } from "node:path";
|
|
3
3
|
import { existsSync, readFileSync } from "node:fs";
|
|
4
4
|
//#region src/cli/commands/doctor.ts
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { t as generate } from "../../generate-
|
|
1
|
+
/*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
|
|
2
|
+
import { t as generate } from "../../generate-BSSdtiOy.mjs";
|
|
3
3
|
export { generate };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { t as init } from "../../init-
|
|
1
|
+
/*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
|
|
2
|
+
import { t as init } from "../../init-pl88PHzb.mjs";
|
|
3
3
|
export { init };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { t as loadResourcesFromEntry } from "../../loadResourcesFromEntry-
|
|
1
|
+
/*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
|
|
2
|
+
import { t as loadResourcesFromEntry } from "../../loadResourcesFromEntry-C2jrJbWG.mjs";
|
|
3
3
|
//#region src/cli/commands/introspect.ts
|
|
4
4
|
function describePermission(value) {
|
|
5
5
|
if (!value) return "none";
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
1
|
+
/*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
|
|
2
2
|
import { describe } from "./commands/describe.mjs";
|
|
3
3
|
import { exportDocs } from "./commands/docs.mjs";
|
|
4
4
|
import { doctor } from "./commands/doctor.mjs";
|
|
5
|
-
import { t as generate } from "../generate-
|
|
6
|
-
import { t as init } from "../init-
|
|
5
|
+
import { t as generate } from "../generate-BSSdtiOy.mjs";
|
|
6
|
+
import { t as init } from "../init-pl88PHzb.mjs";
|
|
7
7
|
import { introspect } from "./commands/introspect.mjs";
|
|
8
8
|
export { describe, doctor, exportDocs, generate, init, introspect };
|