@classytic/arc 2.41.1 → 2.44.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/{EventTransport-CbUKDzZZ.d.mts → EventTransport-CiicKz2Z.d.mts} +1 -1
- package/dist/{EventTransport-DSqD_Xsg.mjs → EventTransport-DZWDsaPa.mjs} +22 -17
- package/dist/{HookSystem-CMF94SEA.mjs → HookSystem-yjEgn7Cm.mjs} +2 -2
- package/dist/{QueryCache-DFA-QrU9.d.mts → QueryCache--5uAuYPW.d.mts} +7 -3
- package/dist/{ResourceRegistry-MGpXoxHZ.mjs → ResourceRegistry-DJxHUpE4.mjs} +44 -13
- package/dist/acquire-BozJ-9yt.mjs +35 -0
- package/dist/actionPermissions-5N04zBL4.mjs +772 -0
- package/dist/audit/index.d.mts +46 -8
- package/dist/audit/index.mjs +48 -26
- package/dist/auth/audit.d.mts +8 -8
- package/dist/auth/audit.mjs +1 -1
- package/dist/auth/index.d.mts +46 -16
- package/dist/auth/index.mjs +134 -156
- package/dist/auth/redis-session.d.mts +4 -5
- package/dist/auth/redis-session.mjs +1 -1
- package/dist/{authorizationDecision-DawKGoXb.mjs → authorizationDecision-wX3SA9w_.mjs} +7 -102
- package/dist/{base-CxrV1LmG.d.mts → base-CZyixEQR.d.mts} +27 -5
- package/dist/boundedMap-DWiKW7lP.mjs +57 -0
- package/dist/{buildHandler-CvxKOc0m.mjs → buildHandler-Bswu_vNb.mjs} +4 -4
- package/dist/cache/index.d.mts +31 -43
- package/dist/cache/index.mjs +4 -4
- package/dist/{caching-DbCBxlgw.mjs → caching-Drp68DIS.mjs} +3 -3
- package/dist/claimed-DYvQoZLv.mjs +8 -0
- package/dist/cleanup/index.d.mts +18 -22
- package/dist/cleanup/index.mjs +27 -73
- package/dist/cli/commands/describe.d.mts +7 -5
- package/dist/cli/commands/describe.mjs +7 -4
- package/dist/cli/commands/docs.d.mts +2 -3
- package/dist/cli/commands/docs.mjs +3 -3
- package/dist/cli/commands/doctor.d.mts +2 -3
- package/dist/cli/commands/doctor.mjs +1 -1
- package/dist/cli/commands/generate.mjs +2 -3
- package/dist/cli/commands/init.mjs +2 -3
- package/dist/cli/commands/introspect.d.mts +2 -3
- package/dist/cli/commands/introspect.mjs +2 -2
- package/dist/cli/index.mjs +3 -3
- package/dist/{constants-D5Ubn1fe.mjs → constants-B2QHb6u6.mjs} +4 -2
- package/dist/context/index.d.mts +11 -14
- package/dist/context/index.mjs +18 -38
- package/dist/core/index.d.mts +3 -3
- package/dist/core/index.mjs +8 -8
- package/dist/{core-5lazhva9.mjs → core-COcqo0Cp.mjs} +15 -5
- package/dist/{createActionRouter-DNqoaK81.mjs → createActionRouter-zG13rpPJ.mjs} +97 -39
- package/dist/{createAggregationRouter-BcbQJf10.mjs → createAggregationRouter-CWRz96Vr.mjs} +11 -8
- package/dist/{preloadResources-f3boenVZ.mjs → createApp-BGLYtErt.mjs} +305 -394
- package/dist/{createMcpServer-CbDWkZ1T.d.mts → createMcpServer-DSztofa9.d.mts} +1 -1
- package/dist/{defineAggregation-D_eJjm5A.mjs → defineAggregation--3xguLkk.mjs} +1 -1
- package/dist/{defineResource-DxkMTjRn.mjs → defineResource-gUp9ug66.mjs} +118 -1024
- package/dist/discovery/index.d.mts +6 -7
- package/dist/discovery/index.mjs +1 -1
- package/dist/docs/index.d.mts +11 -5
- package/dist/docs/index.mjs +4 -4
- package/dist/{elevation-CkvG0LG2.mjs → elevation-BG4gnMsJ.mjs} +41 -12
- package/dist/{elevation-BXCfVcNG.d.mts → elevation-BW2J3tNj.d.mts} +1 -2
- package/dist/encryption/index.d.mts +5 -5
- package/dist/encryption/index.mjs +3 -3
- package/dist/{errorHandler-D1GHKGlV.mjs → errorHandler-COHw3N1b.mjs} +26 -5
- package/dist/{errors-BH7YU_9O.mjs → errors-CW4anJBy.mjs} +58 -23
- package/dist/{errors-BGdVwP25.d.mts → errors-JYc9vwqE.d.mts} +9 -0
- package/dist/{eventPlugin-B52abJ8W.d.mts → eventPlugin-BtmA4-3P.d.mts} +65 -9
- package/dist/{eventPlugin-zZY-unhr.mjs → eventPlugin-BweHAVws.mjs} +82 -21
- package/dist/{subscribe-helpers-DatDkcuG.mjs → eventTypes-N4-omQFR.mjs} +151 -17
- package/dist/events/index.d.mts +43 -18
- package/dist/events/index.mjs +49 -53
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis-stream-entry.mjs +139 -157
- package/dist/events/transports/redis.d.mts +5 -6
- package/dist/events/transports/redis.mjs +2 -2
- package/dist/factory/index.d.mts +42 -27
- package/dist/factory/index.mjs +213 -32
- package/dist/{fastify-augmentation-Cq2nHVaW.d.mts → fastify-augmentation-DRlCIWE9.d.mts} +11 -25
- package/dist/{fields-BHrkoF5y.mjs → fields-A5crhsJb.mjs} +1 -1
- package/dist/{fields-I_EeRWND.d.mts → fields-BBSpf8pS.d.mts} +1 -1
- package/dist/filter-merge-DGM-GQ1J.mjs +99 -0
- package/dist/{generate-BLRf2m3y.mjs → generate-BXKo2Gc8.mjs} +2 -2
- package/dist/{headers-BIXWKrzQ.mjs → headers-DKZQKL-Z.mjs} +2 -2
- package/dist/health-BYAwA6YS.mjs +22 -0
- package/dist/{health-ZRHeDHXH.mjs → health-CrqUp3sz.mjs} +115 -55
- package/dist/hooks/index.d.mts +2 -2
- package/dist/hooks/index.mjs +2 -3
- package/dist/idempotency/index.d.mts +36 -10
- package/dist/idempotency/index.mjs +230 -111
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/idempotency/redis.mjs +77 -12
- package/dist/{index-D4u76eQW.d.mts → index-Beg3aNnK.d.mts} +23 -101
- package/dist/{preloadResources-CjS2OfpU.d.mts → index-BkV55WlV.d.mts} +37 -38
- package/dist/{index-BHdZD8zK.d.mts → index-Bxriq3so.d.mts} +84 -21
- package/dist/index-CUJvoyw3.d.mts +510 -0
- package/dist/{index-CbJiYrfv.d.mts → index-Chgz3d0i.d.mts} +1 -1
- package/dist/{index-DHbyPo5j.d.mts → index-WH7xgvxS.d.mts} +304 -254
- package/dist/index.d.mts +9 -9
- package/dist/index.mjs +11 -11
- package/dist/{init-CpLkjU18.mjs → init-BPzK5Lnr.mjs} +1 -1
- package/dist/integrations/event-gateway.d.mts +11 -7
- package/dist/integrations/event-gateway.mjs +4 -4
- package/dist/integrations/index.d.mts +3 -3
- package/dist/integrations/index.mjs +1 -1
- package/dist/integrations/jobs/index.d.mts +1 -1
- package/dist/integrations/jobs/index.mjs +18 -5
- package/dist/integrations/mcp/index.d.mts +102 -89
- package/dist/integrations/mcp/index.mjs +19 -4
- package/dist/integrations/mcp/testing.d.mts +8 -9
- package/dist/integrations/mcp/testing.mjs +2 -2
- package/dist/integrations/streamline.d.mts +85 -144
- package/dist/integrations/streamline.mjs +131 -55
- package/dist/integrations/webhooks.d.mts +83 -143
- package/dist/integrations/webhooks.mjs +36 -80
- package/dist/integrations/websocket-pushref-redis.d.mts +5 -6
- package/dist/integrations/websocket-pushref-redis.mjs +1 -1
- package/dist/integrations/websocket-redis.d.mts +5 -6
- package/dist/integrations/websocket-redis.mjs +1 -1
- package/dist/integrations/websocket.d.mts +3 -3
- package/dist/integrations/websocket.mjs +2 -2
- package/dist/{interface-DEWNOMza.d.mts → interface-JJzwH4Ro.d.mts} +34 -2
- package/dist/{jsonBody-ELR9lfeU.mjs → jsonBody-YIq-vGLv.mjs} +2 -2
- package/dist/{keys-cpZCtcIE.mjs → keys-CpoiZ8hU.mjs} +7 -18
- package/dist/{loadResources-BPfWiI5s.mjs → loadResources-6jO52-RR.mjs} +3 -3
- package/dist/{loadResourcesFromEntry-ixtfL3J2.mjs → loadResourcesFromEntry-MP8xEppu.mjs} +2 -2
- package/dist/logger/index.d.mts +9 -17
- package/dist/logger/index.mjs +2 -153
- package/dist/logger-D4V1zGLI.mjs +160 -0
- package/dist/{mcpPlugin-BX5PujI0.mjs → mcpPlugin-srPc7ItN.mjs} +446 -170
- package/dist/{memory-Iotz0cCx.mjs → memory-CTa5pOCW.mjs} +36 -34
- package/dist/{metrics-NMsmpRmY.mjs → metrics-DsZrvnpB.mjs} +39 -72
- package/dist/middleware/index.d.mts +5 -5
- package/dist/middleware/index.mjs +3 -3
- package/dist/migrations/index.d.mts +13 -13
- package/dist/migrations/index.mjs +2 -2
- package/dist/{module-DpLJG2_N.mjs → module--L0iBIZz.mjs} +8 -8
- package/dist/mongodb-memory-server-CHhYSq5y.mjs +35539 -0
- package/dist/mongoose-CYJCLyi-.mjs +67451 -0
- package/dist/multiTenant-CAtYlW6H.d.mts +104 -0
- package/dist/{multipartBody-DtRWM6_U.mjs → multipartBody-Cc7eZ9cq.mjs} +46 -7
- package/dist/node-D8UZv_8c.mjs +41236 -0
- package/dist/{openapi-CmFf3yq_.mjs → openapi-CMegfsm8.mjs} +48 -10
- package/dist/outbox-admin/index.d.mts +5 -5
- package/dist/outbox-admin/index.mjs +6 -18
- package/dist/{outbox-module-D2z5WkDY.mjs → outbox-module-Ryk270jd.mjs} +203 -33
- package/dist/{outbox-module-BHdUnuuK.d.mts → outbox-module-gZCHoE4H.d.mts} +79 -6
- package/dist/permissions/index.d.mts +5 -4
- package/dist/permissions/index.mjs +8 -6
- package/dist/{permissions-D8TBH44E.mjs → permissions-C5ijIz5Q.mjs} +149 -33
- package/dist/{pipe-FMWNheSO.mjs → pipe-D81zMtWs.mjs} +2 -2
- package/dist/pipeline/index.d.mts +7 -7
- package/dist/pipeline/index.mjs +2 -2
- package/dist/plan-CJGMKoui.mjs +565 -0
- package/dist/{BaseController-CYEwjyjN.mjs → plugin-DALd9dcF.mjs} +1269 -346
- package/dist/plugins/index.d.mts +17 -14
- package/dist/plugins/index.mjs +44 -22
- package/dist/plugins/response-cache.d.mts +5 -6
- package/dist/plugins/response-cache.mjs +8 -14
- package/dist/plugins/tracing-entry.mjs +2 -2
- package/dist/{pluralize-CXWZIzTv.mjs → pluralize-COUNYo3d.mjs} +1 -1
- package/dist/presets/filesUpload.d.mts +8 -8
- package/dist/presets/filesUpload.mjs +5 -5
- package/dist/presets/index.d.mts +35 -40
- package/dist/presets/index.mjs +4 -4
- package/dist/presets/multiTenant.d.mts +2 -107
- package/dist/presets/multiTenant.mjs +22 -162
- package/dist/presets/search.d.mts +9 -10
- package/dist/presets/search.mjs +2 -2
- package/dist/{presets-ZJSPgmT2.mjs → presets-CONf2Qem.mjs} +99 -107
- package/dist/{projection-BzIgzoKZ.mjs → projection-wFoLqdss.mjs} +2 -2
- package/dist/{pushref-registry-Dov9l4qE.d.mts → pushref-registry-UxCkoA4C.d.mts} +1 -1
- package/dist/{queryCachePlugin-DZHPOm9p.mjs → queryCachePlugin-BATECpyh.mjs} +12 -14
- package/dist/{queryCachePlugin-BzqxconG.d.mts → queryCachePlugin-C2lZjTxk.d.mts} +1 -1
- package/dist/{rateLimitKey-BvOvcBDi.mjs → rateLimitKey-DVEZ_UpV.mjs} +1 -1
- package/dist/{realtime-8tIQWZz4.mjs → realtime-xyubMKSB.mjs} +25 -21
- package/dist/{redis-Bzi1y3F9.d.mts → redis-BDgv9Glw.d.mts} +17 -24
- package/dist/redis-stream-BMk-bpQS.d.mts +219 -0
- package/dist/redisShapes-CQksY67q.d.mts +55 -0
- package/dist/registry/index.d.mts +15 -10
- package/dist/registry/index.mjs +4 -4
- package/dist/{registry-DNkgGQcK.mjs → registry-Bdzg-hdm.mjs} +13 -10
- package/dist/{renewingLease-yF8BdW4b.mjs → renewingLease-BFJxGPuh.mjs} +1 -1
- package/dist/{replyHelpers-CNdvMfM4.mjs → replyHelpers-Bnc6lJyy.mjs} +2 -2
- package/dist/{requestContext-cDkAUr-P.mjs → requestContext-C10UeFe5.mjs} +1 -1
- package/dist/requirement-Bu50QALH.mjs +35 -0
- package/dist/requirement-CbiLdQ1n.d.mts +22 -0
- package/dist/resourceRateLimit-Wf6d6FL9.d.mts +30 -0
- package/dist/resourceRateLimit-urWPJxrt.mjs +180 -0
- package/dist/rolldown-runtime-MYrLNGnq.mjs +45 -0
- package/dist/routeValidator-DHtpzrzk.mjs +70 -0
- package/dist/{runtimeCapabilities-CkhS6jn6.mjs → runtimeCapabilities-DIMKMV2G.mjs} +1 -1
- package/dist/{schedules-j6uXXAeJ.mjs → schedules-CKTs5ys8.mjs} +46 -37
- package/dist/{schemaConverter-BVA7cFRG.mjs → schemaConverter-BVjkQ5DD.mjs} +2 -2
- package/dist/{schemaIR-CTvPDoPB.mjs → schemaIR-BA0Hb21Y.mjs} +2 -2
- package/dist/schemas/index.d.mts +20 -10
- package/dist/schemas/index.mjs +8 -3
- package/dist/scim/index.d.mts +13 -13
- package/dist/scim/index.mjs +2 -2
- package/dist/scope/index.d.mts +4 -4
- package/dist/scope/index.mjs +6 -6
- package/dist/{scope-BUi1xV1I.mjs → scope-DINaj7Ax.mjs} +4 -4
- package/dist/shutdown-LpLMH8T1.mjs +59 -0
- package/dist/{simpleEqualityMatcher-C9bzq2gO.mjs → simpleEqualityMatcher-DbwIM1f1.mjs} +1 -1
- package/dist/{sse-BeqVKQKu.mjs → sse-BzJFPX_1.mjs} +11 -15
- package/dist/{sseStream-Ppzo-WUH.mjs → sseStream-DQChzGTs.mjs} +2 -2
- package/dist/{store-helpers-dW71XVWL.mjs → store-helpers-Coj9RhOZ.mjs} +1 -1
- package/dist/{streaming-IcRFjWQU.mjs → streaming-JzB5CAga.mjs} +1 -1
- package/dist/subscriberIdentity-DeyppIif.mjs +28 -0
- package/dist/tenancy-DxV8OuX2.mjs +43 -0
- package/dist/tenantPreparation-CBvvAcAj.mjs +67 -0
- package/dist/testing/cleanupStoreContract.d.mts +4 -5
- package/dist/testing/cleanupStoreContract.mjs +1 -1
- package/dist/testing/index.d.mts +215 -197
- package/dist/testing/index.mjs +289 -214
- package/dist/testing/outboxStoreContract.d.mts +4 -5
- package/dist/testing/outboxStoreContract.mjs +137 -2
- package/dist/testing/requiredPorts.d.mts +16 -0
- package/dist/testing/requiredPorts.mjs +65 -0
- package/dist/testing/storageContract.d.mts +4 -5
- package/dist/testing/storageContract.mjs +1 -1
- package/dist/timing-CntavTlR.mjs +46 -0
- package/dist/{transactionContext-CPbdlnVw.mjs → transactionContext-orvnGu4F.mjs} +1 -1
- package/dist/{typeGuards-BLjPgVBm.mjs → typeGuards-kEaP_WmO.mjs} +1 -1
- package/dist/types/index.d.mts +4 -4
- package/dist/types/index.mjs +1 -1
- package/dist/types/storage.mjs +1 -1
- package/dist/{types-DfVDvkdP.d.mts → types-BJ-2XqVF.d.mts} +189 -204
- package/dist/{types-CWQn9-IC.d.mts → types-D3Ixsh00.d.mts} +22 -9
- package/dist/{types-CgenB1gv.mjs → types-fvO6Ovzx.mjs} +4 -4
- package/dist/usage/index.d.mts +5 -6
- package/dist/usage/index.mjs +5 -5
- package/dist/{userHelpers-ChRvkuSZ.mjs → userHelpers-C76zD5pa.mjs} +1 -1
- package/dist/utils/index.d.mts +125 -264
- package/dist/utils/index.mjs +13 -12
- package/dist/{utils-CxcctrAh.mjs → utils-BpkVZ8rB.mjs} +315 -404
- package/dist/{validate-DrYWnOzI.mjs → validate-CWp-lsrm.mjs} +6 -14
- package/dist/{versioning-D6JIK8Tk.d.mts → versioning-Bsb51gGT.d.mts} +28 -13
- package/dist/{versioning-DKkT4hNJ.mjs → versioning-CHhL9P3o.mjs} +4 -4
- package/dist/{websocket-BOXVggMf.d.mts → websocket-Cs4awVyD.d.mts} +1 -1
- package/dist/{workScope-CxKqoIFn.mjs → workScope-n9a7d_lZ.mjs} +2 -2
- package/package.json +57 -59
- package/skills/arc/SKILL.md +13 -4
- package/skills/arc/references/auth.md +8 -5
- package/skills/arc/references/integrations.md +1 -1
- package/skills/arc/references/mcp.md +8 -6
- package/skills/arc/references/multi-tenancy.md +19 -14
- package/skills/arc/references/production.md +27 -10
- package/dist/actionPermissions-BoPGQ5-4.mjs +0 -350
- package/dist/index-CFfLKMH4.d.mts +0 -290
- package/dist/interface-YzIbF7Ii.mjs +0 -17
- package/dist/redis-stream-BPKscsTB.d.mts +0 -260
- package/dist/registerRoute-Bsnk6NiZ.mjs +0 -364
- package/dist/rolldown-runtime-eysyzFAF.mjs +0 -15
- package/dist/sync/changelog.d.mts +0 -3
- package/dist/sync/changelog.mjs +0 -3
|
@@ -1,165 +1,27 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import "../constants-
|
|
3
|
-
import {
|
|
1
|
+
/*! @classytic/arc v2.44.0 | MIT | https://classytic.com */
|
|
2
|
+
import "../constants-B2QHb6u6.mjs";
|
|
3
|
+
import { t as ArcError } from "../errors-CW4anJBy.mjs";
|
|
4
|
+
import { u as getRequestScope } from "../types-fvO6Ovzx.mjs";
|
|
5
|
+
import { i as tagTenantPreparation, t as applyTenantPreparation } from "../tenantPreparation-CBvvAcAj.mjs";
|
|
4
6
|
//#region src/presets/multiTenant.ts
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
function resolveSpec(scope, spec) {
|
|
10
|
-
if ("contextKey" in spec) return getScopeContext(scope, spec.contextKey);
|
|
11
|
-
if (spec.type === "org") return getOrgId(scope);
|
|
12
|
-
if (spec.type === "team") return getTeamId(scope);
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Stash the resolved tenant field map on the request so `BaseController`
|
|
16
|
-
* can forward it to the repository layer as top-level options. Needed by
|
|
17
|
-
* plugin-scoped repos (mongokit's `multiTenantPlugin`) that read tenant
|
|
18
|
-
* from `context.<field>` rather than from filter/query/data stamping.
|
|
19
|
-
*/
|
|
20
|
-
function stashTenantFields(request, resolved) {
|
|
21
|
-
if (Object.keys(resolved).length === 0) return;
|
|
22
|
-
const target = request;
|
|
23
|
-
target._tenantFields = {
|
|
24
|
-
...target._tenantFields ?? {},
|
|
25
|
-
...resolved
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
/** Resolve every spec — returns the partial map of fields that have a value. */
|
|
29
|
-
function resolveAll(scope, specs) {
|
|
30
|
-
const resolved = {};
|
|
31
|
-
const missing = [];
|
|
32
|
-
for (const spec of specs) {
|
|
33
|
-
const value = resolveSpec(scope, spec);
|
|
34
|
-
if (value !== void 0) resolved[spec.field] = value;
|
|
35
|
-
else missing.push(spec.field);
|
|
36
|
-
}
|
|
37
|
-
return {
|
|
38
|
-
resolved,
|
|
39
|
-
missing
|
|
7
|
+
function createTenantMiddleware(specs, mode) {
|
|
8
|
+
const preparation = {
|
|
9
|
+
specs,
|
|
10
|
+
mode
|
|
40
11
|
};
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
function createTenantFilter(specs) {
|
|
48
|
-
return async (request, reply) => {
|
|
49
|
-
const scope = getRequestScope(request);
|
|
50
|
-
if (isElevated(scope)) {
|
|
51
|
-
const { resolved } = resolveAll(scope, specs);
|
|
52
|
-
if (Object.keys(resolved).length > 0) {
|
|
53
|
-
request._policyFilters = {
|
|
54
|
-
...request._policyFilters ?? {},
|
|
55
|
-
...resolved
|
|
56
|
-
};
|
|
57
|
-
stashTenantFields(request, resolved);
|
|
58
|
-
}
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
if (hasOrgAccess(scope)) {
|
|
62
|
-
const { resolved, missing } = resolveAll(scope, specs);
|
|
63
|
-
if (missing.length === 0) {
|
|
64
|
-
request._policyFilters = {
|
|
65
|
-
...request._policyFilters ?? {},
|
|
66
|
-
...resolved
|
|
67
|
-
};
|
|
68
|
-
stashTenantFields(request, resolved);
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
reply.code(403).send({
|
|
12
|
+
const middleware = async (request, reply) => {
|
|
13
|
+
try {
|
|
14
|
+
applyTenantPreparation(request, request.body, getRequestScope(request), preparation);
|
|
15
|
+
} catch (error) {
|
|
16
|
+
if (!(error instanceof ArcError)) throw error;
|
|
17
|
+
reply.code(error.status).send({
|
|
72
18
|
success: false,
|
|
73
|
-
error: "Forbidden",
|
|
74
|
-
message:
|
|
19
|
+
error: error.status === 401 ? "Unauthorized" : "Forbidden",
|
|
20
|
+
message: error.message
|
|
75
21
|
});
|
|
76
|
-
return;
|
|
77
22
|
}
|
|
78
|
-
if (scope.kind === "public") {
|
|
79
|
-
reply.code(401).send({
|
|
80
|
-
success: false,
|
|
81
|
-
error: "Unauthorized",
|
|
82
|
-
message: "Authentication required for multi-tenant resources"
|
|
83
|
-
});
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
reply.code(403).send({
|
|
87
|
-
success: false,
|
|
88
|
-
error: "Forbidden",
|
|
89
|
-
message: "Organization context required for this operation"
|
|
90
|
-
});
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Create flexible tenant filter middleware (allowPublic).
|
|
95
|
-
* Same policy as the strict variant for authenticated callers, but
|
|
96
|
-
* allows public/unauthenticated requests through without filtering.
|
|
97
|
-
*/
|
|
98
|
-
function createFlexibleTenantFilter(specs) {
|
|
99
|
-
return async (request, reply) => {
|
|
100
|
-
const scope = getRequestScope(request);
|
|
101
|
-
if (isElevated(scope)) {
|
|
102
|
-
const { resolved } = resolveAll(scope, specs);
|
|
103
|
-
if (Object.keys(resolved).length > 0) {
|
|
104
|
-
request._policyFilters = {
|
|
105
|
-
...request._policyFilters ?? {},
|
|
106
|
-
...resolved
|
|
107
|
-
};
|
|
108
|
-
stashTenantFields(request, resolved);
|
|
109
|
-
}
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
if (hasOrgAccess(scope)) {
|
|
113
|
-
const { resolved, missing } = resolveAll(scope, specs);
|
|
114
|
-
if (missing.length === 0) {
|
|
115
|
-
request._policyFilters = {
|
|
116
|
-
...request._policyFilters ?? {},
|
|
117
|
-
...resolved
|
|
118
|
-
};
|
|
119
|
-
stashTenantFields(request, resolved);
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
reply.code(403).send({
|
|
123
|
-
success: false,
|
|
124
|
-
error: "Forbidden",
|
|
125
|
-
message: `Tenant context incomplete — missing: ${missing.join(", ")}`
|
|
126
|
-
});
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* Create tenant injection middleware.
|
|
133
|
-
* Walks the configured tenant fields and writes each into the request body.
|
|
134
|
-
* Fails closed if any required dimension is missing for non-elevated callers.
|
|
135
|
-
*
|
|
136
|
-
* Also stashes the resolved fields on `request._tenantFields` so
|
|
137
|
-
* `BaseController.tenantRepoOptions()` can forward them to the repo layer
|
|
138
|
-
* as top-level options — needed by plugin-scoped repos like mongokit's
|
|
139
|
-
* `multiTenantPlugin`, which reads tenant from `context.<field>` rather
|
|
140
|
-
* than from `data.<field>`. Without this forwarding, multi-field preset
|
|
141
|
-
* writes (update/delete) work only when the plugin's `allowDataInjection`
|
|
142
|
-
* fallback covers the operation's policy key, which is write-only.
|
|
143
|
-
*/
|
|
144
|
-
function createTenantInjection(specs) {
|
|
145
|
-
return async (request, reply) => {
|
|
146
|
-
const scope = getRequestScope(request);
|
|
147
|
-
if (isElevated(scope) && !getOrgId(scope)) return;
|
|
148
|
-
const { resolved, missing } = resolveAll(scope, specs);
|
|
149
|
-
if (missing.length > 0) {
|
|
150
|
-
reply.code(403).send({
|
|
151
|
-
success: false,
|
|
152
|
-
error: "Forbidden",
|
|
153
|
-
message: `Tenant context incomplete — missing: ${missing.join(", ")}`
|
|
154
|
-
});
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
if (request.body) Object.assign(request.body, resolved);
|
|
158
|
-
request._tenantFields = {
|
|
159
|
-
...request._tenantFields ?? {},
|
|
160
|
-
...resolved
|
|
161
|
-
};
|
|
162
23
|
};
|
|
24
|
+
return tagTenantPreparation(middleware, preparation);
|
|
163
25
|
}
|
|
164
26
|
function multiTenantPreset(options = {}) {
|
|
165
27
|
const { tenantField, tenantFields, allowPublic = [], crossTenant = [] } = options;
|
|
@@ -169,9 +31,9 @@ function multiTenantPreset(options = {}) {
|
|
|
169
31
|
type: "org"
|
|
170
32
|
}];
|
|
171
33
|
if (specs.length === 0) throw new Error("multiTenantPreset: `tenantFields` must contain at least one entry");
|
|
172
|
-
const strictTenantFilter =
|
|
173
|
-
const flexibleTenantFilter =
|
|
174
|
-
const tenantInjection =
|
|
34
|
+
const strictTenantFilter = createTenantMiddleware(specs, "strict");
|
|
35
|
+
const flexibleTenantFilter = createTenantMiddleware(specs, "flexible");
|
|
36
|
+
const tenantInjection = createTenantMiddleware(specs, "inject");
|
|
175
37
|
const getFilter = (route) => allowPublic.includes(route) ? flexibleTenantFilter : strictTenantFilter;
|
|
176
38
|
/**
|
|
177
39
|
* A cross-tenant read MARKS the request rather than simply skipping the filter.
|
|
@@ -187,9 +49,7 @@ function multiTenantPreset(options = {}) {
|
|
|
187
49
|
* repository layer needs no change of its own — kits already accept `bypassTenant`, which is the
|
|
188
50
|
* same door elevated cross-tenant reads have always used.
|
|
189
51
|
*/
|
|
190
|
-
const markCrossTenantRead =
|
|
191
|
-
request._crossTenantRead = true;
|
|
192
|
-
};
|
|
52
|
+
const markCrossTenantRead = createTenantMiddleware(specs, "crossTenant");
|
|
193
53
|
const readMiddleware = (route) => crossTenant.includes(route) ? [markCrossTenantRead] : [getFilter(route)];
|
|
194
54
|
const fieldRules = {};
|
|
195
55
|
for (const spec of specs) fieldRules[spec.field] = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
|
-
import { l as PermissionCheck } from "../base-
|
|
3
|
-
import {
|
|
2
|
+
import { l as PermissionCheck } from "../base-CZyixEQR.mjs";
|
|
3
|
+
import { Dt as RouteMcpConfig, Et as RouteDefinition, Ln as ControllerHandler, W as PresetResult } from "../index-WH7xgvxS.mjs";
|
|
4
4
|
//#region src/presets/search.d.ts
|
|
5
5
|
/**
|
|
6
6
|
* Search Preset — backend-agnostic search / vector / embed routes
|
|
@@ -46,7 +46,7 @@ import { At as RouteDefinition, Y as PresetResult, jn as ControllerHandler, jt a
|
|
|
46
46
|
* kit happens to ship these methods, without forcing every repo to declare
|
|
47
47
|
* them.
|
|
48
48
|
*/
|
|
49
|
-
interface SearchableRepository {
|
|
49
|
+
export interface SearchableRepository {
|
|
50
50
|
search?(query: unknown, options?: unknown): Promise<unknown>;
|
|
51
51
|
searchSimilar?(query: unknown, options?: unknown): Promise<unknown>;
|
|
52
52
|
embed?(input: unknown): Promise<number[]>;
|
|
@@ -56,8 +56,8 @@ interface SearchableRepository {
|
|
|
56
56
|
* non-raw route handler) and returns either the raw result (wrapped into
|
|
57
57
|
* `{ success: true, data }` by arc) or an explicit `IControllerResponse`.
|
|
58
58
|
*/
|
|
59
|
-
type SearchHandler = ControllerHandler;
|
|
60
|
-
interface SearchRouteConfig {
|
|
59
|
+
export type SearchHandler = ControllerHandler;
|
|
60
|
+
export interface SearchRouteConfig {
|
|
61
61
|
/**
|
|
62
62
|
* User-supplied handler. When omitted, the preset auto-synthesises a handler
|
|
63
63
|
* from `options.repository` (calling `repo.search` / `repo.searchSimilar` /
|
|
@@ -95,8 +95,8 @@ interface SearchRouteConfig {
|
|
|
95
95
|
* - `true` → mount with defaults, auto-wire from `repository`
|
|
96
96
|
* - `SearchRouteConfig` → explicit config (and optional handler override)
|
|
97
97
|
*/
|
|
98
|
-
type SearchSection = true | SearchRouteConfig;
|
|
99
|
-
interface SearchPresetOptions {
|
|
98
|
+
export type SearchSection = true | SearchRouteConfig;
|
|
99
|
+
export interface SearchPresetOptions {
|
|
100
100
|
/**
|
|
101
101
|
* Repository exposing `search`/`searchSimilar`/`embed`. When provided,
|
|
102
102
|
* any section without an explicit `handler` is auto-wired to the matching
|
|
@@ -135,6 +135,5 @@ interface SearchPresetOptions {
|
|
|
135
135
|
* The preset itself stays DB-agnostic: nothing is imported from mongokit —
|
|
136
136
|
* it only feature-detects the optional methods on whatever repo you pass.
|
|
137
137
|
*/
|
|
138
|
-
declare function searchPreset(options?: SearchPresetOptions): PresetResult;
|
|
139
|
-
//#endregion
|
|
140
|
-
export { SearchHandler, SearchPresetOptions, SearchRouteConfig, SearchSection, SearchableRepository, searchPreset };
|
|
138
|
+
export declare function searchPreset(options?: SearchPresetOptions): PresetResult;
|
|
139
|
+
//#endregion
|
package/dist/presets/search.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { B as requireAuth, F as allowPublic } from "../permissions-
|
|
1
|
+
/*! @classytic/arc v2.44.0 | MIT | https://classytic.com */
|
|
2
|
+
import { B as requireAuth, F as allowPublic } from "../permissions-C5ijIz5Q.mjs";
|
|
3
3
|
//#region src/presets/search.ts
|
|
4
4
|
const BUILTINS = [
|
|
5
5
|
{
|
|
@@ -1,102 +1,8 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { l as UnauthorizedError } from "./errors-
|
|
3
|
-
import { b as isElevated, n as PUBLIC_SCOPE } from "./types-
|
|
4
|
-
import { B as requireAuth, F as allowPublic, U as requireRoles } from "./permissions-
|
|
1
|
+
/*! @classytic/arc v2.44.0 | MIT | https://classytic.com */
|
|
2
|
+
import { l as UnauthorizedError } from "./errors-CW4anJBy.mjs";
|
|
3
|
+
import { b as isElevated, n as PUBLIC_SCOPE } from "./types-fvO6Ovzx.mjs";
|
|
4
|
+
import { B as requireAuth, F as allowPublic, U as requireRoles } from "./permissions-C5ijIz5Q.mjs";
|
|
5
5
|
import { multiTenantPreset } from "./presets/multiTenant.mjs";
|
|
6
|
-
//#region src/presets/ownedByUser.ts
|
|
7
|
-
/**
|
|
8
|
-
* Create ownership check middleware.
|
|
9
|
-
*
|
|
10
|
-
* FAIL-CLOSED: ownership is meaningless without an authenticated identity, so a
|
|
11
|
-
* request with no user (or a user with no id) is DENIED here rather than sliding
|
|
12
|
-
* through with no ownership check installed. Elevated scope (platform admin)
|
|
13
|
-
* bypasses the check by design.
|
|
14
|
-
*/
|
|
15
|
-
function createOwnershipCheck(ownerField, missingOwner) {
|
|
16
|
-
return async (request, _reply) => {
|
|
17
|
-
const scope = request.scope ?? PUBLIC_SCOPE;
|
|
18
|
-
if (isElevated(scope)) return;
|
|
19
|
-
const user = request.user;
|
|
20
|
-
if (!user) throw new UnauthorizedError("Authentication required for this operation");
|
|
21
|
-
const userWithId = user;
|
|
22
|
-
const userId = userWithId._id ?? userWithId.id;
|
|
23
|
-
if (!userId) throw new UnauthorizedError("Authenticated identity has no usable id");
|
|
24
|
-
request._ownershipCheck = {
|
|
25
|
-
field: ownerField,
|
|
26
|
-
userId,
|
|
27
|
-
missingOwner
|
|
28
|
-
};
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
function ownedByUserPreset(options = {}) {
|
|
32
|
-
const { ownerField = "userId", missingOwner = "deny" } = options;
|
|
33
|
-
const ownershipMiddleware = createOwnershipCheck(ownerField, missingOwner);
|
|
34
|
-
return {
|
|
35
|
-
name: "ownedByUser",
|
|
36
|
-
permissions: {
|
|
37
|
-
update: requireAuth(),
|
|
38
|
-
delete: requireAuth()
|
|
39
|
-
},
|
|
40
|
-
middlewares: {
|
|
41
|
-
update: [ownershipMiddleware],
|
|
42
|
-
delete: [ownershipMiddleware]
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
//#endregion
|
|
47
|
-
//#region src/presets/slugLookup.ts
|
|
48
|
-
/**
|
|
49
|
-
* Slug Lookup Preset
|
|
50
|
-
*
|
|
51
|
-
* Adds a route to get resource by slug.
|
|
52
|
-
*/
|
|
53
|
-
function slugLookupPreset(options = {}) {
|
|
54
|
-
const { slugField = "slug" } = options;
|
|
55
|
-
return {
|
|
56
|
-
name: "slugLookup",
|
|
57
|
-
routes: (permissions) => [{
|
|
58
|
-
method: "GET",
|
|
59
|
-
path: `/slug/:${slugField}`,
|
|
60
|
-
handler: "getBySlug",
|
|
61
|
-
summary: "Get by slug",
|
|
62
|
-
permissions: permissions.get ?? allowPublic(),
|
|
63
|
-
operation: "getBySlug"
|
|
64
|
-
}],
|
|
65
|
-
controllerOptions: { slugField }
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
//#endregion
|
|
69
|
-
//#region src/presets/softDelete.ts
|
|
70
|
-
/**
|
|
71
|
-
* Soft Delete Preset
|
|
72
|
-
*
|
|
73
|
-
* Adds routes for listing deleted items and restoring them.
|
|
74
|
-
* The actual soft-delete behavior (deletedAt field, query filtering)
|
|
75
|
-
* is handled by the repository/adapter layer (e.g., MongoKit's softDelete plugin).
|
|
76
|
-
*/
|
|
77
|
-
function softDeletePreset() {
|
|
78
|
-
return {
|
|
79
|
-
name: "softDelete",
|
|
80
|
-
routes: (permissions) => [{
|
|
81
|
-
method: "GET",
|
|
82
|
-
path: "/deleted",
|
|
83
|
-
handler: "getDeleted",
|
|
84
|
-
summary: "Get soft-deleted items",
|
|
85
|
-
permissions: permissions.list ?? requireRoles(["admin"]),
|
|
86
|
-
operation: "listDeleted",
|
|
87
|
-
_presetSource: "softDelete"
|
|
88
|
-
}, {
|
|
89
|
-
method: "POST",
|
|
90
|
-
path: "/:id/restore",
|
|
91
|
-
handler: "restore",
|
|
92
|
-
summary: "Restore soft-deleted item",
|
|
93
|
-
permissions: permissions.update ?? requireRoles(["admin"]),
|
|
94
|
-
operation: "restore",
|
|
95
|
-
_presetSource: "softDelete"
|
|
96
|
-
}]
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
//#endregion
|
|
100
6
|
//#region src/presets/audited.ts
|
|
101
7
|
/**
|
|
102
8
|
* Audited preset - adds createdBy/updatedBy tracking
|
|
@@ -236,6 +142,100 @@ function bulkPreset(opts) {
|
|
|
236
142
|
};
|
|
237
143
|
}
|
|
238
144
|
//#endregion
|
|
145
|
+
//#region src/presets/ownedByUser.ts
|
|
146
|
+
/**
|
|
147
|
+
* Create ownership check middleware.
|
|
148
|
+
*
|
|
149
|
+
* FAIL-CLOSED: ownership is meaningless without an authenticated identity, so a
|
|
150
|
+
* request with no user (or a user with no id) is DENIED here rather than sliding
|
|
151
|
+
* through with no ownership check installed. Elevated scope (platform admin)
|
|
152
|
+
* bypasses the check by design.
|
|
153
|
+
*/
|
|
154
|
+
function createOwnershipCheck(ownerField, missingOwner) {
|
|
155
|
+
return async (request, _reply) => {
|
|
156
|
+
const scope = request.scope ?? PUBLIC_SCOPE;
|
|
157
|
+
if (isElevated(scope)) return;
|
|
158
|
+
const user = request.user;
|
|
159
|
+
if (!user) throw new UnauthorizedError("Authentication required for this operation");
|
|
160
|
+
const userWithId = user;
|
|
161
|
+
const userId = userWithId._id ?? userWithId.id;
|
|
162
|
+
if (!userId) throw new UnauthorizedError("Authenticated identity has no usable id");
|
|
163
|
+
request._ownershipCheck = {
|
|
164
|
+
field: ownerField,
|
|
165
|
+
userId,
|
|
166
|
+
missingOwner
|
|
167
|
+
};
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
function ownedByUserPreset(options = {}) {
|
|
171
|
+
const { ownerField = "userId", missingOwner = "deny" } = options;
|
|
172
|
+
const ownershipMiddleware = createOwnershipCheck(ownerField, missingOwner);
|
|
173
|
+
return {
|
|
174
|
+
name: "ownedByUser",
|
|
175
|
+
permissions: {
|
|
176
|
+
update: requireAuth(),
|
|
177
|
+
delete: requireAuth()
|
|
178
|
+
},
|
|
179
|
+
middlewares: {
|
|
180
|
+
update: [ownershipMiddleware],
|
|
181
|
+
delete: [ownershipMiddleware]
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
//#endregion
|
|
186
|
+
//#region src/presets/slugLookup.ts
|
|
187
|
+
/**
|
|
188
|
+
* Slug Lookup Preset
|
|
189
|
+
*
|
|
190
|
+
* Adds a route to get resource by slug.
|
|
191
|
+
*/
|
|
192
|
+
function slugLookupPreset(options = {}) {
|
|
193
|
+
const { slugField = "slug" } = options;
|
|
194
|
+
return {
|
|
195
|
+
name: "slugLookup",
|
|
196
|
+
routes: (permissions) => [{
|
|
197
|
+
method: "GET",
|
|
198
|
+
path: `/slug/:${slugField}`,
|
|
199
|
+
handler: "getBySlug",
|
|
200
|
+
summary: "Get by slug",
|
|
201
|
+
permissions: permissions.get ?? allowPublic(),
|
|
202
|
+
operation: "getBySlug"
|
|
203
|
+
}],
|
|
204
|
+
controllerOptions: { slugField }
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
//#endregion
|
|
208
|
+
//#region src/presets/softDelete.ts
|
|
209
|
+
/**
|
|
210
|
+
* Soft Delete Preset
|
|
211
|
+
*
|
|
212
|
+
* Adds routes for listing deleted items and restoring them.
|
|
213
|
+
* The actual soft-delete behavior (deletedAt field, query filtering)
|
|
214
|
+
* is handled by the repository/adapter layer (e.g., MongoKit's softDelete plugin).
|
|
215
|
+
*/
|
|
216
|
+
function softDeletePreset() {
|
|
217
|
+
return {
|
|
218
|
+
name: "softDelete",
|
|
219
|
+
routes: (permissions) => [{
|
|
220
|
+
method: "GET",
|
|
221
|
+
path: "/deleted",
|
|
222
|
+
handler: "getDeleted",
|
|
223
|
+
summary: "Get soft-deleted items",
|
|
224
|
+
permissions: permissions.list ?? requireRoles(["admin"]),
|
|
225
|
+
operation: "listDeleted",
|
|
226
|
+
_presetSource: "softDelete"
|
|
227
|
+
}, {
|
|
228
|
+
method: "POST",
|
|
229
|
+
path: "/:id/restore",
|
|
230
|
+
handler: "restore",
|
|
231
|
+
summary: "Restore soft-deleted item",
|
|
232
|
+
permissions: permissions.update ?? requireRoles(["admin"]),
|
|
233
|
+
operation: "restore",
|
|
234
|
+
_presetSource: "softDelete"
|
|
235
|
+
}]
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
//#endregion
|
|
239
239
|
//#region src/presets/tree.ts
|
|
240
240
|
/**
|
|
241
241
|
* Tree Preset
|
|
@@ -266,14 +266,6 @@ function treePreset(options = {}) {
|
|
|
266
266
|
}
|
|
267
267
|
//#endregion
|
|
268
268
|
//#region src/presets/index.ts
|
|
269
|
-
/**
|
|
270
|
-
* Convenience alias for multiTenantPreset with public list/get routes
|
|
271
|
-
* Equivalent to: multiTenantPreset({ allowPublic: ['list', 'get'] })
|
|
272
|
-
*/
|
|
273
|
-
const flexibleMultiTenantPreset = (options = {}) => multiTenantPreset({
|
|
274
|
-
...options,
|
|
275
|
-
allowPublic: ["list", "get"]
|
|
276
|
-
});
|
|
277
269
|
const presetRegistry = {
|
|
278
270
|
softDelete: softDeletePreset,
|
|
279
271
|
slugLookup: slugLookupPreset,
|
|
@@ -409,4 +401,4 @@ function mergePreset(config, preset) {
|
|
|
409
401
|
return result;
|
|
410
402
|
}
|
|
411
403
|
//#endregion
|
|
412
|
-
export {
|
|
404
|
+
export { treePreset as a, ownedByUserPreset as c, registerPreset as i, bulkPreset as l, getAvailablePresets as n, softDeletePreset as o, getPreset as r, slugLookupPreset as s, applyPresets as t, auditedPreset as u };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { c as getOrgId, f as getScopeContextMap, g as getUserId, m as getTeamId, x as isMember } from "./types-
|
|
1
|
+
/*! @classytic/arc v2.44.0 | MIT | https://classytic.com */
|
|
2
|
+
import { c as getOrgId, f as getScopeContextMap, g as getUserId, m as getTeamId, x as isMember } from "./types-fvO6Ovzx.mjs";
|
|
3
3
|
//#region src/scope/projection.ts
|
|
4
4
|
/**
|
|
5
5
|
* Compute the request-scope projection. Returns `undefined` when no
|
|
@@ -435,4 +435,4 @@ declare class PushRefRegistry {
|
|
|
435
435
|
private hydrateEnvelope;
|
|
436
436
|
}
|
|
437
437
|
//#endregion
|
|
438
|
-
export { PushRefRegistry as a, SerializedEntry as c, Principal as i, EnvelopeWriter as l, FencedWriteOutcome as n, PushRefRegistryOptions as o, MemoryPushRefStore as r, PushRefStore as s, EnvelopeSnapshot as t };
|
|
438
|
+
export { PushRefRegistry as a, SerializedEntry as c, Principal as i, EnvelopeWriter as l, FencedWriteOutcome as n, PushRefRegistryOptions as o, MemoryPushRefStore as r, PushRefStore as s, EnvelopeSnapshot as t, DeadQueueEntry as u };
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import {
|
|
3
|
-
import { i as versionKey, r as tagVersionKey } from "./keys-
|
|
4
|
-
import { n as declareRuntimeCapability } from "./runtimeCapabilities-
|
|
5
|
-
import { t as hasEvents } from "./typeGuards-
|
|
6
|
-
import { t as MemoryCacheStore } from "./memory-
|
|
1
|
+
/*! @classytic/arc v2.44.0 | MIT | https://classytic.com */
|
|
2
|
+
import { r as __exportAll } from "./rolldown-runtime-MYrLNGnq.mjs";
|
|
3
|
+
import { i as versionKey, r as tagVersionKey } from "./keys-CpoiZ8hU.mjs";
|
|
4
|
+
import { n as declareRuntimeCapability } from "./runtimeCapabilities-DIMKMV2G.mjs";
|
|
5
|
+
import { t as hasEvents } from "./typeGuards-kEaP_WmO.mjs";
|
|
6
|
+
import { t as MemoryCacheStore } from "./memory-CTa5pOCW.mjs";
|
|
7
7
|
import fp from "fastify-plugin";
|
|
8
8
|
//#region src/cache/QueryCache.ts
|
|
9
|
+
const MISS = Object.freeze({
|
|
10
|
+
status: "miss",
|
|
11
|
+
data: void 0
|
|
12
|
+
});
|
|
9
13
|
var QueryCache = class {
|
|
10
14
|
store;
|
|
11
15
|
constructor(store) {
|
|
@@ -13,17 +17,11 @@ var QueryCache = class {
|
|
|
13
17
|
}
|
|
14
18
|
async get(key) {
|
|
15
19
|
const envelope = await this.store.get(key);
|
|
16
|
-
if (!envelope?.createdAt) return
|
|
17
|
-
data: void 0,
|
|
18
|
-
status: "miss"
|
|
19
|
-
};
|
|
20
|
+
if (!envelope?.createdAt) return MISS;
|
|
20
21
|
const now = Date.now();
|
|
21
22
|
if (now >= envelope.expiresAt) {
|
|
22
23
|
await this.store.delete(key);
|
|
23
|
-
return
|
|
24
|
-
data: void 0,
|
|
25
|
-
status: "miss"
|
|
26
|
-
};
|
|
24
|
+
return MISS;
|
|
27
25
|
}
|
|
28
26
|
if (now < envelope.staleAfter) return {
|
|
29
27
|
data: envelope.data,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
import { r as CacheStore } from "./interface-BOk3YnTz.mjs";
|
|
3
|
-
import { i as QueryCache } from "./QueryCache
|
|
3
|
+
import { i as QueryCache } from "./QueryCache--5uAuYPW.mjs";
|
|
4
4
|
import { FastifyPluginAsync } from "fastify";
|
|
5
5
|
//#region src/cache/queryCachePlugin.d.ts
|
|
6
6
|
interface QueryCachePluginOptions {
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import {
|
|
3
|
-
import { arcLog } from "./logger
|
|
4
|
-
import {
|
|
5
|
-
import { n as getUserRoles } from "./userHelpers-
|
|
6
|
-
import {
|
|
7
|
-
import { t as
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { t as openSseStream } from "./sseStream-
|
|
1
|
+
/*! @classytic/arc v2.44.0 | MIT | https://classytic.com */
|
|
2
|
+
import { r as __exportAll } from "./rolldown-runtime-MYrLNGnq.mjs";
|
|
3
|
+
import { t as arcLog } from "./logger-D4V1zGLI.mjs";
|
|
4
|
+
import { t as simpleEqualityMatcher } from "./simpleEqualityMatcher-DbwIM1f1.mjs";
|
|
5
|
+
import { n as getUserRoles } from "./userHelpers-C76zD5pa.mjs";
|
|
6
|
+
import { n as isEventVisible, t as eventAudienceOf } from "./tenancy-DxV8OuX2.mjs";
|
|
7
|
+
import { t as applyFieldReadPermissions } from "./fields-A5crhsJb.mjs";
|
|
8
|
+
import { a as promoteStreamTokenToHeader } from "./streaming-JzB5CAga.mjs";
|
|
9
|
+
import { n as evaluateAndApplyPermission } from "./authorizationDecision-wX3SA9w_.mjs";
|
|
10
|
+
import { t as openSseStream } from "./sseStream-DQChzGTs.mjs";
|
|
11
|
+
import { n as arcRouteValidatorCompiler } from "./routeValidator-DHtpzrzk.mjs";
|
|
11
12
|
import fp from "fastify-plugin";
|
|
12
13
|
//#region src/plugins/realtime.ts
|
|
13
14
|
var realtime_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -123,10 +124,10 @@ function resolveRowMatcher(filters, adapter) {
|
|
|
123
124
|
* the client adds it if absent.
|
|
124
125
|
*/
|
|
125
126
|
function resolveDelivery(event, policy, operation) {
|
|
126
|
-
if (policy.tenantScoped
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
127
|
+
if (policy.tenantScoped && !isEventVisible(event.meta?.organizationId, {
|
|
128
|
+
...policy.subscriberOrgId !== void 0 ? { orgId: policy.subscriberOrgId } : {},
|
|
129
|
+
platformView: policy.subscriberPlatformView === true
|
|
130
|
+
})) return { kind: "drop" };
|
|
130
131
|
const doc = event.payload?.data;
|
|
131
132
|
if (!(!!policy.filters && Object.keys(policy.filters).length > 0)) return {
|
|
132
133
|
kind: "deliver",
|
|
@@ -202,9 +203,8 @@ const realtimePlugin = async (fastify, opts = {}) => {
|
|
|
202
203
|
* when the caller should stop.
|
|
203
204
|
*/
|
|
204
205
|
const authorizeResource = async (resourceName, entry, request, reply) => {
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
holder._policyFilters = void 0;
|
|
206
|
+
const saved = request._policyFilters;
|
|
207
|
+
request._policyFilters = void 0;
|
|
208
208
|
try {
|
|
209
209
|
const listCheck = entry.permissions?.list;
|
|
210
210
|
if (typeof listCheck === "function") {
|
|
@@ -215,7 +215,7 @@ const realtimePlugin = async (fastify, opts = {}) => {
|
|
|
215
215
|
action: "list"
|
|
216
216
|
}, request, reply)) return null;
|
|
217
217
|
}
|
|
218
|
-
const filters =
|
|
218
|
+
const filters = request._policyFilters;
|
|
219
219
|
const resolution = resolveRowMatcher(filters, fastify.arc?.registry?.getAdapter(resourceName));
|
|
220
220
|
if (!resolution.enforceable) {
|
|
221
221
|
await reply.code(501).send({
|
|
@@ -226,18 +226,20 @@ const realtimePlugin = async (fastify, opts = {}) => {
|
|
|
226
226
|
return null;
|
|
227
227
|
}
|
|
228
228
|
const scope = request.scope;
|
|
229
|
+
const audience = eventAudienceOf(scope);
|
|
229
230
|
return {
|
|
230
231
|
name: resourceName,
|
|
231
232
|
policy: {
|
|
232
233
|
tenantScoped: entry.tenantField !== false,
|
|
233
|
-
subscriberOrgId:
|
|
234
|
+
subscriberOrgId: audience.orgId,
|
|
235
|
+
subscriberPlatformView: audience.platformView,
|
|
234
236
|
filters,
|
|
235
237
|
matcher: resolution.matcher
|
|
236
238
|
},
|
|
237
239
|
fields: entry.fields
|
|
238
240
|
};
|
|
239
241
|
} finally {
|
|
240
|
-
|
|
242
|
+
request._policyFilters = saved;
|
|
241
243
|
}
|
|
242
244
|
};
|
|
243
245
|
/** Open the stream and wire every authorized subscription onto it. */
|
|
@@ -327,9 +329,11 @@ const realtimePlugin = async (fastify, opts = {}) => {
|
|
|
327
329
|
}
|
|
328
330
|
});
|
|
329
331
|
const multiplexPath = path.replace(/\/:resource$/, "");
|
|
332
|
+
const validatorCompiler = arcRouteValidatorCompiler(fastify);
|
|
330
333
|
fastify.route({
|
|
331
334
|
method: "GET",
|
|
332
335
|
url: multiplexPath,
|
|
336
|
+
...validatorCompiler ? { validatorCompiler } : {},
|
|
333
337
|
schema: {
|
|
334
338
|
tags: ["Events"],
|
|
335
339
|
summary: "Realtime multi-resource change feed",
|
|
@@ -384,4 +388,4 @@ var realtime_default = fp(realtimePlugin, {
|
|
|
384
388
|
dependencies: ["arc-events"]
|
|
385
389
|
});
|
|
386
390
|
//#endregion
|
|
387
|
-
export {
|
|
391
|
+
export { realtime_exports as n, realtime_default as t };
|