@classytic/arc 2.4.2 → 2.6.1

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 (104) hide show
  1. package/README.md +22 -6
  2. package/dist/{BaseController-CkM5dUh_.mjs → BaseController-AbbRx3e0.mjs} +5 -2
  3. package/dist/adapters/index.d.mts +2 -2
  4. package/dist/adapters/index.mjs +1 -1
  5. package/dist/{adapters-DTC4Ug66.mjs → adapters-CTn28N4y.mjs} +72 -11
  6. package/dist/audit/index.d.mts +1 -1
  7. package/dist/audit/index.mjs +11 -1
  8. package/dist/audit/mongodb.d.mts +1 -1
  9. package/dist/auth/index.d.mts +1 -1
  10. package/dist/auth/index.mjs +2 -2
  11. package/dist/cache/index.mjs +2 -2
  12. package/dist/cli/commands/describe.d.mts +1 -1
  13. package/dist/cli/commands/describe.mjs +1 -1
  14. package/dist/cli/commands/generate.d.mts +1 -1
  15. package/dist/cli/commands/generate.mjs +1 -1
  16. package/dist/cli/commands/init.d.mts +1 -1
  17. package/dist/cli/commands/init.mjs +13 -10
  18. package/dist/cli/commands/introspect.d.mts +1 -1
  19. package/dist/cli/commands/introspect.mjs +1 -1
  20. package/dist/cli/index.d.mts +4 -4
  21. package/dist/cli/index.mjs +4 -4
  22. package/dist/core/index.d.mts +2 -2
  23. package/dist/core/index.mjs +2 -2
  24. package/dist/{createApp-ByWNRsZj.mjs → createApp-Bol7DLUf.mjs} +404 -279
  25. package/dist/{defineResource-D9aY5Cy6.mjs → defineResource-bVKHjQzE.mjs} +116 -19
  26. package/dist/discovery/index.d.mts +1 -1
  27. package/dist/discovery/index.mjs +2 -2
  28. package/dist/docs/index.d.mts +1 -1
  29. package/dist/dynamic/index.d.mts +1 -1
  30. package/dist/dynamic/index.mjs +2 -2
  31. package/dist/{elevation-Ca_yveIO.d.mts → elevation-C_taLQrM.d.mts} +27 -1
  32. package/dist/{errorHandler--zp54tGc.mjs → errorHandler-r2595m8T.mjs} +5 -5
  33. package/dist/{errors-CPpvPHT0.d.mts → errors-CcVbl1-T.d.mts} +17 -1
  34. package/dist/{errors-rxhfP7Hf.mjs → errors-NoQKsbAT.mjs} +23 -1
  35. package/dist/{eventPlugin-iGrSEmwJ.d.mts → eventPlugin-DW45v4V5.d.mts} +30 -2
  36. package/dist/events/index.d.mts +2 -2
  37. package/dist/events/index.mjs +40 -10
  38. package/dist/events/transports/redis.d.mts +1 -1
  39. package/dist/events/transports/redis.mjs +1 -1
  40. package/dist/factory/index.d.mts +44 -23
  41. package/dist/factory/index.mjs +136 -2
  42. package/dist/hooks/index.d.mts +1 -1
  43. package/dist/idempotency/index.d.mts +3 -3
  44. package/dist/idempotency/mongodb.d.mts +1 -1
  45. package/dist/idempotency/redis.d.mts +1 -1
  46. package/dist/{index-yhxyjqNb.d.mts → index-BIsZ_su5.d.mts} +4 -8
  47. package/dist/{index-BL8CaQih.d.mts → index-Cb3gtbg7.d.mts} +2 -2
  48. package/dist/{index-Diqcm14c.d.mts → index-NGZksqM5.d.mts} +30 -1
  49. package/dist/index.d.mts +6 -6
  50. package/dist/index.mjs +8 -7
  51. package/dist/integrations/event-gateway.d.mts +1 -1
  52. package/dist/integrations/event-gateway.mjs +2 -2
  53. package/dist/integrations/index.d.mts +1 -1
  54. package/dist/integrations/jobs.d.mts +1 -1
  55. package/dist/integrations/jobs.mjs +1 -1
  56. package/dist/integrations/mcp/index.d.mts +4 -2
  57. package/dist/integrations/mcp/index.mjs +1 -1
  58. package/dist/integrations/mcp/testing.d.mts +1 -1
  59. package/dist/integrations/mcp/testing.mjs +1 -1
  60. package/dist/integrations/streamline.d.mts +1 -1
  61. package/dist/integrations/streamline.mjs +1 -1
  62. package/dist/integrations/websocket-redis.d.mts +1 -1
  63. package/dist/integrations/websocket-redis.mjs +1 -1
  64. package/dist/integrations/websocket.d.mts +1 -1
  65. package/dist/integrations/websocket.mjs +1 -1
  66. package/dist/{interface-DGmPxakH.d.mts → interface-DDW43OmS.d.mts} +194 -13
  67. package/dist/{memory-Cb_7iy9e.mjs → memory-BFAYkf8H.mjs} +1 -4
  68. package/dist/{mongodb-CUpYfxfD.d.mts → mongodb-kltrBPa1.d.mts} +10 -0
  69. package/dist/{mongodb-bga9AbkD.d.mts → mongodb-pMvOlR5_.d.mts} +1 -1
  70. package/dist/org/index.d.mts +1 -1
  71. package/dist/org/index.mjs +1 -1
  72. package/dist/permissions/index.d.mts +2 -2
  73. package/dist/permissions/index.mjs +2 -2
  74. package/dist/{permissions-CA5zg0yK.mjs → permissions-C8ImI8gC.mjs} +45 -3
  75. package/dist/plugins/index.d.mts +1 -1
  76. package/dist/plugins/index.mjs +3 -3
  77. package/dist/plugins/response-cache.d.mts +1 -1
  78. package/dist/plugins/response-cache.mjs +1 -1
  79. package/dist/plugins/tracing-entry.mjs +1 -1
  80. package/dist/presets/index.d.mts +2 -2
  81. package/dist/presets/index.mjs +2 -2
  82. package/dist/presets/multiTenant.d.mts +2 -2
  83. package/dist/presets/multiTenant.mjs +2 -2
  84. package/dist/{presets-C9QXJV1u.mjs → presets-BMfdy34e.mjs} +3 -3
  85. package/dist/{queryCachePlugin-ClosZdNS.mjs → queryCachePlugin-XtFplYO9.mjs} +1 -1
  86. package/dist/{redis-CQ5YxMC5.d.mts → redis-D0Qc-9EW.d.mts} +1 -1
  87. package/dist/registry/index.d.mts +1 -1
  88. package/dist/{resourceToTools-PMFE8HIv.mjs → resourceToTools-DH3c3e-T.mjs} +81 -7
  89. package/dist/scope/index.d.mts +2 -2
  90. package/dist/scope/index.mjs +2 -2
  91. package/dist/{sse-BkViJPlT.mjs → sse-BF7GR7IB.mjs} +1 -1
  92. package/dist/testing/index.d.mts +2 -2
  93. package/dist/testing/index.mjs +1 -1
  94. package/dist/types/index.d.mts +3 -3
  95. package/dist/types/index.mjs +23 -2
  96. package/dist/{types-C6TQjtdi.mjs → types-BhtYdxZU.mjs} +26 -1
  97. package/dist/{types-Dt0-AI6E.d.mts → types-D5hJ-k_3.d.mts} +189 -6
  98. package/dist/{types-BJmgxNbF.d.mts → types-D5rjsS_i.d.mts} +1 -1
  99. package/dist/utils/index.d.mts +2 -2
  100. package/dist/utils/index.mjs +1 -1
  101. package/package.json +7 -5
  102. package/skills/arc/SKILL.md +115 -8
  103. package/skills/arc/references/mcp.md +160 -2
  104. /package/dist/{interface-B4awm1RJ.d.mts → interface-gr-7qo9j.d.mts} +0 -0
