diffsurge 0.3.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 +136 -0
- package/bin/surge +55 -0
- package/binaries/surge-darwin-amd64.gz +0 -0
- package/binaries/surge-darwin-arm64.gz +0 -0
- package/binaries/surge-linux-amd64.gz +0 -0
- package/binaries/surge-linux-arm64.gz +0 -0
- package/binaries/surge-windows-amd64.exe.gz +0 -0
- package/install.js +68 -0
- package/package.json +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# diffsurge
|
|
2
|
+
|
|
3
|
+
> Catch breaking API changes before your users do.
|
|
4
|
+
|
|
5
|
+
Diffsurge helps you detect breaking API changes before they reach production.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g diffsurge
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Or use Docker:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
docker run equixankit/diffsurge-cli --help
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Setup
|
|
20
|
+
|
|
21
|
+
1. **Create an API key** in the [Diffsurge dashboard](https://app.diffsurge.com) → Settings → API Keys
|
|
22
|
+
2. **Add it to your `.env` file** in your project root:
|
|
23
|
+
|
|
24
|
+
```env
|
|
25
|
+
SURGE_API_KEY=tvc_live_your_key_here
|
|
26
|
+
SURGE_PROJECT_ID=your-project-uuid
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
3. **Verify it works:**
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
surge whoami
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Commands
|
|
36
|
+
|
|
37
|
+
### `surge whoami`
|
|
38
|
+
|
|
39
|
+
Verify your API key is valid and see account info:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
surge whoami
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### `surge check`
|
|
46
|
+
|
|
47
|
+
Run API checks in your CI/CD pipeline:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# Basic check — validates API key, fetches traffic & schema stats
|
|
51
|
+
surge check --project-id abc-123
|
|
52
|
+
|
|
53
|
+
# With local schema diff — detect breaking changes before deploy
|
|
54
|
+
surge check --project-id abc-123 --schema openapi.yaml --fail-on-breaking
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### `surge diff`
|
|
58
|
+
|
|
59
|
+
Compare two JSON API responses:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
surge diff --old response-v1.json --new response-v2.json
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### `surge schema diff`
|
|
66
|
+
|
|
67
|
+
Compare two OpenAPI/Swagger schema files and detect breaking changes:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
surge schema diff --old api-v1.yaml --new api-v2.yaml --fail-on-breaking
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### `surge replay`
|
|
74
|
+
|
|
75
|
+
Replay captured traffic against a target server:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
surge replay --source captured.json --target http://localhost:8080
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## CI/CD Integration
|
|
82
|
+
|
|
83
|
+
### GitHub Actions
|
|
84
|
+
|
|
85
|
+
```yaml
|
|
86
|
+
name: API Check
|
|
87
|
+
on: [push, pull_request]
|
|
88
|
+
jobs:
|
|
89
|
+
api-check:
|
|
90
|
+
runs-on: ubuntu-latest
|
|
91
|
+
steps:
|
|
92
|
+
- uses: actions/checkout@v4
|
|
93
|
+
- uses: actions/setup-node@v4
|
|
94
|
+
with:
|
|
95
|
+
node-version: 20
|
|
96
|
+
- run: npm install -g diffsurge
|
|
97
|
+
- run: surge check --project-id ${{ secrets.SURGE_PROJECT_ID }}
|
|
98
|
+
env:
|
|
99
|
+
SURGE_API_KEY: ${{ secrets.SURGE_API_KEY }}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### GitLab CI
|
|
103
|
+
|
|
104
|
+
```yaml
|
|
105
|
+
api-check:
|
|
106
|
+
image: node:20
|
|
107
|
+
script:
|
|
108
|
+
- npm install -g diffsurge
|
|
109
|
+
- surge check --project-id $SURGE_PROJECT_ID
|
|
110
|
+
variables:
|
|
111
|
+
SURGE_API_KEY: $SURGE_API_KEY
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Environment Variables
|
|
115
|
+
|
|
116
|
+
| Variable | Description | Default |
|
|
117
|
+
|---|---|---|
|
|
118
|
+
| `SURGE_API_KEY` | Your API key (starts with `tvc_live_`) | — |
|
|
119
|
+
| `SURGE_API_URL` | API base URL | `https://api.diffsurge.com` |
|
|
120
|
+
| `SURGE_PROJECT_ID` | Default project ID | — |
|
|
121
|
+
|
|
122
|
+
All variables can also use the `TVC_` prefix (e.g., `TVC_API_KEY`) as a fallback.
|
|
123
|
+
|
|
124
|
+
## Flags
|
|
125
|
+
|
|
126
|
+
All commands support these global flags:
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
--api-key API key (overrides SURGE_API_KEY)
|
|
130
|
+
--api-url API base URL (overrides SURGE_API_URL)
|
|
131
|
+
--project-id Project ID (overrides SURGE_PROJECT_ID)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## License
|
|
135
|
+
|
|
136
|
+
MIT
|
package/bin/surge
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { execFileSync } = require("child_process");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const os = require("os");
|
|
6
|
+
const fs = require("fs");
|
|
7
|
+
|
|
8
|
+
const isWindows = os.platform() === "win32";
|
|
9
|
+
const binaryName = isWindows ? "surge.exe" : "surge";
|
|
10
|
+
const binaryPath = path.join(__dirname, binaryName);
|
|
11
|
+
|
|
12
|
+
// Load .env from the current working directory and merge into process.env
|
|
13
|
+
function loadDotEnv() {
|
|
14
|
+
const envPath = path.join(process.cwd(), ".env");
|
|
15
|
+
try {
|
|
16
|
+
const content = fs.readFileSync(envPath, "utf8");
|
|
17
|
+
for (const line of content.split("\n")) {
|
|
18
|
+
const trimmed = line.trim();
|
|
19
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
20
|
+
const eqIdx = trimmed.indexOf("=");
|
|
21
|
+
if (eqIdx === -1) continue;
|
|
22
|
+
const key = trimmed.slice(0, eqIdx).trim();
|
|
23
|
+
let val = trimmed.slice(eqIdx + 1).trim();
|
|
24
|
+
// Remove surrounding quotes
|
|
25
|
+
if (
|
|
26
|
+
(val.startsWith('"') && val.endsWith('"')) ||
|
|
27
|
+
(val.startsWith("'") && val.endsWith("'"))
|
|
28
|
+
) {
|
|
29
|
+
val = val.slice(1, -1);
|
|
30
|
+
}
|
|
31
|
+
// Only set if not already in env (real env vars take priority)
|
|
32
|
+
if (!(key in process.env)) {
|
|
33
|
+
process.env[key] = val;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
} catch {
|
|
37
|
+
// .env file not found or unreadable — that's fine
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
loadDotEnv();
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
execFileSync(binaryPath, process.argv.slice(2), {
|
|
45
|
+
stdio: "inherit",
|
|
46
|
+
env: process.env,
|
|
47
|
+
});
|
|
48
|
+
} catch (err) {
|
|
49
|
+
if (err.status !== undefined) {
|
|
50
|
+
process.exit(err.status);
|
|
51
|
+
}
|
|
52
|
+
console.error(`Failed to run surge: ${err.message}`);
|
|
53
|
+
console.error(`Run "npm rebuild diffsurge" to re-download the binary.`);
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/install.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const os = require("os");
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const zlib = require("zlib");
|
|
7
|
+
|
|
8
|
+
function getPlatformBinary() {
|
|
9
|
+
const platform = os.platform();
|
|
10
|
+
const arch = os.arch();
|
|
11
|
+
|
|
12
|
+
const mapping = {
|
|
13
|
+
"darwin-x64": "surge-darwin-amd64",
|
|
14
|
+
"darwin-arm64": "surge-darwin-arm64",
|
|
15
|
+
"linux-x64": "surge-linux-amd64",
|
|
16
|
+
"linux-arm64": "surge-linux-arm64",
|
|
17
|
+
"win32-x64": "surge-windows-amd64.exe",
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const key = `${platform}-${arch}`;
|
|
21
|
+
const binary = mapping[key];
|
|
22
|
+
|
|
23
|
+
if (!binary) {
|
|
24
|
+
console.error(
|
|
25
|
+
`Unsupported platform: ${platform}-${arch}\n` +
|
|
26
|
+
`Supported: ${Object.keys(mapping).join(", ")}\n` +
|
|
27
|
+
`You can use Docker instead: docker run equixankit/diffsurge-cli`
|
|
28
|
+
);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return binary;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function main() {
|
|
36
|
+
const binaryName = getPlatformBinary();
|
|
37
|
+
const isWindows = os.platform() === "win32";
|
|
38
|
+
const binDir = path.join(__dirname, "bin");
|
|
39
|
+
const dest = path.join(binDir, isWindows ? "surge.exe" : "surge");
|
|
40
|
+
|
|
41
|
+
if (fs.existsSync(dest)) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const gzPath = path.join(__dirname, "binaries", `${binaryName}.gz`);
|
|
46
|
+
|
|
47
|
+
if (!fs.existsSync(gzPath)) {
|
|
48
|
+
console.error(`Binary not found: ${gzPath}`);
|
|
49
|
+
console.error(`Use Docker instead: docker run equixankit/diffsurge-cli`);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
fs.mkdirSync(binDir, { recursive: true });
|
|
54
|
+
|
|
55
|
+
console.log(`Installing surge for ${os.platform()}-${os.arch()}...`);
|
|
56
|
+
|
|
57
|
+
const compressed = fs.readFileSync(gzPath);
|
|
58
|
+
const decompressed = zlib.gunzipSync(compressed);
|
|
59
|
+
fs.writeFileSync(dest, decompressed);
|
|
60
|
+
|
|
61
|
+
if (!isWindows) {
|
|
62
|
+
fs.chmodSync(dest, 0o755);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
console.log("surge installed successfully!");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
main();
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "diffsurge",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Diffsurge CLI — API traffic capture, diff, schema comparison, replay, and CI/CD checks with API key auth",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"api",
|
|
7
|
+
"traffic",
|
|
8
|
+
"diff",
|
|
9
|
+
"schema",
|
|
10
|
+
"replay",
|
|
11
|
+
"testing",
|
|
12
|
+
"proxy",
|
|
13
|
+
"cli"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://github.com/ankit12301/tvc#readme",
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/ankit12301/tvc/issues"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "https://github.com/ankit12301/tvc.git"
|
|
22
|
+
},
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"author": "Ankit Mahopatra",
|
|
25
|
+
"bin": {
|
|
26
|
+
"surge": "bin/surge"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"postinstall": "node install.js"
|
|
30
|
+
},
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=16"
|
|
33
|
+
}
|
|
34
|
+
}
|