@classytic/arc 2.19.0 → 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 (90) 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-D7NGwcAR.mjs → actionPermissions-C9RMiIpc.mjs} +1 -1
  6. package/dist/audit/index.mjs +1 -1
  7. package/dist/auth/index.d.mts +1 -1
  8. package/dist/auth/index.mjs +7 -5
  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-Ba-6Sue6.mjs → core-CWhyGkiM.mjs} +125 -53
  22. package/dist/{createActionRouter-B_WzBFyf.mjs → createActionRouter-HlQso0jO.mjs} +4 -4
  23. package/dist/{createAggregationRouter-B_G_nIjm.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/events/index.mjs +9 -6
  28. package/dist/factory/index.d.mts +3 -2
  29. package/dist/factory/index.mjs +2 -2
  30. package/dist/{fastify-augmentation-D-5_yQJi.d.mts → fastify-augmentation-CCQJEDgh.d.mts} +12 -1
  31. package/dist/{generate-Brans3fW.mjs → generate-usRSdQmP.mjs} +4 -3
  32. package/dist/hooks/index.d.mts +1 -1
  33. package/dist/idempotency/index.mjs +1 -1
  34. package/dist/{index-CRKiiP5o.d.mts → index-CdFkIMEd.d.mts} +5 -0
  35. package/dist/{index-CP6A1Ffj.d.mts → index-DUa8WHz3.d.mts} +1 -1
  36. package/dist/{index-CUTG2Cuo.d.mts → index-_--GyzcO.d.mts} +28 -1
  37. package/dist/index.d.mts +3 -3
  38. package/dist/index.mjs +6 -6
  39. package/dist/{init-Bqpt1Hxf.mjs → init-YH_nslQR.mjs} +87 -5
  40. package/dist/integrations/index.d.mts +1 -1
  41. package/dist/integrations/mcp/index.d.mts +2 -2
  42. package/dist/integrations/mcp/index.mjs +1 -1
  43. package/dist/integrations/mcp/testing.d.mts +1 -1
  44. package/dist/integrations/mcp/testing.mjs +1 -1
  45. package/dist/integrations/streamline.d.mts +17 -5
  46. package/dist/integrations/streamline.mjs +9 -5
  47. package/dist/{loadResourcesFromEntry-BTlFEx05.mjs → loadResourcesFromEntry-OMCvIEE7.mjs} +1 -1
  48. package/dist/{mcpPlugin-C088Nd-G.mjs → mcpPlugin-CuW6L_uD.mjs} +148 -49
  49. package/dist/middleware/index.d.mts +1 -1
  50. package/dist/middleware/index.mjs +1 -1
  51. package/dist/module-JYH9V0I8.d.mts +384 -0
  52. package/dist/{openapi-DZ-5a5Op.mjs → openapi-Dq6RbEGK.mjs} +3 -3
  53. package/dist/permissions/index.d.mts +1 -1
  54. package/dist/permissions/index.mjs +1 -1
  55. package/dist/{permissions-BPB1xqGf.mjs → permissions-CgbOLJZG.mjs} +10 -2
  56. package/dist/pipeline/index.d.mts +1 -1
  57. package/dist/plugins/index.d.mts +10 -5
  58. package/dist/plugins/index.mjs +3 -3
  59. package/dist/plugins/tracing-entry.mjs +1 -1
  60. package/dist/{pluralize-DccFV9R7.mjs → pluralize-BhrgwZb9.mjs} +3 -3
  61. package/dist/presets/filesUpload.d.mts +1 -1
  62. package/dist/presets/filesUpload.mjs +1 -1
  63. package/dist/presets/index.d.mts +16 -2
  64. package/dist/presets/index.mjs +1 -1
  65. package/dist/presets/multiTenant.d.mts +1 -1
  66. package/dist/presets/multiTenant.mjs +1 -1
  67. package/dist/presets/search.d.mts +1 -1
  68. package/dist/presets/search.mjs +3 -2
  69. package/dist/{presets-BtyFwTO4.mjs → presets-DWsYQdbV.mjs} +1 -1
  70. package/dist/{queryCachePlugin-emHb0CuX.mjs → queryCachePlugin-DzqLN904.mjs} +2 -2
  71. package/dist/{registerRoute-BdV8DDwU.mjs → registerRoute-DGSREwPw.mjs} +1 -1
  72. package/dist/registry/index.d.mts +1 -1
  73. package/dist/registry/index.mjs +2 -2
  74. package/dist/{registry-Bm9LjWKs.mjs → registry-vcOCtPij.mjs} +1 -1
  75. package/dist/{schemaIR-D1MJwqmp.mjs → schemaIR-ajetw3Fv.mjs} +1 -42
  76. package/dist/scim/index.mjs +2 -2
  77. package/dist/sync/changelog.d.mts +2 -0
  78. package/dist/sync/changelog.mjs +2 -0
  79. package/dist/testing/index.d.mts +2 -2
  80. package/dist/testing/index.mjs +2 -2
  81. package/dist/types/index.d.mts +1 -1
  82. package/dist/{types-9_wtNPsI.d.mts → types-BHMKlMBU.d.mts} +53 -195
  83. package/dist/{types-DpvSF5Hh.d.mts → types-C9b2HR5W.d.mts} +1 -1
  84. package/dist/utils/index.d.mts +1 -1
  85. package/dist/utils/index.mjs +1 -1
  86. package/dist/{utils-C6QQ9-hd.mjs → utils-ChjYQpjn.mjs} +1400 -1400
  87. package/dist/{validate-CRcaWzp2.mjs → validate-C2mGgSXg.mjs} +3 -3
  88. package/package.json +13 -8
  89. package/skills/arc/SKILL.md +10 -0
  90. package/skills/arc/references/mcp.md +2 -0
@@ -245,7 +245,7 @@ async function registerArcPlugins(fastify, config, trackPlugin, modules) {
245
245
  trackPlugin("arc-caching", opts);
246
246
  }
247
247
  if (config.arcPlugins?.queryCache) {
248
- const { queryCachePlugin } = await import("./queryCachePlugin-emHb0CuX.mjs").then((n) => n.n);
248
+ const { queryCachePlugin } = await import("./queryCachePlugin-DzqLN904.mjs").then((n) => n.n);
249
249
  const opts = config.arcPlugins.queryCache === true ? {} : config.arcPlugins.queryCache;
250
250
  const store = config.stores?.queryCache ?? new (await (import("./memory-CLXA2VeJ.mjs").then((n) => n.n))).MemoryCacheStore();
251
251
  await fastify.register(queryCachePlugin, {
@@ -384,6 +384,134 @@ function createOptionalAuthenticate(authenticate) {
384
384
  };
385
385
  }
386
386
  //#endregion
387
+ //#region src/factory/module.ts
388
+ /**
389
+ * Resolve any module-input form to a concrete `ArcModule`. A thunk is invoked
390
+ * (this is where a dynamic `import()` fires); a promise (or plain module) is
391
+ * awaited. Called once per module at the start of the bootstrap phase.
392
+ */
393
+ async function resolveModule(input) {
394
+ const resolved = typeof input === "function" ? await input() : await input;
395
+ if (!resolved || typeof resolved !== "object" || typeof resolved.name !== "string") throw new Error("[arc] a `modules` entry resolved to something that is not an ArcModule (expected an object with a string `name`). Check dynamic-import thunks return `createXModule(deps)` (or the module object), not the namespace.");
396
+ return resolved;
397
+ }
398
+ /**
399
+ * Order modules for composition by their `dependsOn` edges — a STABLE
400
+ * topological sort. Called once at the start of the bootstrap phase; every
401
+ * subsequent phase (bootstrap, resources, afterResources, and reverse-order
402
+ * onClose) iterates the returned list, so a module's declared dependencies are
403
+ * always composed before it.
404
+ *
405
+ * "Stable" = modules with no edge between them keep their original list order,
406
+ * so declaring `dependsOn` on one module never silently reorders an unrelated
407
+ * one. Backward compatible: a `modules` array with NO `dependsOn` anywhere is
408
+ * returned unchanged.
409
+ *
410
+ * Fail-fast — throws (never reorders past a broken contract) on:
411
+ * - duplicate module names (the name is the graph key)
412
+ * - a `dependsOn` name not present in the composed set
413
+ * - a self-reference (`dependsOn` includes the module's own name)
414
+ * - a dependency cycle (reports the concrete `a → b → … → a` path)
415
+ */
416
+ function orderModules(modules) {
417
+ const byName = /* @__PURE__ */ new Map();
418
+ for (const m of modules) {
419
+ if (byName.has(m.name)) throw new Error(`[arc] Duplicate module name "${m.name}" — composed twice; check your modules array.`);
420
+ byName.set(m.name, m);
421
+ }
422
+ for (const m of modules) for (const dep of m.dependsOn ?? []) {
423
+ if (dep === m.name) throw new Error(`[arc] module "${m.name}" dependsOn itself — remove the self-reference.`);
424
+ if (!byName.has(dep)) throw new Error(`[arc] module "${m.name}" dependsOn "${dep}", which is not composed. Add the "${dep}" module to createApp({ modules }) (before this one is fine — arc orders them), or drop the dependency. Composed modules: ${[...byName.keys()].join(", ") || "(none)"}.`);
425
+ }
426
+ if (modules.every((m) => !m.dependsOn || m.dependsOn.length === 0)) return [...modules];
427
+ const originalIndex = /* @__PURE__ */ new Map();
428
+ let nextIndex = 0;
429
+ for (const m of modules) originalIndex.set(m.name, nextIndex++);
430
+ const pendingDeps = new Map(modules.map((m) => [m.name, (m.dependsOn ?? []).length]));
431
+ const dependents = /* @__PURE__ */ new Map();
432
+ for (const m of modules) for (const dep of m.dependsOn ?? []) {
433
+ const list = dependents.get(dep);
434
+ if (list) list.push(m.name);
435
+ else dependents.set(dep, [m.name]);
436
+ }
437
+ const ordered = [];
438
+ const remaining = new Set(modules.map((m) => m.name));
439
+ while (remaining.size > 0) {
440
+ let pick;
441
+ let pickIndex = Number.POSITIVE_INFINITY;
442
+ for (const name of remaining) {
443
+ if (pendingDeps.get(name) !== 0) continue;
444
+ const index = originalIndex.get(name) ?? Number.POSITIVE_INFINITY;
445
+ if (index < pickIndex) {
446
+ pick = name;
447
+ pickIndex = index;
448
+ }
449
+ }
450
+ if (pick === void 0) throw new Error(describeModuleCycle(remaining, byName));
451
+ const picked = byName.get(pick);
452
+ if (!picked) throw new Error(`[arc] internal: ordered module "${pick}" is missing from the index`);
453
+ ordered.push(picked);
454
+ remaining.delete(pick);
455
+ for (const dependent of dependents.get(pick) ?? []) pendingDeps.set(dependent, (pendingDeps.get(dependent) ?? 1) - 1);
456
+ }
457
+ return ordered;
458
+ }
459
+ /** Walk the still-unordered subgraph for one concrete cycle path. */
460
+ function describeModuleCycle(remaining, byName) {
461
+ const stack = [];
462
+ const onStack = /* @__PURE__ */ new Set();
463
+ const done = /* @__PURE__ */ new Set();
464
+ let cycle = null;
465
+ const walk = (name) => {
466
+ if (cycle) return;
467
+ stack.push(name);
468
+ onStack.add(name);
469
+ for (const dep of byName.get(name)?.dependsOn ?? []) {
470
+ if (!remaining.has(dep)) continue;
471
+ if (onStack.has(dep)) {
472
+ cycle = [...stack.slice(stack.indexOf(dep)), dep];
473
+ return;
474
+ }
475
+ if (!done.has(dep)) walk(dep);
476
+ if (cycle) return;
477
+ }
478
+ onStack.delete(name);
479
+ stack.pop();
480
+ done.add(name);
481
+ };
482
+ for (const name of remaining) {
483
+ if (!done.has(name)) walk(name);
484
+ if (cycle) break;
485
+ }
486
+ return `[arc] module dependency cycle: ${cycle ? cycle.join(" → ") : [...remaining].join(", ")}. Modules cannot dependsOn each other circularly — break it with a shared module both point at, or wire the softer direction through an event/port instead of a hard dependsOn.`;
487
+ }
488
+ /**
489
+ * Identity helper for authoring a typed module — mirrors `defineResource`.
490
+ * Gives inference + a single obvious construction site; does no work.
491
+ *
492
+ * `TExports` is inferred from the `bootstrap` return value, so a module
493
+ * author gets a typed public export for free:
494
+ *
495
+ * ```ts
496
+ * export const accountingModule = (deps: Deps) =>
497
+ * defineModule({
498
+ * name: "accounting",
499
+ * bootstrap: async () => createAccountingEngine(deps), // TExports inferred
500
+ * });
501
+ * ```
502
+ */
503
+ function defineModule(module) {
504
+ return module;
505
+ }
506
+ function getModuleExports(fastify, name) {
507
+ const modules = fastify.arc?.modules;
508
+ if (!modules || !Object.hasOwn(modules, name)) {
509
+ const available = modules ? Object.keys(modules) : [];
510
+ throw new Error(`[arc] no public export recorded for module "${name}".\nA module's export is its bootstrap() return value; it is readable only AFTER that module's bootstrap ran (dependsOn / list order = init order).\nModules with recorded exports: ${available.length ? available.join(", ") : "(none)"}.`);
511
+ }
512
+ return modules[name];
513
+ }
514
+ //#endregion
387
515
  //#region src/factory/registerResources.ts
388
516
  function isResourcesFactory(value) {
389
517
  return typeof value === "function";
@@ -401,15 +529,29 @@ async function registerOne(parent, resource) {
401
529
  }
402
530
  }
403
531
  /**
404
- * Execute the full resource lifecycle:
405
- * 1. plugins() — infra (DB, data, webhooks)
406
- * 2. bootstrap[] — domain init (singletons, event handlers)
407
- * 3. resources factory (if any) — resolved AFTER bootstrap, so engine-backed
532
+ * Execute the full resource lifecycle. The module graph is resolved + ordered
533
+ * by `dependsOn` (stable topological sort) once, up FRONT — before any
534
+ * side-effecting plugin — so a bad graph fails fast with no half-initialised
535
+ * infra. Every phase below iterates that order; each module phase runs BEFORE
536
+ * its app-level counterpart:
537
+ *
538
+ * 1. resolve + orderModules — validate the graph (dup names, missing/self
539
+ * deps, cycles fail fast) BEFORE side effects
540
+ * 2. plugins() — app infra (DB, data, webhooks)
541
+ * 3. module.plugins — module infra, dependsOn order, before bootstraps
542
+ * 4a. module.bootstrap — engine init (return value → arc.modules[name])
543
+ * 4b. bootstrap[] — app-level domain init
544
+ * 5. resources factory (if any) — resolved AFTER bootstrap, so engine-backed
408
545
  * adapters can `await ensureEngine()` and pass
409
546
  * live models/repos into `defineResource(...)`
410
- * 4. resources[] — register each (split by prefix)
411
- * 5. afterResources() — post-registration wiring
412
- * 6. onReady/onClose — lifecycle hooks
547
+ * 5b. module resources — RESOLVED after the app factory, but PREPENDED
548
+ * so they REGISTER before app resources (two
549
+ * orderings, both intentional — see §5b)
550
+ * 6. module.afterResources → afterResources() — post-registration wiring
551
+ * 7. onReady — lifecycle hook
552
+ * 7b. onClose — module.onClose (reverse composition order)
553
+ * THEN app onClose, in ONE hook so module
554
+ * teardown runs before shared infra closes.
413
555
  */
414
556
  async function registerResources(fastify, config) {
415
557
  if (config.preset === "production") {
@@ -422,10 +564,37 @@ async function registerResources(fastify, config) {
422
564
  strictResourceDir: true
423
565
  };
424
566
  }
567
+ const modules = orderModules(await Promise.all((config.modules ?? []).map((m) => resolveModule(m))));
425
568
  if (config.plugins) {
426
569
  await config.plugins(fastify);
427
570
  fastify.log.debug("Custom plugins registered");
428
571
  }
572
+ for (const m of modules) {
573
+ if (!m.plugins) continue;
574
+ try {
575
+ await m.plugins(fastify);
576
+ } catch (err) {
577
+ const msg = err instanceof Error ? err.message : String(err);
578
+ throw new Error(`[arc] module "${m.name}" plugins() threw: ${msg}`, { cause: err });
579
+ }
580
+ }
581
+ for (const m of modules) {
582
+ if (!m.bootstrap) continue;
583
+ let exported;
584
+ try {
585
+ exported = await m.bootstrap(fastify);
586
+ } catch (err) {
587
+ const msg = err instanceof Error ? err.message : String(err);
588
+ throw new Error(`[arc] module "${m.name}" bootstrap threw: ${msg}`, { cause: err });
589
+ }
590
+ if (exported !== void 0) {
591
+ const arc = fastify.arc;
592
+ if (!arc) throw new Error(`[arc] module "${m.name}" returned a public export but fastify.arc is not decorated — arcCorePlugin must register first.`);
593
+ if (!arc.modules) arc.modules = Object.create(null);
594
+ arc.modules[m.name] = exported;
595
+ }
596
+ }
597
+ if (modules.length) fastify.log.debug(`${modules.length} module(s) composed (in dependency order): ${modules.map((m) => m.name).join(" → ")}`);
429
598
  if (config.bootstrap?.length) {
430
599
  for (const init of config.bootstrap) await init(fastify);
431
600
  fastify.log.debug(`${config.bootstrap.length} bootstrap function(s) executed`);
@@ -462,6 +631,20 @@ async function registerResources(fastify, config) {
462
631
  }
463
632
  resolvedResources = discovered;
464
633
  }
634
+ if (modules.length) {
635
+ const moduleResources = [];
636
+ for (const m of modules) {
637
+ if (!m.resources) continue;
638
+ try {
639
+ const rs = typeof m.resources === "function" ? await m.resources(fastify) : m.resources;
640
+ moduleResources.push(...rs);
641
+ } catch (err) {
642
+ const msg = err instanceof Error ? err.message : String(err);
643
+ throw new Error(`[arc] module "${m.name}" resources factory threw: ${msg}. Check the module's bootstrap ran and its adapters received booted engines.`, { cause: err });
644
+ }
645
+ }
646
+ if (moduleResources.length) resolvedResources = [...moduleResources, ...resolvedResources ?? []];
647
+ }
465
648
  if (resolvedResources && resolvedResources.length > 0) {
466
649
  const seen = /* @__PURE__ */ new Set();
467
650
  for (const resource of resolvedResources) if (resource.name) {
@@ -490,6 +673,15 @@ async function registerResources(fastify, config) {
490
673
  const hints = discoveryYieldedZero ? ` but yielded 0 resources. Check the path, file naming (*.resource.{ts,js,mts,mjs}), and runtime layout (src/ vs dist/). Use \`strictResourceDir: true\` to fail boot.` : "";
491
674
  fastify.log.warn(`0 resources registered${prefix}${scanned}${hints}`);
492
675
  }
676
+ for (const m of modules) {
677
+ if (!m.afterResources) continue;
678
+ try {
679
+ await m.afterResources(fastify);
680
+ } catch (err) {
681
+ const msg = err instanceof Error ? err.message : String(err);
682
+ throw new Error(`[arc] module "${m.name}" afterResources() threw: ${msg}`, { cause: err });
683
+ }
684
+ }
493
685
  if (config.afterResources) {
494
686
  await config.afterResources(fastify);
495
687
  fastify.log.debug("afterResources hook executed");
@@ -500,12 +692,12 @@ async function registerResources(fastify, config) {
500
692
  await onReady(fastify);
501
693
  });
502
694
  }
503
- if (config.onClose) {
504
- const onClose = config.onClose;
505
- fastify.addHook("onClose", async () => {
506
- await onClose(fastify);
507
- });
508
- }
695
+ const closers = modules.filter((m) => m.onClose).reverse();
696
+ const appOnClose = config.onClose;
697
+ if (closers.length || appOnClose) fastify.addHook("onClose", async () => {
698
+ for (const m of closers) await m.onClose?.(fastify);
699
+ if (appOnClose) await appOnClose(fastify);
700
+ });
509
701
  }
510
702
  //#endregion
511
703
  //#region src/factory/registerSecurity.ts
@@ -522,7 +714,8 @@ function buildRateLimitOpts(input) {
522
714
  };
523
715
  const matchesPath = compilePathMatcher(skipPaths);
524
716
  const combined = async (req, key) => {
525
- if (matchesPath((req.url ?? "").split("?", 1)[0] ?? "")) return true;
717
+ const path = (req.url ?? "").split("?", 1)[0] ?? "";
718
+ if (matchesPath(path)) return true;
526
719
  if (typeof allowList === "function") return await allowList(req, key);
527
720
  if (Array.isArray(allowList)) return allowList.includes(key);
528
721
  return false;
@@ -711,7 +904,7 @@ var createApp_exports = /* @__PURE__ */ __exportAll({
711
904
  createApp: () => createApp,
712
905
  resolveLoggerConfig: () => resolveLoggerConfig
713
906
  });
714
- const MEMORY_STORE_NAMES = new Set(["memory", "memory-cache"]);
907
+ const MEMORY_STORE_NAMES = /* @__PURE__ */ new Set(["memory", "memory-cache"]);
715
908
  /**
716
909
  * Default redact paths layered into Fastify's pino logger when the host
717
910
  * doesn't supply a `logger.redact` of their own. Covers the common token /
@@ -947,4 +1140,4 @@ const ArcFactory = {
947
1140
  }
948
1141
  };
949
1142
  //#endregion
950
- export { edgePreset as a, testingPreset as c, developmentPreset as i, createApp as n, getPreset as o, createApp_exports as r, productionPreset as s, ArcFactory as t };
1143
+ export { getModuleExports as a, developmentPreset as c, productionPreset as d, testingPreset as f, defineModule as i, edgePreset as l, createApp as n, orderModules as o, createApp_exports as r, resolveModule as s, ArcFactory as t, getPreset as u };
@@ -1,4 +1,4 @@
1
- import { p as RegistryEntry } from "../index-CUTG2Cuo.mjs";
1
+ import { p as RegistryEntry } from "../index-_--GyzcO.mjs";
2
2
  import { t as ExternalOpenApiPaths } from "../externalPaths-BE6wFpYv.mjs";
3
3
  import { FastifyPluginAsync } from "fastify";
4
4
 
@@ -1,5 +1,5 @@
1
1
  import { t as getUserRoles } from "../types-XTApa8b6.mjs";
2
- import { n as openApiPlugin, r as openapi_default, t as buildOpenApiSpec } from "../openapi-DZ-5a5Op.mjs";
2
+ import { n as openApiPlugin, r as openapi_default, t as buildOpenApiSpec } from "../openapi-Dq6RbEGK.mjs";
3
3
  import fp from "fastify-plugin";
4
4
  //#region src/docs/scalar.ts
5
5
  const scalarPlugin = async (fastify, opts = {}) => {
@@ -417,12 +417,13 @@ function repositoryAsOutboxStore(repository) {
417
417
  },
418
418
  async getPending(limit) {
419
419
  const now = /* @__PURE__ */ new Date();
420
- return unwrapDocs(await r.getAll({
420
+ const result = await r.getAll({
421
421
  filters: claimableFilter(now),
422
422
  sort: { createdAt: 1 },
423
423
  page: 1,
424
424
  limit
425
- })).map((d) => d.event).filter(isWellFormed);
425
+ });
426
+ return unwrapDocs(result).map((d) => d.event).filter(isWellFormed);
426
427
  },
427
428
  async claimPending(options) {
428
429
  const limit = options?.limit ?? DEFAULT_CLAIM_LIMIT;
@@ -493,12 +494,13 @@ function repositoryAsOutboxStore(repository) {
493
494
  }
494
495
  },
495
496
  async getDeadLettered(limit) {
496
- return unwrapDocs(await r.getAll({
497
+ const result = await r.getAll({
497
498
  filters: eq("status", "dead_letter"),
498
499
  sort: { [idField]: 1 },
499
500
  page: 1,
500
501
  limit
501
- })).filter((d) => isWellFormed(d.event)).map((d) => ({
502
+ });
503
+ return unwrapDocs(result).filter((d) => isWellFormed(d.event)).map((d) => ({
502
504
  event: d.event,
503
505
  error: {
504
506
  message: d.lastError?.message ?? "unknown",
@@ -513,13 +515,14 @@ function repositoryAsOutboxStore(repository) {
513
515
  const cutoff = new Date(Date.now() - olderThanMs);
514
516
  let totalDeleted = 0;
515
517
  for (;;) {
516
- const batch = unwrapDocs(await r.getAll({
518
+ const result = await r.getAll({
517
519
  filters: and(eq("status", "delivered"), lte("deliveredAt", cutoff)),
518
520
  sort: { deliveredAt: 1 },
519
521
  page: 1,
520
522
  limit: DEFAULT_PURGE_BATCH,
521
523
  select: idField
522
- }));
524
+ });
525
+ const batch = unwrapDocs(result);
523
526
  if (batch.length === 0) break;
524
527
  const ids = batch.map((d) => d[idField]);
525
528
  const res = await r.deleteMany(anyOf(idField, ids));
@@ -1,4 +1,5 @@
1
- import { a as CustomPluginAuthOption, c as RawBodyOptions, d as preloadResourcesAsync, f as LoadResourcesOptions, h as loadResources, i as CustomAuthenticatorOption, l as UnderPressureOptions, m as ResourceModule, n as BetterAuthOption, o as JwtAuthOption, p as ResourceLike, r as CreateAppOptions, s as MultipartOptions, t as AuthOption, u as preloadResources } from "../types-9_wtNPsI.mjs";
1
+ import { a as getModuleExports, c as LoadResourcesOptions, d as loadResources, i as defineModule, l as ResourceLike, n as ArcModuleInput, o as orderModules, r as ArcModuleRegistry, s as resolveModule, t as ArcModule, u as ResourceModule } from "../module-JYH9V0I8.mjs";
2
+ import { a as CustomPluginAuthOption, c as RawBodyOptions, d as preloadResourcesAsync, i as CustomAuthenticatorOption, l as UnderPressureOptions, n as BetterAuthOption, o as JwtAuthOption, r as CreateAppOptions, s as MultipartOptions, t as AuthOption, u as preloadResources } from "../types-BHMKlMBU.mjs";
2
3
  import { FastifyInstance, FastifyServerOptions } from "fastify";
3
4
 
4
5
  //#region src/factory/createApp.d.ts
@@ -95,4 +96,4 @@ declare const edgePreset: Partial<CreateAppOptions>;
95
96
  */
96
97
  declare function getPreset(name: "production" | "development" | "testing" | "edge"): Partial<CreateAppOptions>;
97
98
  //#endregion
98
- export { ArcFactory, type AuthOption, type BetterAuthOption, type CreateAppOptions, type CustomAuthenticatorOption, type CustomPluginAuthOption, type FetchHandlerOptions, type JwtAuthOption, type LoadResourcesOptions, type MultipartOptions, type RawBodyOptions, type ResourceLike, type ResourceModule, type UnderPressureOptions, createApp, developmentPreset, edgePreset, getPreset, loadResources, preloadResources, preloadResourcesAsync, productionPreset, testingPreset, toFetchHandler };
99
+ export { ArcFactory, type ArcModule, type ArcModuleInput, type ArcModuleRegistry, type AuthOption, type BetterAuthOption, type CreateAppOptions, type CustomAuthenticatorOption, type CustomPluginAuthOption, type FetchHandlerOptions, type JwtAuthOption, type LoadResourcesOptions, type MultipartOptions, type RawBodyOptions, type ResourceLike, type ResourceModule, type UnderPressureOptions, createApp, defineModule, developmentPreset, edgePreset, getModuleExports, getPreset, loadResources, orderModules, preloadResources, preloadResourcesAsync, productionPreset, resolveModule, testingPreset, toFetchHandler };
@@ -1,5 +1,5 @@
1
1
  import { n as preloadResourcesAsync, t as preloadResources } from "../preloadResources-CHw3_oA_.mjs";
2
- import { a as edgePreset, c as testingPreset, i as developmentPreset, n as createApp, o as getPreset, s as productionPreset, t as ArcFactory } from "../createApp--703hQE1.mjs";
2
+ import { a as getModuleExports, c as developmentPreset, d as productionPreset, f as testingPreset, i as defineModule, l as edgePreset, n as createApp, o as orderModules, s as resolveModule, t as ArcFactory, u as getPreset } from "../createApp-D6uwzCKu.mjs";
3
3
  import { t as loadResources } from "../loadResources-B8UmpITt.mjs";
4
4
  //#region src/factory/edge.ts
5
5
  /**
@@ -47,4 +47,4 @@ function toFetchHandler(app, options = {}) {
47
47
  };
48
48
  }
49
49
  //#endregion
50
- export { ArcFactory, createApp, developmentPreset, edgePreset, getPreset, loadResources, preloadResources, preloadResourcesAsync, productionPreset, testingPreset, toFetchHandler };
50
+ export { ArcFactory, createApp, defineModule, developmentPreset, edgePreset, getModuleExports, getPreset, loadResources, orderModules, preloadResources, preloadResourcesAsync, productionPreset, resolveModule, testingPreset, toFetchHandler };
@@ -1,5 +1,6 @@
1
- import { bn as HookSystem, z as ResourceRegistry } from "./index-CUTG2Cuo.mjs";
1
+ import { bn as HookSystem, z as ResourceRegistry } from "./index-_--GyzcO.mjs";
2
2
  import { t as ExternalOpenApiPaths } from "./externalPaths-BE6wFpYv.mjs";
3
+ import { r as ArcModuleRegistry } from "./module-JYH9V0I8.mjs";
3
4
  import { FastifyPluginAsync } from "fastify";
4
5
 
5
6
  //#region src/core/arcCorePlugin.d.ts
@@ -28,6 +29,16 @@ interface ArcCore {
28
29
  externalOpenApiPaths: ExternalOpenApiPaths[];
29
30
  /** Registered plugins for introspection */
30
31
  plugins: Map<string, PluginMeta>;
32
+ /**
33
+ * Module public exports — `bootstrap()` return values keyed by module name
34
+ * (see `src/factory/module.ts`). Read via `getModuleExports(fastify, name)`:
35
+ * augment `ArcModuleRegistry` once and the name infers the export type;
36
+ * otherwise pass it inline. `Partial<ArcModuleRegistry>` gives augmented
37
+ * apps typed direct access (`fastify.arc.modules.order`), while the
38
+ * `Record<string, unknown>` intersection keeps un-augmented reads open.
39
+ * Populated lazily by `registerResources` — absent until a module exports.
40
+ */
41
+ modules?: Partial<ArcModuleRegistry> & Record<string, unknown>;
31
42
  }
32
43
  declare const arcCorePlugin: FastifyPluginAsync<ArcCorePluginOptions>;
33
44
  declare const _default: FastifyPluginAsync<ArcCorePluginOptions>;
@@ -1,4 +1,4 @@
1
- import { t as pluralize } from "./pluralize-DccFV9R7.mjs";
1
+ import { t as pluralize } from "./pluralize-BhrgwZb9.mjs";
2
2
  import { join } from "node:path";
3
3
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
4
4
  //#region src/cli/commands/generate/name-helpers.ts
@@ -601,9 +601,10 @@ async function generate(type, args) {
601
601
  if (!type) throw new Error("Missing type argument\nUsage: arc generate <resource|controller|model|repository|schemas> <name>");
602
602
  const [name, ...restArgs] = args;
603
603
  if (!name) throw new Error("Missing name argument\nUsage: arc generate <type> <name>\nExample: arc generate resource product");
604
+ if (!/^[A-Za-z][A-Za-z0-9-]*$/.test(name)) throw new Error(`Invalid name "${name}". Use kebab-case: a letter followed by letters, digits, or hyphens (e.g. 'product', 'order-line'). No slashes, dots, spaces, or path segments.`);
604
605
  const capitalizedName = toPascalCase(name);
605
606
  const lowerName = name.toLowerCase();
606
- if ((type === "resource" || type === "r" || type === "model" || type === "m") && new Set([
607
+ if ((type === "resource" || type === "r" || type === "model" || type === "m") && (/* @__PURE__ */ new Set([
607
608
  "user",
608
609
  "session",
609
610
  "account",
@@ -614,7 +615,7 @@ async function generate(type, args) {
614
615
  "team",
615
616
  "team-member",
616
617
  "apikey"
617
- ]).has(lowerName)) {
618
+ ])).has(lowerName)) {
618
619
  console.warn(`\n[arc generate] "${lowerName}" is a Better Auth-owned collection.\nBetter Auth's organization/admin/bearer plugins write this collection directly,\nso generating a parallel arc model would create a duplicate registration.\n\nRecommended pattern:\n import { createBetterAuthOverlay } from '@classytic/mongokit/better-auth';\n const adapter = await createBetterAuthOverlay({\n auth, mongoose, collection: '${lowerName}',\n });\n // ...then \`defineResource({ name: '${lowerName}', adapter, ... })\` reads\n // BA's collection through arc with full pagination/filters/permissions.\n\nAborting. Re-run with a different name if you need a separate domain model.\n`);
619
620
  return;
620
621
  }
@@ -1,2 +1,2 @@
1
- import { Cn as afterDelete, Dn as beforeUpdate, En as beforeDelete, On as createHookSystem, Sn as afterCreate, Tn as beforeCreate, _n as HookOperation, bn as HookSystem, gn as HookHandler, hn as HookContext, kn as defineHook, mn as DefineHookOptions, vn as HookPhase, wn as afterUpdate, xn as HookSystemOptions, yn as HookRegistration } from "../index-CUTG2Cuo.mjs";
1
+ import { Cn as afterDelete, Dn as beforeUpdate, En as beforeDelete, On as createHookSystem, Sn as afterCreate, Tn as beforeCreate, _n as HookOperation, bn as HookSystem, gn as HookHandler, hn as HookContext, kn as defineHook, mn as DefineHookOptions, vn as HookPhase, wn as afterUpdate, xn as HookSystemOptions, yn as HookRegistration } from "../index-_--GyzcO.mjs";
2
2
  export { type DefineHookOptions, type HookContext, type HookHandler, type HookOperation, type HookPhase, type HookRegistration, HookSystem, type HookSystemOptions, afterCreate, afterDelete, afterUpdate, beforeCreate, beforeDelete, beforeUpdate, createHookSystem, defineHook };
@@ -387,7 +387,7 @@ const idempotencyPlugin = async (fastify, opts = {}) => {
387
387
  const statusCode = reply.statusCode;
388
388
  if (statusCode < 200 || statusCode >= 300) return payload;
389
389
  const headersToCache = {};
390
- const excludeHeaders = new Set([
390
+ const excludeHeaders = /* @__PURE__ */ new Set([
391
391
  "content-length",
392
392
  "transfer-encoding",
393
393
  "connection",
@@ -669,6 +669,11 @@ declare function fullPublic<TDoc = Record<string, unknown>>(overrides?: Permissi
669
669
  /**
670
670
  * Read-only: list + get authenticated, write operations denied.
671
671
  * Useful for computed/derived resources.
672
+ *
673
+ * Writes carry an explicit `denyAll` check — an omitted CRUD permission
674
+ * mounts the route with NO gate (public-by-omission), so leaving
675
+ * create/update/delete undefined here would expose unauthenticated writes.
676
+ * Hosts that disable write routes entirely (`disabledRoutes`) are unaffected.
672
677
  */
673
678
  declare function readOnly<TDoc = Record<string, unknown>>(overrides?: PermissionOverrides<TDoc>): ResourcePermissions<TDoc>;
674
679
  //#endregion
@@ -1,4 +1,4 @@
1
- import { C as RequestContext, Et as AggregationConfig, F as FastifyWithDecorators, H as ActionDefinition, K as ArcFieldRule, L as RequestWithExtras, T as CrudRouterOptions, V as ResourceDefinition, bt as IControllerResponse, ht as RouteSchemaOptions, pt as RouteMcpConfig, q as CrudController, qt as AnyRecord, st as ResourceConfig, xt as IRequestContext, yt as IController } from "./index-CUTG2Cuo.mjs";
1
+ import { C as RequestContext, Et as AggregationConfig, F as FastifyWithDecorators, H as ActionDefinition, K as ArcFieldRule, L as RequestWithExtras, T as CrudRouterOptions, V as ResourceDefinition, bt as IControllerResponse, ht as RouteSchemaOptions, pt as RouteMcpConfig, q as CrudController, qt as AnyRecord, st as ResourceConfig, xt as IRequestContext, yt as IController } 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 { FastifyReply, FastifyRequest, RouteHandlerMethod } from "fastify";
@@ -2467,6 +2467,25 @@ interface RouteDefinition {
2467
2467
  * pipeline entirely.
2468
2468
  */
2469
2469
  readonly fieldWrite?: boolean;
2470
+ /**
2471
+ * Per-route rate limit. A custom route is its own Fastify route, so this
2472
+ * overrides the resource-level `rateLimit` for THIS endpoint only:
2473
+ *
2474
+ * - omitted → inherit the resource-level limit (or app default)
2475
+ * - `false` → disable rate limiting on this route
2476
+ * - `{ max, timeWindow }` → apply this specific limit
2477
+ *
2478
+ * Requires `@fastify/rate-limit` registered (arc's factory wires it by
2479
+ * default). Use for an expensive `/export` or an auth-sensitive `/reset`
2480
+ * that needs a tighter cap than the resource's read-heavy CRUD, or `false`
2481
+ * on an internal health/webhook route that must not be throttled.
2482
+ *
2483
+ * Note: this is per-route because each custom route is a distinct endpoint.
2484
+ * `actions` share ONE `POST /:id/action` mount by design, so a per-ACTION
2485
+ * limit can't be expressed here — throttle a specific action by promoting
2486
+ * it to a dedicated `routes:` entry, or rely on the resource-level limit.
2487
+ */
2488
+ readonly rateLimit?: RateLimitConfig | false;
2470
2489
  /**
2471
2490
  * Fastify route schema. Each slot (`body`, `querystring`, `params`,
2472
2491
  * `headers`, `response[status]`) accepts a plain JSON Schema object
@@ -2504,7 +2523,15 @@ interface RouteDefinition {
2504
2523
  * ID, action-specific data, and the request.
2505
2524
  */
2506
2525
  type ActionHandlerFn = (id: string, data: Record<string, unknown>, req: RequestWithExtras) => Promise<unknown>;
2507
- /** Full action configuration with handler, permissions, and schema. */
2526
+ /**
2527
+ * Full action configuration with handler, permissions, and schema.
2528
+ *
2529
+ * Rate limiting is intentionally NOT per-action: every action shares one
2530
+ * `POST /:id/action` (or `POST /action`) mount, so Fastify's per-route limit
2531
+ * can't distinguish them. Actions inherit the resource-level `rateLimit`; to
2532
+ * throttle a specific operation, promote it to a `routes:` entry (which
2533
+ * supports `RouteDefinition.rateLimit`).
2534
+ */
2508
2535
  interface ActionDefinition {
2509
2536
  readonly handler: ActionHandlerFn;
2510
2537
  /** Per-action permission (overrides resource-level `actionPermissions`) */
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
- import { $t as UserOrganization, A as RequestIdOptions, An as ArcCreateResult, At as AggregationMaterializedResult, B as defineResource, C as RequestContext, Ct as AggMeasureInput, D as HealthCheck, Dt as AggregationDateRangeRequirement, E as GracefulShutdownOptions, Et as AggregationConfig, F as FastifyWithDecorators, Fn as BaseControllerOptions, Ht as AuthPluginOptions, In as ControllerConfigurableOptions, J as CrudRouteKey, Jt as ApiResponse, L as RequestWithExtras, Ln as ControllerConstructionOptions, Mn as ArcGetResult, Mt as AggregationsMap, N as FastifyRequestExtras, Nn as ArcListResult, O as HealthOptions, Ot as AggregationIndexHint, P as FastifyWithAuth, Pn as ArcUpdateResult, Q as MiddlewareConfig, Rn as ListResult, S as QueryParserInterface, St as RouteHandler, T as CrudRouterOptions, Tt as AggregationCacheConfig, V as ResourceDefinition, X as EventDefinition, Xt as JWTPayload, Y as CrudSchemas, Yt as ArcRequest, Z as FieldRule, _t as ControllerLike, a as InferAdapterDoc, an as SlugExt, bt as IControllerResponse, c as TypedController, cn as BulkMixin, d as PaginationResult, en as BaseController, f as IntrospectionData, g as ArcInternalMetadata, h as ResourceMetadata, ht as RouteSchemaOptions, i as ValidationResult, in as TreeMixin, it as RateLimitConfig, jn as ArcDeleteResult, jt as AggregationRateLimit, k as IntrospectionPluginOptions, kt as AggregationMaterializedContext, l as TypedRepository, ln as BaseCrudController, m as RegistryStats, n as ConfigError, nn as SoftDeleteMixin, o as InferDocType, on as SlugMixin, p as RegistryEntry, q as CrudController, qt as AnyRecord, r as ValidateOptions, rn as TreeExt, rt as PresetResult, s as InferResourceDoc, sn as BulkExt, st as ResourceConfig, t as RouteHandlerMethod, tn as SoftDeleteExt, tt as PresetFunction, u as TypedResourceConfig, w as ServiceContext, wt as AggMeasureShorthand, xt as IRequestContext, y as OwnershipCheck, yt as IController } from "./index-CUTG2Cuo.mjs";
1
+ import { $t as UserOrganization, A as RequestIdOptions, An as ArcCreateResult, At as AggregationMaterializedResult, B as defineResource, C as RequestContext, Ct as AggMeasureInput, D as HealthCheck, Dt as AggregationDateRangeRequirement, E as GracefulShutdownOptions, Et as AggregationConfig, F as FastifyWithDecorators, Fn as BaseControllerOptions, Ht as AuthPluginOptions, In as ControllerConfigurableOptions, J as CrudRouteKey, Jt as ApiResponse, L as RequestWithExtras, Ln as ControllerConstructionOptions, Mn as ArcGetResult, Mt as AggregationsMap, N as FastifyRequestExtras, Nn as ArcListResult, O as HealthOptions, Ot as AggregationIndexHint, P as FastifyWithAuth, Pn as ArcUpdateResult, Q as MiddlewareConfig, Rn as ListResult, S as QueryParserInterface, St as RouteHandler, T as CrudRouterOptions, Tt as AggregationCacheConfig, V as ResourceDefinition, X as EventDefinition, Xt as JWTPayload, Y as CrudSchemas, Yt as ArcRequest, Z as FieldRule, _t as ControllerLike, a as InferAdapterDoc, an as SlugExt, bt as IControllerResponse, c as TypedController, cn as BulkMixin, d as PaginationResult, en as BaseController, f as IntrospectionData, g as ArcInternalMetadata, h as ResourceMetadata, ht as RouteSchemaOptions, i as ValidationResult, in as TreeMixin, it as RateLimitConfig, jn as ArcDeleteResult, jt as AggregationRateLimit, k as IntrospectionPluginOptions, kt as AggregationMaterializedContext, l as TypedRepository, ln as BaseCrudController, m as RegistryStats, n as ConfigError, nn as SoftDeleteMixin, o as InferDocType, on as SlugMixin, p as RegistryEntry, q as CrudController, qt as AnyRecord, r as ValidateOptions, rn as TreeExt, rt as PresetResult, s as InferResourceDoc, sn as BulkExt, st as ResourceConfig, t as RouteHandlerMethod, tn as SoftDeleteExt, tt as PresetFunction, u as TypedResourceConfig, w as ServiceContext, wt as AggMeasureShorthand, xt as IRequestContext, y as OwnershipCheck, yt as IController } from "./index-_--GyzcO.mjs";
2
2
  import { a as applyFieldWritePermissions, c as PermissionCheck, d as UserBase, i as applyFieldReadPermissions, l as PermissionContext, n as FieldPermissionMap, o as fields, t as FieldPermission, u as PermissionResult } from "./fields-C7ahdGYf.mjs";
3
- import { A as MAX_FILTER_DEPTH, C as DEFAULT_SORT, D as HOOK_PHASES, E as HOOK_OPERATIONS, F as RESERVED_QUERY_PARAMS, I as SYSTEM_FIELDS, M as MAX_SEARCH_LENGTH, N as MUTATION_OPERATIONS, O as HookOperation, P as MutationOperation, S as DEFAULT_MAX_LIMIT, T as DEFAULT_UPDATE_METHOD, _ as defineAggregation, b as DEFAULT_ID_FIELD, f as defineResourceVariants, j as MAX_REGEX_LENGTH, k as HookPhase, m as defineAction, s as getControllerScope, v as CRUD_OPERATIONS, w as DEFAULT_TENANT_FIELD, x as DEFAULT_LIMIT, y as CrudOperation } from "./index-CP6A1Ffj.mjs";
4
- import { A as requireRoles, C as allOf, E as denyAll, M as when, O as requireAuth, S as createOrgPermissions, T as anyOf, a as presets_d_exports, c as readOnly, d as requireOrgRole, f as requireScopeContext, i as ownerWithAdminBypass, 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 } from "./index-CRKiiP5o.mjs";
3
+ import { A as MAX_FILTER_DEPTH, C as DEFAULT_SORT, D as HOOK_PHASES, E as HOOK_OPERATIONS, F as RESERVED_QUERY_PARAMS, I as SYSTEM_FIELDS, M as MAX_SEARCH_LENGTH, N as MUTATION_OPERATIONS, O as HookOperation, P as MutationOperation, S as DEFAULT_MAX_LIMIT, T as DEFAULT_UPDATE_METHOD, _ as defineAggregation, b as DEFAULT_ID_FIELD, f as defineResourceVariants, j as MAX_REGEX_LENGTH, k as HookPhase, m as defineAction, s as getControllerScope, v as CRUD_OPERATIONS, w as DEFAULT_TENANT_FIELD, x as DEFAULT_LIMIT, y as CrudOperation } from "./index-DUa8WHz3.mjs";
4
+ import { A as requireRoles, C as allOf, E as denyAll, M as when, O as requireAuth, S as createOrgPermissions, T as anyOf, a as presets_d_exports, c as readOnly, d as requireOrgRole, f as requireScopeContext, i as ownerWithAdminBypass, 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 } from "./index-CdFkIMEd.mjs";
5
5
  import { a as NotFoundError, d as ValidationError, f as createDomainError, i as ForbiddenError, t as ArcError, u as UnauthorizedError } from "./errors-DOHkjQlD.mjs";
6
6
 
7
7
  //#region src/index.d.ts
package/dist/index.mjs CHANGED
@@ -1,10 +1,10 @@
1
- import { a as DEFAULT_SORT, c as HOOK_OPERATIONS, d as MAX_REGEX_LENGTH, f as MAX_SEARCH_LENGTH, h as SYSTEM_FIELDS, i as DEFAULT_MAX_LIMIT, l as HOOK_PHASES, m as RESERVED_QUERY_PARAMS, n as DEFAULT_ID_FIELD, o as DEFAULT_TENANT_FIELD, p as MUTATION_OPERATIONS, r as DEFAULT_LIMIT, s as DEFAULT_UPDATE_METHOD, t as CRUD_OPERATIONS, u as MAX_FILTER_DEPTH } from "./constants-gaEeMlz-.mjs";
1
+ import { a as DEFAULT_SORT, c as HOOK_OPERATIONS, d as MAX_REGEX_LENGTH, f as MAX_SEARCH_LENGTH, h as SYSTEM_FIELDS, i as DEFAULT_MAX_LIMIT, l as HOOK_PHASES, m as RESERVED_QUERY_PARAMS, n as DEFAULT_ID_FIELD, o as DEFAULT_TENANT_FIELD, p as MUTATION_OPERATIONS, r as DEFAULT_LIMIT, s as DEFAULT_UPDATE_METHOD, t as CRUD_OPERATIONS, u as MAX_FILTER_DEPTH } from "./constants-DNre0wRg.mjs";
2
2
  import { d as createDomainError, i as NotFoundError, l as UnauthorizedError, r as ForbiddenError, t as ArcError, u as ValidationError } from "./errors-DkO8Nk6-.mjs";
3
- import { a as BulkMixin, i as SlugMixin, n as TreeMixin, o as BaseCrudController, r as SoftDeleteMixin, t as BaseController } from "./BaseController-Dy6EQHjM.mjs";
4
- import { a as defineResource, i as defineResourceVariants, o as ResourceDefinition, s as defineAction, u as defineAggregation } from "./core-Ba-6Sue6.mjs";
5
- import { C as requireAuth, D as when, F as applyFieldWritePermissions, I as fields, P as applyFieldReadPermissions, 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, 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";
6
- import { l as getControllerScope } from "./actionPermissions-D7NGwcAR.mjs";
3
+ import { a as BulkMixin, i as SlugMixin, n as TreeMixin, o as BaseCrudController, r as SoftDeleteMixin, t as BaseController } from "./BaseController-D-MHZ27_.mjs";
4
+ import { C as requireAuth, D as when, F as applyFieldWritePermissions, I as fields, P as applyFieldReadPermissions, 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, 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";
5
+ import { a as defineResource, i as defineResourceVariants, o as ResourceDefinition, s as defineAction, u as defineAggregation } from "./core-CWhyGkiM.mjs";
6
+ import { l as getControllerScope } from "./actionPermissions-C9RMiIpc.mjs";
7
7
  //#region src/index.ts
8
- const version = "2.19.0";
8
+ const version = "2.20.0";
9
9
  //#endregion
10
10
  export { ArcError, BaseController, BaseCrudController, BulkMixin, CRUD_OPERATIONS, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, ForbiddenError, HOOK_OPERATIONS, HOOK_PHASES, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, NotFoundError, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, SlugMixin, SoftDeleteMixin, TreeMixin, UnauthorizedError, ValidationError, adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, authenticated, createDomainError, createDynamicPermissionMatrix, createOrgPermissions, defineAction, defineAggregation, defineResource, defineResourceVariants, denyAll, fields, fullPublic, getControllerScope, ownerWithAdminBypass, presets_exports as permissions, publicRead, publicReadAdminWrite, readOnly, requireAuth, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, version, when };