@duckfly/proxy 1.0.0 → 1.0.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/README.md CHANGED
@@ -43,7 +43,7 @@ After running, the CLI will ask for:
43
43
 
44
44
  | Prompt | Description | Default |
45
45
  |---|---|---|
46
- | **Token** | Your Duckfly application token | |
46
+ | **Token** | Your Duckfly application token | N/D |
47
47
  | **Proxy Port** | Port where the proxy listens | `8080` |
48
48
  | **Target URL** | Your backend API address | `http://localhost:3000` |
49
49
 
package/bin/cli.js CHANGED
@@ -51,9 +51,7 @@ let config = {
51
51
  appUrl: null,
52
52
  domainPackageId: null,
53
53
  proxyPort: 8080,
54
- targetUrl: 'http://localhost:3000',
55
- apiUrl: DUCKFLY_API_URL,
56
- proxyUrl: DUCKFLY_PROXY_URL
54
+ targetUrl: null,
57
55
  };
58
56
 
59
57
  const CONFIG_FILE = path.join(process.cwd(), '.duckfly-proxy.json');
@@ -62,7 +60,8 @@ function loadConfig() {
62
60
  try {
63
61
  if (fs.existsSync(CONFIG_FILE)) {
64
62
  const saved = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
65
- config = { ...config, ...saved };
63
+ const { apiUrl, proxyUrl, ...rest } = saved;
64
+ config = { ...config, ...rest };
66
65
  return true;
67
66
  }
68
67
  } catch (error) {
@@ -73,7 +72,8 @@ function loadConfig() {
73
72
 
74
73
  function saveConfig() {
75
74
  try {
76
- fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
75
+ const { token, appName, appUrl, domainPackageId, proxyPort, targetUrl, hostAlias } = config;
76
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify({ token, appName, appUrl, domainPackageId, proxyPort, targetUrl, hostAlias }, null, 2));
77
77
  } catch (error) {
78
78
  console.log(chalk.yellow('⚠️ Não foi possível salvar a configuração'));
79
79
  }
@@ -85,7 +85,7 @@ async function validateToken(token) {
85
85
  spinner.start();
86
86
 
87
87
  try {
88
- const apiClient = new ApiClient(config.apiUrl, config.proxyUrl, token);
88
+ const apiClient = new ApiClient(DUCKFLY_API_URL, DUCKFLY_PROXY_URL, token);
89
89
  const result = await apiClient.validateToken();
90
90
 
91
91
  spinner.stop(true);
@@ -96,7 +96,6 @@ async function validateToken(token) {
96
96
  console.log(chalk.gray('─'.repeat(60)));
97
97
  console.log(chalk.yellow(' Nome: ') + chalk.white(result.appName));
98
98
  console.log(chalk.yellow(' URL: ') + chalk.white(result.appUrl));
99
- console.log(chalk.yellow(' Package ID: ') + chalk.white(result.domainPackageId));
100
99
  console.log(chalk.gray('─'.repeat(60)) + '\n');
101
100
 
102
101
  config.appName = result.appName;
@@ -143,10 +142,7 @@ async function askQuestions() {
143
142
  }
144
143
  }
145
144
 
146
- config.apiUrl = DUCKFLY_API_URL;
147
- config.proxyUrl = DUCKFLY_PROXY_URL;
148
-
149
- const questions = [
145
+ const { proxyPort } = await inquirer.prompt([
150
146
  {
151
147
  type: 'input',
152
148
  name: 'proxyPort',
@@ -159,12 +155,37 @@ async function askQuestions() {
159
155
  }
160
156
  return true;
161
157
  }
162
- },
158
+ }
159
+ ]);
160
+
161
+ config.proxyPort = proxyPort;
162
+
163
+ // Alias: se o domínio do proxy não bate com o da aplicação, ativa automaticamente
164
+ config.hostAlias = null;
165
+ if (config.appUrl) {
166
+ try {
167
+ const appHost = new URL(config.appUrl).host;
168
+ const proxyHost = `localhost:${config.proxyPort}`;
169
+
170
+ if (appHost && appHost !== proxyHost && appHost !== `127.0.0.1:${config.proxyPort}`) {
171
+ config.hostAlias = appHost;
172
+ console.log('');
173
+ console.log(chalk.blue(' O domínio da aplicação (') + chalk.bold.white(appHost) + chalk.blue(') difere do proxy local.'));
174
+ console.log(chalk.blue(' As requisições capturadas serão enviadas com o domínio ') + chalk.bold.white(appHost));
175
+ console.log(chalk.blue(' para que possam ser processadas corretamente pela aplicação.\n'));
176
+ }
177
+ } catch { }
178
+ }
179
+
180
+ const isWildcard = config.appUrl && config.appUrl.includes('*');
181
+ const defaultTarget = isWildcard ? null : (config.appUrl || config.targetUrl);
182
+
183
+ const { targetUrl } = await inquirer.prompt([
163
184
  {
164
185
  type: 'input',
165
186
  name: 'targetUrl',
166
187
  message: chalk.yellow('🎯 URL de destino (para onde encaminhar as requisições):'),
167
- default: config.targetUrl,
188
+ default: defaultTarget,
168
189
  validate: (input) => {
169
190
  try {
170
191
  new URL(input);
@@ -174,13 +195,11 @@ async function askQuestions() {
174
195
  }
175
196
  }
176
197
  }
177
- ];
178
-
179
- const answers = await inquirer.prompt(questions);
198
+ ]);
180
199
 
181
- Object.assign(config, answers);
200
+ config.targetUrl = targetUrl;
182
201
 
183
- return answers;
202
+ return;
184
203
  }
185
204
 
186
205
  let proxyServer = null;
@@ -188,7 +207,7 @@ let proxyServer = null;
188
207
  async function startProxy() {
189
208
  console.log(chalk.yellow('\n🚀 Iniciando Duckfly Proxy...\n'));
190
209
 
191
- proxyServer = new ProxyServer(config);
210
+ proxyServer = new ProxyServer({ ...config, apiUrl: DUCKFLY_API_URL, proxyUrl: DUCKFLY_PROXY_URL });
192
211
 
193
212
  try {
194
213
  await proxyServer.start();
@@ -200,8 +219,8 @@ async function startProxy() {
200
219
  console.log(chalk.yellow(' Proxy rodando em: ') + chalk.white(`http://localhost:${config.proxyPort}`));
201
220
  console.log(chalk.yellow(' Encaminhando para: ') + chalk.white(config.targetUrl));
202
221
  console.log(chalk.gray('─'.repeat(60)));
203
- console.log(chalk.yellow('\n💡 Dica: Configure sua aplicação para apontar para ') + chalk.white(`http://localhost:${config.proxyPort}`));
204
- console.log(chalk.yellow(' Todas as requisições serão capturadas e documentadas automaticamente!\n'));
222
+ console.log(chalk.blue('\n💡 Dica: Configure sua aplicação para apontar para ') + chalk.white(`http://localhost:${config.proxyPort}`));
223
+ console.log(chalk.blue(' Todas as requisições serão capturadas e documentadas automaticamente!\n'));
205
224
  console.log(chalk.gray('Pressione Ctrl+C para parar o proxy\n'));
206
225
 
207
226
  saveConfig();
@@ -242,8 +261,11 @@ async function main() {
242
261
  if (!useExisting) {
243
262
  config.token = null;
244
263
  config.appName = null;
264
+ config.appUrl = null;
265
+ config.domainPackageId = null;
245
266
  config.proxyPort = 8080;
246
- config.targetUrl = 'http://localhost:3000';
267
+ config.targetUrl = null;
268
+ try { fs.unlinkSync(CONFIG_FILE); } catch { }
247
269
  }
248
270
  }
249
271
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@duckfly/proxy",
3
- "version": "1.0.0",
3
+ "version": "1.0.4",
4
4
  "description": "Duckfly Proxy observes real API usage to continuously enrich and generate API documentation and MCP servers on Duckfly.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -47,4 +47,4 @@
47
47
  "publishConfig": {
48
48
  "access": "public"
49
49
  }
50
- }
50
+ }
package/src/api-client.js CHANGED
@@ -9,7 +9,7 @@ class ApiClient {
9
9
 
10
10
  async validateToken() {
11
11
  try {
12
- const url = `${this.apiUrl}/internal/v1/core/token/${this.token}`;
12
+ const url = `${this.apiUrl}/internal/v1/core/token/${this.token}?source=plugin-proxy`;
13
13
 
14
14
  const response = await axios.get(url, {
15
15
  timeout: 30000,
@@ -9,6 +9,7 @@ const { sanitizeRequestData } = require('./sanitizer');
9
9
  class ProxyServer {
10
10
  constructor(config) {
11
11
  this.config = config;
12
+ this.hostAlias = config.hostAlias || null;
12
13
  this.proxy = httpProxy.createProxyServer({});
13
14
  this.app = express();
14
15
  this.server = null;
@@ -85,10 +86,16 @@ class ProxyServer {
85
86
 
86
87
  captureRequest(req, res) {
87
88
  try {
89
+ const headers = { ...req.headers };
90
+
91
+ if (this.hostAlias) {
92
+ headers.host = this.hostAlias;
93
+ }
94
+
88
95
  req._captureData = {
89
96
  method: req.method,
90
97
  url: req.url,
91
- headers: { ...req.headers },
98
+ headers,
92
99
  body: this.parseBody(req.rawBody, req.headers['content-type']),
93
100
  protocol: req.socket.encrypted ? 'https' : 'http',
94
101
  timestamp: new Date().toISOString(),