package/README.md CHANGED
@@ -15,26 +15,42 @@ npm install @classytic/mongokit mongoose # MongoDB adapter
15
15
 
16
16
  ```typescript
17
17
  import mongoose from 'mongoose';
18
- import { createApp } from '@classytic/arc/factory';
18
+ import { createApp, loadResources } from '@classytic/arc/factory';
19
19
 
20
20
  await mongoose.connect(process.env.DB_URI);
21
21
 
22
22
  const app = await createApp({
23
23
  preset: 'production',
24
+ resourcePrefix: '/api/v1',
25
+ resources: await loadResources(import.meta.url), // auto-discovers *.resource.ts
24
26
  auth: { type: 'jwt', jwt: { secret: process.env.JWT_SECRET } },
25
27
  cors: { origin: process.env.ALLOWED_ORIGINS?.split(',') },
26
28
  });
27
29
 
28
- await app.register(productResource.toPlugin());
29
30
  await app.listen({ port: 8040, host: '0.0.0.0' });
30
31
  ```
31
32
 
33
+ Three ways to register resources:
34
+
35
+ ```typescript
36
+ // Auto-discover from directory (recommended)
37
+ resources: await loadResources('./src/resources'),
38
+
39
+ // Explicit array
40
+ resources: [productResource, orderResource],
41
+
42
+ // Via plugins callback (full Fastify control)
43
+ plugins: async (f) => { await f.register(productResource.toPlugin()); },
44
+ ```
45
+
46
+ > **Note:** `loadResources()` works with standard relative imports and Node.js `#` subpath imports (`package.json` `imports` field). It does **not** support tsconfig path aliases (`@/*`, `~/`) — use explicit `resources: [...]` instead.
47
+
32
48
  ## defineResource
