From d9af59f14f3208116c5d12aa9cac4f648439e0c3 Mon Sep 17 00:00:00 2001 From: Anthony Donlon Date: Mon, 22 Dec 2025 23:43:07 +0800 Subject: [PATCH] nodejs: load template from bundled string --- nodejs/.gitignore | 2 + nodejs/package-lock.json | 537 +++++++++++++++++- nodejs/package.json | 8 +- nodejs/rollup.config.ts | 35 ++ nodejs/scripts/copy-files.js | 14 + nodejs/src/assets.d.ts | 4 + nodejs/src/index.ts | 80 +-- nodejs/src/templates/.gitignore | 1 + .../src/templates/template.ejs | 85 ++- nodejs/templates/error.ejs | 110 ---- scripts/inline_resources.py | 5 - 11 files changed, 663 insertions(+), 218 deletions(-) create mode 100644 nodejs/rollup.config.ts create mode 100644 nodejs/scripts/copy-files.js create mode 100644 nodejs/src/assets.d.ts create mode 100644 nodejs/src/templates/.gitignore rename resources/templates/error.ejs => nodejs/src/templates/template.ejs (66%) delete mode 100644 nodejs/templates/error.ejs diff --git a/nodejs/.gitignore b/nodejs/.gitignore index a0a7fe7..4396021 100644 --- a/nodejs/.gitignore +++ b/nodejs/.gitignore @@ -1,5 +1,7 @@ node_modules/ dist/ +*.tgz + *.log *.html .DS_Store diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index 6c3a013..53cac3a 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -12,14 +12,375 @@ "ejs": "^3.1.10" }, "devDependencies": { + "@rollup/plugin-typescript": "^12.3.0", + "@rollup/pluginutils": "^5.3.0", "@types/ejs": "^3.1.5", "@types/node": "^20.0.0", - "typescript": "^5.3.0" + "rollup": "^4.54.0", + "tslib": "^2.8.1" }, "engines": { "node": ">=18.0.0" } }, + "node_modules/@rollup/plugin-typescript": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-12.3.0.tgz", + "integrity": "sha512-7DP0/p7y3t67+NabT9f8oTBFE6gGkto4SA6Np2oudYmZE/m1dt8RB0SjL1msMxFpLo631qjRCcBlAbq1ml/Big==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.1.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.14.0||^3.0.0||^4.0.0", + "tslib": "*", + "typescript": ">=3.7.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + }, + "tslib": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.54.0.tgz", + "integrity": "sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.54.0.tgz", + "integrity": "sha512-Skx39Uv+u7H224Af+bDgNinitlmHyQX1K/atIA32JP3JQw6hVODX5tkbi2zof/E69M1qH2UoN3Xdxgs90mmNYw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.54.0.tgz", + "integrity": "sha512-k43D4qta/+6Fq+nCDhhv9yP2HdeKeP56QrUUTW7E6PhZP1US6NDqpJj4MY0jBHlJivVJD5P8NxrjuobZBJTCRw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.54.0.tgz", + "integrity": "sha512-cOo7biqwkpawslEfox5Vs8/qj83M/aZCSSNIWpVzfU2CYHa2G3P1UN5WF01RdTHSgCkri7XOlTdtk17BezlV3A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.54.0.tgz", + "integrity": "sha512-miSvuFkmvFbgJ1BevMa4CPCFt5MPGw094knM64W9I0giUIMMmRYcGW/JWZDriaw/k1kOBtsWh1z6nIFV1vPNtA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.54.0.tgz", + "integrity": "sha512-KGXIs55+b/ZfZsq9aR026tmr/+7tq6VG6MsnrvF4H8VhwflTIuYh+LFUlIsRdQSgrgmtM3fVATzEAj4hBQlaqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.54.0.tgz", + "integrity": "sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.54.0.tgz", + "integrity": "sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.54.0.tgz", + "integrity": "sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.54.0.tgz", + "integrity": "sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.54.0.tgz", + "integrity": "sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.54.0.tgz", + "integrity": "sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.54.0.tgz", + "integrity": "sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.54.0.tgz", + "integrity": "sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.54.0.tgz", + "integrity": "sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.54.0.tgz", + "integrity": "sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.54.0.tgz", + "integrity": "sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.54.0.tgz", + "integrity": "sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.54.0.tgz", + "integrity": "sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.54.0.tgz", + "integrity": "sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.54.0.tgz", + "integrity": "sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.54.0.tgz", + "integrity": "sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@types/ejs": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.1.5.tgz", @@ -27,6 +388,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { "version": "20.19.26", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.26.tgz", @@ -73,6 +441,13 @@ "node": ">=0.10.0" } }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, "node_modules/filelist": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", @@ -82,6 +457,60 @@ "minimatch": "^5.0.1" } }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/jake": { "version": "10.9.4", "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", @@ -111,18 +540,124 @@ "node": ">=10" } }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "license": "ISC" }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/rollup": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.54.0.tgz", + "integrity": "sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.54.0", + "@rollup/rollup-android-arm64": "4.54.0", + "@rollup/rollup-darwin-arm64": "4.54.0", + "@rollup/rollup-darwin-x64": "4.54.0", + "@rollup/rollup-freebsd-arm64": "4.54.0", + "@rollup/rollup-freebsd-x64": "4.54.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.54.0", + "@rollup/rollup-linux-arm-musleabihf": "4.54.0", + "@rollup/rollup-linux-arm64-gnu": "4.54.0", + "@rollup/rollup-linux-arm64-musl": "4.54.0", + "@rollup/rollup-linux-loong64-gnu": "4.54.0", + "@rollup/rollup-linux-ppc64-gnu": "4.54.0", + "@rollup/rollup-linux-riscv64-gnu": "4.54.0", + "@rollup/rollup-linux-riscv64-musl": "4.54.0", + "@rollup/rollup-linux-s390x-gnu": "4.54.0", + "@rollup/rollup-linux-x64-gnu": "4.54.0", + "@rollup/rollup-linux-x64-musl": "4.54.0", + "@rollup/rollup-openharmony-arm64": "4.54.0", + "@rollup/rollup-win32-arm64-msvc": "4.54.0", + "@rollup/rollup-win32-ia32-msvc": "4.54.0", + "@rollup/rollup-win32-x64-gnu": "4.54.0", + "@rollup/rollup-win32-x64-msvc": "4.54.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "peer": true + }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/nodejs/package.json b/nodejs/package.json index e3e9336..617eb00 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -6,7 +6,8 @@ "types": "dist/index.d.ts", "type": "module", "scripts": { - "build": "tsc", + "build": "node scripts/copy-files.js && rollup -c", + "dev": "rollup -c -w", "prepublishOnly": "pnpm run build", "example": "node examples/example.js" }, @@ -32,9 +33,12 @@ "ejs": "^3.1.10" }, "devDependencies": { + "@rollup/plugin-typescript": "^12.3.0", + "@rollup/pluginutils": "^5.3.0", "@types/ejs": "^3.1.5", "@types/node": "^20.0.0", - "typescript": "^5.3.0" + "rollup": "^4.54.0", + "tslib": "^2.8.1" }, "files": [ "dist/**/*", diff --git a/nodejs/rollup.config.ts b/nodejs/rollup.config.ts new file mode 100644 index 0000000..e71ea44 --- /dev/null +++ b/nodejs/rollup.config.ts @@ -0,0 +1,35 @@ +import typescript from "@rollup/plugin-typescript"; +import { createFilter } from "@rollup/pluginutils"; +// import pkg from './package.json' with { type: 'json' }; + +function createRawImportPlugin(include: string) { + const rawFilter = createFilter(include); + + return { + name: "raw-import", + + transform(code: string, id: string): any { + if (rawFilter(id)) { + return { + code: `export default ${JSON.stringify(code)};`, + map: { mappings: "" }, + }; + } + }, + }; +} + +export default { + input: "src/index.ts", + output: { + // file: pkg.module, + file: "dist/index.js", + format: "esm", + sourcemap: true, + }, + watch: { + include: "src/**", + }, + external: ["ejs"], + plugins: [typescript(), createRawImportPlugin("**/templates/**")], +}; diff --git a/nodejs/scripts/copy-files.js b/nodejs/scripts/copy-files.js new file mode 100644 index 0000000..02e9674 --- /dev/null +++ b/nodejs/scripts/copy-files.js @@ -0,0 +1,14 @@ +import fs from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +// Resolve the directory of this script +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// Define paths relative to scripts/copy.js +const src = path.resolve(__dirname, "../../resources/styles/main.css"); +const dest = path.resolve(__dirname, "../src/templates/main.css"); + +// Copy file +fs.copyFileSync(src, dest); diff --git a/nodejs/src/assets.d.ts b/nodejs/src/assets.d.ts new file mode 100644 index 0000000..370800f --- /dev/null +++ b/nodejs/src/assets.d.ts @@ -0,0 +1,4 @@ +declare module "./templates/*" { + const content: string; + export default content; +} diff --git a/nodejs/src/index.ts b/nodejs/src/index.ts index 6e5565c..6a96a97 100644 --- a/nodejs/src/index.ts +++ b/nodejs/src/index.ts @@ -1,11 +1,7 @@ -import * as fs from "fs"; -import * as path from "path"; -import { fileURLToPath } from "url"; import * as ejs from "ejs"; -import * as crypto from "crypto"; -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); +import templateString from "./templates/template.ejs"; +import cssString from "./templates/main.css"; export interface StatusItem { status?: "ok" | "error"; @@ -55,69 +51,51 @@ export interface ErrorPageParams { creator_info?: CreatorInfo; } -/** - * Fill default parameters if not provided - */ -function fillParams(params: ErrorPageParams): ErrorPageParams { - const filledParams = { ...params }; - - if (!filledParams.time) { - const now = new Date(); - filledParams.time = - now.toISOString().replace("T", " ").substring(0, 19) + " UTC"; - } - - if (!filledParams.ray_id) { - filledParams.ray_id = crypto.randomBytes(8).toString("hex"); - } - - return filledParams; -} +// Load EJS template +export const baseTemplate: ejs.TemplateFunction = ejs.compile(templateString); /** - * Escape HTML special characters + * Generate random hex string for ray-id */ -function escapeHtml(text: string): string { - const htmlEscapeMap: Record = { - "&": "&", - "<": "<", - ">": ">", - '"': """, - "'": "'", - }; - return text.replace(/[&<>"']/g, (char) => htmlEscapeMap[char] || char); +function genHexString(digits: number): string { + const hex = "0123456789ABCDEF"; + let output = ""; + for (let i = 0; i < digits; i++) { + output += hex.charAt(Math.floor(Math.random() * hex.length)); + } + return output; } /** * Render a customized Cloudflare error page * @param params - The parameters for the error page * @param allowHtml - Whether to allow HTML in what_happened and what_can_i_do fields (default: true) + * @param moreArgs - More arguments passed to ejs template * @returns The rendered HTML string */ export function render( params: ErrorPageParams, - allowHtml: boolean = true + allowHtml: boolean = true, + moreArgs: { + [name: string]: any; + } = {} ): string { - let processedParams = fillParams(params); + params = { ...params }; - if (!allowHtml) { - processedParams = { ...processedParams }; - if (processedParams.what_happened) { - processedParams.what_happened = escapeHtml(processedParams.what_happened); - } - if (processedParams.what_can_i_do) { - processedParams.what_can_i_do = escapeHtml(processedParams.what_can_i_do); - } + if (!params.time) { + const now = new Date(); + params.time = now.toISOString().replace("T", " ").substring(0, 19) + " UTC"; + } + if (!params.ray_id) { + params.ray_id = genHexString(16); } - // Load EJS template - const templatePath = path.join(__dirname, "..", "templates", "error.ejs"); + if (!allowHtml) { + params.what_happened = ejs.escapeXML(params.what_happened ?? ""); + params.what_can_i_do = ejs.escapeXML(params.what_can_i_do ?? ""); + } - const template = fs.readFileSync(templatePath, "utf-8"); - - const rendered = ejs.render(template, { params: processedParams }); - - return rendered; + return baseTemplate({ params, html_style: cssString, ...moreArgs }); } export default render; diff --git a/nodejs/src/templates/.gitignore b/nodejs/src/templates/.gitignore new file mode 100644 index 0000000..5f93228 --- /dev/null +++ b/nodejs/src/templates/.gitignore @@ -0,0 +1 @@ +main.css \ No newline at end of file diff --git a/resources/templates/error.ejs b/nodejs/src/templates/template.ejs similarity index 66% rename from resources/templates/error.ejs rename to nodejs/src/templates/template.ejs index af806b4..cf31de5 100644 --- a/resources/templates/error.ejs +++ b/nodejs/src/templates/template.ejs @@ -4,31 +4,31 @@ -<% -let error_code = params.error_code || 500; -let title = params.title || 'Internal server error'; -let html_title_output = params.html_title || (error_code + ': ' + title); -%> -<%= html_title_output %> +<% const error_code = params.error_code || 500; %> +<% const title = params.title || 'Internal server error'; %> +<% const html_title = params.html_title || (error_code + ': ' + title); %> +<%= html_title %> - +
-
+

<%= title %> Error code <%= error_code %>

- <% let more_info = params.more_information || {}; %> + <% const more_info = params.more_information || {}; %> <% if (!more_info.hidden) { %>
- Visit <%= more_info.text || 'cloudflare.com' %> for <%= more_info.for || "more information" %>. + Visit <%= more_info.text || 'cloudflare.com' %> for <%= more_info.for || 'more information' %>.
<% } %>
<%= params.time %>
@@ -36,27 +36,16 @@ let html_title_output = params.html_title || (error_code + ': ' + title);
- <% for (let item_id of ['browser', 'cloudflare', 'host']) { %> - <% - let icon, default_location, default_name, text_color, status_text; - - if (item_id === 'browser') { - icon = 'browser'; - default_location = 'You'; - default_name = 'Browser'; - } else if (item_id === 'cloudflare') { - icon = 'cloud'; - default_location = 'San Francisco'; - default_name = 'Cloudflare'; - } else { - icon = 'server'; - default_location = 'Website'; - default_name = 'Host'; - } - - let item = params[item_id + '_status'] || {}; - let status = item.status || 'ok'; - + <% + const items = [ + { id: 'browser', icon: 'browser', default_location: 'You', default_name: 'Browser' }, + { id: 'cloudflare', icon: 'cloud', default_location: 'San Francisco', default_name: 'Cloudflare' }, + { id: 'host', icon: 'server', default_location: 'Website', default_name: 'Host' } + ]; + items.forEach(({ id, icon, default_location, default_name }) => { + const item = params[id + '_status'] || {}; + const status = item.status || 'ok'; + let text_color; if (item.status_text_color) { text_color = item.status_text_color; } else if (status === 'ok') { @@ -64,27 +53,19 @@ let html_title_output = params.html_title || (error_code + ': ' + title); } else if (status === 'error') { text_color = '#bd2426'; // text-red-error } - - status_text = item.status_text || (status === 'ok' ? 'Working' : 'Error'); - %> -
+ const status_text = item.status_text || (status === 'ok' ? 'Working' : 'Error'); + const is_error_source = params.error_source === id; + %> +
<%= item.location || default_location %> - <% - let _name_style; - if ((item.name || default_name) === 'Cloudflare') { - _name_style = 'style="color: #2f7bbf;"' - } else{ - _name_style = '' - } - %> -

><%= item.name || default_name %>

+

><%= item.name || default_name %>

<%= status_text %>
- <% } %> + <% }); %>
@@ -93,11 +74,11 @@ let html_title_output = params.html_title || (error_code + ': ' + title);

What happened?

- <%= (params.what_happened || 'There is an internal server error on Cloudflare\'s network.') %> + <%- params.what_happened || '

There is an internal server error on Cloudflare\'s network.

' %>

What can I do?

- <%= (params.what_can_i_do || 'Please try again in a few minutes.') %> + <%- params.what_can_i_do || '

Please try again in a few minutes.

' %>
@@ -112,12 +93,18 @@ let html_title_output = params.html_title || (error_code + ': ' + title); - <% let perf_sec_by = params.perf_sec_by || {}; %> + <% const perf_sec_by = params.perf_sec_by || {}; %> Performance & security by <%= perf_sec_by.text || 'Cloudflare' %> + + <% const creator_info = params.creator_info || {}; %> + <% if (!(creator_info.hidden ?? true)) { %> + + Created with <%= creator_info.text %> + <% } %>

- \ No newline at end of file + diff --git a/nodejs/templates/error.ejs b/nodejs/templates/error.ejs deleted file mode 100644 index 91f47a9..0000000 --- a/nodejs/templates/error.ejs +++ /dev/null @@ -1,110 +0,0 @@ -<%# Note: This file is generated with scripts/inline_resources.py. Please do not edit manually. %> - - - - - - -<% const error_code = params.error_code || 500; %> -<% const title = params.title || 'Internal server error'; %> -<% const html_title = params.html_title || (error_code + ': ' + title); %> -<%= html_title %> - - - - - - - - -
-
-
-

- <%= title %> - Error code <%= error_code %> -

- <% const more_info = params.more_information || {}; %> - <% if (!more_info.hidden) { %> -
- Visit <%= more_info.text || 'cloudflare.com' %> for <%= more_info.for || 'more information' %>. -
- <% } %> -
<%= params.time %>
-
-
-
-
- <% - const items = [ - { id: 'browser', icon: 'browser', default_location: 'You', default_name: 'Browser' }, - { id: 'cloudflare', icon: 'cloud', default_location: 'San Francisco', default_name: 'Cloudflare' }, - { id: 'host', icon: 'server', default_location: 'Website', default_name: 'Host' } - ]; - items.forEach(({ id, icon, default_location, default_name }) => { - const item = params[id + '_status'] || {}; - const status = item.status || 'ok'; - let text_color; - if (item.status_text_color) { - text_color = item.status_text_color; - } else if (status === 'ok') { - text_color = '#9bca3e'; // text-green-success - } else if (status === 'error') { - text_color = '#bd2426'; // text-red-error - } - const status_text = item.status_text || (status === 'ok' ? 'Working' : 'Error'); - const is_error_source = params.error_source === id; - %> -
-
- - -
- <%= item.location || default_location %> -

><%= item.name || default_name %>

- <%= status_text %> -
- <% }); %> -
-
-
- -
-
-
-

What happened?

- <%- params.what_happened || '

There is an internal server error on Cloudflare\'s network.

' %> -
-
-

What can I do?

- <%- params.what_can_i_do || '

Please try again in a few minutes.

' %> -
-
-
- - -
-
- - - diff --git a/scripts/inline_resources.py b/scripts/inline_resources.py index b2ad312..ccb5c89 100644 --- a/scripts/inline_resources.py +++ b/scripts/inline_resources.py @@ -65,8 +65,3 @@ def generate_inlined_css(): if __name__ == '__main__': generate_inlined_css() - inline_css_resource( - os.path.join(resources_folder, 'templates/error.ejs'), - os.path.join(resources_folder, 'styles/main.css'), - os.path.join(root, 'editor/web/src/template.ejs'), - )