@classytic/arc 2.18.5 → 2.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/README.md +1 -1
  2. package/bin/arc.js +37 -0
  3. package/dist/{BaseController-Dy6EQHjM.mjs → BaseController-D-MHZ27_.mjs} +4 -4
  4. package/dist/{ResourceRegistry-5fKZwhK_.mjs → ResourceRegistry-7RnrEWNP.mjs} +1 -1
  5. package/dist/{actionPermissions-h7DYDNMg.mjs → actionPermissions-C9RMiIpc.mjs} +2 -1
  6. package/dist/audit/index.mjs +1 -1
  7. package/dist/auth/index.d.mts +1 -1
  8. package/dist/auth/index.mjs +17 -6
  9. package/dist/{buildHandler-B0qvAguf.mjs → buildHandler-D_2ULWxZ.mjs} +3 -3
  10. package/dist/cache/index.mjs +2 -2
  11. package/dist/cli/commands/describe.d.mts +1 -1
  12. package/dist/cli/commands/describe.mjs +2 -2
  13. package/dist/cli/commands/docs.mjs +2 -2
  14. package/dist/cli/commands/generate.mjs +1 -1
  15. package/dist/cli/commands/init.mjs +1 -1
  16. package/dist/cli/commands/introspect.mjs +4 -13
  17. package/dist/cli/index.mjs +2 -2
  18. package/dist/{constants-gaEeMlz-.mjs → constants-DNre0wRg.mjs} +1 -1
  19. package/dist/core/index.d.mts +2 -2
  20. package/dist/core/index.mjs +4 -4
  21. package/dist/{core-ZnQBa5rh.mjs → core-CWhyGkiM.mjs} +136 -59
  22. package/dist/{createActionRouter-CagItpxI.mjs → createActionRouter-HlQso0jO.mjs} +8 -7
  23. package/dist/{createAggregationRouter-DVKroXhC.mjs → createAggregationRouter-5LzPzgw1.mjs} +5 -4
  24. package/dist/{createApp--703hQE1.mjs → createApp-D6uwzCKu.mjs} +210 -17
  25. package/dist/docs/index.d.mts +1 -1
  26. package/dist/docs/index.mjs +1 -1
  27. package/dist/encryption/index.d.mts +222 -0
  28. package/dist/encryption/index.mjs +270 -0
  29. package/dist/events/index.mjs +9 -6
  30. package/dist/factory/index.d.mts +3 -2
  31. package/dist/factory/index.mjs +2 -2
  32. package/dist/{fastify-augmentation-Cxb0ROIw.d.mts → fastify-augmentation-CCQJEDgh.d.mts} +12 -1
  33. package/dist/{generate-Brans3fW.mjs → generate-usRSdQmP.mjs} +4 -3
  34. package/dist/hooks/index.d.mts +1 -1
  35. package/dist/idempotency/index.mjs +1 -1
  36. package/dist/{index-CRKiiP5o.d.mts → index-CdFkIMEd.d.mts} +5 -0
  37. package/dist/{index-Dh0_RSTd.d.mts → index-DUa8WHz3.d.mts} +7 -7
  38. package/dist/{index-CHNQIhcb.d.mts → index-_--GyzcO.d.mts} +111 -2
  39. package/dist/index.d.mts +3 -3
  40. package/dist/index.mjs +6 -6
  41. package/dist/{init-Bqpt1Hxf.mjs → init-YH_nslQR.mjs} +87 -5
  42. package/dist/integrations/index.d.mts +1 -1
  43. package/dist/integrations/mcp/index.d.mts +2 -2
  44. package/dist/integrations/mcp/index.mjs +1 -1
  45. package/dist/integrations/mcp/testing.d.mts +1 -1
  46. package/dist/integrations/mcp/testing.mjs +1 -1
  47. package/dist/integrations/streamline.d.mts +17 -5
  48. package/dist/integrations/streamline.mjs +9 -5
  49. package/dist/{loadResourcesFromEntry-BTlFEx05.mjs → loadResourcesFromEntry-OMCvIEE7.mjs} +1 -1
  50. package/dist/{mcpPlugin-D1wuRD2c.mjs → mcpPlugin-CuW6L_uD.mjs} +148 -49
  51. package/dist/middleware/index.d.mts +1 -1
  52. package/dist/middleware/index.mjs +1 -1
  53. package/dist/module-JYH9V0I8.d.mts +384 -0
  54. package/dist/{openapi-xVJibapr.mjs → openapi-Dq6RbEGK.mjs} +3 -3
  55. package/dist/permissions/index.d.mts +1 -1
  56. package/dist/permissions/index.mjs +1 -1
  57. package/dist/{permissions-BPB1xqGf.mjs → permissions-CgbOLJZG.mjs} +10 -2
  58. package/dist/pipeline/index.d.mts +1 -1
  59. package/dist/plugins/index.d.mts +10 -5
  60. package/dist/plugins/index.mjs +3 -3
  61. package/dist/plugins/tracing-entry.mjs +1 -1
  62. package/dist/{pluralize-DccFV9R7.mjs → pluralize-BhrgwZb9.mjs} +3 -3
  63. package/dist/presets/filesUpload.d.mts +1 -1
  64. package/dist/presets/filesUpload.mjs +1 -1
  65. package/dist/presets/index.d.mts +16 -2
  66. package/dist/presets/index.mjs +1 -1
  67. package/dist/presets/multiTenant.d.mts +1 -1
  68. package/dist/presets/multiTenant.mjs +1 -1
  69. package/dist/presets/search.d.mts +1 -1
  70. package/dist/presets/search.mjs +3 -2
  71. package/dist/{presets-BtyFwTO4.mjs → presets-DWsYQdbV.mjs} +1 -1
  72. package/dist/{queryCachePlugin-emHb0CuX.mjs → queryCachePlugin-DzqLN904.mjs} +2 -2
  73. package/dist/{registerRoute-CPmdkZGu.mjs → registerRoute-DGSREwPw.mjs} +20 -2
  74. package/dist/registry/index.d.mts +1 -1
  75. package/dist/registry/index.mjs +2 -2
  76. package/dist/{registry-Bm9LjWKs.mjs → registry-vcOCtPij.mjs} +1 -1
  77. package/dist/{schemaIR-D1MJwqmp.mjs → schemaIR-ajetw3Fv.mjs} +1 -42
  78. package/dist/scim/index.mjs +2 -2
  79. package/dist/sync/changelog.d.mts +2 -0
  80. package/dist/sync/changelog.mjs +2 -0
  81. package/dist/testing/index.d.mts +2 -2
  82. package/dist/testing/index.mjs +2 -2
  83. package/dist/types/index.d.mts +2 -2
  84. package/dist/{types-CmkknLzI.d.mts → types-BHMKlMBU.d.mts} +53 -195
  85. package/dist/{types-D60PFwfG.d.mts → types-C9b2HR5W.d.mts} +1 -1
  86. package/dist/utils/index.d.mts +1 -1
  87. package/dist/utils/index.mjs +1 -1
  88. package/dist/{utils-C6QQ9-hd.mjs → utils-ChjYQpjn.mjs} +1400 -1400
  89. package/dist/{validate-CRcaWzp2.mjs → validate-C2mGgSXg.mjs} +3 -3
  90. package/package.json +22 -8
  91. package/skills/arc/SKILL.md +10 -0
  92. package/skills/arc/references/mcp.md +2 -0
