@classytic/arc 2.19.0 → 2.21.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 (139) hide show
  1. package/README.md +1 -1
  2. package/bin/arc.js +37 -0
  3. package/dist/{BaseController-Dy6EQHjM.mjs → BaseController-BnLYgE9A.mjs} +4 -4
  4. package/dist/{EventTransport-IEn7Tn-Q.d.mts → EventTransport-QmY7A258.d.mts} +0 -1
  5. package/dist/{QueryCache-TRfXau3W.d.mts → QueryCache-Z1B38koh.d.mts} +0 -1
  6. package/dist/{ResourceRegistry-5fKZwhK_.mjs → ResourceRegistry-7RnrEWNP.mjs} +1 -1
  7. package/dist/{actionPermissions-D7NGwcAR.mjs → actionPermissions-ze70xXJi.mjs} +1 -1
  8. package/dist/audit/index.d.mts +9 -5
  9. package/dist/audit/index.mjs +1 -1
  10. package/dist/auth/audit.d.mts +7 -4
  11. package/dist/auth/audit.mjs +5 -0
  12. package/dist/auth/index.d.mts +7 -14
  13. package/dist/auth/index.mjs +7 -5
  14. package/dist/auth/redis-session.d.mts +1 -2
  15. package/dist/{buildHandler-B0qvAguf.mjs → buildHandler-D_2ULWxZ.mjs} +3 -3
  16. package/dist/cache/index.d.mts +2 -3
  17. package/dist/cache/index.mjs +2 -2
  18. package/dist/cli/commands/describe.d.mts +1 -2
  19. package/dist/cli/commands/describe.mjs +2 -2
  20. package/dist/cli/commands/docs.mjs +2 -2
  21. package/dist/cli/commands/generate.mjs +1 -1
  22. package/dist/cli/commands/init.mjs +1 -1
  23. package/dist/cli/commands/introspect.mjs +4 -13
  24. package/dist/cli/index.mjs +2 -2
  25. package/dist/{constants-gaEeMlz-.mjs → constants-DNre0wRg.mjs} +1 -1
  26. package/dist/context/index.d.mts +2 -2
  27. package/dist/core/index.d.mts +3 -3
  28. package/dist/core/index.mjs +5 -5
  29. package/dist/{core-Ba-6Sue6.mjs → core-DZ6Xe1jR.mjs} +182 -55
  30. package/dist/{createActionRouter-B_WzBFyf.mjs → createActionRouter-BWMDW-dL.mjs} +4 -4
  31. package/dist/{createAggregationRouter-B_G_nIjm.mjs → createAggregationRouter-l5mNdYrZ.mjs} +5 -4
  32. package/dist/{createApp--703hQE1.mjs → createApp-Bi61XxqU.mjs} +229 -24
  33. package/dist/discovery/index.d.mts +0 -1
  34. package/dist/docs/index.d.mts +1 -2
  35. package/dist/docs/index.mjs +1 -1
  36. package/dist/{elevation-xGUBq6p_.d.mts → elevation-C9s5hFP_.d.mts} +0 -1
  37. package/dist/encryption/index.d.mts +2 -144
  38. package/dist/{errorHandler-BtUUDPEa.d.mts → errorHandler-B0e-bq-O.d.mts} +0 -1
  39. package/dist/{errors-DOHkjQlD.d.mts → errors-DHcHVAgk.d.mts} +0 -1
  40. package/dist/{eventPlugin-DbBFd3x_.d.mts → eventPlugin-A6EbthXR.d.mts} +10 -6
  41. package/dist/events/index.d.mts +9 -6
  42. package/dist/events/index.mjs +9 -6
  43. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  44. package/dist/events/transports/redis.d.mts +1 -2
  45. package/dist/factory/index.d.mts +5 -4
  46. package/dist/factory/index.mjs +3 -3
  47. package/dist/{fastify-augmentation-D-5_yQJi.d.mts → fastify-augmentation-DafigGQp.d.mts} +12 -2
  48. package/dist/{fields-C7ahdGYf.d.mts → fields-BGqrAa_u.d.mts} +1 -2
  49. package/dist/{generate-Brans3fW.mjs → generate-usRSdQmP.mjs} +4 -3
  50. package/dist/hooks/index.d.mts +1 -1
  51. package/dist/idempotency/index.d.mts +4 -3
  52. package/dist/idempotency/index.mjs +1 -1
  53. package/dist/idempotency/redis.d.mts +1 -1
  54. package/dist/{index-CP6A1Ffj.d.mts → index-B5N-NaHs.d.mts} +88 -7
  55. package/dist/{index-CRKiiP5o.d.mts → index-B5PoNbfu.d.mts} +41 -7
  56. package/dist/{index-CUTG2Cuo.d.mts → index-Dtrj6XZk.d.mts} +90 -29
  57. package/dist/index.d.mts +7 -7
  58. package/dist/index.mjs +7 -7
  59. package/dist/{init-Bqpt1Hxf.mjs → init-0YhHkXGk.mjs} +239 -140
  60. package/dist/integrations/event-gateway.d.mts +2 -3
  61. package/dist/integrations/index.d.mts +2 -2
  62. package/dist/integrations/jobs.d.mts +0 -1
  63. package/dist/integrations/mcp/index.d.mts +6 -7
  64. package/dist/integrations/mcp/index.mjs +1 -1
  65. package/dist/integrations/mcp/testing.d.mts +1 -2
  66. package/dist/integrations/mcp/testing.mjs +1 -1
  67. package/dist/integrations/streamline.d.mts +19 -7
  68. package/dist/integrations/streamline.mjs +9 -5
  69. package/dist/integrations/webhooks.d.mts +0 -1
  70. package/dist/integrations/websocket-pushref-redis.d.mts +1 -2
  71. package/dist/integrations/websocket-redis.d.mts +1 -2
  72. package/dist/integrations/websocket.d.mts +2 -2
  73. package/dist/{loadResources-B8UmpITt.mjs → loadResources-DpU8pfjV.mjs} +4 -3
  74. package/dist/{loadResourcesFromEntry-BTlFEx05.mjs → loadResourcesFromEntry-OMCvIEE7.mjs} +1 -1
  75. package/dist/{mcpPlugin-C088Nd-G.mjs → mcpPlugin-B9XjjNVG.mjs} +148 -49
  76. package/dist/middleware/index.d.mts +1 -2
  77. package/dist/middleware/index.mjs +1 -1
  78. package/dist/module-WeuU5jfd.d.mts +429 -0
  79. package/dist/{openapi-DZ-5a5Op.mjs → openapi-Kyod_di6.mjs} +3 -3
  80. package/dist/permissions/index.d.mts +3 -3
  81. package/dist/permissions/index.mjs +2 -2
  82. package/dist/{permissions-BPB1xqGf.mjs → permissions-BJMuKMl7.mjs} +43 -3
  83. package/dist/pipeline/index.d.mts +1 -2
  84. package/dist/plugins/index.d.mts +87 -10
  85. package/dist/plugins/index.mjs +91 -4
  86. package/dist/plugins/response-cache.d.mts +5 -3
  87. package/dist/plugins/tracing-entry.d.mts +1 -1
  88. package/dist/plugins/tracing-entry.mjs +1 -1
  89. package/dist/{pluralize-DccFV9R7.mjs → pluralize-BhrgwZb9.mjs} +3 -3
  90. package/dist/presets/filesUpload.d.mts +4 -5
  91. package/dist/presets/filesUpload.mjs +1 -1
  92. package/dist/presets/index.d.mts +16 -3
  93. package/dist/presets/index.mjs +1 -1
  94. package/dist/presets/multiTenant.d.mts +1 -2
  95. package/dist/presets/multiTenant.mjs +1 -1
  96. package/dist/presets/search.d.mts +2 -3
  97. package/dist/presets/search.mjs +3 -2
  98. package/dist/{presets-BtyFwTO4.mjs → presets-gw0ciIUD.mjs} +1 -1
  99. package/dist/{pushref-registry-DnCqL3aa.d.mts → pushref-registry-BbcnpNTm.d.mts} +4 -2
  100. package/dist/{queryCachePlugin-xzFyKAjT.d.mts → queryCachePlugin-CfYWq-Ak.d.mts} +1 -2
  101. package/dist/{queryCachePlugin-emHb0CuX.mjs → queryCachePlugin-DzqLN904.mjs} +2 -2
  102. package/dist/{redis-C3W0qbz8.d.mts → redis-UDtLaNj6.d.mts} +0 -1
  103. package/dist/{redis-stream-DsP1vqZB.d.mts → redis-stream-iVR2l7aS.d.mts} +1 -2
  104. package/dist/{registerRoute-BdV8DDwU.mjs → registerRoute-oGAl0oA8.mjs} +1 -1
  105. package/dist/registry/index.d.mts +2 -2
  106. package/dist/registry/index.mjs +2 -2
  107. package/dist/{registry-Bm9LjWKs.mjs → registry-vcOCtPij.mjs} +1 -1
  108. package/dist/{schemaIR-D1MJwqmp.mjs → schemaIR-ajetw3Fv.mjs} +1 -42
  109. package/dist/schemas/index.d.mts +0 -1
  110. package/dist/scim/index.d.mts +0 -1
  111. package/dist/scim/index.mjs +2 -2
  112. package/dist/scope/index.d.mts +2 -3
  113. package/dist/{sessionManager-BXG-HGwG.d.mts → sessionManager-BHOM3N_0.d.mts} +10 -6
  114. package/dist/{storage-Co_PQpeQ.d.mts → storage-DLUZ04kK.d.mts} +8 -4
  115. package/dist/sync/changelog.d.mts +2 -0
  116. package/dist/sync/changelog.mjs +2 -0
  117. package/dist/testing/index.d.mts +2 -3
  118. package/dist/testing/index.mjs +6 -3
  119. package/dist/testing/storageContract.d.mts +1 -2
  120. package/dist/{tracing-D8jlGXP7.d.mts → tracing-CsGKQJGg.d.mts} +0 -1
  121. package/dist/types/index.d.mts +4 -4
  122. package/dist/types/storage.d.mts +1 -1
  123. package/dist/types-Cc91nXuA.d.mts +132 -0
  124. package/dist/{types-LNebCoJx.d.mts → types-DH0GupI7.d.mts} +8 -4
  125. package/dist/{types-DpvSF5Hh.d.mts → types-DRj-Ut4n.d.mts} +1 -2
  126. package/dist/{types-9_wtNPsI.d.mts → types-DpxoNX5v.d.mts} +112 -214
  127. package/dist/utils/index.d.mts +182 -128
  128. package/dist/utils/index.mjs +2 -2
  129. package/dist/{utils-C6QQ9-hd.mjs → utils-CO8a3B_1.mjs} +1435 -1391
  130. package/dist/{validate-CRcaWzp2.mjs → validate-C2mGgSXg.mjs} +3 -3
  131. package/dist/{versioning-D_eBCfNr.d.mts → versioning-DQ4mCvg0.d.mts} +1 -2
  132. package/dist/{websocket-MlYlrYq0.d.mts → websocket-uuWqM6UY.d.mts} +5 -4
  133. package/package.json +18 -13
  134. package/skills/arc/SKILL.md +10 -0
  135. package/skills/arc/references/mcp.md +2 -0
  136. package/skills/arc-module-publishing/SKILL.md +242 -0
  137. package/skills/arc-module-publishing/references/authoring-modules.md +272 -0
  138. package/skills/arc-module-publishing/references/package-manifest.md +155 -0
  139. package/skills/arc-module-publishing/references/publishing-workflow.md +182 -0
