openxiangda 1.0.158 → 1.0.159

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.
Files changed (3) hide show
  1. package/lib/cli.js +2 -0
  2. package/lib/http.js +107 -11
  3. package/package.json +2 -2
package/lib/cli.js CHANGED
@@ -5924,6 +5924,8 @@ async function runDirectRequest(config, target, flags, request, options = {}) {
5924
5924
  method: request.method || 'GET',
5925
5925
  body: request.body,
5926
5926
  strictEnvelope: request.strictEnvelope,
5927
+ timeoutMs:
5928
+ request.timeoutMs || flags['timeout-ms'] || flags.timeout || undefined,
5927
5929
  };
5928
5930
  let data;
5929
5931
  if (request.auth === false) {
package/lib/http.js CHANGED
@@ -1,8 +1,15 @@
1
1
  const { formatFetchError, maskText } = require('./utils');
2
2
 
3
- const DEFAULT_REQUEST_TIMEOUT_MS = 60000;
3
+ const DEFAULT_REQUEST_TIMEOUT_MS = normalizeTimeoutMs(
4
+ process.env.OPENXIANGDA_REQUEST_TIMEOUT_MS,
5
+ 120000
6
+ );
7
+ const DEFAULT_CONNECT_TIMEOUT_MS = normalizeTimeoutMs(
8
+ process.env.OPENXIANGDA_CONNECT_TIMEOUT_MS,
9
+ 30000
10
+ );
4
11
 
5
- configureFetchDispatcher(DEFAULT_REQUEST_TIMEOUT_MS);
12
+ configureFetchDispatcher(DEFAULT_CONNECT_TIMEOUT_MS);
6
13
 
7
14
  async function requestJson(baseUrl, apiPath, options = {}) {
8
15
  if (typeof fetch !== 'function') {
@@ -82,17 +89,106 @@ module.exports = {
82
89
 
83
90
  function configureFetchDispatcher(timeoutMs) {
84
91
  try {
85
- // Node fetch uses undici internally. Setting the global dispatcher prevents
86
- // large resource operations from failing on undici's 10s connect default.
87
- const { Agent, setGlobalDispatcher } = require('undici');
88
- setGlobalDispatcher(
89
- new Agent({
90
- connect: {
91
- timeout: timeoutMs,
92
- },
93
- })
92
+ // Node fetch uses undici internally but does not honor proxy environment
93
+ // variables by itself. Keep NO_PROXY-aware routing while extending the
94
+ // connect timeout for private and high-latency deployments.
95
+ const { Agent, ProxyAgent, setGlobalDispatcher } = require('undici');
96
+ const connect = { timeout: timeoutMs };
97
+ const directAgent = new Agent({ connect });
98
+ const httpProxyUrl = readProxyUrl('HTTP_PROXY');
99
+ const httpsProxyUrl = readProxyUrl('HTTPS_PROXY') || httpProxyUrl;
100
+ const allProxyUrl = readProxyUrl('ALL_PROXY');
101
+ const httpProxyAgent = createProxyAgent(
102
+ ProxyAgent,
103
+ httpProxyUrl || allProxyUrl,
104
+ connect
94
105
  );
106
+ const httpsProxyAgent = createProxyAgent(
107
+ ProxyAgent,
108
+ httpsProxyUrl || allProxyUrl,
109
+ connect
110
+ );
111
+
112
+ setGlobalDispatcher({
113
+ dispatch(options, handler) {
114
+ const origin = new URL(String(options.origin));
115
+ if (shouldBypassProxy(origin)) {
116
+ return directAgent.dispatch(options, handler);
117
+ }
118
+ const proxyAgent =
119
+ origin.protocol === 'https:' ? httpsProxyAgent : httpProxyAgent;
120
+ return (proxyAgent || directAgent).dispatch(options, handler);
121
+ },
122
+ close() {
123
+ return closeDispatchers([
124
+ directAgent,
125
+ httpProxyAgent,
126
+ httpsProxyAgent,
127
+ ]);
128
+ },
129
+ destroy(error) {
130
+ return destroyDispatchers(
131
+ [directAgent, httpProxyAgent, httpsProxyAgent],
132
+ error
133
+ );
134
+ },
135
+ });
95
136
  } catch {
96
137
  // Keep working on runtimes where undici is not directly importable.
97
138
  }
98
139
  }
140
+
141
+ function readProxyUrl(name) {
142
+ const value = process.env[name] || process.env[name.toLowerCase()];
143
+ return String(value || '').trim();
144
+ }
145
+
146
+ function createProxyAgent(ProxyAgent, uri, connect) {
147
+ if (!uri) return null;
148
+ return new ProxyAgent({ uri, connect });
149
+ }
150
+
151
+ function shouldBypassProxy(origin) {
152
+ const noProxy = readProxyUrl('NO_PROXY');
153
+ if (!noProxy) return false;
154
+ const hostname = origin.hostname.replace(/^\[|\]$/g, '').toLowerCase();
155
+ const port = origin.port || (origin.protocol === 'https:' ? '443' : '80');
156
+
157
+ return noProxy.split(',').some(rawEntry => {
158
+ const entry = rawEntry.trim().toLowerCase();
159
+ if (!entry) return false;
160
+ if (entry === '*') return true;
161
+
162
+ const normalized = entry.replace(/^https?:\/\//, '');
163
+ const separator = normalized.lastIndexOf(':');
164
+ const hasSinglePortSeparator =
165
+ separator > -1 && normalized.indexOf(':') === separator;
166
+ const entryHost = (hasSinglePortSeparator
167
+ ? normalized.slice(0, separator)
168
+ : normalized
169
+ ).replace(/^\[|\]$/g, '');
170
+ const entryPort = hasSinglePortSeparator
171
+ ? normalized.slice(separator + 1)
172
+ : '';
173
+ if (entryPort && entryPort !== port) return false;
174
+
175
+ const suffix = entryHost.replace(/^\*?\./, '');
176
+ return hostname === suffix || hostname.endsWith(`.${suffix}`);
177
+ });
178
+ }
179
+
180
+ async function closeDispatchers(dispatchers) {
181
+ await Promise.all(
182
+ uniqueDispatchers(dispatchers).map(dispatcher => dispatcher.close())
183
+ );
184
+ }
185
+
186
+ async function destroyDispatchers(dispatchers, error) {
187
+ await Promise.all(
188
+ uniqueDispatchers(dispatchers).map(dispatcher => dispatcher.destroy(error))
189
+ );
190
+ }
191
+
192
+ function uniqueDispatchers(dispatchers) {
193
+ return [...new Set(dispatchers.filter(Boolean))];
194
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openxiangda",
3
- "version": "1.0.158",
3
+ "version": "1.0.159",
4
4
  "description": "OpenXiangda CLI, workspace build tools, runtime SDK, and form components.",
5
5
  "private": false,
6
6
  "bin": {
@@ -62,7 +62,7 @@
62
62
  "scripts": {
63
63
  "build:sdk": "tsup --config packages/sdk/tsup.config.ts",
64
64
  "check": "node --check bin/openxiangda.js && node --check lib/*.js && node --check packages/sdk/src/build-source/src/cli.mjs && node --check packages/sdk/src/build-source/scripts/*.mjs && node --check packages/sdk/src/build-source/scripts/utils/*.mjs",
65
- "test": "npm run check && node scripts/form-export-cli-smoke.mjs && node scripts/open-api-cli-smoke.mjs",
65
+ "test": "npm run check && node scripts/http-proxy-smoke.mjs && node scripts/form-export-cli-smoke.mjs && node scripts/open-api-cli-smoke.mjs",
66
66
  "prepack": "npm run build:sdk",
67
67
  "test:profile-isolation": "bash scripts/profile-isolation-smoke.sh",
68
68
  "test:resource-plan": "node scripts/resource-plan-smoke.mjs",