@@ -0,0 +1,384 @@
1
+ import { FastifyInstance } from "fastify";
2
+
3
+ //#region src/factory/loadResources.d.ts
4
+ /**
5
+ * loadResources — Auto-discover resource files from a directory.
6
+ *
7
+ * Scans for `*.resource.{ts,js,mts,mjs}` files, imports each,
8
+ * and collects their default exports. No barrel file needed.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { createApp, loadResources } from '@classytic/arc/factory';
13
+ *
14
+ * // Recommended: import.meta.url — works in both src/ (dev) and dist/ (prod)
15
+ * const app = await createApp({
16
+ * resources: await loadResources(import.meta.url),
17
+ * auth: { type: 'jwt', jwt: { secret: process.env.JWT_SECRET } },
18
+ * });
19
+ *
20
+ * // Or explicit path (must match runtime layout)
21
+ * const app2 = await createApp({
22
+ * resources: await loadResources('./src/resources'),
23
+ * });
24
+ * ```
25
+ *
26
+ * File convention:
27
+ * ```
28
+ * src/resources/
29
+ * product/product.resource.ts → export default defineResource({ name: 'product', ... })
30
+ * order/order.resource.ts → export default defineResource({ name: 'order', ... })
31
+ * ```
32
+ */
33
+ /**
34
+ * Resource interface — the contract between `loadResources`/`createApp` and resource definitions.
35
+ *
36
+ * Matches the shape of `ResourceDefinition` from `defineResource()` without requiring
37
+ * the import. All properties except `toPlugin` are optional so plain objects work too:
38
+ *
39
+ * ```typescript
40
+ * // Full resource (from defineResource)
41
+ * const product = defineResource({ name: 'product', ... }); // satisfies ResourceLike
42
+ *
43
+ * // Minimal resource (plain object)
44
+ * const simple: ResourceLike = { name: 'ping', toPlugin: () => () => {} };
45
+ * ```
46
+ *
47
+ * **DO NOT add an index signature** (`[key: string]: unknown`) to this interface.
48
+ * Class instances (like `ResourceDefinition`) don't implicitly carry index signatures,
49
+ * so adding one here makes `ResourceDefinition` *unassignable* to `ResourceLike` —
50
+ * the exact opposite of the intent. TypeScript's structural typing already allows
51
+ * classes with extra properties to satisfy this interface without an index signature.
52
+ */
53
+ interface ResourceLike {
54
+ /** Plugin factory — called by createApp to register routes */
55
+ toPlugin: () => unknown;
56
+ /** Resource name (used for route generation, logging, duplicate detection) */
57
+ name?: string;
58
+ /** Route prefix (default: `/${name}s`) */
59
+ prefix?: string;
60
+ /** Skip the global `resourcePrefix` from createApp — register at root */
61
+ skipGlobalPrefix?: boolean;
62
+ /** Display name for docs/OpenAPI */
63
+ displayName?: string;
64
+ /** Applied preset names */
65
+ _appliedPresets?: string[];
66
+ }
67
+ /**
68
+ * Resource module — what a `.resource.ts` file's default (or named) export
69
+ * may resolve to.
70
+ *
71
+ * Two shapes accepted:
72
+ * 1. **Plain `ResourceLike`** — the result of `defineResource({...})`.
73
+ * Used as-is; no engine wiring needed.
74
+ * 2. **Factory `(ctx: TContext) => ResourceLike | Promise<ResourceLike>`**
75
+ * — a function arc calls with the `context` from `LoadResourcesOptions`.
76
+ * Eliminates the parallel `createXResource(engine)` factory files +
77
+ * `exclude: [...]` bookkeeping that engine-bound resources used to need.
78
+ *
79
+ * Detection is by `typeof === 'function'`: `ResourceDefinition` instances
80
+ * (returned by `defineResource()`) are class instances (`typeof === 'object'`),
81
+ * so the two shapes are unambiguous in practice.
82
+ */
83
+ type ResourceModule<TContext = unknown> = ResourceLike | ((ctx: TContext) => ResourceLike | Promise<ResourceLike>);
84
+ interface LoadResourcesOptions<TContext = unknown> {
85
+ /** File pattern suffix (default: '.resource'). Matches `*.resource.{ts,js,mts,mjs}`. */
86
+ suffix?: string;
87
+ /** Recurse into subdirectories (default: true) */
88
+ recursive?: boolean;
89
+ /**
90
+ * Context passed to factory-style default exports. Resources whose default
91
+ * export is a function `(ctx) => ResourceLike` are called with this value;
92
+ * plain `ResourceLike` exports are returned unchanged.
93
+ *
94
+ * Use this to thread engine handles into engine-bound resources without
95
+ * creating parallel factory files outside `loadResources`'s sweep:
96
+ *
97
+ * ```ts
98
+ * // category.resource.ts
99
+ * import type { AppContext } from '#core/app/context.js';
100
+ * export default (ctx: AppContext) =>
101
+ * defineResource({
102
+ * name: 'category',
103
+ * adapter: createMongooseAdapter(
104
+ * ctx.catalog.models.Category,
105
+ * ctx.catalog.repositories.category,
106
+ * ),
107
+ * });
108
+ *
109
+ * // create-arc-app-options.ts
110
+ * resources: async () => {
111
+ * const [catalog, flow] = await Promise.all([
112
+ * ensureCatalogEngine(),
113
+ * ensureFlowEngine(),
114
+ * ]);
115
+ * return loadResources(import.meta.url, { context: { catalog, flow } });
116
+ * }
117
+ * ```
118
+ *
119
+ * Backwards compatible — pre-2.11.1 callers omit `context`, plain exports
120
+ * keep working unchanged. Factories that need a context but receive
121
+ * `undefined` should narrow defensively.
122
+ */
123
+ context?: TContext;
124
+ /**
125
+ * Resource names to exclude. Matched against the resource's `.name` property
126
+ * after import, so you use the resource name (not the filename).
127
+ *
128
+ * @example
129
+ * ```ts
130
+ * await loadResources('./src/resources', { exclude: ['debug', 'legacy-report'] })
131
+ * ```
132
+ */
133
+ exclude?: string[];
134
+ /**
135
+ * Resource names to include. When set, only matching resources are returned.
136
+ * Takes priority over `exclude`.
137
+ *
138
+ * @example
139
+ * ```ts
140
+ * // Only load these two resources (useful for testing or microservice splits)
141
+ * await loadResources('./src/resources', { include: ['product', 'order'] })
142
+ * ```
143
+ */
144
+ include?: string[];
145
+ /**
146
+ * Optional logger override for diagnostics. When omitted, warnings flow
147
+ * through arc's standard logger (`arcLog('loadResources')`) — same path
148
+ * as every other arc-internal warning, controlled by `ARC_SUPPRESS_WARNINGS=1`
149
+ * and routable via `configureArcLogger({ writer })`.
150
+ *
151
+ * Pass any object with `warn(msg)` to override (e.g. `fastify.log` —
152
+ * which is what `registerResources` passes automatically when arc's
153
+ * factory triggers auto-discovery via `resourceDir`).
154
+ *
155
+ * Pre-2.11.1 had a `silent: boolean` flag and "silent by default" semantics;
156
+ * both removed. Migration:
157
+ *
158
+ * ```ts
159
+ * // Pre-2.11.1 // 2.11.1+
160
+ * loadResources(url, { silent: true }); // ARC_SUPPRESS_WARNINGS=1 (env)
161
+ * // OR configureArcLogger({ writer })
162
+ * loadResources(url, { silent: !isDev }); // ARC_SUPPRESS_WARNINGS=1 in prod
163
+ * loadResources(url, { logger: pinoAdapter }); // unchanged — still works
164
+ * ```
165
+ */
166
+ logger?: {
167
+ warn: (msg: string) => void;
168
+ };
169
+ }
170
+ /**
171
+ * Scan a directory for resource files and import their default exports.
172
+ *
173
+ * Accepts a directory path OR `import.meta.url` (file:// URL).
174
+ * When given a URL, resolves to the directory containing that file —
175
+ * so `loadResources(import.meta.url)` works in both dev (`src/`) and
176
+ * production (`dist/`) without path gymnastics.
177
+ *
178
+ * @param dir - Directory path, or `import.meta.url` (file:// URL resolved to its dirname)
179
+ * @param options - Pattern and recursion options
180
+ * @returns Array of resource definitions (anything with `.toPlugin()`)
181
+ *
182
+ * @example
183
+ * ```ts
184
+ * // Works from both src/ and dist/ — resolves relative to the calling file
185
+ * await loadResources(import.meta.url);
186
+ *
187
+ * // Subdirectory relative to the calling file
188
+ * await loadResources(import.meta.url, { suffix: '.resource' });
189
+ *
190
+ * // Explicit path (must match runtime layout)
191
+ * await loadResources('./src/resources');
192
+ * ```
193
+ */
194
+ declare function loadResources<TContext = unknown>(dir: string, options?: LoadResourcesOptions<TContext>): Promise<ResourceLike[]>;
195
+ //#endregion
196
+ //#region src/factory/module.d.ts
197
+ interface ArcModule<TExports = unknown> {
198
+ /** Stable identifier — appears in boot logs and duplicate-module detection. */
199
+ readonly name: string;
200
+ /**
201
+ * Names of modules this one must be composed AFTER. arc topologically orders
202
+ * the `modules` array from these edges before ANY phase runs, so a
203
+ * dependency's `bootstrap` (and thus its `fastify.arc.modules[dep]` export)
204
+ * is always live before this module's bootstrap, resources, or
205
+ * afterResources. Teardown (`onClose`) runs in the reverse of that order.
206
+ *
207
+ * Use this instead of relying on list position when a module reads another's
208
+ * public export — e.g. `@classytic/arc-reservation` wiring off
209
+ * `arc.modules.order`:
210
+ *
211
+ * ```ts
212
+ * defineModule({ name: "reservation", dependsOn: ["order"], bootstrap: (f) => {
213
+ * const order = getModuleExports<OrderEngine>(f, "order"); // guaranteed live
214
+ * …
215
+ * }});
216
+ * ```
217
+ *
218
+ * The order is a STABLE topological sort: modules with no `dependsOn` (and
219
+ * any two modules with no edge between them) keep their original list order,
220
+ * so adding `dependsOn` never silently reorders an unrelated module. All
221
+ * failure modes are fail-fast at boot: a name not in the composed set, a
222
+ * self-reference, and dependency CYCLES each throw with the offending path.
223
+ *
224
+ * **`dependsOn` is COMPOSITION order, not lazy loading.** Every module input
225
+ * (including dynamic-import thunks) is resolved — imported — up front via
226
+ * `Promise.all` BEFORE the sort; `dependsOn` then orders the *composition*
227
+ * (which module's `plugins`/`bootstrap` runs first), it does NOT delay
228
+ * *importing* a dependent until its dependency is ready. Use a thunk to gate
229
+ * whether a module is imported at all (region/tier packs); use `dependsOn`
230
+ * to order modules that are already selected.
231
+ */
232
+ readonly dependsOn?: readonly string[];
233
+ /**
234
+ * Fastify plugins / decorators this module needs — the module-level analog
235
+ * of the app's `plugins()` slot. Runs in the plugins phase: AFTER the app's
236
+ * own `plugins()` (so module infra can build on app foundations like a DB
237
+ * connection) and in `dependsOn` order, but BEFORE any module `bootstrap` —
238
+ * so engines initialised in `bootstrap` can rely on what's registered here.
239
+ *
240
+ * Separating this from `bootstrap` keeps lifecycle intent explicit for
241
+ * published ecosystem packages: `plugins` = "register infra"; `bootstrap` =
242
+ * "initialise engines (and return the public export)". Registering a plugin
243
+ * inside `bootstrap` still works — this slot just makes the two distinct.
244
+ */
245
+ plugins?: (fastify: FastifyInstance) => void | Promise<void>;
246
+ /**
247
+ * Domain init — runs in the `bootstrap` phase (after all `plugins`, before
248
+ * resources). Initialize engines / singletons / event subscriptions here so
249
+ * they are live when this module's `resources` factory runs.
250
+ *
251
+ * A returned value becomes the module's PUBLIC EXPORT, recorded at
252
+ * `fastify.arc.modules[name]` (wiki/modules.md — "no container", layer 2).
253
+ * Later modules' bootstraps can read it (list order = init order), which is
254
+ * how cross-module ports are wired without a DI container. Declare the
255
+ * export shape via `defineModule<TExports>` and read it back with the typed
256
+ * accessor — no cast at the consuming end:
257
+ *
258
+ * ```ts
259
+ * // arc-invoice bootstrap, composed AFTER arc-accounting:
260
+ * const acct = getModuleExports<AccountingEngine>(fastify, "accounting");
261
+ * ```
262
+ */
263
+ bootstrap?: (fastify: FastifyInstance) => TExports | Promise<TExports>;
264
+ /**
265
+ * The module's resources. Array or factory — the factory form runs AFTER all
266
+ * bootstraps, so `defineResource(...)` receives fully-booted engines. Flows
267
+ * through arc's normal registration (prefix, dedup, docs), identical to a
268
+ * top-level `resources` entry.
269
+ */
270
+ resources?: ReadonlyArray<ResourceLike> | ((fastify: FastifyInstance) => ReadonlyArray<ResourceLike> | Promise<ReadonlyArray<ResourceLike>>);
271
+ /**
272
+ * Post-registration wiring — runs in the `afterResources` phase, once this
273
+ * module's routes are mounted. Use for cross-resource event subscriptions the
274
+ * module owns.
275
+ */
276
+ afterResources?: (fastify: FastifyInstance) => void | Promise<void>;
277
+ /**
278
+ * Teardown — registered as a Fastify `onClose` hook. Destroy engines, stop
279
+ * timers, flush the module's outbox. Modules close in REVERSE list order
280
+ * (last composed, first closed), mirroring init.
281
+ */
282
+ onClose?: (fastify: FastifyInstance) => void | Promise<void>;
283
+ }
284
+ /**
285
+ * A module in any of the forms `createApp({ modules })` accepts:
286
+ *
287
+ * - `ArcModule` — eager (already imported)
288
+ * - `Promise<ArcModule>` — an in-flight import
289
+ * - `() => ArcModule | Promise<…>` — a thunk, resolved at boot
290
+ *
291
+ * The **thunk of a dynamic import** is the point of this union — it lets a host
292
+ * compose modules *logically* and load them *lazily / conditionally*, the
293
+ * `next/dynamic` idea applied to backend domains. The module's code (and its
294
+ * heavy deps) is only pulled in when the thunk runs, so region- or tier-gated
295
+ * packs never enter the bundle path they aren't selected for:
296
+ *
297
+ * ```ts
298
+ * const taxPack =
299
+ * region === "BD"
300
+ * ? () => import("@classytic/bd-tax").then((m) => m.createBdTaxModule(deps))
301
+ * : () => import("@classytic/us-tax").then((m) => m.createUsTaxModule(deps));
302
+ *
303
+ * await createApp({ modules: [coreModule(deps), taxPack] });
304
+ * // only the selected tax package is imported + composed
305
+ * ```
306
+ */
307
+ type ArcModuleInput<TExports = unknown> = ArcModule<TExports> | Promise<ArcModule<TExports>> | (() => ArcModule<TExports> | Promise<ArcModule<TExports>>);
308
+ /**
309
+ * Resolve any module-input form to a concrete `ArcModule`. A thunk is invoked
310
+ * (this is where a dynamic `import()` fires); a promise (or plain module) is
311
+ * awaited. Called once per module at the start of the bootstrap phase.
312
+ */
313
+ declare function resolveModule(input: ArcModuleInput): Promise<ArcModule>;
314
+ /**
315
+ * Order modules for composition by their `dependsOn` edges — a STABLE
316
+ * topological sort. Called once at the start of the bootstrap phase; every
317
+ * subsequent phase (bootstrap, resources, afterResources, and reverse-order
318
+ * onClose) iterates the returned list, so a module's declared dependencies are
319
+ * always composed before it.
320
+ *
321
+ * "Stable" = modules with no edge between them keep their original list order,
322
+ * so declaring `dependsOn` on one module never silently reorders an unrelated
323
+ * one. Backward compatible: a `modules` array with NO `dependsOn` anywhere is
324
+ * returned unchanged.
325
+ *
326
+ * Fail-fast — throws (never reorders past a broken contract) on:
327
+ * - duplicate module names (the name is the graph key)
328
+ * - a `dependsOn` name not present in the composed set
329
+ * - a self-reference (`dependsOn` includes the module's own name)
330
+ * - a dependency cycle (reports the concrete `a → b → … → a` path)
331
+ */
332
+ declare function orderModules(modules: readonly ArcModule[]): ArcModule[];
333
+ /**
334
+ * Typed module registry — hosts augment this via declaration merging so
335
+ * `getModuleExports(f, "order")` infers the export type without a manual type
336
+ * argument (the fastify / awilix pattern):
337
+ *
338
+ * ```ts
339
+ * declare module "@classytic/arc/factory" {
340
+ * interface ArcModuleRegistry {
341
+ * order: OrderEngine;
342
+ * accounting: AccountingEngine;
343
+ * }
344
+ * }
345
+ * ```
346
+ *
347
+ * Left empty here so the fallback `getModuleExports<T>(f, name: string)` stays
348
+ * available for apps that don't augment it.
349
+ */
350
+ interface ArcModuleRegistry {}
351
+ /**
352
+ * Identity helper for authoring a typed module — mirrors `defineResource`.
353
+ * Gives inference + a single obvious construction site; does no work.
354
+ *
355
+ * `TExports` is inferred from the `bootstrap` return value, so a module
356
+ * author gets a typed public export for free:
357
+ *
358
+ * ```ts
359
+ * export const accountingModule = (deps: Deps) =>
360
+ * defineModule({
361
+ * name: "accounting",
362
+ * bootstrap: async () => createAccountingEngine(deps), // TExports inferred
363
+ * });
364
+ * ```
365
+ */
366
+ declare function defineModule<TExports = unknown>(module: ArcModule<TExports>): ArcModule<TExports>;
367
+ /**
368
+ * Typed accessor for a module's public export (its `bootstrap` return value),
369
+ * recorded at `fastify.arc.modules[name]`.
370
+ *
371
+ * Throwing, in line with the fail-fast contract (and `requireOrgId`-style
372
+ * accessors): a missing entry means the module either isn't composed, is
373
+ * composed AFTER the caller (list order = init order), or returned nothing —
374
+ * all wiring bugs that must surface at boot, not as `undefined` downstream.
375
+ *
376
+ * The type parameter is an assertion, not a proof. Two ways to type it:
377
+ * - augment `ArcModuleRegistry` once — then the name alone infers the type:
378
+ * `getModuleExports(f, "accounting")` → `AccountingEngine`.
379
+ * - or pass it inline: `getModuleExports<AccountingEngine>(f, "accounting")`.
380
+ */
381
+ declare function getModuleExports<K extends keyof ArcModuleRegistry>(fastify: FastifyInstance, name: K): ArcModuleRegistry[K];
382
+ declare function getModuleExports<TExports = unknown>(fastify: FastifyInstance, name: string): TExports;
383
+ //#endregion
384
+ export { getModuleExports as a, LoadResourcesOptions as c, loadResources as d, defineModule as i, ResourceLike as l, ArcModuleInput as n, orderModules as o, ArcModuleRegistry as r, resolveModule as s, ArcModule as t, ResourceModule as u };
@@ -1,8 +1,8 @@
1
1
  import { t as getUserRoles } from "./types-XTApa8b6.mjs";
