graphjin 3.11.2 → 3.12.0

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 CHANGED
@@ -61,6 +61,7 @@ GraphJin started
61
61
  Web UI: http://localhost:8080/
62
62
  GraphQL: http://localhost:8080/api/v1/graphql
63
63
  REST API: http://localhost:8080/api/v1/rest/
64
+ Workflows: http://localhost:8080/api/v1/workflows/<name>
64
65
  MCP: http://localhost:8080/api/v1/mcp
65
66
 
66
67
  Claude Desktop Configuration
@@ -155,7 +156,8 @@ Copy paste the Claude Desktop Config provided by `graphjin serve` into the Claud
155
156
  1. **Connects to database** - Reads your schema automatically
156
157
  2. **Discovers relationships** - Foreign keys become navigable joins
157
158
  3. **Exposes MCP tools** - Teach any LLM the query syntax
158
- 4. **Compiles to SQL** - Every request becomes a single optimized query
159
+ 4. **Runs JS workflows** - Chain multiple GraphJin MCP tools in one reusable workflow
160
+ 5. **Compiles to SQL** - Every request becomes a single optimized query
159
161
 
160
162
  No resolvers. No ORM. No N+1 queries. Just point and query.
161
163
 
@@ -221,7 +223,45 @@ Works from Node.js, Go, or any WebSocket client.
221
223
 
222
224
  ## MCP Tools
223
225
 
224
- GraphJin exposes several tools that guide AI models to write valid queries. Key tools: `list_tables` and `describe_table` for schema discovery, `get_query_syntax` for learning the DSL, `execute_graphql` for running queries, and `execute_saved_query` for production-approved queries. Prompts like `write_query` and `fix_query_error` help models construct and debug queries.
226
+ GraphJin exposes several tools that guide AI models to write valid queries. Key tools: `list_tables` and `describe_table` for schema discovery, `get_query_syntax` for learning the DSL, `execute_graphql` for running queries, and `execute_saved_query` for production-approved queries.
227
+
228
+ For JS orchestration, use:
229
+ - `get_js_runtime_api` to discover exactly which globals/functions are available inside workflow scripts
230
+ - `execute_workflow` to run `./workflows/<name>.js` with input variables
231
+
232
+ Prompts like `write_query` and `fix_query_error` help models construct and debug queries.
233
+
234
+ ## JS Workflows (MCP + REST)
235
+
236
+ Workflows let an LLM run multi-step logic in JavaScript while still using GraphJin MCP tools for DB-aware operations.
237
+
238
+ Create a file in `./workflows`, for example `./workflows/customer_insights.js`:
239
+
240
+ ```js
241
+ function main(input) {
242
+ const tables = gj.tools.listTables({});
243
+ const top = gj.tools.executeSavedQuery({
244
+ name: "top_customers",
245
+ variables: { limit: input.limit || 5 }
246
+ });
247
+ return { tables, top };
248
+ }
249
+ ```
250
+
251
+ ### Run via MCP
252
+
253
+ Call:
254
+ - `get_js_runtime_api` first (for exact runtime schema)
255
+ - `execute_workflow` with:
256
+ - `name`: workflow file name (with or without `.js`)
257
+ - `variables`: input payload passed to global `input` and `main(input)`
258
+
259
+ ### Run via REST
260
+
261
+ - `POST /api/v1/workflows/<name>` with JSON body
262
+ - `GET /api/v1/workflows/<name>?variables={...json...}`
263
+
264
+ Both map variables to the same workflow input object.
225
265
 
226
266
  ## Chat Walkthroughs
227
267
 
package/bin/graphjin.js CHANGED
@@ -1,10 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
  const { spawn } = require('child_process');
3
3
  const path = require('path');
4
+ const fs = require('fs');
4
5
 
5
6
  const ext = process.platform === 'win32' ? '.exe' : '';
6
7
  const binary = path.join(__dirname, 'graphjin' + ext);
7
8
 
9
+ if (!fs.existsSync(binary)) {
10
+ console.error(`GraphJin binary not found at: ${binary}`);
11
+ console.error('Try reinstalling: npm install -g graphjin');
12
+ process.exit(1);
13
+ }
14
+
8
15
  const child = spawn(binary, process.argv.slice(2), { stdio: 'inherit' });
9
16
 
