@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.
Files changed (132) hide show
  1. package/README.md +20 -91
  2. package/dist/{BaseController-Vu2yc56T.mjs → BaseController-DVNKvoX4.mjs} +154 -170
  3. package/dist/{ResourceRegistry-Dq3_zBQP.mjs → ResourceRegistry-CcN2LVrc.mjs} +1 -1
  4. package/dist/actionPermissions-TUVR3uiZ.mjs +22 -0
  5. package/dist/adapters/index.d.mts +3 -3
  6. package/dist/adapters/index.mjs +2 -2
  7. package/dist/{adapters-BBqAVvPK.mjs → adapters-BXY4i-hw.mjs} +210 -41
  8. package/dist/audit/index.d.mts +38 -3
  9. package/dist/audit/index.mjs +54 -22
  10. package/dist/auth/index.d.mts +2 -2
  11. package/dist/auth/index.mjs +3 -3
  12. package/dist/cache/index.d.mts +17 -15
  13. package/dist/cache/index.mjs +16 -15
  14. package/dist/{caching-CjybdRwx.mjs → caching-3h93rkJM.mjs} +8 -3
  15. package/dist/cli/commands/describe.mjs +1 -1
  16. package/dist/cli/commands/docs.mjs +2 -2
  17. package/dist/cli/commands/init.mjs +1 -1
  18. package/dist/cli/commands/introspect.mjs +1 -1
  19. package/dist/context/index.d.mts +58 -0
  20. package/dist/context/index.mjs +2 -0
  21. package/dist/core/index.d.mts +2 -2
  22. package/dist/core/index.mjs +3 -4
  23. package/dist/{defineResource-C__jkwvs.mjs → core-3MWJosCH.mjs} +174 -94
  24. package/dist/{createActionRouter-DH1YFL9m.mjs → createActionRouter-C8UUB3Px.mjs} +1 -1
  25. package/dist/{createApp-CBJUJKGP.mjs → createApp-BwnEAO2h.mjs} +53 -19
  26. package/dist/docs/index.d.mts +1 -1
  27. package/dist/docs/index.mjs +2 -2
  28. package/dist/{elevation-DxQ6ACbt.mjs → elevation-Dci0AYLT.mjs} +2 -2
  29. package/dist/errorHandler-2ii4RIYr.d.mts +114 -0
  30. package/dist/{errorHandler-CZDW4EXS.mjs → errorHandler-CSxe7KIM.mjs} +1 -1
  31. package/dist/{eventPlugin-Dl7MoVWH.mjs → eventPlugin-ByU4Cv0e.mjs} +1 -1
  32. package/dist/{eventPlugin-BxvaCIZF.d.mts → eventPlugin-D1ThQ1Pp.d.mts} +1 -1
  33. package/dist/events/index.d.mts +8 -5
  34. package/dist/events/index.mjs +87 -52
  35. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  36. package/dist/events/transports/redis.d.mts +1 -1
  37. package/dist/factory/index.d.mts +1 -1
  38. package/dist/factory/index.mjs +1 -1
  39. package/dist/{types-DZi1aYhm.d.mts → fields-C8Y0XLAu.d.mts} +122 -2
  40. package/dist/hooks/index.d.mts +1 -1
  41. package/dist/idempotency/index.d.mts +5 -2
  42. package/dist/idempotency/index.mjs +46 -37
  43. package/dist/{interface-YrWsmKqE.d.mts → index-BGbpGVyM.d.mts} +2107 -2756
  44. package/dist/{index-CtGKT0lf.d.mts → index-BziRPS4H.d.mts} +81 -7
  45. package/dist/{index-C-xjcA6F.d.mts → index-C_Noptz-.d.mts} +284 -409
  46. package/dist/{index-Cibkchnx.d.mts → index-EqQN6p0W.d.mts} +3 -3
  47. package/dist/index.d.mts +6 -219
  48. package/dist/index.mjs +10 -131
  49. package/dist/integrations/event-gateway.d.mts +1 -1
  50. package/dist/integrations/event-gateway.mjs +1 -1
  51. package/dist/integrations/index.d.mts +1 -1
  52. package/dist/integrations/mcp/index.d.mts +2 -2
  53. package/dist/integrations/mcp/index.mjs +1 -1
  54. package/dist/integrations/mcp/testing.d.mts +1 -1
  55. package/dist/integrations/mcp/testing.mjs +1 -1
  56. package/dist/interface-yhyb_pLY.d.mts +77 -0
  57. package/dist/logger/index.d.mts +81 -0
  58. package/dist/{logger-CDjpjySd.mjs → logger/index.mjs} +1 -6
  59. package/dist/{memory-BFAYkf8H.mjs → memory-DqI-449b.mjs} +23 -8
  60. package/dist/middleware/index.d.mts +109 -0
  61. package/dist/middleware/index.mjs +70 -0
  62. package/dist/multipartBody-CUQGVlM_.mjs +123 -0
  63. package/dist/{openapi-CXuTG1M9.mjs → openapi-DpNpqBmo.mjs} +9 -7
  64. package/dist/org/index.d.mts +2 -2
  65. package/dist/permissions/index.d.mts +3 -4
  66. package/dist/permissions/index.mjs +5 -5
  67. package/dist/{permissions-oNZawnkR.mjs → permissions-wkqRwicB.mjs} +315 -397
  68. package/dist/pipe-CGJxqDGx.mjs +62 -0
  69. package/dist/pipeline/index.d.mts +62 -0
  70. package/dist/pipeline/index.mjs +53 -0
  71. package/dist/plugins/index.d.mts +23 -3
  72. package/dist/plugins/index.mjs +9 -11
  73. package/dist/plugins/response-cache.mjs +1 -1
  74. package/dist/plugins/tracing-entry.mjs +1 -1
  75. package/dist/presets/filesUpload.d.mts +3 -3
  76. package/dist/presets/filesUpload.mjs +255 -1
  77. package/dist/presets/index.d.mts +1 -1
  78. package/dist/presets/index.mjs +2 -2
  79. package/dist/presets/multiTenant.d.mts +1 -1
  80. package/dist/presets/multiTenant.mjs +43 -9
  81. package/dist/presets/search.d.mts +91 -4
  82. package/dist/presets/search.mjs +1 -1
  83. package/dist/{presets-hM4WhNWY.mjs → presets-CrwOvuXI.mjs} +1 -1
  84. package/dist/{queryCachePlugin-DbUVroUG.mjs → queryCachePlugin-ChLNZvFT.mjs} +9 -9
  85. package/dist/{queryCachePlugin-CnTZZTC5.d.mts → queryCachePlugin-Dumka73q.d.mts} +1 -1
  86. package/dist/{queryParser-Cs-6SHQK.mjs → queryParser-NR__Qiju.mjs} +69 -2
  87. package/dist/{redis-stream-Bz-4q96t.d.mts → redis-stream-bkO88VHx.d.mts} +1 -1
  88. package/dist/registry/index.d.mts +1 -1
  89. package/dist/registry/index.mjs +1 -1
  90. package/dist/{requestContext-DYtmNpm5.mjs → requestContext-C38GskNt.mjs} +1 -1
  91. package/dist/{resourceToTools-C3cWymnW.mjs → resourceToTools-BhF3JV5p.mjs} +8 -3
  92. package/dist/scope/index.d.mts +2 -2
  93. package/dist/scope/index.mjs +2 -2
  94. package/dist/{sse-CJpt7LGI.mjs → sse-D8UeDwis.mjs} +1 -1
  95. package/dist/{store-helpers-DFiZl5TL.mjs → store-helpers-DYYUQbQN.mjs} +4 -0
  96. package/dist/testing/index.d.mts +6 -5
  97. package/dist/testing/index.mjs +17 -10
  98. package/dist/types/index.d.mts +5 -5
  99. package/dist/types/index.mjs +1 -31
  100. package/dist/types-CDnTEpga.mjs +27 -0
  101. package/dist/{types-CoSzA-s-.d.mts → types-CVKBssX5.d.mts} +1 -1
  102. package/dist/{types-CunEX4UX.d.mts → types-CVdgPXBW.d.mts} +20 -7
  103. package/dist/utils/index.d.mts +277 -3
  104. package/dist/utils/index.mjs +4 -5
  105. package/dist/{utils-B7FuRr9w.mjs → utils-LMwVidKy.mjs} +303 -2
  106. package/dist/{versioning-Cm8qoFDg.mjs → versioning-B6mimogM.mjs} +3 -5
  107. package/dist/versioning-CeUXHfjw.d.mts +117 -0
  108. package/package.json +31 -18
  109. package/skills/arc/SKILL.md +8 -12
  110. package/skills/arc/references/production.md +0 -41
  111. package/dist/circuitBreaker-CvXkjfrW.d.mts +0 -206
  112. package/dist/circuitBreaker-l18oRgL5.mjs +0 -284
  113. package/dist/core-DNncu0xF.mjs +0 -34
  114. package/dist/dynamic/index.d.mts +0 -93
  115. package/dist/dynamic/index.mjs +0 -122
  116. package/dist/errorHandler-DixGcttC.d.mts +0 -218
  117. package/dist/fields-BC7zcmI9.d.mts +0 -121
  118. package/dist/filesUpload-q8oHt--L.mjs +0 -377
  119. package/dist/interface-DplgQO2e.d.mts +0 -54
  120. package/dist/policies/index.d.mts +0 -425
  121. package/dist/policies/index.mjs +0 -318
  122. package/dist/rpc/index.d.mts +0 -90
  123. package/dist/rpc/index.mjs +0 -248
  124. /package/dist/{EventTransport-CqZ8FyM_.d.mts → EventTransport-CfVEGaEl.d.mts} +0 -0
  125. /package/dist/{applyPermissionResult-bqGpo9ML.mjs → applyPermissionResult-QhV1Pa-g.mjs} +0 -0
  126. /package/dist/{constants-Cxde4rpC.mjs → constants-BhY1OHoH.mjs} +0 -0
  127. /package/dist/{elevation-B6S5csVA.d.mts → elevation-s5ykdNHr.d.mts} +0 -0
  128. /package/dist/{errors-CqWnSqM-.mjs → errors-BqdUDja_.mjs} +0 -0
  129. /package/dist/{fields-CU6FlaDV.mjs → fields-CTMWOUDt.mjs} +0 -0
  130. /package/dist/{keys-qcD-TVJl.mjs → keys-nWQGUTu1.mjs} +0 -0
  131. /package/dist/{types-ZUu_h0jp.mjs → types-D57iXYb8.mjs} +0 -0
  132. /package/dist/{types-BD85MlEK.d.mts → types-tgR4Pt8F.d.mts} +0 -0