33
49
 
34
50
  Single API for a full REST resource with routes, permissions, and behaviors:
35
51
 
36
52
  ```typescript
37
- import { defineResource, createMongooseAdapter, allowPublic, requireRoles } from '@classytic/arc';
53
+ import { defineResource, createMongooseAdapter, allowPublic, roles } from '@classytic/arc';
38
54
 
39
55
  const productResource = defineResource({
40
56
  name: 'product',
@@ -43,9 +59,9 @@ const productResource = defineResource({
43
59
  permissions: {
44
60
  list: allowPublic(),
45
61
  get: allowPublic(),
46
- create: requireRoles(['admin']),
47
- update: requireRoles(['admin']),
48
- delete: requireRoles(['admin']),
62
+ create: roles('admin', 'editor'), // checks platform + org roles
63
+ update: roles('admin', 'editor'),
64
+ delete: roles('admin'),
49
65
  },
50
66
  cache: { staleTime: 30, gcTime: 300, tags: ['catalog'] }, // QueryCache (opt-in)
51
67
  additionalRoutes: [
@@ -1,5 +1,5 @@
1
1
  import { h as SYSTEM_FIELDS, o as DEFAULT_TENANT_FIELD } from "./constants-Cxde4rpC.mjs";
2
- import { d as isMember, n as PUBLIC_SCOPE, r as getOrgId, u as isElevated } from "./types-C6TQjtdi.mjs";
2
+ import { d as isElevated, f as isMember, i as getOrgId, n as PUBLIC_SCOPE } from "./types-BhtYdxZU.mjs";
3
3
  import { t as buildQueryKey } from "./keys-qcD-TVJl.mjs";
4
4
  import { getUserId } from "./types/index.mjs";
5
5
  import { i as resolveEffectiveRoles, n as applyFieldWritePermissions } from "./fields-ipsbIRPK.mjs";
@@ -247,7 +247,10 @@ var BodySanitizer = class {
247
247
  let sanitized = { ...body };
248
248
  for (const field of SYSTEM_FIELDS) delete sanitized[field];
249
249
  const fieldRules = this.schemaOptions.fieldRules ?? {};
250
- for (const [field, rules] of Object.entries(fieldRules)) if (rules.systemManaged || rules.readonly) delete sanitized[field];
250
+ for (const [field, rules] of Object.entries(fieldRules)) {
251
+ if (rules.systemManaged || rules.readonly) delete sanitized[field];
252
+ if (_operation === "update" && (rules.immutable || rules.immutableAfterCreate)) delete sanitized[field];
253
+ }
251
254
  if (req) {
252
255
  const arcContext = meta ?? req.metadata;
253
256
  const scope = arcContext?._scope ?? PUBLIC_SCOPE;
@@ -1,3 +1,3 @@
1
- import { a as RepositoryLike, i as RelationMetadata, n as DataAdapter, o as SchemaMetadata, r as FieldMetadata, s as ValidationResult, t as AdapterFactory } from "../interface-DGmPxakH.mjs";
2
- import { a as PrismaQueryParserOptions, c as MongooseAdapterOptions, i as PrismaQueryParser, l as createMongooseAdapter, n as PrismaAdapterOptions, o as createPrismaAdapter, r as PrismaQueryOptions, s as MongooseAdapter, t as PrismaAdapter } from "../index-yhxyjqNb.mjs";
1
+ import { a as RepositoryLike, i as RelationMetadata, n as DataAdapter, o as SchemaMetadata, r as FieldMetadata, s as ValidationResult, t as AdapterFactory } from "../interface-DDW43OmS.mjs";
2
+ import { a as PrismaQueryParserOptions, c as MongooseAdapterOptions, i as PrismaQueryParser, l as createMongooseAdapter, n as PrismaAdapterOptions, o as createPrismaAdapter, r as PrismaQueryOptions, s as MongooseAdapter, t as PrismaAdapter } from "../index-BIsZ_su5.mjs";
3
3
  export { AdapterFactory, DataAdapter, FieldMetadata, MongooseAdapter, MongooseAdapterOptions, PrismaAdapter, PrismaAdapterOptions, PrismaQueryOptions, PrismaQueryParser, PrismaQueryParserOptions, RelationMetadata, RepositoryLike, SchemaMetadata, ValidationResult, createMongooseAdapter, createPrismaAdapter };
@@ -1,2 +1,2 @@
1
- import { a as createMongooseAdapter, i as MongooseAdapter, n as PrismaQueryParser, r as createPrismaAdapter, t as PrismaAdapter } from "../adapters-DTC4Ug66.mjs";
1
+ import { a as createMongooseAdapter, i as MongooseAdapter, n as PrismaQueryParser, r as createPrismaAdapter, t as PrismaAdapter } from "../adapters-CTn28N4y.mjs";
2
2
  export { MongooseAdapter, PrismaAdapter, PrismaQueryParser, createMongooseAdapter, createPrismaAdapter };
@@ -78,17 +78,28 @@ var MongooseAdapter = class {
78
78
  const properties = {};
79
79
  const required = [];
80
80
  const fieldRules = schemaOptions?.fieldRules || {};
81
- const blockedFields = new Set(Object.entries(fieldRules).filter(([, rules]) => rules.systemManaged || rules.hidden).map(([field]) => field));
81
+ const blockedFields = new Set([
82
+ ...Object.entries(fieldRules).filter(([, rules]) => rules.systemManaged || rules.hidden).map(([field]) => field),
83
+ ...schemaOptions?.excludeFields ?? [],
84
+ ...schemaOptions?.hiddenFields ?? []
85
+ ]);
86
+ const readonlySet = new Set(schemaOptions?.readonlyFields ?? []);
87
+ const optionalSet = new Set(schemaOptions?.optionalFields ?? []);
82
88
  for (const [fieldName, schemaType] of Object.entries(paths)) {
83
89
  if (fieldName.startsWith("__")) continue;
84
90
  if (blockedFields.has(fieldName)) continue;
85
91
  const typeInfo = schemaType;
86
92
  properties[fieldName] = this.mongooseTypeToOpenApi(typeInfo);
87
- if (typeInfo.isRequired) required.push(fieldName);
93
+ if (typeInfo.isRequired && !optionalSet.has(fieldName) && !fieldRules[fieldName]?.optional) required.push(fieldName);
88
94
  }
89
- const systemFieldSet = new Set(SYSTEM_FIELDS);
90
- const inputProperties = Object.fromEntries(Object.entries(properties).filter(([field]) => !systemFieldSet.has(field)));
91
- const inputRequired = required.filter((field) => !systemFieldSet.has(field));
95
+ const readonlyForInput = new Set([...readonlySet]);
96
+ for (const [field, rules] of Object.entries(fieldRules)) if (rules.immutable || rules.immutableAfterCreate) readonlyForInput.add(field);
97
+ const inputBlockedSet = new Set([...SYSTEM_FIELDS, ...readonlyForInput]);
98
+ const inputProperties = Object.fromEntries(Object.entries(properties).filter(([field]) => !inputBlockedSet.has(field)));
99
+ const inputRequired = required.filter((field) => !inputBlockedSet.has(field) && !blockedFields.has(field));
100
+ const immutableSet = /* @__PURE__ */ new Set();
101
+ for (const [field, rules] of Object.entries(fieldRules)) if (rules.immutable || rules.immutableAfterCreate) immutableSet.add(field);
102
+ const updateProperties = Object.fromEntries(Object.entries(inputProperties).filter(([field]) => !immutableSet.has(field)));
92
103
  return {
93
104
  createBody: {
94
105
  type: "object",
@@ -97,11 +108,12 @@ var MongooseAdapter = class {
97
108
  },
98
109
  updateBody: {
99
110
  type: "object",
100
- properties: inputProperties
111
+ properties: updateProperties
101
112
  },
102
113
  response: {
103
114
  type: "object",
104
- properties
115
+ properties,
116
+ additionalProperties: true
105
117
  }
106
118
  };
107
119
  } catch {
@@ -147,18 +159,67 @@ var MongooseAdapter = class {
147
159
  break;
148
160
  case "Date":
149
161
  baseType.type = "string";
150
- baseType.format = "date-time";
151
162
  break;
152
163
  case "ObjectID":
153
164
  case "ObjectId":
154
165
  baseType.type = "string";
155
166
  baseType.pattern = "^[a-f\\d]{24}$";
156
167
  break;
157
- case "Array":
168
+ case "Array": {
158
169
  baseType.type = "array";
159
- baseType.items = { type: "string" };
170
+ const ti = typeInfo;
171
+ if (ti.$isMongooseDocumentArray && ti.schema) {
172
+ const subSchema = ti.schema;
173
+ const subProps = {};
174
+ const subRequired = [];
175
+ for (const [subField, subType] of Object.entries(subSchema.paths)) {
176
+ if (subField.startsWith("_")) continue;
177
+ subProps[subField] = this.mongooseTypeToOpenApi(subType);
178
+ if (subType.isRequired) subRequired.push(subField);
179
+ }
180
+ baseType.items = {
181
+ type: "object",
182
+ properties: subProps,
183
+ ...subRequired.length > 0 ? { required: subRequired } : {},
184
+ additionalProperties: true
185
+ };
186
+ } else if (ti.embeddedSchemaType?.instance) baseType.items = this.mongooseTypeToOpenApi(ti.embeddedSchemaType);
187
+ else baseType.items = {};
188
+ break;
189
+ }
190
+ case "Mixed":
191
+ baseType.type = [
192
+ "string",
193
+ "number",
194
+ "boolean",
195
+ "object",
196
+ "array"
197
+ ];
198
+ break;
199
+ case "Map":
200
+ baseType.type = "object";
201
+ baseType.additionalProperties = true;
202
+ break;
203
+ case "Embedded":
204
+ case "SubDocument":
205
+ baseType.type = "object";
206
+ baseType.additionalProperties = true;
207
+ break;
208
+ case "Buffer":
209
+ baseType.type = "string";
210
+ baseType.format = "binary";
211
+ break;
212
+ case "Decimal128":
213
+ baseType.type = "string";
214
+ baseType.description = "Decimal128 (high-precision number as string)";
215
+ break;
216
+ case "UUID":
217
+ baseType.type = "string";
218
+ baseType.format = "uuid";
160
219
  break;
161
- default: baseType.type = "object";
220
+ default:
221
+ baseType.type = "object";
222
+ baseType.additionalProperties = true;
162
223
  }
163
224
  return baseType;
164
225
  }
@@ -1,4 +1,4 @@
1
- import { a as AuditContext, c as AuditStore, i as AuditAction, l as AuditStoreOptions, n as MongoAuditStoreOptions, o as AuditEntry, r as MongoConnection, s as AuditQueryOptions, u as createAuditEntry } from "../mongodb-CUpYfxfD.mjs";
1
+ import { a as AuditContext, c as AuditStore, i as AuditAction, l as AuditStoreOptions, n as MongoAuditStoreOptions, o as AuditEntry, r as MongoConnection, s as AuditQueryOptions, u as createAuditEntry } from "../mongodb-kltrBPa1.mjs";
2
2
  import { FastifyPluginAsync } from "fastify";
3
3
 
4
4
  //#region src/audit/auditPlugin.d.ts
@@ -11,7 +11,7 @@ function createAuditEntry(resource, documentId, action, context, data) {
11
11
  resource,
12
12
  documentId,
13
13
  action,
14
- userId: context.user?._id?.toString() ?? context.user?.id,
14
+ userId: extractUserId(context.user),
15
15
  organizationId: context.organizationId,
16
16
  before: data?.before,
17
17
  after: data?.after,
@@ -24,6 +24,16 @@ function createAuditEntry(resource, documentId, action, context, data) {
24
24
  };
25
25
  }
26
26
  /**
27
+ * Extract userId from a user object — DB-agnostic.
28
+ * Handles Mongoose ObjectId, string, number, or any type with toString().
29
+ */
30
+ function extractUserId(user) {
31
+ if (!user) return void 0;
32
+ const raw = user._id ?? user.id;
33
+ if (raw == null) return void 0;
34
+ return typeof raw === "string" ? raw : String(raw);
35
+ }
36
+ /**
27
37
  * Detect changed fields between two objects
28
38
  */
29
39
  function detectChanges(before, after) {
@@ -1,2 +1,2 @@
1
- import { n as MongoAuditStoreOptions, t as MongoAuditStore } from "../mongodb-CUpYfxfD.mjs";
1
+ import { n as MongoAuditStoreOptions, t as MongoAuditStore } from "../mongodb-kltrBPa1.mjs";
2
2
  export { MongoAuditStore, type MongoAuditStoreOptions };
@@ -1,4 +1,4 @@
1
- import { m as AuthPluginOptions, p as AuthHelpers } from "../interface-DGmPxakH.mjs";
1
+ import { h as AuthPluginOptions, m as AuthHelpers } from "../interface-DDW43OmS.mjs";
2
2
  import { t as PermissionCheck } from "../types-BNUccdcf.mjs";
3
3
  import { t as ExternalOpenApiPaths } from "../externalPaths-DpO-s7r8.mjs";
4
4
  import { a as SessionManagerOptions, c as createSessionManager, i as SessionData, n as MemorySessionStoreOptions, o as SessionManagerResult, r as SessionCookieOptions, s as SessionStore, t as MemorySessionStore } from "../sessionManager-wbkYj2HL.mjs";
@@ -1,6 +1,6 @@
1
1
  import { n as normalizeRoles, t as getUserRoles } from "../types-ZUu_h0jp.mjs";
2
- import { t as ArcError } from "../errors-rxhfP7Hf.mjs";
3
- import { c as requireOrgMembership, f as requireTeamMembership, l as requireOrgRole } from "../permissions-CA5zg0yK.mjs";
2
+ import { t as ArcError } from "../errors-NoQKsbAT.mjs";
3
+ import { c as requireOrgMembership, f as requireTeamMembership, l as requireOrgRole } from "../permissions-C8ImI8gC.mjs";
4
4
  import { n as extractBetterAuthOpenApi } from "../betterAuthOpenApi-lz0IRbXJ.mjs";
5
5
  import { createHmac, randomUUID, timingSafeEqual } from "node:crypto";
6
6
  import fp from "fastify-plugin";
@@ -1,6 +1,6 @@
1
1
  import { i as versionKey, n as hashParams, r as tagVersionKey, t as buildQueryKey } from "../keys-qcD-TVJl.mjs";
2
- import { t as MemoryCacheStore } from "../memory-Cb_7iy9e.mjs";
3
- import { r as QueryCache, t as queryCachePlugin } from "../queryCachePlugin-ClosZdNS.mjs";
2
+ import { t as MemoryCacheStore } from "../memory-BFAYkf8H.mjs";
3
+ import { r as QueryCache, t as queryCachePlugin } from "../queryCachePlugin-XtFplYO9.mjs";
4
4
  //#region src/cache/redis.ts
5
5
  /**
6
6
  * Redis-backed cache store.
@@ -15,4 +15,4 @@
15
15
  */
16
16
  declare function describe(args: string[]): Promise<void>;
17
17
  //#endregion
18
- export { describe as default, describe };
18
+ export { describe };
@@ -252,4 +252,4 @@ async function describe(args) {
252
252
  }
253
253
  }
254
254
  //#endregion
255
- export { describe as default, describe };
255
+ export { describe };
@@ -19,4 +19,4 @@
19
19
  */
20
20
  declare function generate(type: string | undefined, args: string[]): Promise<void>;
21
21
  //#endregion
22
- export { generate as default, generate };
22
+ export { generate };
@@ -435,4 +435,4 @@ async function generateFile(name, lowerName, resourcePath, fileType, template, e
435
435
  console.log(` + Created: ${filename}`);
436
436
  }
437
437
  //#endregion
438
- export { generate as default, generate };
438
+ export { generate };
@@ -24,4 +24,4 @@ interface InitOptions {
24
24
  */
25
25
  declare function init(options?: InitOptions): Promise<void>;
26
26
  //#endregion
27
- export { InitOptions, init as default, init };
27
+ export { InitOptions, init };
@@ -1,7 +1,7 @@
1
+ import * as fs from "node:fs/promises";
1
2
  import * as path from "node:path";
2
3
  import { accessSync } from "node:fs";
3
4
  import { execSync, spawn } from "node:child_process";
4
- import * as fs from "node:fs/promises";
5
5
  import * as readline from "node:readline";
6
6
  //#region src/cli/commands/init.ts
7
7
  /**
@@ -694,13 +694,13 @@ import { getAuth } from './auth.js';
694
694
  */
695
695
 
696
696
  ${typeImport}import config from '#config/index.js';
697
- import { createApp } from '@classytic/arc/factory';
697
+ import { createApp, loadResources } from '@classytic/arc/factory';
698
698
  ${betterAuthImport}
699
699
  // App-specific plugins
700
700
  import { registerPlugins } from '#plugins/index.js';
701
701
 
702
702
  // Resource registry
703
- import { registerResources } from '#resources/index.js';
703
+ import { resources, registerResources } from '#resources/index.js';
704
704
 
705
705
  /**
706
706
  * Create a fully configured app instance
@@ -708,9 +708,10 @@ import { registerResources } from '#resources/index.js';
708
708
  * @returns Configured Fastify instance ready to use
709
709
  */
710
710
  export async function createAppInstance()${ts ? ": Promise<FastifyInstance>" : ""} {
711
- // Create Arc app with base configuration
711
+ // Create Arc app with resources and base configuration
712
712
  const app = await createApp({
713
713
  preset: config.env === 'production' ? (${config.edge ? "'edge'" : "'production'"}) : 'development',
714
+ resources,
714
715
  ${authConfig}
715
716
  cors: {
716
717
  origin: config.cors.origins,
@@ -727,9 +728,6 @@ export async function createAppInstance()${ts ? ": Promise<FastifyInstance>" : "
727
728
  // Register app-specific plugins (explicit dependency injection)
728
729
  await registerPlugins(app, { config });
729
730
 
730
- // Register all resources
731
- await registerResources(app);
732
-
733
731
  return app;
734
732
  }
735
733
 
@@ -1275,6 +1273,7 @@ import {
1275
1273
  requireRoles,
1276
1274
  requireOwnership,
1277
1275
  allowPublic,
1276
+ roles,
1278
1277
  anyOf,
1279
1278
  allOf,
1280
1279
  denyAll,
@@ -1287,6 +1286,7 @@ export {
1287
1286
  requireAuth,
1288
1287
  requireRoles,
1289
1288
  requireOwnership,
1289
+ roles,
1290
1290
  allOf,
1291
1291
  anyOf,
1292
1292
  denyAll,
@@ -1323,11 +1323,14 @@ export const requireSuperadmin = ()${returnType} =>
1323
1323
  /**
1324
1324
  * Organization-level guards (per-org member.role):
1325
1325
  *
1326
- * - requireOrgRole(['admin','owner']) — checks member.role in active org
1326
+ * - roles('admin') — checks BOTH user.role AND org member.role (recommended)
1327
+ * - requireOrgRole(['admin','owner']) — checks member.role in active org ONLY
1327
1328
  * - requireOrgMembership() — just checks if user is in the org (any role)
1328
1329
  * - requireTeamMembership() — checks if user is in the active team
1329
1330
  *
1330
- * These are DIFFERENT from platform-level helpers above (requireRoles checks user.role).
1331
+ * RECOMMENDED: Use roles() for most cases it checks platform + org roles automatically.
1332
+ * Use requireOrgRole() when you ONLY want org-level checks (exclude platform admins).
1333
+ *
1331
1334
  * Platform superadmin automatically bypasses all org role checks.
1332
1335
  *
1333
1336
  * IMPORTANT: When using Better Auth's Access Control (ac) with custom roles,
@@ -2889,4 +2892,4 @@ ${dbConfig}
2889
2892
  `;
