@woniru/we-installer 0.1.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 +107 -0
- package/bin/we-installer.js +34 -0
- package/package.json +20 -0
- package/src/auth.js +87 -0
- package/src/authServer.js +490 -0
- package/src/download.js +123 -0
- package/src/extractZip.js +32 -0
- package/src/githubApi.js +22 -0
- package/src/githubDeviceFlow.js +82 -0
- package/src/githubDownload.js +33 -0
- package/src/prompt.js +14 -0
- package/src/sqlRunner.js +165 -0
- package/templates/auth.html +377 -0
- package/templates/configure.html +488 -0
package/README.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Woniru Engine Installer (WE)
|
|
2
|
+
|
|
3
|
+
This repository contains the **public NPX installer** for **Woniru Engine (WE)**.
|
|
4
|
+
|
|
5
|
+
The installer is intentionally small and public. It **does not** contain the engine source code.
|
|
6
|
+
Instead, it guides the user through GitHub authorization and then **downloads the private WE repository** (only if the user has access), installs dependencies, and launches a local configuration wizard.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Quick Start
|
|
11
|
+
|
|
12
|
+
Run the installer using NPX:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx @woniru/we-installer
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## What the Installer Does
|
|
19
|
+
|
|
20
|
+
1. The installer performs the following steps:
|
|
21
|
+
1. Opens a browser to authorize with GitHub using the Device Flow.
|
|
22
|
+
1. Verifies that the user has collaborator access to the private Woniru Engine repository.
|
|
23
|
+
1. Downloads the engine source code from the repository.
|
|
24
|
+
1. Runs npm install in the project directory.
|
|
25
|
+
1. Launches a local configuration wizard.
|
|
26
|
+
|
|
27
|
+
## The configuration wizard guides the user through:
|
|
28
|
+
|
|
29
|
+
### Step 1 — Redis Setup
|
|
30
|
+
|
|
31
|
+
- Connect to an existing Redis instance, or
|
|
32
|
+
|
|
33
|
+
- Automatically create a new Redis instance using Docker.
|
|
34
|
+
|
|
35
|
+
### Step 2 — Database Configuration
|
|
36
|
+
|
|
37
|
+
- Database host
|
|
38
|
+
|
|
39
|
+
- Database user
|
|
40
|
+
|
|
41
|
+
- Database password
|
|
42
|
+
|
|
43
|
+
- Database name
|
|
44
|
+
|
|
45
|
+
- Applies the WE schema to the database.
|
|
46
|
+
|
|
47
|
+
### Step 3 — Admin Access
|
|
48
|
+
|
|
49
|
+
- Creates the initial admin user.
|
|
50
|
+
|
|
51
|
+
- Displays commands required to start the server.
|
|
52
|
+
|
|
53
|
+
## Default Admin Credentials
|
|
54
|
+
|
|
55
|
+
After installation completes, the default admin account is:
|
|
56
|
+
|
|
57
|
+
**Username:**
|
|
58
|
+
```
|
|
59
|
+
admin@we.com
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Password:**
|
|
63
|
+
```
|
|
64
|
+
weAdmin
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
These credentials can be changed after logging into the system.
|
|
68
|
+
|
|
69
|
+
## Commands After Installation
|
|
70
|
+
|
|
71
|
+
The installer provides two commands:
|
|
72
|
+
|
|
73
|
+
**Start the server:**
|
|
74
|
+
```
|
|
75
|
+
npm run dev --redisAdminKey=<your-admin-key>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Recalculate user permissions:**
|
|
79
|
+
```
|
|
80
|
+
npm run recalculate:user-permissions
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The second command is only required if permissions need to be recalculated after changes.
|
|
84
|
+
|
|
85
|
+
## Access Control
|
|
86
|
+
|
|
87
|
+
This installer is public, but the **Woniru Engine repository is private**.
|
|
88
|
+
|
|
89
|
+
If you are a collaborator on the repository, the installer will download the engine successfully.
|
|
90
|
+
|
|
91
|
+
If you are not authorized, the installer will stop with an access error.
|
|
92
|
+
|
|
93
|
+
## Requirements
|
|
94
|
+
|
|
95
|
+
Before running the installer ensure the following are installed:
|
|
96
|
+
|
|
97
|
+
**Node.js** version 18 or higher
|
|
98
|
+
|
|
99
|
+
**npm** version 9 or higher
|
|
100
|
+
|
|
101
|
+
**Docker Desktop** for running private redis instance
|
|
102
|
+
|
|
103
|
+
Network access is required for:
|
|
104
|
+
|
|
105
|
+
- GitHub
|
|
106
|
+
- npm registry
|
|
107
|
+
- your configured database server
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { runAuth } = require("../src/auth");
|
|
4
|
+
const { runDownload } = require("../src/download");
|
|
5
|
+
|
|
6
|
+
const command = process.argv[2];
|
|
7
|
+
|
|
8
|
+
(async () => {
|
|
9
|
+
if (!command) {
|
|
10
|
+
console.log("Usage: we-installer <command>");
|
|
11
|
+
console.log("Commands:");
|
|
12
|
+
console.log(" auth Authenticate with GitHub");
|
|
13
|
+
console.log(" install Auth + download repo");
|
|
14
|
+
process.exit(0);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (command === "auth") {
|
|
18
|
+
await runAuth();
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (command === "install") {
|
|
23
|
+
const { token, user, ui } = await runAuth(); // make sure runAuth returns ui as well (see note below)
|
|
24
|
+
await runDownload({ token, ui });
|
|
25
|
+
console.log(`Done. Authenticated as ${user.login}.`);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
console.log(`Unknown command: ${command}`);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
})().catch((err) => {
|
|
32
|
+
console.error("Error:", err.message);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@woniru/we-installer",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "commonjs",
|
|
6
|
+
"bin": {
|
|
7
|
+
"we-installer": "./bin/we-installer.js"
|
|
8
|
+
},
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"adm-zip": "^0.5.16",
|
|
11
|
+
"mysql2": "^3.18.2",
|
|
12
|
+
"open": "^11.0.0",
|
|
13
|
+
"redis": "^5.11.0"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"bin",
|
|
17
|
+
"src",
|
|
18
|
+
"templates"
|
|
19
|
+
]
|
|
20
|
+
}
|
package/src/auth.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// src/auth.js
|
|
2
|
+
const { requestDeviceCode, pollForAccessToken } = require("./githubDeviceFlow");
|
|
3
|
+
const { startAuthServer } = require("./authServer");
|
|
4
|
+
const { getGithubUser } = require("./githubApi");
|
|
5
|
+
|
|
6
|
+
function openBrowserNative(url) {
|
|
7
|
+
const { exec } = require("child_process");
|
|
8
|
+
const platform = process.platform;
|
|
9
|
+
|
|
10
|
+
// Best-effort open; no external deps
|
|
11
|
+
if (platform === "win32") exec(`start "" "${url}"`);
|
|
12
|
+
else if (platform === "darwin") exec(`open "${url}"`);
|
|
13
|
+
else exec(`xdg-open "${url}"`);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Auth flow:
|
|
18
|
+
* 1) Request device code
|
|
19
|
+
* 2) Start local server + open browser
|
|
20
|
+
* 3) Poll GitHub for access token
|
|
21
|
+
* 4) Fetch /user to confirm identity
|
|
22
|
+
* 5) Switch UI phase to "install" so the page shows Accept/Manual section
|
|
23
|
+
*
|
|
24
|
+
* Returns: { token, user, ui }
|
|
25
|
+
*/
|
|
26
|
+
async function runAuth() {
|
|
27
|
+
const clientId = 'Ov23lifTq8hC15zQcG4C';
|
|
28
|
+
if (!clientId) throw new Error("Missing env var WE_GITHUB_CLIENT_ID");
|
|
29
|
+
|
|
30
|
+
// Optional: allow overriding scope later; default is repo for private repo access
|
|
31
|
+
const scope = "repo";
|
|
32
|
+
|
|
33
|
+
console.log("Requesting GitHub device code...");
|
|
34
|
+
const device = await requestDeviceCode({ clientId, scope });
|
|
35
|
+
|
|
36
|
+
const ui = await startAuthServer({
|
|
37
|
+
verificationUri: device.verification_uri,
|
|
38
|
+
userCode: device.user_code
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
console.log("\nOpen this page to continue:");
|
|
42
|
+
console.log(ui.url + "\n");
|
|
43
|
+
|
|
44
|
+
// Best-effort open browser (user can still open manually from printed URL)
|
|
45
|
+
try { openBrowserNative(ui.url); } catch { }
|
|
46
|
+
|
|
47
|
+
// Phase: auth
|
|
48
|
+
ui.setPhase("auth");
|
|
49
|
+
ui.setStatus("Waiting for approval in GitHub…");
|
|
50
|
+
|
|
51
|
+
// Poll for access token
|
|
52
|
+
let token;
|
|
53
|
+
try {
|
|
54
|
+
token = await pollForAccessToken({
|
|
55
|
+
clientId,
|
|
56
|
+
deviceCode: device.device_code,
|
|
57
|
+
intervalSeconds: device.interval ?? 5,
|
|
58
|
+
expiresInSeconds: device.expires_in ?? 900
|
|
59
|
+
});
|
|
60
|
+
} catch (err) {
|
|
61
|
+
ui.setStatus(`Authorization failed ❌ ${err.message}`);
|
|
62
|
+
throw err;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Verify identity
|
|
66
|
+
ui.setStatus("Authorized ✅ Verifying identity…");
|
|
67
|
+
|
|
68
|
+
let me;
|
|
69
|
+
try {
|
|
70
|
+
me = await getGithubUser({ token });
|
|
71
|
+
} catch (err) {
|
|
72
|
+
ui.setStatus(`Failed to verify identity ❌ ${err.message}`);
|
|
73
|
+
throw err;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
ui.setUserLogin(me.login);
|
|
77
|
+
console.log(`✅ GitHub authentication successful as: ${me.login}`);
|
|
78
|
+
|
|
79
|
+
// ✅ THIS is the “one line” you were looking for:
|
|
80
|
+
// Move UI to install-choice phase so the page hides auth controls and shows Accept/Manual.
|
|
81
|
+
ui.setPhase("install");
|
|
82
|
+
ui.setStatus("Choose install location in the browser: Accept (use current directory) or Choose manually…");
|
|
83
|
+
|
|
84
|
+
return { token, user: me, ui };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
module.exports = { runAuth };
|