@olegkuibar/plunk 0.2.3 → 0.3.0-canary.0807dec
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/dist/add-4LHIITHV.mjs +14 -0
- package/dist/chokidar-LVDD2IK4.mjs +4 -0
- package/dist/chunk-2VCW5RWI.mjs +3 -0
- package/dist/chunk-4QWBGXB5.mjs +15 -0
- package/dist/chunk-4TNTNSAB.mjs +4 -0
- package/dist/chunk-6YX2BGO2.mjs +3 -0
- package/dist/chunk-7JG555TZ.mjs +3 -0
- package/dist/chunk-AR7AKSKG.mjs +3 -0
- package/dist/chunk-HW7AEGI3.mjs +3 -0
- package/dist/chunk-KVVUZ6KL.mjs +4 -0
- package/dist/chunk-LI4HG26F.mjs +4 -0
- package/dist/chunk-MBKCCWSD.mjs +3 -0
- package/dist/chunk-OL7SNXMX.mjs +7 -0
- package/dist/chunk-QUI5JAIH.mjs +3 -0
- package/dist/chunk-RITKSDMP.mjs +3 -0
- package/dist/chunk-UAGG5WMD.mjs +3 -0
- package/dist/chunk-UDONDVIM.mjs +7 -0
- package/dist/chunk-ZAUWE3N7.mjs +12 -0
- package/dist/chunk-ZIXSXQRE.mjs +3 -0
- package/dist/chunk-ZJMZKJNW.mjs +3 -0
- package/dist/clean-EWBL6FW2.mjs +3 -0
- package/dist/cli.mjs +2 -56
- package/dist/dev-NCLIWE2E.mjs +3 -0
- package/dist/doctor-PXC45S34.mjs +4 -0
- package/dist/index.d.ts +19 -2
- package/dist/index.mjs +572 -244
- package/dist/init-TZ76GAWN.mjs +7 -0
- package/dist/list-CCR7QD7N.mjs +5 -0
- package/dist/migrate-6RZ3SEU5.mjs +8 -0
- package/dist/publish-4TDT6TTS.mjs +3 -0
- package/dist/push-M4RSFETI.mjs +3 -0
- package/dist/remove-R55FIXPL.mjs +3 -0
- package/dist/restore-XBFOHISI.mjs +11 -0
- package/dist/status-GCATYK2I.mjs +4 -0
- package/dist/tailwind-source-VPNLLSRJ.mjs +5 -0
- package/dist/update-6PLGM37S.mjs +3 -0
- package/dist/vite-config-ZMDIOTXC.mjs +10 -0
- package/dist/vite-plugin.mjs +2 -1
- package/dist/workspace-VREEJZ76.mjs +3 -0
- package/package.json +2 -8
- package/dist/add-5ZRFUL6Z.mjs +0 -258
- package/dist/chokidar-XGAEDN45.mjs +0 -1746
- package/dist/chunk-34UXZ622.mjs +0 -98
- package/dist/chunk-4O2QOKVO.mjs +0 -1958
- package/dist/chunk-CSMZ6DZA.mjs +0 -367
- package/dist/chunk-CZM4TNAI.mjs +0 -292
- package/dist/chunk-EDUXIQ5W.mjs +0 -1729
- package/dist/chunk-GAAB2TLH.mjs +0 -160
- package/dist/chunk-HKNM3UWU.mjs +0 -496
- package/dist/chunk-I6SN7BBN.mjs +0 -1131
- package/dist/chunk-KYDBD2KQ.mjs +0 -39
- package/dist/chunk-LKQINKH4.mjs +0 -130
- package/dist/chunk-PUSXMPOF.mjs +0 -82
- package/dist/chunk-S4HJSJ32.mjs +0 -69
- package/dist/chunk-W3C72UKC.mjs +0 -113
- package/dist/chunk-WSECI6M7.mjs +0 -85
- package/dist/chunk-XMIZ7OUZ.mjs +0 -26
- package/dist/chunk-XZK5T4GK.mjs +0 -23
- package/dist/chunk-ZOYNYK5Y.mjs +0 -23
- package/dist/chunk-ZQCGJUBJ.mjs +0 -92
- package/dist/clean-LTR5MZTY.mjs +0 -84
- package/dist/dev-LFXQP6SA.mjs +0 -194
- package/dist/dist-DUFCZSIL.mjs +0 -813
- package/dist/doctor-R7ZVR7PY.mjs +0 -230
- package/dist/hash-worker.mjs +0 -65
- package/dist/init-SWCNRISY.mjs +0 -310
- package/dist/list-B77L2F34.mjs +0 -119
- package/dist/migrate-X5TIC5SS.mjs +0 -124
- package/dist/prompt-HTPH6HQ7.mjs +0 -756
- package/dist/publish-UXCLPNM6.mjs +0 -63
- package/dist/push-JI6HGCFG.mjs +0 -197
- package/dist/remove-DCR7KKD5.mjs +0 -149
- package/dist/restore-SUN3WGSW.mjs +0 -124
- package/dist/status-MESRBH54.mjs +0 -103
- package/dist/tailwind-source-JBBEIXIJ.mjs +0 -89
- package/dist/update-SKDSA673.mjs +0 -100
- package/dist/vite-config-BAK67JHB.mjs +0 -128
- package/dist/workspace-76HJPAK2.mjs +0 -97
package/dist/index.mjs
CHANGED
|
@@ -8,8 +8,120 @@ var __export = (target, all) => {
|
|
|
8
8
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
+
// src/utils/console.ts
|
|
12
|
+
import pc from "picocolors";
|
|
13
|
+
import { createInterface } from "readline/promises";
|
|
14
|
+
import { stdin, stdout } from "process";
|
|
15
|
+
async function prompt(message, options) {
|
|
16
|
+
const rl = createInterface({ input: stdin, output: stdout });
|
|
17
|
+
try {
|
|
18
|
+
if (options.type === "confirm") {
|
|
19
|
+
const hint = options.initial !== false ? "Y/n" : "y/N";
|
|
20
|
+
const answer2 = await rl.question(
|
|
21
|
+
`${pc.cyan("?")} ${message} ${pc.dim(`(${hint})`)} `
|
|
22
|
+
);
|
|
23
|
+
const val = answer2.trim().toLowerCase();
|
|
24
|
+
if (val === "") return options.initial !== false;
|
|
25
|
+
return val === "y" || val === "yes";
|
|
26
|
+
}
|
|
27
|
+
if (options.type === "text") {
|
|
28
|
+
const hint = options.default ? pc.dim(` (${options.default})`) : "";
|
|
29
|
+
const answer2 = await rl.question(`${pc.cyan("?")} ${message}${hint} `);
|
|
30
|
+
return answer2.trim() || options.default || "";
|
|
31
|
+
}
|
|
32
|
+
console.log(`${pc.cyan("?")} ${message}`);
|
|
33
|
+
for (let i = 0; i < options.options.length; i++) {
|
|
34
|
+
console.log(` ${pc.cyan(`${i + 1}.`)} ${options.options[i].label}`);
|
|
35
|
+
}
|
|
36
|
+
const answer = await rl.question(`${pc.dim("Enter number:")} `);
|
|
37
|
+
const idx = parseInt(answer, 10) - 1;
|
|
38
|
+
if (idx >= 0 && idx < options.options.length) {
|
|
39
|
+
return options.options[idx].value;
|
|
40
|
+
}
|
|
41
|
+
return options.options[0].value;
|
|
42
|
+
} finally {
|
|
43
|
+
rl.close();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
var _level, consola;
|
|
47
|
+
var init_console = __esm({
|
|
48
|
+
"src/utils/console.ts"() {
|
|
49
|
+
"use strict";
|
|
50
|
+
_level = 3;
|
|
51
|
+
consola = {
|
|
52
|
+
get level() {
|
|
53
|
+
return _level;
|
|
54
|
+
},
|
|
55
|
+
set level(n) {
|
|
56
|
+
_level = n;
|
|
57
|
+
},
|
|
58
|
+
info(msg, ...args) {
|
|
59
|
+
if (_level >= 3) console.log(pc.cyan("\u2139"), msg, ...args);
|
|
60
|
+
},
|
|
61
|
+
success(msg, ...args) {
|
|
62
|
+
if (_level >= 3) console.log(pc.green("\u2714"), msg, ...args);
|
|
63
|
+
},
|
|
64
|
+
warn(msg, ...args) {
|
|
65
|
+
if (_level >= 2) console.warn(pc.yellow("\u26A0"), msg, ...args);
|
|
66
|
+
},
|
|
67
|
+
error(msg, ...args) {
|
|
68
|
+
if (_level >= 1) console.error(pc.red("\u2716"), msg, ...args);
|
|
69
|
+
},
|
|
70
|
+
start(msg, ...args) {
|
|
71
|
+
if (_level >= 3) console.log(pc.cyan("\u25D0"), msg, ...args);
|
|
72
|
+
},
|
|
73
|
+
debug(msg, ...args) {
|
|
74
|
+
if (_level >= 4) console.debug(pc.dim("D"), msg, ...args);
|
|
75
|
+
},
|
|
76
|
+
/** Plain log (no icon) that still respects level suppression */
|
|
77
|
+
log(msg, ...args) {
|
|
78
|
+
if (_level >= 3) console.log(msg, ...args);
|
|
79
|
+
},
|
|
80
|
+
prompt
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// src/utils/concurrency.ts
|
|
86
|
+
function pLimit(concurrency) {
|
|
87
|
+
let active = 0;
|
|
88
|
+
const queue = [];
|
|
89
|
+
const next = () => {
|
|
90
|
+
if (queue.length > 0 && active < concurrency) {
|
|
91
|
+
active++;
|
|
92
|
+
queue.shift()();
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
return (fn) => new Promise((resolve6, reject) => {
|
|
96
|
+
const run = () => {
|
|
97
|
+
fn().then(
|
|
98
|
+
(val) => {
|
|
99
|
+
active--;
|
|
100
|
+
resolve6(val);
|
|
101
|
+
next();
|
|
102
|
+
},
|
|
103
|
+
(err) => {
|
|
104
|
+
active--;
|
|
105
|
+
reject(err);
|
|
106
|
+
next();
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
};
|
|
110
|
+
if (active < concurrency) {
|
|
111
|
+
active++;
|
|
112
|
+
run();
|
|
113
|
+
} else {
|
|
114
|
+
queue.push(run);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
var init_concurrency = __esm({
|
|
119
|
+
"src/utils/concurrency.ts"() {
|
|
120
|
+
"use strict";
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
11
124
|
// src/utils/logger.ts
|
|
12
|
-
import { consola } from "consola";
|
|
13
125
|
function isDryRun() {
|
|
14
126
|
return _dryRun;
|
|
15
127
|
}
|
|
@@ -20,6 +132,7 @@ var _verbose, _dryRun;
|
|
|
20
132
|
var init_logger = __esm({
|
|
21
133
|
"src/utils/logger.ts"() {
|
|
22
134
|
"use strict";
|
|
135
|
+
init_console();
|
|
23
136
|
_verbose = false;
|
|
24
137
|
_dryRun = false;
|
|
25
138
|
}
|
|
@@ -30,33 +143,7 @@ import { createHash } from "crypto";
|
|
|
30
143
|
import { createReadStream } from "fs";
|
|
31
144
|
import { readFile, stat } from "fs/promises";
|
|
32
145
|
import { relative } from "path";
|
|
33
|
-
import pLimit from "p-limit";
|
|
34
146
|
import { availableParallelism } from "os";
|
|
35
|
-
import xxhash from "xxhash-wasm";
|
|
36
|
-
async function getXxhash() {
|
|
37
|
-
if (!xxh) xxh = await xxhash();
|
|
38
|
-
return xxh;
|
|
39
|
-
}
|
|
40
|
-
async function getPool() {
|
|
41
|
-
if (poolFailed) return null;
|
|
42
|
-
if (pool) return pool;
|
|
43
|
-
try {
|
|
44
|
-
const { default: Tinypool } = await import("tinypool");
|
|
45
|
-
const poolSize = Math.min(Math.max(availableParallelism(), 2), 8);
|
|
46
|
-
const workerUrl = new URL("./hash-worker.mjs", import.meta.url);
|
|
47
|
-
pool = new Tinypool({
|
|
48
|
-
filename: workerUrl.href,
|
|
49
|
-
minThreads: 0,
|
|
50
|
-
maxThreads: poolSize
|
|
51
|
-
});
|
|
52
|
-
verbose(`[hash] Worker pool initialized (max ${poolSize} threads)`);
|
|
53
|
-
return pool;
|
|
54
|
-
} catch {
|
|
55
|
-
poolFailed = true;
|
|
56
|
-
verbose("[hash] Worker pool unavailable, using main-thread hashing");
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
147
|
async function computeContentHash(files, baseDir) {
|
|
61
148
|
const sorted = [...files].sort((a, b) => {
|
|
62
149
|
const relA = relative(baseDir, a).replace(/\\/g, "/");
|
|
@@ -73,60 +160,43 @@ async function computeContentHash(files, baseDir) {
|
|
|
73
160
|
);
|
|
74
161
|
verbose(`[hash] Computing content hash for ${files.length} files`);
|
|
75
162
|
const hash = createHash("sha256");
|
|
163
|
+
const lenBuf = Buffer.alloc(4);
|
|
76
164
|
for (const { rel, content } of contents) {
|
|
77
165
|
hash.update(rel);
|
|
78
166
|
hash.update("\0");
|
|
167
|
+
lenBuf.writeUInt32LE(content.length);
|
|
168
|
+
hash.update(lenBuf);
|
|
79
169
|
hash.update(content);
|
|
80
170
|
}
|
|
81
|
-
const result = "
|
|
171
|
+
const result = "sha256v2:" + hash.digest("hex");
|
|
82
172
|
verbose(`[hash] Result: ${result.slice(0, 20)}...`);
|
|
83
173
|
return result;
|
|
84
174
|
}
|
|
85
175
|
async function hashFile(filePath, knownSize) {
|
|
86
176
|
const size = knownSize ?? (await stat(filePath)).size;
|
|
87
|
-
if (size <= WORKER_THRESHOLD) {
|
|
88
|
-
return hashFileMainThread(filePath, size);
|
|
89
|
-
}
|
|
90
|
-
const p = await getPool();
|
|
91
|
-
if (p) {
|
|
92
|
-
try {
|
|
93
|
-
return await p.run([filePath, size]);
|
|
94
|
-
} catch {
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return hashFileMainThread(filePath, size);
|
|
98
|
-
}
|
|
99
|
-
async function hashFileMainThread(filePath, size) {
|
|
100
177
|
if (size > STREAM_THRESHOLD) {
|
|
101
178
|
return hashFileStream(filePath);
|
|
102
179
|
}
|
|
103
|
-
const { h64Raw } = await getXxhash();
|
|
104
180
|
const content = await readFile(filePath);
|
|
105
|
-
return
|
|
181
|
+
return createHash("sha256").update(content).digest("hex");
|
|
106
182
|
}
|
|
107
183
|
function hashFileStream(filePath) {
|
|
108
|
-
return new Promise((
|
|
184
|
+
return new Promise((resolve6, reject) => {
|
|
109
185
|
const hash = createHash("sha256");
|
|
110
186
|
const stream = createReadStream(filePath);
|
|
111
187
|
stream.on("data", (chunk) => hash.update(chunk));
|
|
112
|
-
stream.on("end", () =>
|
|
188
|
+
stream.on("end", () => resolve6(hash.digest("hex")));
|
|
113
189
|
stream.on("error", reject);
|
|
114
190
|
});
|
|
115
191
|
}
|
|
116
|
-
var STREAM_THRESHOLD,
|
|
192
|
+
var STREAM_THRESHOLD, limit;
|
|
117
193
|
var init_hash = __esm({
|
|
118
194
|
"src/utils/hash.ts"() {
|
|
119
195
|
"use strict";
|
|
196
|
+
init_concurrency();
|
|
120
197
|
init_logger();
|
|
121
198
|
STREAM_THRESHOLD = 1024 * 1024;
|
|
122
|
-
WORKER_THRESHOLD = 64 * 1024;
|
|
123
199
|
limit = pLimit(Math.max(availableParallelism(), 8));
|
|
124
|
-
xxh = null;
|
|
125
|
-
pool = null;
|
|
126
|
-
poolFailed = false;
|
|
127
|
-
process.on("exit", () => {
|
|
128
|
-
pool?.destroy();
|
|
129
|
-
});
|
|
130
200
|
}
|
|
131
201
|
});
|
|
132
202
|
|
|
@@ -143,7 +213,6 @@ import {
|
|
|
143
213
|
constants
|
|
144
214
|
} from "fs/promises";
|
|
145
215
|
import { join as join2, dirname, relative as relative2, parse as parsePath } from "path";
|
|
146
|
-
import pLimit2 from "p-limit";
|
|
147
216
|
import { availableParallelism as availableParallelism2 } from "os";
|
|
148
217
|
function isNodeError(err) {
|
|
149
218
|
return err instanceof Error && "code" in err;
|
|
@@ -178,21 +247,8 @@ async function copyWithCoW(src, dest) {
|
|
|
178
247
|
}
|
|
179
248
|
}
|
|
180
249
|
async function collectFiles(dir) {
|
|
181
|
-
const entries = await readdir(dir, { recursive: true });
|
|
182
|
-
|
|
183
|
-
entries.map(
|
|
184
|
-
(entry) => ioLimit(async () => {
|
|
185
|
-
const full = join2(dir, entry);
|
|
186
|
-
try {
|
|
187
|
-
const s = await stat2(full);
|
|
188
|
-
return s.isFile() ? full : null;
|
|
189
|
-
} catch {
|
|
190
|
-
return null;
|
|
191
|
-
}
|
|
192
|
-
})
|
|
193
|
-
)
|
|
194
|
-
);
|
|
195
|
-
return results.filter((f) => f !== null);
|
|
250
|
+
const entries = await readdir(dir, { recursive: true, withFileTypes: true });
|
|
251
|
+
return entries.filter((e) => e.isFile()).map((e) => join2(e.parentPath, e.name));
|
|
196
252
|
}
|
|
197
253
|
async function incrementalCopy(srcDir, destDir) {
|
|
198
254
|
const srcFiles = await collectFiles(srcDir);
|
|
@@ -246,16 +302,18 @@ async function incrementalCopy(srcDir, destDir) {
|
|
|
246
302
|
try {
|
|
247
303
|
const destFiles = await collectFiles(destDir);
|
|
248
304
|
const srcRelPaths = new Set(srcFiles.map((f) => relative2(srcDir, f)));
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
305
|
+
const filesToRemove = destFiles.filter(
|
|
306
|
+
(f) => !srcRelPaths.has(relative2(destDir, f))
|
|
307
|
+
);
|
|
308
|
+
await Promise.all(
|
|
309
|
+
filesToRemove.map(
|
|
310
|
+
(destFile) => ioLimit(async () => {
|
|
311
|
+
verbose(`[remove] ${relative2(destDir, destFile)} (no longer in source)`);
|
|
312
|
+
if (!isDryRun()) await rm(destFile);
|
|
313
|
+
})
|
|
314
|
+
)
|
|
315
|
+
);
|
|
316
|
+
removed = filesToRemove.length;
|
|
259
317
|
} catch (err) {
|
|
260
318
|
if (isNodeError(err) && err.code === "ENOENT") {
|
|
261
319
|
} else {
|
|
@@ -313,10 +371,11 @@ var ioLimit, reflinkSupported;
|
|
|
313
371
|
var init_fs = __esm({
|
|
314
372
|
"src/utils/fs.ts"() {
|
|
315
373
|
"use strict";
|
|
374
|
+
init_concurrency();
|
|
316
375
|
init_hash();
|
|
317
376
|
init_logger();
|
|
318
377
|
init_logger();
|
|
319
|
-
ioLimit =
|
|
378
|
+
ioLimit = pLimit(Math.max(availableParallelism2(), 8));
|
|
320
379
|
reflinkSupported = /* @__PURE__ */ new Map();
|
|
321
380
|
}
|
|
322
381
|
});
|
|
@@ -324,11 +383,13 @@ var init_fs = __esm({
|
|
|
324
383
|
// src/utils/workspace.ts
|
|
325
384
|
var workspace_exports = {};
|
|
326
385
|
__export(workspace_exports, {
|
|
386
|
+
findWorkspacePackages: () => findWorkspacePackages,
|
|
327
387
|
findWorkspaceRoot: () => findWorkspaceRoot,
|
|
328
388
|
parseCatalogs: () => parseCatalogs
|
|
329
389
|
});
|
|
330
|
-
import { readFile as readFile4 } from "fs/promises";
|
|
331
|
-
import { join as join5, dirname as dirname3 } from "path";
|
|
390
|
+
import { readFile as readFile4, readdir as readdir4 } from "fs/promises";
|
|
391
|
+
import { join as join5, dirname as dirname3, resolve as resolve2, relative as relative4 } from "path";
|
|
392
|
+
import picomatch2 from "picomatch";
|
|
332
393
|
async function findWorkspaceRoot(startDir) {
|
|
333
394
|
let dir = startDir;
|
|
334
395
|
for (; ; ) {
|
|
@@ -401,6 +462,130 @@ async function parseCatalogs(workspaceRoot) {
|
|
|
401
462
|
}
|
|
402
463
|
return result;
|
|
403
464
|
}
|
|
465
|
+
async function findWorkspacePackages(startDir) {
|
|
466
|
+
const pnpmRoot = await findWorkspaceRoot(startDir);
|
|
467
|
+
if (pnpmRoot) {
|
|
468
|
+
const patterns = await parsePnpmWorkspacePackages(pnpmRoot);
|
|
469
|
+
if (patterns.length > 0) {
|
|
470
|
+
return resolveWorkspaceGlobs(pnpmRoot, patterns);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
const rootDir = pnpmRoot ?? await findPackageJsonWorkspaceRoot(startDir);
|
|
474
|
+
if (!rootDir) return [];
|
|
475
|
+
try {
|
|
476
|
+
const rootPkg = JSON.parse(await readFile4(join5(rootDir, "package.json"), "utf-8"));
|
|
477
|
+
const workspaces = Array.isArray(rootPkg.workspaces) ? rootPkg.workspaces : rootPkg.workspaces?.packages ?? [];
|
|
478
|
+
if (workspaces.length === 0) return [];
|
|
479
|
+
return resolveWorkspaceGlobs(rootDir, workspaces);
|
|
480
|
+
} catch {
|
|
481
|
+
return [];
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
async function parsePnpmWorkspacePackages(workspaceRoot) {
|
|
485
|
+
const filePath = join5(workspaceRoot, "pnpm-workspace.yaml");
|
|
486
|
+
let content;
|
|
487
|
+
try {
|
|
488
|
+
content = await readFile4(filePath, "utf-8");
|
|
489
|
+
} catch {
|
|
490
|
+
return [];
|
|
491
|
+
}
|
|
492
|
+
const patterns = [];
|
|
493
|
+
let inPackages = false;
|
|
494
|
+
for (const line of content.split(/\r?\n/)) {
|
|
495
|
+
const trimmed = line.trim();
|
|
496
|
+
if (trimmed === "" || trimmed.startsWith("#")) continue;
|
|
497
|
+
const indent = line.length - line.trimStart().length;
|
|
498
|
+
if (indent === 0) {
|
|
499
|
+
inPackages = trimmed === "packages:";
|
|
500
|
+
continue;
|
|
501
|
+
}
|
|
502
|
+
if (inPackages && indent >= 2) {
|
|
503
|
+
const match = trimmed.match(/^-\s+["']?([^"']+)["']?$/);
|
|
504
|
+
if (match) {
|
|
505
|
+
if (!match[1].startsWith("!")) {
|
|
506
|
+
patterns.push(match[1]);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
return patterns;
|
|
512
|
+
}
|
|
513
|
+
async function findPackageJsonWorkspaceRoot(startDir) {
|
|
514
|
+
let dir = startDir;
|
|
515
|
+
for (; ; ) {
|
|
516
|
+
try {
|
|
517
|
+
const pkg = JSON.parse(await readFile4(join5(dir, "package.json"), "utf-8"));
|
|
518
|
+
if (pkg.workspaces) return dir;
|
|
519
|
+
} catch {
|
|
520
|
+
}
|
|
521
|
+
const parent = dirname3(dir);
|
|
522
|
+
if (parent === dir) return null;
|
|
523
|
+
dir = parent;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
async function resolveWorkspaceGlobs(rootDir, patterns) {
|
|
527
|
+
const results = [];
|
|
528
|
+
for (const pattern of patterns) {
|
|
529
|
+
if (pattern.includes("*")) {
|
|
530
|
+
const parts = pattern.split("/");
|
|
531
|
+
let staticPrefix = rootDir;
|
|
532
|
+
const globParts = [];
|
|
533
|
+
let foundGlob = false;
|
|
534
|
+
for (const part of parts) {
|
|
535
|
+
if (foundGlob || part.includes("*")) {
|
|
536
|
+
foundGlob = true;
|
|
537
|
+
globParts.push(part);
|
|
538
|
+
} else {
|
|
539
|
+
staticPrefix = join5(staticPrefix, part);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
if (globParts.length === 1 && globParts[0] === "*") {
|
|
543
|
+
try {
|
|
544
|
+
const entries = await readdir4(staticPrefix, { withFileTypes: true });
|
|
545
|
+
for (const entry of entries) {
|
|
546
|
+
if (entry.isDirectory()) {
|
|
547
|
+
const pkgDir = join5(staticPrefix, entry.name);
|
|
548
|
+
if (await exists(join5(pkgDir, "package.json"))) {
|
|
549
|
+
results.push(pkgDir);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
} catch {
|
|
554
|
+
}
|
|
555
|
+
} else {
|
|
556
|
+
const isMatch = picomatch2(pattern);
|
|
557
|
+
const candidates = await collectDirs(rootDir, 8);
|
|
558
|
+
for (const candidate of candidates) {
|
|
559
|
+
const rel = relative4(rootDir, candidate).replace(/\\/g, "/");
|
|
560
|
+
if (isMatch(rel) && await exists(join5(candidate, "package.json"))) {
|
|
561
|
+
results.push(candidate);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
} else {
|
|
566
|
+
const pkgDir = resolve2(rootDir, pattern);
|
|
567
|
+
if (await exists(join5(pkgDir, "package.json"))) {
|
|
568
|
+
results.push(pkgDir);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
return [...new Set(results)];
|
|
573
|
+
}
|
|
574
|
+
async function collectDirs(dir, maxDepth) {
|
|
575
|
+
if (maxDepth <= 0) return [];
|
|
576
|
+
const results = [];
|
|
577
|
+
try {
|
|
578
|
+
const entries = await readdir4(dir, { withFileTypes: true });
|
|
579
|
+
for (const entry of entries) {
|
|
580
|
+
if (!entry.isDirectory() || entry.name === "node_modules" || entry.name === ".git") continue;
|
|
581
|
+
const full = join5(dir, entry.name);
|
|
582
|
+
results.push(full);
|
|
583
|
+
results.push(...await collectDirs(full, maxDepth - 1));
|
|
584
|
+
}
|
|
585
|
+
} catch {
|
|
586
|
+
}
|
|
587
|
+
return results;
|
|
588
|
+
}
|
|
404
589
|
function parseKeyValue(line) {
|
|
405
590
|
const trimmed = line.trim();
|
|
406
591
|
const colonIdx = trimmed.indexOf(":");
|
|
@@ -419,13 +604,13 @@ var init_workspace = __esm({
|
|
|
419
604
|
});
|
|
420
605
|
|
|
421
606
|
// src/core/publisher.ts
|
|
422
|
-
|
|
607
|
+
init_console();
|
|
608
|
+
init_concurrency();
|
|
609
|
+
import { readFile as readFile5, writeFile as writeFile2, rename as rename2, stat as stat5 } from "fs/promises";
|
|
423
610
|
import { randomBytes } from "crypto";
|
|
424
|
-
import { join as join6, relative as
|
|
611
|
+
import { join as join6, relative as relative5, dirname as dirname4, resolve as resolve3 } from "path";
|
|
425
612
|
import { spawn } from "child_process";
|
|
426
613
|
import { platform } from "os";
|
|
427
|
-
import { consola as consola4 } from "consola";
|
|
428
|
-
import pLimit3 from "p-limit";
|
|
429
614
|
import { availableParallelism as availableParallelism3 } from "os";
|
|
430
615
|
|
|
431
616
|
// src/utils/paths.ts
|
|
@@ -475,23 +660,23 @@ function getNodeModulesPackagePath(consumerPath, packageName) {
|
|
|
475
660
|
}
|
|
476
661
|
|
|
477
662
|
// src/utils/pack-list.ts
|
|
663
|
+
init_console();
|
|
478
664
|
init_fs();
|
|
479
665
|
import { readFile as readFile2, readdir as readdir2, stat as stat3 } from "fs/promises";
|
|
480
666
|
import { join as join3, relative as relative3, resolve, sep } from "path";
|
|
481
667
|
import picomatch from "picomatch";
|
|
482
|
-
import { consola as consola2 } from "consola";
|
|
483
668
|
async function resolvePackFiles(packageDir, pkg) {
|
|
484
669
|
const files = [];
|
|
485
670
|
const absDir = resolve(packageDir);
|
|
486
671
|
files.push(join3(absDir, "package.json"));
|
|
487
|
-
const allFiles = await collectAllFiles(absDir);
|
|
672
|
+
const allFiles = await collectAllFiles(absDir, absDir);
|
|
488
673
|
const allRelPaths = allFiles.map((f) => relative3(absDir, f).replace(/\\/g, "/"));
|
|
489
674
|
if (pkg.files && pkg.files.length > 0) {
|
|
490
675
|
for (const pattern of pkg.files) {
|
|
491
676
|
const target = join3(absDir, pattern);
|
|
492
677
|
const resolved = resolve(target);
|
|
493
678
|
if (!resolved.startsWith(absDir + sep) && resolved !== absDir) {
|
|
494
|
-
|
|
679
|
+
consola.warn(`files pattern "${pattern}" escapes package directory, skipping`);
|
|
495
680
|
continue;
|
|
496
681
|
}
|
|
497
682
|
let matched = false;
|
|
@@ -526,7 +711,7 @@ async function resolvePackFiles(packageDir, pkg) {
|
|
|
526
711
|
}
|
|
527
712
|
}
|
|
528
713
|
if (globMatched === 0) {
|
|
529
|
-
|
|
714
|
+
consola.warn(`files pattern "${pattern}" matched no files`);
|
|
530
715
|
}
|
|
531
716
|
}
|
|
532
717
|
}
|
|
@@ -583,6 +768,9 @@ var DEFAULT_IGNORES = /* @__PURE__ */ new Set([
|
|
|
583
768
|
"vitest.config.js"
|
|
584
769
|
]);
|
|
585
770
|
function shouldIgnore(relPath, matchers) {
|
|
771
|
+
for (const isMatch of matchers.negations) {
|
|
772
|
+
if (isMatch(relPath)) return false;
|
|
773
|
+
}
|
|
586
774
|
const parts = relPath.split(/[\\/]/);
|
|
587
775
|
for (const part of parts) {
|
|
588
776
|
if (DEFAULT_IGNORES.has(part)) return true;
|
|
@@ -592,9 +780,6 @@ function shouldIgnore(relPath, matchers) {
|
|
|
592
780
|
for (const isMatch of matchers.patterns) {
|
|
593
781
|
if (isMatch(relPath)) return true;
|
|
594
782
|
}
|
|
595
|
-
for (const isMatch of matchers.negations) {
|
|
596
|
-
if (isMatch(relPath)) return false;
|
|
597
|
-
}
|
|
598
783
|
return false;
|
|
599
784
|
}
|
|
600
785
|
async function loadNpmIgnore(dir) {
|
|
@@ -627,16 +812,17 @@ async function loadNpmIgnore(dir) {
|
|
|
627
812
|
function hasGlobChars(pattern) {
|
|
628
813
|
return /[*?[\]{}()]/.test(pattern);
|
|
629
814
|
}
|
|
630
|
-
async function collectAllFiles(dir) {
|
|
815
|
+
async function collectAllFiles(dir, rootDir) {
|
|
631
816
|
const results = [];
|
|
632
817
|
try {
|
|
633
818
|
const entries = await readdir2(dir, { withFileTypes: true });
|
|
634
819
|
for (const entry of entries) {
|
|
635
820
|
const full = join3(dir, entry.name);
|
|
636
821
|
if (entry.isDirectory()) {
|
|
637
|
-
if (entry.name === "
|
|
822
|
+
if (entry.name === ".git") continue;
|
|
823
|
+
if (dir === rootDir && entry.name === "node_modules") continue;
|
|
638
824
|
if (entry.isSymbolicLink()) continue;
|
|
639
|
-
results.push(...await collectAllFiles(full));
|
|
825
|
+
results.push(...await collectAllFiles(full, rootDir));
|
|
640
826
|
} else if (!entry.isSymbolicLink()) {
|
|
641
827
|
results.push(full);
|
|
642
828
|
}
|
|
@@ -655,16 +841,16 @@ init_hash();
|
|
|
655
841
|
init_fs();
|
|
656
842
|
|
|
657
843
|
// src/core/store.ts
|
|
844
|
+
init_console();
|
|
658
845
|
import { readFile as readFile3, readdir as readdir3 } from "fs/promises";
|
|
659
846
|
import "path";
|
|
660
|
-
import { consola as consola3 } from "consola";
|
|
661
847
|
init_fs();
|
|
662
848
|
|
|
663
849
|
// src/utils/validators.ts
|
|
664
850
|
function isPlunkMeta(value) {
|
|
665
851
|
if (typeof value !== "object" || value === null) return false;
|
|
666
852
|
const v = value;
|
|
667
|
-
return typeof v.contentHash === "string" && typeof v.publishedAt === "string" && typeof v.sourcePath === "string" && (v.buildId === void 0 || typeof v.buildId === "string");
|
|
853
|
+
return typeof v.contentHash === "string" && typeof v.publishedAt === "string" && typeof v.sourcePath === "string" && (v.buildId === void 0 || typeof v.buildId === "string") && (v.schemaVersion === void 0 || typeof v.schemaVersion === "number");
|
|
668
854
|
}
|
|
669
855
|
function isLinkEntry(value) {
|
|
670
856
|
if (typeof value !== "object" || value === null) return false;
|
|
@@ -697,20 +883,27 @@ function isConsumersRegistry(value) {
|
|
|
697
883
|
// src/core/store.ts
|
|
698
884
|
async function readMeta(name, version) {
|
|
699
885
|
const metaPath = getStoreMetaPath(name, version);
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
886
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
887
|
+
try {
|
|
888
|
+
const content = await readFile3(metaPath, "utf-8");
|
|
889
|
+
const parsed = JSON.parse(content);
|
|
890
|
+
if (!isPlunkMeta(parsed)) {
|
|
891
|
+
consola.warn(`Invalid metadata for ${name}@${version}, ignoring`);
|
|
892
|
+
return null;
|
|
893
|
+
}
|
|
894
|
+
return parsed;
|
|
895
|
+
} catch (err) {
|
|
896
|
+
if (isNodeError(err) && err.code === "ENOENT" && attempt === 0) {
|
|
897
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
898
|
+
continue;
|
|
899
|
+
}
|
|
900
|
+
if (isNodeError(err) && err.code !== "ENOENT") {
|
|
901
|
+
consola.warn(`Failed to read metadata for ${name}@${version}: ${err instanceof Error ? err.message : String(err)}`);
|
|
902
|
+
}
|
|
705
903
|
return null;
|
|
706
904
|
}
|
|
707
|
-
return parsed;
|
|
708
|
-
} catch (err) {
|
|
709
|
-
if (isNodeError(err) && err.code !== "ENOENT") {
|
|
710
|
-
consola3.warn(`Failed to read metadata for ${name}@${version}: ${err}`);
|
|
711
|
-
}
|
|
712
|
-
return null;
|
|
713
905
|
}
|
|
906
|
+
return null;
|
|
714
907
|
}
|
|
715
908
|
async function getStoreEntry(name, version) {
|
|
716
909
|
const packageDir = getStorePackagePath(name, version);
|
|
@@ -742,10 +935,9 @@ async function findStoreEntry(name) {
|
|
|
742
935
|
);
|
|
743
936
|
const matching = results.filter((r) => r !== null);
|
|
744
937
|
if (matching.length === 0) return null;
|
|
745
|
-
matching.
|
|
746
|
-
(
|
|
938
|
+
return matching.reduce(
|
|
939
|
+
(latest, entry) => new Date(entry.meta.publishedAt).getTime() > new Date(latest.meta.publishedAt).getTime() ? entry : latest
|
|
747
940
|
);
|
|
748
|
-
return matching[0];
|
|
749
941
|
}
|
|
750
942
|
async function listStoreEntries() {
|
|
751
943
|
const storePath = getStorePath();
|
|
@@ -777,44 +969,64 @@ async function listStoreEntries() {
|
|
|
777
969
|
|
|
778
970
|
// src/utils/lockfile.ts
|
|
779
971
|
init_fs();
|
|
780
|
-
import {
|
|
972
|
+
import { mkdir as mkdir2, stat as stat4, rm as rm2 } from "fs/promises";
|
|
781
973
|
import { dirname as dirname2 } from "path";
|
|
782
|
-
import {
|
|
783
|
-
var
|
|
784
|
-
retries:
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
},
|
|
790
|
-
stale: 1e4,
|
|
791
|
-
realpath: false
|
|
974
|
+
import { setTimeout as sleep } from "timers/promises";
|
|
975
|
+
var DEFAULTS = {
|
|
976
|
+
retries: 5,
|
|
977
|
+
minTimeout: 100,
|
|
978
|
+
maxTimeout: 1e3,
|
|
979
|
+
factor: 2,
|
|
980
|
+
stale: 1e4
|
|
792
981
|
};
|
|
793
982
|
async function withFileLock(filePath, fn, lockOptions) {
|
|
794
983
|
await mkdir2(dirname2(filePath), { recursive: true });
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
984
|
+
const lockDir = filePath + ".lk";
|
|
985
|
+
const stale = lockOptions?.stale ?? DEFAULTS.stale;
|
|
986
|
+
let acquired = false;
|
|
987
|
+
for (let attempt = 0; attempt <= DEFAULTS.retries; attempt++) {
|
|
988
|
+
try {
|
|
989
|
+
await mkdir2(lockDir);
|
|
990
|
+
acquired = true;
|
|
991
|
+
break;
|
|
992
|
+
} catch (err) {
|
|
993
|
+
if (isNodeError(err) && err.code === "EEXIST") {
|
|
994
|
+
try {
|
|
995
|
+
const s = await stat4(lockDir);
|
|
996
|
+
if (Date.now() - s.mtimeMs > stale) {
|
|
997
|
+
await rm2(lockDir, { recursive: true, force: true });
|
|
998
|
+
continue;
|
|
999
|
+
}
|
|
1000
|
+
} catch {
|
|
1001
|
+
continue;
|
|
1002
|
+
}
|
|
1003
|
+
if (attempt < DEFAULTS.retries) {
|
|
1004
|
+
const delay = Math.min(
|
|
1005
|
+
DEFAULTS.minTimeout * DEFAULTS.factor ** attempt,
|
|
1006
|
+
DEFAULTS.maxTimeout
|
|
1007
|
+
);
|
|
1008
|
+
await sleep(delay);
|
|
1009
|
+
}
|
|
1010
|
+
} else {
|
|
1011
|
+
throw err;
|
|
1012
|
+
}
|
|
801
1013
|
}
|
|
802
1014
|
}
|
|
803
|
-
|
|
804
|
-
|
|
1015
|
+
if (!acquired) {
|
|
1016
|
+
throw new Error(
|
|
1017
|
+
`Failed to acquire lock after ${DEFAULTS.retries} attempts. Another plunk process may be running. If this persists, delete ${lockDir} and retry.`
|
|
1018
|
+
);
|
|
1019
|
+
}
|
|
805
1020
|
try {
|
|
806
|
-
release = await lock(filePath, opts);
|
|
807
1021
|
return await fn();
|
|
808
1022
|
} finally {
|
|
809
|
-
|
|
810
|
-
await release();
|
|
811
|
-
}
|
|
1023
|
+
await rm2(lockDir, { recursive: true, force: true });
|
|
812
1024
|
}
|
|
813
1025
|
}
|
|
814
1026
|
|
|
815
1027
|
// src/core/publisher.ts
|
|
816
1028
|
init_logger();
|
|
817
|
-
var copyLimit =
|
|
1029
|
+
var copyLimit = pLimit(Math.max(availableParallelism3(), 8));
|
|
818
1030
|
async function publish(packageDir, options = {}) {
|
|
819
1031
|
const pkgPath = join6(packageDir, "package.json");
|
|
820
1032
|
let pkgContent;
|
|
@@ -832,16 +1044,37 @@ async function publish(packageDir, options = {}) {
|
|
|
832
1044
|
);
|
|
833
1045
|
}
|
|
834
1046
|
await runLifecycleHook(packageDir, pkg, "preplunk");
|
|
835
|
-
|
|
1047
|
+
if (options.runScripts !== false) {
|
|
1048
|
+
await runLifecycleHook(packageDir, pkg, "prepack");
|
|
1049
|
+
}
|
|
1050
|
+
let publishDir = packageDir;
|
|
1051
|
+
if (pkg.publishConfig?.directory) {
|
|
1052
|
+
publishDir = resolve3(packageDir, pkg.publishConfig.directory);
|
|
1053
|
+
try {
|
|
1054
|
+
const s = await stat5(publishDir);
|
|
1055
|
+
if (!s.isDirectory()) {
|
|
1056
|
+
throw new Error(`publishConfig.directory "${pkg.publishConfig.directory}" is not a directory`);
|
|
1057
|
+
}
|
|
1058
|
+
} catch (err) {
|
|
1059
|
+
if (err instanceof Error && "code" in err && err.code === "ENOENT") {
|
|
1060
|
+
throw new Error(`publishConfig.directory "${pkg.publishConfig.directory}" does not exist`);
|
|
1061
|
+
}
|
|
1062
|
+
throw err;
|
|
1063
|
+
}
|
|
1064
|
+
verbose(`[publish] Using publishConfig.directory: ${publishDir}`);
|
|
1065
|
+
}
|
|
1066
|
+
const filePkg = publishDir !== packageDir ? JSON.parse(await readFile5(join6(publishDir, "package.json"), "utf-8").catch(() => JSON.stringify(pkg))) : pkg;
|
|
1067
|
+
const files = await resolvePackFiles(publishDir, filePkg);
|
|
836
1068
|
if (files.length === 0) {
|
|
837
1069
|
throw new Error("No publishable files found");
|
|
838
1070
|
}
|
|
839
1071
|
verbose(`[publish] Resolved ${files.length} files for ${pkg.name}@${pkg.version}`);
|
|
840
|
-
const contentHash = await computeContentHash(files,
|
|
1072
|
+
const contentHash = await computeContentHash(files, publishDir);
|
|
1073
|
+
await preloadWorkspaceVersions(pkg, packageDir);
|
|
841
1074
|
await preloadCatalogs(pkg, packageDir);
|
|
842
1075
|
const existingMeta = await readMeta(pkg.name, pkg.version);
|
|
843
1076
|
if (existingMeta && existingMeta.contentHash === contentHash) {
|
|
844
|
-
|
|
1077
|
+
consola.info(`${pkg.name}@${pkg.version} already up to date (no changes since last publish)`);
|
|
845
1078
|
return {
|
|
846
1079
|
name: pkg.name,
|
|
847
1080
|
version: pkg.version,
|
|
@@ -857,7 +1090,7 @@ async function publish(packageDir, options = {}) {
|
|
|
857
1090
|
async () => {
|
|
858
1091
|
const metaUnderLock = await readMeta(pkg.name, pkg.version);
|
|
859
1092
|
if (metaUnderLock && metaUnderLock.contentHash === contentHash) {
|
|
860
|
-
|
|
1093
|
+
consola.info(`${pkg.name}@${pkg.version} already up to date (no changes since last publish)`);
|
|
861
1094
|
return {
|
|
862
1095
|
name: pkg.name,
|
|
863
1096
|
version: pkg.version,
|
|
@@ -872,32 +1105,40 @@ async function publish(packageDir, options = {}) {
|
|
|
872
1105
|
const buildId = randomBytes(4).toString("hex");
|
|
873
1106
|
try {
|
|
874
1107
|
await ensurePrivateDir(tmpPackageDir);
|
|
875
|
-
|
|
1108
|
+
let processedPkg = rewriteProtocolVersions(pkg, packageDir);
|
|
1109
|
+
processedPkg = applyPublishConfig(processedPkg);
|
|
876
1110
|
verbose(`[publish] Copying files to temp store...`);
|
|
877
1111
|
const uniqueDirs = new Set(
|
|
878
|
-
files.map((file) => dirname4(join6(tmpPackageDir,
|
|
1112
|
+
files.map((file) => dirname4(join6(tmpPackageDir, relative5(publishDir, file))))
|
|
879
1113
|
);
|
|
880
1114
|
await Promise.all([...uniqueDirs].map((d) => ensureDir(d)));
|
|
881
1115
|
await Promise.all(
|
|
882
1116
|
files.map(
|
|
883
1117
|
(file) => copyLimit(async () => {
|
|
884
|
-
const rel =
|
|
1118
|
+
const rel = relative5(publishDir, file);
|
|
885
1119
|
const dest = join6(tmpPackageDir, rel);
|
|
886
1120
|
if (rel === "package.json" && processedPkg !== pkg) {
|
|
887
|
-
await
|
|
1121
|
+
await writeFile2(dest, JSON.stringify(processedPkg, null, 2));
|
|
888
1122
|
} else {
|
|
889
1123
|
await copyWithCoW(file, dest);
|
|
890
1124
|
}
|
|
891
1125
|
})
|
|
892
1126
|
)
|
|
893
1127
|
);
|
|
1128
|
+
if (publishDir !== packageDir) {
|
|
1129
|
+
await writeFile2(
|
|
1130
|
+
join6(tmpPackageDir, "package.json"),
|
|
1131
|
+
JSON.stringify(processedPkg, null, 2)
|
|
1132
|
+
);
|
|
1133
|
+
}
|
|
894
1134
|
const meta = {
|
|
1135
|
+
schemaVersion: 1,
|
|
895
1136
|
contentHash,
|
|
896
1137
|
publishedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
897
1138
|
sourcePath: packageDir,
|
|
898
1139
|
buildId
|
|
899
1140
|
};
|
|
900
|
-
await
|
|
1141
|
+
await writeFile2(
|
|
901
1142
|
join6(tmpDir, ".plunk-meta.json"),
|
|
902
1143
|
JSON.stringify(meta, null, 2)
|
|
903
1144
|
);
|
|
@@ -923,8 +1164,11 @@ async function publish(packageDir, options = {}) {
|
|
|
923
1164
|
{ stale: 6e4 }
|
|
924
1165
|
);
|
|
925
1166
|
if (result.skipped) return result;
|
|
1167
|
+
if (options.runScripts !== false) {
|
|
1168
|
+
await runLifecycleHook(packageDir, pkg, "postpack");
|
|
1169
|
+
}
|
|
926
1170
|
await runLifecycleHook(packageDir, pkg, "postplunk");
|
|
927
|
-
|
|
1171
|
+
consola.success(
|
|
928
1172
|
`Published ${pkg.name}@${pkg.version} (${files.length} files) [${result.buildId}]`
|
|
929
1173
|
);
|
|
930
1174
|
return result;
|
|
@@ -934,7 +1178,7 @@ async function runLifecycleHook(packageDir, pkg, hookName) {
|
|
|
934
1178
|
const script = pkg.scripts?.[hookName];
|
|
935
1179
|
if (!script) return;
|
|
936
1180
|
verbose(`[lifecycle] Running ${hookName}: ${script}`);
|
|
937
|
-
return new Promise((
|
|
1181
|
+
return new Promise((resolve6, reject) => {
|
|
938
1182
|
const isWin = platform() === "win32";
|
|
939
1183
|
const shell = isWin ? "cmd" : "sh";
|
|
940
1184
|
const shellFlag = isWin ? "/c" : "-c";
|
|
@@ -944,12 +1188,12 @@ async function runLifecycleHook(packageDir, pkg, hookName) {
|
|
|
944
1188
|
});
|
|
945
1189
|
const timer = setTimeout(() => {
|
|
946
1190
|
child.kill("SIGTERM");
|
|
947
|
-
reject(new Error(`${hookName} script timed out after ${HOOK_TIMEOUT}
|
|
1191
|
+
reject(new Error(`${hookName} script timed out after ${HOOK_TIMEOUT / 1e3}s. Increase PLUNK_HOOK_TIMEOUT env var if the script needs more time.`));
|
|
948
1192
|
}, HOOK_TIMEOUT);
|
|
949
1193
|
child.on("close", (code) => {
|
|
950
1194
|
clearTimeout(timer);
|
|
951
1195
|
if (code === 0) {
|
|
952
|
-
|
|
1196
|
+
resolve6();
|
|
953
1197
|
} else {
|
|
954
1198
|
reject(new Error(`${hookName} script failed with exit code ${code}`));
|
|
955
1199
|
}
|
|
@@ -960,6 +1204,26 @@ async function runLifecycleHook(packageDir, pkg, hookName) {
|
|
|
960
1204
|
});
|
|
961
1205
|
});
|
|
962
1206
|
}
|
|
1207
|
+
var PUBLISH_CONFIG_OVERRIDES = [
|
|
1208
|
+
"main",
|
|
1209
|
+
"module",
|
|
1210
|
+
"exports",
|
|
1211
|
+
"types",
|
|
1212
|
+
"typings",
|
|
1213
|
+
"browser",
|
|
1214
|
+
"bin"
|
|
1215
|
+
];
|
|
1216
|
+
function applyPublishConfig(pkg) {
|
|
1217
|
+
if (!pkg.publishConfig) return pkg;
|
|
1218
|
+
const result = { ...pkg };
|
|
1219
|
+
for (const field of PUBLISH_CONFIG_OVERRIDES) {
|
|
1220
|
+
if (field in pkg.publishConfig) {
|
|
1221
|
+
result[field] = pkg.publishConfig[field];
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
delete result.publishConfig;
|
|
1225
|
+
return result;
|
|
1226
|
+
}
|
|
963
1227
|
function rewriteProtocolVersions(pkg, packageDir) {
|
|
964
1228
|
let changed = false;
|
|
965
1229
|
const result = { ...pkg };
|
|
@@ -968,7 +1232,8 @@ function rewriteProtocolVersions(pkg, packageDir) {
|
|
|
968
1232
|
for (const depField of [
|
|
969
1233
|
"dependencies",
|
|
970
1234
|
"devDependencies",
|
|
971
|
-
"peerDependencies"
|
|
1235
|
+
"peerDependencies",
|
|
1236
|
+
"optionalDependencies"
|
|
972
1237
|
]) {
|
|
973
1238
|
const deps = pkg[depField];
|
|
974
1239
|
if (!deps) continue;
|
|
@@ -978,7 +1243,8 @@ function rewriteProtocolVersions(pkg, packageDir) {
|
|
|
978
1243
|
if (version.startsWith("workspace:")) {
|
|
979
1244
|
const versionPart = version.slice("workspace:".length);
|
|
980
1245
|
if (versionPart === "*" || versionPart === "^" || versionPart === "~") {
|
|
981
|
-
|
|
1246
|
+
const depVersion = _cachedWorkspaceVersions?.versions.get(name) ?? pkg.version;
|
|
1247
|
+
newDeps[name] = versionPart === "*" ? depVersion : versionPart + depVersion;
|
|
982
1248
|
} else {
|
|
983
1249
|
newDeps[name] = versionPart;
|
|
984
1250
|
}
|
|
@@ -986,7 +1252,7 @@ function rewriteProtocolVersions(pkg, packageDir) {
|
|
|
986
1252
|
changed = true;
|
|
987
1253
|
} else if (version.startsWith("catalog:")) {
|
|
988
1254
|
if (!catalogsLoaded) {
|
|
989
|
-
catalogs =
|
|
1255
|
+
catalogs = loadCatalogsFromCache();
|
|
990
1256
|
catalogsLoaded = true;
|
|
991
1257
|
}
|
|
992
1258
|
if (catalogs) {
|
|
@@ -1016,12 +1282,48 @@ function resolveCatalogVersion(specifier, depName, catalogs) {
|
|
|
1016
1282
|
}
|
|
1017
1283
|
return catalogs.named[catalogRef]?.[depName] ?? null;
|
|
1018
1284
|
}
|
|
1285
|
+
var _cachedWorkspaceVersions = null;
|
|
1286
|
+
async function preloadWorkspaceVersions(pkg, packageDir) {
|
|
1287
|
+
const hasWorkspace = [
|
|
1288
|
+
"dependencies",
|
|
1289
|
+
"devDependencies",
|
|
1290
|
+
"peerDependencies",
|
|
1291
|
+
"optionalDependencies"
|
|
1292
|
+
].some((field) => {
|
|
1293
|
+
const deps = pkg[field];
|
|
1294
|
+
return deps && Object.values(deps).some((v) => v.startsWith("workspace:"));
|
|
1295
|
+
});
|
|
1296
|
+
if (!hasWorkspace) return;
|
|
1297
|
+
const { findWorkspaceRoot: findWorkspaceRoot2, findWorkspacePackages: findWorkspacePackages2 } = await Promise.resolve().then(() => (init_workspace(), workspace_exports));
|
|
1298
|
+
const root = await findWorkspaceRoot2(packageDir);
|
|
1299
|
+
if (!root) {
|
|
1300
|
+
_cachedWorkspaceVersions = null;
|
|
1301
|
+
return;
|
|
1302
|
+
}
|
|
1303
|
+
if (_cachedWorkspaceVersions?.root === root) return;
|
|
1304
|
+
const pkgDirs = await findWorkspacePackages2(root);
|
|
1305
|
+
const versions = /* @__PURE__ */ new Map();
|
|
1306
|
+
await Promise.all(
|
|
1307
|
+
pkgDirs.map(async (dir) => {
|
|
1308
|
+
try {
|
|
1309
|
+
const depPkg = JSON.parse(
|
|
1310
|
+
await readFile5(join6(dir, "package.json"), "utf-8")
|
|
1311
|
+
);
|
|
1312
|
+
if (depPkg.name && depPkg.version) {
|
|
1313
|
+
versions.set(depPkg.name, depPkg.version);
|
|
1314
|
+
}
|
|
1315
|
+
} catch {
|
|
1316
|
+
}
|
|
1317
|
+
})
|
|
1318
|
+
);
|
|
1319
|
+
_cachedWorkspaceVersions = { root, versions };
|
|
1320
|
+
}
|
|
1019
1321
|
var _cachedCatalogs = null;
|
|
1020
|
-
function
|
|
1322
|
+
function loadCatalogsFromCache() {
|
|
1021
1323
|
return _cachedCatalogs?.catalogs ?? null;
|
|
1022
1324
|
}
|
|
1023
1325
|
async function preloadCatalogs(pkg, packageDir) {
|
|
1024
|
-
const hasCatalog = ["dependencies", "devDependencies", "peerDependencies"].some(
|
|
1326
|
+
const hasCatalog = ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"].some(
|
|
1025
1327
|
(field) => {
|
|
1026
1328
|
const deps = pkg[field];
|
|
1027
1329
|
return deps && Object.values(deps).some((v) => v.startsWith("catalog:"));
|
|
@@ -1034,24 +1336,26 @@ async function preloadCatalogs(pkg, packageDir) {
|
|
|
1034
1336
|
_cachedCatalogs = null;
|
|
1035
1337
|
return;
|
|
1036
1338
|
}
|
|
1037
|
-
|
|
1339
|
+
const workspaceFile = join6(root, "pnpm-workspace.yaml");
|
|
1340
|
+
const mtimeMs = (await stat5(workspaceFile).catch(() => null))?.mtimeMs ?? 0;
|
|
1341
|
+
if (_cachedCatalogs?.root === root && _cachedCatalogs.mtimeMs === mtimeMs) return;
|
|
1038
1342
|
const catalogs = await parseCatalogs2(root);
|
|
1039
|
-
_cachedCatalogs = { root, catalogs };
|
|
1343
|
+
_cachedCatalogs = { root, mtimeMs, catalogs };
|
|
1040
1344
|
}
|
|
1041
1345
|
|
|
1042
1346
|
// src/core/injector.ts
|
|
1043
|
-
|
|
1044
|
-
import {
|
|
1045
|
-
import {
|
|
1347
|
+
init_console();
|
|
1348
|
+
import { readFile as readFile7, readdir as readdir5, realpath, stat as stat7 } from "fs/promises";
|
|
1349
|
+
import { join as join11, resolve as resolve5 } from "path";
|
|
1046
1350
|
init_fs();
|
|
1047
1351
|
|
|
1048
1352
|
// src/utils/bin-linker.ts
|
|
1353
|
+
init_console();
|
|
1049
1354
|
init_fs();
|
|
1050
1355
|
init_logger();
|
|
1051
|
-
import { mkdir as mkdir3, symlink, writeFile as
|
|
1052
|
-
import { join as join7, relative as
|
|
1356
|
+
import { mkdir as mkdir3, symlink, writeFile as writeFile3, chmod, rm as rm3 } from "fs/promises";
|
|
1357
|
+
import { join as join7, relative as relative6, resolve as resolve4, sep as sep2 } from "path";
|
|
1053
1358
|
import { platform as platform2 } from "os";
|
|
1054
|
-
import { consola as consola5 } from "consola";
|
|
1055
1359
|
function resolveBinEntries(pkg) {
|
|
1056
1360
|
if (!pkg.bin) return {};
|
|
1057
1361
|
if (typeof pkg.bin === "string") {
|
|
@@ -1070,12 +1374,12 @@ async function createBinLinks(consumerPath, packageName, pkg) {
|
|
|
1070
1374
|
for (const [binName, binPath] of Object.entries(entries)) {
|
|
1071
1375
|
const packageRoot = join7(consumerPath, "node_modules", packageName);
|
|
1072
1376
|
const targetAbsolute = join7(packageRoot, binPath);
|
|
1073
|
-
const resolvedTarget =
|
|
1074
|
-
if (!resolvedTarget.startsWith(
|
|
1075
|
-
|
|
1377
|
+
const resolvedTarget = resolve4(targetAbsolute);
|
|
1378
|
+
if (!resolvedTarget.startsWith(resolve4(packageRoot) + sep2) && resolvedTarget !== resolve4(packageRoot)) {
|
|
1379
|
+
consola.warn(`bin "${binName}" points outside package directory, skipping`);
|
|
1076
1380
|
continue;
|
|
1077
1381
|
}
|
|
1078
|
-
const targetRelative =
|
|
1382
|
+
const targetRelative = relative6(binDir, targetAbsolute).replace(
|
|
1079
1383
|
/\\/g,
|
|
1080
1384
|
"/"
|
|
1081
1385
|
);
|
|
@@ -1090,16 +1394,16 @@ EXIT /b\r
|
|
|
1090
1394
|
CALL :find_dp0\r
|
|
1091
1395
|
"%dp0%\\${targetRelative}" %*\r
|
|
1092
1396
|
`;
|
|
1093
|
-
await
|
|
1397
|
+
await writeFile3(cmdPath, cmdContent);
|
|
1094
1398
|
const shPath = join7(binDir, binName);
|
|
1095
1399
|
const shContent = `#!/bin/sh
|
|
1096
1400
|
exec node "${targetRelative}" "$@"
|
|
1097
1401
|
`;
|
|
1098
|
-
await
|
|
1402
|
+
await writeFile3(shPath, shContent);
|
|
1099
1403
|
} else {
|
|
1100
1404
|
const linkPath = join7(binDir, binName);
|
|
1101
1405
|
try {
|
|
1102
|
-
await
|
|
1406
|
+
await rm3(linkPath, { force: true });
|
|
1103
1407
|
} catch {
|
|
1104
1408
|
}
|
|
1105
1409
|
try {
|
|
@@ -1111,7 +1415,7 @@ exec node "${targetRelative}" "$@"
|
|
|
1111
1415
|
const shContent = `#!/bin/sh
|
|
1112
1416
|
exec node "${targetRelative}" "$@"
|
|
1113
1417
|
`;
|
|
1114
|
-
await
|
|
1418
|
+
await writeFile3(linkPath, shContent);
|
|
1115
1419
|
await chmod(linkPath, 493);
|
|
1116
1420
|
} else {
|
|
1117
1421
|
throw err;
|
|
@@ -1128,9 +1432,9 @@ async function removeBinLinks(consumerPath, pkg) {
|
|
|
1128
1432
|
const isWindows = platform2() === "win32";
|
|
1129
1433
|
for (const binName of Object.keys(entries)) {
|
|
1130
1434
|
try {
|
|
1131
|
-
await
|
|
1435
|
+
await rm3(join7(binDir, binName), { force: true });
|
|
1132
1436
|
if (isWindows) {
|
|
1133
|
-
await
|
|
1437
|
+
await rm3(join7(binDir, `${binName}.cmd`), { force: true });
|
|
1134
1438
|
}
|
|
1135
1439
|
} catch {
|
|
1136
1440
|
}
|
|
@@ -1141,8 +1445,8 @@ async function removeBinLinks(consumerPath, pkg) {
|
|
|
1141
1445
|
init_logger();
|
|
1142
1446
|
|
|
1143
1447
|
// src/utils/pm-detect.ts
|
|
1144
|
-
import { readFile as readFile6, stat as
|
|
1145
|
-
import { join as join8 } from "path";
|
|
1448
|
+
import { readFile as readFile6, stat as stat6 } from "fs/promises";
|
|
1449
|
+
import { join as join8, dirname as dirname5 } from "path";
|
|
1146
1450
|
var LOCKFILES = [
|
|
1147
1451
|
["pnpm-lock.yaml", "pnpm"],
|
|
1148
1452
|
["bun.lockb", "bun"],
|
|
@@ -1151,37 +1455,50 @@ var LOCKFILES = [
|
|
|
1151
1455
|
["package-lock.json", "npm"]
|
|
1152
1456
|
];
|
|
1153
1457
|
async function detectPackageManager(projectDir) {
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1458
|
+
let dir = projectDir;
|
|
1459
|
+
for (; ; ) {
|
|
1460
|
+
const results = await Promise.all(
|
|
1461
|
+
LOCKFILES.map(async ([lockfile, pm]) => {
|
|
1462
|
+
try {
|
|
1463
|
+
await stat6(join8(dir, lockfile));
|
|
1464
|
+
return pm;
|
|
1465
|
+
} catch {
|
|
1466
|
+
return null;
|
|
1467
|
+
}
|
|
1468
|
+
})
|
|
1469
|
+
);
|
|
1470
|
+
const found = results.find((pm) => pm !== null);
|
|
1471
|
+
if (found) return found;
|
|
1472
|
+
const parent = dirname5(dir);
|
|
1473
|
+
if (parent === dir) return "npm";
|
|
1474
|
+
dir = parent;
|
|
1475
|
+
}
|
|
1165
1476
|
}
|
|
1166
1477
|
async function detectYarnNodeLinker(projectDir) {
|
|
1167
|
-
let
|
|
1168
|
-
|
|
1169
|
-
content
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1478
|
+
let dir = projectDir;
|
|
1479
|
+
for (; ; ) {
|
|
1480
|
+
let content;
|
|
1481
|
+
try {
|
|
1482
|
+
content = await readFile6(join8(dir, ".yarnrc.yml"), "utf-8");
|
|
1483
|
+
} catch {
|
|
1484
|
+
const parent = dirname5(dir);
|
|
1485
|
+
if (parent === dir) return null;
|
|
1486
|
+
dir = parent;
|
|
1487
|
+
continue;
|
|
1488
|
+
}
|
|
1489
|
+
for (const line of content.split("\n")) {
|
|
1490
|
+
const trimmed = line.trim();
|
|
1491
|
+
if (trimmed.startsWith("#") || !trimmed.includes("nodeLinker")) continue;
|
|
1492
|
+
const match = trimmed.match(/^nodeLinker:\s*(.+)$/);
|
|
1493
|
+
if (match) {
|
|
1494
|
+
const value = match[1].trim().replace(/^["']|["']$/g, "");
|
|
1495
|
+
if (value === "node-modules" || value === "pnpm" || value === "pnp") {
|
|
1496
|
+
return value;
|
|
1497
|
+
}
|
|
1181
1498
|
}
|
|
1182
1499
|
}
|
|
1500
|
+
return null;
|
|
1183
1501
|
}
|
|
1184
|
-
return null;
|
|
1185
1502
|
}
|
|
1186
1503
|
|
|
1187
1504
|
// src/utils/bundler-cache.ts
|
|
@@ -1218,8 +1535,13 @@ var CACHE_DIRS = {
|
|
|
1218
1535
|
next: [".next/cache"],
|
|
1219
1536
|
webpack: ["node_modules/.cache"]
|
|
1220
1537
|
};
|
|
1538
|
+
var bundlerCache = /* @__PURE__ */ new Map();
|
|
1221
1539
|
async function invalidateBundlerCache(consumerPath) {
|
|
1222
|
-
|
|
1540
|
+
let bundlers = bundlerCache.get(consumerPath);
|
|
1541
|
+
if (!bundlers) {
|
|
1542
|
+
bundlers = await detectAllBundlers(consumerPath);
|
|
1543
|
+
bundlerCache.set(consumerPath, bundlers);
|
|
1544
|
+
}
|
|
1223
1545
|
for (const bundler of bundlers) {
|
|
1224
1546
|
if (!bundler.type) continue;
|
|
1225
1547
|
const dirs = CACHE_DIRS[bundler.type];
|
|
@@ -1300,14 +1622,14 @@ async function checkMissingDeps(storeEntry, consumerPath) {
|
|
|
1300
1622
|
)
|
|
1301
1623
|
};
|
|
1302
1624
|
if (Object.keys(allDeps).length === 0) return [];
|
|
1303
|
-
const
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
}
|
|
1309
|
-
|
|
1310
|
-
return
|
|
1625
|
+
const depNames = Object.keys(allDeps);
|
|
1626
|
+
const results = await Promise.all(
|
|
1627
|
+
depNames.map(async (dep) => ({
|
|
1628
|
+
dep,
|
|
1629
|
+
installed: await exists(join11(consumerPath, "node_modules", dep))
|
|
1630
|
+
}))
|
|
1631
|
+
);
|
|
1632
|
+
return results.filter((r) => !r.installed).map((r) => r.dep);
|
|
1311
1633
|
}
|
|
1312
1634
|
async function resolveTargetDir(consumerPath, packageName, pm, version) {
|
|
1313
1635
|
const directPath = getNodeModulesPackagePath(consumerPath, packageName);
|
|
@@ -1317,13 +1639,13 @@ async function resolveTargetDir(consumerPath, packageName, pm, version) {
|
|
|
1317
1639
|
}
|
|
1318
1640
|
try {
|
|
1319
1641
|
const realPath = await resolveRealPath(directPath);
|
|
1320
|
-
if (realPath !==
|
|
1642
|
+
if (realPath !== resolve5(directPath)) {
|
|
1321
1643
|
verbose(`[inject] pnpm: resolved symlink \u2192 ${realPath}`);
|
|
1322
1644
|
return realPath;
|
|
1323
1645
|
}
|
|
1324
1646
|
} catch (err) {
|
|
1325
1647
|
if (isNodeError(err) && err.code !== "ENOENT") {
|
|
1326
|
-
|
|
1648
|
+
consola.debug(`pnpm symlink resolution error: ${err instanceof Error ? err.message : String(err)}`);
|
|
1327
1649
|
}
|
|
1328
1650
|
}
|
|
1329
1651
|
const pnpmDir = join11(consumerPath, "node_modules", ".pnpm");
|
|
@@ -1338,7 +1660,7 @@ async function resolveTargetDir(consumerPath, packageName, pm, version) {
|
|
|
1338
1660
|
return candidate;
|
|
1339
1661
|
}
|
|
1340
1662
|
}
|
|
1341
|
-
const entries = await
|
|
1663
|
+
const entries = await readdir5(pnpmDir);
|
|
1342
1664
|
for (const entry of entries) {
|
|
1343
1665
|
if (entry.startsWith(encodedName + "@")) {
|
|
1344
1666
|
const candidate = join11(
|
|
@@ -1354,16 +1676,16 @@ async function resolveTargetDir(consumerPath, packageName, pm, version) {
|
|
|
1354
1676
|
}
|
|
1355
1677
|
}
|
|
1356
1678
|
}
|
|
1357
|
-
|
|
1679
|
+
consola.warn(`pnpm: Could not find ${packageName} in .pnpm/ virtual store, using direct node_modules path`);
|
|
1358
1680
|
return directPath;
|
|
1359
1681
|
}
|
|
1360
1682
|
async function resolveRealPath(linkPath) {
|
|
1361
1683
|
try {
|
|
1362
|
-
await
|
|
1684
|
+
await stat7(linkPath);
|
|
1363
1685
|
return await realpath(linkPath);
|
|
1364
1686
|
} catch (err) {
|
|
1365
1687
|
if (isNodeError(err) && err.code === "ENOENT") {
|
|
1366
|
-
return
|
|
1688
|
+
return resolve5(linkPath);
|
|
1367
1689
|
}
|
|
1368
1690
|
throw err;
|
|
1369
1691
|
}
|
|
@@ -1374,16 +1696,16 @@ async function readPackageJson(dir) {
|
|
|
1374
1696
|
return JSON.parse(content);
|
|
1375
1697
|
} catch (err) {
|
|
1376
1698
|
if (isNodeError(err) && err.code !== "ENOENT") {
|
|
1377
|
-
|
|
1699
|
+
consola.warn(`Failed to read package.json in ${dir}: ${err instanceof Error ? err.message : String(err)}`);
|
|
1378
1700
|
}
|
|
1379
1701
|
return null;
|
|
1380
1702
|
}
|
|
1381
1703
|
}
|
|
1382
1704
|
|
|
1383
1705
|
// src/core/tracker.ts
|
|
1706
|
+
init_console();
|
|
1384
1707
|
import { readFile as readFile8 } from "fs/promises";
|
|
1385
|
-
import { dirname as
|
|
1386
|
-
import { consola as consola7 } from "consola";
|
|
1708
|
+
import { dirname as dirname6 } from "path";
|
|
1387
1709
|
init_fs();
|
|
1388
1710
|
async function readConsumerState(consumerPath) {
|
|
1389
1711
|
const statePath = getConsumerStatePath(consumerPath);
|
|
@@ -1391,13 +1713,13 @@ async function readConsumerState(consumerPath) {
|
|
|
1391
1713
|
const content = await readFile8(statePath, "utf-8");
|
|
1392
1714
|
const parsed = JSON.parse(content);
|
|
1393
1715
|
if (!isConsumerState(parsed)) {
|
|
1394
|
-
|
|
1716
|
+
consola.warn(`Invalid consumer state in ${statePath}, using defaults`);
|
|
1395
1717
|
return { version: "1", links: {} };
|
|
1396
1718
|
}
|
|
1397
1719
|
return parsed;
|
|
1398
1720
|
} catch (err) {
|
|
1399
1721
|
if (isNodeError(err) && err.code !== "ENOENT") {
|
|
1400
|
-
|
|
1722
|
+
consola.warn(`Failed to read consumer state: ${err instanceof Error ? err.message : String(err)}`);
|
|
1401
1723
|
}
|
|
1402
1724
|
return { version: "1", links: {} };
|
|
1403
1725
|
}
|
|
@@ -1429,20 +1751,20 @@ async function readConsumersRegistry() {
|
|
|
1429
1751
|
const content = await readFile8(regPath, "utf-8");
|
|
1430
1752
|
const parsed = JSON.parse(content);
|
|
1431
1753
|
if (!isConsumersRegistry(parsed)) {
|
|
1432
|
-
|
|
1754
|
+
consola.warn(`Invalid consumers registry, using empty registry`);
|
|
1433
1755
|
return {};
|
|
1434
1756
|
}
|
|
1435
1757
|
return parsed;
|
|
1436
1758
|
} catch (err) {
|
|
1437
1759
|
if (isNodeError(err) && err.code !== "ENOENT") {
|
|
1438
|
-
|
|
1760
|
+
consola.warn(`Failed to read consumers registry: ${err instanceof Error ? err.message : String(err)}`);
|
|
1439
1761
|
}
|
|
1440
1762
|
return {};
|
|
1441
1763
|
}
|
|
1442
1764
|
}
|
|
1443
1765
|
async function writeConsumersRegistry(registry) {
|
|
1444
1766
|
const regPath = getConsumersPath();
|
|
1445
|
-
await ensurePrivateDir(
|
|
1767
|
+
await ensurePrivateDir(dirname6(getConsumersPath()));
|
|
1446
1768
|
await atomicWriteFile(regPath, JSON.stringify(registry, null, 2));
|
|
1447
1769
|
}
|
|
1448
1770
|
async function registerConsumer(packageName, consumerPath) {
|
|
@@ -1486,14 +1808,14 @@ async function cleanStaleConsumers() {
|
|
|
1486
1808
|
const registry = await readConsumersRegistry();
|
|
1487
1809
|
const updated = {};
|
|
1488
1810
|
for (const [pkgName, consumers] of Object.entries(registry)) {
|
|
1489
|
-
const
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
}
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1811
|
+
const results = await Promise.all(
|
|
1812
|
+
consumers.map(async (consumerPath) => ({
|
|
1813
|
+
consumerPath,
|
|
1814
|
+
valid: await exists(consumerPath)
|
|
1815
|
+
}))
|
|
1816
|
+
);
|
|
1817
|
+
const validConsumers = results.filter((r) => r.valid).map((r) => r.consumerPath);
|
|
1818
|
+
removedConsumers += consumers.length - validConsumers.length;
|
|
1497
1819
|
if (validConsumers.length > 0) {
|
|
1498
1820
|
updated[pkgName] = validConsumers;
|
|
1499
1821
|
} else {
|
|
@@ -1506,9 +1828,9 @@ async function cleanStaleConsumers() {
|
|
|
1506
1828
|
}
|
|
1507
1829
|
|
|
1508
1830
|
// src/core/watcher.ts
|
|
1831
|
+
init_console();
|
|
1509
1832
|
import { spawn as spawn2 } from "child_process";
|
|
1510
1833
|
import { platform as platform3 } from "os";
|
|
1511
|
-
import { consola as consola8 } from "consola";
|
|
1512
1834
|
var activeChild = null;
|
|
1513
1835
|
var activeWatcher = null;
|
|
1514
1836
|
function killActiveBuild() {
|
|
@@ -1525,12 +1847,14 @@ async function startWatcher(watchDir, options, onChange) {
|
|
|
1525
1847
|
);
|
|
1526
1848
|
const debounceMs = options.debounce ?? 100;
|
|
1527
1849
|
let coalesceTimer = null;
|
|
1850
|
+
let closed = false;
|
|
1528
1851
|
let running = false;
|
|
1529
1852
|
let pendingWhileRunning = false;
|
|
1530
1853
|
const scheduleFlush = () => {
|
|
1531
1854
|
if (coalesceTimer) return;
|
|
1532
1855
|
coalesceTimer = setTimeout(async () => {
|
|
1533
1856
|
coalesceTimer = null;
|
|
1857
|
+
if (closed) return;
|
|
1534
1858
|
if (running) {
|
|
1535
1859
|
pendingWhileRunning = true;
|
|
1536
1860
|
return;
|
|
@@ -1540,13 +1864,13 @@ async function startWatcher(watchDir, options, onChange) {
|
|
|
1540
1864
|
if (options.buildCmd) {
|
|
1541
1865
|
const success = await runBuildCommand(options.buildCmd, watchDir);
|
|
1542
1866
|
if (!success) {
|
|
1543
|
-
|
|
1867
|
+
consola.warn("Build failed (see output above), skipping push");
|
|
1544
1868
|
return;
|
|
1545
1869
|
}
|
|
1546
1870
|
}
|
|
1547
1871
|
await onChange();
|
|
1548
1872
|
} catch (err) {
|
|
1549
|
-
|
|
1873
|
+
consola.error(`Push failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1550
1874
|
} finally {
|
|
1551
1875
|
running = false;
|
|
1552
1876
|
if (pendingWhileRunning) {
|
|
@@ -1579,8 +1903,12 @@ async function startWatcher(watchDir, options, onChange) {
|
|
|
1579
1903
|
watcher.on("change", onFileEvent);
|
|
1580
1904
|
watcher.on("add", onFileEvent);
|
|
1581
1905
|
watcher.on("unlink", onFileEvent);
|
|
1906
|
+
watcher.on("error", (err) => {
|
|
1907
|
+
consola.error(`Watcher error: ${err instanceof Error ? err.message : String(err)}`);
|
|
1908
|
+
});
|
|
1582
1909
|
const watcherHandle = {
|
|
1583
1910
|
close: async () => {
|
|
1911
|
+
closed = true;
|
|
1584
1912
|
if (coalesceTimer) clearTimeout(coalesceTimer);
|
|
1585
1913
|
killActiveBuild();
|
|
1586
1914
|
await watcher.close();
|
|
@@ -1589,21 +1917,21 @@ async function startWatcher(watchDir, options, onChange) {
|
|
|
1589
1917
|
};
|
|
1590
1918
|
activeWatcher = watcherHandle;
|
|
1591
1919
|
const cleanup = async () => {
|
|
1592
|
-
|
|
1920
|
+
consola.info("Stopping watcher...");
|
|
1593
1921
|
await watcherHandle.close();
|
|
1594
1922
|
process.exit(0);
|
|
1595
1923
|
};
|
|
1596
1924
|
process.once("SIGINT", cleanup);
|
|
1597
1925
|
process.once("SIGTERM", cleanup);
|
|
1598
|
-
|
|
1926
|
+
consola.info(`Watching for changes in: ${patterns.join(", ")}`);
|
|
1599
1927
|
return watcherHandle;
|
|
1600
1928
|
}
|
|
1601
1929
|
function runBuildCommand(cmd, cwd) {
|
|
1602
|
-
return new Promise((
|
|
1930
|
+
return new Promise((resolve6) => {
|
|
1603
1931
|
const isWin = platform3() === "win32";
|
|
1604
1932
|
const shell = isWin ? "cmd" : "sh";
|
|
1605
1933
|
const shellFlag = isWin ? "/c" : "-c";
|
|
1606
|
-
|
|
1934
|
+
consola.start(`Running: ${cmd}`);
|
|
1607
1935
|
const child = spawn2(shell, [shellFlag, cmd], {
|
|
1608
1936
|
cwd,
|
|
1609
1937
|
stdio: "inherit"
|
|
@@ -1612,17 +1940,17 @@ function runBuildCommand(cmd, cwd) {
|
|
|
1612
1940
|
child.on("close", (code) => {
|
|
1613
1941
|
activeChild = null;
|
|
1614
1942
|
if (code === 0) {
|
|
1615
|
-
|
|
1616
|
-
|
|
1943
|
+
consola.success("Build succeeded");
|
|
1944
|
+
resolve6(true);
|
|
1617
1945
|
} else {
|
|
1618
|
-
|
|
1619
|
-
|
|
1946
|
+
consola.error(`Build failed with code ${code}`);
|
|
1947
|
+
resolve6(false);
|
|
1620
1948
|
}
|
|
1621
1949
|
});
|
|
1622
1950
|
child.on("error", (err) => {
|
|
1623
1951
|
activeChild = null;
|
|
1624
|
-
|
|
1625
|
-
|
|
1952
|
+
consola.error(`Build error: ${err.message}`);
|
|
1953
|
+
resolve6(false);
|
|
1626
1954
|
});
|
|
1627
1955
|
});
|
|
1628
1956
|
}
|