@classytic/arc 2.9.1 → 2.10.8
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 +20 -91
- package/dist/{BaseController-Vu2yc56T.mjs → BaseController-DVNKvoX4.mjs} +154 -170
- package/dist/{ResourceRegistry-Dq3_zBQP.mjs → ResourceRegistry-CcN2LVrc.mjs} +1 -1
- package/dist/actionPermissions-TUVR3uiZ.mjs +22 -0
- package/dist/adapters/index.d.mts +3 -3
- package/dist/adapters/index.mjs +2 -2
- package/dist/{adapters-BBqAVvPK.mjs → adapters-BXY4i-hw.mjs} +210 -41
- package/dist/audit/index.d.mts +38 -3
- package/dist/audit/index.mjs +54 -22
- package/dist/auth/index.d.mts +2 -2
- package/dist/auth/index.mjs +3 -3
- package/dist/cache/index.d.mts +17 -15
- package/dist/cache/index.mjs +16 -15
- package/dist/{caching-CjybdRwx.mjs → caching-3h93rkJM.mjs} +8 -3
- package/dist/cli/commands/describe.mjs +1 -1
- package/dist/cli/commands/docs.mjs +2 -2
- package/dist/cli/commands/init.mjs +1 -1
- package/dist/cli/commands/introspect.mjs +1 -1
- package/dist/context/index.d.mts +58 -0
- package/dist/context/index.mjs +2 -0
- package/dist/core/index.d.mts +2 -2
- package/dist/core/index.mjs +3 -4
- package/dist/{defineResource-C__jkwvs.mjs → core-3MWJosCH.mjs} +174 -94
- package/dist/{createActionRouter-DH1YFL9m.mjs → createActionRouter-C8UUB3Px.mjs} +1 -1
- package/dist/{createApp-CBJUJKGP.mjs → createApp-BwnEAO2h.mjs} +53 -19
- package/dist/docs/index.d.mts +1 -1
- package/dist/docs/index.mjs +2 -2
- package/dist/{elevation-DxQ6ACbt.mjs → elevation-Dci0AYLT.mjs} +2 -2
- package/dist/errorHandler-2ii4RIYr.d.mts +114 -0
- package/dist/{errorHandler-CZDW4EXS.mjs → errorHandler-CSxe7KIM.mjs} +1 -1
- package/dist/{eventPlugin-Dl7MoVWH.mjs → eventPlugin-ByU4Cv0e.mjs} +1 -1
- package/dist/{eventPlugin-BxvaCIZF.d.mts → eventPlugin-D1ThQ1Pp.d.mts} +1 -1
- package/dist/events/index.d.mts +8 -5
- package/dist/events/index.mjs +87 -52
- 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/{types-DZi1aYhm.d.mts → fields-C8Y0XLAu.d.mts} +122 -2
- package/dist/hooks/index.d.mts +1 -1
- package/dist/idempotency/index.d.mts +5 -2
- package/dist/idempotency/index.mjs +46 -37
- package/dist/{interface-YrWsmKqE.d.mts → index-BGbpGVyM.d.mts} +2107 -2756
- package/dist/{index-CtGKT0lf.d.mts → index-BziRPS4H.d.mts} +81 -7
- package/dist/{index-C-xjcA6F.d.mts → index-C_Noptz-.d.mts} +284 -409
- package/dist/{index-Cibkchnx.d.mts → index-EqQN6p0W.d.mts} +3 -3
- package/dist/index.d.mts +6 -219
- package/dist/index.mjs +10 -131
- 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 +1 -1
- package/dist/integrations/mcp/testing.d.mts +1 -1
- package/dist/integrations/mcp/testing.mjs +1 -1
- package/dist/interface-yhyb_pLY.d.mts +77 -0
- package/dist/logger/index.d.mts +81 -0
- package/dist/{logger-CDjpjySd.mjs → logger/index.mjs} +1 -6
- package/dist/{memory-BFAYkf8H.mjs → memory-DqI-449b.mjs} +23 -8
- package/dist/middleware/index.d.mts +109 -0
- package/dist/middleware/index.mjs +70 -0
- package/dist/multipartBody-CUQGVlM_.mjs +123 -0
- package/dist/{openapi-CXuTG1M9.mjs → openapi-DpNpqBmo.mjs} +9 -7
- package/dist/org/index.d.mts +2 -2
- package/dist/permissions/index.d.mts +3 -4
- package/dist/permissions/index.mjs +5 -5
- package/dist/{permissions-oNZawnkR.mjs → permissions-wkqRwicB.mjs} +315 -397
- package/dist/pipe-CGJxqDGx.mjs +62 -0
- package/dist/pipeline/index.d.mts +62 -0
- package/dist/pipeline/index.mjs +53 -0
- package/dist/plugins/index.d.mts +23 -3
- package/dist/plugins/index.mjs +9 -11
- package/dist/plugins/response-cache.mjs +1 -1
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/presets/filesUpload.d.mts +3 -3
- package/dist/presets/filesUpload.mjs +255 -1
- package/dist/presets/index.d.mts +1 -1
- package/dist/presets/index.mjs +2 -2
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/presets/multiTenant.mjs +43 -9
- package/dist/presets/search.d.mts +91 -4
- package/dist/presets/search.mjs +1 -1
- package/dist/{presets-hM4WhNWY.mjs → presets-CrwOvuXI.mjs} +1 -1
- package/dist/{queryCachePlugin-DbUVroUG.mjs → queryCachePlugin-ChLNZvFT.mjs} +9 -9
- package/dist/{queryCachePlugin-CnTZZTC5.d.mts → queryCachePlugin-Dumka73q.d.mts} +1 -1
- package/dist/{queryParser-Cs-6SHQK.mjs → queryParser-NR__Qiju.mjs} +69 -2
- package/dist/{redis-stream-Bz-4q96t.d.mts → redis-stream-bkO88VHx.d.mts} +1 -1
- package/dist/registry/index.d.mts +1 -1
- package/dist/registry/index.mjs +1 -1
- package/dist/{requestContext-DYtmNpm5.mjs → requestContext-C38GskNt.mjs} +1 -1
- package/dist/{resourceToTools-C3cWymnW.mjs → resourceToTools-BhF3JV5p.mjs} +8 -3
- package/dist/scope/index.d.mts +2 -2
- package/dist/scope/index.mjs +2 -2
- package/dist/{sse-CJpt7LGI.mjs → sse-D8UeDwis.mjs} +1 -1
- package/dist/{store-helpers-DFiZl5TL.mjs → store-helpers-DYYUQbQN.mjs} +4 -0
- package/dist/testing/index.d.mts +6 -5
- package/dist/testing/index.mjs +17 -10
- package/dist/types/index.d.mts +5 -5
- package/dist/types/index.mjs +1 -31
- package/dist/types-CDnTEpga.mjs +27 -0
- package/dist/{types-CoSzA-s-.d.mts → types-CVKBssX5.d.mts} +1 -1
- package/dist/{types-CunEX4UX.d.mts → types-CVdgPXBW.d.mts} +20 -7
- package/dist/utils/index.d.mts +277 -3
- package/dist/utils/index.mjs +4 -5
- package/dist/{utils-B7FuRr9w.mjs → utils-LMwVidKy.mjs} +303 -2
- package/dist/{versioning-Cm8qoFDg.mjs → versioning-B6mimogM.mjs} +3 -5
- package/dist/versioning-CeUXHfjw.d.mts +117 -0
- package/package.json +31 -18
- package/skills/arc/SKILL.md +8 -12
- package/skills/arc/references/production.md +0 -41
- package/dist/circuitBreaker-CvXkjfrW.d.mts +0 -206
- package/dist/circuitBreaker-l18oRgL5.mjs +0 -284
- package/dist/core-DNncu0xF.mjs +0 -34
- package/dist/dynamic/index.d.mts +0 -93
- package/dist/dynamic/index.mjs +0 -122
- package/dist/errorHandler-DixGcttC.d.mts +0 -218
- package/dist/fields-BC7zcmI9.d.mts +0 -121
- package/dist/filesUpload-q8oHt--L.mjs +0 -377
- package/dist/interface-DplgQO2e.d.mts +0 -54
- package/dist/policies/index.d.mts +0 -425
- package/dist/policies/index.mjs +0 -318
- package/dist/rpc/index.d.mts +0 -90
- package/dist/rpc/index.mjs +0 -248
- /package/dist/{EventTransport-CqZ8FyM_.d.mts → EventTransport-CfVEGaEl.d.mts} +0 -0
- /package/dist/{applyPermissionResult-bqGpo9ML.mjs → applyPermissionResult-QhV1Pa-g.mjs} +0 -0
- /package/dist/{constants-Cxde4rpC.mjs → constants-BhY1OHoH.mjs} +0 -0
- /package/dist/{elevation-B6S5csVA.d.mts → elevation-s5ykdNHr.d.mts} +0 -0
- /package/dist/{errors-CqWnSqM-.mjs → errors-BqdUDja_.mjs} +0 -0
- /package/dist/{fields-CU6FlaDV.mjs → fields-CTMWOUDt.mjs} +0 -0
- /package/dist/{keys-qcD-TVJl.mjs → keys-nWQGUTu1.mjs} +0 -0
- /package/dist/{types-ZUu_h0jp.mjs → types-D57iXYb8.mjs} +0 -0
- /package/dist/{types-BD85MlEK.d.mts → types-tgR4Pt8F.d.mts} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import "../constants-
|
|
1
|
+
import "../constants-BhY1OHoH.mjs";
|
|
2
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
4
|
/**
|
|
@@ -10,6 +10,20 @@ function resolveSpec(scope, spec) {
|
|
|
10
10
|
if (spec.type === "org") return getOrgId(scope);
|
|
11
11
|
if (spec.type === "team") return getTeamId(scope);
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Stash the resolved tenant field map on the request so `BaseController`
|
|
15
|
+
* can forward it to the repository layer as top-level options. Needed by
|
|
16
|
+
* plugin-scoped repos (mongokit's `multiTenantPlugin`) that read tenant
|
|
17
|
+
* from `context.<field>` rather than from filter/query/data stamping.
|
|
18
|
+
*/
|
|
19
|
+
function stashTenantFields(request, resolved) {
|
|
20
|
+
if (Object.keys(resolved).length === 0) return;
|
|
21
|
+
const target = request;
|
|
22
|
+
target._tenantFields = {
|
|
23
|
+
...target._tenantFields ?? {},
|
|
24
|
+
...resolved
|
|
25
|
+
};
|
|
26
|
+
}
|
|
13
27
|
/** Resolve every spec — returns the partial map of fields that have a value. */
|
|
14
28
|
function resolveAll(scope, specs) {
|
|
15
29
|
const resolved = {};
|
|
@@ -34,10 +48,13 @@ function createTenantFilter(specs) {
|
|
|
34
48
|
const scope = getRequestScope(request);
|
|
35
49
|
if (isElevated(scope)) {
|
|
36
50
|
const { resolved } = resolveAll(scope, specs);
|
|
37
|
-
if (Object.keys(resolved).length > 0)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
51
|
+
if (Object.keys(resolved).length > 0) {
|
|
52
|
+
request._policyFilters = {
|
|
53
|
+
...request._policyFilters ?? {},
|
|
54
|
+
...resolved
|
|
55
|
+
};
|
|
56
|
+
stashTenantFields(request, resolved);
|
|
57
|
+
}
|
|
41
58
|
return;
|
|
42
59
|
}
|
|
43
60
|
if (hasOrgAccess(scope)) {
|
|
@@ -47,6 +64,7 @@ function createTenantFilter(specs) {
|
|
|
47
64
|
...request._policyFilters ?? {},
|
|
48
65
|
...resolved
|
|
49
66
|
};
|
|
67
|
+
stashTenantFields(request, resolved);
|
|
50
68
|
return;
|
|
51
69
|
}
|
|
52
70
|
reply.code(403).send({
|
|
@@ -81,10 +99,13 @@ function createFlexibleTenantFilter(specs) {
|
|
|
81
99
|
const scope = getRequestScope(request);
|
|
82
100
|
if (isElevated(scope)) {
|
|
83
101
|
const { resolved } = resolveAll(scope, specs);
|
|
84
|
-
if (Object.keys(resolved).length > 0)
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
102
|
+
if (Object.keys(resolved).length > 0) {
|
|
103
|
+
request._policyFilters = {
|
|
104
|
+
...request._policyFilters ?? {},
|
|
105
|
+
...resolved
|
|
106
|
+
};
|
|
107
|
+
stashTenantFields(request, resolved);
|
|
108
|
+
}
|
|
88
109
|
return;
|
|
89
110
|
}
|
|
90
111
|
if (hasOrgAccess(scope)) {
|
|
@@ -94,6 +115,7 @@ function createFlexibleTenantFilter(specs) {
|
|
|
94
115
|
...request._policyFilters ?? {},
|
|
95
116
|
...resolved
|
|
96
117
|
};
|
|
118
|
+
stashTenantFields(request, resolved);
|
|
97
119
|
return;
|
|
98
120
|
}
|
|
99
121
|
reply.code(403).send({
|
|
@@ -109,6 +131,14 @@ function createFlexibleTenantFilter(specs) {
|
|
|
109
131
|
* Create tenant injection middleware.
|
|
110
132
|
* Walks the configured tenant fields and writes each into the request body.
|
|
111
133
|
* Fails closed if any required dimension is missing for non-elevated callers.
|
|
134
|
+
*
|
|
135
|
+
* Also stashes the resolved fields on `request._tenantFields` so
|
|
136
|
+
* `BaseController.tenantRepoOptions()` can forward them to the repo layer
|
|
137
|
+
* as top-level options — needed by plugin-scoped repos like mongokit's
|
|
138
|
+
* `multiTenantPlugin`, which reads tenant from `context.<field>` rather
|
|
139
|
+
* than from `data.<field>`. Without this forwarding, multi-field preset
|
|
140
|
+
* writes (update/delete) work only when the plugin's `allowDataInjection`
|
|
141
|
+
* fallback covers the operation's policy key, which is write-only.
|
|
112
142
|
*/
|
|
113
143
|
function createTenantInjection(specs) {
|
|
114
144
|
return async (request, reply) => {
|
|
@@ -124,6 +154,10 @@ function createTenantInjection(specs) {
|
|
|
124
154
|
return;
|
|
125
155
|
}
|
|
126
156
|
if (request.body) Object.assign(request.body, resolved);
|
|
157
|
+
request._tenantFields = {
|
|
158
|
+
...request._tenantFields ?? {},
|
|
159
|
+
...resolved
|
|
160
|
+
};
|
|
127
161
|
};
|
|
128
162
|
}
|
|
129
163
|
function multiTenantPreset(options = {}) {
|
|
@@ -1,7 +1,94 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { Ot as ControllerHandler, Tt as RouteMcpConfig, _t as PresetResult, wt as RouteDefinition } from "../index-BGbpGVyM.mjs";
|
|
2
|
+
import { c as PermissionCheck } from "../fields-C8Y0XLAu.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/presets/search.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Search Preset — backend-agnostic search / vector / embed routes
|
|
7
|
+
*
|
|
8
|
+
* Arc doesn't ship a search engine. It ships the **routes** that front one.
|
|
9
|
+
* The preset mounts up to three standard routes on a resource:
|
|
10
|
+
*
|
|
11
|
+
* POST /search → full-text / engine-backed search (ES, OpenSearch, Algolia, Typesense, …)
|
|
12
|
+
* POST /search-similar → vector / semantic similarity (Atlas, Pinecone, Qdrant, Milvus, …)
|
|
13
|
+
* POST /embed → text / media → vector embedding
|
|
14
|
+
*
|
|
15
|
+
* Each route is OFF by default. You opt in by providing a `handler` that calls
|
|
16
|
+
* whatever backend you use. The preset contributes:
|
|
17
|
+
* - Default path + method + permissions (customisable)
|
|
18
|
+
* - OpenAPI description + MCP tool naming
|
|
19
|
+
* - Arc envelope + pipeline (permissions, audit, hooks)
|
|
20
|
+
* - Sensible Fastify route schema defaults
|
|
21
|
+
*
|
|
22
|
+
* Paths are fully customisable — if your product wants `/abc/search` or a
|
|
23
|
+
* GET-based autocomplete, pass `path`/`method` overrides or use `routes` for
|
|
24
|
+
* fully bespoke endpoints.
|
|
25
|
+
*
|
|
26
|
+
* @example MongoKit wiring (elasticSearchPlugin + vectorPlugin)
|
|
27
|
+
* ```typescript
|
|
28
|
+
* import { Repository, methodRegistryPlugin, elasticSearchPlugin } from '@classytic/mongokit';
|
|
29
|
+
* import { vectorPlugin } from '@classytic/mongokit/ai';
|
|
30
|
+
* import { searchPreset } from '@classytic/arc/presets/search';
|
|
31
|
+
*
|
|
32
|
+
* const productRepo = new Repository(Product, [
|
|
33
|
+
* methodRegistryPlugin(),
|
|
34
|
+
* elasticSearchPlugin({ client: esClient, indexName: 'products' }),
|
|
35
|
+
* vectorPlugin({ fields: [{ path: 'embedding', dimensions: 1536 }], embedFn }),
|
|
36
|
+
* ]);
|
|
37
|
+
*
|
|
38
|
+
* defineResource({
|
|
39
|
+
* name: 'product',
|
|
40
|
+
* adapter: createMongooseAdapter({ model: Product, repository: productRepo }),
|
|
41
|
+
* presets: [
|
|
42
|
+
* searchPreset({
|
|
43
|
+
* search: { handler: (req) => productRepo.search(req.body.query, req.body) },
|
|
44
|
+
* similar: { handler: (req) => productRepo.searchSimilar(req.body.query, req.body) },
|
|
45
|
+
* }),
|
|
46
|
+
* ],
|
|
47
|
+
* });
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @example Custom vector backend (Pinecone)
|
|
51
|
+
* ```typescript
|
|
52
|
+
* searchPreset({
|
|
53
|
+
* similar: {
|
|
54
|
+
* path: '/vector-search', // custom path
|
|
55
|
+
* handler: async (req) => {
|
|
56
|
+
* const hits = await pinecone.query({
|
|
57
|
+
* vector: req.body.vector,
|
|
58
|
+
* topK: req.body.topK ?? 10,
|
|
59
|
+
* });
|
|
60
|
+
* return hits.matches;
|
|
61
|
+
* },
|
|
62
|
+
* schema: { body: { type: 'object', properties: { vector: { type: 'array' }, topK: { type: 'integer' } } } },
|
|
63
|
+
* mcp: false, // no MCP tool for this one
|
|
64
|
+
* },
|
|
65
|
+
* // Extra app-specific route
|
|
66
|
+
* routes: [
|
|
67
|
+
* {
|
|
68
|
+
* method: 'GET',
|
|
69
|
+
* path: '/autocomplete',
|
|
70
|
+
* handler: async (req) => algolia.suggest(req.query.q as string),
|
|
71
|
+
* permissions: allowPublic(),
|
|
72
|
+
* },
|
|
73
|
+
* ],
|
|
74
|
+
* });
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
/**
|
|
78
|
+
* Feature-detected search surface. Arc's `RepositoryLike` is the cross-kit
|
|
79
|
+
* minimum (repo-core's `MinimalRepo & Partial<StandardRepo>`) and does not
|
|
80
|
+
* declare search/vector/embed methods — those are kit-specific (mongokit's
|
|
81
|
+
* `elasticSearchPlugin` + `vectorPlugin`, pgkit's `pgvector` extension,
|
|
82
|
+
* sqlitekit FTS5, or a standalone Pinecone/Algolia adapter). We type the
|
|
83
|
+
* `repository` option locally so the preset can auto-wire handlers when a
|
|
84
|
+
* kit happens to ship these methods, without forcing every repo to declare
|
|
85
|
+
* them.
|
|
86
|
+
*/
|
|
87
|
+
interface SearchableRepository {
|
|
88
|
+
search?(query: unknown, options?: unknown): Promise<unknown>;
|
|
89
|
+
searchSimilar?(query: unknown, options?: unknown): Promise<unknown>;
|
|
90
|
+
embed?(input: unknown): Promise<number[]>;
|
|
91
|
+
}
|
|
5
92
|
/**
|
|
6
93
|
* Handler contract — receives arc's `IRequestContext` (same as any `actions` or
|
|
7
94
|
* non-raw route handler) and returns either the raw result (wrapped into
|
|
@@ -57,7 +144,7 @@ interface SearchPresetOptions {
|
|
|
57
144
|
* Sections set to `true` REQUIRE `repository` (otherwise the route is
|
|
58
145
|
* skipped silently). Sections with an explicit `handler` ignore this field.
|
|
59
146
|
*/
|
|
60
|
-
repository?:
|
|
147
|
+
repository?: SearchableRepository;
|
|
61
148
|
/** Full-text / engine-backed search route. Opt-in. */
|
|
62
149
|
search?: SearchSection;
|
|
63
150
|
/** Vector / semantic similarity route. Opt-in. */
|
|
@@ -88,4 +175,4 @@ interface SearchPresetOptions {
|
|
|
88
175
|
*/
|
|
89
176
|
declare function searchPreset(options?: SearchPresetOptions): PresetResult;
|
|
90
177
|
//#endregion
|
|
91
|
-
export { SearchHandler, SearchPresetOptions, SearchRouteConfig, SearchSection, searchPreset };
|
|
178
|
+
export { SearchHandler, SearchPresetOptions, SearchRouteConfig, SearchSection, SearchableRepository, searchPreset };
|
package/dist/presets/search.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { _ as isElevated, n as PUBLIC_SCOPE } from "./types-AOD8fxIw.mjs";
|
|
2
2
|
import { multiTenantPreset } from "./presets/multiTenant.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { C as requireAuth, T as requireRoles, y as allowPublic } from "./permissions-wkqRwicB.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
|
-
import { i as versionKey, r as tagVersionKey } from "./keys-
|
|
2
|
+
import { i as versionKey, r as tagVersionKey } from "./keys-nWQGUTu1.mjs";
|
|
3
3
|
import { t as hasEvents } from "./typeGuards-Cj5Rgvlg.mjs";
|
|
4
|
-
import { t as MemoryCacheStore } from "./memory-
|
|
4
|
+
import { t as MemoryCacheStore } from "./memory-DqI-449b.mjs";
|
|
5
5
|
import fp from "fastify-plugin";
|
|
6
6
|
//#region src/cache/QueryCache.ts
|
|
7
7
|
var QueryCache = class {
|
|
@@ -33,17 +33,17 @@ var QueryCache = class {
|
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
35
|
async set(key, data, config) {
|
|
36
|
-
const
|
|
37
|
-
const
|
|
36
|
+
const staleTimeSec = config.staleTime ?? 0;
|
|
37
|
+
const totalTtlSec = staleTimeSec + (config.gcTime ?? 60);
|
|
38
38
|
const now = Date.now();
|
|
39
39
|
const envelope = {
|
|
40
40
|
data,
|
|
41
41
|
createdAt: now,
|
|
42
|
-
staleAfter: now +
|
|
43
|
-
expiresAt: now +
|
|
42
|
+
staleAfter: now + staleTimeSec * 1e3,
|
|
43
|
+
expiresAt: now + totalTtlSec * 1e3,
|
|
44
44
|
tags: config.tags ?? []
|
|
45
45
|
};
|
|
46
|
-
await this.store.set(key, envelope,
|
|
46
|
+
await this.store.set(key, envelope, totalTtlSec);
|
|
47
47
|
}
|
|
48
48
|
async invalidate(key) {
|
|
49
49
|
await this.store.delete(key);
|
|
@@ -56,7 +56,7 @@ var QueryCache = class {
|
|
|
56
56
|
async bumpResourceVersion(resource) {
|
|
57
57
|
const key = versionKey(resource);
|
|
58
58
|
const newVersion = Date.now();
|
|
59
|
-
await this.store.set(key, newVersion,
|
|
59
|
+
await this.store.set(key, newVersion, 1440 * 60);
|
|
60
60
|
}
|
|
61
61
|
/** Get current version for a tag */
|
|
62
62
|
async getTagVersion(tag) {
|
|
@@ -66,7 +66,7 @@ var QueryCache = class {
|
|
|
66
66
|
async bumpTagVersion(tag) {
|
|
67
67
|
const key = tagVersionKey(tag);
|
|
68
68
|
const newVersion = Date.now();
|
|
69
|
-
await this.store.set(key, newVersion,
|
|
69
|
+
await this.store.set(key, newVersion, 1440 * 60);
|
|
70
70
|
}
|
|
71
71
|
};
|
|
72
72
|
//#endregion
|
|
@@ -1,4 +1,71 @@
|
|
|
1
|
-
import { m as RESERVED_QUERY_PARAMS } from "./constants-
|
|
1
|
+
import { m as RESERVED_QUERY_PARAMS } from "./constants-BhY1OHoH.mjs";
|
|
2
|
+
//#region src/utils/simpleEqualityMatcher.ts
|
|
3
|
+
/**
|
|
4
|
+
* `simpleEqualityMatcher` — a minimal, dialect-agnostic flat-key equality
|
|
5
|
+
* matcher for `DataAdapter.matchesFilter` / `BaseController({ matchesFilter })`.
|
|
6
|
+
*
|
|
7
|
+
* **What it does:** for each `[key, expected]` in the filter, compares
|
|
8
|
+
* `item[key]` to `expected` via string coercion (so Mongo `ObjectId` values
|
|
9
|
+
* match their string representation) and returns `true` only if every
|
|
10
|
+
* filter entry matches. Array item values are matched implicitly (contains).
|
|
11
|
+
*
|
|
12
|
+
* **What it does NOT do:**
|
|
13
|
+
* - No `$eq` / `$ne` / `$in` / `$nin` / `$gt` / `$lt` / `$regex` / `$exists`
|
|
14
|
+
* - No `$and` / `$or`
|
|
15
|
+
* - No dot-path traversal (`"owner.id"`)
|
|
16
|
+
* - No schema-specific coercion
|
|
17
|
+
*
|
|
18
|
+
* **Why it exists:** 95%+ of arc's `_policyFilters` are produced by built-in
|
|
19
|
+
* permission helpers and are shaped like `{ ownerId: "u1" }` or
|
|
20
|
+
* `{ organizationId: "org_x" }` — flat equality. For that common shape,
|
|
21
|
+
* this helper is a safe, tested, 15-line defense-in-depth matcher that
|
|
22
|
+
* hosts using minimal repos (no `getOne(compoundFilter)` DB path) can opt
|
|
23
|
+
* into without arc shipping a full Mongo-syntax engine.
|
|
24
|
+
*
|
|
25
|
+
* **When to use:**
|
|
26
|
+
* - Your adapter/repo doesn't natively filter on `getOne(compoundFilter)`
|
|
27
|
+
* - Your `_policyFilters` are flat equality (from arc's built-in permission helpers)
|
|
28
|
+
* - You want defense-in-depth on `validateItemAccess` / `fetchDetailed`'s `getById` fallback
|
|
29
|
+
*
|
|
30
|
+
* **When NOT to use:**
|
|
31
|
+
* - Your `_policyFilters` use operators (`$in`, `$ne`, etc.) — supply a
|
|
32
|
+
* native matcher (mongokit's repo does the filter at the DB layer; for
|
|
33
|
+
* custom repos, wrap the kit's own predicate engine).
|
|
34
|
+
* - You're a mongokit / sqlitekit / Prisma user — the DB-level filter
|
|
35
|
+
* applied by `getOne(compoundFilter)` already covers this.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* import { simpleEqualityMatcher } from '@classytic/arc/utils';
|
|
40
|
+
*
|
|
41
|
+
* // On a custom adapter
|
|
42
|
+
* const adapter: DataAdapter = {
|
|
43
|
+
* repository,
|
|
44
|
+
* type: 'custom',
|
|
45
|
+
* name: 'in-memory',
|
|
46
|
+
* matchesFilter: simpleEqualityMatcher,
|
|
47
|
+
* };
|
|
48
|
+
*
|
|
49
|
+
* // Or directly on BaseController for ad-hoc controllers
|
|
50
|
+
* new BaseController(repo, { matchesFilter: simpleEqualityMatcher });
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
function simpleEqualityMatcher(item, filters) {
|
|
54
|
+
if (!item || typeof item !== "object") return false;
|
|
55
|
+
const obj = item;
|
|
56
|
+
for (const [key, expected] of Object.entries(filters)) {
|
|
57
|
+
if (expected && typeof expected === "object" && !Array.isArray(expected) && Object.getPrototypeOf(expected) === Object.prototype && Object.keys(expected).some((k) => k.startsWith("$"))) return false;
|
|
58
|
+
const actual = obj[key];
|
|
59
|
+
if (Array.isArray(actual)) {
|
|
60
|
+
const expectedStr = String(expected);
|
|
61
|
+
if (!actual.some((v) => String(v) === expectedStr)) return false;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (String(actual) !== String(expected)) return false;
|
|
65
|
+
}
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
2
69
|
//#region src/utils/queryParser.ts
|
|
3
70
|
/**
|
|
4
71
|
* Arc Query Parser - Default URL-to-Query Parser
|
|
@@ -349,4 +416,4 @@ function createQueryParser(options) {
|
|
|
349
416
|
return new ArcQueryParser(options);
|
|
350
417
|
}
|
|
351
418
|
//#endregion
|
|
352
|
-
export { createQueryParser as n, ArcQueryParser as t };
|
|
419
|
+
export { createQueryParser as n, simpleEqualityMatcher as r, ArcQueryParser as t };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as EventLogger, n as DomainEvent, o as EventTransport, r as EventHandler } from "./EventTransport-
|
|
1
|
+
import { i as EventLogger, n as DomainEvent, o as EventTransport, r as EventHandler } from "./EventTransport-CfVEGaEl.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/events/transports/redis-stream.d.ts
|
|
4
4
|
interface RedisStreamLike {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { R as RegisterOptions, k as IntrospectionPluginOptions, z as ResourceRegistry } from "../index-BGbpGVyM.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
1
|
import { n as introspectionPlugin_default, t as introspectionPlugin } from "../registry-B0Wl7uVV.mjs";
|
|
2
|
-
import { t as ResourceRegistry } from "../ResourceRegistry-
|
|
2
|
+
import { t as ResourceRegistry } from "../ResourceRegistry-CcN2LVrc.mjs";
|
|
3
3
|
export { ResourceRegistry, introspectionPlugin_default as introspectionPlugin, introspectionPlugin as introspectionPluginFn };
|
|
@@ -11,7 +11,7 @@ import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
11
11
|
*
|
|
12
12
|
* @example
|
|
13
13
|
* ```typescript
|
|
14
|
-
* import { requestContext } from '@classytic/arc';
|
|
14
|
+
* import { requestContext } from '@classytic/arc/context';
|
|
15
15
|
*
|
|
16
16
|
* // Anywhere in the call stack — no parameter passing needed
|
|
17
17
|
* async function auditAction(action: string) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { t as BaseController } from "./BaseController-
|
|
2
|
-
import { n as normalizePermissionResult } from "./applyPermissionResult-
|
|
1
|
+
import { t as BaseController } from "./BaseController-DVNKvoX4.mjs";
|
|
2
|
+
import { n as normalizePermissionResult } from "./applyPermissionResult-QhV1Pa-g.mjs";
|
|
3
|
+
import { t as resolveActionPermission } from "./actionPermissions-TUVR3uiZ.mjs";
|
|
3
4
|
import { t as pluralize } from "./pluralize-CWP6MB39.mjs";
|
|
4
5
|
import { z } from "zod";
|
|
5
6
|
//#region src/integrations/mcp/createMcpServer.ts
|
|
@@ -655,7 +656,11 @@ function resourceToTools(resource, config = {}) {
|
|
|
655
656
|
}
|
|
656
657
|
const toolName = prefix ? `${prefix}_${actionName}_${resource.name}` : `${actionName}_${resource.name}`;
|
|
657
658
|
const handler = typeof entry === "function" ? entry : def.handler;
|
|
658
|
-
const actionPerms = (
|
|
659
|
+
const actionPerms = resolveActionPermission({
|
|
660
|
+
action: entry,
|
|
661
|
+
resourcePermissions: resource.permissions,
|
|
662
|
+
resourceActionPermissions: resource.actionPermissions
|
|
663
|
+
});
|
|
659
664
|
tools.push({
|
|
660
665
|
name: toolName,
|
|
661
666
|
description: String(description),
|
package/dist/scope/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { _ as isAuthenticated, a as getClientId, b as isOrgInScope, c as getOrgRoles, d as getScopeContextMap, f as getServiceScopes, g as hasOrgAccess, h as getUserRoles, i as getAncestorOrgIds, l as getRequestScope, m as getUserId, n as PUBLIC_SCOPE, o as getOrgContext, p as getTeamId, r as RequestScope, s as getOrgId, t as AUTHENTICATED_SCOPE, u as getScopeContext, v as isElevated, x as isService, y as isMember } from "../types-
|
|
2
|
-
import { i as elevationPlugin, n as ElevationOptions, r as _default, t as ElevationEvent } from "../elevation-
|
|
1
|
+
import { _ as isAuthenticated, a as getClientId, b as isOrgInScope, c as getOrgRoles, d as getScopeContextMap, f as getServiceScopes, g as hasOrgAccess, h as getUserRoles, i as getAncestorOrgIds, l as getRequestScope, m as getUserId, n as PUBLIC_SCOPE, o as getOrgContext, p as getTeamId, r as RequestScope, s as getOrgId, t as AUTHENTICATED_SCOPE, u as getScopeContext, v as isElevated, x as isService, y as isMember } from "../types-tgR4Pt8F.mjs";
|
|
2
|
+
import { i as elevationPlugin, n as ElevationOptions, r as _default, t as ElevationEvent } from "../elevation-s5ykdNHr.mjs";
|
|
3
3
|
import { FastifyReply, FastifyRequest } from "fastify";
|
|
4
4
|
|
|
5
5
|
//#region src/scope/rateLimitKey.d.ts
|
package/dist/scope/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { _ as isElevated, a as getOrgContext, b as isService, c as getRequestScope, d as getServiceScopes, f as getTeamId, g as isAuthenticated, h as hasOrgAccess, i as getClientId, l as getScopeContext, m as getUserRoles, n as PUBLIC_SCOPE, o as getOrgId, p as getUserId, r as getAncestorOrgIds, s as getOrgRoles, t as AUTHENTICATED_SCOPE, u as getScopeContextMap, v as isMember, y as isOrgInScope } from "../types-AOD8fxIw.mjs";
|
|
2
|
-
import { n as normalizeRoles } from "../types-
|
|
3
|
-
import { n as elevation_default, t as elevationPlugin } from "../elevation-
|
|
2
|
+
import { n as normalizeRoles } from "../types-D57iXYb8.mjs";
|
|
3
|
+
import { n as elevation_default, t as elevationPlugin } from "../elevation-Dci0AYLT.mjs";
|
|
4
4
|
//#region src/scope/rateLimitKey.ts
|
|
5
5
|
function createTenantKeyGenerator(opts) {
|
|
6
6
|
if (opts?.strategy) return opts.strategy;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
2
|
+
import { arcLog } from "./logger/index.mjs";
|
|
2
3
|
import { n as PUBLIC_SCOPE, o as getOrgId } from "./types-AOD8fxIw.mjs";
|
|
3
|
-
import { t as arcLog } from "./logger-CDjpjySd.mjs";
|
|
4
4
|
import fp from "fastify-plugin";
|
|
5
5
|
//#region src/plugins/sse.ts
|
|
6
6
|
var sse_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -18,6 +18,10 @@ function isNotFoundError(err) {
|
|
|
18
18
|
* Build a `safeGetOne(filter)` that papers over the throw-vs-null split
|
|
19
19
|
* in kit implementations. Real errors propagate; miss returns `null`.
|
|
20
20
|
* Throws if the repository lacks `getOne` — callers must check.
|
|
21
|
+
*
|
|
22
|
+
* Accepts `FilterInput` (the repo-core union) so callers can compose
|
|
23
|
+
* portable Filter IR (`and(eq(...), gt(...))`) OR pass a flat kit-native
|
|
24
|
+
* record. Both forms reach the kit's `getOne` unchanged — kits dispatch.
|
|
21
25
|
*/
|
|
22
26
|
function createSafeGetOne(repository) {
|
|
23
27
|
if (typeof repository.getOne !== "function") throw new Error("createSafeGetOne: repository.getOne is required");
|
package/dist/testing/index.d.mts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { d as ResourceLike, r as CreateAppOptions } from "../types-
|
|
1
|
+
import { B as ResourceDefinition, Yt as AnyRecord } from "../index-BGbpGVyM.mjs";
|
|
2
|
+
import { d as ResourceLike, r as CreateAppOptions } from "../types-CVdgPXBW.mjs";
|
|
3
3
|
import { StorageContractSetup, StorageContractSetupResult, runStorageContract } from "./storageContract.mjs";
|
|
4
4
|
import Fastify, { FastifyInstance, FastifyServerOptions } from "fastify";
|
|
5
5
|
import { Connection } from "mongoose";
|
|
6
6
|
import { Mock } from "vitest";
|
|
7
|
+
import { StandardRepo } from "@classytic/repo-core/repository";
|
|
7
8
|
|
|
8
9
|
//#region src/testing/authHelpers.d.ts
|
|
9
10
|
interface BetterAuthTestHelpersOptions {
|
|
@@ -478,7 +479,7 @@ declare function createHttpTestHarness<T = unknown>(resource: ResourceDefinition
|
|
|
478
479
|
/**
|
|
479
480
|
* Extended repository interface for testing (includes optional preset methods)
|
|
480
481
|
*/
|
|
481
|
-
interface MockRepository<T> extends
|
|
482
|
+
interface MockRepository<T> extends StandardRepo<T> {
|
|
482
483
|
getBySlug?: Mock;
|
|
483
484
|
getDeleted?: Mock;
|
|
484
485
|
restore?: Mock;
|
|
@@ -519,8 +520,8 @@ declare function createMockReply(): unknown;
|
|
|
519
520
|
/**
|
|
520
521
|
* Create a mock controller for testing
|
|
521
522
|
*/
|
|
522
|
-
declare function createMockController(repository:
|
|
523
|
-
repository:
|
|
523
|
+
declare function createMockController(repository: StandardRepo<AnyRecord>): {
|
|
524
|
+
repository: StandardRepo<AnyRecord>;
|
|
524
525
|
list: Mock<(...args: any[]) => any>;
|
|
525
526
|
get: Mock<(...args: any[]) => any>;
|
|
526
527
|
create: Mock<(...args: any[]) => any>;
|
package/dist/testing/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as CRUD_OPERATIONS } from "../constants-
|
|
2
|
-
import { n as applyFieldWritePermissions, t as applyFieldReadPermissions } from "../fields-
|
|
1
|
+
import { t as CRUD_OPERATIONS } from "../constants-BhY1OHoH.mjs";
|
|
2
|
+
import { n as applyFieldWritePermissions, t as applyFieldReadPermissions } from "../fields-CTMWOUDt.mjs";
|
|
3
3
|
import { runStorageContract } from "./storageContract.mjs";
|
|
4
4
|
import Fastify from "fastify";
|
|
5
5
|
import mongoose from "mongoose";
|
|
@@ -566,7 +566,10 @@ var HttpTestHarness = class {
|
|
|
566
566
|
this.resource = resource;
|
|
567
567
|
this.optionsOrGetter = optionsOrGetter;
|
|
568
568
|
if (typeof optionsOrGetter === "function") this.eagerBaseUrl = null;
|
|
569
|
-
else
|
|
569
|
+
else {
|
|
570
|
+
const apiPrefix = optionsOrGetter.apiPrefix ?? "/api";
|
|
571
|
+
this.eagerBaseUrl = `${apiPrefix}${resource.prefix}`;
|
|
572
|
+
}
|
|
570
573
|
const disabled = new Set(resource.disabledRoutes ?? []);
|
|
571
574
|
this.enabledRoutes = new Set(resource.disableDefaultRoutes ? [] : CRUD_OPERATIONS.filter((op) => !disabled.has(op)));
|
|
572
575
|
this.updateMethod = resource.updateMethod === "PUT" ? "PUT" : "PATCH";
|
|
@@ -877,12 +880,6 @@ function createHttpTestHarness(resource, optionsOrGetter) {
|
|
|
877
880
|
//#endregion
|
|
878
881
|
//#region src/testing/mocks.ts
|
|
879
882
|
/**
|
|
880
|
-
* Testing Utilities - Mock Factories
|
|
881
|
-
*
|
|
882
|
-
* Create mock repositories, controllers, and services for testing.
|
|
883
|
-
* Uses Vitest for mocking (compatible with Jest API).
|
|
884
|
-
*/
|
|
885
|
-
/**
|
|
886
883
|
* Create a mock repository for testing
|
|
887
884
|
*
|
|
888
885
|
* @example
|
|
@@ -896,6 +893,7 @@ function createHttpTestHarness(resource, optionsOrGetter) {
|
|
|
896
893
|
function createMockRepository(overrides = {}) {
|
|
897
894
|
return {
|
|
898
895
|
getAll: vi.fn().mockResolvedValue({
|
|
896
|
+
method: "offset",
|
|
899
897
|
docs: [],
|
|
900
898
|
total: 0,
|
|
901
899
|
page: 1,
|
|
@@ -917,6 +915,15 @@ function createMockRepository(overrides = {}) {
|
|
|
917
915
|
success: true,
|
|
918
916
|
message: "Deleted"
|
|
919
917
|
}),
|
|
918
|
+
updateMany: vi.fn().mockResolvedValue({
|
|
919
|
+
acknowledged: true,
|
|
920
|
+
matchedCount: 0,
|
|
921
|
+
modifiedCount: 0
|
|
922
|
+
}),
|
|
923
|
+
deleteMany: vi.fn().mockResolvedValue({
|
|
924
|
+
acknowledged: true,
|
|
925
|
+
deletedCount: 0
|
|
926
|
+
}),
|
|
920
927
|
getBySlug: vi.fn().mockResolvedValue(null),
|
|
921
928
|
getDeleted: vi.fn().mockResolvedValue([]),
|
|
922
929
|
restore: vi.fn().mockResolvedValue(null),
|
|
@@ -1743,7 +1750,7 @@ function runEventTests(resourceName, displayName, events) {
|
|
|
1743
1750
|
* ```
|
|
1744
1751
|
*/
|
|
1745
1752
|
async function createTestApp(options = {}) {
|
|
1746
|
-
const { createApp } = await import("../createApp-
|
|
1753
|
+
const { createApp } = await import("../createApp-BwnEAO2h.mjs").then((n) => n.r);
|
|
1747
1754
|
const { useInMemoryDb = true, mongoUri: providedMongoUri, ...appOptions } = options;
|
|
1748
1755
|
const defaultAuth = {
|
|
1749
1756
|
type: "jwt",
|
package/dist/types/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { _ as
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { n as ElevationOptions, t as ElevationEvent } from "../elevation-
|
|
5
|
-
export { AUTHENTICATED_SCOPE, ActionDefinition, ActionEntry, ActionHandlerFn, ActionsMap, AnyRecord, ApiResponse, ArcDecorator, ArcInternalMetadata, ArcRequest, AuthHelpers, AuthPluginOptions, Authenticator, AuthenticatorContext, BaseControllerOptions,
|
|
1
|
+
import { $t as ObjectId, A as RequestIdOptions, At as FastifyHandler, C as RequestContext, Ct as ResourcePermissions, D as HealthCheck, Dt as RouteSchemaOptions, E as GracefulShutdownOptions, Et as RouteMethod, F as FastifyWithDecorators, Gt as Authenticator, I as MiddlewareHandler, Jt as TokenPair, Kt as AuthenticatorContext, L as RequestWithExtras, M as EventsDecorator, Mt as IControllerResponse, N as FastifyRequestExtras, Nt as IRequestContext, O as HealthOptions, Ot as ControllerHandler, P as FastifyWithAuth, Pt as RouteHandler, Qt as JWTPayload, S as QueryParserInterface, St as ResourceHooks, T as CrudRouterOptions, Tt as RouteMcpConfig, Ut as AuthHelpers, Wt as AuthPluginOptions, Xt as ApiResponse, Yt as AnyRecord, Zt as ArcRequest, _ as ControllerQueryOptions, _t as PresetResult, a as InferAdapterDoc, an as BaseControllerOptions, at as ActionEntry, b as ParsedQuery, bt as ResourceConfig, c as TypedController, ct as CrudController, d as PaginationResult, dt as EventDefinition, en as UserLike, f as IntrospectionData, ft as FieldRule, g as ArcInternalMetadata, gt as PresetHook, h as ResourceMetadata, ht as PresetFunction, i as ValidationResult, it as ActionDefinition, j as ArcDecorator, jt as IController, k as IntrospectionPluginOptions, kt as ControllerLike, l as TypedRepository, lt as CrudRouteKey, m as RegistryStats, mt as OpenApiSchemas, n as ConfigError, nn as envelope, o as InferDocType, ot as ActionHandlerFn, p as RegistryEntry, pt as MiddlewareConfig, qt as JwtContext, r as ValidateOptions, rn as getUserId, s as InferResourceDoc, st as ActionsMap, t as RouteHandlerMethod, tn as UserOrganization, u as TypedResourceConfig, ut as CrudSchemas, v as LookupOption, vt as RateLimitConfig, w as ServiceContext, wt as RouteDefinition, x as PopulateOption, xt as ResourceHookContext, y as OwnershipCheck, yt as ResourceCacheConfig } from "../index-BGbpGVyM.mjs";
|
|
2
|
+
import { _ as isAuthenticated, c as getOrgRoles, g as hasOrgAccess, n as PUBLIC_SCOPE, p as getTeamId, r as RequestScope, s as getOrgId, t as AUTHENTICATED_SCOPE, v as isElevated, y as isMember } from "../types-tgR4Pt8F.mjs";
|
|
3
|
+
import { c as PermissionCheck, d as UserBase, l as PermissionContext, u as PermissionResult } from "../fields-C8Y0XLAu.mjs";
|
|
4
|
+
import { n as ElevationOptions, t as ElevationEvent } from "../elevation-s5ykdNHr.mjs";
|
|
5
|
+
export { AUTHENTICATED_SCOPE, ActionDefinition, ActionEntry, ActionHandlerFn, ActionsMap, AnyRecord, ApiResponse, ArcDecorator, ArcInternalMetadata, ArcRequest, AuthHelpers, AuthPluginOptions, Authenticator, AuthenticatorContext, BaseControllerOptions, ConfigError, ControllerHandler, ControllerLike, ControllerQueryOptions, CrudController, CrudRouteKey, CrudRouterOptions, CrudSchemas, ElevationEvent, ElevationOptions, EventDefinition, EventsDecorator, FastifyHandler, FastifyRequestExtras, FastifyWithAuth, FastifyWithDecorators, FieldRule, GracefulShutdownOptions, HealthCheck, HealthOptions, IController, IControllerResponse, IRequestContext, InferAdapterDoc, InferDocType, InferResourceDoc, IntrospectionData, IntrospectionPluginOptions, JWTPayload, JwtContext, LookupOption, MiddlewareConfig, MiddlewareHandler, ObjectId, OpenApiSchemas, OwnershipCheck, PUBLIC_SCOPE, PaginationResult, ParsedQuery, PermissionCheck, PermissionContext, PermissionResult, PopulateOption, PresetFunction, PresetHook, PresetResult, QueryParserInterface, RateLimitConfig, RegistryEntry, RegistryStats, RequestContext, RequestIdOptions, RequestScope, RequestWithExtras, ResourceCacheConfig, ResourceConfig, ResourceHookContext, ResourceHooks, ResourceMetadata, ResourcePermissions, RouteDefinition, RouteHandler, RouteHandlerMethod, RouteMcpConfig, RouteMethod, RouteSchemaOptions, ServiceContext, TokenPair, TypedController, TypedRepository, TypedResourceConfig, UserBase, UserLike, UserOrganization, ValidateOptions, ValidationResult, envelope, getOrgId, getOrgRoles, getTeamId, getUserId, hasOrgAccess, isAuthenticated, isElevated, isMember };
|
package/dist/types/index.mjs
CHANGED
|
@@ -1,33 +1,3 @@
|
|
|
1
1
|
import { _ as isElevated, f as getTeamId, g as isAuthenticated, h as hasOrgAccess, n as PUBLIC_SCOPE, o as getOrgId, s as getOrgRoles, t as AUTHENTICATED_SCOPE, v as isMember } from "../types-AOD8fxIw.mjs";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Response envelope helper — wraps data in Arc's standard `{ success, data }` format.
|
|
5
|
-
*
|
|
6
|
-
* @example
|
|
7
|
-
* ```typescript
|
|
8
|
-
* import { envelope } from '@classytic/arc';
|
|
9
|
-
*
|
|
10
|
-
* handler: async (req, reply) => {
|
|
11
|
-
* const data = await getResults();
|
|
12
|
-
* return envelope(data);
|
|
13
|
-
* // → { success: true, data }
|
|
14
|
-
* }
|
|
15
|
-
* ```
|
|
16
|
-
*/
|
|
17
|
-
function envelope(data, meta) {
|
|
18
|
-
return {
|
|
19
|
-
success: true,
|
|
20
|
-
data,
|
|
21
|
-
...meta
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Extract user ID from a user object (supports both id and _id)
|
|
26
|
-
*/
|
|
27
|
-
function getUserId(user) {
|
|
28
|
-
if (!user) return void 0;
|
|
29
|
-
const id = user.id ?? user._id;
|
|
30
|
-
return id ? String(id) : void 0;
|
|
31
|
-
}
|
|
32
|
-
//#endregion
|
|
2
|
+
import { n as getUserId, t as envelope } from "../types-CDnTEpga.mjs";
|
|
33
3
|
export { AUTHENTICATED_SCOPE, PUBLIC_SCOPE, envelope, getOrgId, getOrgRoles, getTeamId, getUserId, hasOrgAccess, isAuthenticated, isElevated, isMember };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//#region src/types/base.ts
|
|
2
|
+
/** Extract user ID from a user object (supports both id and _id). */
|
|
3
|
+
function getUserId(user) {
|
|
4
|
+
if (!user) return void 0;
|
|
5
|
+
const id = user.id ?? user._id;
|
|
6
|
+
return id ? String(id) : void 0;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Wrap data in Arc's standard `{ success: true, data }` envelope.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* handler: async (req, reply) => {
|
|
14
|
+
* const data = await getResults();
|
|
15
|
+
* return envelope(data); // → { success: true, data }
|
|
16
|
+
* }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
function envelope(data, meta) {
|
|
20
|
+
return {
|
|
21
|
+
success: true,
|
|
22
|
+
data,
|
|
23
|
+
...meta
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { getUserId as n, envelope as t };
|