@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
@@ -1,7 +1,7 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.mjs";
2
- import { i as versionKey, r as tagVersionKey } from "./keys-Cd316u_y.mjs";
3
2
  import { t as MemoryCacheStore } from "./memory-CLXA2VeJ.mjs";
4
3
  import { t as hasEvents } from "./typeGuards-C9KXUly6.mjs";
4
+ import { i as versionKey, r as tagVersionKey } from "./keys-Cd316u_y.mjs";
5
5
  import fp from "fastify-plugin";
6
6
  //#region src/cache/QueryCache.ts
7
7
  var QueryCache = class {
@@ -72,7 +72,7 @@ var QueryCache = class {
72
72
  //#endregion
73
73
  //#region src/cache/queryCachePlugin.ts
74
74
  var queryCachePlugin_exports = /* @__PURE__ */ __exportAll({ queryCachePlugin: () => queryCachePlugin });
75
- const CRUD_SUFFIXES = new Set([
75
+ const CRUD_SUFFIXES = /* @__PURE__ */ new Set([
76
76
  "created",
77
77
  "updated",
78
78
  "deleted"
@@ -1,6 +1,6 @@
1
1
  import { f as createError } from "./errors-DkO8Nk6-.mjs";
2
- import { M as evaluateAndApplyPermission } from "./permissions-BPB1xqGf.mjs";
3
2
  import { n as requestContext } from "./requestContext-BZKOr13H.mjs";
3
+ import { M as evaluateAndApplyPermission } from "./permissions-CgbOLJZG.mjs";
4
4
  //#region src/core/middlewares/arcDecorator.ts
5
5
  /**
6
6
  * Build the `arcDecorator` preHandler for a resource.
@@ -1,4 +1,4 @@
1
- import { J as CrudRouteKey, R as RegisterOptions, V as ResourceDefinition, at as ResolvedTenantPurge, k as IntrospectionPluginOptions, p as RegistryEntry, z as ResourceRegistry } from "../index-CUTG2Cuo.mjs";
1
+ import { J as CrudRouteKey, R as RegisterOptions, V as ResourceDefinition, at as ResolvedTenantPurge, k as IntrospectionPluginOptions, p as RegistryEntry, z as ResourceRegistry } from "../index-_--GyzcO.mjs";
2
2
  import { FastifyPluginAsync } from "fastify";
3
3
  import { TenantPurgeProgress, TenantPurgeStrategy } from "@classytic/repo-core/repository";
4
4
 
@@ -1,3 +1,3 @@
1
- import { a as cascadeDeleteForOrganization, c as assertNoTenantData, i as introspectionPlugin_default, n as buildResourceManifestFromRegistry, o as getCascadingResources, r as introspectionPlugin, s as getCascadingResourcesWithMetadata, t as buildResourceManifest } from "../registry-Bm9LjWKs.mjs";
2
- import { t as ResourceRegistry } from "../ResourceRegistry-5fKZwhK_.mjs";
1
+ import { a as cascadeDeleteForOrganization, c as assertNoTenantData, i as introspectionPlugin_default, n as buildResourceManifestFromRegistry, o as getCascadingResources, r as introspectionPlugin, s as getCascadingResourcesWithMetadata, t as buildResourceManifest } from "../registry-vcOCtPij.mjs";
2
+ import { t as ResourceRegistry } from "../ResourceRegistry-7RnrEWNP.mjs";
3
3
  export { ResourceRegistry, assertNoTenantData, buildResourceManifest, buildResourceManifestFromRegistry, cascadeDeleteForOrganization, getCascadingResources, getCascadingResourcesWithMetadata, introspectionPlugin_default as introspectionPlugin, introspectionPlugin as introspectionPluginFn };
@@ -1,4 +1,4 @@
1
- import { t as CRUD_OPERATIONS } from "./constants-gaEeMlz-.mjs";
1
+ import { t as CRUD_OPERATIONS } from "./constants-DNre0wRg.mjs";
2
2
  import fp from "fastify-plugin";
3
3
  //#region src/registry/assertNoTenantData.ts
4
4
  /**
@@ -1,5 +1,4 @@
1
1
  import { a as toJsonSchema } from "./schemaConverter-U0MnO9vd.mjs";
2
- import { z } from "zod";
3
2
  //#region src/core/schemaIR.ts
4
3
  /**
5
4
  * Schema IR — one canonical representation, two adapters.
@@ -98,27 +97,6 @@ function schemaIRToJsonSchemaBranch(ir, extras = {}) {
98
97
  };
99
98
  }
100
99
  /**
101
- * Emit a flat Zod shape from the IR. The MCP SDK wraps the returned record
102
- * in `z.object()` internally, so we return the bare shape (same contract
103
- * as `ToolDefinition.inputSchema`).
104
- *
105
- * `additionalProperties: false` is honored at the MCP handler layer rather
106
- * than baked into the Zod shape — the SDK's input validation happens before
107
- * the handler runs, and flat shapes can't express `.strict()` mode.
108
- * `strictAdditionalProperties(ir)` returns the flag so callers can gate
109
- * their handler on it.
110
- */
111
- function schemaIRToZodShape(ir) {
112
- const requiredSet = new Set(ir.required);
113
- const result = {};
114
- for (const [name, prop] of Object.entries(ir.properties)) {
115
- const desc = typeof prop.description === "string" && prop.description.length > 0 ? prop.description : name;
116
- const base = jsonSchemaPropToZod(prop);
117
- result[name] = requiredSet.has(name) ? base.describe(desc) : base.optional().describe(desc);
118
- }
119
- return result;
120
- }
121
- /**
122
100
  * Returns `true` when the IR declares `additionalProperties: false`. MCP
123
101
  * tool handlers should reject inputs with unknown keys when this is true,
124
102
  * matching HTTP's AJV-level strict enforcement.
@@ -126,24 +104,5 @@ function schemaIRToZodShape(ir) {
126
104
  function shouldRejectAdditionalProperties(ir) {
127
105
  return ir.additionalProperties === false;
128
106
  }
129
- /**
130
- * Convert a single JSON Schema property to a Zod type. Understands enum,
131
- * numeric/integer/boolean/array/object, and falls back to string for
132
- * unrecognized types (matches MCP's "strings for opaque fields" convention).
133
- *
134
- * Internal — use `schemaIRToZodShape` which wires this up with required/optional
135
- * + description handling.
136
- */
137
- function jsonSchemaPropToZod(schema) {
138
- if (Array.isArray(schema.enum) && schema.enum.length > 0) return z.enum(schema.enum);
139
- switch (typeof schema.type === "string" ? schema.type : "string") {
140
- case "number":
141
- case "integer": return z.number();
142
- case "boolean": return z.boolean();
143
- case "array": return z.array(z.unknown());
144
- case "object": return z.record(z.string(), z.unknown());
145
- default: return z.string();
146
- }
147
- }
148
107
  //#endregion
149
- export { shouldRejectAdditionalProperties as i, schemaIRToJsonSchemaBranch as n, schemaIRToZodShape as r, normalizeSchemaIR as t };
108
+ export { schemaIRToJsonSchemaBranch as n, shouldRejectAdditionalProperties as r, normalizeSchemaIR as t };
@@ -381,7 +381,7 @@ function resourceToScim(resource, mapping, baseUrl) {
381
381
  * parseScimFilter('active eq true and name.familyName sw "S"')
382
382
  * → { $and: [{ active: true }, { 'name.familyName': { $regex: '^S' } }] }
383
383
  */
384
- const COMPARISON_OPS = new Set([
384
+ const COMPARISON_OPS = /* @__PURE__ */ new Set([
385
385
  "eq",
386
386
  "ne",
387
387
  "co",
@@ -393,7 +393,7 @@ const COMPARISON_OPS = new Set([
393
393
  "le",
394
394
  "pr"
395
395
  ]);
396
- const LOGICAL_OPS = new Set([
396
+ const LOGICAL_OPS = /* @__PURE__ */ new Set([
397
397
  "and",
398
398
  "or",
399
399
  "not"
@@ -0,0 +1,2 @@
1
+ import { ChangeEntry, ChangeLogAppendOptions, ChangeLogStore, ChangeOp, ChangesPage, ChangesSinceOptions, CursorExpiredError, MemoryChangeLogStore, PushMutation, PushVerdict, PushVerdictStatus } from "@classytic/repo-core/sync";
2
+ export { type ChangeEntry, type ChangeLogAppendOptions, type ChangeLogStore, type ChangeOp, type ChangesPage, type ChangesSinceOptions, CursorExpiredError, MemoryChangeLogStore, type PushMutation, type PushVerdict, type PushVerdictStatus };
@@ -0,0 +1,2 @@
1
+ import { CursorExpiredError, MemoryChangeLogStore } from "@classytic/repo-core/sync";
2
+ export { CursorExpiredError, MemoryChangeLogStore };
@@ -1,5 +1,5 @@
1
- import { V as ResourceDefinition, qt as AnyRecord } from "../index-CUTG2Cuo.mjs";
2
- import { d as preloadResourcesAsync, r as CreateAppOptions, u as preloadResources } from "../types-9_wtNPsI.mjs";
1
+ import { V as ResourceDefinition, qt as AnyRecord } from "../index-_--GyzcO.mjs";
2
+ import { d as preloadResourcesAsync, r as CreateAppOptions, u as preloadResources } from "../types-BHMKlMBU.mjs";
3
3
  import { StorageContractSetup, StorageContractSetupResult, runStorageContract } from "./storageContract.mjs";
4
4
  import { FastifyInstance, FastifyServerOptions } from "fastify";
5
5
  import { Mock } from "vitest";
@@ -1,4 +1,4 @@
1
- import { t as CRUD_OPERATIONS } from "../constants-gaEeMlz-.mjs";
1
+ import { t as CRUD_OPERATIONS } from "../constants-DNre0wRg.mjs";
2
2
  import { n as preloadResourcesAsync, t as preloadResources } from "../preloadResources-CHw3_oA_.mjs";
3
3
  import { runStorageContract } from "./storageContract.mjs";
4
4
  import Fastify from "fastify";
@@ -1046,7 +1046,7 @@ function pickDefaultAuth(authMode, callerAuth) {
1046
1046
  };
1047
1047
  }
1048
1048
  async function createTestApp(options = {}) {
1049
- const { createApp } = await import("../createApp--703hQE1.mjs").then((n) => n.r);
1049
+ const { createApp } = await import("../createApp-D6uwzCKu.mjs").then((n) => n.r);
1050
1050
  const { resources = [], db = "in-memory", connectMongoose = false, authMode = "jwt", defaultOrgId, plugins, auth: callerAuth, ...appOptions } = options;
1051
1051
  let dbHandle;
1052
1052
  let dbUri;
@@ -1,4 +1,4 @@
1
- import { $ as OnTenantDeleteConfig, $t as UserOrganization, A as RequestIdOptions, C as RequestContext, D as HealthCheck, E as GracefulShutdownOptions, F as FastifyWithDecorators, Fn as BaseControllerOptions, G as ActionsMap, Gt as JwtContext, H as ActionDefinition, Ht as AuthPluginOptions, I as MiddlewareHandler, J as CrudRouteKey, Jt as ApiResponse, K as ArcFieldRule, Kt as TokenPair, L as RequestWithExtras, M as EventsDecorator, N as FastifyRequestExtras, O as HealthOptions, P as FastifyWithAuth, Q as MiddlewareConfig, Qt as UserLike, S as QueryParserInterface, St as RouteHandler, T as CrudRouterOptions, U as ActionEntry, Ut as Authenticator, Vt as AuthHelpers, W as ActionHandlerFn, Wt as AuthenticatorContext, X as EventDefinition, Xt as JWTPayload, Y as CrudSchemas, Yt as ArcRequest, Z as FieldRule, Zt as ObjectId, _ as ControllerQueryOptions, _t as ControllerLike, a as InferAdapterDoc, at as ResolvedTenantPurge, b as ParsedQuery, bt as IControllerResponse, c as TypedController, ct as ResourceExtensions, d as PaginationResult, dt as ResourcePermissions, et as OpenApiSchemas, f as IntrospectionData, ft as RouteDefinition, g as ArcInternalMetadata, gt as ControllerHandler, h as ResourceMetadata, ht as RouteSchemaOptions, i as ValidationResult, it as RateLimitConfig, j as ArcDecorator, k as IntrospectionPluginOptions, l as TypedRepository, lt as ResourceHookContext, m as RegistryStats, mt as RouteMethod, n as ConfigError, nt as PresetHook, o as InferDocType, ot as ResourceCacheConfig, p as RegistryEntry, pt as RouteMcpConfig, q as CrudController, qt as AnyRecord, r as ValidateOptions, rt as PresetResult, s as InferResourceDoc, st as ResourceConfig, t as RouteHandlerMethod, tt as PresetFunction, u as TypedResourceConfig, ut as ResourceHooks, v as LookupOption, vt as FastifyHandler, w as ServiceContext, x as PopulateOption, xt as IRequestContext, y as OwnershipCheck, yt as IController } from "../index-CUTG2Cuo.mjs";
1
+ import { $ as OnTenantDeleteConfig, $t as UserOrganization, A as RequestIdOptions, C as RequestContext, D as HealthCheck, E as GracefulShutdownOptions, F as FastifyWithDecorators, Fn as BaseControllerOptions, G as ActionsMap, Gt as JwtContext, H as ActionDefinition, Ht as AuthPluginOptions, I as MiddlewareHandler, J as CrudRouteKey, Jt as ApiResponse, K as ArcFieldRule, Kt as TokenPair, L as RequestWithExtras, M as EventsDecorator, N as FastifyRequestExtras, O as HealthOptions, P as FastifyWithAuth, Q as MiddlewareConfig, Qt as UserLike, S as QueryParserInterface, St as RouteHandler, T as CrudRouterOptions, U as ActionEntry, Ut as Authenticator, Vt as AuthHelpers, W as ActionHandlerFn, Wt as AuthenticatorContext, X as EventDefinition, Xt as JWTPayload, Y as CrudSchemas, Yt as ArcRequest, Z as FieldRule, Zt as ObjectId, _ as ControllerQueryOptions, _t as ControllerLike, a as InferAdapterDoc, at as ResolvedTenantPurge, b as ParsedQuery, bt as IControllerResponse, c as TypedController, ct as ResourceExtensions, d as PaginationResult, dt as ResourcePermissions, et as OpenApiSchemas, f as IntrospectionData, ft as RouteDefinition, g as ArcInternalMetadata, gt as ControllerHandler, h as ResourceMetadata, ht as RouteSchemaOptions, i as ValidationResult, it as RateLimitConfig, j as ArcDecorator, k as IntrospectionPluginOptions, l as TypedRepository, lt as ResourceHookContext, m as RegistryStats, mt as RouteMethod, n as ConfigError, nt as PresetHook, o as InferDocType, ot as ResourceCacheConfig, p as RegistryEntry, pt as RouteMcpConfig, q as CrudController, qt as AnyRecord, r as ValidateOptions, rt as PresetResult, s as InferResourceDoc, st as ResourceConfig, t as RouteHandlerMethod, tt as PresetFunction, u as TypedResourceConfig, ut as ResourceHooks, v as LookupOption, vt as FastifyHandler, w as ServiceContext, x as PopulateOption, xt as IRequestContext, y as OwnershipCheck, yt as IController } from "../index-_--GyzcO.mjs";
2
2
  import { i as RequestScope } from "../types-LNebCoJx.mjs";
3
3
  import { c as PermissionCheck, d as UserBase, l as PermissionContext, u as PermissionResult } from "../fields-C7ahdGYf.mjs";
4
4
  import { n as ElevationOptions, t as ElevationEvent } from "../elevation-xGUBq6p_.mjs";
@@ -1,208 +1,16 @@
1
- import { Ut as Authenticator } from "./index-CUTG2Cuo.mjs";
1
+ import { Ut as Authenticator } from "./index-_--GyzcO.mjs";
2
2
  import { r as CacheStore } from "./interface-C1_WLTMK.mjs";
3
3
  import { n as ElevationOptions } from "./elevation-xGUBq6p_.mjs";
4
4
  import { a as EventTransport } from "./EventTransport-IEn7Tn-Q.mjs";
5
5
  import { t as ExternalOpenApiPaths } from "./externalPaths-BE6wFpYv.mjs";
6
6
  import { r as QueryCachePluginOptions } from "./queryCachePlugin-xzFyKAjT.mjs";
7
+ import { l as ResourceLike, n as ArcModuleInput } from "./module-JYH9V0I8.mjs";
7
8
  import { t as EventPluginOptions } from "./eventPlugin-DbBFd3x_.mjs";
8
9
  import { _ as HealthOptions, f as CachingOptions, l as SSEOptions, o as MetricsOptions, t as VersioningOptions } from "./versioning-D_eBCfNr.mjs";
9
10
  import { t as ErrorHandlerOptions } from "./errorHandler-BtUUDPEa.mjs";
10
11
  import { r as IdempotencyStore } from "./interface-Uk8ONJv7.mjs";
11
12
  import { FastifyInstance, FastifyPluginAsync, FastifyReply, FastifyRequest, FastifyServerOptions } from "fastify";
12
13
 
13
- //#region src/factory/loadResources.d.ts
14
- /**
15
- * loadResources — Auto-discover resource files from a directory.
16
- *
17
- * Scans for `*.resource.{ts,js,mts,mjs}` files, imports each,
18
- * and collects their default exports. No barrel file needed.
19
- *
20
- * @example
21
- * ```ts
22
- * import { createApp, loadResources } from '@classytic/arc/factory';
23
- *
24
- * // Recommended: import.meta.url — works in both src/ (dev) and dist/ (prod)
25
- * const app = await createApp({
26
- * resources: await loadResources(import.meta.url),
27
- * auth: { type: 'jwt', jwt: { secret: process.env.JWT_SECRET } },
28
- * });
29
- *
30
- * // Or explicit path (must match runtime layout)
31
- * const app2 = await createApp({
32
- * resources: await loadResources('./src/resources'),
33
- * });
34
- * ```
35
- *
36
- * File convention:
37
- * ```
38
- * src/resources/
39
- * product/product.resource.ts → export default defineResource({ name: 'product', ... })
40
- * order/order.resource.ts → export default defineResource({ name: 'order', ... })
41
- * ```
42
- */
43
- /**
44
- * Resource interface — the contract between `loadResources`/`createApp` and resource definitions.
45
- *
46
- * Matches the shape of `ResourceDefinition` from `defineResource()` without requiring
47
- * the import. All properties except `toPlugin` are optional so plain objects work too:
48
- *
49
- * ```typescript
50
- * // Full resource (from defineResource)
51
- * const product = defineResource({ name: 'product', ... }); // satisfies ResourceLike
52
- *
53
- * // Minimal resource (plain object)
54
- * const simple: ResourceLike = { name: 'ping', toPlugin: () => () => {} };
55
- * ```
56
- *
57
- * **DO NOT add an index signature** (`[key: string]: unknown`) to this interface.
58
- * Class instances (like `ResourceDefinition`) don't implicitly carry index signatures,
59
- * so adding one here makes `ResourceDefinition` *unassignable* to `ResourceLike` —
60
- * the exact opposite of the intent. TypeScript's structural typing already allows
61
- * classes with extra properties to satisfy this interface without an index signature.
62
- */
63
- interface ResourceLike {
64
- /** Plugin factory — called by createApp to register routes */
65
- toPlugin: () => unknown;
66
- /** Resource name (used for route generation, logging, duplicate detection) */
67
- name?: string;
68
- /** Route prefix (default: `/${name}s`) */
69
- prefix?: string;
70
- /** Skip the global `resourcePrefix` from createApp — register at root */
71
- skipGlobalPrefix?: boolean;
72
- /** Display name for docs/OpenAPI */
73
- displayName?: string;
74
- /** Applied preset names */
75
- _appliedPresets?: string[];
76
- }
77
- /**
78
- * Resource module — what a `.resource.ts` file's default (or named) export
79
- * may resolve to.
80
- *
81
- * Two shapes accepted:
82
- * 1. **Plain `ResourceLike`** — the result of `defineResource({...})`.
83
- * Used as-is; no engine wiring needed.
84
- * 2. **Factory `(ctx: TContext) => ResourceLike | Promise<ResourceLike>`**
85
- * — a function arc calls with the `context` from `LoadResourcesOptions`.
86
- * Eliminates the parallel `createXResource(engine)` factory files +
87
- * `exclude: [...]` bookkeeping that engine-bound resources used to need.
88
- *
89
- * Detection is by `typeof === 'function'`: `ResourceDefinition` instances
90
- * (returned by `defineResource()`) are class instances (`typeof === 'object'`),
91
- * so the two shapes are unambiguous in practice.
92
- */
93
- type ResourceModule<TContext = unknown> = ResourceLike | ((ctx: TContext) => ResourceLike | Promise<ResourceLike>);
94
- interface LoadResourcesOptions<TContext = unknown> {
95
- /** File pattern suffix (default: '.resource'). Matches `*.resource.{ts,js,mts,mjs}`. */
96
- suffix?: string;
97
- /** Recurse into subdirectories (default: true) */
98
- recursive?: boolean;
99
- /**
100
- * Context passed to factory-style default exports. Resources whose default
101
- * export is a function `(ctx) => ResourceLike` are called with this value;
102
- * plain `ResourceLike` exports are returned unchanged.
103
- *
104
- * Use this to thread engine handles into engine-bound resources without
105
- * creating parallel factory files outside `loadResources`'s sweep:
106
- *
107
- * ```ts
108
- * // category.resource.ts
109
- * import type { AppContext } from '#core/app/context.js';
110
- * export default (ctx: AppContext) =>
111
- * defineResource({
112
- * name: 'category',
113
- * adapter: createMongooseAdapter(
114
- * ctx.catalog.models.Category,
115
- * ctx.catalog.repositories.category,
116
- * ),
117
- * });
118
- *
119
- * // create-arc-app-options.ts
120
- * resources: async () => {
121
- * const [catalog, flow] = await Promise.all([
122
- * ensureCatalogEngine(),
123
- * ensureFlowEngine(),
124
- * ]);
125
- * return loadResources(import.meta.url, { context: { catalog, flow } });
126
- * }
127
- * ```
128
- *
129
- * Backwards compatible — pre-2.11.1 callers omit `context`, plain exports
130
- * keep working unchanged. Factories that need a context but receive
131
- * `undefined` should narrow defensively.
132
- */
133
- context?: TContext;
134
- /**
135
- * Resource names to exclude. Matched against the resource's `.name` property
136
- * after import, so you use the resource name (not the filename).
137
- *
138
- * @example
139
- * ```ts
140
- * await loadResources('./src/resources', { exclude: ['debug', 'legacy-report'] })
141
- * ```
142
- */
143
- exclude?: string[];
144
- /**
145
- * Resource names to include. When set, only matching resources are returned.
146
- * Takes priority over `exclude`.
147
- *
148
- * @example
149
- * ```ts
150
- * // Only load these two resources (useful for testing or microservice splits)
151
- * await loadResources('./src/resources', { include: ['product', 'order'] })
152
- * ```
153
- */
154
- include?: string[];
155
- /**
156
- * Optional logger override for diagnostics. When omitted, warnings flow
157
- * through arc's standard logger (`arcLog('loadResources')`) — same path
158
- * as every other arc-internal warning, controlled by `ARC_SUPPRESS_WARNINGS=1`
159
- * and routable via `configureArcLogger({ writer })`.
160
- *
161
- * Pass any object with `warn(msg)` to override (e.g. `fastify.log` —
162
- * which is what `registerResources` passes automatically when arc's
163
- * factory triggers auto-discovery via `resourceDir`).
164
- *
165
- * Pre-2.11.1 had a `silent: boolean` flag and "silent by default" semantics;
166
- * both removed. Migration:
167
- *
168
- * ```ts
169
- * // Pre-2.11.1 // 2.11.1+
170
- * loadResources(url, { silent: true }); // ARC_SUPPRESS_WARNINGS=1 (env)
171
- * // OR configureArcLogger({ writer })
172
- * loadResources(url, { silent: !isDev }); // ARC_SUPPRESS_WARNINGS=1 in prod
173
- * loadResources(url, { logger: pinoAdapter }); // unchanged — still works
174
- * ```
175
- */
176
- logger?: {
177
- warn: (msg: string) => void;
178
- };
179
- }
180
- /**
181
- * Scan a directory for resource files and import their default exports.
182
- *
183
- * Accepts a directory path OR `import.meta.url` (file:// URL).
184
- * When given a URL, resolves to the directory containing that file —
185
- * so `loadResources(import.meta.url)` works in both dev (`src/`) and
186
- * production (`dist/`) without path gymnastics.
187
- *
188
- * @param dir - Directory path, or `import.meta.url` (file:// URL resolved to its dirname)
189
- * @param options - Pattern and recursion options
190
- * @returns Array of resource definitions (anything with `.toPlugin()`)
191
- *
192
- * @example
193
- * ```ts
194
- * // Works from both src/ and dist/ — resolves relative to the calling file
195
- * await loadResources(import.meta.url);
196
- *
197
- * // Subdirectory relative to the calling file
198
- * await loadResources(import.meta.url, { suffix: '.resource' });
199
- *
200
- * // Explicit path (must match runtime layout)
201
- * await loadResources('./src/resources');
202
- * ```
203
- */
204
- declare function loadResources<TContext = unknown>(dir: string, options?: LoadResourcesOptions<TContext>): Promise<ResourceLike[]>;
205
- //#endregion
206
14
  //#region src/testing/preloadResources.d.ts
207
15
  /** Eager glob result: `{ '/path/to/file.ts': resourceModule }` */
208
16
  type EagerGlobResult = Record<string, unknown>;
@@ -843,6 +651,56 @@ interface CreateAppOptions {
843
651
  * ```
844
652
  */
845
653
  serializeBigInt?: boolean | "number" | "string";
654
+ /**
655
+ * Domain modules — compose whole domains into the app, one entry each.
656
+ *
657
+ * Where a `resources` entry is a single route group, a module is a self-
658
+ * contained domain package's full contribution (engine init + resources +
659
+ * post-wiring) bundled as one `ArcModule`. A package exports
660
+ * `createXModule(deps): ArcModule`; the host lists it here instead of hand-
661
+ * threading the package's pieces across `bootstrap` / `resources` /
662
+ * `afterResources`.
663
+ *
664
+ * Modules are pure sugar over the existing lifecycle — each expands into the
665
+ * SAME phases, in `dependsOn` order, running BEFORE the app-level entry in
666
+ * every phase:
667
+ * ```
668
+ * app plugins() → modules[].plugins (infra registration)
669
+ * modules[].bootstrap → options.bootstrap
670
+ * modules[].resources → options.resources / resourceDir (see note ↓)
671
+ * modules[].afterResources → options.afterResources
672
+ * modules[].onClose (REVERSE order) → options.onClose (one hook; see below)
673
+ * ```
674
+ * RESOURCES — two orderings, both intentional: app `resources`/`resourceDir`
675
+ * RESOLVE first (semantics untouched), but module resources REGISTER first
676
+ * (prepended, so their routes mount ahead of app resources). Teardown runs
677
+ * module `onClose` (reverse composition order) then app `onClose` in a single
678
+ * close hook, so module teardown (flush outboxes, drain queues, close a
679
+ * module-owned connection) sees live shared infra — the app/plugin
680
+ * connections close last. Module resources flow through arc's normal
681
+ * registration (prefix, dedup, docs, audit) — they are not special-cased.
682
+ *
683
+ * Entries may be eager modules, promises, or **thunks of dynamic imports**
684
+ * (the `next/dynamic` idea, backend-shaped) — thunks resolve once at boot,
685
+ * so region/tier-gated packs are only imported when selected:
686
+ *
687
+ * @example
688
+ * ```ts
689
+ * const taxPack = region === 'BD'
690
+ * ? () => import('@classytic/bd-tax/module').then((m) => m.createBdTaxModule(deps))
691
+ * : () => import('@classytic/us-tax/module').then((m) => m.createUsTaxModule(deps));
692
+ *
693
+ * const app = await createApp({
694
+ * resourcePrefix: '/api/v1',
695
+ * modules: [accountingModule({ permissions }), taxPack],
696
+ * resources: [healthResource], // app-local resources still compose alongside
697
+ * });
698
+ * ```
699
+ *
700
+ * See `wiki/modules.md` for the full design (authoring convention, events/
701
+ * outbox integration, microservices path).
702
+ */
703
+ modules?: ReadonlyArray<ArcModuleInput>;
846
704
  /**
847
705
  * Resources to register automatically. Accepts two shapes:
848
706
  *
@@ -1064,4 +922,4 @@ interface RawBodyOptions {
1064
922
  runFirst?: boolean;
1065
923
  }
1066
924
  //#endregion
1067
- export { CustomPluginAuthOption as a, RawBodyOptions as c, preloadResourcesAsync as d, LoadResourcesOptions as f, loadResources as h, CustomAuthenticatorOption as i, UnderPressureOptions as l, ResourceModule as m, BetterAuthOption as n, JwtAuthOption as o, ResourceLike as p, CreateAppOptions as r, MultipartOptions as s, AuthOption as t, preloadResources as u };
925
+ export { CustomPluginAuthOption as a, RawBodyOptions as c, preloadResourcesAsync as d, CustomAuthenticatorOption as i, UnderPressureOptions as l, BetterAuthOption as n, JwtAuthOption as o, CreateAppOptions as r, MultipartOptions as s, AuthOption as t, preloadResources as u };
@@ -1,4 +1,4 @@
1
- import { V as ResourceDefinition } from "./index-CUTG2Cuo.mjs";
1
+ import { V as ResourceDefinition } from "./index-_--GyzcO.mjs";
2
2
  import { z } from "zod";
3
3
 
4
4
  //#region src/integrations/mcp/types.d.ts
@@ -1,4 +1,4 @@
1
- import { Qt as UserLike, S as QueryParserInterface, b as ParsedQuery, et as OpenApiSchemas, qt as AnyRecord, st as ResourceConfig } from "../index-CUTG2Cuo.mjs";
1
+ import { Qt as UserLike, S as QueryParserInterface, b as ParsedQuery, et as OpenApiSchemas, qt as AnyRecord, st as ResourceConfig } from "../index-_--GyzcO.mjs";
2
2
  import { n as ErrorMapper } from "../errorHandler-BtUUDPEa.mjs";
3
3
  import { a as NotFoundError, c as RateLimitError, d as ValidationError, f as createDomainError, i as ForbiddenError, l as ServiceUnavailableError, m as isArcError, n as ConflictError, o as OrgAccessDeniedError, p as createError, r as ErrorOptions, s as OrgRequiredError, t as ArcError, u as UnauthorizedError } from "../errors-DOHkjQlD.mjs";
4
4
  import { errorContractSchema, errorDetailSchema } from "@classytic/repo-core/errors";
@@ -1,5 +1,5 @@
1
1
  import { a as OrgAccessDeniedError, c as ServiceUnavailableError, d as createDomainError, f as createError, i as NotFoundError, l as UnauthorizedError, n as ConflictError, o as OrgRequiredError, p as isArcError, r as ForbiddenError, s as RateLimitError, t as ArcError, u as ValidationError } from "../errors-DkO8Nk6-.mjs";
2
- import { A as createQueryParser, C as keysetListResponse, D as queryParams, E as paginationSchema, M as scheduleBackground, N as simpleEqualityMatcher, O as responses, S as getListQueryParams, T as offsetListResponse, _ as bareListResponse, a as defineCompensation, b as errorDetailSchema, c as CircuitBreakerError, d as createCircuitBreaker, f as createCircuitBreakerRegistry, g as aggregateListResponse, h as validateResourceConfig, i as defineErrorMapper, j as getUserId, k as ArcQueryParser, l as CircuitBreakerRegistry, m as formatValidationErrors, n as handleRaw, o as withCompensation, p as assertValidConfig, r as defineGuard, s as CircuitBreaker, t as createStateMachine, u as CircuitState, v as deleteResponse, w as listResponse, x as getDefaultCrudSchemas, y as errorContractSchema } from "../utils-C6QQ9-hd.mjs";
2
+ import { A as assertValidConfig, C as withCompensation, D as CircuitState, E as CircuitBreakerRegistry, M as validateResourceConfig, N as simpleEqualityMatcher, O as createCircuitBreaker, S as defineCompensation, T as CircuitBreakerError, _ as ArcQueryParser, a as bareListResponse, b as defineGuard, c as errorDetailSchema, d as keysetListResponse, f as listResponse, g as responses, h as queryParams, i as aggregateListResponse, j as formatValidationErrors, k as createCircuitBreakerRegistry, l as getDefaultCrudSchemas, m as paginationSchema, n as createStateMachine, o as deleteResponse, p as offsetListResponse, r as scheduleBackground, s as errorContractSchema, t as getUserId, u as getListQueryParams, v as createQueryParser, w as CircuitBreaker, x as defineErrorMapper, y as handleRaw } from "../utils-ChjYQpjn.mjs";
3
3
  import { a as toJsonSchema, i as isZodSchema, n as convertRouteSchema, r as isJsonSchema, t as convertOpenApiSchemas } from "../schemaConverter-U0MnO9vd.mjs";
4
4
  import { a as promoteStreamTokenToHeader, i as pipeUIMessageStreamToReply, n as forwardedStreamHeaders, r as isReadableStream, t as UI_MESSAGE_STREAM_HEADERS } from "../streaming-BQcW6_Kq.mjs";
5
5
  import { t as hasEvents } from "../typeGuards-C9KXUly6.mjs";