2890
2893
  }
2891
2894
  //#endregion
2892
- export { init as default, init };
2895
+ export { init };
@@ -7,4 +7,4 @@
7
7
  */
8
8
  declare function introspect(args: string[]): Promise<void>;
9
9
  //#endregion
10
- export { introspect as default, introspect };
10
+ export { introspect };
@@ -70,4 +70,4 @@ async function introspect(args) {
70
70
  }
71
71
  }
72
72
  //#endregion
73
- export { introspect as default, introspect };
73
+ export { introspect };
@@ -1,7 +1,7 @@
1
- import describe from "./commands/describe.mjs";
1
+ import { describe } from "./commands/describe.mjs";
2
2
  import { exportDocs } from "./commands/docs.mjs";
3
3
  import { doctor } from "./commands/doctor.mjs";
4
- import generate from "./commands/generate.mjs";
5
- import init from "./commands/init.mjs";
6
- import introspect from "./commands/introspect.mjs";
4
+ import { generate } from "./commands/generate.mjs";
5
+ import { init } from "./commands/init.mjs";
6
+ import { introspect } from "./commands/introspect.mjs";
7
7
  export { describe, doctor, exportDocs, generate, init, introspect };
@@ -1,7 +1,7 @@
1
- import describe from "./commands/describe.mjs";
1
+ import { describe } from "./commands/describe.mjs";
2
2
  import { exportDocs } from "./commands/docs.mjs";