@@ -1,4 +1,4 @@
1
- import "../constants-Cxde4rpC.mjs";
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) request._policyFilters = {
38
- ...request._policyFilters ?? {},
39
- ...resolved
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) request._policyFilters = {
85
- ...request._policyFilters ?? {},
86
- ...resolved
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 { Lt as ControllerHandler, et as PresetResult, gt as RouteMcpConfig, mt as RouteDefinition, o as RepositoryLike } from "../interface-YrWsmKqE.mjs";
2
- import { t as PermissionCheck } from "../types-DZi1aYhm.mjs";
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?: Pick<RepositoryLike, "search" | "searchSimilar" | "embed">;
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 };
@@ -1,4 +1,4 @@
1
- import { n as allowPublic, s as requireAuth } from "../permissions-oNZawnkR.mjs";
1
+ import { C as requireAuth, y as allowPublic } from "../permissions-wkqRwicB.mjs";
2
2
  //#region src/presets/search.ts
3
3
  const BUILTINS = [
4
4
  {
@@ -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 { f as requireRoles, n as allowPublic, s as requireAuth } from "./permissions-oNZawnkR.mjs";
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-qcD-TVJl.mjs";
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-BFAYkf8H.mjs";
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 staleTimeMs = (config.staleTime ?? 0) * 1e3;
37
- const totalTtl = staleTimeMs + (config.gcTime ?? 60) * 1e3;
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 + staleTimeMs,
43
- expiresAt: now + totalTtl,
42
+ staleAfter: now + staleTimeSec * 1e3,
43
+ expiresAt: now + totalTtlSec * 1e3,
44
44
  tags: config.tags ?? []
45
45
  };
46
- await this.store.set(key, envelope, { ttlMs: totalTtl });
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, { ttlMs: 1440 * 60 * 1e3 });
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, { ttlMs: 1440 * 60 * 1e3 });
69
+ await this.store.set(key, newVersion, 1440 * 60);
70
70
  }
