cwbridge 1.7.0

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 ADDED
@@ -0,0 +1,30 @@
1
+ # CWBridge
2
+
3
+ CWBridge is a Windows command-line bridge for locally configured Roblox
4
+ services. This npm package contains the compiled Windows executable and a
5
+ minimal launcher; it does not include the Python source code.
6
+
7
+ ## Run
8
+
9
+ ```powershell
10
+ npx --yes cwbridge
11
+ ```
12
+
13
+ Pass normal CWBridge arguments after the command, for example:
14
+
15
+ ```powershell
16
+ npx --yes cwbridge --version
17
+ npx --yes cwbridge start --only weather
18
+ ```
19
+
20
+ The launcher checks npm at most once every 24 hours and reports when a newer
21
+ package is available. It does not update the executable automatically. Fetch
22
+ the newest launcher with:
23
+
24
+ ```powershell
25
+ npx --yes cwbridge@latest
26
+ ```
27
+
28
+ Set `CWBRIDGE_NO_UPDATE_CHECK=1` to disable the launcher update check.
29
+
30
+ This package is currently Windows x64 only.
Binary file
@@ -0,0 +1,158 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ const fs = require("node:fs");
5
+ const https = require("node:https");
6
+ const path = require("node:path");
7
+ const { spawnSync } = require("node:child_process");
8
+
9
+ const packageInfo = require("../package.json");
10
+ const UPDATE_CHECK_MS = 24 * 60 * 60 * 1000;
11
+ const UPDATE_TIMEOUT_MS = 900;
12
+
13
+ function parseVersion(value) {
14
+ const match = /^v?(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/.exec(String(value));
15
+ return match ? match.slice(1, 4).map(Number) : null;
16
+ }
17
+
18
+ function isNewerVersion(latest, current) {
19
+ const latestParts = parseVersion(latest);
20
+ const currentParts = parseVersion(current);
21
+ if (!latestParts || !currentParts) {
22
+ return false;
23
+ }
24
+ for (let index = 0; index < latestParts.length; index += 1) {
25
+ if (latestParts[index] !== currentParts[index]) {
26
+ return latestParts[index] > currentParts[index];
27
+ }
28
+ }
29
+ return false;
30
+ }
31
+
32
+ function cachePath() {
33
+ const base = process.env.LOCALAPPDATA || process.env.APPDATA;
34
+ return base ? path.join(base, "CWBridge", "npm-update-check.json") : null;
35
+ }
36
+
37
+ function readCachedLatest() {
38
+ const filename = cachePath();
39
+ if (!filename) {
40
+ return null;
41
+ }
42
+ try {
43
+ const cached = JSON.parse(fs.readFileSync(filename, "utf8"));
44
+ if (
45
+ cached.package === packageInfo.name &&
46
+ typeof cached.checkedAt === "number" &&
47
+ Date.now() - cached.checkedAt < UPDATE_CHECK_MS &&
48
+ typeof cached.latest === "string"
49
+ ) {
50
+ return cached.latest;
51
+ }
52
+ } catch {
53
+ // A missing or malformed cache must never prevent CWBridge from starting.
54
+ }
55
+ return null;
56
+ }
57
+
58
+ function writeCachedLatest(latest) {
59
+ const filename = cachePath();
60
+ if (!filename) {
61
+ return;
62
+ }
63
+ try {
64
+ fs.mkdirSync(path.dirname(filename), { recursive: true });
65
+ fs.writeFileSync(
66
+ filename,
67
+ JSON.stringify({ package: packageInfo.name, latest, checkedAt: Date.now() }),
68
+ "utf8",
69
+ );
70
+ } catch {
71
+ // The update cache is optional and must not affect command execution.
72
+ }
73
+ }
74
+
75
+ function fetchLatestVersion() {
76
+ return new Promise((resolve) => {
77
+ const request = https.get(
78
+ `https://registry.npmjs.org/${encodeURIComponent(packageInfo.name)}/latest`,
79
+ { headers: { Accept: "application/json", "User-Agent": "cwbridge-npx-launcher" } },
80
+ (response) => {
81
+ let body = "";
82
+ response.setEncoding("utf8");
83
+ response.on("data", (chunk) => {
84
+ body += chunk;
85
+ });
86
+ response.on("end", () => {
87
+ if (response.statusCode !== 200) {
88
+ resolve(null);
89
+ return;
90
+ }
91
+ try {
92
+ resolve(JSON.parse(body).version || null);
93
+ } catch {
94
+ resolve(null);
95
+ }
96
+ });
97
+ },
98
+ );
99
+ request.setTimeout(UPDATE_TIMEOUT_MS, () => request.destroy());
100
+ request.on("error", () => resolve(null));
101
+ });
102
+ }
103
+
104
+ async function reportAvailableUpdate() {
105
+ if (process.env.CWBRIDGE_NO_UPDATE_CHECK === "1") {
106
+ return;
107
+ }
108
+ const cachedLatest = readCachedLatest();
109
+ const latest = cachedLatest || (await fetchLatestVersion());
110
+ if (!latest) {
111
+ return;
112
+ }
113
+ if (!cachedLatest) {
114
+ writeCachedLatest(latest);
115
+ }
116
+ if (isNewerVersion(latest, packageInfo.version)) {
117
+ console.error(
118
+ `A newer CWBridge version is available: v${packageInfo.version} -> v${latest}\n` +
119
+ "Run: npx --yes cwbridge@latest",
120
+ );
121
+ }
122
+ }
123
+
124
+ async function main() {
125
+ if (process.platform !== "win32") {
126
+ console.error("CWBridge via npx currently supports Windows x64 only.");
127
+ process.exitCode = 1;
128
+ return;
129
+ }
130
+
131
+ const executable = path.join(__dirname, "cwbridge.exe");
132
+ if (!fs.existsSync(executable)) {
133
+ console.error("CWBridge executable is missing from this npm package.");
134
+ process.exitCode = 1;
135
+ return;
136
+ }
137
+
138
+ await reportAvailableUpdate();
139
+ const result = spawnSync(executable, process.argv.slice(2), {
140
+ stdio: "inherit",
141
+ windowsHide: false,
142
+ });
143
+ if (result.error) {
144
+ console.error(`Unable to start CWBridge: ${result.error.message}`);
145
+ process.exitCode = 1;
146
+ return;
147
+ }
148
+ process.exitCode = typeof result.status === "number" ? result.status : 1;
149
+ }
150
+
151
+ if (require.main === module) {
152
+ main().catch((error) => {
153
+ console.error(`CWBridge launcher failed: ${error.message}`);
154
+ process.exitCode = 1;
155
+ });
156
+ }
157
+
158
+ module.exports = { isNewerVersion, parseVersion };
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "cwbridge",
3
+ "version": "1.7.0",
4
+ "description": "Windows launcher for the compiled CWBridge executable",
5
+ "license": "UNLICENSED",
6
+ "private": false,
7
+ "os": [
8
+ "win32"
9
+ ],
10
+ "cpu": [
11
+ "x64"
12
+ ],
13
+ "engines": {
14
+ "node": ">=18"
15
+ },
16
+ "bin": {
17
+ "cwbridge": "bin/cwbridge.js"
18
+ },
19
+ "files": [
20
+ "bin/cwbridge.js",
21
+ "bin/cwbridge.exe",
22
+ "README.md"
23
+ ],
24
+ "publishConfig": {
25
+ "access": "public"
26
+ }
27
+ }