@classytic/arc 2.3.0 → 2.4.2
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 +187 -18
- package/bin/arc.js +11 -3
- package/dist/BaseController-CkM5dUh_.mjs +1031 -0
- package/dist/{EventTransport-BkUDYZEb.d.mts → EventTransport-wc5hSLik.d.mts} +1 -1
- package/dist/{HookSystem-BsGV-j2l.mjs → HookSystem-COkyWztM.mjs} +2 -3
- package/dist/{ResourceRegistry-7Ic20ZMw.mjs → ResourceRegistry-DeCIFlix.mjs} +8 -5
- package/dist/adapters/index.d.mts +3 -5
- package/dist/adapters/index.mjs +2 -3
- package/dist/{prisma-DJbMt3yf.mjs → adapters-DTC4Ug66.mjs} +45 -12
- package/dist/audit/index.d.mts +4 -7
- package/dist/audit/index.mjs +2 -29
- package/dist/audit/mongodb.d.mts +1 -4
- package/dist/audit/mongodb.mjs +2 -3
- package/dist/auth/index.d.mts +7 -9
- package/dist/auth/index.mjs +65 -63
- package/dist/auth/redis-session.d.mts +1 -1
- package/dist/auth/redis-session.mjs +1 -2
- package/dist/{betterAuthOpenApi-DjWDddNc.mjs → betterAuthOpenApi-lz0IRbXJ.mjs} +4 -6
- package/dist/cache/index.d.mts +23 -23
- package/dist/cache/index.mjs +4 -6
- package/dist/{caching-GSDJcA6-.mjs → caching-BSXB-Xr7.mjs} +2 -24
- package/dist/chunk-BpYLSNr0.mjs +14 -0
- package/dist/circuitBreaker-BOBOpN2w.mjs +284 -0
- package/dist/circuitBreaker-JP2GdJ4b.d.mts +206 -0
- package/dist/cli/commands/describe.mjs +24 -7
- package/dist/cli/commands/docs.mjs +6 -7
- package/dist/cli/commands/doctor.d.mts +10 -0
- package/dist/cli/commands/doctor.mjs +156 -0
- package/dist/cli/commands/generate.mjs +66 -17
- package/dist/cli/commands/init.mjs +315 -45
- package/dist/cli/commands/introspect.mjs +2 -4
- package/dist/cli/index.d.mts +1 -10
- package/dist/cli/index.mjs +4 -153
- package/dist/{constants-DdXFXQtN.mjs → constants-Cxde4rpC.mjs} +1 -2
- package/dist/core/index.d.mts +3 -5
- package/dist/core/index.mjs +5 -4
- package/dist/core-C1XCMtqM.mjs +185 -0
- package/dist/{createApp-CgKOPhA4.mjs → createApp-ByWNRsZj.mjs} +64 -35
- package/dist/{defineResource-DWbpJYtm.mjs → defineResource-D9aY5Cy6.mjs} +108 -1157
- package/dist/discovery/index.mjs +37 -5
- package/dist/docs/index.d.mts +6 -9
- package/dist/docs/index.mjs +3 -21
- package/dist/dynamic/index.d.mts +93 -0
- package/dist/dynamic/index.mjs +122 -0
- package/dist/{elevation-DSTbVvYj.mjs → elevation-BEdACOLB.mjs} +5 -36
- package/dist/{elevation-DGo5shaX.d.mts → elevation-Ca_yveIO.d.mts} +41 -7
- package/dist/{errorHandler-C3GY3_ow.mjs → errorHandler--zp54tGc.mjs} +3 -5
- package/dist/errorHandler-Do4vVQ1f.d.mts +139 -0
- package/dist/{errors-DBANPbGr.mjs → errors-rxhfP7Hf.mjs} +1 -2
- package/dist/{eventPlugin-BEOvaDqo.mjs → eventPlugin-Ba00swHF.mjs} +25 -27
- package/dist/{eventPlugin-H6wDDjGO.d.mts → eventPlugin-iGrSEmwJ.d.mts} +105 -5
- package/dist/events/index.d.mts +72 -7
- package/dist/events/index.mjs +216 -4
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis-stream-entry.mjs +19 -7
- package/dist/events/transports/redis.d.mts +1 -1
- package/dist/events/transports/redis.mjs +3 -4
- package/dist/factory/index.d.mts +23 -9
- package/dist/factory/index.mjs +48 -3
- package/dist/{fields-Bi_AVKSo.d.mts → fields-DFwdaWCq.d.mts} +1 -1
- package/dist/{fields-CTd_CrKr.mjs → fields-ipsbIRPK.mjs} +1 -2
- package/dist/hooks/index.d.mts +1 -3
- package/dist/hooks/index.mjs +2 -3
- package/dist/idempotency/index.d.mts +5 -5
- package/dist/idempotency/index.mjs +3 -7
- package/dist/idempotency/mongodb.d.mts +1 -1
- package/dist/idempotency/mongodb.mjs +4 -5
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/idempotency/redis.mjs +2 -5
- package/dist/{fastifyAdapter-6b_eRDBw.d.mts → index-BL8CaQih.d.mts} +56 -57
- package/dist/index-Diqcm14c.d.mts +369 -0
- package/dist/{prisma-Dy5S5F5i.d.mts → index-yhxyjqNb.d.mts} +4 -5
- package/dist/index.d.mts +100 -105
- package/dist/index.mjs +85 -58
- package/dist/integrations/event-gateway.d.mts +1 -1
- package/dist/integrations/event-gateway.mjs +8 -4
- package/dist/integrations/index.d.mts +4 -2
- package/dist/integrations/index.mjs +1 -1
- package/dist/integrations/jobs.d.mts +2 -2
- package/dist/integrations/jobs.mjs +63 -14
- package/dist/integrations/mcp/index.d.mts +219 -0
- package/dist/integrations/mcp/index.mjs +572 -0
- package/dist/integrations/mcp/testing.d.mts +53 -0
- package/dist/integrations/mcp/testing.mjs +104 -0
- package/dist/integrations/streamline.mjs +39 -19
- package/dist/integrations/webhooks.d.mts +56 -0
- package/dist/integrations/webhooks.mjs +139 -0
- package/dist/integrations/websocket-redis.d.mts +46 -0
- package/dist/integrations/websocket-redis.mjs +50 -0
- package/dist/integrations/websocket.d.mts +68 -2
- package/dist/integrations/websocket.mjs +96 -13
- package/dist/{interface-CSNjltAc.d.mts → interface-B4awm1RJ.d.mts} +2 -2
- package/dist/interface-DGmPxakH.d.mts +2213 -0
- package/dist/{keys-DhqDRxv3.mjs → keys-qcD-TVJl.mjs} +3 -4
- package/dist/{logger-ByrvQWZO.mjs → logger-Dz3j1ItV.mjs} +2 -4
- package/dist/{memory-B2v7KrCB.mjs → memory-Cb_7iy9e.mjs} +2 -4
- package/dist/metrics-Csh4nsvv.mjs +224 -0
- package/dist/migrations/index.d.mts +113 -44
- package/dist/migrations/index.mjs +84 -102
- package/dist/{mongodb-DNKEExbf.mjs → mongodb-BuQ7fNTg.mjs} +1 -4
- package/dist/{mongodb-ClykrfGo.d.mts → mongodb-CUpYfxfD.d.mts} +2 -3
- package/dist/{mongodb-Dg8O_gvd.d.mts → mongodb-bga9AbkD.d.mts} +2 -2
- package/dist/{openapi-9nB_kiuR.mjs → openapi-CBmZ6EQN.mjs} +4 -21
- package/dist/org/index.d.mts +12 -14
- package/dist/org/index.mjs +92 -119
- package/dist/org/types.d.mts +2 -2
- package/dist/org/types.mjs +1 -1
- package/dist/permissions/index.d.mts +4 -278
- package/dist/permissions/index.mjs +4 -579
- package/dist/permissions-CA5zg0yK.mjs +751 -0
- package/dist/plugins/index.d.mts +104 -107
- package/dist/plugins/index.mjs +203 -313
- package/dist/plugins/response-cache.mjs +4 -69
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +24 -11
- package/dist/{pluralize-CM-jZg7p.mjs → pluralize-CcT6qF0a.mjs} +12 -13
- package/dist/policies/index.d.mts +2 -2
- package/dist/policies/index.mjs +80 -83
- package/dist/presets/index.d.mts +26 -19
- package/dist/presets/index.mjs +2 -142
- package/dist/presets/multiTenant.d.mts +1 -4
- package/dist/presets/multiTenant.mjs +4 -6
- package/dist/presets-C9QXJV1u.mjs +422 -0
- package/dist/{queryCachePlugin-B6R0d4av.mjs → queryCachePlugin-ClosZdNS.mjs} +6 -27
- package/dist/{queryCachePlugin-Q6SYuHZ6.d.mts → queryCachePlugin-DcmETvcB.d.mts} +3 -3
- package/dist/queryParser-CgCtsjti.mjs +352 -0
- package/dist/{redis-UwjEp8Ea.d.mts → redis-CQ5YxMC5.d.mts} +2 -2
- package/dist/{redis-stream-CBg0upHI.d.mts → redis-stream-BW9UKLZM.d.mts} +9 -2
- package/dist/registry/index.d.mts +1 -4
- package/dist/registry/index.mjs +3 -4
- package/dist/{introspectionPlugin-B3JkrjwU.mjs → registry-I-ogLgL9.mjs} +1 -8
- package/dist/{requestContext-xi6OKBL-.mjs → requestContext-DYtmNpm5.mjs} +1 -3
- package/dist/resourceToTools-PMFE8HIv.mjs +533 -0
- package/dist/rpc/index.d.mts +90 -0
- package/dist/rpc/index.mjs +248 -0
- package/dist/{schemaConverter-Dtg0Kt9T.mjs → schemaConverter-DjzHpFam.mjs} +1 -2
- package/dist/schemas/index.d.mts +30 -30
- package/dist/schemas/index.mjs +2 -4
- package/dist/scope/index.d.mts +13 -2
- package/dist/scope/index.mjs +18 -5
- package/dist/{sessionManager-D_iEHjQl.d.mts → sessionManager-wbkYj2HL.d.mts} +2 -2
- package/dist/{sse-DkqQ1uxb.mjs → sse-BkViJPlT.mjs} +4 -25
- package/dist/testing/index.d.mts +551 -567
- package/dist/testing/index.mjs +1744 -1799
- package/dist/{tracing-8CEbhF0w.d.mts → tracing-bz_U4EM1.d.mts} +6 -1
- package/dist/{typeGuards-DwxA1t_L.mjs → typeGuards-Cj5Rgvlg.mjs} +1 -2
- package/dist/types/index.d.mts +4 -946
- package/dist/types/index.mjs +2 -4
- package/dist/types-BJmgxNbF.d.mts +275 -0
- package/dist/{types-RLkFVgaw.d.mts → types-BNUccdcf.d.mts} +2 -2
- package/dist/{types-Beqn1Un7.mjs → types-C6TQjtdi.mjs} +30 -2
- package/dist/{types-tKwaViYB.d.mts → types-Dt0-AI6E.d.mts} +68 -27
- package/dist/{types-DelU6kln.mjs → types-ZUu_h0jp.mjs} +1 -2
- package/dist/utils/index.d.mts +254 -351
- package/dist/utils/index.mjs +7 -6
- package/dist/utils-Dc0WhlIl.mjs +594 -0
- package/dist/versioning-BzfeHmhj.mjs +37 -0
- package/package.json +44 -10
- package/skills/arc/SKILL.md +518 -0
- package/skills/arc/references/auth.md +250 -0
- package/skills/arc/references/events.md +272 -0
- package/skills/arc/references/integrations.md +385 -0
- package/skills/arc/references/mcp.md +431 -0
- package/skills/arc/references/production.md +610 -0
- package/skills/arc/references/testing.md +183 -0
- package/dist/audited-CGdLiSlE.mjs +0 -140
- package/dist/chunk-C7Uep-_p.mjs +0 -20
- package/dist/circuitBreaker-CSS2VvL6.mjs +0 -1109
- package/dist/errorHandler-CW3OOeYq.d.mts +0 -72
- package/dist/interface-BtdYtQUA.d.mts +0 -1114
- package/dist/presets-BTeYbw7h.d.mts +0 -57
- package/dist/presets-CeFtfDR8.mjs +0 -119
- /package/dist/{errors-DAWRdiYP.d.mts → errors-CPpvPHT0.d.mts} +0 -0
- /package/dist/{externalPaths-SyPF2tgK.d.mts → externalPaths-DpO-s7r8.d.mts} +0 -0
- /package/dist/{interface-DTbsvIWe.d.mts → interface-D_BWALyZ.d.mts} +0 -0
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { t as ResourceRegistry } from "../../ResourceRegistry-
|
|
2
|
-
import { t as buildOpenApiSpec } from "../../openapi-
|
|
3
|
-
import {
|
|
4
|
-
import { resolve } from "node:path";
|
|
1
|
+
import { t as ResourceRegistry } from "../../ResourceRegistry-DeCIFlix.mjs";
|
|
2
|
+
import { t as buildOpenApiSpec } from "../../openapi-CBmZ6EQN.mjs";
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
5
4
|
import { pathToFileURL } from "node:url";
|
|
6
|
-
|
|
5
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
7
6
|
//#region src/cli/commands/docs.ts
|
|
8
7
|
/**
|
|
9
8
|
* Arc CLI - Docs Command
|
|
@@ -41,12 +40,12 @@ async function exportDocs(args) {
|
|
|
41
40
|
description: "Auto-generated from Arc resources"
|
|
42
41
|
});
|
|
43
42
|
const fullPath = resolve(process.cwd(), outputPath);
|
|
43
|
+
mkdirSync(dirname(fullPath), { recursive: true });
|
|
44
44
|
writeFileSync(fullPath, JSON.stringify(spec, null, 2));
|
|
45
45
|
console.log(`OpenAPI spec exported to: ${fullPath}`);
|
|
46
46
|
console.log(`\nResources included: ${resources.length}`);
|
|
47
47
|
console.log(`Total endpoints: ${Object.keys(spec.paths).length}`);
|
|
48
48
|
}
|
|
49
49
|
var docs_default = { exportDocs };
|
|
50
|
-
|
|
51
50
|
//#endregion
|
|
52
|
-
export { docs_default as default, exportDocs };
|
|
51
|
+
export { docs_default as default, exportDocs };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/cli/commands/doctor.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Arc CLI - Doctor Command
|
|
4
|
+
*
|
|
5
|
+
* Health check utility that validates the development environment.
|
|
6
|
+
* Checks Node.js version, dependencies, configuration, and env variables.
|
|
7
|
+
*/
|
|
8
|
+
declare function doctor(_args?: string[]): Promise<void>;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { doctor };
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { dirname, join, parse, resolve } from "node:path";
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
+
//#region src/cli/commands/doctor.ts
|
|
4
|
+
/**
|
|
5
|
+
* Arc CLI - Doctor Command
|
|
6
|
+
*
|
|
7
|
+
* Health check utility that validates the development environment.
|
|
8
|
+
* Checks Node.js version, dependencies, configuration, and env variables.
|
|
9
|
+
*/
|
|
10
|
+
async function doctor(_args = []) {
|
|
11
|
+
console.log("\nArc Doctor\n");
|
|
12
|
+
const results = [];
|
|
13
|
+
const cwd = process.cwd();
|
|
14
|
+
const nodeVersion = process.versions.node;
|
|
15
|
+
if (parseInt(nodeVersion.split(".")[0] ?? "0", 10) >= 22) results.push({
|
|
16
|
+
status: "pass",
|
|
17
|
+
label: `Node.js ${nodeVersion}`,
|
|
18
|
+
detail: "required: >=22"
|
|
19
|
+
});
|
|
20
|
+
else results.push({
|
|
21
|
+
status: "fail",
|
|
22
|
+
label: `Node.js ${nodeVersion}`,
|
|
23
|
+
detail: "required: >=22"
|
|
24
|
+
});
|
|
25
|
+
const pkg = findPackageJson(cwd);
|
|
26
|
+
const allDeps = {
|
|
27
|
+
...pkg?.dependencies ?? {},
|
|
28
|
+
...pkg?.devDependencies ?? {}
|
|
29
|
+
};
|
|
30
|
+
const arcVersion = allDeps["@classytic/arc"];
|
|
31
|
+
if (arcVersion) results.push({
|
|
32
|
+
status: "pass",
|
|
33
|
+
label: `@classytic/arc ${arcVersion}`
|
|
34
|
+
});
|
|
35
|
+
else results.push({
|
|
36
|
+
status: "warn",
|
|
37
|
+
label: "@classytic/arc not found in dependencies"
|
|
38
|
+
});
|
|
39
|
+
const fastifyVersion = allDeps.fastify;
|
|
40
|
+
if (fastifyVersion) {
|
|
41
|
+
const clean = fastifyVersion.replace(/^[\^~>=<]+/, "").split("-")[0] ?? "0.0.0";
|
|
42
|
+
if (parseInt(clean.split(".")[0] ?? "0", 10) >= 5) results.push({
|
|
43
|
+
status: "pass",
|
|
44
|
+
label: `fastify ${fastifyVersion}`,
|
|
45
|
+
detail: "required: ^5.0.0"
|
|
46
|
+
});
|
|
47
|
+
else results.push({
|
|
48
|
+
status: "fail",
|
|
49
|
+
label: `fastify ${fastifyVersion}`,
|
|
50
|
+
detail: "required: ^5.0.0 — Arc requires Fastify 5"
|
|
51
|
+
});
|
|
52
|
+
} else results.push({
|
|
53
|
+
status: "fail",
|
|
54
|
+
label: "fastify not found in dependencies",
|
|
55
|
+
detail: "required: ^5.0.0"
|
|
56
|
+
});
|
|
57
|
+
const tsconfigPath = resolve(cwd, "tsconfig.json");
|
|
58
|
+
if (existsSync(tsconfigPath)) try {
|
|
59
|
+
const stripped = readFileSync(tsconfigPath, "utf-8").replace(/\/\/.*$/gm, "");
|
|
60
|
+
const moduleRes = JSON.parse(stripped)?.compilerOptions?.moduleResolution;
|
|
61
|
+
if (moduleRes && ![
|
|
62
|
+
"nodenext",
|
|
63
|
+
"node16",
|
|
64
|
+
"bundler"
|
|
65
|
+
].includes(moduleRes.toLowerCase())) results.push({
|
|
66
|
+
status: "warn",
|
|
67
|
+
label: "tsconfig.json found",
|
|
68
|
+
detail: `moduleResolution "${moduleRes}" — recommend "NodeNext" or "Bundler"`
|
|
69
|
+
});
|
|
70
|
+
else results.push({
|
|
71
|
+
status: "pass",
|
|
72
|
+
label: "tsconfig.json found"
|
|
73
|
+
});
|
|
74
|
+
} catch {
|
|
75
|
+
results.push({
|
|
76
|
+
status: "pass",
|
|
77
|
+
label: "tsconfig.json found"
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
else results.push({
|
|
81
|
+
status: "warn",
|
|
82
|
+
label: "tsconfig.json not found"
|
|
83
|
+
});
|
|
84
|
+
for (const dep of [
|
|
85
|
+
{
|
|
86
|
+
name: "@fastify/rate-limit",
|
|
87
|
+
purpose: "rate limiting"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: "@fastify/helmet",
|
|
91
|
+
purpose: "security headers"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: "@fastify/cors",
|
|
95
|
+
purpose: "CORS support"
|
|
96
|
+
}
|
|
97
|
+
]) if (allDeps[dep.name]) results.push({
|
|
98
|
+
status: "pass",
|
|
99
|
+
label: `${dep.name} installed`
|
|
100
|
+
});
|
|
101
|
+
else results.push({
|
|
102
|
+
status: "warn",
|
|
103
|
+
label: `${dep.name} not installed`,
|
|
104
|
+
detail: `${dep.purpose} disabled`
|
|
105
|
+
});
|
|
106
|
+
if (allDeps["better-auth"]) results.push({
|
|
107
|
+
status: "pass",
|
|
108
|
+
label: `better-auth ${allDeps["better-auth"]}`
|
|
109
|
+
});
|
|
110
|
+
for (const env of [{
|
|
111
|
+
name: "MONGO_URI",
|
|
112
|
+
severity: "warn",
|
|
113
|
+
detail: "required at runtime for MongoDB"
|
|
114
|
+
}, {
|
|
115
|
+
name: "BETTER_AUTH_SECRET",
|
|
116
|
+
severity: "warn",
|
|
117
|
+
detail: "required for Better Auth session encryption"
|
|
118
|
+
}]) if (process.env[env.name]) results.push({
|
|
119
|
+
status: "pass",
|
|
120
|
+
label: `${env.name} set`
|
|
121
|
+
});
|
|
122
|
+
else results.push({
|
|
123
|
+
status: env.severity,
|
|
124
|
+
label: `${env.name} not set`,
|
|
125
|
+
detail: env.detail
|
|
126
|
+
});
|
|
127
|
+
let passCount = 0;
|
|
128
|
+
let warnCount = 0;
|
|
129
|
+
let failCount = 0;
|
|
130
|
+
for (const r of results) {
|
|
131
|
+
const icon = r.status === "pass" ? "[pass]" : r.status === "warn" ? "[warn]" : "[FAIL]";
|
|
132
|
+
const detail = r.detail ? ` (${r.detail})` : "";
|
|
133
|
+
console.log(` ${icon} ${r.label}${detail}`);
|
|
134
|
+
if (r.status === "pass") passCount++;
|
|
135
|
+
else if (r.status === "warn") warnCount++;
|
|
136
|
+
else failCount++;
|
|
137
|
+
}
|
|
138
|
+
console.log(`\n${passCount} passed, ${warnCount} warnings, ${failCount} failures\n`);
|
|
139
|
+
if (failCount > 0) process.exitCode = 1;
|
|
140
|
+
}
|
|
141
|
+
function findPackageJson(dir) {
|
|
142
|
+
let current = resolve(dir);
|
|
143
|
+
const root = parse(current).root;
|
|
144
|
+
while (current !== root) {
|
|
145
|
+
const p = join(current, "package.json");
|
|
146
|
+
try {
|
|
147
|
+
if (existsSync(p)) return JSON.parse(readFileSync(p, "utf-8"));
|
|
148
|
+
} catch {}
|
|
149
|
+
const parent = dirname(current);
|
|
150
|
+
if (parent === current) break;
|
|
151
|
+
current = parent;
|
|
152
|
+
}
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
//#endregion
|
|
156
|
+
export { doctor };
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { t as pluralize } from "../../pluralize-
|
|
2
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
1
|
+
import { t as pluralize } from "../../pluralize-CcT6qF0a.mjs";
|
|
3
2
|
import { join } from "node:path";
|
|
4
|
-
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
4
|
//#region src/cli/commands/generate.ts
|
|
6
5
|
/**
|
|
7
6
|
* Arc CLI - Generate Command
|
|
@@ -45,7 +44,7 @@ function toCamelCase(pascalName) {
|
|
|
45
44
|
function getTemplates(ts, config = {}) {
|
|
46
45
|
const isMultiTenant = config.tenant === "multi";
|
|
47
46
|
return {
|
|
48
|
-
model: (name,
|
|
47
|
+
model: (name, _fileName) => {
|
|
49
48
|
const camel = toCamelCase(name);
|
|
50
49
|
return `/**
|
|
51
50
|
* ${name} Model
|
|
@@ -83,6 +82,7 @@ export default ${name};
|
|
|
83
82
|
},
|
|
84
83
|
repository: (name, fileName) => {
|
|
85
84
|
const camel = toCamelCase(name);
|
|
85
|
+
const generic = ts ? `<I${name}>` : "";
|
|
86
86
|
return `/**
|
|
87
87
|
* ${name} Repository
|
|
88
88
|
* Generated by Arc CLI
|
|
@@ -94,9 +94,9 @@ import {
|
|
|
94
94
|
softDeletePlugin,
|
|
95
95
|
mongoOperationsPlugin,
|
|
96
96
|
} from '@classytic/mongokit';
|
|
97
|
-
import ${name} from './${fileName}.model.js'
|
|
97
|
+
import ${name} from './${fileName}.model.js';${ts ? `\nimport type { I${name} } from './${fileName}.model.js';` : ""}
|
|
98
98
|
|
|
99
|
-
class ${name}Repository extends Repository {
|
|
99
|
+
class ${name}Repository extends Repository${generic} {
|
|
100
100
|
constructor() {
|
|
101
101
|
super(${name}, [
|
|
102
102
|
methodRegistryPlugin(),
|
|
@@ -159,8 +159,14 @@ import { buildCrudSchemasFromModel } from '@classytic/mongokit/utils';
|
|
|
159
159
|
const crudSchemas = buildCrudSchemasFromModel(${name}, {
|
|
160
160
|
strictAdditionalProperties: true,
|
|
161
161
|
fieldRules: {
|
|
162
|
-
//
|
|
162
|
+
// systemManaged: excluded from create/update schemas
|
|
163
163
|
// deletedAt: { systemManaged: true },
|
|
164
|
+
// immutable: cannot be updated after creation
|
|
165
|
+
// slug: { immutable: true },
|
|
166
|
+
// immutableAfterCreate: same as immutable (alias)
|
|
167
|
+
// organizationId: { immutableAfterCreate: true },
|
|
168
|
+
// optional: removed from required array
|
|
169
|
+
// description: { optional: true },
|
|
164
170
|
},
|
|
165
171
|
query: {
|
|
166
172
|
filterableFields: {
|
|
@@ -175,7 +181,7 @@ export default crudSchemas;
|
|
|
175
181
|
resource: (name, fileName) => {
|
|
176
182
|
const camel = toCamelCase(name);
|
|
177
183
|
const useMongoKit = config.adapter === "mongokit" || !config.adapter;
|
|
178
|
-
const queryParserImport = useMongoKit ? `\nimport { QueryParser } from '@classytic/mongokit';\n\nconst queryParser = new QueryParser();\n` : "";
|
|
184
|
+
const queryParserImport = useMongoKit ? `\nimport { QueryParser } from '@classytic/mongokit';\n\nconst queryParser = new QueryParser({\n allowedFilterFields: ['isActive'],\n});\n` : "";
|
|
179
185
|
const queryParserConfig = useMongoKit ? `\n queryParser,` : "";
|
|
180
186
|
return isMultiTenant ? `/**
|
|
181
187
|
* ${name} Resource
|
|
@@ -189,7 +195,7 @@ import ${camel}Repository from './${fileName}.repository.js';${queryParserImport
|
|
|
189
195
|
|
|
190
196
|
const ${camel}Resource = defineResource${ts ? `<I${name}>` : ""}({
|
|
191
197
|
name: '${fileName}',
|
|
192
|
-
adapter: createMongooseAdapter(${name}, ${camel}Repository),${queryParserConfig}
|
|
198
|
+
adapter: createMongooseAdapter({ model: ${name}, repository: ${camel}Repository }),${queryParserConfig}
|
|
193
199
|
presets: ['softDelete'],
|
|
194
200
|
permissions: {
|
|
195
201
|
list: requireAuth(),
|
|
@@ -213,7 +219,7 @@ import ${camel}Repository from './${fileName}.repository.js';${queryParserImport
|
|
|
213
219
|
|
|
214
220
|
const ${camel}Resource = defineResource${ts ? `<I${name}>` : ""}({
|
|
215
221
|
name: '${fileName}',
|
|
216
|
-
adapter: createMongooseAdapter(${name}, ${camel}Repository),${queryParserConfig}
|
|
222
|
+
adapter: createMongooseAdapter({ model: ${name}, repository: ${camel}Repository }),${queryParserConfig}
|
|
217
223
|
presets: ['softDelete'],
|
|
218
224
|
permissions: {
|
|
219
225
|
list: requireAuth(),
|
|
@@ -225,6 +231,42 @@ const ${camel}Resource = defineResource${ts ? `<I${name}>` : ""}({
|
|
|
225
231
|
});
|
|
226
232
|
|
|
227
233
|
export default ${camel}Resource;
|
|
234
|
+
`;
|
|
235
|
+
},
|
|
236
|
+
mcp: (name, fileName) => {
|
|
237
|
+
const camel = toCamelCase(name);
|
|
238
|
+
return `/**
|
|
239
|
+
* ${name} MCP Tools
|
|
240
|
+
* Generated by Arc CLI
|
|
241
|
+
*
|
|
242
|
+
* Custom MCP tools for the ${name} domain.
|
|
243
|
+
* CRUD tools (list/get/create/update/delete) are auto-generated by mcpPlugin.
|
|
244
|
+
* Add domain-specific tools here (actions, analytics, workflows).
|
|
245
|
+
*/
|
|
246
|
+
|
|
247
|
+
import { defineTool } from '@classytic/arc/mcp';
|
|
248
|
+
${ts ? "import { z } from 'zod';\n" : "const { z } = require('zod');\n"}
|
|
249
|
+
// Example: domain-specific action tool
|
|
250
|
+
// export const activate${name}Tool = defineTool('activate_${fileName}', {
|
|
251
|
+
// description: 'Activate a ${name.toLowerCase()} by ID',
|
|
252
|
+
// input: { id: z.string().describe('${name} ID') },
|
|
253
|
+
// annotations: { destructiveHint: true, idempotentHint: true },
|
|
254
|
+
// handler: async ({ id }, ctx) => {
|
|
255
|
+
// // Your logic here
|
|
256
|
+
// return { content: [{ type: 'text', text: \`Activated ${name.toLowerCase()} \${id}\` }] };
|
|
257
|
+
// },
|
|
258
|
+
// });
|
|
259
|
+
|
|
260
|
+
// Example: read-only analytics tool
|
|
261
|
+
// export const ${camel}StatsTool = defineTool('${fileName}_stats', {
|
|
262
|
+
// description: 'Get ${name.toLowerCase()} statistics',
|
|
263
|
+
// input: { period: z.enum(['7d', '30d', '90d']).optional() },
|
|
264
|
+
// annotations: { readOnlyHint: true },
|
|
265
|
+
// handler: async ({ period }) => {
|
|
266
|
+
// // Your logic here
|
|
267
|
+
// return { content: [{ type: 'text', text: JSON.stringify({ total: 0, period }) }] };
|
|
268
|
+
// },
|
|
269
|
+
// });
|
|
228
270
|
`;
|
|
229
271
|
},
|
|
230
272
|
test: (name, fileName) => {
|
|
@@ -278,7 +320,7 @@ describe('${name} Resource', () => {
|
|
|
278
320
|
*/
|
|
279
321
|
async function generate(type, args) {
|
|
280
322
|
if (!type) throw new Error("Missing type argument\nUsage: arc generate <resource|controller|model|repository|schemas> <name>");
|
|
281
|
-
const [name] = args;
|
|
323
|
+
const [name, ...restArgs] = args;
|
|
282
324
|
if (!name) throw new Error("Missing name argument\nUsage: arc generate <type> <name>\nExample: arc generate resource product");
|
|
283
325
|
const capitalizedName = toPascalCase(name);
|
|
284
326
|
const lowerName = name.toLowerCase();
|
|
@@ -290,7 +332,7 @@ async function generate(type, args) {
|
|
|
290
332
|
switch (type) {
|
|
291
333
|
case "resource":
|
|
292
334
|
case "r":
|
|
293
|
-
await generateResource(capitalizedName, lowerName, resourcePath, templates, ext);
|
|
335
|
+
await generateResource(capitalizedName, lowerName, resourcePath, templates, ext, projectConfig.mcp === true || restArgs.includes("--mcp"));
|
|
294
336
|
break;
|
|
295
337
|
case "controller":
|
|
296
338
|
case "c":
|
|
@@ -308,13 +350,16 @@ async function generate(type, args) {
|
|
|
308
350
|
case "s":
|
|
309
351
|
await generateFile(capitalizedName, lowerName, resourcePath, "schemas", templates.schemas, ext);
|
|
310
352
|
break;
|
|
311
|
-
|
|
353
|
+
case "mcp":
|
|
354
|
+
await generateFile(capitalizedName, lowerName, resourcePath, "mcp", templates.mcp, ext);
|
|
355
|
+
break;
|
|
356
|
+
default: throw new Error(`Unknown type: ${type}\nAvailable types: resource, controller, model, repository, schemas, mcp`);
|
|
312
357
|
}
|
|
313
358
|
}
|
|
314
359
|
/**
|
|
315
360
|
* Generate a full resource
|
|
316
361
|
*/
|
|
317
|
-
async function generateResource(name, lowerName, resourcePath, templates, ext) {
|
|
362
|
+
async function generateResource(name, lowerName, resourcePath, templates, ext, includeMcp = false) {
|
|
318
363
|
console.log(`\nGenerating resource: ${name}...\n`);
|
|
319
364
|
if (!existsSync(resourcePath)) {
|
|
320
365
|
mkdirSync(resourcePath, { recursive: true });
|
|
@@ -325,6 +370,7 @@ async function generateResource(name, lowerName, resourcePath, templates, ext) {
|
|
|
325
370
|
[`${lowerName}.repository.${ext}`]: templates.repository(name, lowerName),
|
|
326
371
|
[`${lowerName}.resource.${ext}`]: templates.resource(name, lowerName)
|
|
327
372
|
};
|
|
373
|
+
if (includeMcp) files[`${lowerName}.mcp.${ext}`] = templates.mcp(name, lowerName);
|
|
328
374
|
for (const [filename, content] of Object.entries(files)) {
|
|
329
375
|
const filepath = join(resourcePath, filename);
|
|
330
376
|
if (existsSync(filepath)) console.warn(` ! Skipped: ${filename} (already exists)`);
|
|
@@ -367,7 +413,11 @@ ${isMultiTenant ? ` - requireAuth() → any authenticated user
|
|
|
367
413
|
|
|
368
414
|
4. Run tests:
|
|
369
415
|
npm test
|
|
370
|
-
`
|
|
416
|
+
${includeMcp ? `
|
|
417
|
+
5. MCP tools file created: ${lowerName}.mcp.${ext}
|
|
418
|
+
Uncomment and customize the example tools.
|
|
419
|
+
Import and add to extraTools in your mcpPlugin config.
|
|
420
|
+
` : ""}`);
|
|
371
421
|
}
|
|
372
422
|
/**
|
|
373
423
|
* Generate a single file
|
|
@@ -384,6 +434,5 @@ async function generateFile(name, lowerName, resourcePath, fileType, template, e
|
|
|
384
434
|
writeFileSync(filepath, template(name, lowerName));
|
|
385
435
|
console.log(` + Created: ${filename}`);
|
|
386
436
|
}
|
|
387
|
-
|
|
388
437
|
//#endregion
|
|
389
|
-
export { generate as default, generate };
|
|
438
|
+
export { generate as default, generate };
|