@classytic/arc 2.32.0 → 2.33.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/README.md +1 -1
- package/bin/arc.js +58 -17
- package/dist/{BaseController-Dk34dxhI.mjs → BaseController-CaQC5EXX.mjs} +293 -33
- package/dist/{EventTransport-2uVV34WU.d.mts → EventTransport-BEVP50ka.d.mts} +16 -0
- package/dist/{EventTransport-BV10D0oG.mjs → EventTransport-tq4CEB-q.mjs} +39 -2
- package/dist/{HookSystem-vimw5D7Z.mjs → HookSystem-DqXkMXkB.mjs} +2 -2
- package/dist/{ResourceRegistry-BVr7PgA0.mjs → ResourceRegistry-DoALUlOO.mjs} +3 -2
- package/dist/{actionPermissions-Dti7ebyv.mjs → actionPermissions-CUeCmpUd.mjs} +1 -1
- package/dist/audit/index.d.mts +2 -2
- package/dist/audit/index.mjs +2 -2
- package/dist/auth/audit.mjs +1 -1
- package/dist/auth/index.d.mts +2 -2
- package/dist/auth/index.mjs +39 -7
- package/dist/auth/redis-session.mjs +1 -1
- package/dist/{authorizationDecision-__T3EJDA.mjs → authorizationDecision-B3mP_QTy.mjs} +2 -2
- package/dist/{types-B7XeLEgK.d.mts → base-Csjc2oF-.d.mts} +74 -74
- package/dist/{buildHandler-Dn7rzUJo.mjs → buildHandler-DLE9xX-V.mjs} +4 -4
- package/dist/cache/index.mjs +4 -4
- package/dist/{caching-DFJqHyFs.mjs → caching-BcGmvnHh.mjs} +2 -2
- package/dist/cleanup/index.d.mts +17 -5
- package/dist/cleanup/index.mjs +240 -7
- 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-J99LGTJI.mjs → constants-BxCoxmiN.mjs} +1 -1
- package/dist/context/index.mjs +3 -3
- package/dist/core/index.d.mts +2 -2
- package/dist/core/index.mjs +7 -7
- package/dist/{core-BwwmNSp7.mjs → core-dxhcHhUD.mjs} +3 -3
- package/dist/{createActionRouter-DkJZWo0m.mjs → createActionRouter-DVpoA0do.mjs} +8 -8
- package/dist/{createAggregationRouter-B1exOVD8.mjs → createAggregationRouter-B_B48JZ-.mjs} +7 -7
- package/dist/{createApp-Bv0m-Q6_.mjs → createApp-CLGegqiG.mjs} +128 -24
- package/dist/{defineAggregation-gX4No1gt.mjs → defineAggregation-Nv-DwfOf.mjs} +1 -1
- package/dist/{defineResource-XFPPUu2c.mjs → defineResource-DR9vsUYy.mjs} +297 -23
- 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-DNXXxgjl.mjs → elevation-B0tlY8y1.mjs} +4 -4
- package/dist/encryption/index.mjs +3 -3
- package/dist/{errorHandler-B2AZUJUj.mjs → errorHandler-C7xBqHsI.mjs} +42 -5
- package/dist/{errorHandler-CpYUJmPA.d.mts → errorHandler-DI5AN2b5.d.mts} +14 -3
- package/dist/{errors-Bh1KK5ps.mjs → errors-Cd_yy7aW.mjs} +1 -1
- package/dist/{eventPlugin-GF5nnBIq.d.mts → eventPlugin-DSNEZWfV.d.mts} +29 -1
- package/dist/{eventPlugin-Dk_TyXeE.mjs → eventPlugin-Dar8qRaj.mjs} +65 -9
- package/dist/events/index.d.mts +5 -351
- package/dist/events/index.mjs +5 -780
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis-stream-entry.mjs +1 -1
- package/dist/events/transports/redis.d.mts +1 -1
- package/dist/events/transports/redis.mjs +1 -1
- package/dist/factory/index.d.mts +20 -5
- package/dist/factory/index.mjs +7 -7
- package/dist/{fastify-augmentation-BppG5bMT.d.mts → fastify-augmentation-DVsTAy6X.d.mts} +3 -3
- package/dist/{fields-DEi65pGj.mjs → fields-CojeUkS4.mjs} +1 -1
- package/dist/{generate-CRSG0jTv.mjs → generate-DiB0nHPR.mjs} +2 -2
- package/dist/{headers-BXjQYbeC.mjs → headers-CveNO9gR.mjs} +2 -2
- package/dist/{health-5XnTa2uo.mjs → health-CasG2A28.mjs} +1 -1
- package/dist/hooks/index.d.mts +1 -1
- package/dist/hooks/index.mjs +2 -2
- package/dist/idempotency/index.d.mts +45 -1
- package/dist/idempotency/index.mjs +91 -9
- package/dist/idempotency/redis.mjs +1 -1
- package/dist/{index-zq6VrjaB.d.mts → index-B-DvUzsr.d.mts} +12 -2
- package/dist/{index-CpzxqePp.d.mts → index-BcR2bFZQ.d.mts} +707 -373
- package/dist/{index-DXlHwvuE.d.mts → index-Brin0ODU.d.mts} +4 -4
- package/dist/{index-ZWhLTp_s.d.mts → index-C5NnMEKF.d.mts} +1 -1
- package/dist/{index-C-481Zf2.d.mts → index-ugr1tQlW.d.mts} +17 -1
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +11 -11
- package/dist/{init-BbfP8aky.mjs → init-mdJ-v4Xp.mjs} +18 -12
- package/dist/integrations/event-gateway.d.mts +1 -1
- package/dist/integrations/event-gateway.mjs +2 -2
- package/dist/integrations/index.d.mts +2 -2
- package/dist/integrations/index.mjs +1 -1
- package/dist/integrations/jobs/index.d.mts +1 -1
- package/dist/integrations/jobs/index.mjs +99 -97
- package/dist/integrations/mcp/index.d.mts +12 -3
- package/dist/integrations/mcp/index.mjs +2 -2
- package/dist/integrations/mcp/testing.d.mts +1 -1
- package/dist/integrations/mcp/testing.mjs +2 -2
- package/dist/integrations/streamline.mjs +3 -3
- package/dist/integrations/webhooks.d.mts +124 -1
- package/dist/integrations/webhooks.mjs +180 -2
- package/dist/integrations/websocket-pushref-redis.mjs +1 -1
- package/dist/integrations/websocket-redis.mjs +1 -1
- package/dist/integrations/websocket.mjs +1 -1
- package/dist/{interface-BP4IJCBO.mjs → interface-DznJrm9R.mjs} +1 -1
- package/dist/{jsonBody-DDSR2HFl.mjs → jsonBody-CfGH-GxO.mjs} +2 -2
- package/dist/{keys-B-HBTGXl.mjs → keys-WeKvY1dE.mjs} +1 -1
- package/dist/{loadResources-DisEAmkm.mjs → loadResources-Bj-aSsXi.mjs} +2 -2
- package/dist/{loadResourcesFromEntry-D1MJp13f.mjs → loadResourcesFromEntry-DwaxNcE2.mjs} +2 -2
- package/dist/logger/index.mjs +1 -1
- package/dist/{mcpPlugin-CpfVpKHE.mjs → mcpPlugin-aJg5TqHi.mjs} +60 -21
- package/dist/{memory-DsuWnj4T.mjs → memory-qYSB7rMQ.mjs} +2 -2
- package/dist/{metrics-DdQL8syd.mjs → metrics-D7uchLjN.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-Br81am6m.mjs → module-CwKsgZXp.mjs} +1 -1
- package/dist/{multipartBody-BnkBLN7v.mjs → multipartBody-4w-S3-PU.mjs} +1 -1
- package/dist/{openapi-DIRzvxC0.mjs → openapi-BN5cQaO2.mjs} +6 -6
- package/dist/outbox-admin/index.d.mts +2 -2
- package/dist/outbox-admin/index.mjs +4 -4
- package/dist/outbox-module-CXB79bvt.mjs +839 -0
- package/dist/outbox-module-D-VFq37T.d.mts +368 -0
- package/dist/permissions/index.d.mts +2 -2
- package/dist/permissions/index.mjs +5 -5
- package/dist/{permissions-Dl_m0NCe.mjs → permissions-BAfwgBxc.mjs} +25 -6
- package/dist/{pipe-ELHCP3zj.mjs → pipe-BzzoEhHj.mjs} +2 -2
- package/dist/pipeline/index.d.mts +1 -1
- package/dist/pipeline/index.mjs +2 -2
- package/dist/{pipeline-CPA-jx0M.mjs → pipeline-q69DZzgG.mjs} +6 -6
- package/dist/plugins/index.d.mts +6 -6
- package/dist/plugins/index.mjs +16 -16
- package/dist/plugins/response-cache.mjs +2 -2
- package/dist/plugins/tracing-entry.mjs +2 -2
- package/dist/{pluralize-C2ZkKbsn.mjs → pluralize-B7xf8qZF.mjs} +1 -1
- package/dist/{preloadResources-CDs87fTw.mjs → preloadResources-BkyqeTDz.mjs} +1 -1
- package/dist/{preloadResources-T1hmlTEZ.d.mts → preloadResources-g07ldtzh.d.mts} +30 -7
- package/dist/presets/filesUpload.d.mts +2 -2
- package/dist/presets/filesUpload.mjs +5 -5
- package/dist/presets/index.d.mts +2 -2
- 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 +2 -2
- package/dist/presets/search.mjs +2 -2
- package/dist/{presets-Dntd_pUO.mjs → presets-D-h0uWtP.mjs} +4 -4
- package/dist/projection-BKM0Ui-s.mjs +42 -0
- package/dist/{queryCachePlugin-Dhps-Ldt.mjs → queryCachePlugin-DhsZ0ZIc.mjs} +49 -7
- package/dist/{rateLimit-C7mmAGs3.mjs → rateLimit-D4-ASwsI.mjs} +2 -2
- package/dist/{rateLimitKey-CccEFBfk.mjs → rateLimitKey-XngqVNEV.mjs} +1 -1
- package/dist/{realtime-DVvVZZFz.mjs → realtime-CTkv3O59.mjs} +9 -9
- package/dist/{redis-stream-qN6A-RFv.d.mts → redis-stream-mwLWlfHG.d.mts} +1 -1
- package/dist/{registerRoute-B_QrjYZS.mjs → registerRoute-DNnd3vkz.mjs} +4 -4
- package/dist/registry/index.d.mts +3 -3
- package/dist/registry/index.mjs +3 -3
- package/dist/{registry-DqUmzA9W.mjs → registry-CLxCR5LF.mjs} +2 -2
- package/dist/{renewingLease-BpP9wwj7.mjs → renewingLease-BnWtbA2U.mjs} +1 -1
- package/dist/{replyHelpers-DS-P0b32.mjs → replyHelpers-BSBVCwL3.mjs} +2 -2
- package/dist/{repositoryFilter-DotlxG3L.mjs → repositoryFilter-DKny7PDn.mjs} +1 -1
- package/dist/{requestContext-B6vQF-sy.mjs → requestContext-uYE35JxI.mjs} +1 -1
- package/dist/{rolldown-runtime-BhflRrBs.mjs → rolldown-runtime-DNg-KNCk.mjs} +1 -1
- package/dist/runtimeCapabilities-Dm88DaTW.mjs +49 -0
- package/dist/{schedules-C2Q3uv2d.mjs → schedules-CAcZgia0.mjs} +3 -3
- package/dist/{schemaConverter-Crjvczi_.mjs → schemaConverter-XH1RZRyu.mjs} +1 -1
- package/dist/{schemaIR-CnyKK_1j.mjs → schemaIR-CDvclAew.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-afz_Ieek.mjs → scope-BaWcqBvr.mjs} +4 -4
- package/dist/{simpleEqualityMatcher-C4KiMWUa.mjs → simpleEqualityMatcher-Se8VrsaP.mjs} +1 -1
- package/dist/{sse-B9P4Y-UI.mjs → sse-Cf0jUHsh.mjs} +5 -5
- package/dist/{sseStream-B3zb_d1h.mjs → sseStream-Bvpi-UXQ.mjs} +2 -2
- package/dist/{store-helpers-DmEMHlPQ.mjs → store-helpers-B88p99Z2.mjs} +1 -1
- package/dist/{streaming-DPZdQmDz.mjs → streaming-DsT1B5zJ.mjs} +1 -1
- package/dist/{subscribe-helpers-sp5xTDVA.mjs → subscribe-helpers-CLIOHsOK.mjs} +2 -2
- package/dist/sync/changelog.mjs +1 -1
- package/dist/testing/cleanupStoreContract.d.mts +1 -1
- package/dist/testing/cleanupStoreContract.mjs +3 -1
- package/dist/testing/index.d.mts +24 -12
- package/dist/testing/index.mjs +24 -12
- package/dist/testing/outboxStoreContract.mjs +1 -1
- package/dist/testing/storageContract.mjs +1 -1
- package/dist/{transactionContext-BvLKvOIL.mjs → transactionContext-BYtWnwAS.mjs} +1 -1
- package/dist/{typeGuards-B_5-hKjJ.mjs → typeGuards-jjKJDN13.mjs} +1 -1
- package/dist/types/index.d.mts +3 -3
- package/dist/types/index.mjs +1 -1
- package/dist/types/storage.mjs +1 -1
- package/dist/{types-CT5vu6M0.d.mts → types-BcTumAz_.d.mts} +41 -7
- package/dist/{types-CwcUQ610.d.mts → types-BfC83KsP.d.mts} +15 -1
- package/dist/{types-DXYX7dIR.mjs → types-CoqIRrkY.mjs} +4 -4
- package/dist/{types-C4QE8qnm.d.mts → types-DVLddu2q.d.mts} +144 -1
- package/dist/usage/index.d.mts +1 -1
- package/dist/usage/index.mjs +0 -0
- package/dist/{userHelpers-BNsOXzOd.mjs → userHelpers-CWF5pbZD.mjs} +1 -1
- package/dist/utils/index.d.mts +57 -5
- package/dist/utils/index.mjs +12 -11
- package/dist/{utils-BtOha_Sp.mjs → utils-h1V_sT-t.mjs} +38 -7
- package/dist/{validate-PMCPR9El.mjs → validate-CdQlz52F.mjs} +2 -2
- package/dist/{versioning-D_rhHfZm.d.mts → versioning-DEs-_hFi.d.mts} +1 -1
- package/dist/{versioning-CKv2jz_U.mjs → versioning-rZbyLVD-.mjs} +3 -3
- package/package.json +17 -16
- package/skills/arc/SKILL.md +96 -4
- package/skills/arc/references/api-reference.md +19 -0
- package/skills/arc/references/production.md +2 -2
- package/dist/projection-CjHhM5W1.mjs +0 -18
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { m as RESERVED_QUERY_PARAMS } from "./constants-
|
|
1
|
+
/*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
|
|
2
|
+
import { m as RESERVED_QUERY_PARAMS } from "./constants-BxCoxmiN.mjs";
|
|
3
3
|
import { arcLog } from "./logger/index.mjs";
|
|
4
|
-
import { t as ArcError } from "./errors-
|
|
4
|
+
import { t as ArcError, u as ValidationError } from "./errors-Cd_yy7aW.mjs";
|
|
5
5
|
import { errorContractSchema as errorContractSchema$1, errorDetailSchema as errorDetailSchema$1 } from "@classytic/repo-core/errors";
|
|
6
6
|
import { scheduleBackground } from "@classytic/repo-core/cache";
|
|
7
7
|
//#region src/utils/circuitBreaker.ts
|
|
@@ -591,6 +591,11 @@ const DANGEROUS_REGEX_PATTERNS = /(\{[0-9,]+\}|\*\+|\+\+|\?\+|(\(.+\))\+|\(\?:|\
|
|
|
591
591
|
* For advanced MongoDB features ($lookup, aggregations), use MongoKit's QueryParser.
|
|
592
592
|
*/
|
|
593
593
|
var ArcQueryParser = class {
|
|
594
|
+
/**
|
|
595
|
+
* PUBLIC, deliberately: `QueryResolver` reads it so it does not apply a second cap
|
|
596
|
+
* on top of this one. Three layers capping independently, lowest winning silently,
|
|
597
|
+
* is what made a 696-row chart of accounts render as 100.
|
|
598
|
+
*/
|
|
594
599
|
maxLimit;
|
|
595
600
|
defaultLimit;
|
|
596
601
|
maxRegexLength;
|
|
@@ -599,6 +604,7 @@ var ArcQueryParser = class {
|
|
|
599
604
|
_allowedFilterFields;
|
|
600
605
|
_allowedSortFields;
|
|
601
606
|
_allowedOperators;
|
|
607
|
+
strictFilterFields;
|
|
602
608
|
/** Allowed filter fields (used by MCP for auto-derive) */
|
|
603
609
|
allowedFilterFields;
|
|
604
610
|
/** Allowed sort fields (used by MCP for sort descriptions) */
|
|
@@ -621,6 +627,7 @@ var ArcQueryParser = class {
|
|
|
621
627
|
this.maxRegexLength = options.maxRegexLength ?? 200;
|
|
622
628
|
this.maxSearchLength = options.maxSearchLength ?? 200;
|
|
623
629
|
this.maxFilterDepth = options.maxFilterDepth ?? 10;
|
|
630
|
+
this.strictFilterFields = options.strictFilterFields ?? process.env.ARC_STRICT_QUERY_PARAMS === "true";
|
|
624
631
|
if (options.allowedFilterFields) {
|
|
625
632
|
this._allowedFilterFields = new Set(options.allowedFilterFields);
|
|
626
633
|
this.allowedFilterFields = options.allowedFilterFields;
|
|
@@ -787,7 +794,10 @@ var ArcQueryParser = class {
|
|
|
787
794
|
if (value === void 0 || value === null) return;
|
|
788
795
|
if (!/^[a-zA-Z_][a-zA-Z0-9_.]*(?:\[[a-z]+\])?$/.test(key)) return;
|
|
789
796
|
const bareKey = key.replace(/\[[a-z]+\]$/, "");
|
|
790
|
-
if (this._allowedFilterFields && !this._allowedFilterFields.has(bareKey))
|
|
797
|
+
if (this._allowedFilterFields && !this._allowedFilterFields.has(bareKey)) {
|
|
798
|
+
if (this.strictFilterFields) throw new ValidationError(`Unknown filter field: ${bareKey}. Allowed: ${[...this._allowedFilterFields].sort().join(", ")}`);
|
|
799
|
+
return;
|
|
800
|
+
}
|
|
791
801
|
if (this.exceedsDepth(value)) return;
|
|
792
802
|
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
793
803
|
const operatorObj = value;
|
|
@@ -879,10 +889,31 @@ var ArcQueryParser = class {
|
|
|
879
889
|
},
|
|
880
890
|
limit: {
|
|
881
891
|
type: "integer",
|
|
882
|
-
|
|
892
|
+
/**
|
|
893
|
+
* The cap is DOCUMENTED here, not enforced — deliberately.
|
|
894
|
+
*
|
|
895
|
+
* Both layers that handle `limit` CLAMP it: this parser
|
|
896
|
+
* (`Math.min(…, this.maxLimit)`) and `QueryResolver`. Emitting
|
|
897
|
+
* `maximum` contradicted them, because arc layers this schema as the
|
|
898
|
+
* route's `listQuery` and Fastify validates the querystring BEFORE
|
|
899
|
+
* either runs — so the clamp was unreachable and `?limit=200` became a
|
|
900
|
+
* hard 400.
|
|
901
|
+
*
|
|
902
|
+
* That combination is worse than either policy alone. Asking for more
|
|
903
|
+
* rows than allowed is a benign over-ask with an obvious right answer
|
|
904
|
+
* (give the maximum); turning it into a validation failure means a UI
|
|
905
|
+
* passing a generous page size gets NOTHING, and a caller that does not
|
|
906
|
+
* inspect the error body renders it as an empty list — a 400 disguised
|
|
907
|
+
* as "no results", which is the hardest kind to find.
|
|
908
|
+
*
|
|
909
|
+
* A deployment wanting refusal instead of clamping should say so in the
|
|
910
|
+
* parser's policy, where both halves can agree, not in a schema that
|
|
911
|
+
* silently outranks them. Mirrors the same fix in mongokit's
|
|
912
|
+
* `buildQuerySchema`.
|
|
913
|
+
*/
|
|
914
|
+
description: `Number of items per page (values above ${this.maxLimit} are capped to ${this.maxLimit})`,
|
|
883
915
|
default: this.defaultLimit,
|
|
884
|
-
minimum: 1
|
|
885
|
-
maximum: this.maxLimit
|
|
916
|
+
minimum: 1
|
|
886
917
|
},
|
|
887
918
|
sort: {
|
|
888
919
|
type: "string",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { t as __exportAll } from "./rolldown-runtime-
|
|
1
|
+
/*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
|
|
2
|
+
import { t as __exportAll } from "./rolldown-runtime-DNg-KNCk.mjs";
|
|
3
3
|
//#region src/core/aggregation/normalize.ts
|
|
4
4
|
/**
|
|
5
5
|
* Framework cap on URL-driven aggregation limits when the host opts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { t as __exportAll } from "./rolldown-runtime-
|
|
3
|
-
import { d as createDomainError } from "./errors-
|
|
1
|
+
/*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
|
|
2
|
+
import { t as __exportAll } from "./rolldown-runtime-DNg-KNCk.mjs";
|
|
3
|
+
import { d as createDomainError } from "./errors-Cd_yy7aW.mjs";
|
|
4
4
|
import fp from "fastify-plugin";
|
|
5
5
|
//#region src/plugins/versioning.ts
|
|
6
6
|
var versioning_exports = /* @__PURE__ */ __exportAll({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@classytic/arc",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.33.0",
|
|
4
4
|
"description": "Resource-oriented backend framework for Fastify - clean, minimal, powerful, tree-shakable",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -336,13 +336,14 @@
|
|
|
336
336
|
"test:smoke:redis": "node scripts/smoke-ws-redis.mjs",
|
|
337
337
|
"smoke": "node scripts/smoke-test.mjs",
|
|
338
338
|
"smoke:consumer": "node scripts/smoke-test.mjs --consumer",
|
|
339
|
+
"smoke:mcp": "node scripts/mcp-e2e.mjs",
|
|
339
340
|
"push": "classytic-push",
|
|
340
341
|
"release:tag": "node -e \"require('child_process').execSync('npm run push -- v'+require('./package.json').version,{stdio:'inherit'})\"",
|
|
341
342
|
"release": "npm run push -- main && npm run release:tag && npm publish",
|
|
342
343
|
"check:peer-skew": "node scripts/check-peer-skew.mjs",
|
|
343
344
|
"check:docs-drift": "node scripts/check-docs-drift.mjs",
|
|
344
345
|
"check:boundaries": "node scripts/check-boundaries.mjs",
|
|
345
|
-
"prepublishOnly": "npm run check:peer-skew && npm run check:docs-drift && npm run check:route-api && npm run check:boundaries && npm run typecheck && npm run lint && npm run build && npm run check:api-surface && npm run check:forgotten-exports && npm run check:package && npm run test:ci && npm run smoke:consumer",
|
|
346
|
+
"prepublishOnly": "npm run check:peer-skew && npm run check:docs-drift && npm run check:route-api && npm run check:boundaries && npm run typecheck && npm run lint && npm run build && npm run check:api-surface && npm run check:forgotten-exports && npm run check:package && npm run test:ci && npm run smoke:consumer && npm run smoke:mcp",
|
|
346
347
|
"check:route-api": "node scripts/check-removed-route-api.mjs",
|
|
347
348
|
"check:forgotten-exports": "node scripts/check-forgotten-exports.mjs"
|
|
348
349
|
},
|
|
@@ -350,8 +351,8 @@
|
|
|
350
351
|
"node": ">=22"
|
|
351
352
|
},
|
|
352
353
|
"peerDependencies": {
|
|
353
|
-
"@classytic/primitives": ">=0.
|
|
354
|
-
"@classytic/repo-core": ">=0.
|
|
354
|
+
"@classytic/primitives": ">=0.23.0",
|
|
355
|
+
"@classytic/repo-core": ">=0.24.0",
|
|
355
356
|
"@classytic/streamline": ">=2.8.0",
|
|
356
357
|
"@fastify/cors": ">=11.0.0",
|
|
357
358
|
"@fastify/helmet": ">=13.0.0",
|
|
@@ -359,6 +360,7 @@
|
|
|
359
360
|
"@fastify/multipart": ">=9.0.0",
|
|
360
361
|
"@fastify/rate-limit": ">=10.0.0",
|
|
361
362
|
"@fastify/sensible": ">=6.0.0",
|
|
363
|
+
"@fastify/static": ">=8.0.0",
|
|
362
364
|
"@fastify/type-provider-typebox": ">=6.0.0",
|
|
363
365
|
"@fastify/under-pressure": ">=9.0.0",
|
|
364
366
|
"@fastify/websocket": ">=11.0.0",
|
|
@@ -378,9 +380,8 @@
|
|
|
378
380
|
"jose": ">=5.0.0",
|
|
379
381
|
"pino-pretty": ">=13.0.0",
|
|
380
382
|
"typebox": ">=1.0.0",
|
|
381
|
-
"
|
|
382
|
-
"
|
|
383
|
-
"vitest": ">=3.0.0"
|
|
383
|
+
"vitest": ">=3.0.0",
|
|
384
|
+
"zod": ">=4.4.0"
|
|
384
385
|
},
|
|
385
386
|
"peerDependenciesMeta": {
|
|
386
387
|
"better-auth": {
|
|
@@ -480,11 +481,11 @@
|
|
|
480
481
|
"@biomejs/biome": "^2.5.7",
|
|
481
482
|
"@classytic/dev-tools": "^0.2.0",
|
|
482
483
|
"@classytic/gitkit": ">=0.1.0",
|
|
483
|
-
"@classytic/mongokit": "^3.
|
|
484
|
+
"@classytic/mongokit": "^3.33.0",
|
|
484
485
|
"@classytic/pgkit": "^0.1.0",
|
|
485
|
-
"@classytic/primitives": "^0.
|
|
486
|
-
"@classytic/repo-core": "^0.
|
|
487
|
-
"@classytic/sqlitekit": "^0.
|
|
486
|
+
"@classytic/primitives": "^0.23.0",
|
|
487
|
+
"@classytic/repo-core": "^0.24.0",
|
|
488
|
+
"@classytic/sqlitekit": "^0.9.0",
|
|
488
489
|
"@classytic/streamline": "^2.8.2",
|
|
489
490
|
"@electric-sql/pglite": "^0.5.4",
|
|
490
491
|
"@fastify/cors": "^11.2.0",
|
|
@@ -504,15 +505,15 @@
|
|
|
504
505
|
"@vitest/coverage-v8": "^4.1.9",
|
|
505
506
|
"ajv": "^8.20.0",
|
|
506
507
|
"better-auth": "^1.6.25",
|
|
507
|
-
"better-sqlite3": "^
|
|
508
|
-
"bullmq": "^
|
|
508
|
+
"better-sqlite3": "^13.0.3",
|
|
509
|
+
"bullmq": "^6.1.2",
|
|
509
510
|
"dotenv": "^17.4.2",
|
|
510
511
|
"drizzle-orm": "^0.45.2",
|
|
511
512
|
"fast-check": "^4.8.0",
|
|
512
|
-
"fastify": "^5.
|
|
513
|
-
"fastify-raw-body": "^
|
|
513
|
+
"fastify": "^5.12.0",
|
|
514
|
+
"fastify-raw-body": "^6.0.1",
|
|
514
515
|
"h3-js": "^4.4.0",
|
|
515
|
-
"ioredis": "^
|
|
516
|
+
"ioredis": "^6.0.0",
|
|
516
517
|
"jose": "^6.2.3",
|
|
517
518
|
"jsonwebtoken": "^9.0.3",
|
|
518
519
|
"knip": "^6.31.0",
|
package/skills/arc/SKILL.md
CHANGED
|
@@ -69,6 +69,14 @@ await app.listen({ port: 8040, host: '0.0.0.0' });
|
|
|
69
69
|
|
|
70
70
|
**Boot order (fixed):** `beforeBoot` → modules resolve → `plugins` → `bootstrap[]` → `resources` → `afterResources` → `onReady`.
|
|
71
71
|
|
|
72
|
+
**`role` — one image, N deployments (2.34).** `createApp({ role })` declares what a process is FOR, so the same codebase ships as api / worker / relay / scheduler without per-deployment builds:
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
createApp({ role: process.env.ARC_ROLE as 'api' | 'worker' | 'relay' | 'scheduler' | 'all' })
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`api` and `worker` mount NO module schedule arms; `relay` mounts only `kind: 'relay'` arms (the outbox relay, durable webhook delivery); `scheduler` mounts all of them. Declaring `relay`/`scheduler` together with `resources`/`resourceDir` is BOOT-FATAL — a relay process must not serve routes. Default `all` is the pre-2.34 behaviour, unchanged. `createWorker()` forwards `role`; without one it still runs everything non-HTTP.
|
|
79
|
+
|
|
72
80
|
`beforeBoot()` (2.21) runs before Fastify exists and before module thunks / resource files import — connect the DB there instead of dynamic-import ordering hacks.
|
|
73
81
|
|
|
74
82
|
For async-booted engines, pass `resources` as a factory so it runs after `bootstrap[]`:
|
|
@@ -162,7 +170,7 @@ defineResource({ name: 'health', customRoutesOnly: true, routes: [...] });
|
|
|
162
170
|
defineResource({ name: 'pipeline', adapter, defaultLimit: 200, maxLimit: 500 });
|
|
163
171
|
```
|
|
164
172
|
|
|
165
|
-
|
|
173
|
+
A `?limit=` above the cap is **clamped to it**, not rejected (2.33 — see Query parsing). The effective cap rides in the OpenAPI parameter description.
|
|
166
174
|
|
|
167
175
|
## fieldRules
|
|
168
176
|
|
|
@@ -304,12 +312,18 @@ Decorates `app.authenticate` / `app.optionalAuthenticate` / `app.authorize`.
|
|
|
304
312
|
## Authoritative gotchas
|
|
305
313
|
|
|
306
314
|
- **Field-write reject (default).** Requests carrying non-writable fields → 403 with denied list. Opt into silent strip: `defineResource({ onFieldWriteDenied: 'strip' })`.
|
|
315
|
+
- **Immutable writes are STRIPPED, not refused (default).** `PATCH {"type":"rent"}` on an `immutable` field returns 200 with the value unchanged. Opt into 403: `defineResource({ onImmutableWrite: 'reject' })`, or `ARC_STRICT_IMMUTABLE_WRITES=true`. Separate from `onFieldWriteDenied` because a full-object PATCH echoing an immutable field back UNCHANGED is legitimate, and the sanitizer has no stored document to tell that from a real change — turn it on if you send partial patches.
|
|
316
|
+
- **Log redaction is REPLACED, not merged.** Setting `logger.redact` makes yours the whole policy; arc's defaults stop applying. Superset them: `import { DEFAULT_LOGGER_REDACT_PATHS } from '@classytic/arc/factory'` and spread it into your list, rather than hand-copying (a copy drifts — one host's had lost `*.passwordHash`).
|
|
317
|
+
- **Error disclosure derives from `preset`, falling back to the environment.** `includeStack` and `exposeInternalMessages` are both derived, and host keys MERGE over them — stating one no longer resets the other. Direct `errorHandlerPlugin` registration skips the preset derivation entirely.
|
|
307
318
|
- **multiTenant injects org on UPDATE.** Body `organizationId` is overwritten with caller's scope (closes tenant-hop).
|
|
308
319
|
- **`request.user`** is `Record<string, unknown> | undefined`. Guard with `if (req.user)` on public routes.
|
|
309
320
|
- **Arc reads singular `user.role`** (string, comma-separated, or array). Don't put a plural `roles` field on the model.
|
|
310
321
|
- **`verifySignature(body, …)`** throws on parsed body — pass `req.rawBody`.
|
|
311
322
|
- **MCP tools fail-closed.** A resource action without per-action perm + no `actionPermissions` + no `permissions.update` fallback → throws at tool generation. Declare `allowPublic()` to opt into unauthenticated.
|
|
312
323
|
- **Better Auth roles.** BA stores `member.role = "admin,recruiter"` (comma-separated). Arc splits into `scope.orgRoles = ['admin', 'recruiter']`; `?role=admin` won't match — use `role[like]=admin`.
|
|
324
|
+
- **Read-only repositories refuse write ROUTES at boot (2.34).** Kits' Better Auth overlays are sealed by default (`capabilities.readOnly`) — BA owns hashing, session revocation, org cascades. Mounting `create`/`update`/`delete` over one is boot-fatal: disable those routes, or pass the kit's `unsafeWritable: true` for administrative repair only. Normal identity mutations go through `auth.api`.
|
|
325
|
+
- **Arc closes only stores/transports it BUILT (2.34).** One you hand to `idempotencyPlugin` / `eventPlugin` / `queryCachePlugin` stays yours to close — arc used to close every one, which wiped a co-resident app's live idempotency records.
|
|
326
|
+
- **Idempotency self-checks its store at boot (2.34).** A probe write must read back under its own key and NOT under another; registration throws otherwise. Catches a filter-stripping repository (a pathless Mongoose schema under `strictQuery: true` strips filters to `{}`), which otherwise replays cached responses across keys AND users. `selfCheck: false` to disable; the adapter's per-read identity checks remain.
|
|
313
327
|
|
|
314
328
|
## routeGuards + defineGuard
|
|
315
329
|
|
|
@@ -369,6 +383,28 @@ defineResource({
|
|
|
369
383
|
});
|
|
370
384
|
```
|
|
371
385
|
|
|
386
|
+
**An unknown filter key is DROPPED by default, and dropping WIDENS.** `?filters[status]=pending`
|
|
387
|
+
against a parser that does not whitelist `status` returns 200 with every row unfiltered — the
|
|
388
|
+
caller asked to narrow and got a broader set. Refuse instead:
|
|
389
|
+
|
|
390
|
+
```typescript
|
|
391
|
+
new QueryParser({ allowedFilterFields: [...], strictFilterFields: true }) // 400 ValidationError
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
Off by default (an unconditional throw would reject requests that work today). Fleet-wide via
|
|
395
|
+
`ARC_STRICT_QUERY_PARAMS=true`; an explicit `false` beats the env. Only the FILTER whitelist —
|
|
396
|
+
a dropped sort or operator degrades ordering, it does not widen the row set.
|
|
397
|
+
|
|
398
|
+
**`?limit` above the cap CLAMPS, it does not 400** (2.33). The parser and `QueryResolver` both
|
|
399
|
+
clamp, and the querystring schema no longer emits `maximum` — it used to reject first, making the
|
|
400
|
+
documented clamp unreachable and turning a benign over-ask into a 400 that callers render as an
|
|
401
|
+
empty list. The cap is in the parameter description instead, so OpenAPI still shows it.
|
|
402
|
+
|
|
403
|
+
**One cap, one owner.** Page size is capped by the parser, the repository's pagination engine and
|
|
404
|
+
arc — lowest wins silently. Arc defers to the parser's `maxLimit` when the host states none, and
|
|
405
|
+
WARNS at boot when the parser allows more than the repository (`pagination-cap-mismatch`).
|
|
406
|
+
Configure both to the same number.
|
|
407
|
+
|
|
372
408
|
## Aggregations
|
|
373
409
|
|
|
374
410
|
`GET /:prefix/aggregations/:name` per entry. Portable `$match → $group → $project → $sort → $limit` against `repo.aggregate(req, options)` — same shape across kits.
|
|
@@ -453,6 +489,31 @@ defineResource({
|
|
|
453
489
|
|
|
454
490
|
POST/PATCH/DELETE bumps resource version. Response header: `x-cache: HIT | STALE | MISS`. `runtime: 'distributed'` requires `stores.queryCache: RedisCacheStore`.
|
|
455
491
|
|
|
492
|
+
## Transactional writes (2.34)
|
|
493
|
+
|
|
494
|
+
`transactional: true` runs the PERSISTENCE step inside `withTransaction`. Write verbs receive the tx-bound repository plus `ctx.uow` — the join point for work outside the repository:
|
|
495
|
+
|
|
496
|
+
```typescript
|
|
497
|
+
defineResource({
|
|
498
|
+
name: 'order',
|
|
499
|
+
adapter,
|
|
500
|
+
transactional: true,
|
|
501
|
+
writes: {
|
|
502
|
+
create: async (data, ctx) => {
|
|
503
|
+
const order = await ctx.repository.create(data); // tx-bound
|
|
504
|
+
await outbox.store(event, { session: ctx.uow?.session }); // SAME transaction
|
|
505
|
+
return order;
|
|
506
|
+
},
|
|
507
|
+
},
|
|
508
|
+
});
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
- Hooks stay OUTSIDE the retry — before/after run once; only persistence re-runs.
|
|
512
|
+
- Transient conflicts re-run with jittered backoff; `VersionConflictError` surfaces (409), never retried.
|
|
513
|
+
- **Retry authority is the KIT's.** mongokit declares `transactionRetry: 'managed'` (its driver already retries internally) and is called exactly once; sqlitekit declares `'caller'` and gets the envelope's loop. Arc never stacks a second policy.
|
|
514
|
+
- **BOOT-FATAL** without `withTransaction`, and at REGISTRATION when the repository reports `capabilities.transactions !== true` (standalone Mongo, D1, unconfirmed topology). The capability is checked at registration, not at `defineResource()`, because that usually runs at module import — before `beforeBoot()` connects.
|
|
515
|
+
- `ctx.uow.session` is empty on connection-bound backends (SQLite); the tx-bound repo is the join point there.
|
|
516
|
+
|
|
456
517
|
## Events
|
|
457
518
|
|
|
458
519
|
CRUD events auto-emit: `{resource}.created` / `{resource}.updated` / `{resource}.deleted`. Manual publish:
|
|
@@ -464,13 +525,27 @@ await app.events.subscribe('order.*', async (event) => { … });
|
|
|
464
525
|
|
|
465
526
|
Transports: Memory · Redis Pub/Sub (fire-and-forget) · Redis Streams (durable, consumer groups, DLQ). Event types live in `@classytic/primitives/events` (`createEvent`, `createChildEvent`, `matchEventPattern`, …); arc re-exports the runtime `MemoryEventTransport` only.
|
|
466
527
|
|
|
467
|
-
**Outbox** (at-least-once via transactional outbox):
|
|
528
|
+
**Outbox** (at-least-once via transactional outbox) — prefer the MODULE, so the store is a slot other modules depend on rather than a value threaded by hand:
|
|
529
|
+
|
|
530
|
+
```typescript
|
|
531
|
+
createApp({ modules: [createOutboxModule({ store: repositoryAsOutboxStore(outboxRepo) })] });
|
|
532
|
+
// Dev: createOutboxModule({ store: new MemoryOutboxStore() })
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
The relay arm is `kind: 'relay'`, so `role: 'relay'` deployments drain it. It resolves the RAW transport, never the `fastify.events` facade (the facade fails open, which would acknowledge rows whose publish failed) — no transport is boot-fatal. **Fencing (2.34):** stores that support `claimPendingFenced` mint a token in the claim CAS; a relay that lost its lease mid-batch cannot ack or re-schedule a row a successor already owns. Feature-detected end to end.
|
|
536
|
+
|
|
537
|
+
**Durable webhooks (2.34)** — delivery survives crash and deploy, using the outbox machinery rather than a second queue:
|
|
468
538
|
|
|
469
539
|
```typescript
|
|
470
|
-
const
|
|
471
|
-
|
|
540
|
+
const store = repositoryAsOutboxStore(deliveryRepo);
|
|
541
|
+
createApp({
|
|
542
|
+
modules: [createDurableWebhookModule({ store })], // relay does the signed POST
|
|
543
|
+
plugins: async (f) => f.register(webhookPlugin, { durable: { store } }), // enqueue, don't POST
|
|
544
|
+
});
|
|
472
545
|
```
|
|
473
546
|
|
|
547
|
+
One row per (event × subscription), deterministic id so an at-least-once upstream enqueues each delivery exactly once. Transient failures (network/timeout/429/5xx) retry with backoff; 4xx dead-letters on the FIRST attempt. `durable` + `retry` together is a registration error.
|
|
548
|
+
|
|
474
549
|
Full event recipes (retry, DLQ, dual-publish warnings, idempotency keys) → [references/events.md](references/events.md).
|
|
475
550
|
|
|
476
551
|
## Hooks
|
|
@@ -652,6 +727,23 @@ await app.audit.custom('order', req.params.id, 'refund', { reason }, { user });
|
|
|
652
727
|
|
|
653
728
|
`@classytic/arc/usage` — `usagePlugin` decorates `fastify.usage` with per-actor, per-UTC-month counters (`record`/`summary`/`period`/`actorOf`; actor chain org → user → client → ip). Auto-tracks `api.requests` (default on) + `api.egress.bytes` (opt-in); recording is fail-safe (a throwing `UsageStore` never fails a request; `MemoryUsageStore` built in, Redis/kit backends are ~5 lines). Pair with `createApp({ rateLimit: { plan: { resolve, limits: { free: { max: 60 }, enterprise: false }, default: 'free' } } })` for per-plan ceilings — `false` = unlimited, unknown/throwing resolvers fall back to `default` then global `max`, and buckets follow the tenant key chain by default. Caveat: the limiter runs before route auth, so `resolve` sees the raw request.
|
|
654
729
|
|
|
730
|
+
## Runtime capability registry (2.34)
|
|
731
|
+
|
|
732
|
+
Under `runtime: 'distributed'`, subsystems holding process-local state must declare it — the end-of-boot audit FAILS the app on undeclared memory state, naming every violator:
|
|
733
|
+
|
|
734
|
+
```typescript
|
|
735
|
+
import { declareRuntimeCapability } from '@classytic/arc/utils';
|
|
736
|
+
|
|
737
|
+
declareRuntimeCapability(fastify, {
|
|
738
|
+
subsystem: 'billing.sequence-cache',
|
|
739
|
+
durability: 'memory', // 'memory' | 'shared'
|
|
740
|
+
accepted: true, // per-process BY DESIGN (logged, never fatal)
|
|
741
|
+
detail: 'short-TTL cache; correctness from TTL, not shared state',
|
|
742
|
+
});
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
`createApp`'s constructor-time guard only sees what it is passed; state a host wires inside `plugins()` was invisible to it and lived on a checklist. This makes the checklist enforcement. Arc's webhooks plugin declares its default in-memory store.
|
|
746
|
+
|
|
655
747
|
## Adapters
|
|
656
748
|
|
|
657
749
|
Cross-framework adapter contract lives in `@classytic/repo-core/adapter`. Every kit-specific adapter ships from its kit's `/adapter` subpath; arc itself has zero kit-bound adapters.
|
|
@@ -126,8 +126,27 @@ import {
|
|
|
126
126
|
import { tracingPlugin } from '@classytic/arc/plugins/tracing';
|
|
127
127
|
import { auditPlugin } from '@classytic/arc/audit';
|
|
128
128
|
import { idempotencyPlugin } from '@classytic/arc/idempotency';
|
|
129
|
+
// Runtime capability registry (2.34) — declare process-local state so a
|
|
130
|
+
// `runtime: 'distributed'` boot fails on undeclared memory state:
|
|
131
|
+
import { declareRuntimeCapability } from '@classytic/arc/utils';
|
|
129
132
|
```
|
|
130
133
|
|
|
134
|
+
**Idempotency store — the one schema mistake that matters.** Backing the store
|
|
135
|
+
with a repository requires the key path to survive the filter. A Mongoose
|
|
136
|
+
schema with NO declared paths under a global `strictQuery: true` has EVERY
|
|
137
|
+
filter key stripped, so `getOne({ _id: key })` becomes `getOne({})`: one row
|
|
138
|
+
absorbs every key and responses replay across keys AND users. Declare the path
|
|
139
|
+
and pin the option on the schema:
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
new Schema({ _id: String }, { strict: false, strictQuery: false, timestamps: false })
|
|
143
|
+
// NOT `new Schema({}, { _id: false, strict: false })`
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The plugin's boot self-check (default on, `selfCheck: false` to disable) probes
|
|
147
|
+
for exactly this and refuses to register; the adapter also throws
|
|
148
|
+
`IdempotencyStoreMisconfiguredError` on any cross-key read at runtime.
|
|
149
|
+
|
|
131
150
|
## Integrations
|
|
132
151
|
|
|
133
152
|
```typescript
|
|
@@ -292,7 +292,7 @@ field masking. Client = plain `EventSource` with `?token=`. No replay — reconn
|
|
|
292
292
|
refetches the list. Choosing: per-user resource views → realtime; bidirectional/geo
|
|
293
293
|
→ `integrations/websocket` (its CRUD bridge is org-coarse — never expose
|
|
294
294
|
row-permissioned resources through it); event firehose → sse. Massive fan-out
|
|
295
|
-
(viral feeds, live scores) → publish once to
|
|
295
|
+
(viral feeds, live scores) → publish once to a dedicated edge fan-out layer
|
|
296
296
|
via `app.events.subscribe(...)`; full tiering guide: docs/production-ops/realtime.mdx.
|
|
297
297
|
|
|
298
298
|
```typescript
|
|
@@ -618,7 +618,7 @@ presets: [bulkPreset({ operations: ['createMany', 'updateMany'], maxCreateItems:
|
|
|
618
618
|
## Compensating Transaction
|
|
619
619
|
|
|
620
620
|
In-process rollback primitive — runs steps in order, compensates in reverse on failure.
|
|
621
|
-
For distributed sagas across services, use
|
|
621
|
+
For distributed sagas across services, use `@classytic/streamline` or a dedicated workflow orchestrator.
|
|
622
622
|
|
|
623
623
|
```typescript
|
|
624
624
|
import { withCompensation } from '@classytic/arc/utils';
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
|
|
2
|
-
import { c as getOrgId, g as getUserId, x as isMember } from "./types-DXYX7dIR.mjs";
|
|
3
|
-
//#region src/scope/projection.ts
|
|
4
|
-
/**
|
|
5
|
-
* Compute the request-scope projection. Returns `undefined` when no
|
|
6
|
-
* scope is attached (public / unscoped routes) so hosts can idiomatically
|
|
7
|
-
* write `ctx.scope?.organizationId` without a double-null check.
|
|
8
|
-
*/
|
|
9
|
-
function buildRequestScopeProjection(scope) {
|
|
10
|
-
if (!scope) return void 0;
|
|
11
|
-
return {
|
|
12
|
-
organizationId: getOrgId(scope),
|
|
13
|
-
userId: getUserId(scope),
|
|
14
|
-
orgRoles: isMember(scope) ? scope.orgRoles : void 0
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
//#endregion
|
|
18
|
-
export { buildRequestScopeProjection as t };
|