3
3
  import { doctor } from "./commands/doctor.mjs";
4
- import generate from "./commands/generate.mjs";
5
- import init from "./commands/init.mjs";
6
- import introspect from "./commands/introspect.mjs";
4
+ import { generate } from "./commands/generate.mjs";
5
+ import { init } from "./commands/init.mjs";
6
+ import { introspect } from "./commands/introspect.mjs";
7
7
  export { describe, doctor, exportDocs, generate, init, introspect };
@@ -1,3 +1,3 @@
1
- import { Ct as QueryResolverConfig, Dt as AccessControlConfig, Et as AccessControl, Lt as ResourceDefinition, Rt as defineResource, St as QueryResolver, Tt as BodySanitizerConfig, bt as BaseController, wt as BodySanitizer, xt as BaseControllerOptions } from "../interface-DGmPxakH.mjs";
2
- import { A as RESERVED_QUERY_PARAMS, C as HookOperation, D as MAX_SEARCH_LENGTH, E as MAX_REGEX_LENGTH, O as MUTATION_OPERATIONS, S as HOOK_PHASES, T as MAX_FILTER_DEPTH, _ as DEFAULT_MAX_LIMIT, a as getControllerScope, b as DEFAULT_UPDATE_METHOD, c as createPermissionMiddleware, d as IdempotencyService, f as createActionRouter, g as DEFAULT_LIMIT, h as DEFAULT_ID_FIELD, i as getControllerContext, j as SYSTEM_FIELDS, k as MutationOperation, l as ActionHandler, m as CrudOperation, n as createFastifyHandler, o as sendControllerResponse, p as CRUD_OPERATIONS, r as createRequestContext, s as createCrudRouter, t as createCrudHandlers, u as ActionRouterConfig, v as DEFAULT_SORT, w as HookPhase, x as HOOK_OPERATIONS, y as DEFAULT_TENANT_FIELD } from "../index-BL8CaQih.mjs";
1
+ import { At as AccessControlConfig, Bt as ResourceDefinition, Ct as BaseController, Dt as BodySanitizer, Et as QueryResolverConfig, Ot as BodySanitizerConfig, Tt as QueryResolver, Vt as defineResource, kt as AccessControl, wt as BaseControllerOptions } from "../interface-DDW43OmS.mjs";
2
+ import { A as RESERVED_QUERY_PARAMS, C as HookOperation, D as MAX_SEARCH_LENGTH, E as MAX_REGEX_LENGTH, O as MUTATION_OPERATIONS, S as HOOK_PHASES, T as MAX_FILTER_DEPTH, _ as DEFAULT_MAX_LIMIT, a as getControllerScope, b as DEFAULT_UPDATE_METHOD, c as createPermissionMiddleware, d as IdempotencyService, f as createActionRouter, g as DEFAULT_LIMIT, h as DEFAULT_ID_FIELD, i as getControllerContext, j as SYSTEM_FIELDS, k as MutationOperation, l as ActionHandler, m as CrudOperation, n as createFastifyHandler, o as sendControllerResponse, p as CRUD_OPERATIONS, r as createRequestContext, s as createCrudRouter, t as createCrudHandlers, u as ActionRouterConfig, v as DEFAULT_SORT, w as HookPhase, x as HOOK_OPERATIONS, y as DEFAULT_TENANT_FIELD } from "../index-Cb3gtbg7.mjs";
3
3
  export { AccessControl, AccessControlConfig, ActionHandler, ActionRouterConfig, BaseController, BaseControllerOptions, BodySanitizer, BodySanitizerConfig, CRUD_OPERATIONS, CrudOperation, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, HOOK_OPERATIONS, HOOK_PHASES, HookOperation, HookPhase, IdempotencyService, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, MutationOperation, QueryResolver, QueryResolverConfig, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, createActionRouter, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineResource, getControllerContext, getControllerScope, sendControllerResponse };