@@ -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,2 +1,2 @@
1
- import { n as RedisStreamTransport, r as RedisStreamTransportOptions, t as RedisStreamLike } from "../../redis-stream-DsP1vqZB.mjs";
1
+ import { n as RedisStreamTransport, r as RedisStreamTransportOptions, t as RedisStreamLike } from "../../redis-stream-iVR2l7aS.mjs";
2
2
  export { type RedisStreamLike, RedisStreamTransport, type RedisStreamTransportOptions };
@@ -1,5 +1,4 @@
1
- import { a as EventTransport, i as EventLogger, n as DomainEvent, r as EventHandler } from "../../EventTransport-IEn7Tn-Q.mjs";
2
-
1
+ import { a as EventTransport, i as EventLogger, n as DomainEvent, r as EventHandler } from "../../EventTransport-QmY7A258.mjs";
3
2
  //#region src/events/transports/redis.d.ts
4
3
  interface RedisLike {
5
4
  publish(channel: string, message: string): Promise<number>;
@@ -1,13 +1,14 @@
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-WeuU5jfd.mjs";
2
+ import "../fastify-augmentation-DafigGQp.mjs";
3
+ 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-DpxoNX5v.mjs";
2
4
  import { FastifyInstance, FastifyServerOptions } from "fastify";
3
-
4
5
  //#region src/factory/createApp.d.ts
5
6
  /**
6
7
  * Create a production-ready Fastify application with Arc framework.
7
8
  *
8
9
  * Boot order:
9
10
  * ```
10
- * 0. Logger, validation, preset merge
11
+ * 0. Logger, validation → beforeBoot() (DB connect etc.), preset merge
11
12
  * 1. Create Fastify instance
12
13
  * 2. Security plugins (Helmet, CORS, Rate Limit) — opt-out
13
14
  * 3. Utility plugins (Under Pressure, Sensible, Multipart, Raw Body)
@@ -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,6 +1,6 @@
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";
3
- import { t as loadResources } from "../loadResources-B8UmpITt.mjs";
2
+ import { a as edgePreset, c as testingPreset, d as orderModules, f as resolveModule, i as developmentPreset, l as defineModule, n as createApp, o as getPreset, s as productionPreset, t as ArcFactory, u as getModuleExports } from "../createApp-Bi61XxqU.mjs";
3
+ import { t as loadResources } from "../loadResources-DpU8pfjV.mjs";
4
4
  //#region src/factory/edge.ts
5
5
  /**
6
6
  * Convert a Fastify app into a Web Standards fetch handler.
@@ -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,7 +1,7 @@
1
- import { bn as HookSystem, z as ResourceRegistry } from "./index-CUTG2Cuo.mjs";
1
+ import { bn as HookSystem, z as ResourceRegistry } from "./index-Dtrj6XZk.mjs";
2
2
  import { t as ExternalOpenApiPaths } from "./externalPaths-BE6wFpYv.mjs";
3
+ import { r as ArcModuleRegistry } from "./module-WeuU5jfd.mjs";
3
4
  import { FastifyPluginAsync } from "fastify";
4
-
5
5
  //#region src/core/arcCorePlugin.d.ts
6
6
  interface ArcCorePluginOptions {
7
7
  /** Enable event emission for CRUD operations (requires eventPlugin) */
@@ -28,6 +28,16 @@ interface ArcCore {
28
28
  externalOpenApiPaths: ExternalOpenApiPaths[];
29
29
  /** Registered plugins for introspection */
30
30
  plugins: Map<string, PluginMeta>;
31
+ /**
32
+ * Module public exports — `bootstrap()` return values keyed by module name
33
+ * (see `src/factory/module.ts`). Read via `getModuleExports(fastify, name)`:
34
+ * augment `ArcModuleRegistry` once and the name infers the export type;
35
+ * otherwise pass it inline. `Partial<ArcModuleRegistry>` gives augmented
36
+ * apps typed direct access (`fastify.arc.modules.order`), while the
37
+ * `Record<string, unknown>` intersection keeps un-augmented reads open.
38
+ * Populated lazily by `registerResources` — absent until a module exports.
39
+ */
40
+ modules?: Partial<ArcModuleRegistry> & Record<string, unknown>;
31
41
  }
32
42
  declare const arcCorePlugin: FastifyPluginAsync<ArcCorePluginOptions>;
33
43
  declare const _default: FastifyPluginAsync<ArcCorePluginOptions>;
@@ -1,6 +1,5 @@
1
- import { i as RequestScope } from "./types-LNebCoJx.mjs";
1
+ import { i as RequestScope } from "./types-DH0GupI7.mjs";
2
2
  import { FastifyRequest } from "fastify";
3
-
4
3
  //#region src/permissions/types.d.ts
5
4
  /**
6
5
  * User base interface - minimal shape Arc expects
@@ -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-Dtrj6XZk.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 };
@@ -1,8 +1,7 @@
1
1
  import { i as createIdempotencyResult, n as IdempotencyResult, r as IdempotencyStore, t as IdempotencyLock } from "../interface-Uk8ONJv7.mjs";
2
- import { i as RedisIdempotencyStoreOptions, n as RedisClient } from "../redis-C3W0qbz8.mjs";
2
+ import { i as RedisIdempotencyStoreOptions, n as RedisClient } from "../redis-UDtLaNj6.mjs";
3
3
  import { FastifyPluginAsync } from "fastify";
4
4
  import { RepositoryLike } from "@classytic/repo-core/adapter";
5
-
6
5
  //#region src/idempotency/idempotencyPlugin.d.ts
7
6
  interface IdempotencyPluginOptions {
8
7
  /** Enable idempotency (default: false) */
@@ -60,7 +59,9 @@ declare module "fastify" {
60
59
  interface FastifyInstance {
61
60
  /** Idempotency utilities */
62
61
  idempotency: {
63
- /** Manually invalidate an idempotency key */invalidate: (key: string) => Promise<void>; /** Check if a key has a cached response */
62
+ /** Manually invalidate an idempotency key */
63
+ invalidate: (key: string) => Promise<void>;
64
+ /** Check if a key has a cached response */
64
65
  has: (key: string) => Promise<boolean>;
65
66
  /**
66
67
  * Route-level preHandler for idempotency check + lock.
@@ -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",
@@ -1,2 +1,2 @@
1
- import { a as UpstashRedisLike, i as RedisIdempotencyStoreOptions, n as RedisClient, o as ioredisAsIdempotencyClient, r as RedisIdempotencyStore, s as upstashAsIdempotencyClient, t as IoredisLike } from "../redis-C3W0qbz8.mjs";
1
+ import { a as UpstashRedisLike, i as RedisIdempotencyStoreOptions, n as RedisClient, o as ioredisAsIdempotencyClient, r as RedisIdempotencyStore, s as upstashAsIdempotencyClient, t as IoredisLike } from "../redis-UDtLaNj6.mjs";
2
2
  export { type IoredisLike, type RedisClient, RedisIdempotencyStore, type RedisIdempotencyStoreOptions, type UpstashRedisLike, ioredisAsIdempotencyClient, upstashAsIdempotencyClient };
@@ -1,11 +1,12 @@
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";
2
- import { i as RequestScope } from "./types-LNebCoJx.mjs";
3
- import { c as PermissionCheck } from "./fields-C7ahdGYf.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-Dtrj6XZk.mjs";
2
+ import { i as RequestScope } from "./types-DH0GupI7.mjs";
3
+ import { c as PermissionCheck } from "./fields-BGqrAa_u.mjs";
4
+ import "./fastify-augmentation-DafigGQp.mjs";
4
5
  import { FastifyReply, FastifyRequest, RouteHandlerMethod } from "fastify";
5
6
  import { z } from "zod";
7
+ import { DataAdapter } from "@classytic/repo-core/adapter";
6
8
  import { AggDateBucket, AggMeasure, AggTopN } from "@classytic/repo-core/repository";
7
9
  import { LookupSpec } from "@classytic/repo-core/lookup";
8
-
9
10
  //#region src/constants.d.ts
10
11
  /**
11
12
  * Arc Framework Constants — Single Source of Truth
@@ -130,7 +131,7 @@ declare function createPermissionMiddleware(permission: PermissionCheck, resourc
130
131
  * Plain JSON-Schema entries skip the inference path entirely (they go
131
132
  * through the untyped `ActionDefinition` form).
132
133
  */
133
- interface DefineActionConfig<TSchema extends z.ZodTypeAny | undefined = undefined, TData = (TSchema extends z.ZodTypeAny ? z.infer<TSchema> : Record<string, unknown>)> {
134
+ interface DefineActionConfig<TSchema extends z.ZodTypeAny | undefined = undefined, TData = TSchema extends z.ZodTypeAny ? z.infer<TSchema> : Record<string, unknown>> {
134
135
  /** Per-action body schema (Zod v4). Drives both AJV validation and the typed `data` param. */
135
136
  schema?: TSchema;
136
137
  /** Per-action permission gate. Falls back to resource-level if omitted. */
@@ -167,6 +168,86 @@ interface DefineActionConfig<TSchema extends z.ZodTypeAny | undefined = undefine
167
168
  */
168
169
  declare function defineAction<TSchema extends z.ZodTypeAny | undefined = undefined>(config: DefineActionConfig<TSchema>): ActionDefinition;
169
170
  //#endregion
171
+ //#region src/core/defineResource/seams.d.ts
172
+ /**
173
+ * Structural adapter boundary — the `ControllerLike` pattern (v2.10.6)
174
+ * applied to adapters. `DataAdapter<T>` is invariant in `T`, so a
175
+ * `DataAdapter<HydratedDocument<IProduct>>` built by the HOST does not
176
+ * assign to a module's `DataAdapter<AnyRecord>` slot; before this type,
177
+ * module authors erased the slot to `unknown` and cast at every use.
178
+ *
179
+ * Arc only reaches for these members at runtime — the rest of the adapter's
180
+ * shape is the caller's concern. All slots optional + `unknown` so every
181
+ * kit adapter (mongokit, sqlitekit, prismakit, custom) assigns structurally.
182
+ *
183
+ * Used by {@link ResourceSeams}; `ResourceConfig.adapter` itself stays
184
+ * `DataAdapter<TDoc>` so `defineResource`'s doc-type inference is untouched.
185
+ */
186
+ interface AdapterLike {
187
+ repository?: unknown;
188
+ generateSchemas?: unknown;
189
+ getSchemaMetadata?: unknown;
190
+ }
191
+ /**
192
+ * Seam-slot type transform, two widenings per property:
193
+ *
194
+ * - admits explicit `undefined` — {@link mergeResourceConfig} skips
195
+ * `undefined` values at runtime, so the type says so. Makes
196
+ * field-mapping seams (`{ permissions: cfg.permissionsMap, ... }`)
197
+ * ergonomic under `exactOptionalPropertyTypes: true` (stricter than
198
+ * arc's own tsconfig — found by a live spine-module smoke).
199
+ * - array slots also accept `readonly` arrays — hosts naturally write
200
+ * route/preset tables `as const` or behind `readonly` exports; the
201
+ * merge copies arrays into fresh mutable ones, so a frozen host table
202
+ * never leaks into arc's internals.
203
+ */
204
+ type SeamSlot<V> = V | undefined | (V extends (infer E)[] ? readonly E[] : never);
205
+ type SkippableUndefined<T> = { [K in keyof T]: SeamSlot<T[K]>; };
206
+ /**
207
+ * The host-injectable subset of a resource config — everything a module can
208
+ * let its host override, i.e. every `ResourceConfig` slot except the
209
+ * module-owned `name` (and the internal preset-tracking field).
210
+ *
211
+ * Type your module's per-resource override bundles as `ResourceSeams` (or a
212
+ * `Pick<ResourceSeams, ...>` allow-list when you want to constrain what
213
+ * hosts may touch) and pass them through {@link mergeResourceConfig}.
214
+ */
215
+ type ResourceSeams<TDoc = AnyRecord> = SkippableUndefined<Omit<ResourceConfig<TDoc>, "name" | "_appliedPresets" | "adapter">> & {
216
+ /** Any kit adapter — widened via {@link AdapterLike} at this boundary. */
217
+ adapter?: DataAdapter<TDoc> | AdapterLike | undefined;
218
+ };
219
+ /**
220
+ * Base-config input for {@link mergeResourceConfig} — a required `name`
221
+ * plus every seam slot (which is exactly `ResourceConfig` with the
222
+ * {@link AdapterLike} widening, `undefined`-skipping, and readonly-array
223
+ * acceptance the seams get). Module builders constructing DEFAULT adapters
224
+ * from untyped kernel engine bags hit the identical `DataAdapter<T>`
225
+ * invariance at the base as hosts do at the seam.
226
+ */
227
+ type SeamedResourceConfig<TDoc = AnyRecord> = {
228
+ name: string;
229
+ } & ResourceSeams<TDoc>;
230
+ /**
231
+ * Canonical slot-aware merge of a base resource config with host seams.
232
+ * Later seams win over earlier ones; `undefined` values never clobber.
233
+ *
234
+ * Merge semantics (value-driven — no per-slot registry to drift):
235
+ *
236
+ * - **Top-level arrays CONCAT** — `routes`, `middlewares`, `presets`,
237
+ * `routeGuards`, `disabledRoutes`: additive collections, base first.
238
+ * - **Plain objects merge recursively** — `permissions`, `actions`,
239
+ * `schemaOptions` (incl. `fieldRules`), `aggregations`, `customSchemas`,
240
+ * `fields`, `cache`, `events`: per-key composition. Arrays NESTED inside
241
+ * them replace (they're value lists — enums, sort specs), not concat.
242
+ * - **Everything else last-wins** — class instances (`adapter`,
243
+ * `controller`, `queryParser`), functions, scalars.
244
+ *
245
+ * The single `as` at the return is the one documented erasure for the
246
+ * {@link AdapterLike}-widened seam slots — inside the helper so no module
247
+ * author ever writes one (mirrors mongokit's one-cast-at-the-boundary rule).
248
+ */
249
+ declare function mergeResourceConfig<TDoc = AnyRecord>(base: SeamedResourceConfig<TDoc>, ...seams: ReadonlyArray<ResourceSeams<TDoc> | undefined>): ResourceConfig<TDoc>;
250
+ //#endregion
170
251
  //#region src/core/defineResourceVariants.d.ts
171
252
  /**
172
253
  * Required identity fields for each variant. The user MUST provide a unique
@@ -188,7 +269,7 @@ type VariantsMap<TDoc = AnyRecord> = Record<string, VariantOverride<TDoc>>;
188
269
  * Result type — preserves the variant keys so destructuring is type-safe:
189
270
  * `const { articlePublic, articleAdmin } = defineResourceVariants(...)`.
190
271
  */
191
- type VariantsResult<TDoc, V extends VariantsMap<TDoc>> = { [K in keyof V]: ResourceDefinition<TDoc> };
272
+ type VariantsResult<TDoc, V extends VariantsMap<TDoc>> = { [K in keyof V]: ResourceDefinition<TDoc>; };
192
273
  /**
193
274
  * Define multiple resources from a shared base config and per-variant overrides.
194
275
  *
@@ -344,4 +425,4 @@ declare function isFieldReadable(rule: ArcFieldRule | undefined): boolean;
344
425
  */
345
426
  declare function collectReadBlockedFields(schemaOptions: RouteSchemaOptions | undefined): Set<string> | null;
346
427
  //#endregion
347
- export { MAX_FILTER_DEPTH as A, DEFAULT_SORT as C, HOOK_PHASES as D, HOOK_OPERATIONS as E, RESERVED_QUERY_PARAMS as F, SYSTEM_FIELDS as I, MAX_SEARCH_LENGTH as M, MUTATION_OPERATIONS as N, HookOperation as O, MutationOperation as P, DEFAULT_MAX_LIMIT as S, DEFAULT_UPDATE_METHOD as T, defineAggregation as _, createRequestContext as a, DEFAULT_ID_FIELD as b, sendControllerResponse as c, getEntityQuery as d, defineResourceVariants as f, createPermissionMiddleware as g, createCrudRouter as h, createFastifyHandler as i, MAX_REGEX_LENGTH as j, HookPhase as k, getEntityId as l, defineAction as m, isFieldReadable as n, getControllerContext as o, DefineActionConfig as p, createCrudHandlers as r, getControllerScope as s, collectReadBlockedFields as t, getEntityIdField as u, CRUD_OPERATIONS as v, DEFAULT_TENANT_FIELD as w, DEFAULT_LIMIT as x, CrudOperation as y };
428
+ export { HOOK_OPERATIONS as A, SYSTEM_FIELDS as B, CrudOperation as C, DEFAULT_SORT as D, DEFAULT_MAX_LIMIT as E, MAX_REGEX_LENGTH as F, MAX_SEARCH_LENGTH as I, MUTATION_OPERATIONS as L, HookOperation as M, HookPhase as N, DEFAULT_TENANT_FIELD as O, MAX_FILTER_DEPTH as P, MutationOperation as R, CRUD_OPERATIONS as S, DEFAULT_LIMIT as T, DefineActionConfig as _, createRequestContext as a, createPermissionMiddleware as b, sendControllerResponse as c, getEntityQuery as d, defineResourceVariants as f, mergeResourceConfig as g, SeamedResourceConfig as h, createFastifyHandler as i, HOOK_PHASES as j, DEFAULT_UPDATE_METHOD as k, getEntityId as l, ResourceSeams as m, isFieldReadable as n, getControllerContext as o, AdapterLike as p, createCrudHandlers as r, getControllerScope as s, collectReadBlockedFields as t, getEntityIdField as u, defineAction as v, DEFAULT_ID_FIELD as w, defineAggregation as x, createCrudRouter as y, RESERVED_QUERY_PARAMS as z };
@@ -1,8 +1,7 @@
1
1
  import { r as CacheStore, t as CacheLogger } from "./interface-C1_WLTMK.mjs";
2
- import { i as RequestScope, n as Mandate } from "./types-LNebCoJx.mjs";
3
- import { c as PermissionCheck, l as PermissionContext, u as PermissionResult } from "./fields-C7ahdGYf.mjs";
2
+ import { i as RequestScope, n as Mandate } from "./types-DH0GupI7.mjs";
3
+ import { c as PermissionCheck, l as PermissionContext, u as PermissionResult } from "./fields-BGqrAa_u.mjs";
4
4
  import { FastifyReply, FastifyRequest } from "fastify";
5
-
6
5
  //#region src/permissions/agent.d.ts
7
6
  /**
8
7
  * Require a sender-constrained credential — the inbound token MUST carry a
@@ -356,8 +355,11 @@ interface DynamicPermissionMatrixConfig {
356
355
  * and `ttlSeconds > 0`, Arc creates an internal MemoryCacheStore.
357
356
  */
358
357
  cache?: {
359
- /** Cache TTL in seconds */ttlSeconds: number; /** Optional custom cache key builder */
360
- key?: (ctx: PermissionContext) => string | null | undefined; /** Hard entry cap for internal memory store (default: 1000) */
358
+ /** Cache TTL in seconds */
359
+ ttlSeconds: number;
360
+ /** Optional custom cache key builder */
361
+ key?: (ctx: PermissionContext) => string | null | undefined;
362
+ /** Hard entry cap for internal memory store (default: 1000) */
361
363
  maxEntries?: number;
362
364
  };
363
365
  }
@@ -620,7 +622,7 @@ declare function requireOrgInScope<TDoc = Record<string, unknown>>(target: strin
620
622
  */
621
623
  declare function requireTeamMembership<TDoc = Record<string, unknown>>(): PermissionCheck<TDoc>;
622
624
  declare namespace presets_d_exports {
623
- export { adminOnly, authenticated, fullPublic, ownerWithAdminBypass, publicRead, publicReadAdminWrite, readOnly };
625
+ export { adminOnly, authenticated, fullPublic, ownerWithAdminBypass, permissionMatrix, publicRead, publicReadAdminWrite, readOnly };
624
626
  }
625
627
  /**
626
628
  * ResourcePermissions shape — matches the type in types/index.ts
@@ -652,6 +654,33 @@ declare function authenticated<TDoc = Record<string, unknown>>(overrides?: Permi
652
654
  * @param roles - Required roles (user needs at least one). Default: ['admin']
653
655
  */
654
656
  declare function adminOnly<TDoc = Record<string, unknown>>(roles?: readonly string[], overrides?: PermissionOverrides<TDoc>): ResourcePermissions<TDoc>;
657
+ /**
658
+ * Arbitrary-gate CRUD matrix — the generalization every host and arc-*
659
+ * module hand-rolls as `{ list: view, get: view, create: manage, ... }`.
660
+ *
661
+ * Unlike the fixed presets above, the gates are caller-supplied
662
+ * `PermissionCheck`s, so ANY combinator plugs in — org roles, ownership,
663
+ * `anyOf(...)`, service scopes, custom async checks. `delete` defaults to
664
+ * the `write` gate.
665
+ *
666
+ * @example
667
+ * ```typescript
668
+ * // Two-gate (view/manage) — the arc-* module convention:
669
+ * permissionMatrix({ read: requireAuth(), write: requireOrgRole('manager') })
670
+ *
671
+ * // Three-gate with a stricter delete:
672
+ * permissionMatrix({
673
+ * read: allowPublic(),
674
+ * write: requireOrgRole('manager'),
675
+ * delete: requireOrgRole('owner'),
676
+ * })
677
+ * ```
678
+ */
679
+ declare function permissionMatrix<TDoc = Record<string, unknown>>(gates: {
680
+ read: PermissionCheck<TDoc>;
681
+ write: PermissionCheck<TDoc>;
682
+ delete?: PermissionCheck<TDoc>;
683
+ }, overrides?: PermissionOverrides<TDoc>): ResourcePermissions<TDoc>;
655
684
  /**
656
685
  * Owner-scoped with admin bypass.
657
686
  * list = auth (scoped to owner), get = auth, create = auth,
@@ -669,7 +698,12 @@ declare function fullPublic<TDoc = Record<string, unknown>>(overrides?: Permissi
669
698
  /**
670
699
  * Read-only: list + get authenticated, write operations denied.
671
700
  * Useful for computed/derived resources.
701
+ *
702
+ * Writes carry an explicit `denyAll` check — an omitted CRUD permission
703
+ * mounts the route with NO gate (public-by-omission), so leaving
704
+ * create/update/delete undefined here would expose unauthenticated writes.
705
+ * Hosts that disable write routes entirely (`disabledRoutes`) are unaffected.
672
706
  */
673
707
  declare function readOnly<TDoc = Record<string, unknown>>(overrides?: PermissionOverrides<TDoc>): ResourcePermissions<TDoc>;
674
708
  //#endregion
675
- export { requireRoles as A, allOf as C, not as D, denyAll as E, RequireAgentScopeOptions as F, RequireMandateOptions as I, requireAgentScope as L, when as M, applyPermissionResult as N, requireAuth as O, normalizePermissionResult as P, requireDPoP as R, createOrgPermissions as S, anyOf as T, ConnectEventsOptions as _, presets_d_exports as a, PermissionEventBus as b, readOnly as c, requireOrgRole as d, requireScopeContext as f, createRoleHierarchy as g, RoleHierarchy as h, ownerWithAdminBypass as i, roles as j, requireOwnership as k, requireOrgInScope as l, requireTeamMembership as m, authenticated as n, publicRead as o, requireServiceScope as p, fullPublic as r, publicReadAdminWrite as s, adminOnly as t, requireOrgMembership as u, DynamicPermissionMatrix as v, allowPublic as w, createDynamicPermissionMatrix as x, DynamicPermissionMatrixConfig as y, requireMandate as z };
709
+ export { requireOwnership as A, requireMandate as B, createOrgPermissions as C, denyAll as D, anyOf as E, normalizePermissionResult as F, RequireAgentScopeOptions as I, RequireMandateOptions as L, roles as M, when as N, not as O, applyPermissionResult as P, requireAgentScope as R, createDynamicPermissionMatrix as S, allowPublic as T, createRoleHierarchy as _, permissionMatrix as a, DynamicPermissionMatrixConfig as b, publicReadAdminWrite as c, requireOrgMembership as d, requireOrgRole as f, RoleHierarchy as g, requireTeamMembership as h, ownerWithAdminBypass as i, requireRoles as j, requireAuth as k, readOnly as l, requireServiceScope as m, authenticated as n, presets_d_exports as o, requireScopeContext as p, fullPublic as r, publicRead as s, adminOnly as t, requireOrgInScope as u, ConnectEventsOptions as v, allOf as w, PermissionEventBus as x, DynamicPermissionMatrix as y, requireDPoP as z };