@classytic/arc 2.6.3 → 2.7.3
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 +98 -3
- package/dist/{BaseController-DzRtluEF.mjs → BaseController-CpMfCXdn.mjs} +134 -16
- package/dist/adapters/index.d.mts +2 -2
- package/dist/adapters/index.mjs +1 -1
- package/dist/{adapters-gM-WYjNe.mjs → adapters-BxGgSHjj.mjs} +1 -9
- package/dist/applyPermissionResult-D6GPMsvh.mjs +37 -0
- package/dist/audit/index.d.mts +1 -1
- package/dist/audit/index.mjs +1 -1
- package/dist/audit/mongodb.d.mts +1 -1
- package/dist/audit/mongodb.mjs +1 -1
- package/dist/auth/index.d.mts +4 -4
- package/dist/auth/index.mjs +7 -6
- package/dist/auth/mongoose.d.mts +191 -0
- package/dist/auth/mongoose.mjs +73 -0
- package/dist/auth/redis-session.d.mts +1 -1
- package/dist/{betterAuthOpenApi-lz0IRbXJ.mjs → betterAuthOpenApi-CCw3YX0g.mjs} +1 -1
- package/dist/cache/index.d.mts +2 -2
- package/dist/cache/index.mjs +2 -2
- package/dist/cli/commands/docs.mjs +2 -2
- package/dist/cli/commands/generate.mjs +1 -1
- package/dist/cli/commands/init.mjs +7 -5
- package/dist/cli/commands/introspect.mjs +1 -1
- package/dist/core/index.d.mts +3 -3
- package/dist/core/index.mjs +4 -4
- package/dist/{core-C1XCMtqM.mjs → core-BWekSEju.mjs} +41 -13
- package/dist/{createApp-D2w0LdYJ.mjs → createApp-D7e77m8C.mjs} +25 -14
- package/dist/{defineResource-wWMBB4GP.mjs → defineResource-DZzyl4a4.mjs} +42 -37
- package/dist/docs/index.d.mts +2 -2
- package/dist/docs/index.mjs +1 -1
- package/dist/dynamic/index.d.mts +2 -2
- package/dist/dynamic/index.mjs +2 -2
- package/dist/{elevation-BEdACOLB.mjs → elevation-By_p2lnn.mjs} +1 -1
- package/dist/elevation-D7WK0RXq.d.mts +23 -0
- package/dist/{errorHandler-r2595m8T.mjs → errorHandler-CH8wk1eD.mjs} +17 -2
- package/dist/{errorHandler-Do4vVQ1f.d.mts → errorHandler-pCpEtNd7.d.mts} +46 -2
- package/dist/{eventPlugin-Ba00swHF.mjs → eventPlugin-B6U_nCFU.mjs} +4 -3
- package/dist/{eventPlugin-DW45v4V5.d.mts → eventPlugin-CdvUoUna.d.mts} +1 -1
- package/dist/events/index.d.mts +3 -3
- package/dist/events/index.mjs +1 -1
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis.d.mts +1 -1
- package/dist/factory/index.d.mts +1 -1
- package/dist/factory/index.mjs +1 -1
- package/dist/hooks/index.d.mts +1 -1
- package/dist/hooks/index.mjs +1 -1
- package/dist/idempotency/index.d.mts +3 -3
- package/dist/idempotency/mongodb.d.mts +1 -1
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/index-B0extFr4.d.mts +640 -0
- package/dist/{index-gz6iuzCp.d.mts → index-BjShrzoj.d.mts} +47 -4
- package/dist/{index-CHeJa4Zd.d.mts → index-C9eYNjGR.d.mts} +1 -1
- package/dist/index.d.mts +9 -8
- package/dist/index.mjs +10 -9
- package/dist/integrations/event-gateway.d.mts +1 -1
- package/dist/integrations/event-gateway.mjs +1 -1
- package/dist/integrations/index.d.mts +1 -1
- package/dist/integrations/mcp/index.d.mts +2 -2
- package/dist/integrations/mcp/index.mjs +8 -5
- package/dist/integrations/mcp/testing.d.mts +1 -1
- package/dist/integrations/mcp/testing.mjs +1 -1
- package/dist/integrations/webhooks.d.mts +58 -1
- package/dist/integrations/webhooks.mjs +78 -7
- package/dist/integrations/websocket.d.mts +7 -1
- package/dist/integrations/websocket.mjs +7 -1
- package/dist/{interface-DYH8AXGe.d.mts → interface-B91alUzq.d.mts} +151 -15
- package/dist/{mongodb-pMvOlR5_.d.mts → mongodb-B7zupyck.d.mts} +1 -1
- package/dist/{mongodb-kltrBPa1.d.mts → mongodb-Cgu9F1Nd.d.mts} +1 -1
- package/dist/{openapi-CBmZ6EQN.mjs → openapi-BBSTVcMm.mjs} +1 -1
- package/dist/org/index.d.mts +2 -2
- package/dist/org/index.mjs +1 -1
- package/dist/permissions/index.d.mts +4 -4
- package/dist/permissions/index.mjs +3 -2
- package/dist/{permissions-C8ImI8gC.mjs → permissions-CH4cNwJi.mjs} +358 -64
- package/dist/plugins/index.d.mts +52 -5
- package/dist/plugins/index.mjs +12 -11
- package/dist/plugins/response-cache.mjs +1 -1
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/policies/index.d.mts +1 -1
- package/dist/presets/index.d.mts +3 -3
- package/dist/presets/index.mjs +1 -1
- package/dist/presets/multiTenant.d.mts +53 -3
- package/dist/presets/multiTenant.mjs +89 -47
- package/dist/{presets-BMfdy34e.mjs → presets-BFrGvvjL.mjs} +2 -2
- package/dist/{queryCachePlugin-DcmETvcB.d.mts → queryCachePlugin-Ckl71mkc.d.mts} +1 -1
- package/dist/{queryCachePlugin-XtFplYO9.mjs → queryCachePlugin-CwTpR04-.mjs} +2 -2
- package/dist/{redis-D0Qc-9EW.d.mts → redis-3TQxm2VZ.d.mts} +1 -1
- package/dist/{redis-stream-BW9UKLZM.d.mts → redis-stream-Dag5LFa9.d.mts} +1 -1
- package/dist/registry/index.d.mts +1 -1
- package/dist/registry/index.mjs +2 -2
- package/dist/replyHelpers-uDUIYh7u.mjs +40 -0
- package/dist/{resourceToTools-nCJWnG1r.mjs → resourceToTools-BJkoQoUP.mjs} +74 -25
- package/dist/rpc/index.d.mts +1 -1
- package/dist/rpc/index.mjs +1 -1
- package/dist/scope/index.d.mts +3 -2
- package/dist/scope/index.mjs +4 -3
- package/dist/{sse-BF7GR7IB.mjs → sse-6W0hjVS_.mjs} +2 -2
- package/dist/testing/index.d.mts +2 -2
- package/dist/testing/index.mjs +1 -1
- package/dist/types/index.d.mts +4 -3
- package/dist/types/index.mjs +1 -1
- package/dist/types--D3vvfdt.d.mts +286 -0
- package/dist/{types-By-5mIfn.d.mts → types-2FlNl0mL.d.mts} +44 -9
- package/dist/types-AOD8fxIw.mjs +229 -0
- package/dist/types-B4BNthET.d.mts +178 -0
- package/dist/{types-B4_TDdPe.d.mts → types-C5g2oRC7.d.mts} +18 -2
- package/dist/utils/index.d.mts +3 -3
- package/dist/utils/index.mjs +5 -5
- package/package.json +21 -6
- package/skills/arc/SKILL.md +314 -6
- package/skills/arc/references/integrations.md +32 -7
- package/skills/arc/references/mcp.md +31 -7
- package/skills/arc/references/multi-tenancy.md +208 -0
- package/skills/arc/references/production.md +69 -0
- package/dist/elevation-C_taLQrM.d.mts +0 -147
- package/dist/index-NGZksqM5.d.mts +0 -398
- package/dist/types-BNUccdcf.d.mts +0 -101
- package/dist/types-BhtYdxZU.mjs +0 -91
- /package/dist/{EventTransport-wc5hSLik.d.mts → EventTransport-C4VheKeC.d.mts} +0 -0
- /package/dist/{HookSystem-COkyWztM.mjs → HookSystem-D7lfx--K.mjs} +0 -0
- /package/dist/{ResourceRegistry-C6ngvOnn.mjs → ResourceRegistry-DsHiG9cL.mjs} +0 -0
- /package/dist/{caching-BSXB-Xr7.mjs → caching-5DtLwIqb.mjs} +0 -0
- /package/dist/{circuitBreaker-JP2GdJ4b.d.mts → circuitBreaker-BBPDt-J_.d.mts} +0 -0
- /package/dist/{circuitBreaker-BOBOpN2w.mjs → circuitBreaker-l18oRgL5.mjs} +0 -0
- /package/dist/{errors-CcVbl1-T.d.mts → errors-BS6lZvWy.d.mts} +0 -0
- /package/dist/{errors-NoQKsbAT.mjs → errors-Cg58SLNi.mjs} +0 -0
- /package/dist/{externalPaths-DpO-s7r8.d.mts → externalPaths-iba7jD3d.d.mts} +0 -0
- /package/dist/{fields-DFwdaWCq.d.mts → fields-D4nMDqnK.d.mts} +0 -0
- /package/dist/{interface-D_BWALyZ.d.mts → interface-CG7oRZjX.d.mts} +0 -0
- /package/dist/{interface-gr-7qo9j.d.mts → interface-CSbZdv_3.d.mts} +0 -0
- /package/dist/{logger-Dz3j1ItV.mjs → logger-DLg8-Ueg.mjs} +0 -0
- /package/dist/{memory-BFAYkf8H.mjs → memory-Cp7_cAko.mjs} +0 -0
- /package/dist/{metrics-Csh4nsvv.mjs → metrics-Qnvwc-LQ.mjs} +0 -0
- /package/dist/{mongodb-BuQ7fNTg.mjs → mongodb-B7X7P1P8.mjs} +0 -0
- /package/dist/{pluralize-CcT6qF0a.mjs → pluralize-Dckfq6US.mjs} +0 -0
- /package/dist/{registry-I-ogLgL9.mjs → registry-B3lRFBWo.mjs} +0 -0
- /package/dist/{requestContext-DYtmNpm5.mjs → requestContext-xHIKedG6.mjs} +0 -0
- /package/dist/{schemaConverter-DjzHpFam.mjs → schemaConverter-0TyONAwM.mjs} +0 -0
- /package/dist/{sessionManager-wbkYj2HL.d.mts → sessionManager-CEo9jwPI.d.mts} +0 -0
- /package/dist/{tracing-bz_U4EM1.d.mts → tracing-DEqdGkr-.d.mts} +0 -0
- /package/dist/{typeGuards-Cj5Rgvlg.mjs → typeGuards-CcFZXgU7.mjs} +0 -0
- /package/dist/{utils-Dc0WhlIl.mjs → utils-B-l6410F.mjs} +0 -0
- /package/dist/{versioning-BzfeHmhj.mjs → versioning-CdBbFefk.mjs} +0 -0
package/dist/plugins/index.mjs
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { p as MUTATION_OPERATIONS } from "../constants-Cxde4rpC.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { t as requestContext } from "../requestContext-
|
|
4
|
-
import { t as hasEvents } from "../typeGuards-
|
|
5
|
-
import { t as HookSystem } from "../HookSystem-
|
|
6
|
-
import { t as ResourceRegistry } from "../ResourceRegistry-
|
|
7
|
-
import { n as caching_default, t as cachingPlugin } from "../caching-
|
|
8
|
-
import { t as errorHandlerPlugin } from "../errorHandler-
|
|
9
|
-
import { n as metrics_default, t as metricsPlugin } from "../metrics-
|
|
10
|
-
import {
|
|
11
|
-
import { n as
|
|
2
|
+
import { o as getOrgId } from "../types-AOD8fxIw.mjs";
|
|
3
|
+
import { t as requestContext } from "../requestContext-xHIKedG6.mjs";
|
|
4
|
+
import { t as hasEvents } from "../typeGuards-CcFZXgU7.mjs";
|
|
5
|
+
import { t as HookSystem } from "../HookSystem-D7lfx--K.mjs";
|
|
6
|
+
import { t as ResourceRegistry } from "../ResourceRegistry-DsHiG9cL.mjs";
|
|
7
|
+
import { n as caching_default, t as cachingPlugin } from "../caching-5DtLwIqb.mjs";
|
|
8
|
+
import { t as errorHandlerPlugin } from "../errorHandler-CH8wk1eD.mjs";
|
|
9
|
+
import { n as metrics_default, t as metricsPlugin } from "../metrics-Qnvwc-LQ.mjs";
|
|
10
|
+
import { t as replyHelpersPlugin } from "../replyHelpers-uDUIYh7u.mjs";
|
|
11
|
+
import { n as sse_default, t as ssePlugin } from "../sse-6W0hjVS_.mjs";
|
|
12
|
+
import { n as versioning_default, t as versioningPlugin } from "../versioning-CdBbFefk.mjs";
|
|
12
13
|
import { randomUUID } from "node:crypto";
|
|
13
14
|
import fp from "fastify-plugin";
|
|
14
15
|
//#region src/core/arcCorePlugin.ts
|
|
@@ -409,4 +410,4 @@ var requestId_default = fp(requestIdPlugin, {
|
|
|
409
410
|
fastify: "5.x"
|
|
410
411
|
});
|
|
411
412
|
//#endregion
|
|
412
|
-
export { arcCorePlugin_default as arcCorePlugin, arcCorePlugin as arcCorePluginFn, caching_default as cachingPlugin, cachingPlugin as cachingPluginFn, createPlugin, errorHandlerPlugin, errorHandlerPlugin as errorHandlerPluginFn, gracefulShutdown_default as gracefulShutdownPlugin, gracefulShutdownPlugin as gracefulShutdownPluginFn, health_default as healthPlugin, healthPlugin as healthPluginFn, metrics_default as metricsPlugin, metricsPlugin as metricsPluginFn, requestId_default as requestIdPlugin, requestIdPlugin as requestIdPluginFn, sse_default as ssePlugin, ssePlugin as ssePluginFn, versioning_default as versioningPlugin, versioningPlugin as versioningPluginFn };
|
|
413
|
+
export { arcCorePlugin_default as arcCorePlugin, arcCorePlugin as arcCorePluginFn, caching_default as cachingPlugin, cachingPlugin as cachingPluginFn, createPlugin, errorHandlerPlugin, errorHandlerPlugin as errorHandlerPluginFn, gracefulShutdown_default as gracefulShutdownPlugin, gracefulShutdownPlugin as gracefulShutdownPluginFn, health_default as healthPlugin, healthPlugin as healthPluginFn, metrics_default as metricsPlugin, metricsPlugin as metricsPluginFn, replyHelpersPlugin, requestId_default as requestIdPlugin, requestIdPlugin as requestIdPluginFn, sse_default as ssePlugin, ssePlugin as ssePluginFn, versioning_default as versioningPlugin, versioningPlugin as versioningPluginFn };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as traced, i as isTracingAvailable, n as _default, r as createSpan, t as TracingOptions } from "../tracing-
|
|
1
|
+
import { a as traced, i as isTracingAvailable, n as _default, r as createSpan, t as TracingOptions } from "../tracing-DEqdGkr-.mjs";
|
|
2
2
|
export { type TracingOptions, createSpan, isTracingAvailable, traced, _default as tracingPlugin };
|
|
@@ -44,7 +44,7 @@ try {
|
|
|
44
44
|
function createTracerProvider(options) {
|
|
45
45
|
if (!isAvailable) return null;
|
|
46
46
|
const { serviceName = "@classytic/arc", serviceVersion, exporterUrl = "http://localhost:4318/v1/traces" } = options;
|
|
47
|
-
const resolvedVersion = serviceVersion ?? "2.
|
|
47
|
+
const resolvedVersion = serviceVersion ?? "2.7.3";
|
|
48
48
|
const exporter = new OTLPTraceExporter({ url: exporterUrl });
|
|
49
49
|
const provider = new NodeTracerProvider({ resource: { attributes: {
|
|
50
50
|
"service.name": serviceName,
|
package/dist/presets/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Gt as PaginatedResult, It as IControllerResponse, Lt as IRequestContext, Z as PresetResult, ot as ResourceConfig, u as AnyRecord } from "../interface-
|
|
2
|
-
import { MultiTenantOptions, multiTenantPreset } from "./multiTenant.mjs";
|
|
1
|
+
import { Gt as PaginatedResult, It as IControllerResponse, Lt as IRequestContext, Z as PresetResult, ot as ResourceConfig, u as AnyRecord } from "../interface-B91alUzq.mjs";
|
|
2
|
+
import { MultiTenantOptions, TenantFieldSpec, multiTenantPreset } from "./multiTenant.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/presets/ownedByUser.d.ts
|
|
5
5
|
interface OwnedByUserOptions {
|
|
@@ -271,4 +271,4 @@ type PresetInput = string | PresetResult | {
|
|
|
271
271
|
*/
|
|
272
272
|
declare function applyPresets<TDoc = AnyRecord>(config: ResourceConfig<TDoc>, presets?: PresetInput[]): ResourceConfig<TDoc>;
|
|
273
273
|
//#endregion
|
|
274
|
-
export { type AuditedPresetOptions, type BulkOperation, type BulkPresetOptions, type IAuditedPreset, type IMultiTenantPreset, type IOwnedByUserPreset, type IPresetController, type ISlugLookupController, type ISoftDeleteController, type ITreeController, type MultiTenantOptions, type OwnedByUserOptions, type SlugLookupOptions, type TreeOptions, applyPresets, auditedPreset, bulkPreset, flexibleMultiTenantPreset, getAvailablePresets, getPreset, multiTenantPreset, ownedByUserPreset, registerPreset, slugLookupPreset, softDeletePreset, treePreset };
|
|
274
|
+
export { type AuditedPresetOptions, type BulkOperation, type BulkPresetOptions, type IAuditedPreset, type IMultiTenantPreset, type IOwnedByUserPreset, type IPresetController, type ISlugLookupController, type ISoftDeleteController, type ITreeController, type MultiTenantOptions, type OwnedByUserOptions, type SlugLookupOptions, type TenantFieldSpec, type TreeOptions, applyPresets, auditedPreset, bulkPreset, flexibleMultiTenantPreset, getAvailablePresets, getPreset, multiTenantPreset, ownedByUserPreset, registerPreset, slugLookupPreset, softDeletePreset, treePreset };
|
package/dist/presets/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { multiTenantPreset } from "./multiTenant.mjs";
|
|
2
|
-
import { a as registerPreset, c as auditedPreset, d as ownedByUserPreset, i as getPreset, l as softDeletePreset, n as flexibleMultiTenantPreset, o as treePreset, r as getAvailablePresets, s as bulkPreset, t as applyPresets, u as slugLookupPreset } from "../presets-
|
|
2
|
+
import { a as registerPreset, c as auditedPreset, d as ownedByUserPreset, i as getPreset, l as softDeletePreset, n as flexibleMultiTenantPreset, o as treePreset, r as getAvailablePresets, s as bulkPreset, t as applyPresets, u as slugLookupPreset } from "../presets-BFrGvvjL.mjs";
|
|
3
3
|
export { applyPresets, auditedPreset, bulkPreset, flexibleMultiTenantPreset, getAvailablePresets, getPreset, multiTenantPreset, ownedByUserPreset, registerPreset, slugLookupPreset, softDeletePreset, treePreset };
|
|
@@ -1,9 +1,59 @@
|
|
|
1
|
-
import { S as CrudRouteKey, Z as PresetResult } from "../interface-
|
|
1
|
+
import { S as CrudRouteKey, Z as PresetResult } from "../interface-B91alUzq.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/presets/multiTenant.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* One tenant dimension for multi-field filtering. Discriminated by source:
|
|
6
|
+
* - `type: 'org'` → reads `getOrgId(scope)`
|
|
7
|
+
* - `type: 'team'` → reads `getTeamId(scope)`
|
|
8
|
+
* - `contextKey` → reads `getScopeContext(scope, contextKey)` (any custom dimension)
|
|
9
|
+
*/
|
|
10
|
+
type TenantFieldSpec = {
|
|
11
|
+
field: string;
|
|
12
|
+
type: "org";
|
|
13
|
+
} | {
|
|
14
|
+
field: string;
|
|
15
|
+
type: "team";
|
|
16
|
+
} | {
|
|
17
|
+
field: string;
|
|
18
|
+
contextKey: string;
|
|
19
|
+
};
|
|
4
20
|
interface MultiTenantOptions {
|
|
5
|
-
/**
|
|
21
|
+
/**
|
|
22
|
+
* Single-field form: name of the database field to filter by.
|
|
23
|
+
* Reads `getOrgId(scope)` as the value source.
|
|
24
|
+
*
|
|
25
|
+
* Mutually exclusive with `tenantFields` — pass one or the other, not both.
|
|
26
|
+
*
|
|
27
|
+
* @default 'organizationId'
|
|
28
|
+
*/
|
|
6
29
|
tenantField?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Multi-field form (2.7.1+): list of tenant dimensions to filter by in
|
|
32
|
+
* lockstep. Use this when a resource is scoped by more than just
|
|
33
|
+
* organization — e.g. organization + branch, organization + project,
|
|
34
|
+
* or organization + team + workspace.
|
|
35
|
+
*
|
|
36
|
+
* Each entry is a discriminated `TenantFieldSpec` declaring where the
|
|
37
|
+
* value comes from. Use `type: 'org'` / `type: 'team'` for built-in scope
|
|
38
|
+
* fields, or `contextKey: '...'` to read from `scope.context` (set by
|
|
39
|
+
* your auth function).
|
|
40
|
+
*
|
|
41
|
+
* Fail-closed: if any required dimension is missing, the request is
|
|
42
|
+
* rejected. Elevated scopes apply whatever resolves and skip the rest.
|
|
43
|
+
*
|
|
44
|
+
* Mutually exclusive with `tenantField`.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* multiTenantPreset({
|
|
49
|
+
* tenantFields: [
|
|
50
|
+
* { field: 'organizationId', type: 'org' },
|
|
51
|
+
* { field: 'branchId', contextKey: 'branchId' },
|
|
52
|
+
* ],
|
|
53
|
+
* })
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
tenantFields?: readonly TenantFieldSpec[];
|
|
7
57
|
/**
|
|
8
58
|
* Routes that allow public access (no auth required)
|
|
9
59
|
* When a route is in this array:
|
|
@@ -18,4 +68,4 @@ interface MultiTenantOptions {
|
|
|
18
68
|
}
|
|
19
69
|
declare function multiTenantPreset(options?: MultiTenantOptions): PresetResult;
|
|
20
70
|
//#endregion
|
|
21
|
-
export { MultiTenantOptions, multiTenantPreset };
|
|
71
|
+
export { MultiTenantOptions, TenantFieldSpec, multiTenantPreset };
|
|
@@ -1,31 +1,59 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import "../constants-Cxde4rpC.mjs";
|
|
2
|
+
import { _ as isElevated, c as getRequestScope, f as getTeamId, h as hasOrgAccess, l as getScopeContext, o as getOrgId } from "../types-AOD8fxIw.mjs";
|
|
3
3
|
//#region src/presets/multiTenant.ts
|
|
4
|
-
/**
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Resolve a single TenantFieldSpec against the current scope.
|
|
6
|
+
* Returns `undefined` if the source value isn't present on the scope.
|
|
7
|
+
*/
|
|
8
|
+
function resolveSpec(scope, spec) {
|
|
9
|
+
if ("contextKey" in spec) return getScopeContext(scope, spec.contextKey);
|
|
10
|
+
if (spec.type === "org") return getOrgId(scope);
|
|
11
|
+
if (spec.type === "team") return getTeamId(scope);
|
|
12
|
+
}
|
|
13
|
+
/** Resolve every spec — returns the partial map of fields that have a value. */
|
|
14
|
+
function resolveAll(scope, specs) {
|
|
15
|
+
const resolved = {};
|
|
16
|
+
const missing = [];
|
|
17
|
+
for (const spec of specs) {
|
|
18
|
+
const value = resolveSpec(scope, spec);
|
|
19
|
+
if (value !== void 0) resolved[spec.field] = value;
|
|
20
|
+
else missing.push(spec.field);
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
resolved,
|
|
24
|
+
missing
|
|
25
|
+
};
|
|
7
26
|
}
|
|
8
27
|
/**
|
|
9
|
-
* Create tenant filter middleware
|
|
10
|
-
*
|
|
11
|
-
*
|
|
28
|
+
* Create tenant filter middleware (strict).
|
|
29
|
+
* Walks the configured tenant fields and applies all of them in lockstep.
|
|
30
|
+
* Fails closed if any non-elevated caller is missing a required dimension.
|
|
12
31
|
*/
|
|
13
|
-
function createTenantFilter(
|
|
32
|
+
function createTenantFilter(specs) {
|
|
14
33
|
return async (request, reply) => {
|
|
15
|
-
const scope =
|
|
34
|
+
const scope = getRequestScope(request);
|
|
16
35
|
if (isElevated(scope)) {
|
|
17
|
-
const
|
|
18
|
-
if (
|
|
36
|
+
const { resolved } = resolveAll(scope, specs);
|
|
37
|
+
if (Object.keys(resolved).length > 0) request._policyFilters = {
|
|
19
38
|
...request._policyFilters ?? {},
|
|
20
|
-
|
|
39
|
+
...resolved
|
|
21
40
|
};
|
|
22
41
|
return;
|
|
23
42
|
}
|
|
24
|
-
if (
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
43
|
+
if (hasOrgAccess(scope)) {
|
|
44
|
+
const { resolved, missing } = resolveAll(scope, specs);
|
|
45
|
+
if (missing.length === 0) {
|
|
46
|
+
request._policyFilters = {
|
|
47
|
+
...request._policyFilters ?? {},
|
|
48
|
+
...resolved
|
|
49
|
+
};
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
reply.code(403).send({
|
|
53
|
+
success: false,
|
|
54
|
+
error: "Forbidden",
|
|
55
|
+
message: `Tenant context incomplete — missing: ${missing.join(", ")}`
|
|
56
|
+
});
|
|
29
57
|
return;
|
|
30
58
|
}
|
|
31
59
|
if (scope.kind === "public") {
|
|
@@ -44,57 +72,71 @@ function createTenantFilter(tenantField) {
|
|
|
44
72
|
};
|
|
45
73
|
}
|
|
46
74
|
/**
|
|
47
|
-
* Create flexible tenant filter middleware
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* Org context present = require auth and apply filter
|
|
75
|
+
* Create flexible tenant filter middleware (allowPublic).
|
|
76
|
+
* Same policy as the strict variant for authenticated callers, but
|
|
77
|
+
* allows public/unauthenticated requests through without filtering.
|
|
51
78
|
*/
|
|
52
|
-
function createFlexibleTenantFilter(
|
|
53
|
-
return async (request,
|
|
54
|
-
const scope =
|
|
79
|
+
function createFlexibleTenantFilter(specs) {
|
|
80
|
+
return async (request, reply) => {
|
|
81
|
+
const scope = getRequestScope(request);
|
|
55
82
|
if (isElevated(scope)) {
|
|
56
|
-
const
|
|
57
|
-
if (
|
|
83
|
+
const { resolved } = resolveAll(scope, specs);
|
|
84
|
+
if (Object.keys(resolved).length > 0) request._policyFilters = {
|
|
58
85
|
...request._policyFilters ?? {},
|
|
59
|
-
|
|
86
|
+
...resolved
|
|
60
87
|
};
|
|
61
88
|
return;
|
|
62
89
|
}
|
|
63
|
-
if (
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
90
|
+
if (hasOrgAccess(scope)) {
|
|
91
|
+
const { resolved, missing } = resolveAll(scope, specs);
|
|
92
|
+
if (missing.length === 0) {
|
|
93
|
+
request._policyFilters = {
|
|
94
|
+
...request._policyFilters ?? {},
|
|
95
|
+
...resolved
|
|
96
|
+
};
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
reply.code(403).send({
|
|
100
|
+
success: false,
|
|
101
|
+
error: "Forbidden",
|
|
102
|
+
message: `Tenant context incomplete — missing: ${missing.join(", ")}`
|
|
103
|
+
});
|
|
68
104
|
return;
|
|
69
105
|
}
|
|
70
106
|
};
|
|
71
107
|
}
|
|
72
108
|
/**
|
|
73
|
-
* Create tenant injection middleware
|
|
74
|
-
*
|
|
75
|
-
*
|
|
109
|
+
* Create tenant injection middleware.
|
|
110
|
+
* Walks the configured tenant fields and writes each into the request body.
|
|
111
|
+
* Fails closed if any required dimension is missing for non-elevated callers.
|
|
76
112
|
*/
|
|
77
|
-
function createTenantInjection(
|
|
113
|
+
function createTenantInjection(specs) {
|
|
78
114
|
return async (request, reply) => {
|
|
79
|
-
const scope =
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (
|
|
115
|
+
const scope = getRequestScope(request);
|
|
116
|
+
if (isElevated(scope) && !getOrgId(scope)) return;
|
|
117
|
+
const { resolved, missing } = resolveAll(scope, specs);
|
|
118
|
+
if (missing.length > 0) {
|
|
83
119
|
reply.code(403).send({
|
|
84
120
|
success: false,
|
|
85
121
|
error: "Forbidden",
|
|
86
|
-
message:
|
|
122
|
+
message: `Tenant context incomplete — missing: ${missing.join(", ")}`
|
|
87
123
|
});
|
|
88
124
|
return;
|
|
89
125
|
}
|
|
90
|
-
if (request.body) request.body
|
|
126
|
+
if (request.body) Object.assign(request.body, resolved);
|
|
91
127
|
};
|
|
92
128
|
}
|
|
93
129
|
function multiTenantPreset(options = {}) {
|
|
94
|
-
const { tenantField
|
|
95
|
-
|
|
96
|
-
const
|
|
97
|
-
|
|
130
|
+
const { tenantField, tenantFields, allowPublic = [] } = options;
|
|
131
|
+
if (tenantField !== void 0 && tenantFields !== void 0) throw new Error("multiTenantPreset: pass either `tenantField` (single-field) or `tenantFields` (multi-field), not both");
|
|
132
|
+
const specs = tenantFields ?? [{
|
|
133
|
+
field: tenantField ?? "organizationId",
|
|
134
|
+
type: "org"
|
|
135
|
+
}];
|
|
136
|
+
if (specs.length === 0) throw new Error("multiTenantPreset: `tenantFields` must contain at least one entry");
|
|
137
|
+
const strictTenantFilter = createTenantFilter(specs);
|
|
138
|
+
const flexibleTenantFilter = createFlexibleTenantFilter(specs);
|
|
139
|
+
const tenantInjection = createTenantInjection(specs);
|
|
98
140
|
const getFilter = (route) => allowPublic.includes(route) ? flexibleTenantFilter : strictTenantFilter;
|
|
99
141
|
return {
|
|
100
142
|
name: "multiTenant",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _ as isElevated, n as PUBLIC_SCOPE } from "./types-AOD8fxIw.mjs";
|
|
2
2
|
import { multiTenantPreset } from "./presets/multiTenant.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { f as requireRoles, n as allowPublic, s as requireAuth } from "./permissions-CH4cNwJi.mjs";
|
|
4
4
|
//#region src/presets/ownedByUser.ts
|
|
5
5
|
/**
|
|
6
6
|
* Create ownership check middleware.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
2
2
|
import { i as versionKey, r as tagVersionKey } from "./keys-qcD-TVJl.mjs";
|
|
3
|
-
import { t as hasEvents } from "./typeGuards-
|
|
4
|
-
import { t as MemoryCacheStore } from "./memory-
|
|
3
|
+
import { t as hasEvents } from "./typeGuards-CcFZXgU7.mjs";
|
|
4
|
+
import { t as MemoryCacheStore } from "./memory-Cp7_cAko.mjs";
|
|
5
5
|
import fp from "fastify-plugin";
|
|
6
6
|
//#region src/cache/QueryCache.ts
|
|
7
7
|
var QueryCache = class {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as EventTransport, n as EventHandler, r as EventLogger, t as DomainEvent } from "./EventTransport-
|
|
1
|
+
import { i as EventTransport, n as EventHandler, r as EventLogger, t as DomainEvent } from "./EventTransport-C4VheKeC.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/events/transports/redis-stream.d.ts
|
|
4
4
|
interface RedisStreamLike {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Bt as ResourceRegistry, R as IntrospectionPluginOptions, zt as RegisterOptions } from "../interface-
|
|
1
|
+
import { Bt as ResourceRegistry, R as IntrospectionPluginOptions, zt as RegisterOptions } from "../interface-B91alUzq.mjs";
|
|
2
2
|
import { FastifyPluginAsync } from "fastify";
|
|
3
3
|
|
|
4
4
|
//#region src/registry/introspectionPlugin.d.ts
|
package/dist/registry/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { n as introspectionPlugin_default, t as introspectionPlugin } from "../registry-
|
|
2
|
-
import { t as ResourceRegistry } from "../ResourceRegistry-
|
|
1
|
+
import { n as introspectionPlugin_default, t as introspectionPlugin } from "../registry-B3lRFBWo.mjs";
|
|
2
|
+
import { t as ResourceRegistry } from "../ResourceRegistry-DsHiG9cL.mjs";
|
|
3
3
|
export { ResourceRegistry, introspectionPlugin_default as introspectionPlugin, introspectionPlugin as introspectionPluginFn };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
2
|
+
import fp from "fastify-plugin";
|
|
3
|
+
//#region src/plugins/replyHelpers.ts
|
|
4
|
+
var replyHelpers_exports = /* @__PURE__ */ __exportAll({ replyHelpersPlugin: () => replyHelpersPlugin });
|
|
5
|
+
async function replyHelpersPluginFn(fastify) {
|
|
6
|
+
fastify.decorateReply("ok", function(data, statusCode = 200) {
|
|
7
|
+
return this.code(statusCode).send({
|
|
8
|
+
success: true,
|
|
9
|
+
data
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
fastify.decorateReply("fail", function(error, statusCode = 400) {
|
|
13
|
+
if (Array.isArray(error)) return this.code(statusCode).send({
|
|
14
|
+
success: false,
|
|
15
|
+
errors: error
|
|
16
|
+
});
|
|
17
|
+
return this.code(statusCode).send({
|
|
18
|
+
success: false,
|
|
19
|
+
error
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
fastify.decorateReply("paginated", function(result) {
|
|
23
|
+
return this.code(200).send({
|
|
24
|
+
success: true,
|
|
25
|
+
...result
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
fastify.decorateReply("stream", function(source, options) {
|
|
29
|
+
this.code(options.statusCode ?? 200);
|
|
30
|
+
this.header("content-type", options.contentType);
|
|
31
|
+
if (options.filename) this.header("content-disposition", `attachment; filename="${options.filename}"`);
|
|
32
|
+
return this.send(source);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
const replyHelpersPlugin = fp(replyHelpersPluginFn, {
|
|
36
|
+
name: "arc-reply-helpers",
|
|
37
|
+
fastify: "5.x"
|
|
38
|
+
});
|
|
39
|
+
//#endregion
|
|
40
|
+
export { replyHelpers_exports as n, replyHelpersPlugin as t };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { t as BaseController } from "./BaseController-
|
|
2
|
-
import {
|
|
1
|
+
import { t as BaseController } from "./BaseController-CpMfCXdn.mjs";
|
|
2
|
+
import { n as normalizePermissionResult } from "./applyPermissionResult-D6GPMsvh.mjs";
|
|
3
|
+
import { t as pluralize } from "./pluralize-Dckfq6US.mjs";
|
|
3
4
|
import { z } from "zod";
|
|
4
5
|
//#region src/integrations/mcp/createMcpServer.ts
|
|
5
6
|
/**
|
|
@@ -88,7 +89,9 @@ const PAGINATION_SHAPE = {
|
|
|
88
89
|
page: z.number().int().min(1).optional().describe("Page number (1-based)"),
|
|
89
90
|
limit: z.number().int().min(1).max(100).optional().describe("Items per page (max 100)"),
|
|
90
91
|
sort: z.string().optional().describe("Sort field, prefix with - for descending"),
|
|
91
|
-
search: z.string().optional().describe("Full-text search query")
|
|
92
|
+
search: z.string().optional().describe("Full-text search query"),
|
|
93
|
+
select: z.string().optional().describe("Comma-separated field list to project (e.g. 'name,price'). Prefix with '-' to exclude (e.g. '-description')."),
|
|
94
|
+
populate: z.string().optional().describe("Comma-separated relation paths to hydrate (e.g. 'supplier,category'). Follows Mongoose populate syntax when the adapter is MongoKit.")
|
|
92
95
|
};
|
|
93
96
|
/**
|
|
94
97
|
* Convert Arc fieldRules to a flat Zod shape.
|
|
@@ -179,6 +182,7 @@ function buildListShape(fieldRules, options) {
|
|
|
179
182
|
if (allHidden.has(name)) continue;
|
|
180
183
|
const rule = fieldRules[name];
|
|
181
184
|
if (!rule) continue;
|
|
185
|
+
if (rule.hidden || rule.systemManaged) continue;
|
|
182
186
|
const filterField = buildFieldSchema(rule);
|
|
183
187
|
shape[name] = filterField.optional();
|
|
184
188
|
if (allowedOperators?.length) {
|
|
@@ -212,11 +216,19 @@ function buildListShape(fieldRules, options) {
|
|
|
212
216
|
* | create | {} | {} | all input fields |
|
|
213
217
|
* | update | { id } | {} | input minus id |
|
|
214
218
|
* | delete | { id } | {} | undefined |
|
|
219
|
+
*
|
|
220
|
+
* **scopeOverride** — when a permission check (e.g. `requireApiKey()`) returns
|
|
221
|
+
* `PermissionResult.scope`, the MCP tool handler must install it on the request
|
|
222
|
+
* context the same way CRUD/action routes do. This parameter follows the exact
|
|
223
|
+
* same non-downgrade rule as `applyPermissionResult`: it overrides only when
|
|
224
|
+
* the session-derived scope is `public` (i.e. MCP called with `auth: false`).
|
|
225
|
+
* An authenticated session scope is never overwritten.
|
|
215
226
|
*/
|
|
216
|
-
function buildRequestContext(input, auth, operation, policyFilters) {
|
|
217
|
-
const
|
|
227
|
+
function buildRequestContext(input, auth, operation, policyFilters, scopeOverride) {
|
|
228
|
+
const sessionScope = buildScope(auth);
|
|
229
|
+
const scope = scopeOverride && sessionScope.kind === "public" ? scopeOverride : sessionScope;
|
|
218
230
|
const base = {
|
|
219
|
-
user: auth ? {
|
|
231
|
+
user: auth?.userId ? {
|
|
220
232
|
id: auth.userId,
|
|
221
233
|
_id: auth.userId,
|
|
222
234
|
...auth
|
|
@@ -264,7 +276,30 @@ function buildRequestContext(input, auth, operation, policyFilters) {
|
|
|
264
276
|
};
|
|
265
277
|
}
|
|
266
278
|
}
|
|
267
|
-
/**
|
|
279
|
+
/**
|
|
280
|
+
* Convert MCP operator keys (`price_gt`, `location_withinRadius`) to the
|
|
281
|
+
* nested object shape MongoKit's QueryParser expects (`{ price: { gt: ... } }`,
|
|
282
|
+
* `{ location: { withinRadius: ... } }`).
|
|
283
|
+
*
|
|
284
|
+
* **Comparison operators** (price_gt, age_lte, …): coerce filter values via
|
|
285
|
+
* the parser's coercion path.
|
|
286
|
+
*
|
|
287
|
+
* **Set operators** (status_in, role_nin, …): MongoKit accepts both
|
|
288
|
+
* comma-separated strings and arrays.
|
|
289
|
+
*
|
|
290
|
+
* **Existence** (deletedAt_exists): coerced to boolean by the parser.
|
|
291
|
+
*
|
|
292
|
+
* **Geo operators** (location_near, location_withinRadius, location_geoWithin,
|
|
293
|
+
* location_nearSphere): MongoKit 3.5.5+ — values are coordinate strings the
|
|
294
|
+
* parser's geo primitive handles. Without these in the allowlist, MCP agents
|
|
295
|
+
* couldn't pass geo filters at all and Arc would silently leak unfiltered docs.
|
|
296
|
+
*
|
|
297
|
+
* Keep this set in sync with MongoKit's QueryParser operators map (search for
|
|
298
|
+
* `private readonly operators` in QueryParser.ts) plus the geo operators
|
|
299
|
+
* recognized by `isGeoOperator` in primitives/geo.ts. We deliberately list
|
|
300
|
+
* them explicitly here rather than asking the parser at runtime — Arc must
|
|
301
|
+
* not import MongoKit internals just to know what an operator looks like.
|
|
302
|
+
*/
|
|
268
303
|
const OPERATOR_SUFFIXES = new Set([
|
|
269
304
|
"eq",
|
|
270
305
|
"ne",
|
|
@@ -274,7 +309,16 @@ const OPERATOR_SUFFIXES = new Set([
|
|
|
274
309
|
"lte",
|
|
275
310
|
"in",
|
|
276
311
|
"nin",
|
|
277
|
-
"exists"
|
|
312
|
+
"exists",
|
|
313
|
+
"size",
|
|
314
|
+
"type",
|
|
315
|
+
"like",
|
|
316
|
+
"contains",
|
|
317
|
+
"regex",
|
|
318
|
+
"near",
|
|
319
|
+
"nearSphere",
|
|
320
|
+
"withinRadius",
|
|
321
|
+
"geoWithin"
|
|
278
322
|
]);
|
|
279
323
|
function expandOperatorKeys(input) {
|
|
280
324
|
const out = {};
|
|
@@ -300,17 +344,23 @@ function expandOperatorKeys(input) {
|
|
|
300
344
|
}
|
|
301
345
|
function buildScope(auth) {
|
|
302
346
|
if (!auth) return { kind: "public" };
|
|
347
|
+
if (auth.clientId && auth.organizationId) return {
|
|
348
|
+
kind: "service",
|
|
349
|
+
clientId: auth.clientId,
|
|
350
|
+
organizationId: auth.organizationId,
|
|
351
|
+
scopes: auth.scopes
|
|
352
|
+
};
|
|
303
353
|
if (auth.organizationId) return {
|
|
304
354
|
kind: "member",
|
|
305
355
|
userId: auth.userId,
|
|
306
|
-
userRoles: [],
|
|
356
|
+
userRoles: auth.roles ?? [],
|
|
307
357
|
organizationId: auth.organizationId,
|
|
308
|
-
orgRoles: []
|
|
358
|
+
orgRoles: auth.orgRoles ?? []
|
|
309
359
|
};
|
|
310
360
|
return {
|
|
311
361
|
kind: "authenticated",
|
|
312
362
|
userId: auth.userId,
|
|
313
|
-
userRoles: []
|
|
363
|
+
userRoles: auth.roles ?? []
|
|
314
364
|
};
|
|
315
365
|
}
|
|
316
366
|
//#endregion
|
|
@@ -648,15 +698,15 @@ function createHandler(op, controller, resourceName, permissions) {
|
|
|
648
698
|
}],
|
|
649
699
|
isError: true
|
|
650
700
|
};
|
|
651
|
-
const
|
|
652
|
-
if (
|
|
701
|
+
const permResult = await evaluatePermission(permissions?.[op], ctx.session, resourceName, op, input);
|
|
702
|
+
if (permResult && !permResult.granted) return {
|
|
653
703
|
content: [{
|
|
654
704
|
type: "text",
|
|
655
|
-
text: `Permission denied: ${op} on ${resourceName}`
|
|
705
|
+
text: `Permission denied: ${op} on ${resourceName}${permResult.reason ? ` — ${permResult.reason}` : ""}`
|
|
656
706
|
}],
|
|
657
707
|
isError: true
|
|
658
708
|
};
|
|
659
|
-
return toCallToolResult(await method(buildRequestContext(input, ctx.session, op,
|
|
709
|
+
return toCallToolResult(await method(buildRequestContext(input, ctx.session, op, permResult?.filters, permResult?.scope)));
|
|
660
710
|
} catch (err) {
|
|
661
711
|
const msg = err instanceof Error ? err.message : String(err);
|
|
662
712
|
ctx.log("error", `${resourceName}.${op}: ${msg}`).catch(() => {});
|
|
@@ -698,10 +748,13 @@ function createAdditionalRouteHandler(route, controller, hasId) {
|
|
|
698
748
|
/**
|
|
699
749
|
* Evaluate a resource's permission check in MCP context.
|
|
700
750
|
*
|
|
701
|
-
* Returns
|
|
702
|
-
* -
|
|
703
|
-
*
|
|
704
|
-
*
|
|
751
|
+
* Returns the full normalized `PermissionResult` so the caller can honor
|
|
752
|
+
* ALL side-effects (filters + scope) consistently with CRUD/action routes.
|
|
753
|
+
* Returns `null` when no permission is defined (= allow, no side effects).
|
|
754
|
+
*
|
|
755
|
+
* Promoting booleans to `PermissionResult` via the shared `normalizePermissionResult`
|
|
756
|
+
* helper keeps the contract aligned with the rest of Arc — there is a single
|
|
757
|
+
* normalization path for every call site.
|
|
705
758
|
*/
|
|
706
759
|
async function evaluatePermission(check, session, resource, action, input) {
|
|
707
760
|
if (!check) return null;
|
|
@@ -710,7 +763,7 @@ async function evaluatePermission(check, session, resource, action, input) {
|
|
|
710
763
|
_id: session.userId,
|
|
711
764
|
...session
|
|
712
765
|
} : null;
|
|
713
|
-
|
|
766
|
+
return normalizePermissionResult(await check({
|
|
714
767
|
user,
|
|
715
768
|
request: {
|
|
716
769
|
user,
|
|
@@ -724,11 +777,7 @@ async function evaluatePermission(check, session, resource, action, input) {
|
|
|
724
777
|
resourceId: typeof input.id === "string" ? input.id : void 0,
|
|
725
778
|
params: {},
|
|
726
779
|
data: input
|
|
727
|
-
});
|
|
728
|
-
if (typeof result === "boolean") return result ? null : false;
|
|
729
|
-
const permResult = result;
|
|
730
|
-
if (!permResult.granted) return false;
|
|
731
|
-
return permResult.filters ?? null;
|
|
780
|
+
}));
|
|
732
781
|
}
|
|
733
782
|
/**
|
|
734
783
|
* Derive a fieldRules-shaped object from the adapter's auto-generated body
|
package/dist/rpc/index.d.mts
CHANGED
package/dist/rpc/index.mjs
CHANGED