@@ -1,5 +1,5 @@
1
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-Cxde4rpC.mjs";
2
- import { i as AccessControl, n as QueryResolver, r as BodySanitizer, t as BaseController } from "../BaseController-CkM5dUh_.mjs";
2
+ import { i as AccessControl, n as QueryResolver, r as BodySanitizer, t as BaseController } from "../BaseController-AbbRx3e0.mjs";
3
3
  import { t as createActionRouter } from "../core-C1XCMtqM.mjs";
4
- import { c as createCrudHandlers, d as getControllerContext, f as getControllerScope, l as createFastifyHandler, n as defineResource, o as createCrudRouter, p as sendControllerResponse, s as createPermissionMiddleware, t as ResourceDefinition, u as createRequestContext } from "../defineResource-D9aY5Cy6.mjs";
4
+ import { c as createCrudHandlers, d as getControllerContext, f as getControllerScope, l as createFastifyHandler, n as defineResource, o as createCrudRouter, p as sendControllerResponse, s as createPermissionMiddleware, t as ResourceDefinition, u as createRequestContext } from "../defineResource-bVKHjQzE.mjs";
5
5
  export { AccessControl, BaseController, BodySanitizer, CRUD_OPERATIONS, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, HOOK_OPERATIONS, HOOK_PHASES, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, QueryResolver, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, createActionRouter, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineResource, getControllerContext, getControllerScope, sendControllerResponse };