2
2
  import { n as convertRouteSchema } from "./schemaConverter-U0MnO9vd.mjs";
3
- import { t as resolveActionPermission } from "./actionPermissions-h7DYDNMg.mjs";
4
- import { t as pluralize } from "./pluralize-DccFV9R7.mjs";
5
- import { t as buildActionBodySchema } from "./createActionRouter-CagItpxI.mjs";
3
+ import { t as resolveActionPermission } from "./actionPermissions-C9RMiIpc.mjs";
4
+ import { t as pluralize } from "./pluralize-BhrgwZb9.mjs";
5
+ import { t as buildActionBodySchema } from "./createActionRouter-HlQso0jO.mjs";
6
6
  import fp from "fastify-plugin";
7
7
  //#region src/docs/openapi/canonical-schemas.ts
8
8
  /**
@@ -1,3 +1,3 @@
1
1
  import { a as applyFieldWritePermissions, c as PermissionCheck, d as UserBase, f as getUserRoles, i as applyFieldReadPermissions, l as PermissionContext, n as FieldPermissionMap, o as fields, p as normalizeRoles, r as FieldPermissionType, s as resolveEffectiveRoles, t as FieldPermission, u as PermissionResult } from "../fields-C7ahdGYf.mjs";
2
- import { A as requireRoles, C as allOf, D as not, E as denyAll, F as RequireAgentScopeOptions, I as RequireMandateOptions, L as requireAgentScope, M as when, N as applyPermissionResult, O as requireAuth, P as normalizePermissionResult, R as requireDPoP, S as createOrgPermissions, T as anyOf, _ as ConnectEventsOptions, a as presets_d_exports, b as PermissionEventBus, c as readOnly, d as requireOrgRole, f as requireScopeContext, g as createRoleHierarchy, h as RoleHierarchy, i as ownerWithAdminBypass, j as roles, k as requireOwnership, l as requireOrgInScope, m as requireTeamMembership, n as authenticated, o as publicRead, p as requireServiceScope, r as fullPublic, s as publicReadAdminWrite, t as adminOnly, u as requireOrgMembership, v as DynamicPermissionMatrix, w as allowPublic, x as createDynamicPermissionMatrix, y as DynamicPermissionMatrixConfig, z as requireMandate } from "../index-CRKiiP5o.mjs";
2
+ import { A as requireRoles, C as allOf, D as not, E as denyAll, F as RequireAgentScopeOptions, I as RequireMandateOptions, L as requireAgentScope, M as when, N as applyPermissionResult, O as requireAuth, P as normalizePermissionResult, R as requireDPoP, S as createOrgPermissions, T as anyOf, _ as ConnectEventsOptions, a as presets_d_exports, b as PermissionEventBus, c as readOnly, d as requireOrgRole, f as requireScopeContext, g as createRoleHierarchy, h as RoleHierarchy, i as ownerWithAdminBypass, j as roles, k as requireOwnership, l as requireOrgInScope, m as requireTeamMembership, n as authenticated, o as publicRead, p as requireServiceScope, r as fullPublic, s as publicReadAdminWrite, t as adminOnly, u as requireOrgMembership, v as DynamicPermissionMatrix, w as allowPublic, x as createDynamicPermissionMatrix, y as DynamicPermissionMatrixConfig, z as requireMandate } from "../index-CdFkIMEd.mjs";
3
3
  export { type ConnectEventsOptions, type DynamicPermissionMatrix, type DynamicPermissionMatrixConfig, type FieldPermission, type FieldPermissionMap, type FieldPermissionType, type PermissionCheck, type PermissionContext, type PermissionEventBus, type PermissionResult, type RequireAgentScopeOptions, type RequireMandateOptions, type RoleHierarchy, type UserBase, adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, applyPermissionResult, authenticated, createDynamicPermissionMatrix, createOrgPermissions, createRoleHierarchy, denyAll, fields, fullPublic, getUserRoles, normalizePermissionResult, normalizeRoles, not, ownerWithAdminBypass, presets_d_exports as permissions, publicRead, publicReadAdminWrite, readOnly, requireAgentScope, requireAuth, requireDPoP, requireMandate, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, resolveEffectiveRoles, roles, when };
@@ -1,3 +1,3 @@
1
- import { A as requireMandate, C as requireAuth, D as when, E as roles, F as applyFieldWritePermissions, I as fields, L as resolveEffectiveRoles, N as normalizePermissionResult, O as requireAgentScope, P as applyFieldReadPermissions, S as not, T as requireRoles, _ as requireTeamMembership, a as presets_exports, b as anyOf, c as readOnly, d as createOrgPermissions, f as requireOrgInScope, g as requireServiceScope, h as requireScopeContext, i as ownerWithAdminBypass, j as applyPermissionResult, k as requireDPoP, l as createRoleHierarchy, m as requireOrgRole, n as authenticated, o as publicRead, p as requireOrgMembership, r as fullPublic, s as publicReadAdminWrite, t as adminOnly, u as createDynamicPermissionMatrix, v as allOf, w as requireOwnership, x as denyAll, y as allowPublic } from "../permissions-BPB1xqGf.mjs";
1
+ import { A as requireMandate, C as requireAuth, D as when, E as roles, F as applyFieldWritePermissions, I as fields, L as resolveEffectiveRoles, N as normalizePermissionResult, O as requireAgentScope, P as applyFieldReadPermissions, S as not, T as requireRoles, _ as requireTeamMembership, a as presets_exports, b as anyOf, c as readOnly, d as createOrgPermissions, f as requireOrgInScope, g as requireServiceScope, h as requireScopeContext, i as ownerWithAdminBypass, j as applyPermissionResult, k as requireDPoP, l as createRoleHierarchy, m as requireOrgRole, n as authenticated, o as publicRead, p as requireOrgMembership, r as fullPublic, s as publicReadAdminWrite, t as adminOnly, u as createDynamicPermissionMatrix, v as allOf, w as requireOwnership, x as denyAll, y as allowPublic } from "../permissions-CgbOLJZG.mjs";
2
2
  import { n as normalizeRoles, t as getUserRoles } from "../types-XTApa8b6.mjs";
3
3
  export { adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, applyPermissionResult, authenticated, createDynamicPermissionMatrix, createOrgPermissions, createRoleHierarchy, denyAll, fields, fullPublic, getUserRoles, normalizePermissionResult, normalizeRoles, not, ownerWithAdminBypass, presets_exports as permissions, publicRead, publicReadAdminWrite, readOnly, requireAgentScope, requireAuth, requireDPoP, requireMandate, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, resolveEffectiveRoles, roles, when };
@@ -167,7 +167,7 @@ function applyFieldWritePermissions(body, fieldPermissions, userRoles) {
167
167
  function resolveEffectiveRoles(userRoles, orgRoles) {
168
168
  if (orgRoles.length === 0) return [...userRoles];
169
169
  if (userRoles.length === 0) return [...orgRoles];
170
- return [...new Set([...userRoles, ...orgRoles])];
170
+ return [.../* @__PURE__ */ new Set([...userRoles, ...orgRoles])];
171
171
  }
