Skip to content

Commit e6ef2a0

Browse files
felixtrzmeta-codesync[bot]
authored andcommitted
Improve IWSDK Linux dev-server build robustness
Summary: - Make xr-input profile generation proxy-aware with curl fallback, explicit offline/refresh modes, and actionable network diagnostics. - Add Linux dev-server preflight script and package script aliases for dev tarball builds that skip reference-assets. - Make build-tgz fail fast, show package build errors, and validate package/tarball entrypoints. - Add pnpm build-script approvals needed for non-interactive Linux dev-server installs while keeping onnxruntime-node disabled for dev flows that skip reference-assets. Reviewed By: cabanier Differential Revision: D108167257 fbshipit-source-id: 64bf4f9e0338b71c0bac9cf9a04c64b9fa6f4748
1 parent 3a08b40 commit e6ef2a0

6 files changed

Lines changed: 427 additions & 85 deletions

File tree

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
"build": "pnpm --filter '@iwsdk/core' run build",
88
"build:all": "pnpm -r run build",
99
"build:tgz": "bash ./scripts/build-tgz.sh",
10+
"build:tgz:dev": "npm_config_confirmModulesPurge=false bash ./scripts/build-tgz.sh --skip-reference-assets",
11+
"build:tgz:skip-reference-assets": "npm_config_confirmModulesPurge=false bash ./scripts/build-tgz.sh --skip-reference-assets",
1012
"bundle:sdk": "bash ./scripts/build-sdk-bundle.sh",
1113
"docs:api": "typedoc && node scripts/postprocess-typedoc.cjs",
1214
"docs:dev": "vitepress dev docs",
@@ -22,6 +24,7 @@
2224
"prepare": "node scripts/setup-git-hooks.cjs",
2325
"setup-hooks": "node scripts/setup-git-hooks.cjs",
2426
"engines:audit": "node scripts/check-engines.mjs",
27+
"doctor:linux-dev-server": "bash ./scripts/dev/doctor-linux-dev-server.sh",
2528
"headers:check": "node scripts/check-headers.mjs --dry-run",
2629
"headers:fix": "node scripts/check-headers.mjs --fix",
2730
"three:check": "node scripts/check-three-version.mjs",

