@classytic/arc 2.11.3 → 2.11.4
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 +16 -11
- package/dist/EventTransport-BFQjw9pB.mjs +133 -0
- package/dist/{QueryCache-DOBNHBE0.d.mts → QueryCache-D41bfdBB.d.mts} +1 -1
- package/dist/adapters/index.d.mts +3 -3
- package/dist/adapters/index.mjs +2 -2
- package/dist/{adapters-D0tT2Tyo.mjs → adapters-DUUiiimH.mjs} +17 -2
- package/dist/audit/index.d.mts +2 -2
- package/dist/auth/index.d.mts +4 -4
- package/dist/auth/redis-session.d.mts +1 -1
- package/dist/cache/index.d.mts +3 -3
- package/dist/cli/commands/docs.mjs +1 -1
- package/dist/cli/commands/generate.mjs +1 -1
- package/dist/cli/commands/init.mjs +125 -43
- package/dist/core/index.d.mts +2 -2
- package/dist/core/index.mjs +1 -1
- package/dist/{core-DnUsRpuX.mjs → core-CbcQRIch.mjs} +15 -10
- package/dist/{createActionRouter-u3ql2EDo.mjs → createActionRouter-CIKOcNA7.mjs} +1 -1
- package/dist/{createApp-BFxtdKy6.mjs → createApp-C9bRrqlX.mjs} +4 -6
- package/dist/defineEvent-D1Ky9M1D.mjs +188 -0
- package/dist/docs/index.d.mts +2 -2
- package/dist/docs/index.mjs +1 -1
- package/dist/{eventPlugin-KrFIQ097.mjs → eventPlugin-Cts2-Tfj.mjs} +8 -134
- package/dist/{eventPlugin-CUNjYYRY.d.mts → eventPlugin-DDJoNEPL.d.mts} +34 -7
- package/dist/events/index.d.mts +164 -5
- package/dist/events/index.mjs +128 -180
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis-stream-entry.mjs +204 -31
- package/dist/events/transports/redis.d.mts +1 -1
- package/dist/factory/index.d.mts +1 -1
- package/dist/factory/index.mjs +1 -1
- package/dist/{fields-C8Y0XLAu.d.mts → fields-BRjxOAFp.d.mts} +1 -1
- package/dist/hooks/index.d.mts +1 -1
- package/dist/idempotency/index.d.mts +3 -3
- package/dist/idempotency/index.mjs +1 -1
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/{index-6u4_Gg6G.d.mts → index-CXXRbnf8.d.mts} +51 -5
- package/dist/{index-DdQ3O9Pg.d.mts → index-D9t1KNaB.d.mts} +2 -2
- package/dist/{index-BbMrcvGp.d.mts → index-Rg8axYPz.d.mts} +12 -4
- package/dist/{index-BdXnTPRj.d.mts → index-m8mOOlFW.d.mts} +3 -3
- package/dist/{index-BYCqHCVu.d.mts → index-rHjXmJar.d.mts} +3 -3
- package/dist/index.d.mts +7 -7
- package/dist/index.mjs +3 -3
- package/dist/integrations/event-gateway.d.mts +2 -2
- package/dist/integrations/index.d.mts +2 -2
- package/dist/integrations/mcp/index.d.mts +2 -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/integrations/websocket-redis.d.mts +1 -1
- package/dist/integrations/websocket.d.mts +1 -1
- package/dist/middleware/index.d.mts +1 -1
- package/dist/{openapi-BGUn7Ki1.mjs → openapi-D7G1V7ex.mjs} +1 -1
- package/dist/org/index.d.mts +2 -2
- package/dist/permissions/index.d.mts +2 -2
- package/dist/pipeline/index.d.mts +1 -1
- package/dist/plugins/index.d.mts +5 -5
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/presets/filesUpload.d.mts +4 -4
- package/dist/presets/index.d.mts +1 -1
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/presets/search.d.mts +2 -2
- package/dist/{queryCachePlugin-BUXBSm4F.d.mts → queryCachePlugin-CqMdLI2-.d.mts} +2 -2
- package/dist/{redis-Cm1gnRDf.d.mts → redis-DiMkdHEl.d.mts} +1 -1
- package/dist/redis-stream-xTGxB2bm.d.mts +232 -0
- package/dist/registry/index.d.mts +1 -1
- package/dist/{resourceToTools-ByZpgjeH.mjs → resourceToTools-CxNmI6xF.mjs} +2 -2
- package/dist/scope/index.d.mts +2 -2
- package/dist/testing/index.d.mts +2 -2
- package/dist/testing/index.mjs +1 -1
- package/dist/testing/storageContract.d.mts +1 -1
- package/dist/types/index.d.mts +4 -4
- package/dist/types/storage.d.mts +1 -1
- package/dist/{types-9beEMe25.d.mts → types-BQ9TJQNy.d.mts} +1 -1
- package/dist/{types-BH7dEGvU.d.mts → types-D7KpfiL1.d.mts} +10 -10
- package/dist/utils/index.d.mts +1 -1
- package/dist/{versioning-M9lNLhO8.d.mts → versioning-DsglKfM_.d.mts} +1 -1
- package/package.json +1 -1
- package/skills/arc/SKILL.md +409 -769
- package/dist/redis-stream-CM8TXTix.d.mts +0 -110
- /package/dist/{EventTransport-CfVEGaEl.d.mts → EventTransport-CYNUXdCJ.d.mts} +0 -0
- /package/dist/{elevation-s5ykdNHr.d.mts → elevation-BQQXZ_VR.d.mts} +0 -0
- /package/dist/{errorHandler-Co3lnVmJ.d.mts → errorHandler-DEWmGWPz.d.mts} +0 -0
- /package/dist/{externalPaths-Bapitwvd.d.mts → externalPaths-BD5nw6St.d.mts} +0 -0
- /package/dist/{interface-CkkWm5uR.d.mts → interface-DfLGcus7.d.mts} +0 -0
- /package/dist/{interface-Da0r7Lna.d.mts → interface-beEtJyWM.d.mts} +0 -0
- /package/dist/{pluralize-BneOJkpi.mjs → pluralize-CWP6MB39.mjs} +0 -0
- /package/dist/{schemaIR-BlG9bY7v.mjs → schemaIR-Dy2p4MxS.mjs} +0 -0
- /package/dist/{sessionManager-D-oNWHz3.d.mts → sessionManager-C4Le_UB3.d.mts} +0 -0
- /package/dist/{storage-BwGQXUpd.d.mts → storage-Dfzt4VTl.d.mts} +0 -0
- /package/dist/{store-helpers-BhrzxvyQ.mjs → store-helpers-Cp4uKC1U.mjs} +0 -0
- /package/dist/{tracing-DokiEsuz.d.mts → tracing-QJVprktp.d.mts} +0 -0
- /package/dist/{types-tgR4Pt8F.d.mts → types-DDyTPc6y.d.mts} +0 -0
- /package/dist/{websocket-CyJ1VIFI.d.mts → websocket-ChC2rqe1.d.mts} +0 -0
package/README.md
CHANGED
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
# @classytic/arc
|
|
2
2
|
|
|
3
|
-
Database-agnostic resource framework for Fastify. One `defineResource()` call → REST + auth + permissions + events + caching + OpenAPI + MCP tools
|
|
3
|
+
Database-agnostic resource framework for Fastify. One `defineResource()` call → REST + auth + permissions + events + caching + OpenAPI + MCP tools.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Fastify 5+ · Node.js 22+ · ESM only
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
# Core
|
|
9
8
|
npm install @classytic/arc fastify
|
|
10
9
|
|
|
11
|
-
# Security defaults
|
|
10
|
+
# Security defaults createApp() loads (each opt-out via `cors: false` etc.)
|
|
12
11
|
npm install @fastify/cors @fastify/helmet @fastify/rate-limit @fastify/under-pressure @fastify/sensible
|
|
13
|
-
# (each is opt-out via `cors: false` / `helmet: false` / etc.)
|
|
14
12
|
|
|
15
|
-
#
|
|
16
|
-
npm install @classytic/mongokit mongoose # MongoDB
|
|
13
|
+
# Storage adapter — pick one
|
|
14
|
+
npm install @classytic/mongokit mongoose # MongoDB
|
|
17
15
|
# OR @classytic/sqlitekit drizzle-orm better-sqlite3 (sqlite)
|
|
18
|
-
# OR
|
|
16
|
+
# OR implement RepositoryLike from @classytic/repo-core
|
|
19
17
|
```
|
|
20
18
|
|
|
21
19
|
---
|
|
@@ -40,12 +38,19 @@ import { createApp, loadResources } from '@classytic/arc/factory';
|
|
|
40
38
|
|
|
41
39
|
await mongoose.connect(process.env.DB_URI);
|
|
42
40
|
|
|
41
|
+
// Fail fast on missing CORS env — silent `undefined` here drops to surprising
|
|
42
|
+
// browser defaults. Browser apps: declare an explicit allowlist (below).
|
|
43
|
+
// Server-to-server / API-key services: `cors: { origin: '*', credentials: false }`
|
|
44
|
+
// or `cors: false` to disable entirely (CORS is a browser-only concern).
|
|
45
|
+
const ALLOWED_ORIGINS = process.env.ALLOWED_ORIGINS;
|
|
46
|
+
if (!ALLOWED_ORIGINS) throw new Error('ALLOWED_ORIGINS env is required');
|
|
47
|
+
|
|
43
48
|
const app = await createApp({
|
|
44
49
|
preset: 'production',
|
|
45
50
|
resourcePrefix: '/api/v1',
|
|
46
51
|
resources: await loadResources(import.meta.url), // auto-discover *.resource.ts
|
|
47
52
|
auth: { type: 'jwt', jwt: { secret: process.env.JWT_SECRET } },
|
|
48
|
-
cors: { origin:
|
|
53
|
+
cors: { origin: ALLOWED_ORIGINS.split(','), credentials: true },
|
|
49
54
|
});
|
|
50
55
|
|
|
51
56
|
await app.listen({ port: 8040, host: '0.0.0.0' });
|
|
@@ -67,7 +72,7 @@ resources: async () => {
|
|
|
67
72
|
},
|
|
68
73
|
```
|
|
69
74
|
|
|
70
|
-
`loadResources({ context })`
|
|
75
|
+
`loadResources({ context })` threads engine handles into resources whose default export is `(ctx) => defineResource(...)`. No parallel factory files, no `exclude: [...]` bookkeeping.
|
|
71
76
|
|
|
72
77
|
---
|
|
73
78
|
|
|
@@ -206,7 +211,7 @@ const ctx = await createTestApp({
|
|
|
206
211
|
authMode: 'jwt',
|
|
207
212
|
connectMongoose: true, // in-memory Mongo + Mongoose connect
|
|
208
213
|
});
|
|
209
|
-
ctx.auth.register('admin', { user: { id: '1',
|
|
214
|
+
ctx.auth.register('admin', { user: { id: '1', role: 'admin' }, orgId: 'org-1' });
|
|
210
215
|
|
|
211
216
|
const res = await ctx.app.inject({
|
|
212
217
|
method: 'POST',
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
//#region src/events/EventTransport.ts
|
|
2
|
+
/**
|
|
3
|
+
* In-memory event transport (default)
|
|
4
|
+
* Events are delivered synchronously within the process.
|
|
5
|
+
* Not suitable for multi-instance deployments.
|
|
6
|
+
*/
|
|
7
|
+
var MemoryEventTransport = class {
|
|
8
|
+
name = "memory";
|
|
9
|
+
handlers = /* @__PURE__ */ new Map();
|
|
10
|
+
logger;
|
|
11
|
+
constructor(options) {
|
|
12
|
+
this.logger = options?.logger ?? console;
|
|
13
|
+
}
|
|
14
|
+
async publish(event) {
|
|
15
|
+
const exactHandlers = this.handlers.get(event.type) ?? /* @__PURE__ */ new Set();
|
|
16
|
+
const wildcardHandlers = this.handlers.get("*") ?? /* @__PURE__ */ new Set();
|
|
17
|
+
const patternHandlers = /* @__PURE__ */ new Set();
|
|
18
|
+
for (const [pattern, handlers] of this.handlers.entries()) if (pattern.endsWith(".*")) {
|
|
19
|
+
const prefix = pattern.slice(0, -2);
|
|
20
|
+
if (event.type.startsWith(`${prefix}.`)) for (const h of handlers) patternHandlers.add(h);
|
|
21
|
+
}
|
|
22
|
+
const allHandlers = new Set([
|
|
23
|
+
...exactHandlers,
|
|
24
|
+
...wildcardHandlers,
|
|
25
|
+
...patternHandlers
|
|
26
|
+
]);
|
|
27
|
+
for (const handler of allHandlers) try {
|
|
28
|
+
await handler(event);
|
|
29
|
+
} catch (err) {
|
|
30
|
+
this.logger.error(`[EventTransport] Handler error for ${event.type}:`, err);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Reference `publishMany` implementation — delegates to `publish()` in order.
|
|
35
|
+
*
|
|
36
|
+
* Production transports (Kafka, Redis pipeline, SQS batch) should override
|
|
37
|
+
* this with a single batched network call. Memory transport has nothing to
|
|
38
|
+
* batch, so we just loop — the loop still returns a proper result map so
|
|
39
|
+
* `EventOutbox.relay` can exercise the batched code path in tests.
|
|
40
|
+
*/
|
|
41
|
+
async publishMany(events) {
|
|
42
|
+
const results = /* @__PURE__ */ new Map();
|
|
43
|
+
for (const event of events) try {
|
|
44
|
+
await this.publish(event);
|
|
45
|
+
results.set(event.meta.id, null);
|
|
46
|
+
} catch (err) {
|
|
47
|
+
results.set(event.meta.id, err instanceof Error ? err : new Error(String(err)));
|
|
48
|
+
}
|
|
49
|
+
return results;
|
|
50
|
+
}
|
|
51
|
+
async subscribe(pattern, handler) {
|
|
52
|
+
if (!this.handlers.has(pattern)) this.handlers.set(pattern, /* @__PURE__ */ new Set());
|
|
53
|
+
this.handlers.get(pattern)?.add(handler);
|
|
54
|
+
return () => {
|
|
55
|
+
const set = this.handlers.get(pattern);
|
|
56
|
+
if (set) {
|
|
57
|
+
set.delete(handler);
|
|
58
|
+
if (set.size === 0) this.handlers.delete(pattern);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
async close() {
|
|
63
|
+
this.handlers.clear();
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Create a domain event with auto-generated metadata.
|
|
68
|
+
*
|
|
69
|
+
* `id` and `timestamp` are filled in; everything else is caller-controlled.
|
|
70
|
+
* Set `schemaVersion` explicitly for any event type you plan to evolve.
|
|
71
|
+
*/
|
|
72
|
+
function createEvent(type, payload, meta) {
|
|
73
|
+
return {
|
|
74
|
+
type,
|
|
75
|
+
payload,
|
|
76
|
+
meta: {
|
|
77
|
+
id: crypto.randomUUID(),
|
|
78
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
79
|
+
...meta
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Create a child event that chains causation from a parent event.
|
|
85
|
+
*
|
|
86
|
+
* Rules:
|
|
87
|
+
* - `causationId` is set to the parent's `id` (direct cause)
|
|
88
|
+
* - `correlationId` is inherited from the parent if set, else falls back
|
|
89
|
+
* to the parent's `id` (root correlation)
|
|
90
|
+
* - `userId` / `organizationId` are inherited when not overridden so the
|
|
91
|
+
* whole chain stays scoped to the originating principal/tenant
|
|
92
|
+
*
|
|
93
|
+
* Caller-supplied `meta` wins over inherited fields — pass `{ userId: newActor }`
|
|
94
|
+
* to override when a subsystem acts on behalf of a different principal.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```typescript
|
|
98
|
+
* const orderPlaced = createEvent('order.placed', { orderId: 'o1' }, {
|
|
99
|
+
* correlationId: req.id, userId: user.id,
|
|
100
|
+
* });
|
|
101
|
+
* await events.publish(orderPlaced);
|
|
102
|
+
*
|
|
103
|
+
* // Downstream handler emits a child event:
|
|
104
|
+
* const reserved = createChildEvent(orderPlaced, 'inventory.reserved', {
|
|
105
|
+
* orderId: 'o1', skus: ['sku-1', 'sku-2'],
|
|
106
|
+
* });
|
|
107
|
+
* // reserved.meta.causationId === orderPlaced.meta.id
|
|
108
|
+
* // reserved.meta.correlationId === orderPlaced.meta.correlationId
|
|
109
|
+
* // reserved.meta.userId === user.id (inherited)
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
function createChildEvent(parent, type, payload, meta) {
|
|
113
|
+
const inherited = {
|
|
114
|
+
correlationId: parent.meta.correlationId ?? parent.meta.id,
|
|
115
|
+
causationId: parent.meta.id
|
|
116
|
+
};
|
|
117
|
+
if (parent.meta.userId !== void 0) inherited.userId = parent.meta.userId;
|
|
118
|
+
if (parent.meta.organizationId !== void 0) inherited.organizationId = parent.meta.organizationId;
|
|
119
|
+
if (parent.meta.source !== void 0) inherited.source = parent.meta.source;
|
|
120
|
+
if (parent.meta.idempotencyKey !== void 0) inherited.idempotencyKey = parent.meta.idempotencyKey;
|
|
121
|
+
return {
|
|
122
|
+
type,
|
|
123
|
+
payload,
|
|
124
|
+
meta: {
|
|
125
|
+
id: crypto.randomUUID(),
|
|
126
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
127
|
+
...inherited,
|
|
128
|
+
...meta
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
//#endregion
|
|
133
|
+
export { createChildEvent as n, createEvent as r, MemoryEventTransport as t };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { An as
|
|
2
|
-
import { a as PrismaQueryParserOptions, c as MongooseAdapterOptions, d as DrizzleAdapterOptions, f as createDrizzleAdapter, i as PrismaQueryParser, l as createMongooseAdapter, n as PrismaAdapterOptions, o as createPrismaAdapter, r as PrismaQueryOptions, s as MongooseAdapter, t as PrismaAdapter, u as DrizzleAdapter } from "../index-
|
|
3
|
-
export { AdapterFactory, DataAdapter, DrizzleAdapter, DrizzleAdapterOptions, FieldMetadata, MongooseAdapter, MongooseAdapterOptions, PrismaAdapter, PrismaAdapterOptions, PrismaQueryOptions, PrismaQueryParser, PrismaQueryParserOptions, RelationMetadata, RepositoryLike, SchemaMetadata, ValidationResult, createDrizzleAdapter, createMongooseAdapter, createPrismaAdapter };
|
|
1
|
+
import { An as FieldMetadata, Dn as AdapterRepositoryInput, En as AdapterFactory, Fn as asRepositoryLike, Mn as RepositoryLike, Nn as SchemaMetadata, Pn as ValidationResult, jn as RelationMetadata, kn as DataAdapter } from "../index-CXXRbnf8.mjs";
|
|
2
|
+
import { a as PrismaQueryParserOptions, c as MongooseAdapterOptions, d as DrizzleAdapterOptions, f as createDrizzleAdapter, i as PrismaQueryParser, l as createMongooseAdapter, n as PrismaAdapterOptions, o as createPrismaAdapter, r as PrismaQueryOptions, s as MongooseAdapter, t as PrismaAdapter, u as DrizzleAdapter } from "../index-Rg8axYPz.mjs";
|
|
3
|
+
export { AdapterFactory, AdapterRepositoryInput, DataAdapter, DrizzleAdapter, DrizzleAdapterOptions, FieldMetadata, MongooseAdapter, MongooseAdapterOptions, PrismaAdapter, PrismaAdapterOptions, PrismaQueryOptions, PrismaQueryParser, PrismaQueryParserOptions, RelationMetadata, RepositoryLike, SchemaMetadata, ValidationResult, asRepositoryLike, createDrizzleAdapter, createMongooseAdapter, createPrismaAdapter };
|
package/dist/adapters/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as createMongooseAdapter, i as MongooseAdapter, n as PrismaQueryParser, o as
|
|
2
|
-
export { DrizzleAdapter, MongooseAdapter, PrismaAdapter, PrismaQueryParser, createDrizzleAdapter, createMongooseAdapter, createPrismaAdapter };
|
|
1
|
+
import { a as createMongooseAdapter, c as createDrizzleAdapter, i as MongooseAdapter, n as PrismaQueryParser, o as asRepositoryLike, r as createPrismaAdapter, s as DrizzleAdapter, t as PrismaAdapter } from "../adapters-DUUiiimH.mjs";
|
|
2
|
+
export { DrizzleAdapter, MongooseAdapter, PrismaAdapter, PrismaQueryParser, asRepositoryLike, createDrizzleAdapter, createMongooseAdapter, createPrismaAdapter };
|
|
@@ -264,6 +264,21 @@ function createDrizzleAdapter(options) {
|
|
|
264
264
|
return new DrizzleAdapter(options);
|
|
265
265
|
}
|
|
266
266
|
//#endregion
|
|
267
|
+
//#region src/adapters/interface.ts
|
|
268
|
+
/**
|
|
269
|
+
* Widen a permissive `AdapterRepositoryInput<TDoc>` to arc's strict
|
|
270
|
+
* `RepositoryLike<TDoc>` view. Single-source escape hatch for the
|
|
271
|
+
* filter-IR drift documented on `AdapterRepositoryInput`.
|
|
272
|
+
*
|
|
273
|
+
* Arc internals (audit / outbox / idempotency, BaseController) still see
|
|
274
|
+
* the IR-aware `RepositoryLike`; only the call paths arc exercises are
|
|
275
|
+
* shared between the two views, and those use the narrower
|
|
276
|
+
* `Record<string, unknown>` filter shape both sides agree on.
|
|
277
|
+
*/
|
|
278
|
+
function asRepositoryLike(input) {
|
|
279
|
+
return input;
|
|
280
|
+
}
|
|
281
|
+
//#endregion
|
|
267
282
|
//#region src/adapters/mongoose.ts
|
|
268
283
|
/**
|
|
269
284
|
* Mongoose data adapter with proper type safety
|
|
@@ -280,7 +295,7 @@ var MongooseAdapter = class {
|
|
|
280
295
|
if (!isMongooseModel(options.model)) throw new TypeError("MongooseAdapter: Invalid model. Expected Mongoose Model instance.\nUsage: createMongooseAdapter({ model: YourModel, repository: yourRepo })");
|
|
281
296
|
if (!isRepository(options.repository)) throw new TypeError("MongooseAdapter: Invalid repository. Expected StandardRepo instance.\nUsage: createMongooseAdapter({ model: YourModel, repository: yourRepo })");
|
|
282
297
|
this.model = options.model;
|
|
283
|
-
this.repository = options.repository;
|
|
298
|
+
this.repository = asRepositoryLike(options.repository);
|
|
284
299
|
this.schemaGenerator = options.schemaGenerator;
|
|
285
300
|
this.name = `MongooseAdapter<${options.model.modelName}>`;
|
|
286
301
|
}
|
|
@@ -946,4 +961,4 @@ function createPrismaAdapter(options) {
|
|
|
946
961
|
return new PrismaAdapter(options);
|
|
947
962
|
}
|
|
948
963
|
//#endregion
|
|
949
|
-
export { createMongooseAdapter as a, MongooseAdapter as i, PrismaQueryParser as n,
|
|
964
|
+
export { createMongooseAdapter as a, createDrizzleAdapter as c, MongooseAdapter as i, PrismaQueryParser as n, asRepositoryLike as o, createPrismaAdapter as r, DrizzleAdapter as s, PrismaAdapter as t };
|
package/dist/audit/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { d as UserBase } from "../fields-
|
|
1
|
+
import { Mn as RepositoryLike } from "../index-CXXRbnf8.mjs";
|
|
2
|
+
import { d as UserBase } from "../fields-BRjxOAFp.mjs";
|
|
3
3
|
import { FastifyPluginAsync } from "fastify";
|
|
4
4
|
|
|
5
5
|
//#region src/audit/stores/interface.d.ts
|
package/dist/auth/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Ot as AuthHelpers, kt as AuthPluginOptions } from "../index-
|
|
2
|
-
import { c as PermissionCheck } from "../fields-
|
|
3
|
-
import { t as ExternalOpenApiPaths } from "../externalPaths-
|
|
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-
|
|
1
|
+
import { Ot as AuthHelpers, kt as AuthPluginOptions } from "../index-CXXRbnf8.mjs";
|
|
2
|
+
import { c as PermissionCheck } from "../fields-BRjxOAFp.mjs";
|
|
3
|
+
import { t as ExternalOpenApiPaths } from "../externalPaths-BD5nw6St.mjs";
|
|
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-C4Le_UB3.mjs";
|
|
5
5
|
import { FastifyPluginAsync, FastifyReply as FastifyReply$1, FastifyRequest } from "fastify";
|
|
6
6
|
|
|
7
7
|
//#region src/auth/authPlugin.d.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as SessionData, s as SessionStore } from "../sessionManager-
|
|
1
|
+
import { i as SessionData, s as SessionStore } from "../sessionManager-C4Le_UB3.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/auth/redis-session.d.ts
|
|
4
4
|
/** Minimal Redis client interface — compatible with ioredis */
|
package/dist/cache/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { n as CacheStats, r as CacheStore, t as CacheLogger } from "../interface-
|
|
2
|
-
import { a as QueryCacheConfig, i as QueryCache, n as CacheResult, r as CacheStatus, t as CacheEnvelope } from "../QueryCache-
|
|
3
|
-
import { i as queryCachePlugin, n as QueryCacheDefaults, r as QueryCachePluginOptions, t as CrossResourceRule } from "../queryCachePlugin-
|
|
1
|
+
import { n as CacheStats, r as CacheStore, t as CacheLogger } from "../interface-beEtJyWM.mjs";
|
|
2
|
+
import { a as QueryCacheConfig, i as QueryCache, n as CacheResult, r as CacheStatus, t as CacheEnvelope } from "../QueryCache-D41bfdBB.mjs";
|
|
3
|
+
import { i as queryCachePlugin, n as QueryCacheDefaults, r as QueryCachePluginOptions, t as CrossResourceRule } from "../queryCachePlugin-CqMdLI2-.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/cache/keys.d.ts
|
|
6
6
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as ResourceRegistry } from "../../ResourceRegistry-DkAeAuTX.mjs";
|
|
2
|
-
import { t as buildOpenApiSpec } from "../../openapi-
|
|
2
|
+
import { t as buildOpenApiSpec } from "../../openapi-D7G1V7ex.mjs";
|
|
3
3
|
import { dirname, resolve } from "node:path";
|
|
4
4
|
import { pathToFileURL } from "node:url";
|
|
5
5
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as pluralize } from "../../pluralize-
|
|
1
|
+
import { t as pluralize } from "../../pluralize-CWP6MB39.mjs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
4
|
//#region src/cli/commands/generate.ts
|
|
@@ -87,42 +87,103 @@ function existsSync$1(filePath) {
|
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
/**
|
|
90
|
-
*
|
|
90
|
+
* Single source of truth for scaffolded project dependencies.
|
|
91
|
+
*
|
|
92
|
+
* Versions are pinned to the floor each subsystem requires — peer-dep
|
|
93
|
+
* minimums on Arc, kit minimums (mongokit ≥ 3.11, repo-core ≥ 0.2,
|
|
94
|
+
* mongoose ≥ 9.4.1), and major-version stable for the rest. The carets
|
|
95
|
+
* allow minor + patch upgrades without breaking arc's contract, while
|
|
96
|
+
* preventing the silent breakage of `@latest` on a kit floor bump.
|
|
97
|
+
*
|
|
98
|
+
* Used by both `packageJsonTemplate` (declares the deps in the generated
|
|
99
|
+
* `package.json` so `npm install` works without a pre-pass) and
|
|
100
|
+
* `installDependencies` (runs the package manager's `install` against
|
|
101
|
+
* the declared ranges). One source — no drift.
|
|
91
102
|
*/
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
"@classytic/arc
|
|
95
|
-
"fastify
|
|
96
|
-
"@fastify/
|
|
97
|
-
"@fastify/
|
|
98
|
-
"@fastify/
|
|
99
|
-
"@fastify/
|
|
100
|
-
"
|
|
101
|
-
"
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
103
|
+
const SCAFFOLD_DEP_VERSIONS = {
|
|
104
|
+
core: {
|
|
105
|
+
"@classytic/arc": "^2.11.3",
|
|
106
|
+
"@fastify/cors": "^11.0.0",
|
|
107
|
+
"@fastify/helmet": "^13.0.0",
|
|
108
|
+
"@fastify/rate-limit": "^10.0.0",
|
|
109
|
+
"@fastify/sensible": "^6.0.0",
|
|
110
|
+
"@fastify/under-pressure": "^9.0.0",
|
|
111
|
+
dotenv: "^17.0.0",
|
|
112
|
+
fastify: "^5.8.0"
|
|
113
|
+
},
|
|
114
|
+
authJwt: {
|
|
115
|
+
"@fastify/jwt": "^10.0.0",
|
|
116
|
+
bcryptjs: "^3.0.0"
|
|
117
|
+
},
|
|
118
|
+
authBetterAuth: {
|
|
119
|
+
"better-auth": "^1.6.0",
|
|
120
|
+
mongodb: "^6.10.0"
|
|
121
|
+
},
|
|
122
|
+
adapterMongokit: {
|
|
123
|
+
"@classytic/mongokit": "^3.11.0",
|
|
124
|
+
"@classytic/repo-core": "^0.2.0",
|
|
125
|
+
mongoose: "^9.4.1"
|
|
126
|
+
},
|
|
127
|
+
devCommon: {
|
|
128
|
+
"pino-pretty": "^13.0.0",
|
|
129
|
+
vitest: "^4.0.0"
|
|
130
|
+
},
|
|
131
|
+
devTypescript: {
|
|
132
|
+
"@types/node": "^22.0.0",
|
|
133
|
+
tsx: "^4.21.0",
|
|
134
|
+
typescript: "^5.6.0"
|
|
135
|
+
},
|
|
136
|
+
typesJwt: { "@types/bcryptjs": "^3.0.0" }
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* Resolve the dependency manifest for a scaffold configuration.
|
|
140
|
+
*
|
|
141
|
+
* Returns sorted records (alphabetical by package name) so the generated
|
|
142
|
+
* `package.json` is deterministic — diffs across re-runs stay clean.
|
|
143
|
+
*/
|
|
144
|
+
function resolveScaffoldDependencies(config) {
|
|
145
|
+
const dependencies = { ...SCAFFOLD_DEP_VERSIONS.core };
|
|
146
|
+
const devDependencies = { ...SCAFFOLD_DEP_VERSIONS.devCommon };
|
|
147
|
+
if (config.auth === "better-auth") Object.assign(dependencies, SCAFFOLD_DEP_VERSIONS.authBetterAuth);
|
|
148
|
+
else {
|
|
149
|
+
Object.assign(dependencies, SCAFFOLD_DEP_VERSIONS.authJwt);
|
|
150
|
+
if (config.typescript) Object.assign(devDependencies, SCAFFOLD_DEP_VERSIONS.typesJwt);
|
|
151
|
+
}
|
|
152
|
+
if (config.adapter === "mongokit") Object.assign(dependencies, SCAFFOLD_DEP_VERSIONS.adapterMongokit);
|
|
153
|
+
if (config.typescript) Object.assign(devDependencies, SCAFFOLD_DEP_VERSIONS.devTypescript);
|
|
154
|
+
return {
|
|
155
|
+
dependencies: sortByKey(dependencies),
|
|
156
|
+
devDependencies: sortByKey(devDependencies)
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Sort a record alphabetically by key — package.json convention.
|
|
161
|
+
*/
|
|
162
|
+
function sortByKey(record) {
|
|
163
|
+
return Object.fromEntries(Object.entries(record).sort(([a], [b]) => a.localeCompare(b)));
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Install dependencies using the detected package manager.
|
|
167
|
+
*
|
|
168
|
+
* Dependencies are already declared in the generated `package.json` (see
|
|
169
|
+
* `packageJsonTemplate`), so a single plain `install` resolves the full
|
|
170
|
+
* tree. No two-pass `npm add` flow — the manifest is the source of truth.
|
|
171
|
+
*/
|
|
172
|
+
async function installDependencies(projectPath, _config, pm) {
|
|
110
173
|
console.log(` Installing dependencies...`);
|
|
111
|
-
await runCommand(
|
|
112
|
-
console.log(` Installing dev dependencies...`);
|
|
113
|
-
await runCommand(installDevCmd, projectPath);
|
|
174
|
+
await runCommand(getInstallCommand(pm), projectPath);
|
|
114
175
|
console.log(`\nDependencies installed successfully.`);
|
|
115
176
|
}
|
|
116
177
|
/**
|
|
117
|
-
* Get the install command for a package manager
|
|
178
|
+
* Get the plain `install` command for a package manager. Reads the declared
|
|
179
|
+
* dependencies from the project's `package.json`.
|
|
118
180
|
*/
|
|
119
|
-
function getInstallCommand(pm
|
|
120
|
-
const pkgList = packages.join(" ");
|
|
181
|
+
function getInstallCommand(pm) {
|
|
121
182
|
switch (pm) {
|
|
122
|
-
case "pnpm": return
|
|
123
|
-
case "yarn": return
|
|
124
|
-
case "bun": return
|
|
125
|
-
default: return
|
|
183
|
+
case "pnpm": return "pnpm install";
|
|
184
|
+
case "yarn": return "yarn install";
|
|
185
|
+
case "bun": return "bun install";
|
|
186
|
+
default: return "npm install";
|
|
126
187
|
}
|
|
127
188
|
}
|
|
128
189
|
/**
|
|
@@ -267,6 +328,7 @@ async function createProjectStructure(projectPath, config) {
|
|
|
267
328
|
}
|
|
268
329
|
}
|
|
269
330
|
function packageJsonTemplate(config) {
|
|
331
|
+
const { dependencies, devDependencies } = resolveScaffoldDependencies(config);
|
|
270
332
|
const scripts = config.typescript ? config.edge ? {
|
|
271
333
|
dev: "tsx watch src/index.ts",
|
|
272
334
|
build: "tsc",
|
|
@@ -309,6 +371,8 @@ function packageJsonTemplate(config) {
|
|
|
309
371
|
"#utils/*": "./src/utils/*"
|
|
310
372
|
},
|
|
311
373
|
scripts,
|
|
374
|
+
dependencies,
|
|
375
|
+
devDependencies,
|
|
312
376
|
engines: { node: ">=22" }
|
|
313
377
|
}, null, 2);
|
|
314
378
|
}
|
|
@@ -1808,8 +1872,10 @@ describe('Example Resource', () => {
|
|
|
1808
1872
|
authMode: 'jwt',
|
|
1809
1873
|
${config.adapter === "mongokit" ? " connectMongoose: true,\n" : ""} });
|
|
1810
1874
|
|
|
1875
|
+
// Arc's permission engine reads singular user.role — string,
|
|
1876
|
+
// comma-separated string, or array all normalise via getUserRoles().
|
|
1811
1877
|
ctx.auth${ts ? "!" : ""}.register('admin', {
|
|
1812
|
-
user: { id: '1',
|
|
1878
|
+
user: { id: '1', role: 'admin' },
|
|
1813
1879
|
orgId: 'org-1',
|
|
1814
1880
|
});
|
|
1815
1881
|
});
|
|
@@ -1913,13 +1979,19 @@ userSchema.methods.removeOrganization = function(organizationId${ts ? ": Types.O
|
|
|
1913
1979
|
userSchema.index({ 'organizations.organizationId': 1 });
|
|
1914
1980
|
` : "";
|
|
1915
1981
|
const userType = ts ? `
|
|
1916
|
-
|
|
1982
|
+
const PLATFORM_ROLES = ['user', 'admin', 'superadmin'] as const;
|
|
1983
|
+
type PlatformRole = typeof PLATFORM_ROLES[number];
|
|
1917
1984
|
|
|
1985
|
+
/**
|
|
1986
|
+
* Comma-separated list of platform roles (Better Auth admin-plugin convention).
|
|
1987
|
+
* Single role: 'admin'. Multiple: 'admin,trainer'. Arc's permission engine
|
|
1988
|
+
* normalises both forms via getUserRoles() — see @classytic/arc/scope.
|
|
1989
|
+
*/
|
|
1918
1990
|
type User = {
|
|
1919
1991
|
name: string;
|
|
1920
1992
|
email: string;
|
|
1921
1993
|
password: string;
|
|
1922
|
-
|
|
1994
|
+
role: string;${config.tenant === "multi" ? `
|
|
1923
1995
|
organizations: UserOrganization[];` : ""}
|
|
1924
1996
|
resetPasswordToken?: string;
|
|
1925
1997
|
resetPasswordExpires?: Date;
|
|
@@ -1958,11 +2030,21 @@ const userSchema = new Schema${ts ? "<User, UserModel, UserMethods>" : ""}(
|
|
|
1958
2030
|
},
|
|
1959
2031
|
password: { type: String, required: true },
|
|
1960
2032
|
|
|
1961
|
-
// Platform
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
2033
|
+
// Platform role — singular field, matches Arc's permission engine
|
|
2034
|
+
// (req.user.role) and Better Auth's admin-plugin convention.
|
|
2035
|
+
// Comma-separated for multi-role users (e.g. 'admin,trainer');
|
|
2036
|
+
// getUserRoles() in @classytic/arc/scope normalises both forms.
|
|
2037
|
+
role: {
|
|
2038
|
+
type: String,
|
|
2039
|
+
required: true,
|
|
2040
|
+
default: 'user',
|
|
2041
|
+
index: true,
|
|
2042
|
+
validate: {
|
|
2043
|
+
validator: (v${ts ? ": string" : ""}) =>
|
|
2044
|
+
/^(user|admin|superadmin)(,(user|admin|superadmin))*$/.test(v),
|
|
2045
|
+
message: (props${ts ? ": { value: string }" : ""}) =>
|
|
2046
|
+
\`Invalid role "\${props.value}" — expected one or more of user|admin|superadmin\`,
|
|
2047
|
+
},
|
|
1966
2048
|
},
|
|
1967
2049
|
${orgSchema}
|
|
1968
2050
|
// Password reset
|
|
@@ -2381,7 +2463,7 @@ export async function register(request${ts ? ": FastifyRequest" : ""}, reply${ts
|
|
|
2381
2463
|
}
|
|
2382
2464
|
|
|
2383
2465
|
// Create user
|
|
2384
|
-
await userRepository.create({ name, email, password,
|
|
2466
|
+
await userRepository.create({ name, email, password, role: 'user' });
|
|
2385
2467
|
|
|
2386
2468
|
return reply.code(201).send({ success: true, message: 'User registered successfully' });
|
|
2387
2469
|
} catch (error) {
|
|
@@ -2506,10 +2588,10 @@ export async function updateUserProfile(request${ts ? ": FastifyRequest" : ""},
|
|
|
2506
2588
|
const userId = (request${ts ? " as any" : ""}).user?._id || (request${ts ? " as any" : ""}).user?.id;
|
|
2507
2589
|
const updates = { ...request.body${ts ? " as any" : ""} };
|
|
2508
2590
|
|
|
2509
|
-
// Prevent updating protected fields
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2591
|
+
// Prevent updating protected fields — auth-managed only
|
|
2592
|
+
delete updates.password;
|
|
2593
|
+
delete updates.role;
|
|
2594
|
+
delete updates.organizations;
|
|
2513
2595
|
|
|
2514
2596
|
const user = await userRepository.Model.findByIdAndUpdate(userId, updates, { new: true });
|
|
2515
2597
|
return reply.send({ success: true, data: user });
|
|
@@ -2598,7 +2680,7 @@ export const loginResponse = {
|
|
|
2598
2680
|
id: { type: 'string' },
|
|
2599
2681
|
name: { type: 'string' },
|
|
2600
2682
|
email: { type: 'string' },
|
|
2601
|
-
|
|
2683
|
+
role: { type: 'string' },
|
|
2602
2684
|
},
|
|
2603
2685
|
},
|
|
2604
2686
|
accessToken: { type: 'string' },
|
package/dist/core/index.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { B as ResourceDefinition, Gt as TreeMixin, Ht as SoftDeleteExt, Jt as BulkExt, Kt as SlugExt, Ut as SoftDeleteMixin, V as defineResource, Vt as BaseController, Wt as TreeExt, Yt as BulkMixin, an as QueryResolverConfig, cn as AccessControl, in as QueryResolver, ln as AccessControlConfig, nn as BaseCrudController, on as BodySanitizer, qt as SlugMixin, rn as ListResult, sn as BodySanitizerConfig, tn as BaseControllerOptions } from "../index-
|
|
2
|
-
import { C as MAX_REGEX_LENGTH, D as RESERVED_QUERY_PARAMS, E as MutationOperation, O as SYSTEM_FIELDS, S as MAX_FILTER_DEPTH, T as MUTATION_OPERATIONS, _ as DEFAULT_UPDATE_METHOD, a as getControllerScope, b as HookOperation, c as createCrudRouter, d as CrudOperation, f as DEFAULT_ID_FIELD, g as DEFAULT_TENANT_FIELD, h as DEFAULT_SORT, i as getControllerContext, l as createPermissionMiddleware, m as DEFAULT_MAX_LIMIT, n as createFastifyHandler, o as sendControllerResponse, p as DEFAULT_LIMIT, r as createRequestContext, s as defineResourceVariants, t as createCrudHandlers, u as CRUD_OPERATIONS, v as HOOK_OPERATIONS, w as MAX_SEARCH_LENGTH, x as HookPhase, y as HOOK_PHASES } from "../index-
|
|
1
|
+
import { B as ResourceDefinition, Gt as TreeMixin, Ht as SoftDeleteExt, Jt as BulkExt, Kt as SlugExt, Ut as SoftDeleteMixin, V as defineResource, Vt as BaseController, Wt as TreeExt, Yt as BulkMixin, an as QueryResolverConfig, cn as AccessControl, in as QueryResolver, ln as AccessControlConfig, nn as BaseCrudController, on as BodySanitizer, qt as SlugMixin, rn as ListResult, sn as BodySanitizerConfig, tn as BaseControllerOptions } from "../index-CXXRbnf8.mjs";
|
|
2
|
+
import { C as MAX_REGEX_LENGTH, D as RESERVED_QUERY_PARAMS, E as MutationOperation, O as SYSTEM_FIELDS, S as MAX_FILTER_DEPTH, T as MUTATION_OPERATIONS, _ as DEFAULT_UPDATE_METHOD, a as getControllerScope, b as HookOperation, c as createCrudRouter, d as CrudOperation, f as DEFAULT_ID_FIELD, g as DEFAULT_TENANT_FIELD, h as DEFAULT_SORT, i as getControllerContext, l as createPermissionMiddleware, m as DEFAULT_MAX_LIMIT, n as createFastifyHandler, o as sendControllerResponse, p as DEFAULT_LIMIT, r as createRequestContext, s as defineResourceVariants, t as createCrudHandlers, u as CRUD_OPERATIONS, v as HOOK_OPERATIONS, w as MAX_SEARCH_LENGTH, x as HookPhase, y as HOOK_PHASES } from "../index-m8mOOlFW.mjs";
|
|
3
3
|
export { AccessControl, AccessControlConfig, BaseController, BaseControllerOptions, BaseCrudController, BodySanitizer, BodySanitizerConfig, BulkExt, BulkMixin, 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, ListResult, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, MutationOperation, QueryResolver, QueryResolverConfig, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, SlugExt, SlugMixin, SoftDeleteExt, SoftDeleteMixin, TreeExt, TreeMixin, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineResource, defineResourceVariants, 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-BhY1OHoH.mjs";
|
|
2
2
|
import { a as BulkMixin, c as BodySanitizer, i as SlugMixin, l as AccessControl, n as TreeMixin, o as BaseCrudController, r as SoftDeleteMixin, s as QueryResolver, t as BaseController } from "../BaseController-swXruJ2_.mjs";
|
|
3
3
|
import { _ as getControllerContext, g as createRequestContext, h as createFastifyHandler, m as createCrudHandlers, v as getControllerScope, y as sendControllerResponse } from "../routerShared-BqLRb5l7.mjs";
|
|
4
|
-
import { a as createPermissionMiddleware, i as createCrudRouter, n as ResourceDefinition, r as defineResource, t as defineResourceVariants } from "../core-
|
|
4
|
+
import { a as createPermissionMiddleware, i as createCrudRouter, n as ResourceDefinition, r as defineResource, t as defineResourceVariants } from "../core-CbcQRIch.mjs";
|
|
5
5
|
export { AccessControl, BaseController, BaseCrudController, BodySanitizer, BulkMixin, 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, SlugMixin, SoftDeleteMixin, TreeMixin, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineResource, defineResourceVariants, getControllerContext, getControllerScope, sendControllerResponse };
|
|
@@ -470,15 +470,20 @@ function resolveOrAutoCreateController(resolvedConfig, adapter, repository, hasC
|
|
|
470
470
|
else arcLog("defineResource").warn(`Resource "${resolvedConfig.name}" declares a custom \`queryParser\` but its controller does not expose \`setQueryParser(qp)\`. The parser will NOT be threaded into the controller's query resolution — operator filters (\`[contains]\`, \`[like]\`, etc.) may fall back to the controller's internal default. Extend \`BaseController\` / \`BaseCrudController\` (both implement \`setQueryParser\`) OR add the method to your custom controller to honor the resource-level parser.`);
|
|
471
471
|
}
|
|
472
472
|
if (controller) {
|
|
473
|
-
const
|
|
474
|
-
if (resolvedConfig.tenantField !== void 0)
|
|
475
|
-
if (resolvedConfig.schemaOptions !== void 0 && Object.keys(resolvedConfig.schemaOptions).length > 0)
|
|
476
|
-
if (resolvedConfig.idField !== void 0)
|
|
477
|
-
if (resolvedConfig.defaultSort !== void 0)
|
|
478
|
-
if (resolvedConfig.cache !== void 0)
|
|
479
|
-
if (resolvedConfig.onFieldWriteDenied !== void 0)
|
|
480
|
-
if (resolvedConfig.
|
|
481
|
-
if (
|
|
473
|
+
const authorOptions = [];
|
|
474
|
+
if (resolvedConfig.tenantField !== void 0) authorOptions.push("tenantField");
|
|
475
|
+
if (resolvedConfig.schemaOptions !== void 0 && Object.keys(resolvedConfig.schemaOptions).length > 0) authorOptions.push("schemaOptions");
|
|
476
|
+
if (resolvedConfig.idField !== void 0) authorOptions.push("idField");
|
|
477
|
+
if (resolvedConfig.defaultSort !== void 0) authorOptions.push("defaultSort");
|
|
478
|
+
if (resolvedConfig.cache !== void 0) authorOptions.push("cache");
|
|
479
|
+
if (resolvedConfig.onFieldWriteDenied !== void 0) authorOptions.push("onFieldWriteDenied");
|
|
480
|
+
if (authorOptions.length > 0) arcLog("defineResource").warn(`Resource "${resolvedConfig.name}" declares a custom controller AND resource-level option(s) [${authorOptions.join(", ")}]. Arc only threads these when it auto-builds the controller — when you pass your own, they are dropped silently and the controller falls back to its own defaults (e.g. tenantField → 'organizationId'). Forward them to your controller's \`super(repo, { ... })\` call. Same root cause as the \`queryParser\` warn above.`);
|
|
481
|
+
if (resolvedConfig._controllerOptions !== void 0) {
|
|
482
|
+
const presetFields = [];
|
|
483
|
+
if (resolvedConfig._controllerOptions.slugField) presetFields.push("slugField");
|
|
484
|
+
if (resolvedConfig._controllerOptions.parentField) presetFields.push("parentField");
|
|
485
|
+
arcLog("defineResource").warn(`Resource "${resolvedConfig.name}" applies a preset that injects controller field(s) [${presetFields.join(", ") || "preset metadata"}] (e.g. slugLookup / softDelete / parent), but the resource also declares a custom controller. Preset metadata only reaches arc's auto-built BaseController — your custom controller will not see \`slugField\`/\`parentField\`/etc. Either (a) drop the preset on this resource (\`presets: [...]\` without it), or (b) extend \`BaseController\` / \`BaseCrudController\` so arc auto-builds the controller and threads the preset fields automatically.`);
|
|
486
|
+
}
|
|
482
487
|
return controller;
|
|
483
488
|
}
|
|
484
489
|
if (!hasCrudRoutes || !repository) return controller;
|
|
@@ -881,7 +886,7 @@ var ResourceDefinition = class {
|
|
|
881
886
|
fields: self.fields
|
|
882
887
|
});
|
|
883
888
|
if (self.actions && Object.keys(self.actions).length > 0) {
|
|
884
|
-
const { createActionRouter } = await import("./createActionRouter-
|
|
889
|
+
const { createActionRouter } = await import("./createActionRouter-CIKOcNA7.mjs").then((n) => n.n);
|
|
885
890
|
createActionRouter(typedInstance, {
|
|
886
891
|
...normalizeActionsToRouterConfig(self.actions, self.actionPermissions, self.tag, self.permissions, self.name, typedInstance.log),
|
|
887
892
|
resourceName: self.name,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
2
2
|
import { a as buildAuthMiddlewareForPermissions, c as buildPreHandlerChain, f as resolveRouterPluginMw, l as buildRateLimitConfig, n as buildActionPipelineHandler, p as selectPluginMw, r as buildArcDecorator, t as buildActionPermissionMw, u as resolvePipelineSteps, y as sendControllerResponse } from "./routerShared-BqLRb5l7.mjs";
|
|
3
|
-
import { n as schemaIRToJsonSchemaBranch, t as normalizeSchemaIR } from "./schemaIR-
|
|
3
|
+
import { n as schemaIRToJsonSchemaBranch, t as normalizeSchemaIR } from "./schemaIR-Dy2p4MxS.mjs";
|
|
4
4
|
//#region src/core/createActionRouter.ts
|
|
5
5
|
var createActionRouter_exports = /* @__PURE__ */ __exportAll({
|
|
6
6
|
buildActionBodySchema: () => buildActionBodySchema,
|