172
172
  //#endregion
173
173
  //#region src/permissions/applyPermissionResult.ts
@@ -1482,11 +1482,19 @@ function fullPublic(overrides) {
1482
1482
  /**
1483
1483
  * Read-only: list + get authenticated, write operations denied.
1484
1484
  * Useful for computed/derived resources.
1485
+ *
1486
+ * Writes carry an explicit `denyAll` check — an omitted CRUD permission
1487
+ * mounts the route with NO gate (public-by-omission), so leaving
1488
+ * create/update/delete undefined here would expose unauthenticated writes.
1489
+ * Hosts that disable write routes entirely (`disabledRoutes`) are unaffected.
1485
1490
  */
1486
1491
  function readOnly(overrides) {
1487
1492
  return withOverrides({
1488
1493
  list: requireAuth(),
1489
- get: requireAuth()
1494
+ get: requireAuth(),
1495
+ create: denyAll("Write operations are disabled on this read-only resource"),
1496
+ update: denyAll("Write operations are disabled on this read-only resource"),
1497
+ delete: denyAll("Write operations are disabled on this read-only resource")
1490
1498
  }, overrides);
1491
1499
  }
1492
1500
  //#endregion
@@ -1,4 +1,4 @@
1
- import { Ft as OperationFilter, It as PipelineConfig, Lt as PipelineContext, Mt as Guard, Nt as Interceptor, Pt as NextFunction, Rt as PipelineStep, yt as IControllerResponse, zt as Transform } from "../index-CHNQIhcb.mjs";
1
+ import { Bt as Transform, Ft as NextFunction, It as OperationFilter, Lt as PipelineConfig, Nt as Guard, Pt as Interceptor, Rt as PipelineContext, bt as IControllerResponse, zt as PipelineStep } from "../index-_--GyzcO.mjs";
2
2
 
3
3
  //#region src/pipeline/guard.d.ts
4
4
  interface GuardOptions {
@@ -1,5 +1,5 @@
1
- import { Kt as AnyRecord, Q as MiddlewareConfig, dt as RouteDefinition, mt as RouteSchemaOptions, nt as PresetHook } from "../index-CHNQIhcb.mjs";
2
- import { a as arcCorePlugin, i as _default, n as ArcCorePluginOptions, r as PluginMeta, t as ArcCore } from "../fastify-augmentation-Cxb0ROIw.mjs";
1
+ import { Q as MiddlewareConfig, ft as RouteDefinition, ht as RouteSchemaOptions, nt as PresetHook, qt as AnyRecord } from "../index-_--GyzcO.mjs";
2
+ import { a as arcCorePlugin, i as _default, n as ArcCorePluginOptions, r as PluginMeta, t as ArcCore } from "../fastify-augmentation-CCQJEDgh.mjs";
3
3
  import { _ as HealthOptions, a as MetricsCollector, c as metricsPlugin, d as ssePlugin, f as CachingOptions, g as HealthCheck, h as cachingPlugin, i as MetricEntry, l as SSEOptions, m as _default$1, n as _default$7, o as MetricsOptions, p as CachingRule, r as versioningPlugin, s as _default$4, t as VersioningOptions, u as _default$6, v as _default$3, y as healthPlugin } from "../versioning-D_eBCfNr.mjs";
4
4
  import { i as errorHandlerPlugin, n as ErrorMapper, r as defaultIsDuplicateKeyError, t as ErrorHandlerOptions } from "../errorHandler-BtUUDPEa.mjs";
5
5
  import { t as TracingOptions } from "../tracing-D8jlGXP7.mjs";
@@ -24,10 +24,15 @@ interface CreatePluginDefinition<TRootOpts extends AnyRecord = AnyRecord, TResou
24
24
  */
25
25
  forRoot?: (fastify: FastifyInstance, opts: TRootOpts) => void | Promise<void>;
26
26
  /**
27
- * Per-resource configuration function. Called for each resource that uses this plugin.
28
- * Returns hooks, routes, middlewares, etc. to merge into the resource config.
27
+ * Per-resource configuration function. Called (via `plugin.forResource(opts)`)
28
+ * to PRODUCE a partial resource config — hooks, routes, middlewares — that the
29
+ * host spreads into `defineResource(...)`. It receives only the plugin's own
30
+ * `opts`: the resource does not exist yet at this call site, so it cannot be
31
+ * inspected here (that was a false promise pre-2.20; the unused `resourceConfig`
32
+ * parameter is removed). For behavior that must vary by resource, key off the
33
+ * plugin's `opts` the host passes per resource.
29
34
  */
30
- forResource?: (resourceConfig: AnyRecord, opts: TResourceOpts) => PluginResourceResult;
35
+ forResource?: (opts: TResourceOpts) => PluginResourceResult;
31
36
  }
32
37
  interface ArcPlugin<TRootOpts extends AnyRecord = AnyRecord, TResourceOpts extends AnyRecord = AnyRecord> {
33
38
  /** Plugin name */
@@ -1,9 +1,9 @@
1
- import { p as MUTATION_OPERATIONS } from "../constants-gaEeMlz-.mjs";
1
+ import { p as MUTATION_OPERATIONS } from "../constants-DNre0wRg.mjs";
2
2
  import { c as getOrgId } from "../types-bHblZ9YN.mjs";
3
3
  import { n as requestContext } from "../requestContext-BZKOr13H.mjs";
4
4
  import { t as hasEvents } from "../typeGuards-C9KXUly6.mjs";
5
5
  import { t as HookSystem } from "../HookSystem-C1vB_Gc9.mjs";
6
- import { t as ResourceRegistry } from "../ResourceRegistry-5fKZwhK_.mjs";
6
+ import { t as ResourceRegistry } from "../ResourceRegistry-7RnrEWNP.mjs";
7
7
  import { n as caching_default, t as cachingPlugin } from "../caching-_NJeDd1_.mjs";
8
8
  import { n as errorHandlerPlugin, t as defaultIsDuplicateKeyError } from "../errorHandler-Dxf6P_kV.mjs";
9
9
  import { n as metrics_default, t as metricsPlugin } from "../metrics-fdxI5mn_.mjs";
@@ -131,7 +131,7 @@ function createPlugin(name, definition) {
131
131
  },
132
132
  forResource(opts) {
133
133
  if (!definition.forResource) return {};
134
- return definition.forResource({}, opts ?? {});
134
+ return definition.forResource(opts ?? {});
135
135
  }
136
136
  };
137
137
  }
