@classytic/arc 2.4.3 → 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.
- package/README.md +22 -6
- package/dist/{BaseController-CkM5dUh_.mjs → BaseController-AbbRx3e0.mjs} +5 -2
- package/dist/adapters/index.d.mts +2 -2
- package/dist/adapters/index.mjs +1 -1
- package/dist/{adapters-DTC4Ug66.mjs → adapters-CTn28N4y.mjs} +72 -11
- package/dist/audit/index.d.mts +1 -1
- package/dist/audit/index.mjs +11 -1
- package/dist/audit/mongodb.d.mts +1 -1
- package/dist/auth/index.d.mts +1 -1
- package/dist/auth/index.mjs +2 -2
- package/dist/cli/commands/init.mjs +12 -9
- package/dist/core/index.d.mts +2 -2
- package/dist/core/index.mjs +2 -2
- package/dist/{createApp-CBgVaFyh.mjs → createApp-Bol7DLUf.mjs} +404 -279
- package/dist/{defineResource-B22gcNvn.mjs → defineResource-bVKHjQzE.mjs} +116 -19
- package/dist/discovery/index.mjs +1 -1
- package/dist/docs/index.d.mts +1 -1
- package/dist/dynamic/index.d.mts +1 -1
- package/dist/dynamic/index.mjs +2 -2
- package/dist/{elevation-Ca_yveIO.d.mts → elevation-C_taLQrM.d.mts} +27 -1
- package/dist/{errorHandler-DMbGdzBG.mjs → errorHandler-r2595m8T.mjs} +1 -1
- package/dist/{errors-CPpvPHT0.d.mts → errors-CcVbl1-T.d.mts} +17 -1
- package/dist/{errors-rxhfP7Hf.mjs → errors-NoQKsbAT.mjs} +23 -1
- package/dist/{eventPlugin-iGrSEmwJ.d.mts → eventPlugin-DW45v4V5.d.mts} +30 -2
- package/dist/events/index.d.mts +2 -2
- package/dist/events/index.mjs +40 -10
- package/dist/factory/index.d.mts +44 -23
- package/dist/factory/index.mjs +136 -2
- package/dist/hooks/index.d.mts +1 -1
- package/dist/idempotency/index.d.mts +3 -3
- package/dist/idempotency/mongodb.d.mts +1 -1
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/{index-yhxyjqNb.d.mts → index-BIsZ_su5.d.mts} +4 -8
- package/dist/{index-BL8CaQih.d.mts → index-Cb3gtbg7.d.mts} +2 -2
- package/dist/{index-Diqcm14c.d.mts → index-NGZksqM5.d.mts} +30 -1
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +8 -7
- package/dist/integrations/event-gateway.mjs +1 -1
- package/dist/integrations/index.d.mts +1 -1
- package/dist/integrations/mcp/index.d.mts +4 -2
- package/dist/integrations/mcp/index.mjs +1 -1
- package/dist/integrations/mcp/testing.d.mts +1 -1
- package/dist/integrations/mcp/testing.mjs +1 -1
- package/dist/{interface-DGmPxakH.d.mts → interface-DDW43OmS.d.mts} +194 -13
- package/dist/{mongodb-CUpYfxfD.d.mts → mongodb-kltrBPa1.d.mts} +10 -0
- package/dist/{mongodb-bga9AbkD.d.mts → mongodb-pMvOlR5_.d.mts} +1 -1
- package/dist/org/index.d.mts +1 -1
- package/dist/org/index.mjs +1 -1
- package/dist/permissions/index.d.mts +2 -2
- package/dist/permissions/index.mjs +2 -2
- package/dist/{permissions-Jk5x3sxz.mjs → permissions-C8ImI8gC.mjs} +44 -2
- package/dist/plugins/index.d.mts +1 -1
- package/dist/plugins/index.mjs +3 -3
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/presets/index.d.mts +1 -1
- package/dist/presets/index.mjs +1 -1
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/presets/multiTenant.mjs +1 -1
- package/dist/{presets-OMPaHMTY.mjs → presets-BMfdy34e.mjs} +2 -2
- package/dist/{redis-CQ5YxMC5.d.mts → redis-D0Qc-9EW.d.mts} +1 -1
- package/dist/registry/index.d.mts +1 -1
- package/dist/{resourceToTools-PMFE8HIv.mjs → resourceToTools-DH3c3e-T.mjs} +81 -7
- package/dist/scope/index.d.mts +2 -2
- package/dist/scope/index.mjs +2 -2
- package/dist/{sse-BkViJPlT.mjs → sse-BF7GR7IB.mjs} +1 -1
- package/dist/testing/index.d.mts +2 -2
- package/dist/testing/index.mjs +1 -1
- package/dist/types/index.d.mts +3 -3
- package/dist/types/index.mjs +23 -2
- package/dist/{types-C6TQjtdi.mjs → types-BhtYdxZU.mjs} +26 -1
- package/dist/{types-Dt0-AI6E.d.mts → types-D5hJ-k_3.d.mts} +189 -6
- package/dist/{types-BJmgxNbF.d.mts → types-D5rjsS_i.d.mts} +1 -1
- package/dist/utils/index.d.mts +2 -2
- package/dist/utils/index.mjs +1 -1
- package/package.json +6 -5
- package/skills/arc/SKILL.md +104 -4
- package/skills/arc/references/mcp.md +160 -2
- /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,
|
|
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:
|
|
47
|
-
update:
|
|
48
|
-
delete:
|
|
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
|
|
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))
|
|
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-
|
|
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-
|
|
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 };
|
package/dist/adapters/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as createMongooseAdapter, i as MongooseAdapter, n as PrismaQueryParser, r as createPrismaAdapter, t as PrismaAdapter } from "../adapters-
|
|
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(
|
|
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
|
|
90
|
-
const
|
|
91
|
-
const
|
|
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:
|
|
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
|
-
|
|
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:
|
|
220
|
+
default:
|
|
221
|
+
baseType.type = "object";
|
|
222
|
+
baseType.additionalProperties = true;
|
|
162
223
|
}
|
|
163
224
|
return baseType;
|
|
164
225
|
}
|
package/dist/audit/index.d.mts
CHANGED
|
@@ -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-
|
|
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
|
package/dist/audit/index.mjs
CHANGED
|
@@ -11,7 +11,7 @@ function createAuditEntry(resource, documentId, action, context, data) {
|
|
|
11
11
|
resource,
|
|
12
12
|
documentId,
|
|
13
13
|
action,
|
|
14
|
-
userId: context.user
|
|
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) {
|
package/dist/audit/mongodb.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as MongoAuditStoreOptions, t as MongoAuditStore } from "../mongodb-
|
|
1
|
+
import { n as MongoAuditStoreOptions, t as MongoAuditStore } from "../mongodb-kltrBPa1.mjs";
|
|
2
2
|
export { MongoAuditStore, type MongoAuditStoreOptions };
|
package/dist/auth/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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";
|
package/dist/auth/index.mjs
CHANGED
|
@@ -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-
|
|
3
|
-
import { c as requireOrgMembership, f as requireTeamMembership, l as requireOrgRole } from "../permissions-
|
|
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,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
|
-
* -
|
|
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
|
-
*
|
|
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,
|
package/dist/core/index.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
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-
|
|
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 };
|
package/dist/core/index.mjs
CHANGED
|
@@ -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-
|
|
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-
|
|
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 };
|