@restforgejs/mcp-server 1.2.3 → 1.2.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/dist/server.js +52 -7
- package/dist/server.js.map +1 -1
- package/dist/tools/codegen/create-kafka-consumer.d.ts +2 -0
- package/dist/tools/codegen/create-kafka-consumer.js +140 -0
- package/dist/tools/codegen/create-kafka-consumer.js.map +1 -0
- package/dist/tools/codegen/create-processor.d.ts +2 -0
- package/dist/tools/codegen/create-processor.js +157 -0
- package/dist/tools/codegen/create-processor.js.map +1 -0
- package/dist/tools/codegen/generate-test.d.ts +2 -0
- package/dist/tools/codegen/generate-test.js +149 -0
- package/dist/tools/codegen/generate-test.js.map +1 -0
- package/dist/tools/codegen/index.js +6 -0
- package/dist/tools/codegen/index.js.map +1 -1
- package/dist/tools/codegen/migrate-payload.js +3 -0
- package/dist/tools/codegen/migrate-payload.js.map +1 -1
- package/dist/tools/data/index.d.ts +2 -0
- package/dist/tools/data/index.js +7 -0
- package/dist/tools/data/index.js.map +1 -0
- package/dist/tools/data/pull.d.ts +2 -0
- package/dist/tools/data/pull.js +202 -0
- package/dist/tools/data/pull.js.map +1 -0
- package/dist/tools/data/push.d.ts +2 -0
- package/dist/tools/data/push.js +190 -0
- package/dist/tools/data/push.js.map +1 -0
- package/dist/tools/key/generate.d.ts +2 -0
- package/dist/tools/key/generate.js +130 -0
- package/dist/tools/key/generate.js.map +1 -0
- package/dist/tools/key/index.d.ts +2 -0
- package/dist/tools/key/index.js +9 -0
- package/dist/tools/key/index.js.map +1 -0
- package/dist/tools/key/list.d.ts +2 -0
- package/dist/tools/key/list.js +126 -0
- package/dist/tools/key/list.js.map +1 -0
- package/dist/tools/key/revoke.d.ts +2 -0
- package/dist/tools/key/revoke.js +117 -0
- package/dist/tools/key/revoke.js.map +1 -0
- package/dist/tools/project/delete.d.ts +2 -0
- package/dist/tools/project/delete.js +116 -0
- package/dist/tools/project/delete.js.map +1 -0
- package/dist/tools/project/index.d.ts +2 -0
- package/dist/tools/project/index.js +7 -0
- package/dist/tools/project/index.js.map +1 -0
- package/dist/tools/project/list.d.ts +2 -0
- package/dist/tools/project/list.js +107 -0
- package/dist/tools/project/list.js.map +1 -0
- package/dist/tools/setup/clear-default-config.d.ts +2 -0
- package/dist/tools/setup/clear-default-config.js +104 -0
- package/dist/tools/setup/clear-default-config.js.map +1 -0
- package/dist/tools/setup/get-default-config.d.ts +2 -0
- package/dist/tools/setup/get-default-config.js +104 -0
- package/dist/tools/setup/get-default-config.js.map +1 -0
- package/dist/tools/setup/index.js +8 -0
- package/dist/tools/setup/index.js.map +1 -1
- package/dist/tools/setup/init-config.js +3 -5
- package/dist/tools/setup/init-config.js.map +1 -1
- package/dist/tools/setup/list-configs.d.ts +2 -0
- package/dist/tools/setup/list-configs.js +104 -0
- package/dist/tools/setup/list-configs.js.map +1 -0
- package/dist/tools/setup/set-default-config.d.ts +2 -0
- package/dist/tools/setup/set-default-config.js +109 -0
- package/dist/tools/setup/set-default-config.js.map +1 -0
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -6,6 +6,9 @@ import { registerSetupTools } from './tools/setup/index.js';
|
|
|
6
6
|
import { registerCodegenTools } from './tools/codegen/index.js';
|
|
7
7
|
import { registerRuntimeTools } from './tools/runtime/index.js';
|
|
8
8
|
import { registerDesignerTools } from './tools/designer/index.js';
|
|
9
|
+
import { registerDataTools } from './tools/data/index.js';
|
|
10
|
+
import { registerKeyTools } from './tools/key/index.js';
|
|
11
|
+
import { registerProjectTools } from './tools/project/index.js';
|
|
9
12
|
const SERVER_NAME = 'restforge-mcp';
|
|
10
13
|
// Read the version from package.json at runtime so the advertised server version
|
|
11
14
|
// never drifts from the published package version. createRequire resolves the JSON
|
|
@@ -218,8 +221,10 @@ that is NOT covered by an available catalog tool:
|
|
|
218
221
|
2. Do NOT guess based on similar frameworks.
|
|
219
222
|
3. Either:
|
|
220
223
|
(a) Acknowledge that the specific information is not available via
|
|
221
|
-
this MCP server and suggest consulting the canonical
|
|
222
|
-
https://
|
|
224
|
+
this MCP server and suggest consulting the canonical, up-to-date
|
|
225
|
+
RESTForge handbook at https://github.com/restforge/handbook.
|
|
226
|
+
(Do NOT point users to https://restforge.dev/docs — that site is
|
|
227
|
+
outdated; the GitHub handbook is the live source of truth.)
|
|
223
228
|
(b) Ask the user to clarify if the question can be reframed to
|
|
224
229
|
match an available catalog tool.
|
|
225
230
|
|
|
@@ -279,11 +284,19 @@ build or generate a frontend UDF, route along this flow:
|
|
|
279
284
|
codegen_migrate_payload -> designer_get_udf_catalog ->
|
|
280
285
|
designer_validate_payload -> designer_preview_files -> designer_generate
|
|
281
286
|
|
|
282
|
-
-
|
|
283
|
-
'codegen_migrate_payload'
|
|
284
|
-
|
|
285
|
-
'
|
|
286
|
-
|
|
287
|
+
- CREATING a UDF — START HERE (firm rule): the FIRST path to produce a UDF
|
|
288
|
+
is ALWAYS 'codegen_migrate_payload'. RESTForge is backend-first; a UDF is
|
|
289
|
+
normally DERIVED from an existing backend payload (RDF), not written by
|
|
290
|
+
hand. 'codegen_migrate_payload' converts an existing RDF into a split
|
|
291
|
+
multi-file UDF set (this verb belongs to the backend 'restforge' CLI, so it
|
|
292
|
+
lives in the codegen domain even though its output is a UDF).
|
|
293
|
+
- Do NOT hand-author a UDF from scratch (writing the JSON yourself) when a
|
|
294
|
+
backend RDF payload exists. Convert it with 'codegen_migrate_payload'
|
|
295
|
+
first, then refine the generated UDF.
|
|
296
|
+
- Author a UDF from scratch (grounded by 'designer_get_udf_catalog') ONLY
|
|
297
|
+
when there is genuinely no backend RDF to migrate from. If unsure whether
|
|
298
|
+
an RDF exists, ask the user or look for the backend 'payload/' directory
|
|
299
|
+
BEFORE hand-authoring.
|
|
287
300
|
- Grounding: the authoritative structure and rules of a UDF (valid field
|
|
288
301
|
types, required appConfig fields, enums, limits, dashboard widget/chart/
|
|
289
302
|
data-source options) come from 'designer_get_udf_catalog', which is
|
|
@@ -295,6 +308,35 @@ build or generate a frontend UDF, route along this flow:
|
|
|
295
308
|
- Then validate ('designer_validate_payload'), preview
|
|
296
309
|
('designer_preview_files'), and finally generate ('designer_generate'),
|
|
297
310
|
pointing those at the aggregator UDF file, not the page fragments.
|
|
311
|
+
|
|
312
|
+
INTERACTIVE COMMANDS — knowledge only, NOT wrapped as tools:
|
|
313
|
+
Some restforge commands are interactive and are intentionally NOT exposed as
|
|
314
|
+
tools. When the user asks about them, EXPLAIN what they do and give the exact
|
|
315
|
+
command for the user to run themselves in their terminal — this server cannot
|
|
316
|
+
drive the interactive prompts.
|
|
317
|
+
|
|
318
|
+
- 'fast-track' — command: npx restforge fast-track --project=<name> --schema-path=<dir> [--config=<file>] [--license=<KEY>] [--overwrite]
|
|
319
|
+
Purpose: a single interactive flow that scaffolds a full REST API (and
|
|
320
|
+
optionally the frontend app) from an SDF. It does NOT add new generation
|
|
321
|
+
logic; it ORCHESTRATES the existing restforge steps in order: write env (init
|
|
322
|
+
if needed) -> validate --auto-create-db -> config set-default -> schema
|
|
323
|
+
migrate -> payload generate -> payload sync --expand-fk -> endpoint create,
|
|
324
|
+
then (if frontend scope) migrate RDF->UDF -> designer generate, and finally
|
|
325
|
+
writes a server-start launcher.
|
|
326
|
+
Interactive prompts: license + DB params, a scope menu (1 = REST API only,
|
|
327
|
+
2 = REST API + frontend), and a confirmation. Because of these prompts it
|
|
328
|
+
cannot be invoked by this server.
|
|
329
|
+
How to help the user:
|
|
330
|
+
* When the user wants the FASTEST path from an SDF to a running app, tell them
|
|
331
|
+
to run the command above in their terminal and walk them through the prompts
|
|
332
|
+
(license, database, scope choice, confirm).
|
|
333
|
+
* '--overwrite' is DESTRUCTIVE (drops tables and regenerates) — warn before
|
|
334
|
+
suggesting it.
|
|
335
|
+
* If the user prefers a non-interactive / step-by-step path, the same pipeline
|
|
336
|
+
can be reproduced with the individual tools: schema migrate -> generate
|
|
337
|
+
payload -> sync payload (expand FK) -> create endpoint, then (frontend)
|
|
338
|
+
codegen_migrate_payload -> designer validate/preview/generate. Offer this as
|
|
339
|
+
the automatable alternative to fast-track.
|
|
298
340
|
`.trim();
|
|
299
341
|
export async function startServer() {
|
|
300
342
|
const server = new McpServer({
|
|
@@ -308,6 +350,9 @@ export async function startServer() {
|
|
|
308
350
|
registerCodegenTools(server);
|
|
309
351
|
registerRuntimeTools(server);
|
|
310
352
|
registerDesignerTools(server);
|
|
353
|
+
registerDataTools(server);
|
|
354
|
+
registerKeyTools(server);
|
|
355
|
+
registerProjectTools(server);
|
|
311
356
|
const transport = new StdioServerTransport();
|
|
312
357
|
await server.connect(transport);
|
|
313
358
|
}
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAEhE,MAAM,WAAW,GAAG,eAAe,CAAC;AAEpC,iFAAiF;AACjF,mFAAmF;AACnF,6EAA6E;AAC7E,mFAAmF;AACnF,gFAAgF;AAChF,kFAAkF;AAClF,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAwB,CAAC;AAEtF,MAAM,mBAAmB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+T3B,CAAC,IAAI,EAAE,CAAC;AAET,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B;QACE,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,cAAc;KACxB,EACD;QACE,YAAY,EAAE,mBAAmB;KAClC,CACF,CAAC;IAEF,mBAAmB,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC5C,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC3B,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAC9B,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC1B,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACzB,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAE7B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { access } from 'node:fs/promises';
|
|
3
|
+
import { resolve, join } from 'node:path';
|
|
4
|
+
import { execProcess } from '../../lib/exec.js';
|
|
5
|
+
export function registerCodegenCreateKafkaConsumer(server) {
|
|
6
|
+
server.registerTool('codegen_create_kafka_consumer', {
|
|
7
|
+
title: 'Create Kafka Consumer',
|
|
8
|
+
description: `Generate Kafka consumer source code from a payload JSON file, by wrapping restforge kafka consumer-create. The output is written under src/consumers/<project>/<name>/ and is later run by the internal 'restforge-consumer' binary.
|
|
9
|
+
|
|
10
|
+
USE WHEN:
|
|
11
|
+
- The user wants to create or scaffold a Kafka consumer from a consumer payload, e.g. "buat kafka consumer", "generate consumer", "create kafka consumer dari payload"
|
|
12
|
+
- The user has a consumer payload JSON and wants the matching consumer code generated into a backend project
|
|
13
|
+
- The user mentions consuming Kafka topics/events and needs the handler scaffolded
|
|
14
|
+
|
|
15
|
+
DO NOT USE FOR:
|
|
16
|
+
- Generating a REST endpoint -> use 'codegen_create_endpoint'
|
|
17
|
+
- Generating a processor / background job -> use 'codegen_create_processor'
|
|
18
|
+
- Deploying or running the consumer -> out of scope (the generated code is run by the internal 'restforge-consumer' binary, not this server)
|
|
19
|
+
|
|
20
|
+
This tool runs: npx restforge kafka consumer-create --project=<project> --name=<name> --payload=<payload> [--force] in the given cwd.
|
|
21
|
+
|
|
22
|
+
Preconditions:
|
|
23
|
+
- The project must have @restforgejs/platform installed in node_modules.
|
|
24
|
+
- The named consumer payload JSON must exist. This tool does not pre-check it — if the CLI fails, the failure response surfaces the cause.
|
|
25
|
+
- Without 'force', the command fails if the consumer files already exist.
|
|
26
|
+
|
|
27
|
+
PRESENTATION GUIDANCE:
|
|
28
|
+
- Match the user's language. If the user writes in Indonesian, respond in Indonesian.
|
|
29
|
+
- Never mention internal tool names in the reply to the user. Describe actions by what they do (e.g. "generate the Kafka consumer").
|
|
30
|
+
- Speak in plain language; summarise the result. Do not paste raw CLI output unless the user explicitly asks.
|
|
31
|
+
- Mention that the generated consumer is run separately by the internal consumer runtime, not by this assistant.
|
|
32
|
+
- When a precondition is not met, frame it as a question or next-step suggestion rather than an error.`,
|
|
33
|
+
inputSchema: {
|
|
34
|
+
cwd: z
|
|
35
|
+
.string()
|
|
36
|
+
.min(1)
|
|
37
|
+
.describe('Absolute path of the backend project folder (must contain node_modules/@restforgejs/platform)'),
|
|
38
|
+
project: z.string().min(1).describe('Target project name. REQUIRED.'),
|
|
39
|
+
name: z.string().min(1).describe('Consumer name to create. REQUIRED.'),
|
|
40
|
+
payload: z
|
|
41
|
+
.string()
|
|
42
|
+
.min(1)
|
|
43
|
+
.describe('Path or file name of the consumer payload JSON. REQUIRED.'),
|
|
44
|
+
force: z
|
|
45
|
+
.boolean()
|
|
46
|
+
.optional()
|
|
47
|
+
.describe('Overwrite existing consumer files. Without it, the command fails if the files already exist.'),
|
|
48
|
+
},
|
|
49
|
+
annotations: {
|
|
50
|
+
title: 'Create Kafka Consumer',
|
|
51
|
+
readOnlyHint: false,
|
|
52
|
+
idempotentHint: false,
|
|
53
|
+
destructiveHint: false,
|
|
54
|
+
},
|
|
55
|
+
}, async ({ cwd, project, name, payload, force }) => {
|
|
56
|
+
const projectCwd = resolve(cwd);
|
|
57
|
+
try {
|
|
58
|
+
await access(join(projectCwd, 'node_modules', '@restforgejs', 'platform'));
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return {
|
|
62
|
+
content: [
|
|
63
|
+
{
|
|
64
|
+
type: 'text',
|
|
65
|
+
text: `Precondition not met: the RESTForge package is not installed in this project.
|
|
66
|
+
|
|
67
|
+
Project path: ${projectCwd}
|
|
68
|
+
Expected location: node_modules/@restforgejs/platform
|
|
69
|
+
Requested consumer: ${name}
|
|
70
|
+
Requested payload: ${payload}
|
|
71
|
+
|
|
72
|
+
For the assistant:
|
|
73
|
+
- The user needs to install the RESTForge package before a Kafka consumer can be generated.
|
|
74
|
+
- Suggest installing the package first, then retry. When explaining, say something like "the RESTForge package isn't installed yet — should I install it first?". Do not mention internal tool names.`,
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
isError: false,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
const args = ['restforge', 'kafka', 'consumer-create', `--project=${project}`, `--name=${name}`, `--payload=${payload}`];
|
|
81
|
+
if (force)
|
|
82
|
+
args.push('--force');
|
|
83
|
+
const result = await execProcess('npx', args, { cwd: projectCwd, timeout: 60_000 });
|
|
84
|
+
if (!result.success) {
|
|
85
|
+
return {
|
|
86
|
+
content: [
|
|
87
|
+
{
|
|
88
|
+
type: 'text',
|
|
89
|
+
text: `Failed to create the Kafka consumer.
|
|
90
|
+
|
|
91
|
+
Project path: ${projectCwd}
|
|
92
|
+
Project: ${project}
|
|
93
|
+
Consumer: ${name}
|
|
94
|
+
Payload: ${payload}
|
|
95
|
+
Command: ${result.command}
|
|
96
|
+
Exit code: ${result.exitCode}
|
|
97
|
+
|
|
98
|
+
--- CLI output ---
|
|
99
|
+
stdout:
|
|
100
|
+
${result.stdout}
|
|
101
|
+
|
|
102
|
+
stderr:
|
|
103
|
+
${result.stderr}
|
|
104
|
+
--- end CLI output ---
|
|
105
|
+
|
|
106
|
+
For the assistant:
|
|
107
|
+
- Tell the user the Kafka consumer was not generated successfully.
|
|
108
|
+
- Summarise the most likely cause from the CLI output in plain language (common causes: the payload file was not found, the payload is invalid, the consumer files already exist without force, or the target project does not exist). Do not paste raw output unless the user asks.
|
|
109
|
+
- Offer to retry once the issue is resolved. Do not mention internal tool names.`,
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
isError: true,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
content: [
|
|
117
|
+
{
|
|
118
|
+
type: 'text',
|
|
119
|
+
text: `Kafka consumer created.
|
|
120
|
+
|
|
121
|
+
Project path: ${projectCwd}
|
|
122
|
+
Project: ${project}
|
|
123
|
+
Consumer: ${name}
|
|
124
|
+
Payload: ${payload}
|
|
125
|
+
Command: ${result.command}
|
|
126
|
+
|
|
127
|
+
--- CLI output ---
|
|
128
|
+
${result.stdout}
|
|
129
|
+
--- end CLI output ---
|
|
130
|
+
|
|
131
|
+
For the assistant:
|
|
132
|
+
- Confirm the Kafka consumer source was generated under src/consumers/<project>/<name>/.
|
|
133
|
+
- Mention that the consumer is run separately by the internal consumer runtime (restforge-consumer), not by this assistant.
|
|
134
|
+
- Keep the reply concise. Do not paste raw CLI output unless the user explicitly asks. Do not mention internal tool names.`,
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
};
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=create-kafka-consumer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-kafka-consumer.js","sourceRoot":"","sources":["../../../src/tools/codegen/create-kafka-consumer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { access } from 'node:fs/promises';
|
|
3
|
+
import { resolve, join } from 'node:path';
|
|
4
|
+
import { execProcess } from '../../lib/exec.js';
|
|
5
|
+
export function registerCodegenCreateProcessor(server) {
|
|
6
|
+
server.registerTool('codegen_create_processor', {
|
|
7
|
+
title: 'Create Processor Module',
|
|
8
|
+
description: `Generate a processor (a background job / custom business-logic handler) from a payload JSON file, by wrapping restforge processor create. The processor exposes an endpoint whose router + metadata is always regenerated, while the implementation file holds the custom business logic.
|
|
9
|
+
|
|
10
|
+
USE WHEN:
|
|
11
|
+
- The user wants to create or scaffold a processor, background job, or custom business-logic handler from a processor payload, e.g. "buat processor", "generate processor", "create background job", "scaffold business logic handler"
|
|
12
|
+
- The user has a processor payload JSON and wants the matching code generated into a backend project
|
|
13
|
+
- The user wants to re-generate a processor's routing while keeping their hand-written logic (re-run WITHOUT force preserves custom code)
|
|
14
|
+
|
|
15
|
+
DO NOT USE FOR:
|
|
16
|
+
- Generating a standard REST endpoint from a payload -> use 'codegen_create_endpoint'
|
|
17
|
+
- Generating a dashboard endpoint -> use 'codegen_create_dashboard'
|
|
18
|
+
- Generating a Kafka consumer -> use 'codegen_create_kafka_consumer'
|
|
19
|
+
- Generating a backend payload from a database table -> use 'codegen_generate_payload'
|
|
20
|
+
|
|
21
|
+
This tool runs: npx restforge processor create --project=<project> --name=<name> --payload=<payload> [--database] [--force] [--skip-sql-validation] in the given cwd.
|
|
22
|
+
|
|
23
|
+
Re-run behavior (important):
|
|
24
|
+
- WITHOUT 'force': the endpoint router + metadata are regenerated, but the processor implementation file is SKIPPED ("custom code preserved") — safe to re-run to refresh routing without losing hand-written logic.
|
|
25
|
+
- WITH 'force': the implementation file is archived first, then overwritten with a fresh scaffold — custom code survives only in the archive.
|
|
26
|
+
|
|
27
|
+
Preconditions:
|
|
28
|
+
- The project must have @restforgejs/platform installed in node_modules.
|
|
29
|
+
- The named processor payload JSON must exist. This tool does not pre-check it — if the CLI fails, the failure response surfaces the cause.
|
|
30
|
+
|
|
31
|
+
PRESENTATION GUIDANCE:
|
|
32
|
+
- Match the user's language. If the user writes in Indonesian, respond in Indonesian.
|
|
33
|
+
- Never mention internal tool names in the reply to the user. Describe actions by what they do (e.g. "generate the processor", "regenerate the routing").
|
|
34
|
+
- Speak in plain language; summarise the result. Do not paste raw CLI output unless the user explicitly asks.
|
|
35
|
+
- If the user wants to overwrite existing custom implementation, warn that without archiving they would lose hand-written logic; 'force' archives the old file before overwriting.
|
|
36
|
+
- When a precondition is not met, frame it as a question or next-step suggestion rather than an error.`,
|
|
37
|
+
inputSchema: {
|
|
38
|
+
cwd: z
|
|
39
|
+
.string()
|
|
40
|
+
.min(1)
|
|
41
|
+
.describe('Absolute path of the backend project folder (must contain node_modules/@restforgejs/platform)'),
|
|
42
|
+
project: z.string().min(1).describe('Target project name. REQUIRED.'),
|
|
43
|
+
name: z.string().min(1).describe('Processor name (also the endpoint name). REQUIRED.'),
|
|
44
|
+
payload: z
|
|
45
|
+
.string()
|
|
46
|
+
.min(1)
|
|
47
|
+
.describe('Path or file name of the processor payload JSON. REQUIRED.'),
|
|
48
|
+
database: z
|
|
49
|
+
.enum(['postgres', 'mysql', 'oracle', 'sqlite'])
|
|
50
|
+
.optional()
|
|
51
|
+
.describe('Database type. When omitted, the CLI uses its default (postgres / auto-detect).'),
|
|
52
|
+
force: z
|
|
53
|
+
.boolean()
|
|
54
|
+
.optional()
|
|
55
|
+
.describe('Archive then overwrite an existing processor implementation file. Without it, the implementation file is preserved (only routing/metadata regenerate).'),
|
|
56
|
+
skipSqlValidation: z
|
|
57
|
+
.boolean()
|
|
58
|
+
.optional()
|
|
59
|
+
.describe('Skip SQL keyword validation. When omitted, the CLI validates SQL as usual.'),
|
|
60
|
+
},
|
|
61
|
+
annotations: {
|
|
62
|
+
title: 'Create Processor Module',
|
|
63
|
+
readOnlyHint: false,
|
|
64
|
+
idempotentHint: false,
|
|
65
|
+
destructiveHint: false,
|
|
66
|
+
},
|
|
67
|
+
}, async ({ cwd, project, name, payload, database, force, skipSqlValidation }) => {
|
|
68
|
+
const projectCwd = resolve(cwd);
|
|
69
|
+
try {
|
|
70
|
+
await access(join(projectCwd, 'node_modules', '@restforgejs', 'platform'));
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return {
|
|
74
|
+
content: [
|
|
75
|
+
{
|
|
76
|
+
type: 'text',
|
|
77
|
+
text: `Precondition not met: the RESTForge package is not installed in this project.
|
|
78
|
+
|
|
79
|
+
Project path: ${projectCwd}
|
|
80
|
+
Expected location: node_modules/@restforgejs/platform
|
|
81
|
+
Requested processor: ${name}
|
|
82
|
+
Requested payload: ${payload}
|
|
83
|
+
|
|
84
|
+
For the assistant:
|
|
85
|
+
- The user needs to install the RESTForge package before a processor can be generated.
|
|
86
|
+
- Suggest installing the package first, then retry. When explaining, say something like "the RESTForge package isn't installed yet — should I install it first?". Do not mention internal tool names.`,
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
isError: false,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
const args = ['restforge', 'processor', 'create', `--project=${project}`, `--name=${name}`, `--payload=${payload}`];
|
|
93
|
+
if (database)
|
|
94
|
+
args.push(`--database=${database}`);
|
|
95
|
+
if (force)
|
|
96
|
+
args.push('--force');
|
|
97
|
+
if (skipSqlValidation)
|
|
98
|
+
args.push('--skip-sql-validation');
|
|
99
|
+
const result = await execProcess('npx', args, { cwd: projectCwd, timeout: 60_000 });
|
|
100
|
+
if (!result.success) {
|
|
101
|
+
return {
|
|
102
|
+
content: [
|
|
103
|
+
{
|
|
104
|
+
type: 'text',
|
|
105
|
+
text: `Failed to create the processor.
|
|
106
|
+
|
|
107
|
+
Project path: ${projectCwd}
|
|
108
|
+
Project: ${project}
|
|
109
|
+
Processor: ${name}
|
|
110
|
+
Payload: ${payload}
|
|
111
|
+
Command: ${result.command}
|
|
112
|
+
Exit code: ${result.exitCode}
|
|
113
|
+
|
|
114
|
+
--- CLI output ---
|
|
115
|
+
stdout:
|
|
116
|
+
${result.stdout}
|
|
117
|
+
|
|
118
|
+
stderr:
|
|
119
|
+
${result.stderr}
|
|
120
|
+
--- end CLI output ---
|
|
121
|
+
|
|
122
|
+
For the assistant:
|
|
123
|
+
- Tell the user the processor was not generated successfully.
|
|
124
|
+
- Summarise the most likely cause from the CLI output in plain language (common causes: the payload file was not found, the payload is invalid, SQL validation failed, or the target project does not exist). Do not paste raw output unless the user asks.
|
|
125
|
+
- Offer to retry once the issue is resolved. Do not mention internal tool names.`,
|
|
126
|
+
},
|
|
127
|
+
],
|
|
128
|
+
isError: true,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
content: [
|
|
133
|
+
{
|
|
134
|
+
type: 'text',
|
|
135
|
+
text: `Processor created.
|
|
136
|
+
|
|
137
|
+
Project path: ${projectCwd}
|
|
138
|
+
Project: ${project}
|
|
139
|
+
Processor: ${name}
|
|
140
|
+
Payload: ${payload}
|
|
141
|
+
Force: ${force ? 'yes (old implementation archived then overwritten)' : 'no (existing implementation preserved)'}
|
|
142
|
+
Command: ${result.command}
|
|
143
|
+
|
|
144
|
+
--- CLI output ---
|
|
145
|
+
${result.stdout}
|
|
146
|
+
--- end CLI output ---
|
|
147
|
+
|
|
148
|
+
For the assistant:
|
|
149
|
+
- Confirm the processor was generated. Mention the endpoint routing/metadata was (re)generated.
|
|
150
|
+
- If this was a re-run without force, note that any existing custom implementation was preserved. If force was used, note the old implementation was archived before being overwritten.
|
|
151
|
+
- Keep the reply concise. Do not paste raw CLI output unless the user explicitly asks. Do not mention internal tool names.`,
|
|
152
|
+
},
|
|
153
|
+
],
|
|
154
|
+
};
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=create-processor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-processor.js","sourceRoot":"","sources":["../../../src/tools/codegen/create-processor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { access } from 'node:fs/promises';
|
|
3
|
+
import { resolve, join } from 'node:path';
|
|
4
|
+
import { execProcess } from '../../lib/exec.js';
|
|
5
|
+
export function registerCodegenGenerateTest(server) {
|
|
6
|
+
server.registerTool('codegen_generate_test', {
|
|
7
|
+
title: 'Generate Integration Test',
|
|
8
|
+
description: `Generate a Jest + Supertest integration test file for an EXISTING endpoint, by wrapping restforge test generate.
|
|
9
|
+
|
|
10
|
+
USE WHEN:
|
|
11
|
+
- The user wants to generate, scaffold, or create an integration test for an existing endpoint, e.g. "generate test untuk endpoint", "buat integration test", "scaffold jest test", "create supertest test"
|
|
12
|
+
- The user just generated an endpoint and now wants its test
|
|
13
|
+
- The user wants to initialise the Jest test-data configuration for a project (with 'init')
|
|
14
|
+
|
|
15
|
+
DO NOT USE FOR:
|
|
16
|
+
- Generating the endpoint itself -> use 'codegen_create_endpoint'
|
|
17
|
+
- Running the tests -> out of scope (the user runs the generated tests with their own test runner)
|
|
18
|
+
- Validating a payload or SQL -> use 'codegen_validate_payload' / 'codegen_validate_sql'
|
|
19
|
+
|
|
20
|
+
This tool runs: npx restforge test generate --project=<project> --endpoint=<endpoint> [--port] [--init] [--force] in the given cwd.
|
|
21
|
+
|
|
22
|
+
Preconditions:
|
|
23
|
+
- The project must have @restforgejs/platform installed in node_modules.
|
|
24
|
+
- The named endpoint must already exist in the project. This tool does not pre-check it — if the CLI fails, the failure response surfaces the cause.
|
|
25
|
+
|
|
26
|
+
PRESENTATION GUIDANCE:
|
|
27
|
+
- Match the user's language. If the user writes in Indonesian, respond in Indonesian.
|
|
28
|
+
- Never mention internal tool names in the reply to the user. Describe actions by what they do (e.g. "generate the integration test").
|
|
29
|
+
- Speak in plain language; summarise the result. Do not paste raw CLI output unless the user explicitly asks.
|
|
30
|
+
- On the first test for a project, suggest using 'init' to set up the Jest test-data configuration.
|
|
31
|
+
- When a precondition is not met, frame it as a question or next-step suggestion rather than an error.`,
|
|
32
|
+
inputSchema: {
|
|
33
|
+
cwd: z
|
|
34
|
+
.string()
|
|
35
|
+
.min(1)
|
|
36
|
+
.describe('Absolute path of the backend project folder (must contain node_modules/@restforgejs/platform)'),
|
|
37
|
+
project: z.string().min(1).describe('Target project name. REQUIRED.'),
|
|
38
|
+
endpoint: z.string().min(1).describe('Name of the existing endpoint to test. REQUIRED.'),
|
|
39
|
+
port: z
|
|
40
|
+
.number()
|
|
41
|
+
.int()
|
|
42
|
+
.min(1)
|
|
43
|
+
.max(65535)
|
|
44
|
+
.optional()
|
|
45
|
+
.describe('Server port used when the test runs. When omitted, the CLI uses its default (3000).'),
|
|
46
|
+
init: z
|
|
47
|
+
.boolean()
|
|
48
|
+
.optional()
|
|
49
|
+
.describe('Initialise the Jest test-data configuration (global + per-endpoint) if not present. Use on the first test for a project.'),
|
|
50
|
+
force: z
|
|
51
|
+
.boolean()
|
|
52
|
+
.optional()
|
|
53
|
+
.describe('Overwrite an existing test file. Without it, the command will not replace an existing test.'),
|
|
54
|
+
},
|
|
55
|
+
annotations: {
|
|
56
|
+
title: 'Generate Integration Test',
|
|
57
|
+
readOnlyHint: false,
|
|
58
|
+
idempotentHint: false,
|
|
59
|
+
destructiveHint: false,
|
|
60
|
+
},
|
|
61
|
+
}, async ({ cwd, project, endpoint, port, init, force }) => {
|
|
62
|
+
const projectCwd = resolve(cwd);
|
|
63
|
+
try {
|
|
64
|
+
await access(join(projectCwd, 'node_modules', '@restforgejs', 'platform'));
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return {
|
|
68
|
+
content: [
|
|
69
|
+
{
|
|
70
|
+
type: 'text',
|
|
71
|
+
text: `Precondition not met: the RESTForge package is not installed in this project.
|
|
72
|
+
|
|
73
|
+
Project path: ${projectCwd}
|
|
74
|
+
Expected location: node_modules/@restforgejs/platform
|
|
75
|
+
Requested endpoint: ${endpoint}
|
|
76
|
+
|
|
77
|
+
For the assistant:
|
|
78
|
+
- The user needs to install the RESTForge package before an integration test can be generated.
|
|
79
|
+
- Suggest installing the package first, then retry. When explaining, say something like "the RESTForge package isn't installed yet — should I install it first?". Do not mention internal tool names.`,
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
isError: false,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const args = ['restforge', 'test', 'generate', `--project=${project}`, `--endpoint=${endpoint}`];
|
|
86
|
+
if (port !== undefined)
|
|
87
|
+
args.push(`--port=${port}`);
|
|
88
|
+
if (init)
|
|
89
|
+
args.push('--init');
|
|
90
|
+
if (force)
|
|
91
|
+
args.push('--force');
|
|
92
|
+
const result = await execProcess('npx', args, { cwd: projectCwd, timeout: 60_000 });
|
|
93
|
+
if (!result.success) {
|
|
94
|
+
return {
|
|
95
|
+
content: [
|
|
96
|
+
{
|
|
97
|
+
type: 'text',
|
|
98
|
+
text: `Failed to generate the integration test.
|
|
99
|
+
|
|
100
|
+
Project path: ${projectCwd}
|
|
101
|
+
Project: ${project}
|
|
102
|
+
Endpoint: ${endpoint}
|
|
103
|
+
Command: ${result.command}
|
|
104
|
+
Exit code: ${result.exitCode}
|
|
105
|
+
|
|
106
|
+
--- CLI output ---
|
|
107
|
+
stdout:
|
|
108
|
+
${result.stdout}
|
|
109
|
+
|
|
110
|
+
stderr:
|
|
111
|
+
${result.stderr}
|
|
112
|
+
--- end CLI output ---
|
|
113
|
+
|
|
114
|
+
For the assistant:
|
|
115
|
+
- Tell the user the integration test was not generated successfully.
|
|
116
|
+
- Summarise the most likely cause from the CLI output in plain language (common causes: the endpoint does not exist yet, the project does not exist, or an existing test blocks generation without force). Do not paste raw output unless the user asks.
|
|
117
|
+
- Offer to retry once the issue is resolved. Do not mention internal tool names.`,
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
isError: true,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
content: [
|
|
125
|
+
{
|
|
126
|
+
type: 'text',
|
|
127
|
+
text: `Integration test generated.
|
|
128
|
+
|
|
129
|
+
Project path: ${projectCwd}
|
|
130
|
+
Project: ${project}
|
|
131
|
+
Endpoint: ${endpoint}
|
|
132
|
+
Port: ${port ?? 'default (3000)'}
|
|
133
|
+
Init: ${init ? 'yes' : 'no'}
|
|
134
|
+
Command: ${result.command}
|
|
135
|
+
|
|
136
|
+
--- CLI output ---
|
|
137
|
+
${result.stdout}
|
|
138
|
+
--- end CLI output ---
|
|
139
|
+
|
|
140
|
+
For the assistant:
|
|
141
|
+
- Confirm the Jest + Supertest integration test was generated for the endpoint.
|
|
142
|
+
- Mention the user runs the test with their own test runner; this server does not run it.
|
|
143
|
+
- Keep the reply concise. Do not paste raw CLI output unless the user explicitly asks. Do not mention internal tool names.`,
|
|
144
|
+
},
|
|
145
|
+
],
|
|
146
|
+
};
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=generate-test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-test.js","sourceRoot":"","sources":["../../../src/tools/codegen/generate-test.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,9 @@ import { registerCodegenGetQueryDeclarativeCatalog } from './get-query-declarati
|
|
|
8
8
|
import { registerCodegenGetDashboardCatalog } from './get-dashboard-catalog.js';
|
|
9
9
|
import { registerCodegenCreateEndpoint } from './create-endpoint.js';
|
|
10
10
|
import { registerCodegenCreateDashboard } from './create-dashboard.js';
|
|
11
|
+
import { registerCodegenCreateProcessor } from './create-processor.js';
|
|
12
|
+
import { registerCodegenCreateKafkaConsumer } from './create-kafka-consumer.js';
|
|
13
|
+
import { registerCodegenGenerateTest } from './generate-test.js';
|
|
11
14
|
import { registerCodegenValidateDashboardPayload } from './validate-dashboard-payload.js';
|
|
12
15
|
import { registerCodegenListTables } from './list-tables.js';
|
|
13
16
|
import { registerCodegenDescribeTable } from './describe-table.js';
|
|
@@ -33,6 +36,9 @@ export function registerCodegenTools(server) {
|
|
|
33
36
|
registerCodegenGetDashboardCatalog(server);
|
|
34
37
|
registerCodegenCreateEndpoint(server);
|
|
35
38
|
registerCodegenCreateDashboard(server);
|
|
39
|
+
registerCodegenCreateProcessor(server);
|
|
40
|
+
registerCodegenCreateKafkaConsumer(server);
|
|
41
|
+
registerCodegenGenerateTest(server);
|
|
36
42
|
registerCodegenValidateDashboardPayload(server);
|
|
37
43
|
registerCodegenListTables(server);
|
|
38
44
|
registerCodegenDescribeTable(server);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/codegen/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,8BAA8B,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,8BAA8B,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,6BAA6B,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,wCAAwC,EAAE,MAAM,mCAAmC,CAAC;AAC7F,OAAO,EAAE,yCAAyC,EAAE,MAAM,oCAAoC,CAAC;AAC/F,OAAO,EAAE,kCAAkC,EAAE,MAAM,4BAA4B,CAAC;AAChF,OAAO,EAAE,6BAA6B,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,8BAA8B,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,uCAAuC,EAAE,MAAM,iCAAiC,CAAC;AAC1F,OAAO,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,iCAAiC,EAAE,MAAM,2BAA2B,CAAC;AAC9E,OAAO,EAAE,2BAA2B,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,+BAA+B,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,EAAE,6BAA6B,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,kCAAkC,EAAE,MAAM,4BAA4B,CAAC;AAChF,OAAO,EAAE,iCAAiC,EAAE,MAAM,0BAA0B,CAAC;AAC7E,OAAO,EAAE,8BAA8B,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,2BAA2B,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,+BAA+B,EAAE,MAAM,wBAAwB,CAAC;AAEzE,MAAM,UAAU,oBAAoB,CAAC,MAAiB;IACpD,8BAA8B,CAAC,MAAM,CAAC,CAAC;IACvC,8BAA8B,CAAC,MAAM,CAAC,CAAC;IACvC,0BAA0B,CAAC,MAAM,CAAC,CAAC;IACnC,0BAA0B,CAAC,MAAM,CAAC,CAAC;IACnC,6BAA6B,CAAC,MAAM,CAAC,CAAC;IACtC,wCAAwC,CAAC,MAAM,CAAC,CAAC;IACjD,yCAAyC,CAAC,MAAM,CAAC,CAAC;IAClD,kCAAkC,CAAC,MAAM,CAAC,CAAC;IAC3C,6BAA6B,CAAC,MAAM,CAAC,CAAC;IACtC,8BAA8B,CAAC,MAAM,CAAC,CAAC;IACvC,uCAAuC,CAAC,MAAM,CAAC,CAAC;IAChD,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAClC,4BAA4B,CAAC,MAAM,CAAC,CAAC;IACrC,0BAA0B,CAAC,MAAM,CAAC,CAAC;IACnC,iCAAiC,CAAC,MAAM,CAAC,CAAC;IAC1C,2BAA2B,CAAC,MAAM,CAAC,CAAC;IACpC,+BAA+B,CAAC,MAAM,CAAC,CAAC;IACxC,6BAA6B,CAAC,MAAM,CAAC,CAAC;IACtC,kCAAkC,CAAC,MAAM,CAAC,CAAC;IAC3C,iCAAiC,CAAC,MAAM,CAAC,CAAC;IAC1C,8BAA8B,CAAC,MAAM,CAAC,CAAC;IACvC,2BAA2B,CAAC,MAAM,CAAC,CAAC;IACpC,4BAA4B,CAAC,MAAM,CAAC,CAAC;IACrC,+BAA+B,CAAC,MAAM,CAAC,CAAC;AAC1C,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/codegen/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,7 +7,10 @@ export function registerCodegenMigratePayload(server) {
|
|
|
7
7
|
title: 'Migrate Payload (RDF backend -> UDF frontend)',
|
|
8
8
|
description: `Convert an existing backend payload file (RDF) into a frontend payload (UDF) for RESTForge Designer, by wrapping restforge payload migrate. The output is always a SPLIT multi-file set written into an output directory (app-config.json, one file per page under pages/, and an aggregator <appCode>.json), not a single UDF file. The migrator also auto-discovers JOINed tables, so one JOINed RDF can produce several pages at once.
|
|
9
9
|
|
|
10
|
+
PRIMARY PATH TO CREATE A UDF (firm): this is the FIRST and preferred way to produce a UDF. RESTForge is backend-first — a UDF is normally DERIVED from an existing backend RDF via this tool, not written by hand. Whenever a backend RDF payload exists and the user wants a UDF/frontend, START HERE. Only hand-author a UDF from scratch (grounded by 'designer_get_udf_catalog') when there is genuinely no RDF to migrate from.
|
|
11
|
+
|
|
10
12
|
USE WHEN:
|
|
13
|
+
- The user wants to CREATE or start a frontend UDF and a backend RDF payload exists — this is the default on-ramp, before any hand-authoring
|
|
11
14
|
- The user wants to build a frontend UDF from an existing backend payload, e.g. "buat UDF dari payload backend", "konversi RDF ke UDF", "migrate payload ke frontend", "bikin payload designer dari backend existing"
|
|
12
15
|
- The user has a working backend payload and now wants to start authoring the matching frontend in RESTForge Designer (on-ramp from backend to frontend)
|
|
13
16
|
- The user mentions migrating, converting, or porting a backend payload over to the designer / frontend side
|