@@ -58,7 +58,7 @@ try {
58
58
  function createTracerProvider(options) {
59
59
  if (!isAvailable || !NodeTracerProvider || !BatchSpanProcessor || !OTLPTraceExporter) return null;
60
60
  const { serviceName = "@classytic/arc", serviceVersion, exporterUrl = "http://localhost:4318/v1/traces" } = options;
61
- const resolvedVersion = serviceVersion ?? "2.18.5";
61
+ const resolvedVersion = serviceVersion ?? "2.20.0";
62
62
  const exporter = new OTLPTraceExporter({ url: exporterUrl });
63
63
  const provider = new NodeTracerProvider({ resource: { attributes: {
64
64
  "service.name": serviceName,
@@ -34,7 +34,7 @@ const IRREGULARS = {
34
34
  vertex: "vertices",
35
35
  criterion: "criteria"
36
36
  };
37
- const UNCOUNTABLES = new Set([
37
+ const UNCOUNTABLES = /* @__PURE__ */ new Set([
38
38
  "sheep",
39
39
  "fish",
40
40
  "deer",
@@ -65,7 +65,7 @@ function pluralize(word) {
65
65
  if (lower.endsWith("f") && !lower.endsWith("ff") && !lower.endsWith("roof") && !lower.endsWith("chief") && !lower.endsWith("belief")) return `${word.slice(0, -1)}ves`;
66
66
  if (lower.endsWith("y") && !/[aeiou]y$/i.test(lower)) return `${word.slice(0, -1)}ies`;
67
67
  if (lower.endsWith("is")) return `${word.slice(0, -2)}es`;
68
- if (new Set([
68
+ if ((/* @__PURE__ */ new Set([
69
69
  "cactus",
70
70
  "stimulus",
71
71
  "focus",
@@ -76,7 +76,7 @@ function pluralize(word) {
76
76
  "alumnus",
77
77
  "terminus",
78
78
  "bacillus"
79
- ]).has(lower)) return `${word.slice(0, -2)}i`;
79
+ ])).has(lower)) return `${word.slice(0, -2)}i`;
80
80
  if (lower.endsWith("z") && !lower.endsWith("zz")) return `${word}zes`;
81
81
  if (/(?:s|sh|ch|x|zz)$/i.test(lower)) return `${word}es`;
82
82
  if (lower.endsWith("o") && !/[aeiou]o$/i.test(lower)) return `${word}es`;
@@ -1,4 +1,4 @@
1
- import { rt as PresetResult } from "../index-CHNQIhcb.mjs";
1
+ import { rt as PresetResult } from "../index-_--GyzcO.mjs";
2
2
  import { i as RequestScope } from "../types-LNebCoJx.mjs";
3
3
  import { c as PermissionCheck } from "../fields-C7ahdGYf.mjs";
4
4
  import { a as StorageReadResult, i as StorageReadRange, n as StorageContext, o as StorageUploadInput, r as StorageFile, t as Storage } from "../storage-Co_PQpeQ.mjs";
@@ -1,6 +1,6 @@
1
1
  import { i as NotFoundError, u as ValidationError } from "../errors-DkO8Nk6-.mjs";
2
2
  import { c as getOrgId, g as getUserId } from "../types-bHblZ9YN.mjs";
3
- import { C as requireAuth, y as allowPublic } from "../permissions-BPB1xqGf.mjs";
3
+ import { C as requireAuth, y as allowPublic } from "../permissions-CgbOLJZG.mjs";
4
4
  import { t as multipartBody } from "../multipartBody-CHEQSZ6G.mjs";
5
5
  //#region src/presets/filesUpload.ts
6
6
  const DEFAULT_FIELD_NAME = "file";
@@ -1,4 +1,4 @@
1
- import { Kt as AnyRecord, bt as IRequestContext, d as PaginationResult, rt as PresetResult, st as ResourceConfig, yt as IControllerResponse } from "../index-CHNQIhcb.mjs";
1
+ import { bt as IControllerResponse, d as PaginationResult, qt as AnyRecord, rt as PresetResult, st as ResourceConfig, xt as IRequestContext } from "../index-_--GyzcO.mjs";
2
2
  import { FilesUploadPresetOptions, FilesUploadPresetPermissions, FilesUploadPresetRoutes, filesUploadPreset } from "./filesUpload.mjs";
3
3
  import { MultiTenantOptions, TenantFieldSpec, multiTenantPreset } from "./multiTenant.mjs";
4
4
  import { SearchHandler, SearchPresetOptions, SearchRouteConfig, searchPreset } from "./search.mjs";
@@ -237,7 +237,21 @@ type IAuditedPreset = never;
237
237
  * }
238
238
  * ```
239
239
  */
240
- type IPresetController<TDoc = unknown, TPresets extends "softDelete" | "slugLookup" | "tree" | never = never> = TPresets extends "softDelete" ? ISoftDeleteController<TDoc> : TPresets extends "slugLookup" ? ISlugLookupController<TDoc> : TPresets extends "tree" ? ITreeController<TDoc> : unknown;
240
+ /** Preset name → controller contract. Lookup table for {@link IPresetController}. */
241
+ interface PresetControllerContracts<TDoc> {
242
+ softDelete: ISoftDeleteController<TDoc>;
243
+ slugLookup: ISlugLookupController<TDoc>;
244
+ tree: ITreeController<TDoc>;
245
+ }
246
+ /**
247
+ * Collapse a union into an intersection. The pre-2.20 implementation used a
248
+ * distributive conditional, so `IPresetController<T, 'softDelete' | 'tree'>`
249
+ * produced a UNION of contracts — which a class cannot `implements`; the
250
+ * documented multi-preset example didn't compile. An indexed lookup over the
251
+ * union followed by this fold yields the intersection the example promises.
252
+ */
253
+ type UnionToIntersection<U> = (U extends unknown ? (x: U) => void : never) extends ((x: infer I) => void) ? I : never;
254
+ type IPresetController<TDoc = unknown, TPresets extends keyof PresetControllerContracts<TDoc> = never> = UnionToIntersection<PresetControllerContracts<TDoc>[TPresets]>;
241
255
  //#endregion
242
256
  //#region src/presets/index.d.ts
243
257
  /**
@@ -1,5 +1,5 @@
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-BtyFwTO4.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-DWsYQdbV.mjs";
3
3
  import { filesUploadPreset } from "./filesUpload.mjs";
4
4
  import { searchPreset } from "./search.mjs";
5
5
  export { applyPresets, auditedPreset, bulkPreset, filesUploadPreset, flexibleMultiTenantPreset, getAvailablePresets, getPreset, multiTenantPreset, ownedByUserPreset, registerPreset, searchPreset, slugLookupPreset, softDeletePreset, treePreset };
@@ -1,4 +1,4 @@
1
- import { J as CrudRouteKey, rt as PresetResult } from "../index-CHNQIhcb.mjs";
1
+ import { J as CrudRouteKey, rt as PresetResult } from "../index-_--GyzcO.mjs";
2
2
 
3
3
  //#region src/presets/multiTenant.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import "../constants-gaEeMlz-.mjs";
1
+ import "../constants-DNre0wRg.mjs";
2
2
  import { b as isElevated, c as getOrgId, d as getScopeContext, m as getTeamId, u as getRequestScope, v as hasOrgAccess } from "../types-bHblZ9YN.mjs";
3
3
  //#region src/presets/multiTenant.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { dt as RouteDefinition, ft as RouteMcpConfig, ht as ControllerHandler, rt as PresetResult } from "../index-CHNQIhcb.mjs";
1
+ import { ft as RouteDefinition, gt as ControllerHandler, pt as RouteMcpConfig, rt as PresetResult } from "../index-_--GyzcO.mjs";
2
2
  import { c as PermissionCheck } from "../fields-C7ahdGYf.mjs";
3
3
 
4
4
  //#region src/presets/search.d.ts
@@ -1,4 +1,4 @@
1
- import { C as requireAuth, y as allowPublic } from "../permissions-BPB1xqGf.mjs";
1
+ import { C as requireAuth, y as allowPublic } from "../permissions-CgbOLJZG.mjs";
2
2
  //#region src/presets/search.ts
3
3
  const BUILTINS = [
4
4
  {
@@ -84,7 +84,8 @@ function autoHandlerFor(repo, method) {
84
84
  return fn(body.input ?? body);
85
85
  };
86
86
  if (method === "searchSimilar") return async (req) => {
87
- return fn(req.body ?? {});
87
+ const body = req.body ?? {};
88
+ return fn(body);
88
89
  };
89
90
  return async (req) => {
90
91
  const body = req.body ?? {};
@@ -1,5 +1,5 @@
1
1
  import { b as isElevated, n as PUBLIC_SCOPE } from "./types-bHblZ9YN.mjs";
2
- import { C as requireAuth, T as requireRoles, y as allowPublic } from "./permissions-BPB1xqGf.mjs";
2
+ import { C as requireAuth, T as requireRoles, y as allowPublic } from "./permissions-CgbOLJZG.mjs";
3
3
  import { multiTenantPreset } from "./presets/multiTenant.mjs";
4
4
  //#region src/presets/ownedByUser.ts
5
5
  /**