@uxland/harmonix-cli 0.0.5 → 0.0.7
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 +17 -99
- package/index.js +36 -27
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -1,113 +1,31 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @uxland/harmonix-cli
|
|
2
2
|
|
|
3
|
-
`harmonix
|
|
4
|
-
|
|
5
|
-
## 🔧 Instal·lació
|
|
6
|
-
|
|
7
|
-
Assegura’t de tenir `node` i `npm` instal·lats. Afegeix `harmonix-cli` com a dependència del teu projecte o de forma global:
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
npm install -g @uxland/harmonix-cli
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## 🚀 Publicació d’un plugin
|
|
16
|
-
|
|
17
|
-
### Comanda principal
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
harmonix publish
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Aquesa comanda llegeix la informació del `package.json` i puja el fitxer compilat especificat al registry (plugin store) configurat.
|
|
24
|
-
|
|
25
|
-
---
|
|
26
|
-
|
|
27
|
-
## 📁 Estructura requerida
|
|
28
|
-
|
|
29
|
-
### `package.json`
|
|
30
|
-
|
|
31
|
-
El fitxer `package.json` del teu plugin ha de contenir obligatòriament els següents camps:
|
|
32
|
-
|
|
33
|
-
```json
|
|
34
|
-
{
|
|
35
|
-
"name": "plugin-id",
|
|
36
|
-
"version": "1.0.0",
|
|
37
|
-
"module": "dist/plugin.js"
|
|
38
|
-
}
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
- `name`: identificador únic del plugin (id del plugin).
|
|
42
|
-
- `version`: versió que es publicarà.
|
|
43
|
-
- `module`: ruta al fitxer compilat que es pujarà.
|
|
44
|
-
|
|
45
|
-
---
|
|
46
|
-
|
|
47
|
-
## ⚙️ Configuració amb `.harmonixrc`
|
|
48
|
-
|
|
49
|
-
Crea un fitxer `.harmonixrc` a la carpeta arrel del projecte (en cas de monorepo també serveix) amb el següent contingut:
|
|
50
|
-
|
|
51
|
-
```
|
|
52
|
-
registry=https://plugins.harmonix.dev/upload
|
|
53
|
-
apiKey=la_teva_clau_api
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
- `registry`: URL del plugin store.
|
|
57
|
-
- `apiKey`: clau API per a l’autenticació.
|
|
58
|
-
|
|
59
|
-
> 🛑 **Important**: El fitxer `.harmonixrc` conté credencials sensibles. No l’incloguis al repositori de codi. Afegeix-lo al `.gitignore`:
|
|
60
|
-
>
|
|
61
|
-
> ```
|
|
62
|
-
> .harmonixrc
|
|
63
|
-
> ```
|
|
64
|
-
|
|
65
|
-
---
|
|
66
|
-
|
|
67
|
-
## 🧰 Paràmetres opcionals (substitueixen `.harmonixrc`)
|
|
68
|
-
|
|
69
|
-
També pots passar les opcions directament per línia de comandes:
|
|
3
|
+
The [Harmonix](https://harmonixframework.dev) command-line tool. Its command, `harmonix publish`, uploads a built plugin to a Plugin Store. It does not build the plugin or change its version: run your build first and set `version` in `package.json` yourself.
|
|
70
4
|
|
|
71
5
|
```bash
|
|
72
|
-
|
|
6
|
+
npm install --save-dev @uxland/harmonix-cli
|
|
7
|
+
npm run build
|
|
8
|
+
npx harmonix publish
|
|
73
9
|
```
|
|
74
10
|
|
|
75
|
-
|
|
76
|
-
- `--api-key`: clau API d’autenticació.
|
|
77
|
-
|
|
78
|
-
---
|
|
11
|
+
Run it from the plugin folder. From its `package.json` it reads `name` (the plugin id), `version` and `module` (the built file to upload).
|
|
79
12
|
|
|
80
|
-
##
|
|
13
|
+
## Configuration
|
|
81
14
|
|
|
82
|
-
|
|
83
|
-
| ------------------------------------------ | -------------------------------------------------------------------------- | -------------------------------------------------------- |
|
|
84
|
-
| `package.json not found` | No s’ha trobat el fitxer `package.json` a la carpeta actual | Executa `harmonix publish` des de la carpeta del plugin |
|
|
85
|
-
| `'module' field not found in package.json` | Falta el camp `module` al `package.json` | Afegeix "module": "ruta/al/fitxer.js" |
|
|
86
|
-
| `Compiled bundle file not found` | El fitxer indicat al `module` no existeix | Compila el plugin abans de publicar o verifica la ruta |
|
|
87
|
-
| `No registry configured` | No s’ha especificat `registry` ni a `.harmonixrc` ni per línia de comandes | Afegeix `registry=` a `.harmonixrc` o passa `--registry` |
|
|
88
|
-
| `No api key configured` | Falta la clau API (`apiKey`) | Afegeix-la a `.harmonixrc` o passa `--api-key` |
|
|
15
|
+
The registry URL and the API key go in a `.harmonixrc` file, in the plugin folder or any folder above it (one at the root of a monorepo works for all its plugins), or in your home folder:
|
|
89
16
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
Per veure els comandaments disponibles:
|
|
95
|
-
|
|
96
|
-
```bash
|
|
97
|
-
npx harmonix --help
|
|
17
|
+
```ini
|
|
18
|
+
registry=https://your-plugin-store.example.com/upload
|
|
19
|
+
apiKey=your-api-key
|
|
98
20
|
```
|
|
99
21
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
## ✅ Exemple complet
|
|
22
|
+
The `--registry` and `--api-key` options override the file. A project `.harmonixrc` (the nearest one above the plugin folder) overrides the one in your home folder.
|
|
103
23
|
|
|
104
|
-
|
|
105
|
-
npx harmonix publish --registry https://plugins.harmonix.dev/upload --api-key ABC123XYZ
|
|
106
|
-
```
|
|
24
|
+
`harmonix publish` exits with code `1` when the upload fails (for example, the plugin does not exist in the store or the version is already published), so scripts can stop on errors.
|
|
107
25
|
|
|
108
|
-
|
|
26
|
+
> `.harmonixrc` contains credentials: never commit it. Projects made with `npm create @uxland/harmonix-plugin@latest` already ignore it.
|
|
109
27
|
|
|
110
|
-
|
|
111
|
-
npx harmonix publish
|
|
112
|
-
```
|
|
28
|
+
## Documentation
|
|
113
29
|
|
|
30
|
+
- [This package](https://harmonixframework.dev/docs/packages/cli/): configuration order, the request it sends, errors and exit codes.
|
|
31
|
+
- [Build and publish a plugin](https://harmonixframework.dev/docs/create-plugin/build-and-publish/).
|
package/index.js
CHANGED
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const { program } = require(
|
|
4
|
-
const path = require(
|
|
5
|
-
const fs = require(
|
|
6
|
-
const os = require(
|
|
7
|
-
const axios = require(
|
|
8
|
-
const FormData = require(
|
|
9
|
-
|
|
10
|
-
console.log("reached index");
|
|
3
|
+
const { program } = require("commander");
|
|
4
|
+
const path = require("node:path");
|
|
5
|
+
const fs = require("node:fs");
|
|
6
|
+
const os = require("node:os");
|
|
7
|
+
const axios = require("axios");
|
|
8
|
+
const FormData = require("form-data");
|
|
11
9
|
|
|
12
10
|
function getConfig() {
|
|
13
11
|
const config = {};
|
|
12
|
+
|
|
13
|
+
// User-level config (~/.harmonixrc) first, so the project's .harmonixrc overrides it
|
|
14
|
+
const homeConfigPath = path.join(os.homedir(), ".harmonixrc");
|
|
15
|
+
if (fs.existsSync(homeConfigPath)) {
|
|
16
|
+
Object.assign(config, parseConfigFile(homeConfigPath));
|
|
17
|
+
}
|
|
18
|
+
|
|
14
19
|
let dir = process.cwd();
|
|
15
20
|
let steps = 0;
|
|
16
21
|
const maxSteps = 10;
|
|
17
22
|
|
|
18
23
|
while (steps < maxSteps) {
|
|
19
|
-
const configPath = path.join(dir,
|
|
24
|
+
const configPath = path.join(dir, ".harmonixrc");
|
|
20
25
|
if (fs.existsSync(configPath)) {
|
|
21
26
|
Object.assign(config, parseConfigFile(configPath));
|
|
22
27
|
break; // stop at first .harmonixrc found
|
|
@@ -28,27 +33,24 @@ function getConfig() {
|
|
|
28
33
|
steps++;
|
|
29
34
|
}
|
|
30
35
|
|
|
31
|
-
// Also merge user-level config (~/.harmonixrc)
|
|
32
|
-
const homeConfigPath = path.join(os.homedir(), '.harmonixrc');
|
|
33
|
-
if (fs.existsSync(homeConfigPath)) {
|
|
34
|
-
Object.assign(config, parseConfigFile(homeConfigPath));
|
|
35
|
-
}
|
|
36
|
-
|
|
37
36
|
return config;
|
|
38
37
|
}
|
|
39
38
|
|
|
40
39
|
function parseConfigFile(filePath) {
|
|
41
40
|
const result = {};
|
|
42
41
|
try {
|
|
43
|
-
const content = fs.readFileSync(filePath,
|
|
44
|
-
content.split(
|
|
45
|
-
if (line.trim() && !line.startsWith(
|
|
46
|
-
|
|
42
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
43
|
+
for (const line of content.split("\n")) {
|
|
44
|
+
if (line.trim() && !line.startsWith("#")) {
|
|
45
|
+
// Split on the first '=' only: a value may contain '=' (e.g. base64 padding)
|
|
46
|
+
const separator = line.indexOf("=");
|
|
47
|
+
const key = separator === -1 ? "" : line.slice(0, separator).trim();
|
|
48
|
+
const value = separator === -1 ? "" : line.slice(separator + 1).trim();
|
|
47
49
|
if (key && value) {
|
|
48
|
-
result[key
|
|
50
|
+
result[key] = value;
|
|
49
51
|
}
|
|
50
52
|
}
|
|
51
|
-
}
|
|
53
|
+
}
|
|
52
54
|
} catch (err) {
|
|
53
55
|
console.warn(`⚠️ Error reading ${filePath}:`, err.message);
|
|
54
56
|
}
|
|
@@ -56,9 +58,9 @@ function parseConfigFile(filePath) {
|
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
program
|
|
59
|
-
.command(
|
|
60
|
-
.option(
|
|
61
|
-
.option(
|
|
61
|
+
.command("publish")
|
|
62
|
+
.option("--registry <registry>", "Backend URL (overrides .harmonixrc)")
|
|
63
|
+
.option("--api-key <apiKey>", "API Key (overrides .harmonixrc)")
|
|
62
64
|
.action(async (opts) => {
|
|
63
65
|
try {
|
|
64
66
|
const config = getConfig();
|
|
@@ -99,12 +101,19 @@ program
|
|
|
99
101
|
}
|
|
100
102
|
|
|
101
103
|
const headers = {
|
|
102
|
-
|
|
104
|
+
"x-api-key": apiKey,
|
|
103
105
|
};
|
|
104
106
|
const response = await axios.post(registry, formData, { headers });
|
|
105
|
-
|
|
107
|
+
if (response.data?.success === false) {
|
|
108
|
+
throw new Error(response.data.error || response.data.message || "Plugin Store rejected the upload");
|
|
109
|
+
}
|
|
110
|
+
console.log(`✅ Plugin published: ${pluginId}@${versionNumber}`, response.data);
|
|
106
111
|
} catch (err) {
|
|
107
|
-
|
|
112
|
+
// Exit non-zero so scripts and CI can tell a failed publish from a successful one
|
|
113
|
+
const serverError = err.response?.data?.error || err.response?.data?.message;
|
|
114
|
+
const status = err.response ? ` (HTTP ${err.response.status})` : "";
|
|
115
|
+
console.error(`❌ Failed to publish${status}:`, serverError || err.message);
|
|
116
|
+
process.exit(1);
|
|
108
117
|
}
|
|
109
118
|
});
|
|
110
119
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uxland/harmonix-cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"bin": {
|
|
5
5
|
"harmonix": "index.js"
|
|
6
6
|
},
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
"index.js"
|
|
9
9
|
],
|
|
10
10
|
"main": "index.js",
|
|
11
|
-
"description": "
|
|
11
|
+
"description": "The Harmonix command-line tool: publishes a built plugin to a Plugin Store.",
|
|
12
|
+
"homepage": "https://harmonixframework.dev/docs/packages/cli/",
|
|
12
13
|
"author": "Cristian Payet <cpayet@uxland.cat>",
|
|
13
14
|
"publishConfig": {
|
|
14
15
|
"access": "public"
|
|
@@ -19,7 +20,7 @@
|
|
|
19
20
|
"harmonix"
|
|
20
21
|
],
|
|
21
22
|
"dependencies": {
|
|
22
|
-
"axios": "^1.
|
|
23
|
+
"axios": "^1.12.2",
|
|
23
24
|
"commander": "^9.4.0",
|
|
24
25
|
"form-data": "^4.0.0"
|
|
25
26
|
}
|