10
17
  child.on('error', (err) => {
@@ -13,4 +20,10 @@ child.on('error', (err) => {
13
20
  process.exit(1);
14
21
  });
15
22
 
16
- child.on('exit', (code) => process.exit(code || 0));
23
+ child.on('exit', (code, signal) => {
24
+ if (signal) {
25
+ console.error(`graphjin terminated by signal: ${signal}`);
26
+ process.exit(1);
27
+ }
28
+ process.exit(code ?? 0);
29
+ });
package/bin/install.js CHANGED
@@ -39,6 +39,29 @@ async function download(url, dest) {
39
39
  });
40
40
  }
41
41
 
42
+ async function downloadWithFallback(candidates, binDir) {
43
+ let lastErr;
44
+
45
+ for (const candidate of candidates) {
46
+ const archivePath = path.join(binDir, candidate.filename);
47
+
48
+ try {
49
+ await download(candidate.url, archivePath);
50
+ return {
51
+ archivePath,
52
+ filename: candidate.filename,
53
+ };
54
+ } catch (err) {
55
+ lastErr = err;
56
+ try {
57
+ fs.unlinkSync(archivePath);
58
+ } catch {}
59
+ }
60
+ }
61
+
62
+ throw lastErr || new Error('No download candidates available');
63
+ }
64
+
42
65
  async function extract(tarPath, destDir) {
43
66
  // Use tar module for extraction
44
67
  const tar = require('tar');
@@ -62,14 +85,28 @@ async function install() {
62
85
  process.exit(1);
63
86
  }
64
87
 
65
- const ext = platform === 'windows' ? '.zip' : '.tar.gz';
66
- const filename = `graphjin_${platform}_${arch}${ext}`;
67
- const url = `https://github.com/dosco/graphjin/releases/download/v${version}/${filename}`;
68
-
69
88
  const binDir = __dirname;
70
- const archivePath = path.join(binDir, filename);
71
89
  const binaryName = platform === 'windows' ? 'graphjin.exe' : 'graphjin';
72
90
  const binaryPath = path.join(binDir, binaryName);
91
+ const releaseBase = `https://github.com/dosco/graphjin/releases/download/v${version}`;
92
+
93
+ // New releases include version in the archive name. Keep legacy fallback
94
+ // names to remain backward compatible with older tags.
95
+ const filenames = platform === 'windows'
96
+ ? [
97
+ `graphjin_${version}_${platform}_${arch}.tar.gz`,
98
+ `graphjin_${version}_${platform}_${arch}.zip`,
99
+ `graphjin_${platform}_${arch}.tar.gz`,
100
+ `graphjin_${platform}_${arch}.zip`,
101
+ ]
102
+ : [
103
+ `graphjin_${version}_${platform}_${arch}.tar.gz`,
104
+ `graphjin_${platform}_${arch}.tar.gz`,
105
+ ];
106
+ const candidates = filenames.map((filename) => ({
107
+ filename,
108
+ url: `${releaseBase}/${filename}`,
109
+ }));
73
110
 
74
111
  // Skip if binary already exists
75
112
  if (fs.existsSync(binaryPath)) {
@@ -79,12 +116,17 @@ async function install() {
79
116
 
80
117
  console.log(`Downloading GraphJin v${version} for ${platform}/${arch}...`);
81
118
 
119
+ let archivePath = '';
120
+ let selectedFilename = '';
121
+
82
122
  try {
83
- await download(url, archivePath);
123
+ const selected = await downloadWithFallback(candidates, binDir);
124
+ archivePath = selected.archivePath;
125
+ selectedFilename = selected.filename;
84
126
 
85
127
  console.log('Extracting...');
86
128
 
87
- if (platform === 'windows') {
129
+ if (platform === 'windows' && selectedFilename.endsWith('.zip')) {
88
130
  // For Windows, use PowerShell to extract
89
131
  execSync(`powershell -command "Expand-Archive -Path '${archivePath}' -DestinationPath '${binDir}' -Force"`, {
90
132
  stdio: 'inherit',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphjin",
3
- "version": "3.11.2",
3
+ "version": "3.12.0",
4
4
  "description": "GraphJin CLI - Build APIs in 5 minutes with GraphQL",
5
5
  "bin": {
6
6
  "graphjin": "bin/graphjin.js"