monoship 1.8.1

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/index.mjs ADDED
@@ -0,0 +1,616 @@
1
+ import path from "node:path";
2
+ import fs from "node:fs";
3
+ import fg from "fast-glob";
4
+ import consola from "consola";
5
+ import libnpmpack from "libnpmpack";
6
+ import { publish as publish$1 } from "libnpmpublish";
7
+ import { execFile } from "node:child_process";
8
+ import { readFile, unlink, writeFile } from "node:fs/promises";
9
+ import { promisify } from "node:util";
10
+ import semver from "semver";
11
+ import hapic, { hasOwnProperty, isClientError } from "hapic";
12
+ //#region src/core/error.ts
13
+ var BaseError = class extends Error {
14
+ code;
15
+ statusCode;
16
+ constructor(message, options) {
17
+ super(message);
18
+ this.code = options.code;
19
+ this.statusCode = options.statusCode;
20
+ }
21
+ };
22
+ //#endregion
23
+ //#region src/core/filesystem/memory.ts
24
+ var MemoryFileSystem = class {
25
+ files;
26
+ constructor(files = {}) {
27
+ this.files = new Map(Object.entries(files || {}).map(([k, v]) => [this.normalize(k), v]));
28
+ }
29
+ async readFile(filePath) {
30
+ const normalized = this.normalize(filePath);
31
+ const content = this.files.get(normalized);
32
+ if (content === void 0) throw new Error(`ENOENT: no such file or directory, open '${filePath}'`);
33
+ return content;
34
+ }
35
+ async writeFile(filePath, content) {
36
+ this.files.set(this.normalize(filePath), content);
37
+ }
38
+ async glob(patterns, options = {}) {
39
+ const cwd = options.cwd ? this.normalize(options.cwd) : "";
40
+ const dirs = /* @__PURE__ */ new Set();
41
+ const keys = Array.from(this.files.keys());
42
+ for (const key of keys) {
43
+ if (cwd && !key.startsWith(`${cwd}/`) && key !== cwd) continue;
44
+ const parts = (cwd ? key.slice(cwd.length + 1) : key).split("/");
45
+ for (const pattern of patterns) if (this.matchGlobPattern(parts, pattern)) {
46
+ const dir = parts.slice(0, pattern.split("/").length).join("/");
47
+ const absolute = cwd ? `${cwd}/${dir}` : dir;
48
+ dirs.add(absolute);
49
+ }
50
+ }
51
+ return Array.from(dirs);
52
+ }
53
+ getFile(filePath) {
54
+ return this.files.get(this.normalize(filePath));
55
+ }
56
+ normalize(filePath) {
57
+ return path.posix.normalize(filePath.replace(/\\/g, "/"));
58
+ }
59
+ matchGlobPattern(parts, pattern) {
60
+ const patternParts = pattern.split("/");
61
+ for (const [i, pp] of patternParts.entries()) {
62
+ if (i >= parts.length) return false;
63
+ if (pp === "*" || pp === "**") continue;
64
+ if (pp !== parts[i]) return false;
65
+ }
66
+ return true;
67
+ }
68
+ };
69
+ //#endregion
70
+ //#region src/core/filesystem/node.ts
71
+ var NodeFileSystem = class {
72
+ async readFile(filePath) {
73
+ return fs.promises.readFile(filePath, { encoding: "utf-8" });
74
+ }
75
+ async writeFile(filePath, content) {
76
+ await fs.promises.writeFile(filePath, content, { encoding: "utf-8" });
77
+ }
78
+ async glob(patterns, options = {}) {
79
+ return fg(patterns, {
80
+ ignore: options.ignore || ["node_modules/**"],
81
+ cwd: options.cwd,
82
+ absolute: true,
83
+ onlyDirectories: true
84
+ });
85
+ }
86
+ };
87
+ //#endregion
88
+ //#region src/core/logger/consola.ts
89
+ var ConsolaLogger = class {
90
+ info(message) {
91
+ consola.info(message);
92
+ }
93
+ success(message) {
94
+ consola.success(message);
95
+ }
96
+ warn(message) {
97
+ consola.warn(message);
98
+ }
99
+ error(message) {
100
+ consola.error(message);
101
+ }
102
+ };
103
+ //#endregion
104
+ //#region src/core/logger/noop.ts
105
+ var NoopLogger = class {
106
+ info(_message) {}
107
+ success(_message) {}
108
+ warn(_message) {}
109
+ error(_message) {}
110
+ };
111
+ //#endregion
112
+ //#region src/core/publisher/error.ts
113
+ var PublishError = class extends BaseError {
114
+ constructor(message, options) {
115
+ super(message, {
116
+ code: "EPUBLISH",
117
+ statusCode: 500
118
+ });
119
+ if (options?.cause) this.cause = options.cause;
120
+ }
121
+ };
122
+ //#endregion
123
+ //#region src/core/publisher/memory.ts
124
+ var MemoryPublisher = class {
125
+ published;
126
+ constructor() {
127
+ this.published = [];
128
+ }
129
+ async publish(packagePath, manifest, options) {
130
+ this.published.push({
131
+ packagePath,
132
+ manifest,
133
+ options
134
+ });
135
+ return true;
136
+ }
137
+ };
138
+ //#endregion
139
+ //#region src/utils/object.ts
140
+ function isObject(input) {
141
+ return typeof input === "object" && input !== null && !Array.isArray(input);
142
+ }
143
+ function isError(input) {
144
+ return isObject(input) && typeof input.message === "string";
145
+ }
146
+ //#endregion
147
+ //#region src/core/publisher/npm.ts
148
+ var NpmPublisher = class {
149
+ /**
150
+ * Publish a package using libnpmpack + libnpmpublish.
151
+ *
152
+ * @returns `true` if published, `false` if the version already exists.
153
+ * @throws {PublishError} On non-conflict failures (network errors, auth failures, etc.).
154
+ */
155
+ async publish(packagePath, manifest, options) {
156
+ try {
157
+ await publish$1(manifest, await libnpmpack(packagePath), options);
158
+ return true;
159
+ } catch (e) {
160
+ if (this.isNpmJsVersionConflict(e) || this.isNpmPkgGitHubVersionConflict(e)) return false;
161
+ const cause = isError(e) ? e : void 0;
162
+ throw new PublishError(cause?.message || "libnpmpublish failed with an unknown error", { cause });
163
+ }
164
+ }
165
+ /**
166
+ * Determines whether an exception represents a version conflict
167
+ * when publishing to the npmjs.org registry.
168
+ */
169
+ isNpmJsVersionConflict(ex) {
170
+ if (!isObject(ex)) return false;
171
+ if ("code" in ex && ex.code === "EPUBLISHCONFLICT") return true;
172
+ return "code" in ex && ex.code === "E403" && typeof ex.message === "string" && ex.message.includes("You cannot publish over the previously published versions");
173
+ }
174
+ /**
175
+ * Determines whether an exception represents a version conflict
176
+ * when publishing to GitHub Packages (npm.pkg.github.com).
177
+ */
178
+ isNpmPkgGitHubVersionConflict(ex) {
179
+ if (!isObject(ex)) return false;
180
+ if ("code" in ex && ex.code === "E409") return true;
181
+ if ("body" in ex && isObject(ex.body) && ex.body.error === "Cannot publish over existing version") return true;
182
+ return typeof ex.message === "string" && ex.message.startsWith("409 Conflict - PUT https://npm.pkg.github.com");
183
+ }
184
+ };
185
+ //#endregion
186
+ //#region src/core/publisher/npm-cli.ts
187
+ const execFileAsync$1 = promisify(execFile);
188
+ const AUTH_TOKEN_PATTERN = /^(\/\/.+)\/:_authToken$/;
189
+ /**
190
+ * Extract the auth token entry from publish options.
191
+ *
192
+ * When `registry` is provided, prefers the entry whose scope matches
193
+ * the target registry (host + path). Falls back to the first match
194
+ * if no registry-specific entry is found.
195
+ */
196
+ function parseAuthTokenEntry(options, registry) {
197
+ let registryScope;
198
+ if (registry) try {
199
+ const url = new URL(registry);
200
+ registryScope = `//${url.host}${url.pathname.replace(/\/$/, "")}`;
201
+ } catch {}
202
+ let fallback;
203
+ const keys = Object.keys(options);
204
+ for (const key of keys) {
205
+ const match = AUTH_TOKEN_PATTERN.exec(key);
206
+ const registryPath = match?.[1];
207
+ if (match && registryPath && options[key]) {
208
+ const entry = {
209
+ key,
210
+ token: options[key],
211
+ registryPath
212
+ };
213
+ if (registryScope && registryPath === registryScope) return entry;
214
+ if (!fallback) fallback = entry;
215
+ }
216
+ }
217
+ return fallback;
218
+ }
219
+ var NpmCliPublisher = class {
220
+ execFn;
221
+ readFileFn;
222
+ writeFileFn;
223
+ unlinkFn;
224
+ constructor(options = {}) {
225
+ this.execFn = options.execFn || execFileAsync$1;
226
+ this.readFileFn = options.readFileFn || ((fp, enc) => readFile(fp, enc));
227
+ this.writeFileFn = options.writeFileFn || ((fp, content, enc) => writeFile(fp, content, enc));
228
+ this.unlinkFn = options.unlinkFn || ((fp) => unlink(fp));
229
+ }
230
+ /**
231
+ * Publish a package by shelling out to `npm publish`.
232
+ *
233
+ * Writes a temporary `.npmrc` for auth when a token is present and
234
+ * restores/removes it after the command completes (even on failure).
235
+ *
236
+ * @returns `true` if published, `false` if the version already exists.
237
+ * @throws {PublishError} On non-conflict failures (network errors, auth failures, etc.).
238
+ */
239
+ async publish(packagePath, _manifest, options) {
240
+ const args = ["publish"];
241
+ const authEntry = parseAuthTokenEntry(options, options.registry);
242
+ if (options.registry) args.push("--registry", options.registry);
243
+ else if (authEntry) args.push("--registry", `https:${authEntry.registryPath}`);
244
+ if (options.access) args.push("--access", options.access);
245
+ if (options.tag) args.push("--tag", options.tag);
246
+ const env = { ...process.env };
247
+ let npmrcPath;
248
+ let existingNpmrc;
249
+ if (authEntry) {
250
+ env.NODE_AUTH_TOKEN = authEntry.token;
251
+ const registryUrl = options.registry || `https:${authEntry.registryPath}`;
252
+ let npmrcContent;
253
+ try {
254
+ const url = new URL(registryUrl);
255
+ const registryPath = url.pathname.replace(/\/$/, "");
256
+ npmrcContent = `//${url.host}${registryPath}/:_authToken=\${NODE_AUTH_TOKEN}\n`;
257
+ } catch {
258
+ throw new PublishError(`Invalid registry URL: ${registryUrl}`);
259
+ }
260
+ npmrcPath = path.join(packagePath, ".npmrc");
261
+ try {
262
+ existingNpmrc = await this.readFileFn(npmrcPath, "utf-8");
263
+ } catch {}
264
+ const finalContent = existingNpmrc ? `${existingNpmrc.trimEnd()}\n${npmrcContent}` : npmrcContent;
265
+ await this.writeFileFn(npmrcPath, finalContent, "utf-8");
266
+ }
267
+ try {
268
+ await this.execFn("npm", args, {
269
+ cwd: packagePath,
270
+ env
271
+ });
272
+ return true;
273
+ } catch (e) {
274
+ if (this.isVersionConflict(e)) return false;
275
+ const cause = isError(e) ? e : void 0;
276
+ throw new PublishError(cause?.message || "npm publish failed with an unknown error", { cause });
277
+ } finally {
278
+ if (npmrcPath) if (typeof existingNpmrc === "string") await this.writeFileFn(npmrcPath, existingNpmrc, "utf-8");
279
+ else try {
280
+ await this.unlinkFn(npmrcPath);
281
+ } catch {}
282
+ }
283
+ }
284
+ isVersionConflict(e) {
285
+ if (!isObject(e)) return false;
286
+ let stderr = "";
287
+ if (typeof e.stderr === "string") stderr = e.stderr;
288
+ const message = isError(e) ? e.message : "";
289
+ const combined = `${stderr} ${message}`;
290
+ return combined.includes("EPUBLISHCONFLICT") || combined.includes("You cannot publish over the previously published versions") || combined.includes("Cannot publish over existing version") || combined.includes("409 Conflict");
291
+ }
292
+ };
293
+ //#endregion
294
+ //#region src/core/publisher/resolve.ts
295
+ const execFileAsync = promisify(execFile);
296
+ const NPM_MIN_VERSION = "10.0.0";
297
+ async function resolvePublisher(options = {}) {
298
+ const execFn = options.execFn || execFileAsync;
299
+ try {
300
+ const { stdout } = await execFn("npm", ["--version"], {
301
+ cwd: process.cwd(),
302
+ env: process.env
303
+ });
304
+ const version = stdout.trim();
305
+ if (semver.gte(version, NPM_MIN_VERSION)) return new NpmCliPublisher({ execFn });
306
+ } catch {}
307
+ return new NpmPublisher();
308
+ }
309
+ //#endregion
310
+ //#region src/core/registry-client/error.ts
311
+ var RegistryError = class extends BaseError {
312
+ constructor(message, statusCode) {
313
+ super(message, {
314
+ code: `E${statusCode}`,
315
+ statusCode
316
+ });
317
+ }
318
+ };
319
+ /**
320
+ * Duck-type check for RegistryError shape.
321
+ *
322
+ * Validates the error has `message` (string), `statusCode` (number),
323
+ * and `code` (string) — matching the BaseError contract.
324
+ *
325
+ * @param input The value to check.
326
+ * @returns `true` if the value has the RegistryError shape.
327
+ */
328
+ function isRegistryError(input) {
329
+ return isObject(input) && typeof input.message === "string" && typeof input.statusCode === "number" && typeof input.code === "string";
330
+ }
331
+ //#endregion
332
+ //#region src/core/registry-client/hapic.ts
333
+ var HapicRegistryClient = class {
334
+ async getPackument(name, options) {
335
+ const path = encodeURIComponent(name).replace(/^%40/, "@");
336
+ const headers = { ACCEPT: "application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*" };
337
+ if (options.token) headers.AUTHORIZATION = `Bearer ${options.token}`;
338
+ try {
339
+ return (await hapic.get(new URL(path, options.registry || "https://registry.npmjs.org/").toString(), { headers })).data;
340
+ } catch (e) {
341
+ if (isClientError(e)) throw new RegistryError(e.message, e.statusCode || 500);
342
+ throw new RegistryError(`Registry request failed for ${name}`, 500);
343
+ }
344
+ }
345
+ };
346
+ //#endregion
347
+ //#region src/core/registry-client/memory.ts
348
+ var MemoryRegistryClient = class {
349
+ items;
350
+ constructor(items = {}) {
351
+ this.items = new Map(Object.entries(items));
352
+ }
353
+ async getPackument(name) {
354
+ const packument = this.items.get(name);
355
+ if (!packument) throw new RegistryError(`Package not found: ${name}`, 404);
356
+ return packument;
357
+ }
358
+ addPackument(name, packument) {
359
+ this.items.set(name, packument);
360
+ }
361
+ };
362
+ //#endregion
363
+ //#region src/core/token-provider/chain.ts
364
+ var ChainTokenProvider = class {
365
+ providers;
366
+ constructor(providers) {
367
+ this.providers = providers;
368
+ }
369
+ async getToken(packageName, registry) {
370
+ for (const provider of this.providers) {
371
+ const token = await provider.getToken(packageName, registry);
372
+ if (token) return token;
373
+ }
374
+ }
375
+ };
376
+ //#endregion
377
+ //#region src/core/token-provider/env.ts
378
+ var EnvTokenProvider = class {
379
+ async getToken(_packageName, _registry) {
380
+ return process.env.NODE_AUTH_TOKEN || void 0;
381
+ }
382
+ };
383
+ //#endregion
384
+ //#region src/core/token-provider/memory.ts
385
+ var MemoryTokenProvider = class {
386
+ token;
387
+ constructor(token) {
388
+ this.token = token;
389
+ }
390
+ async getToken(_packageName, _registry) {
391
+ return this.token;
392
+ }
393
+ };
394
+ //#endregion
395
+ //#region src/core/token-provider/oidc.ts
396
+ var OidcTokenProvider = class {
397
+ requestUrl;
398
+ requestToken;
399
+ fetchFn;
400
+ maxRetries;
401
+ retryDelayMs;
402
+ tokenCache;
403
+ constructor(options) {
404
+ this.requestUrl = options.requestUrl;
405
+ this.requestToken = options.requestToken;
406
+ this.fetchFn = options.fetchFn ?? globalThis.fetch;
407
+ this.maxRetries = options.maxRetries ?? 2;
408
+ this.retryDelayMs = options.retryDelayMs ?? 1e3;
409
+ this.tokenCache = /* @__PURE__ */ new Map();
410
+ }
411
+ async getToken(packageName, registry) {
412
+ const cacheKey = `${packageName}@${registry}`;
413
+ const cached = this.tokenCache.get(cacheKey);
414
+ if (cached) return cached;
415
+ const audience = `npm:${new URL(registry).host}`;
416
+ const separator = this.requestUrl.includes("?") ? "&" : "?";
417
+ const oidcUrl = `${this.requestUrl}${separator}audience=${encodeURIComponent(audience)}`;
418
+ const oidcResponse = await this.fetchWithRetry(oidcUrl, { headers: { Authorization: `Bearer ${this.requestToken}` } });
419
+ if (!oidcResponse.ok) throw new Error(`Failed to fetch OIDC token from GitHub: ${oidcResponse.status} ${oidcResponse.statusText}`);
420
+ const idToken = (await oidcResponse.json()).value;
421
+ if (!idToken) throw new Error("OIDC response did not contain a valid token");
422
+ const encodedName = encodeURIComponent(packageName).replace(/^%40/, "@");
423
+ const exchangeUrl = new URL(`/-/npm/v1/oidc/token/exchange/package/${encodedName}`, registry).toString();
424
+ const exchangeResponse = await this.fetchWithRetry(exchangeUrl, {
425
+ method: "POST",
426
+ headers: { Authorization: `Bearer ${idToken}` }
427
+ });
428
+ if (!exchangeResponse.ok) throw new Error(`Failed to exchange OIDC token with npm registry: ${exchangeResponse.status} ${exchangeResponse.statusText}`);
429
+ const { token } = await exchangeResponse.json();
430
+ if (!token) throw new Error("Token exchange response did not contain a valid token");
431
+ this.tokenCache.set(cacheKey, token);
432
+ return token;
433
+ }
434
+ async fetchWithRetry(url, init) {
435
+ for (let attempt = 0; attempt <= this.maxRetries; attempt++) try {
436
+ const response = await this.fetchFn(url, init);
437
+ if (response.ok || response.status < 500) return response;
438
+ if (attempt < this.maxRetries) {
439
+ await this.delay(this.retryDelayMs * (attempt + 1));
440
+ continue;
441
+ }
442
+ return response;
443
+ } catch (e) {
444
+ if (attempt >= this.maxRetries) throw e;
445
+ await this.delay(this.retryDelayMs * (attempt + 1));
446
+ }
447
+ throw new Error("Unreachable");
448
+ }
449
+ delay(ms) {
450
+ return new Promise((resolve) => {
451
+ setTimeout(resolve, ms);
452
+ });
453
+ }
454
+ };
455
+ //#endregion
456
+ //#region src/package.ts
457
+ async function isPackagePublished(pkg, registryClient, options) {
458
+ const { name, version } = pkg.content;
459
+ if (!name || !version) throw new Error(`Name or version attribute is missing in ${pkg.path}`);
460
+ try {
461
+ const { versions } = await registryClient.getPackument(name, options);
462
+ if (typeof versions === "undefined" || typeof versions[version] === "undefined") return false;
463
+ } catch (e) {
464
+ if (isRegistryError(e) && e.statusCode === 404) return false;
465
+ throw e;
466
+ }
467
+ return true;
468
+ }
469
+ async function publishPackage(pkg, publisher, options) {
470
+ let pkgPath;
471
+ if (path.isAbsolute(pkg.path)) pkgPath = pkg.path;
472
+ else pkgPath = path.resolve(pkg.path);
473
+ const publishOptions = { ...pkg.content.publishConfig || {} };
474
+ if (options.token && options.token.length > 0) {
475
+ const registry = options.registry || "https://registry.npmjs.org/";
476
+ const url = new URL(registry);
477
+ const registryPath = url.pathname.replace(/\/$/, "");
478
+ publishOptions[`//${url.host}${registryPath}/:_authToken`] = options.token;
479
+ }
480
+ return publisher.publish(pkgPath, pkg.content, publishOptions);
481
+ }
482
+ function isPackagePublishable(pkg) {
483
+ return !!pkg.content.name && !pkg.content.private && !!pkg.content.version;
484
+ }
485
+ //#endregion
486
+ //#region src/package-dependency.ts
487
+ function updatePackagesDependencies(packages) {
488
+ const pkgDir = {};
489
+ for (const package_ of packages) pkgDir[package_.content.name] = package_;
490
+ for (const pkg of packages) {
491
+ if (pkg.content.dependencies) updatePackageDependenciesByType(pkg, "dependencies", pkgDir);
492
+ if (pkg.content.devDependencies) updatePackageDependenciesByType(pkg, "devDependencies", pkgDir);
493
+ if (pkg.content.peerDependencies) updatePackageDependenciesByType(pkg, "peerDependencies", pkgDir);
494
+ }
495
+ }
496
+ function isDependencyWorkspaceProtocolValue(value) {
497
+ return value.substring(0, 10) === "workspace:";
498
+ }
499
+ function normalizeDependencyVersionValue(input, pkgVersion) {
500
+ if (input.length === 1) {
501
+ if (input === "~" || input === "^") return input + pkgVersion;
502
+ return pkgVersion;
503
+ }
504
+ const firstCharacter = input.substring(0, 1);
505
+ if (firstCharacter === "*" || firstCharacter === "~" || firstCharacter === "^") {
506
+ if (semver.valid(input.substring(1))) {
507
+ if (firstCharacter === "~" || firstCharacter === "^") return firstCharacter + pkgVersion;
508
+ return pkgVersion;
509
+ }
510
+ return pkgVersion;
511
+ }
512
+ return pkgVersion;
513
+ }
514
+ function updatePackageDependenciesByType(pkg, depType, pkgDir) {
515
+ const dependencies = pkg.content[depType];
516
+ if (!dependencies) return;
517
+ const keys = Object.keys(dependencies);
518
+ for (const key of keys) {
519
+ const value = dependencies[key];
520
+ if (!value || !isDependencyWorkspaceProtocolValue(value)) continue;
521
+ if (!hasOwnProperty(pkgDir, key)) {
522
+ pkg.valid = false;
523
+ continue;
524
+ }
525
+ const depPkg = pkgDir[key];
526
+ if (!depPkg) {
527
+ pkg.valid = false;
528
+ continue;
529
+ }
530
+ dependencies[key] = normalizeDependencyVersionValue(value.substring(10), depPkg.content.version);
531
+ pkg.modified = true;
532
+ }
533
+ }
534
+ //#endregion
535
+ //#region src/module.ts
536
+ function resolveTokenProvider(options) {
537
+ if (options.tokenProvider) return options.tokenProvider;
538
+ if (options.token) return new MemoryTokenProvider(options.token);
539
+ return new EnvTokenProvider();
540
+ }
541
+ async function readWorkspacePackages(workspace, cwd, fileSystem) {
542
+ const directories = await fileSystem.glob(workspace, {
543
+ cwd,
544
+ ignore: ["node_modules/**"]
545
+ });
546
+ const pkgs = [];
547
+ for (const directory of directories) try {
548
+ const raw = await fileSystem.readFile(path.posix.join(directory, "package.json"));
549
+ const content = JSON.parse(raw);
550
+ pkgs.push({
551
+ path: directory,
552
+ content
553
+ });
554
+ } catch {}
555
+ return pkgs;
556
+ }
557
+ async function publish(options = {}) {
558
+ const cwd = options.cwd || process.cwd();
559
+ const registry = options.registry || "https://registry.npmjs.org/";
560
+ const rootPackage = options.rootPackage ?? true;
561
+ const fileSystem = options.fileSystem ?? new NodeFileSystem();
562
+ const registryClient = options.registryClient ?? new HapicRegistryClient();
563
+ const publisher = options.publisher ?? await resolvePublisher();
564
+ const tokenProvider = resolveTokenProvider(options);
565
+ const logger = options.logger ?? new NoopLogger();
566
+ const raw = await fileSystem.readFile(path.posix.join(cwd, "package.json"));
567
+ let pkg;
568
+ try {
569
+ pkg = JSON.parse(raw);
570
+ } catch {
571
+ throw new Error(`Invalid JSON in package.json at ${path.posix.join(cwd, "package.json")}`);
572
+ }
573
+ const packages = [];
574
+ if (!Array.isArray(pkg.workspaces) && !rootPackage) return [];
575
+ if (rootPackage) packages.push({
576
+ path: cwd,
577
+ content: pkg
578
+ });
579
+ if (Array.isArray(pkg.workspaces)) packages.push(...await readWorkspacePackages(pkg.workspaces, cwd, fileSystem));
580
+ updatePackagesDependencies(packages);
581
+ const unpublishedPackages = [];
582
+ for (const p of packages) {
583
+ if (!isPackagePublishable(p)) continue;
584
+ if (p.valid === false) {
585
+ logger.warn(`Skipping ${p.content.name}: unresolved workspace dependencies`);
586
+ continue;
587
+ }
588
+ const token = await tokenProvider.getToken(p.content.name, registry);
589
+ if (await isPackagePublished(p, registryClient, {
590
+ registry,
591
+ token
592
+ })) continue;
593
+ if (p.modified && !options.dryRun) try {
594
+ await fileSystem.writeFile(path.posix.join(p.path, "package.json"), JSON.stringify(p.content));
595
+ } catch (e) {
596
+ const message = isError(e) ? e.message : String(e);
597
+ logger.warn(`Failed to write package.json for ${p.content.name}: ${message}`);
598
+ continue;
599
+ }
600
+ unpublishedPackages.push({
601
+ pkg: p,
602
+ token
603
+ });
604
+ }
605
+ if (unpublishedPackages.length === 0) return [];
606
+ if (options.dryRun) return unpublishedPackages.map((item) => item.pkg);
607
+ for (const { pkg: p, token } of unpublishedPackages) p.published = await publishPackage(p, publisher, {
608
+ token,
609
+ registry
610
+ });
611
+ return unpublishedPackages.map((item) => item.pkg).filter((p) => !!p.published);
612
+ }
613
+ //#endregion
614
+ export { BaseError, ChainTokenProvider, ConsolaLogger, EnvTokenProvider, HapicRegistryClient, MemoryFileSystem, MemoryPublisher, MemoryRegistryClient, MemoryTokenProvider, NodeFileSystem, NoopLogger, NpmCliPublisher, NpmPublisher, OidcTokenProvider, PublishError, RegistryError, isPackagePublishable, isPackagePublished, isRegistryError, publish, publishPackage, resolvePublisher, updatePackagesDependencies };
615
+
616
+ //# sourceMappingURL=index.mjs.map