packages/xr-input/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
],
1111
"scripts": {
1212
"prebuild": "node -p \"'export const VERSION = ' + JSON.stringify(require('./package.json').version) + ';'\" > src/version.ts && node scripts/generate-input-profiles.js",
13+
"generate:profiles": "node scripts/generate-input-profiles.js",
14+
"generate:profiles:force": "node scripts/generate-input-profiles.js --force",
15+
"generate:profiles:offline": "node scripts/generate-input-profiles.js --offline",
1316
"build": "rollup -c",
1417
"format": "prettier --write ./src/**/*",
1518
"test": "vitest run"

packages/xr-input/scripts/generate-input-profiles.js

Lines changed: 122 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,14 @@
66
* LICENSE file in the root directory of this source tree.
77
*/
88

9+
import { execFile } from 'child_process';
910
import { fileURLToPath } from 'url';
1011
import fs from 'fs';
1112
import https from 'https';
1213
import path from 'path';
14+
import { promisify } from 'util';
15+
16+
const execFileAsync = promisify(execFile);
1317

1418
const __filename = fileURLToPath(import.meta.url);
1519
const __dirname = path.dirname(__filename);
@@ -21,20 +25,102 @@ const OUTPUT_FILE = path.join(
2125
'../src/gamepad/generated-profiles.ts',
2226
);
2327

24-
// Check if we should skip fetching (file exists and --force not passed)
25-
const forceRefresh = process.argv.includes('--force');
28+
function readFlagValue(flag) {
29+
const prefix = `${flag}=`;
30+
const inline = process.argv.find((arg) => arg.startsWith(prefix));
31+
if (inline) {
32+
return inline.slice(prefix.length);
33+
}
34+
35+
const index = process.argv.indexOf(flag);
36+
if (index !== -1) {
37+
return process.argv[index + 1];
38+
}
39+
40+
return undefined;
41+
}
42+
43+
const forceRefresh =
44+
process.argv.includes('--force') || process.argv.includes('--refresh');
45+
const offline = process.argv.includes('--offline');
46+
const proxyUrl =
47+
readFlagValue('--proxy') ??
48+
process.env.HTTPS_PROXY ??
49+
process.env.https_proxy ??
50+
process.env.HTTP_PROXY ??
51+
process.env.http_proxy;
52+
53+
function redactUrlForLogs(value) {
54+
try {
55+
const parsed = new URL(value);
56+
if (parsed.username || parsed.password) {
57+
parsed.username = '***';
58+
parsed.password = '***';
59+
}
60+
return parsed.toString();
61+
} catch {
62+
return '<configured>';
63+
}
64+
}
65+
66+
function explainNetworkMode() {
67+
if (offline) {
68+
console.log(
69+
'🌐 Network mode: offline; using existing generated profiles only.',
70+
);
71+
} else if (proxyUrl) {
72+
console.log(
73+
`🌐 Network mode: fetching input profiles through proxy ${redactUrlForLogs(proxyUrl)}`,
74+
);
75+
} else {
76+
console.log('🌐 Network mode: direct HTTPS fetch.');
77+
}
78+
}
79+
80+
// Check if we should skip fetching (file exists and --force/--refresh not passed)
2681
if (!forceRefresh && fs.existsSync(OUTPUT_FILE)) {
2782
console.log(
2883
`✅ Input profiles already exist at ${OUTPUT_FILE}, skipping CDN fetch.`,
2984
);
30-
console.log(' Use --force to refresh from CDN.');
85+
console.log(' Use --force or --refresh to refresh from CDN.');
3186
process.exit(0);
3287
}
3388

34-
function fetchJson(url) {
89+
if (offline) {
90+
console.error(
91+
`❌ Offline profile generation requested, but ${OUTPUT_FILE} does not exist.`,
92+
);
93+
console.error(' Run this command once with network access to create it.');
94+
process.exit(1);
95+
}
96+
97+
function fetchJsonDirect(url, redirectsRemaining = 5) {
3598
return new Promise((resolve, reject) => {
3699
https
37100
.get(url, (res) => {
101+
if (
102+
res.statusCode &&
103+
res.statusCode >= 300 &&
104+
res.statusCode < 400 &&
105+
res.headers.location &&
106+
redirectsRemaining > 0
107+
) {
108+
res.resume();
109+
const redirectedUrl = new URL(res.headers.location, url).toString();
110+
fetchJsonDirect(redirectedUrl, redirectsRemaining - 1)
111+
.then(resolve)
112+
.catch(reject);
113+
return;
114+
}
115+
116+
if (res.statusCode !== 200) {
117+
res.resume();
118+
reject(
119+
new Error(`Request failed for ${url}: HTTP ${res.statusCode}`),
120+
);
121+
return;
122+
}
123+
38124
let data = '';
39125

40126
res.on('data', (chunk) => {
@@ -59,22 +145,39 @@ function fetchJson(url) {
59145
});
60146
}
61147

62-
function toCamelCase(str) {
63-
return str
64-
.replace(/[-\/]/g, ' ')
65-
.replace(/\.json$/, '')
66-
.split(' ')
67-
.map((word, index) => {
68-
if (index === 0) {
69-
return word.toLowerCase();
70-
}
71-
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
72-
})
73-
.join('');
148+
async function fetchJsonWithCurl(url) {
149+
const { stdout } = await execFileAsync(
150+
'curl',
151+
[
152+
'--fail',
153+
'--silent',
154+
'--show-error',
155+
'--location',
156+
'--proxy',
157+
proxyUrl,
158+
url,
159+
],
160+
{
161+
maxBuffer: 20 * 1024 * 1024,
162+
},
163+
);
164+
return JSON.parse(stdout);
165+
}
166+
167+
async function fetchJson(url) {
168+
try {
169+
return proxyUrl ? await fetchJsonWithCurl(url) : await fetchJsonDirect(url);
170+
} catch (error) {
171+
const hint = proxyUrl
172+
? 'Check that the proxy is reachable and that curl is available.'
173+
: 'If you are on a Linux dev server that requires a proxy, set HTTPS_PROXY/HTTP_PROXY or pass --proxy <url>.';
174+
throw new Error(`Failed to fetch ${url}. ${hint}`, { cause: error });
175+
}
74176
}
75177

76178
async function generateInputProfiles() {
77179
try {
180+
explainNetworkMode();
78181
console.log('Fetching profiles list...');
79182
const profilesList = await fetchJson(`${CDN_BASE_URL}/profilesList.json`);
80183

@@ -150,6 +253,9 @@ export function getProfilesList(): ProfilesList {
150253
console.log(`✅ Generated ${OUTPUT_FILE} with ${profiles.length} profiles`);
151254
} catch (error) {
152255
console.error('❌ Error generating input profiles:', error);
256+
if (error?.cause) {
257+
console.error('Caused by:', error.cause);
258+
}
153259
process.exit(1);
154260
}
155261
}

pnpm-workspace.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,15 @@
11
packages:
22
- 'packages/*'
3+
overrides:
4+
three: 'npm:super-three@0.181.0'
5+
'@types/three': '0.181.0'
6+
three-mesh-bvh: '^0.9.1'
7+
axios: '^1.12.0'
8+
preact: '^10.27.3'
9+
'@pmndrs/uikit': '^1.0.62'
10+
vite: '7.3.1'
11+
allowBuilds:
12+
esbuild: true
13+
onnxruntime-node: false
14+
protobufjs: true
15+
sharp: true

0 commit comments

Comments
 (0)