@o861runners/nmp 1.26.13-0.11255
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/.publishrc.example.json +55 -0
- package/LICENSE +21 -0
- package/README.md +195 -0
- package/bin/cli.js +183 -0
- package/package.json +36 -0
- package/src/config/loader.js +110 -0
- package/src/config/replacer.js +57 -0
- package/src/core/publisher.js +314 -0
- package/src/core/registry.js +42 -0
- package/src/registries/gitea.js +44 -0
- package/src/registries/github.js +39 -0
- package/src/registries/npm.js +90 -0
- package/src/registries/pocketbase.js +102 -0
- package/src/registries/supabase.js +86 -0
- package/src/utils/npm-args.js +48 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"registries": {
|
|
3
|
+
"npmjs-public": {
|
|
4
|
+
"type": "npm",
|
|
5
|
+
"registry": "https://registry.npmjs.org",
|
|
6
|
+
"token": "{{NPM_TOKEN}}",
|
|
7
|
+
"access": "public",
|
|
8
|
+
"enabled": true
|
|
9
|
+
},
|
|
10
|
+
|
|
11
|
+
"codeberg": {
|
|
12
|
+
"type": "gitea",
|
|
13
|
+
"url": "https://codeberg.org",
|
|
14
|
+
"owner": "{{CODEBERG_OWNER}}",
|
|
15
|
+
"token": "{{CODEBERG_TOKEN}}",
|
|
16
|
+
"access": "public",
|
|
17
|
+
"enabled": false
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
"github": {
|
|
21
|
+
"type": "github",
|
|
22
|
+
"owner": "{{GITHUB_OWNER}}",
|
|
23
|
+
"repo": "{{GITHUB_REPO}}",
|
|
24
|
+
"token": "{{GITHUB_TOKEN}}",
|
|
25
|
+
"enabled": false
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
"gitea-selfhost": {
|
|
29
|
+
"type": "gitea",
|
|
30
|
+
"url": "{{GITEA_URL}}",
|
|
31
|
+
"owner": "{{GITEA_OWNER}}",
|
|
32
|
+
"token": "{{GITEA_TOKEN}}",
|
|
33
|
+
"enabled": false
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
"supabase-backup": {
|
|
37
|
+
"type": "supabase",
|
|
38
|
+
"url": "{{SUPABASE_URL}}",
|
|
39
|
+
"bucket": "{{SUPABASE_BUCKET}}",
|
|
40
|
+
"serviceKey": "{{SUPABASE_SERVICE_KEY}}",
|
|
41
|
+
"public": true,
|
|
42
|
+
"enabled": false
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
"build": {
|
|
47
|
+
"command": null,
|
|
48
|
+
"skipBuild": false
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
"npm": {
|
|
52
|
+
"defaultArgs": ["--no-git-checks"],
|
|
53
|
+
"customArgs": []
|
|
54
|
+
}
|
|
55
|
+
}
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 npm-multi-publish
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# npm-multi-publish - Updated Version
|
|
2
|
+
|
|
3
|
+
## 🆕 Các thay đổi mới
|
|
4
|
+
|
|
5
|
+
Phiên bản này đã được cập nhật để giải quyết các vấn đề sau:
|
|
6
|
+
|
|
7
|
+
### ✅ Vấn đề đã giải quyết
|
|
8
|
+
|
|
9
|
+
1. **Publish lên nhiều host với package name khác nhau**
|
|
10
|
+
- Mỗi registry có thể có scope khác nhau
|
|
11
|
+
- Tự động tạo package name phù hợp cho từng registry
|
|
12
|
+
|
|
13
|
+
2. **Tách riêng source tgz cho từng host**
|
|
14
|
+
- Mỗi registry có file .tgz riêng biệt
|
|
15
|
+
- Tránh xung đột khi publish đồng thời
|
|
16
|
+
|
|
17
|
+
3. **Tự động tăng version**
|
|
18
|
+
- Format: `1.yy.mmdd.1hhMM`
|
|
19
|
+
- Ví dụ: `1.26.0130.11545` (30 Jan 2026, 15:45)
|
|
20
|
+
- Đảm bảo mỗi lần publish đều có version mới
|
|
21
|
+
|
|
22
|
+
4. **NPX commands**
|
|
23
|
+
- Hướng dẫn chi tiết cách chạy trực tiếp từ các registry
|
|
24
|
+
- Support cả Windows và Linux
|
|
25
|
+
|
|
26
|
+
## 📚 Tài liệu
|
|
27
|
+
|
|
28
|
+
- **[SUMMARY.md](SUMMARY.md)** - Tóm tắt ngắn gọn các thay đổi
|
|
29
|
+
- **[CHANGES.md](CHANGES.md)** - Chi tiết đầy đủ về code changes
|
|
30
|
+
- **[NPX.md](NPX.md)** - Hướng dẫn sử dụng npx commands
|
|
31
|
+
|
|
32
|
+
## 🚀 Quick Start
|
|
33
|
+
|
|
34
|
+
### 1. Config file
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"registries": {
|
|
39
|
+
"npmjs": {
|
|
40
|
+
"type": "npm",
|
|
41
|
+
"token": "{{NPM_TOKEN}}",
|
|
42
|
+
"enabled": true
|
|
43
|
+
},
|
|
44
|
+
"codeberg": {
|
|
45
|
+
"type": "gitea",
|
|
46
|
+
"url": "https://codeberg.org",
|
|
47
|
+
"owner": "o861runners",
|
|
48
|
+
"token": "{{CODEBERG_TOKEN}}",
|
|
49
|
+
"enabled": true
|
|
50
|
+
},
|
|
51
|
+
"github": {
|
|
52
|
+
"type": "github",
|
|
53
|
+
"owner": "myusername",
|
|
54
|
+
"repo": "myrepo",
|
|
55
|
+
"token": "{{GITHUB_TOKEN}}",
|
|
56
|
+
"enabled": true
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 2. Publish
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
export NPM_TOKEN=npm_xxxxx
|
|
66
|
+
export CODEBERG_TOKEN=xxxxx
|
|
67
|
+
export GITHUB_TOKEN=ghp_xxxxx
|
|
68
|
+
|
|
69
|
+
npm-multi-publish publish
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 3. Kết quả
|
|
73
|
+
|
|
74
|
+
**Original package.json:**
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"name": "my-package",
|
|
79
|
+
"version": "1.0.0"
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Packages được publish:**
|
|
84
|
+
|
|
85
|
+
- npmjs: `my-package@1.26.0130.11545`
|
|
86
|
+
- codeberg: `@o861runners/my-package@1.26.0130.11545`
|
|
87
|
+
- github: `@myusername/my-package@1.26.0130.11545`
|
|
88
|
+
|
|
89
|
+
**Files được tạo:**
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
.npm-multi-publish-tmp/
|
|
93
|
+
├── npmjs-my-package-1.26.0130.11545.tgz
|
|
94
|
+
├── codeberg-o861runners-my-package-1.26.0130.11545.tgz
|
|
95
|
+
└── github-myusername-my-package-1.26.0130.11545.tgz
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## 📝 Code Changes Overview
|
|
99
|
+
|
|
100
|
+
### `src/core/publisher.js`
|
|
101
|
+
|
|
102
|
+
**3 methods mới:**
|
|
103
|
+
|
|
104
|
+
1. `generateVersion()` - Auto-generate version
|
|
105
|
+
2. `createRegistryPackage()` - Tạo package.json riêng cho registry
|
|
106
|
+
3. `packForRegistry()` - Pack file .tgz riêng
|
|
107
|
+
|
|
108
|
+
**Flow mới:**
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
Original package.json
|
|
112
|
+
↓
|
|
113
|
+
For each registry:
|
|
114
|
+
↓
|
|
115
|
+
1. Create registry-specific package.json (with scope + new version)
|
|
116
|
+
↓
|
|
117
|
+
2. Backup original package.json
|
|
118
|
+
↓
|
|
119
|
+
3. Replace with registry-specific package.json
|
|
120
|
+
↓
|
|
121
|
+
4. npm pack → create .tgz
|
|
122
|
+
↓
|
|
123
|
+
5. Rename: registry-name-package-version.tgz
|
|
124
|
+
↓
|
|
125
|
+
6. Restore original package.json
|
|
126
|
+
↓
|
|
127
|
+
7. Publish .tgz to registry
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## 🔍 Example Commands
|
|
131
|
+
|
|
132
|
+
### Publish to all registries
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
npm-multi-publish publish
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Publish to specific registries
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
npm-multi-publish publish --target npmjs,codeberg
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Test from each registry
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
# NPM
|
|
148
|
+
npx --yes my-package hello
|
|
149
|
+
|
|
150
|
+
# Codeberg
|
|
151
|
+
npx --yes --registry=https://codeberg.org/api/packages/o861runners/npm/ @o861runners/my-package hello
|
|
152
|
+
|
|
153
|
+
# GitHub
|
|
154
|
+
npx --yes --registry=https://npm.pkg.github.com @myusername/my-package hello
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## 📊 Version Format
|
|
158
|
+
|
|
159
|
+
Format: `1.yy.mmdd.1hhMM`
|
|
160
|
+
|
|
161
|
+
**Ví dụ:**
|
|
162
|
+
|
|
163
|
+
- 30/01/2026 15:45 → `1.26.0130.11545`
|
|
164
|
+
- 15/12/2026 09:30 → `1.26.1215.10930`
|
|
165
|
+
- 01/03/2027 23:59 → `1.27.0301.12359`
|
|
166
|
+
|
|
167
|
+
**Giải thích:**
|
|
168
|
+
|
|
169
|
+
- `1` - Fixed prefix
|
|
170
|
+
- `yy` - 2 chữ số cuối của năm (26 = 2026)
|
|
171
|
+
- `mmdd` - Tháng + ngày (0130 = 30 tháng 1)
|
|
172
|
+
- `1` - Fixed separator
|
|
173
|
+
- `hhMM` - Giờ + phút (1545 = 15:45)
|
|
174
|
+
|
|
175
|
+
→ Đảm bảo version luôn tăng dần theo thời gian
|
|
176
|
+
|
|
177
|
+
## 🎯 Benefits
|
|
178
|
+
|
|
179
|
+
✅ **Tách biệt hoàn toàn:** Mỗi registry có file riêng
|
|
180
|
+
✅ **Tự động hóa:** Package name và version tự động đúng
|
|
181
|
+
✅ **An toàn:** Luôn backup và restore package.json gốc
|
|
182
|
+
✅ **Dễ debug:** Biết chính xác file nào publish đến đâu
|
|
183
|
+
✅ **Không xung đột:** Các registry không ảnh hưởng lẫn nhau
|
|
184
|
+
|
|
185
|
+
## 🔗 Links
|
|
186
|
+
|
|
187
|
+
- [Full Documentation](CHANGES.md)
|
|
188
|
+
- [Quick Summary](SUMMARY.md)
|
|
189
|
+
- [NPX Commands Guide](NPX.md)
|
|
190
|
+
- [Original PLANS.md](PLANS.md)
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
**Version:** 1.1.0
|
|
195
|
+
**Last Updated:** 2026-01-30
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import { loadConfig } from "../src/config/loader.js";
|
|
5
|
+
import { hasUnresolvedVars } from "../src/config/replacer.js";
|
|
6
|
+
import { Publisher } from "../src/core/publisher.js";
|
|
7
|
+
import chalk from "chalk";
|
|
8
|
+
import fs from "fs";
|
|
9
|
+
|
|
10
|
+
const program = new Command();
|
|
11
|
+
|
|
12
|
+
program.name("npm-multi-publish").description("Publish NPM packages to multiple registries").version("1.0.0");
|
|
13
|
+
|
|
14
|
+
// ============================================================
|
|
15
|
+
// Command: publish
|
|
16
|
+
// ============================================================
|
|
17
|
+
program
|
|
18
|
+
.command("publish")
|
|
19
|
+
.description("Build and publish package to registries")
|
|
20
|
+
.option("-c, --config <path>", "Config file path", ".publishrc.json")
|
|
21
|
+
.option("-t, --target <targets>", "Comma-separated registry names to publish to")
|
|
22
|
+
.option("--dry-run", "Dry run mode (no actual publishing)")
|
|
23
|
+
.option("--skip-build", "Skip build step")
|
|
24
|
+
.allowUnknownOption()
|
|
25
|
+
.action(async (options) => {
|
|
26
|
+
try {
|
|
27
|
+
// 1. Load config (auto replace {{VAR}} from process.env)
|
|
28
|
+
console.log(chalk.gray(`Loading config from ${options.config}...`));
|
|
29
|
+
const config = loadConfig(options.config);
|
|
30
|
+
|
|
31
|
+
// 2. Parse targets
|
|
32
|
+
if (options.target) {
|
|
33
|
+
options.targets = options.target.split(",").map((t) => t.trim());
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// 3. Run publisher
|
|
37
|
+
const publisher = new Publisher(config, options);
|
|
38
|
+
const results = await publisher.run();
|
|
39
|
+
|
|
40
|
+
// 4. Check results and exit
|
|
41
|
+
const failures = results.filter((r) => !r.success && !r.dryRun);
|
|
42
|
+
|
|
43
|
+
if (failures.length > 0) {
|
|
44
|
+
console.error(chalk.red(`\n❌ ${failures.length} registry(ies) failed`));
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
console.log(chalk.green("\n✅ All registries published successfully!"));
|
|
49
|
+
process.exit(0);
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.error(chalk.red(`\n❌ Error: ${error.message}`));
|
|
52
|
+
if (process.env.DEBUG) {
|
|
53
|
+
console.error(error.stack);
|
|
54
|
+
}
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// ============================================================
|
|
60
|
+
// Command: init
|
|
61
|
+
// ============================================================
|
|
62
|
+
program
|
|
63
|
+
.command("init")
|
|
64
|
+
.description("Create example .publishrc.json config file")
|
|
65
|
+
.action(() => {
|
|
66
|
+
const template = {
|
|
67
|
+
registries: {
|
|
68
|
+
"npmjs-public": {
|
|
69
|
+
type: "npm",
|
|
70
|
+
token: "{{NPM_TOKEN}}",
|
|
71
|
+
access: "public",
|
|
72
|
+
enabled: true,
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
build: {
|
|
76
|
+
command: null,
|
|
77
|
+
skipBuild: false,
|
|
78
|
+
},
|
|
79
|
+
npm: {
|
|
80
|
+
defaultArgs: ["--no-git-checks"],
|
|
81
|
+
customArgs: [],
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const configPath = ".publishrc.json";
|
|
86
|
+
|
|
87
|
+
if (fs.existsSync(configPath)) {
|
|
88
|
+
console.error(chalk.red("❌ .publishrc.json already exists"));
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
fs.writeFileSync(configPath, JSON.stringify(template, null, 2));
|
|
93
|
+
console.log(chalk.green("✅ Created .publishrc.json"));
|
|
94
|
+
console.log("\nNext steps:");
|
|
95
|
+
console.log("1. Edit .publishrc.json and configure your registries");
|
|
96
|
+
console.log("2. Set environment variables (NPM_TOKEN, etc.)");
|
|
97
|
+
console.log("3. Run: npm-multi-publish publish");
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// ============================================================
|
|
101
|
+
// Command: verify
|
|
102
|
+
// ============================================================
|
|
103
|
+
program
|
|
104
|
+
.command("verify")
|
|
105
|
+
.description("Verify config and environment variables")
|
|
106
|
+
.option("-c, --config <path>", "Config file path", ".publishrc.json")
|
|
107
|
+
.action((options) => {
|
|
108
|
+
try {
|
|
109
|
+
console.log(chalk.bold("\n🔍 Verifying configuration...\n"));
|
|
110
|
+
|
|
111
|
+
const config = loadConfig(options.config);
|
|
112
|
+
const unresolved = hasUnresolvedVars(config);
|
|
113
|
+
|
|
114
|
+
// List all registries
|
|
115
|
+
for (const [name, registry] of Object.entries(config.registries || {})) {
|
|
116
|
+
const status = registry.enabled ? chalk.green("✓") : chalk.gray("○");
|
|
117
|
+
const label = registry.enabled ? "enabled" : "disabled";
|
|
118
|
+
console.log(`${status} ${name} (${registry.type}) - ${label}`);
|
|
119
|
+
|
|
120
|
+
// Check for unresolved vars in this registry
|
|
121
|
+
const regJson = JSON.stringify(registry);
|
|
122
|
+
const regUnresolved = regJson.match(/\{\{[A-Z_][A-Z0-9_]*\}\}/g) || [];
|
|
123
|
+
|
|
124
|
+
if (regUnresolved.length > 0 && registry.enabled) {
|
|
125
|
+
console.log(chalk.yellow(` ⚠️ Missing env vars: ${regUnresolved.join(", ")}`));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
console.log("");
|
|
130
|
+
|
|
131
|
+
if (unresolved.length > 0) {
|
|
132
|
+
console.log(chalk.yellow(`⚠️ Total unresolved variables: ${unresolved.length}`));
|
|
133
|
+
console.log(chalk.yellow(" Set these environment variables before publishing:"));
|
|
134
|
+
unresolved.forEach((v) => console.log(chalk.yellow(` - ${v.replace(/[{}]/g, "")}`)));
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
console.log(chalk.green("✅ Configuration is valid!"));
|
|
139
|
+
console.log(chalk.gray("\nAll environment variables are set correctly."));
|
|
140
|
+
process.exit(0);
|
|
141
|
+
} catch (error) {
|
|
142
|
+
console.error(chalk.red(`\n❌ Error: ${error.message}`));
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// ============================================================
|
|
148
|
+
// Command: list
|
|
149
|
+
// ============================================================
|
|
150
|
+
program
|
|
151
|
+
.command("list")
|
|
152
|
+
.description("List all configured registries")
|
|
153
|
+
.option("-c, --config <path>", "Config file path", ".publishrc.json")
|
|
154
|
+
.action((options) => {
|
|
155
|
+
try {
|
|
156
|
+
const config = loadConfig(options.config);
|
|
157
|
+
|
|
158
|
+
console.log(chalk.bold("\n📋 Configured Registries:\n"));
|
|
159
|
+
|
|
160
|
+
if (Object.keys(config.registries || {}).length === 0) {
|
|
161
|
+
console.log(chalk.yellow("No registries configured."));
|
|
162
|
+
console.log("Run: npm-multi-publish init");
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
for (const [name, registry] of Object.entries(config.registries)) {
|
|
167
|
+
const icon = registry.enabled ? "✓" : "○";
|
|
168
|
+
const color = registry.enabled ? chalk.green : chalk.gray;
|
|
169
|
+
console.log(color(`${icon} ${name}`));
|
|
170
|
+
console.log(color(` Type: ${registry.type}`));
|
|
171
|
+
console.log(color(` Access: ${registry.access || "public"}`));
|
|
172
|
+
if (registry.registry) {
|
|
173
|
+
console.log(color(` Registry: ${registry.registry}`));
|
|
174
|
+
}
|
|
175
|
+
console.log("");
|
|
176
|
+
}
|
|
177
|
+
} catch (error) {
|
|
178
|
+
console.error(chalk.red(`\n❌ Error: ${error.message}`));
|
|
179
|
+
process.exit(1);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
program.parse();
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@o861runners/nmp",
|
|
3
|
+
"version": "1.26.0130.11255",
|
|
4
|
+
"description": "CLI tool to build, pack and publish NPM packages to multiple registries with auto-versioning",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"npm-multi-publish": "./bin/cli.js",
|
|
9
|
+
"nmp": "./bin/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"test": "node test/runner.js"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"npm",
|
|
16
|
+
"publish",
|
|
17
|
+
"multi-registry",
|
|
18
|
+
"github-packages",
|
|
19
|
+
"gitea",
|
|
20
|
+
"codeberg",
|
|
21
|
+
"supabase",
|
|
22
|
+
"auto-version"
|
|
23
|
+
],
|
|
24
|
+
"author": "",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=14.0.0"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"commander": "^11.0.0",
|
|
31
|
+
"chalk": "^4.1.2",
|
|
32
|
+
"ora": "^5.4.1",
|
|
33
|
+
"node-fetch": "^2.7.0",
|
|
34
|
+
"form-data": "^4.0.0"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { replaceEnvVarsDeep, hasUnresolvedVars } from './replacer.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Load config với full defaults support
|
|
7
|
+
*/
|
|
8
|
+
export function loadConfig(configPath = '.publishrc.json') {
|
|
9
|
+
let config = {};
|
|
10
|
+
|
|
11
|
+
// 1. Load file nếu tồn tại
|
|
12
|
+
if (fs.existsSync(configPath)) {
|
|
13
|
+
const raw = fs.readFileSync(configPath, 'utf-8');
|
|
14
|
+
config = JSON.parse(raw);
|
|
15
|
+
} else {
|
|
16
|
+
console.warn(`⚠️ Config file ${configPath} not found, using defaults`);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// 2. Apply base defaults
|
|
20
|
+
config = applyBaseDefaults(config);
|
|
21
|
+
|
|
22
|
+
// 3. Replace {{VAR}} từ process.env
|
|
23
|
+
config = replaceEnvVarsDeep(config, process.env);
|
|
24
|
+
|
|
25
|
+
// 4. Validate có VAR nào chưa resolve không
|
|
26
|
+
const unresolved = hasUnresolvedVars(config);
|
|
27
|
+
if (unresolved.length > 0) {
|
|
28
|
+
console.warn(`⚠️ Unresolved variables: ${unresolved.join(', ')}`);
|
|
29
|
+
console.warn(' These registries may fail if enabled');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return config;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Apply defaults cho toàn bộ config
|
|
37
|
+
*/
|
|
38
|
+
function applyBaseDefaults(config) {
|
|
39
|
+
// Build defaults
|
|
40
|
+
if (!config.build) {
|
|
41
|
+
config.build = {};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (config.build.command === undefined) {
|
|
45
|
+
config.build.command = detectBuildCommand();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (config.build.skipBuild === undefined) {
|
|
49
|
+
config.build.skipBuild = false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// NPM defaults
|
|
53
|
+
if (!config.npm) {
|
|
54
|
+
config.npm = {};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (!config.npm.defaultArgs) {
|
|
58
|
+
config.npm.defaultArgs = ['--no-git-checks'];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (!config.npm.customArgs) {
|
|
62
|
+
config.npm.customArgs = [];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Registries defaults
|
|
66
|
+
if (!config.registries) {
|
|
67
|
+
config.registries = {};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
for (const [name, registry] of Object.entries(config.registries)) {
|
|
71
|
+
config.registries[name] = applyRegistryDefaults(registry);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return config;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Apply defaults cho từng registry
|
|
79
|
+
*/
|
|
80
|
+
function applyRegistryDefaults(registry) {
|
|
81
|
+
const defaults = {
|
|
82
|
+
enabled: true,
|
|
83
|
+
access: 'public',
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// Type-specific defaults
|
|
87
|
+
if (registry.type === 'npm') {
|
|
88
|
+
defaults.registry = defaults.registry || 'https://registry.npmjs.org';
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return { ...defaults, ...registry };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Auto-detect build command từ package.json
|
|
96
|
+
*/
|
|
97
|
+
function detectBuildCommand() {
|
|
98
|
+
try {
|
|
99
|
+
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf-8'));
|
|
100
|
+
|
|
101
|
+
if (pkg.scripts?.build) {
|
|
102
|
+
return 'npm run build';
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return null; // Không có build script
|
|
106
|
+
} catch (err) {
|
|
107
|
+
console.warn('⚠️ Cannot read package.json');
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Replace {{VAR}} với process.env
|
|
3
|
+
* @param {string} template - String chứa {{VAR}}
|
|
4
|
+
* @param {object} env - Environment variables (default: process.env)
|
|
5
|
+
* @returns {string} - String đã replace
|
|
6
|
+
*/
|
|
7
|
+
export function replaceEnvVars(template, env = process.env) {
|
|
8
|
+
if (typeof template !== 'string') return template;
|
|
9
|
+
|
|
10
|
+
return template.replace(/\{\{([A-Z_][A-Z0-9_]*)\}\}/g, (match, varName) => {
|
|
11
|
+
const value = env[varName];
|
|
12
|
+
|
|
13
|
+
if (value === undefined) {
|
|
14
|
+
console.warn(`⚠️ Env var ${varName} not set, keeping ${match}`);
|
|
15
|
+
return match;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return value;
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Deep replace toàn bộ object/array
|
|
24
|
+
* @param {object|array|string} obj - Object cần replace
|
|
25
|
+
* @param {object} env - Environment variables
|
|
26
|
+
* @returns {object|array|string} - Object đã replace
|
|
27
|
+
*/
|
|
28
|
+
export function replaceEnvVarsDeep(obj, env = process.env) {
|
|
29
|
+
if (typeof obj === 'string') {
|
|
30
|
+
return replaceEnvVars(obj, env);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (Array.isArray(obj)) {
|
|
34
|
+
return obj.map(item => replaceEnvVarsDeep(item, env));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (obj && typeof obj === 'object') {
|
|
38
|
+
const result = {};
|
|
39
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
40
|
+
result[key] = replaceEnvVarsDeep(value, env);
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return obj;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Kiểm tra config có còn {{VAR}} chưa replace không
|
|
50
|
+
* @param {object} config - Config object
|
|
51
|
+
* @returns {array} - Danh sách các VAR chưa resolve
|
|
52
|
+
*/
|
|
53
|
+
export function hasUnresolvedVars(config) {
|
|
54
|
+
const json = JSON.stringify(config);
|
|
55
|
+
const matches = json.match(/\{\{[A-Z_][A-Z0-9_]*\}\}/g);
|
|
56
|
+
return matches || [];
|
|
57
|
+
}
|