servflow-pro 0.1.14
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 +133 -0
- package/install.js +6 -0
- package/lib.js +259 -0
- package/package.json +73 -0
- package/run-servflow-pro.js +6 -0
package/README.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# ServFlow Pro
|
|
2
|
+
|
|
3
|
+
ServFlow Pro is an advanced API workflow orchestration platform that provides enterprise features and enhanced performance capabilities for production environments.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
1. Create a configuration file:
|
|
8
|
+
```bash
|
|
9
|
+
cp config.example.toml config.toml
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
2. Edit `config.toml` with your settings:
|
|
13
|
+
```toml
|
|
14
|
+
[server]
|
|
15
|
+
port = "8080"
|
|
16
|
+
config_folder = "./api-configs"
|
|
17
|
+
integrations_file = "./integrations.yaml"
|
|
18
|
+
env = "production"
|
|
19
|
+
|
|
20
|
+
[dashboard]
|
|
21
|
+
port = "3000"
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
3. Start the server:
|
|
25
|
+
```bash
|
|
26
|
+
# Server only
|
|
27
|
+
./servflow-pro start --config config.toml
|
|
28
|
+
|
|
29
|
+
# Server with dashboard
|
|
30
|
+
./servflow-pro start --config config.toml --dashboard
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Configuration
|
|
34
|
+
|
|
35
|
+
ServFlow Pro uses TOML configuration files. All settings are centralized in a single configuration file.
|
|
36
|
+
|
|
37
|
+
### Configuration Structure
|
|
38
|
+
|
|
39
|
+
```toml
|
|
40
|
+
[server]
|
|
41
|
+
port = "8080" # Server port
|
|
42
|
+
config_folder = "./api-configs" # Directory containing API YAML files
|
|
43
|
+
integrations_file = "./integrations.yaml" # Integrations configuration (optional)
|
|
44
|
+
env = "production" # Environment
|
|
45
|
+
|
|
46
|
+
[dashboard]
|
|
47
|
+
port = "3000" # Dashboard port
|
|
48
|
+
configs_folder = "./api-configs" # Dashboard configs directory (optional)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Required Settings
|
|
52
|
+
|
|
53
|
+
- `server.config_folder`: Directory containing your API configuration YAML files
|
|
54
|
+
|
|
55
|
+
### Optional Settings
|
|
56
|
+
|
|
57
|
+
- `server.port`: Defaults to "8080"
|
|
58
|
+
- `server.integrations_file`: Path to integrations configuration
|
|
59
|
+
- `server.env`: Defaults to "production"
|
|
60
|
+
- `dashboard.port`: Defaults to "3000"
|
|
61
|
+
- `dashboard.configs_folder`: Defaults to `server.config_folder`
|
|
62
|
+
|
|
63
|
+
## Usage
|
|
64
|
+
|
|
65
|
+
### Start Command
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
servflow-pro start --config <path-to-config.toml> [--dashboard [port]]
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Options:**
|
|
72
|
+
- `--config, -c`: Path to TOML configuration file (required)
|
|
73
|
+
- `--dashboard`: Start dashboard interface (uses port from config file)
|
|
74
|
+
|
|
75
|
+
**Examples:**
|
|
76
|
+
```bash
|
|
77
|
+
# Server only
|
|
78
|
+
servflow-pro start --config config.toml
|
|
79
|
+
|
|
80
|
+
# Server with dashboard
|
|
81
|
+
servflow-pro start --config config.toml --dashboard
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Dashboard
|
|
85
|
+
|
|
86
|
+
The dashboard provides a web interface for:
|
|
87
|
+
- Visual workflow building
|
|
88
|
+
- API configuration management
|
|
89
|
+
- Real-time workflow execution
|
|
90
|
+
- Integration testing
|
|
91
|
+
|
|
92
|
+
Access the dashboard at `http://localhost:<dashboard-port>` when enabled.
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
Create a `config.toml` file with your previous settings:
|
|
96
|
+
```toml
|
|
97
|
+
[server]
|
|
98
|
+
port = "8080"
|
|
99
|
+
config_folder = "./api-configs"
|
|
100
|
+
integrations_file = "./integrations.yaml"
|
|
101
|
+
|
|
102
|
+
[dashboard]
|
|
103
|
+
port = "3000"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Project Structure
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
servflow-pro/
|
|
110
|
+
├── cmd/ # CLI commands
|
|
111
|
+
├── dashboard/ # Web dashboard
|
|
112
|
+
├── pkg/ # Core packages
|
|
113
|
+
├── config.example.toml # Example configuration
|
|
114
|
+
└── README.md
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Development
|
|
118
|
+
|
|
119
|
+
### Building
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
go build -o servflow-pro
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Testing
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
go test ./...
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## License
|
|
132
|
+
|
|
133
|
+
ServFlow Pro - Professional API workflow orchestration platform.
|
package/install.js
ADDED
package/lib.js
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
// This file was generated by GoReleaser. DO NOT EDIT.
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import crypto from "crypto";
|
|
4
|
+
import http from "http";
|
|
5
|
+
import https from "https";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import JSZip from "jszip";
|
|
8
|
+
import { x as tarExtract } from "tar";
|
|
9
|
+
import { ProxyAgent } from "proxy-agent";
|
|
10
|
+
import { spawnSync } from "child_process";
|
|
11
|
+
import { fileURLToPath } from "url";
|
|
12
|
+
|
|
13
|
+
const { archives, name, version } = JSON.parse(
|
|
14
|
+
fs.readFileSync(new URL("./package.json", import.meta.url), "utf8"),
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
const agent = new ProxyAgent();
|
|
18
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
|
|
20
|
+
const getArchive = () => {
|
|
21
|
+
let target = `${process.platform}-${process.arch}`;
|
|
22
|
+
const archive = archives[target];
|
|
23
|
+
if (!archive) {
|
|
24
|
+
throw new Error(`No archive available for ${target}`);
|
|
25
|
+
}
|
|
26
|
+
return archive;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const binDir = path.join(__dirname, "bin");
|
|
30
|
+
|
|
31
|
+
async function extractTar(tarPath, binaries, dir, wrappedIn) {
|
|
32
|
+
try {
|
|
33
|
+
const filesToExtract = wrappedIn
|
|
34
|
+
? binaries.map((bin) =>
|
|
35
|
+
path.join(wrappedIn, bin).replace(/\\/g, "/"),
|
|
36
|
+
)
|
|
37
|
+
: binaries;
|
|
38
|
+
|
|
39
|
+
await tarExtract({
|
|
40
|
+
file: tarPath,
|
|
41
|
+
cwd: dir,
|
|
42
|
+
filter: (path) => filesToExtract.includes(path),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// If wrapped, move files from wrapped directory to bin directory
|
|
46
|
+
if (wrappedIn) {
|
|
47
|
+
const wrappedDir = path.join(dir, wrappedIn);
|
|
48
|
+
for (const binary of binaries) {
|
|
49
|
+
const srcPath = path.join(wrappedDir, binary);
|
|
50
|
+
const destPath = path.join(dir, binary);
|
|
51
|
+
if (fs.existsSync(srcPath)) {
|
|
52
|
+
fs.renameSync(srcPath, destPath);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Clean up empty wrapped directory
|
|
56
|
+
try {
|
|
57
|
+
fs.rmSync(wrappedDir, { recursive: true, force: true });
|
|
58
|
+
} catch (err) {
|
|
59
|
+
// Ignore cleanup errors
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
console.log(`Successfully extracted ${binaries} to "${dir}"`);
|
|
64
|
+
} catch (err) {
|
|
65
|
+
throw new Error(`Extraction failed: ${err.message}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function extractZip(zipPath, binaries, dir, wrappedIn) {
|
|
70
|
+
try {
|
|
71
|
+
const zipData = fs.readFileSync(zipPath);
|
|
72
|
+
const zip = await JSZip.loadAsync(zipData);
|
|
73
|
+
|
|
74
|
+
for (const binary of binaries) {
|
|
75
|
+
const binaryPath = wrappedIn
|
|
76
|
+
? path.join(wrappedIn, binary).replace(/\\/g, "/")
|
|
77
|
+
: binary;
|
|
78
|
+
|
|
79
|
+
if (!zip.files[binaryPath]) {
|
|
80
|
+
throw new Error(
|
|
81
|
+
`Error: ${binaryPath} does not exist in ${zipPath}`,
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const content = await zip.files[binaryPath].async("nodebuffer");
|
|
86
|
+
if (!fs.existsSync(dir)) {
|
|
87
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
88
|
+
}
|
|
89
|
+
const file = path.join(dir, binary);
|
|
90
|
+
fs.writeFileSync(file, content);
|
|
91
|
+
fs.chmodSync(file, "755");
|
|
92
|
+
console.log(`Successfully extracted "${binary}" to "${dir}"`);
|
|
93
|
+
}
|
|
94
|
+
} catch (err) {
|
|
95
|
+
throw new Error(`Extraction failed: ${err.message}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const run = async (bin) => {
|
|
100
|
+
await install();
|
|
101
|
+
if (process.platform === "win32") {
|
|
102
|
+
bin += ".exe";
|
|
103
|
+
}
|
|
104
|
+
const [, , ...args] = process.argv;
|
|
105
|
+
let result = spawnSync(path.join(binDir, bin), args, {
|
|
106
|
+
cwd: process.cwd(),
|
|
107
|
+
stdio: "inherit",
|
|
108
|
+
});
|
|
109
|
+
if (result.error) {
|
|
110
|
+
console.error(result.error);
|
|
111
|
+
}
|
|
112
|
+
return result.status;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const install = async () => {
|
|
116
|
+
try {
|
|
117
|
+
let archive = getArchive();
|
|
118
|
+
if (await exists(archive)) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
let tmp = fs.mkdtempSync("archive-");
|
|
122
|
+
let archivePath = path.join(tmp, archive.name);
|
|
123
|
+
await download(archive.url, archivePath);
|
|
124
|
+
verify(archivePath, archive.checksum);
|
|
125
|
+
|
|
126
|
+
if (!fs.existsSync(binDir)) {
|
|
127
|
+
fs.mkdirSync(binDir);
|
|
128
|
+
}
|
|
129
|
+
switch (archive.format) {
|
|
130
|
+
case "binary":
|
|
131
|
+
const bin = path.join(binDir, archive.bins[0]);
|
|
132
|
+
fs.copyFileSync(archivePath, bin);
|
|
133
|
+
fs.chmodSync(bin, 0o755);
|
|
134
|
+
break;
|
|
135
|
+
case "zip":
|
|
136
|
+
await extractZip(
|
|
137
|
+
archivePath,
|
|
138
|
+
archive.bins,
|
|
139
|
+
binDir,
|
|
140
|
+
archive.wrappedIn,
|
|
141
|
+
);
|
|
142
|
+
break;
|
|
143
|
+
case "tar":
|
|
144
|
+
case "tar.gz":
|
|
145
|
+
case "tgz":
|
|
146
|
+
await extractTar(
|
|
147
|
+
archivePath,
|
|
148
|
+
archive.bins,
|
|
149
|
+
binDir,
|
|
150
|
+
archive.wrappedIn,
|
|
151
|
+
);
|
|
152
|
+
break;
|
|
153
|
+
case "tar.zst":
|
|
154
|
+
case "tzst":
|
|
155
|
+
case "tar.xz":
|
|
156
|
+
case "txz":
|
|
157
|
+
default:
|
|
158
|
+
throw new Error(`unsupported format: ${archive.format}`);
|
|
159
|
+
}
|
|
160
|
+
console.log(`Installed ${name} ${version} to ${binDir}`);
|
|
161
|
+
} catch (err) {
|
|
162
|
+
throw new Error(`Installation failed: ${err.message}`);
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const verify = (filename, checksum) => {
|
|
167
|
+
if (checksum.algorithm == "" || checksum.digest == "") {
|
|
168
|
+
console.warn("Warning: No checksum provided for verification");
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
let digest = crypto
|
|
172
|
+
.createHash(checksum.algorithm)
|
|
173
|
+
.update(fs.readFileSync(filename))
|
|
174
|
+
.digest("hex");
|
|
175
|
+
if (digest != checksum.digest) {
|
|
176
|
+
throw new Error(
|
|
177
|
+
`${filename}: ${checksum.algorithm} does not match, expected ${checksum.digest}, got ${digest}`,
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const download = async (url, filename, maxRedirects = 10) => {
|
|
183
|
+
try {
|
|
184
|
+
console.log(`Downloading ${url} to ${filename}...`);
|
|
185
|
+
const dir = path.dirname(filename);
|
|
186
|
+
if (!fs.existsSync(dir)) {
|
|
187
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return new Promise((resolve, reject) => {
|
|
191
|
+
const parsedUrl = new URL(url);
|
|
192
|
+
const mod = parsedUrl.protocol === "https:" ? https : http;
|
|
193
|
+
|
|
194
|
+
const request = mod.get(url, { agent }, (response) => {
|
|
195
|
+
if (
|
|
196
|
+
response.statusCode >= 300 &&
|
|
197
|
+
response.statusCode < 400 &&
|
|
198
|
+
response.headers.location
|
|
199
|
+
) {
|
|
200
|
+
if (maxRedirects <= 0) {
|
|
201
|
+
reject(new Error("Too many redirects"));
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
download(response.headers.location, filename, maxRedirects - 1)
|
|
205
|
+
.then(resolve)
|
|
206
|
+
.catch(reject);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (response.statusCode !== 200) {
|
|
211
|
+
reject(
|
|
212
|
+
new Error(
|
|
213
|
+
`HTTP ${response.statusCode}: ${response.statusMessage}`,
|
|
214
|
+
),
|
|
215
|
+
);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const writer = fs.createWriteStream(filename);
|
|
220
|
+
response.pipe(writer);
|
|
221
|
+
|
|
222
|
+
writer.on("finish", () => {
|
|
223
|
+
console.log(`Download complete: ${filename}`);
|
|
224
|
+
resolve(dir);
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
writer.on("error", (err) => {
|
|
228
|
+
console.error(`Error writing file: ${err.message}`);
|
|
229
|
+
reject(err);
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
request.on("error", (err) => {
|
|
234
|
+
reject(new Error(`Request failed: ${err.message}`));
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
request.setTimeout(300000, () => {
|
|
238
|
+
request.destroy();
|
|
239
|
+
reject(new Error("Request timed out"));
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
} catch (err) {
|
|
243
|
+
throw new Error(`Download failed: ${err.message}`);
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
function exists(archive) {
|
|
248
|
+
if (!fs.existsSync(binDir)) {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
return archive.bins.every((bin) => fs.existsSync(path.join(binDir, bin)));
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export {
|
|
255
|
+
install,
|
|
256
|
+
run,
|
|
257
|
+
getArchive,
|
|
258
|
+
download,
|
|
259
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "servflow-pro",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.1.14",
|
|
5
|
+
"description": "ServFlow Pro - API management and testing tool",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"postinstall": "node install.js",
|
|
8
|
+
"run": "node run-servflow-pro.js"
|
|
9
|
+
},
|
|
10
|
+
"repository": {},
|
|
11
|
+
"author": "Servflow \u003ccontact@servflow.io\u003e",
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"bugs": {},
|
|
14
|
+
"homepage": "https://servflow.io",
|
|
15
|
+
"bin": {
|
|
16
|
+
"servflow-pro": "run-servflow-pro.js"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"jszip": "^3.10.1",
|
|
20
|
+
"proxy-agent": "^7.0.0",
|
|
21
|
+
"tar": "^7.4.3"
|
|
22
|
+
},
|
|
23
|
+
"archives": {
|
|
24
|
+
"darwin-arm64": {
|
|
25
|
+
"name": "servflow-pro_Darwin_arm64.tar.gz",
|
|
26
|
+
"url": "https://github.com/Servflow/servflow-pro/releases/download/v0.1.14/servflow-pro_Darwin_arm64.tar.gz",
|
|
27
|
+
"bins": [
|
|
28
|
+
"servflow-pro"
|
|
29
|
+
],
|
|
30
|
+
"format": "tar.gz",
|
|
31
|
+
"checksum": {
|
|
32
|
+
"algorithm": "sha256",
|
|
33
|
+
"digest": "17944cbf7e7043595a1e83801b06dd6b1cc25760c07310151e81e4839a2e5970"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"darwin-x64": {
|
|
37
|
+
"name": "servflow-pro_Darwin_x86_64.tar.gz",
|
|
38
|
+
"url": "https://github.com/Servflow/servflow-pro/releases/download/v0.1.14/servflow-pro_Darwin_x86_64.tar.gz",
|
|
39
|
+
"bins": [
|
|
40
|
+
"servflow-pro"
|
|
41
|
+
],
|
|
42
|
+
"format": "tar.gz",
|
|
43
|
+
"checksum": {
|
|
44
|
+
"algorithm": "sha256",
|
|
45
|
+
"digest": "2ce4a18aa089fbeb7a5f4575ba1f1696078bb7e31171b3a0d9b2dde31a3677d1"
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"linux-arm64": {
|
|
49
|
+
"name": "servflow-pro_Linux_arm64.tar.gz",
|
|
50
|
+
"url": "https://github.com/Servflow/servflow-pro/releases/download/v0.1.14/servflow-pro_Linux_arm64.tar.gz",
|
|
51
|
+
"bins": [
|
|
52
|
+
"servflow-pro"
|
|
53
|
+
],
|
|
54
|
+
"format": "tar.gz",
|
|
55
|
+
"checksum": {
|
|
56
|
+
"algorithm": "sha256",
|
|
57
|
+
"digest": "ba3fa28af2d9f3bc4d23dc6b80a36a404d9700f2a52154b0222fa4c89947679d"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"linux-x64": {
|
|
61
|
+
"name": "servflow-pro_Linux_x86_64.tar.gz",
|
|
62
|
+
"url": "https://github.com/Servflow/servflow-pro/releases/download/v0.1.14/servflow-pro_Linux_x86_64.tar.gz",
|
|
63
|
+
"bins": [
|
|
64
|
+
"servflow-pro"
|
|
65
|
+
],
|
|
66
|
+
"format": "tar.gz",
|
|
67
|
+
"checksum": {
|
|
68
|
+
"algorithm": "sha256",
|
|
69
|
+
"digest": "f34fd0b37e3f57c6906db38c8d788c2b7174cda7054b295a22689b8fbf1ce9b9"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|