71
71
  };
72
72
  //#endregion
@@ -1,4 +1,4 @@
1
- import { i as CacheStore } from "./interface-DplgQO2e.mjs";
1
+ import { r as CacheStore } from "./interface-yhyb_pLY.mjs";
2
2
  import { FastifyPluginAsync } from "fastify";
3
3
 
4
4
  //#region src/cache/QueryCache.d.ts
@@ -1,4 +1,71 @@
1
- import { m as RESERVED_QUERY_PARAMS } from "./constants-Cxde4rpC.mjs";
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-CqZ8FyM_.mjs";
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 { Gt as ResourceRegistry, V as IntrospectionPluginOptions, Wt as RegisterOptions } from "../interface-YrWsmKqE.mjs";
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
@@ -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-Dq3_zBQP.mjs";
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-Vu2yc56T.mjs";
2
- import { n as normalizePermissionResult } from "./applyPermissionResult-bqGpo9ML.mjs";
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 = (typeof def !== "function" ? def.permissions : void 0) ?? resource.actionPermissions;
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),
@@ -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-BD85MlEK.mjs";
2
- import { i as elevationPlugin, n as ElevationOptions, r as _default, t as ElevationEvent } from "../elevation-B6S5csVA.mjs";
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
@@ -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-ZUu_h0jp.mjs";
3
- import { n as elevation_default, t as elevationPlugin } from "../elevation-DxQ6ACbt.mjs";
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");
@@ -1,9 +1,10 @@
1
- import { Kt as ResourceDefinition, Xt as CrudRepository, p as AnyRecord } from "../interface-YrWsmKqE.mjs";
2
- import { d as ResourceLike, r as CreateAppOptions } from "../types-CunEX4UX.mjs";
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 CrudRepository<T> {
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: CrudRepository<AnyRecord>): {
523
- repository: CrudRepository<AnyRecord>;
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>;
@@ -1,5 +1,5 @@
1
- import { t as CRUD_OPERATIONS } from "../constants-Cxde4rpC.mjs";
2
- import { n as applyFieldWritePermissions, t as applyFieldReadPermissions } from "../fields-CU6FlaDV.mjs";
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 this.eagerBaseUrl = `${optionsOrGetter.apiPrefix ?? "/api"}${resource.prefix}`;
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-CBJUJKGP.mjs").then((n) => n.r);
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",
@@ -1,5 +1,5 @@
1
- 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-BD85MlEK.mjs";
2
- import { $ as PresetHook, $t as DeleteResult, A as FastifyRequestExtras, At as BaseControllerOptions, B as IntrospectionData, Bt as IController, C as ControllerQueryOptions, Ct as UserLike, D as CrudSchemas, Dt as envelope, E as CrudRouterOptions, Et as ValidationResult, F as HealthCheck, G as MiddlewareConfig, H as JWTPayload, Ht as IRequestContext, I as HealthOptions, J as OpenApiSchemas, Jt as BulkWriteOperation, K as MiddlewareHandler, L as InferAdapterDoc, Lt as ControllerHandler, M as FastifyWithDecorators, N as FieldRule, O as EventDefinition, Ot as getUserId, P as GracefulShutdownOptions, Q as PresetFunction, Qt as DeleteOptions, R as InferDocType, Rt as ControllerLike, S as ConfigError, St as TypedResourceConfig, T as CrudRouteKey, Tt as ValidateOptions, U as JwtContext, Ut as RouteHandler, V as IntrospectionPluginOptions, Vt as IControllerResponse, W as LookupOption, X as ParsedQuery, Xt as CrudRepository, Y as OwnershipCheck, Yt as BulkWriteResult, Z as PopulateOption, Zt as DeleteManyResult, _ as ArcRequest, _t as RouteSchemaOptions, an as PaginationParams, at as RequestContext, b as Authenticator, bt as TypedController, cn as RepositorySession, ct as ResourceCacheConfig, d as ActionHandlerFn, dt as ResourceHooks, en as FindOneAndUpdateOptions, et as PresetResult, f as ActionsMap, ft as ResourceMetadata, g as ArcInternalMetadata, gt as RouteMcpConfig, h as ArcDecorator, ht as RouteHandlerMethod, in as PaginatedResult, it as RegistryStats, j as FastifyWithAuth, k as EventsDecorator, l as ActionDefinition, ln as UpdateManyResult, lt as ResourceConfig, m as ApiResponse, mt as RouteDefinition, nn as KeysetPaginatedResult, nt as RateLimitConfig, on as PaginationResult, ot as RequestIdOptions, p as AnyRecord, pt as ResourcePermissions, q as ObjectId, rn as OffsetPaginatedResult, rt as RegistryEntry, sn as QueryOptions, st as RequestWithExtras, tn as InferDoc, tt as QueryParserInterface, u as ActionEntry, un as WriteOptions, ut as ResourceHookContext, v as AuthHelpers, vt as ServiceContext, w as CrudController, wt as UserOrganization, x as AuthenticatorContext, xt as TypedRepository, y as AuthPluginOptions, yt as TokenPair, z as InferResourceDoc, zt as FastifyHandler } from "../interface-YrWsmKqE.mjs";
3
- import { i as UserBase, n as PermissionContext, r as PermissionResult, t as PermissionCheck } from "../types-DZi1aYhm.mjs";
4
- import { n as ElevationOptions, t as ElevationEvent } from "../elevation-B6S5csVA.mjs";
5
- export { AUTHENTICATED_SCOPE, ActionDefinition, ActionEntry, ActionHandlerFn, ActionsMap, AnyRecord, ApiResponse, ArcDecorator, ArcInternalMetadata, ArcRequest, AuthHelpers, AuthPluginOptions, Authenticator, AuthenticatorContext, BaseControllerOptions, BulkWriteOperation, BulkWriteResult, ConfigError, ControllerHandler, ControllerLike, ControllerQueryOptions, CrudController, CrudRepository, CrudRouteKey, CrudRouterOptions, CrudSchemas, DeleteManyResult, DeleteOptions, DeleteResult, ElevationEvent, ElevationOptions, EventDefinition, EventsDecorator, FastifyHandler, FastifyRequestExtras, FastifyWithAuth, FastifyWithDecorators, FieldRule, FindOneAndUpdateOptions, GracefulShutdownOptions, HealthCheck, HealthOptions, IController, IControllerResponse, IRequestContext, InferAdapterDoc, InferDoc, InferDocType, InferResourceDoc, IntrospectionData, IntrospectionPluginOptions, JWTPayload, JwtContext, KeysetPaginatedResult, LookupOption, MiddlewareConfig, MiddlewareHandler, ObjectId, OffsetPaginatedResult, OpenApiSchemas, OwnershipCheck, PUBLIC_SCOPE, PaginatedResult, PaginationParams, PaginationResult, ParsedQuery, PermissionCheck, PermissionContext, PermissionResult, PopulateOption, PresetFunction, PresetHook, PresetResult, QueryOptions, QueryParserInterface, RateLimitConfig, RegistryEntry, RegistryStats, RepositorySession, RequestContext, RequestIdOptions, RequestScope, RequestWithExtras, ResourceCacheConfig, ResourceConfig, ResourceHookContext, ResourceHooks, ResourceMetadata, ResourcePermissions, RouteDefinition, RouteHandler, RouteHandlerMethod, RouteMcpConfig, RouteSchemaOptions, ServiceContext, TokenPair, TypedController, TypedRepository, TypedResourceConfig, UpdateManyResult, UserBase, UserLike, UserOrganization, ValidateOptions, ValidationResult, WriteOptions, envelope, getOrgId, getOrgRoles, getTeamId, getUserId, hasOrgAccess, isAuthenticated, isElevated, isMember };
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 };
@@ -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
- //#region src/types/index.ts
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 };