@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.
@@ -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
+ }