auklet 0.1.1 → 0.1.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/README.md CHANGED
@@ -131,6 +131,7 @@ auk publish --version patch --dry-run
131
131
  auk publish --no-format
132
132
  auk publish --no-git
133
133
  auk publish --otp 123456
134
+ auk publish --token npm_xxx
134
135
  auk inspect publish --version patch
135
136
  auk inspect pack --filter @scope/ui
136
137
  auk inspect css --modules
@@ -161,8 +162,16 @@ Before writing versions, auklet checks npm authentication from each target
161
162
  package directory. Package-local `.npmrc` files and
162
163
  `package.json#publishConfig.registry` are respected.
163
164
  `--otp` is forwarded to `pnpm publish` for npm accounts or organizations that
164
- require publish 2FA, and to `pnpm owner add` for owner management 2FA. In CI,
165
- prefer an npm automation token.
165
+ require publish 2FA, and to `pnpm owner add` for owner management 2FA.
166
+ `--token` sets `NODE_AUTH_TOKEN` and `NPM_TOKEN` for publish subprocesses. The
167
+ token still needs npmrc auth config, for example:
168
+
169
+ ```ini
170
+ //registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}
171
+ ```
172
+
173
+ When a package uses `package.json#publishConfig.registry`, the npmrc token entry
174
+ must target that registry. In CI, prefer an npm automation token over `--otp`.
166
175
 
167
176
  `auk inspect publish` accepts the same publish selection and version flags as
168
177
  `auk publish`. It resolves the publish plan, checks package entry/export files,
@@ -177,7 +186,9 @@ and declared `files` paths point to existing package files.
177
186
  `auk inspect css` accepts the same build override flags as `auk build`. It
178
187
  prints the normalized CSS plan, including output entries, theme files, and
179
188
  module entries. When run from a pnpm workspace root, it inspects workspace child
180
- packages instead of the root package. It does not write CSS output.
189
+ packages instead of the root package. It does not write CSS output, but
190
+ dependency CSS files must already exist when the plan relies on external package
191
+ style entries or component auto imports.
181
192
 
182
193
  ## Configuration
183
194
 
package/dist/config.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { AukletConfig, StyleDependencyGroup } from '#auklet/types';
1
+ import type { AukletConfig } from '#auklet/types';
2
2
  export declare const aukletConfigFiles: string[];
3
3
  export declare function isAukletConfigFile(file: string): boolean;
4
4
  export declare const aukletDefaultOptions: {
@@ -15,7 +15,6 @@ export declare const aukletDefaultOptions: {
15
15
  dependencies: {};
16
16
  };
17
17
  };
18
- export declare const aukletDefaultStyleDependencyConfig: StyleDependencyGroup;
19
18
  export declare function normalizeAukletConfig(config?: AukletConfig): {
20
19
  source: string;
21
20
  output: string;
package/dist/config.js CHANGED
@@ -16,14 +16,6 @@ export const aukletDefaultOptions = {
16
16
  dependencies: {},
17
17
  },
18
18
  };
19
- export const aukletDefaultStyleDependencyConfig = {
20
- entry: '/style.css',
21
- components: ['/pages/**.css', '/components/**.css'],
22
- themes: {
23
- dark: '/themes/dark.css',
24
- light: '/themes/light.css',
25
- },
26
- };
27
19
  const normalizeStyleDependency = (dependency) => ({
28
20
  entry: dependency.entry,
29
21
  themes: dependency.themes,
@@ -0,0 +1,8 @@
1
+ export type NpmrcAuthEnvOptions = {
2
+ token?: string;
3
+ };
4
+ export declare function findNpmrcWithAuthToken(packageRoot: string, root: string, registry?: string): string | undefined;
5
+ export declare function findNpmrcFiles(packageRoot: string, root: string): string[];
6
+ export declare function validateNpmrcAuthEnv(packageRoot: string, root: string, options?: NpmrcAuthEnvOptions): void;
7
+ export declare function hasAuthToken(content: string, registry?: string): boolean;
8
+ export declare function toNpmrcRegistryKey(registry: string): string;
@@ -0,0 +1,89 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ export function findNpmrcWithAuthToken(packageRoot, root, registry) {
4
+ const npmrcFiles = findNpmrcFiles(packageRoot, root);
5
+ return npmrcFiles.find((file) => {
6
+ return hasAuthToken(fs.readFileSync(file, 'utf8'), registry);
7
+ });
8
+ }
9
+ export function findNpmrcFiles(packageRoot, root) {
10
+ const files = [];
11
+ let current = path.resolve(packageRoot);
12
+ const boundary = path.resolve(root);
13
+ while (true) {
14
+ const file = path.join(current, '.npmrc');
15
+ if (fs.existsSync(file))
16
+ files.push(file);
17
+ if (current === boundary)
18
+ break;
19
+ const parent = path.dirname(current);
20
+ if (parent === current)
21
+ break;
22
+ current = parent;
23
+ }
24
+ return files;
25
+ }
26
+ export function validateNpmrcAuthEnv(packageRoot, root, options = {}) {
27
+ const env = createAvailableAuthEnv(options);
28
+ for (const file of findNpmrcFiles(packageRoot, root)) {
29
+ const missing = findMissingNpmrcEnvVars(fs.readFileSync(file, 'utf8'), env);
30
+ if (!missing.length)
31
+ continue;
32
+ const variable = missing[0];
33
+ throw new Error(`[publish] npmrc auth environment is missing: ${variable}\n` +
34
+ `[publish] file: ${file}\n` +
35
+ `[publish] Set ${variable} before retrying, or use --token with an npmrc entry such as:\n` +
36
+ ' //registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}');
37
+ }
38
+ }
39
+ export function hasAuthToken(content, registry) {
40
+ const lines = content
41
+ .split(/\r?\n/)
42
+ .map((line) => line.trim())
43
+ .filter((line) => line && !line.startsWith('#') && !line.startsWith(';'));
44
+ if (!registry)
45
+ return lines.some((line) => line.includes('_authToken'));
46
+ const authKey = `${toNpmrcRegistryKey(registry)}:_authToken`;
47
+ return lines.some((line) => line.startsWith(authKey));
48
+ }
49
+ export function toNpmrcRegistryKey(registry) {
50
+ const url = parseRegistryUrl(registry);
51
+ const pathname = url.pathname.endsWith('/')
52
+ ? url.pathname
53
+ : `${url.pathname}/`;
54
+ return `//${url.host}${pathname}`;
55
+ }
56
+ const parseRegistryUrl = (registry) => {
57
+ try {
58
+ return new URL(registry);
59
+ }
60
+ catch (error) {
61
+ throw new Error(`[publish] invalid publishConfig.registry: ${registry}`, {
62
+ cause: error,
63
+ });
64
+ }
65
+ };
66
+ const findMissingNpmrcEnvVars = (content, env) => {
67
+ return getNpmrcAuthLines(content)
68
+ .flatMap((line) => [...line.matchAll(/\$\{([^}]+)\}/g)])
69
+ .map((match) => match[1])
70
+ .filter((name) => name && !env[name]);
71
+ };
72
+ const getNpmrcAuthLines = (content) => {
73
+ return content
74
+ .split(/\r?\n/)
75
+ .map((line) => line.trim())
76
+ .filter((line) => line &&
77
+ !line.startsWith('#') &&
78
+ !line.startsWith(';') &&
79
+ line.includes('_authToken'));
80
+ };
81
+ const createAvailableAuthEnv = (options) => {
82
+ if (!options.token)
83
+ return process.env;
84
+ return {
85
+ ...process.env,
86
+ NODE_AUTH_TOKEN: options.token,
87
+ NPM_TOKEN: options.token,
88
+ };
89
+ };
@@ -8,23 +8,37 @@ export declare class NpmPackageVersionExistsError extends Error {
8
8
  constructor(packageName: string, version: string, registry?: string);
9
9
  }
10
10
  export declare function withPnpmTimeout(subprocess: ReturnType<typeof execa>, timeout: number): Promise<import("node_modules/execa/types/return/result").CommonResult<false, Options> & import("node_modules/execa/types/return/result").OmitErrorIfReject<boolean | undefined>>;
11
- export declare function ensurePnpm(): Promise<string>;
12
- export declare function readPnpmWorkspacePackages(root: string): Promise<WorkspacePackage[]>;
13
- export declare function runPnpmBuild(packageRoot: string): Promise<void>;
14
- export declare function runPnpmPublish(packageRoot: string, args: Array<string>): Promise<void>;
11
+ export declare function ensurePnpm(options?: {
12
+ token?: string;
13
+ }): Promise<string>;
14
+ export declare function readPnpmWorkspacePackages(root: string, options?: {
15
+ token?: string;
16
+ }): Promise<WorkspacePackage[]>;
17
+ export declare function runPnpmBuild(packageRoot: string, options?: {
18
+ token?: string;
19
+ }): Promise<void>;
20
+ export declare function runPnpmPublish(packageRoot: string, args: Array<string>, options?: {
21
+ token?: string;
22
+ }): Promise<void>;
15
23
  export declare function runPnpmWhoami(packageRoot: string, options?: {
16
24
  packageName?: string;
17
25
  registry?: string;
18
26
  timeout?: number;
27
+ token?: string;
19
28
  }): Promise<string>;
20
29
  export declare function hasPublishedPackageVersion(packageRoot: string, packageName: string, version: string, options?: {
21
30
  registry?: string;
22
31
  timeout?: number;
32
+ token?: string;
23
33
  }): Promise<boolean>;
24
34
  export declare function runPnpmOwnerAdd(packageName: string, user: string, options: {
25
35
  cwd: string;
26
36
  otp?: string;
27
37
  }): Promise<void>;
38
+ export declare function createPnpmAuthEnv(token?: string): {
39
+ NODE_AUTH_TOKEN: string;
40
+ NPM_TOKEN: string;
41
+ } | undefined;
28
42
  export declare function hasNpmAuthChallenge(result: {
29
43
  stdout?: unknown;
30
44
  stderr?: unknown;
@@ -50,8 +50,10 @@ export async function withPnpmTimeout(subprocess, timeout) {
50
50
  subprocess.catch(() => { });
51
51
  return result;
52
52
  }
53
- export async function ensurePnpm() {
54
- const result = await runPnpm(['--version']);
53
+ export async function ensurePnpm(options = {}) {
54
+ const result = await runPnpm(['--version'], {
55
+ env: createPnpmAuthEnv(options.token),
56
+ });
55
57
  const stdout = String(result.stdout ?? '');
56
58
  if (hasFailedPnpmResult(result) || !stdout) {
57
59
  throw new Error('[publish] pnpm is required for publishing.\n' +
@@ -66,9 +68,11 @@ export async function ensurePnpm() {
66
68
  }
67
69
  return version;
68
70
  }
69
- export async function readPnpmWorkspacePackages(root) {
71
+ export async function readPnpmWorkspacePackages(root, options = {}) {
70
72
  try {
71
- return (await readPnpmWorkspacePackageInfo(root)).map((item) => {
73
+ return (await readPnpmWorkspacePackageInfo(root, {
74
+ env: createPnpmAuthEnv(options.token),
75
+ })).map((item) => {
72
76
  if (!isWorkspacePackage(item))
73
77
  throwInvalidWorkspacePackages();
74
78
  return item;
@@ -80,19 +84,21 @@ export async function readPnpmWorkspacePackages(root) {
80
84
  });
81
85
  }
82
86
  }
83
- export async function runPnpmBuild(packageRoot) {
87
+ export async function runPnpmBuild(packageRoot, options = {}) {
84
88
  const result = await runPnpm(['run', 'build'], {
85
89
  cwd: packageRoot,
90
+ env: createPnpmAuthEnv(options.token),
86
91
  stdio: 'inherit',
87
92
  });
88
93
  if (hasFailedPnpmResult(result)) {
89
94
  throw new Error(`[publish] build failed at ${packageRoot}.`);
90
95
  }
91
96
  }
92
- export async function runPnpmPublish(packageRoot, args) {
97
+ export async function runPnpmPublish(packageRoot, args, options = {}) {
93
98
  const isDryRun = args.includes('--dry-run');
94
99
  const result = await runPnpm(['publish', ...args], {
95
100
  cwd: packageRoot,
101
+ env: createPnpmAuthEnv(options.token),
96
102
  stdio: isDryRun ? 'pipe' : 'inherit',
97
103
  });
98
104
  if (isDryRun)
@@ -110,6 +116,7 @@ export async function runPnpmWhoami(packageRoot, options = {}) {
110
116
  args.push('--registry', options.registry);
111
117
  const result = await runPnpm(args, {
112
118
  cwd: packageRoot,
119
+ env: createPnpmAuthEnv(options.token),
113
120
  timeout: options.timeout,
114
121
  });
115
122
  if (hasFailedPnpmResult(result)) {
@@ -128,6 +135,7 @@ export async function hasPublishedPackageVersion(packageRoot, packageName, versi
128
135
  args.push('--registry', options.registry);
129
136
  const result = await runPnpm(args, {
130
137
  cwd: packageRoot,
138
+ env: createPnpmAuthEnv(options.token),
131
139
  timeout: options.timeout,
132
140
  });
133
141
  if (!hasFailedPnpmResult(result)) {
@@ -151,6 +159,14 @@ export async function runPnpmOwnerAdd(packageName, user, options) {
151
159
  throw new Error(`[publish] pnpm owner add failed for ${user} -> ${packageName}.`);
152
160
  }
153
161
  }
162
+ export function createPnpmAuthEnv(token) {
163
+ if (!token)
164
+ return undefined;
165
+ return {
166
+ NODE_AUTH_TOKEN: token,
167
+ NPM_TOKEN: token,
168
+ };
169
+ }
154
170
  const isWorkspacePackage = (value) => {
155
171
  if (!isPlainObject(value)) {
156
172
  return false;
@@ -2,6 +2,11 @@ import { runPnpmPublish } from '#auklet/publish/api/pnpmApi';
2
2
  import { createPublishArgs } from '#auklet/publish/api/publishArgs';
3
3
  export class PnpmPublishApi {
4
4
  async publish(target, options) {
5
- await runPnpmPublish(target.packageRoot, createPublishArgs(target, options));
5
+ const args = createPublishArgs(target, options);
6
+ if (options.token) {
7
+ await runPnpmPublish(target.packageRoot, args, { token: options.token });
8
+ return;
9
+ }
10
+ await runPnpmPublish(target.packageRoot, args);
6
11
  }
7
12
  }
@@ -9,5 +9,6 @@ export declare function resolvePublishCliOptions(args: Array<string>, cwd?: stri
9
9
  dryRun: boolean;
10
10
  allowDirty: boolean;
11
11
  ignoreScripts: boolean;
12
+ token: string | undefined;
12
13
  };
13
14
  export declare function runOwnerCli(args: Array<string>): Promise<void>;
@@ -2,7 +2,9 @@ import minimist from 'minimist';
2
2
  import { isArray } from 'aidly';
3
3
  import { OwnerRunner } from '#auklet/publish/ownerRunner';
4
4
  import { PublishRunner } from '#auklet/publish/publishRunner';
5
+ import { validateNpmrcAuthEnv } from '#auklet/publish/api/npmrc';
5
6
  import { ensurePnpm } from '#auklet/publish/api/pnpmApi';
7
+ import { findWorkspaceRoot } from '#auklet/workspace/root';
6
8
  const publishFlags = new Set([
7
9
  '_',
8
10
  'filter',
@@ -11,13 +13,16 @@ const publishFlags = new Set([
11
13
  'format',
12
14
  'git',
13
15
  'otp',
16
+ 'token',
14
17
  'ignore-scripts',
15
18
  'allow-dirty',
16
19
  ]);
17
20
  const ownerFlags = new Set(['_', 'filter', 'package', 'otp']);
18
21
  export async function runPublishCli(args) {
19
- await ensurePnpm();
20
- await new PublishRunner(resolvePublishCliOptions(args)).run();
22
+ const options = resolvePublishCliOptions(args);
23
+ validatePublishCliNpmrcAuthEnv(options.cwd, options.token);
24
+ await ensurePnpm({ token: options.token });
25
+ await new PublishRunner(options).run();
21
26
  }
22
27
  export function resolvePublishCliOptions(args, cwd = process.cwd()) {
23
28
  const argv = parsePublishArgs(args);
@@ -34,13 +39,14 @@ export function resolvePublishCliOptions(args, cwd = process.cwd()) {
34
39
  dryRun: argv['dry-run'] === true,
35
40
  allowDirty: argv['allow-dirty'] === true,
36
41
  ignoreScripts: argv['ignore-scripts'] === true,
42
+ token: stringOption(argv.token),
37
43
  };
38
44
  }
39
45
  const parsePublishArgs = (args) => {
40
46
  const cliArgs = stripLeadingArgsSeparator(args);
41
47
  validateNoPrefixedFlags(cliArgs, new Set(['--no-format', '--no-git']));
42
48
  const argv = minimist(cliArgs, {
43
- string: ['filter', 'version', 'otp'],
49
+ string: ['filter', 'version', 'otp', 'token'],
44
50
  boolean: ['dry-run', 'format', 'git', 'ignore-scripts', 'allow-dirty'],
45
51
  default: {
46
52
  git: true,
@@ -64,9 +70,11 @@ export async function runOwnerCli(args) {
64
70
  if (!users.length) {
65
71
  throw new Error('[publish] owner add requires at least one user.');
66
72
  }
73
+ const cwd = process.cwd();
74
+ validatePublishCliNpmrcAuthEnv(cwd);
67
75
  await ensurePnpm();
68
76
  await new OwnerRunner({
69
- cwd: process.cwd(),
77
+ cwd,
70
78
  users,
71
79
  filters: toArray(argv.filter),
72
80
  packages: toArray(argv.package),
@@ -103,3 +111,6 @@ const stringOption = (value) => {
103
111
  return String(value.at(-1));
104
112
  return String(value);
105
113
  };
114
+ const validatePublishCliNpmrcAuthEnv = (cwd, token) => {
115
+ validateNpmrcAuthEnv(cwd, findWorkspaceRoot(cwd) ?? cwd, { token });
116
+ };
@@ -4,13 +4,18 @@ import { createAukletLogger } from '#auklet/logger';
4
4
  import { resolvePublishTag } from '#auklet/publish/api/publishArgs';
5
5
  import { getPublishRegistry } from '#auklet/publish/api/registry';
6
6
  import { ensurePnpm } from '#auklet/publish/api/pnpmApi';
7
+ import { validateNpmrcAuthEnv } from '#auklet/publish/api/npmrc';
7
8
  import { resolvePublishCliOptions } from '#auklet/publish/cli';
9
+ import { findWorkspaceRoot } from '#auklet/workspace/root';
8
10
  import { inspectPublishRegistry, } from '#auklet/publish/inspectRegistry';
9
11
  import { inspectPackageFiles, PackInspectReporter, } from '#auklet/publish/inspectPack';
10
12
  import { resolvePublishPlan } from '#auklet/publish/targetResolver';
11
13
  export async function runInspectPublishCli(args) {
12
- await ensurePnpm();
13
14
  const options = resolvePublishCliOptions(args);
15
+ validateNpmrcAuthEnv(options.cwd, findWorkspaceRoot(options.cwd) ?? options.cwd, {
16
+ token: options.token,
17
+ });
18
+ await ensurePnpm({ token: options.token });
14
19
  const logger = createAukletLogger({ scope: 'inspect' });
15
20
  const plan = await resolvePublishPlan(options, logger);
16
21
  const packageFileChecks = inspectPackageFiles(plan.targets);
@@ -22,6 +27,7 @@ export async function runInspectPublishCli(args) {
22
27
  const spinner = logger.spinner('Checking publish registry');
23
28
  spinner.start();
24
29
  const registryChecks = await inspectPublishRegistry(plan, {
30
+ token: options.token,
25
31
  onCheck: (info) => {
26
32
  spinner.text([
27
33
  'Checking registry ',
@@ -1,4 +1,4 @@
1
- import type { PublishPlan } from '#auklet/publish/types';
1
+ import type { PublishOptions, PublishPlan } from '#auklet/publish/types';
2
2
  export type PublishRegistryCheckStatus = 'success' | 'error';
3
3
  export type PublishRegistryCheck = {
4
4
  packageName: string;
@@ -17,6 +17,7 @@ export type PublishRegistryRetryInfo = {
17
17
  };
18
18
  export type PublishRegistryCheckInfo = Pick<PublishRegistryRetryInfo, 'packageName' | 'registry' | 'check'>;
19
19
  export type InspectPublishRegistryOptions = {
20
+ token?: PublishOptions['token'];
20
21
  onCheck?: (info: PublishRegistryCheckInfo) => void;
21
22
  onRetry?: (info: PublishRegistryRetryInfo) => void;
22
23
  };
@@ -35,6 +35,7 @@ const checkAuth = async (authResults, authKey, packageRoot, packageName, registr
35
35
  await retryWithLog(() => runPnpmWhoami(packageRoot, {
36
36
  packageName,
37
37
  registry,
38
+ token: options.token,
38
39
  timeout: registryCheckTimeout,
39
40
  }), {
40
41
  check: 'auth',
@@ -60,6 +61,7 @@ const checkVersion = async (packageRoot, packageName, version, registry, options
60
61
  });
61
62
  const exists = await retryWithLog(() => hasPublishedPackageVersion(packageRoot, packageName, version, {
62
63
  registry,
64
+ token: options.token,
63
65
  timeout: registryCheckTimeout,
64
66
  }), {
65
67
  check: 'version',
@@ -36,7 +36,7 @@ export class PublishRunner {
36
36
  await runPublishHook({ status: 'beforeBuild', plan });
37
37
  failureHookEnabled = true;
38
38
  this.versions.writeBeforeBuild(plan);
39
- await runPackageBuilds(plan.targets, this.logger);
39
+ await runPackageBuilds(plan.targets, this.logger, this.options);
40
40
  await runPublishHook({ status: 'afterBuild', plan });
41
41
  await formatPublishOutputs(plan.targets, this.options.format);
42
42
  await runPublishHook({ status: 'beforePublish', plan });
@@ -1,4 +1,5 @@
1
1
  import type { PublishTarget } from '#auklet/publish/types';
2
2
  import type { AukletLogger } from '#auklet/logger';
3
+ import type { PublishOptions } from '#auklet/publish/types';
3
4
  export declare function validateBuildScript(targets: Array<PublishTarget>): void;
4
- export declare function runPackageBuilds(targets: Array<PublishTarget>, logger: AukletLogger): Promise<void>;
5
+ export declare function runPackageBuilds(targets: Array<PublishTarget>, logger: AukletLogger, options?: Pick<PublishOptions, 'token'>): Promise<void>;
@@ -8,9 +8,13 @@ export function validateBuildScript(targets) {
8
8
  }
9
9
  }
10
10
  }
11
- export async function runPackageBuilds(targets, logger) {
11
+ export async function runPackageBuilds(targets, logger, options = {}) {
12
12
  for (const target of targets) {
13
13
  logger.step('build ', logger.package(target.packageName));
14
+ if (options.token) {
15
+ await runPnpmBuild(target.packageRoot, { token: options.token });
16
+ continue;
17
+ }
14
18
  await runPnpmBuild(target.packageRoot);
15
19
  }
16
20
  }
@@ -7,6 +7,8 @@ export declare class PublishPreflight {
7
7
  constructor(options: PublishOptions, logger: AukletLogger);
8
8
  run(plan: PublishPlan): Promise<void>;
9
9
  verifyBeforeBuild(plan: PublishPlan): Promise<void>;
10
+ private verifyNpmrcAuthEnv;
11
+ private verifyTokenConfig;
10
12
  private verifyAuthentication;
11
13
  private verifyPnpmPublishDryRun;
12
14
  private verifyPackageVersions;
@@ -1,5 +1,6 @@
1
1
  import { PnpmPublishApi } from '#auklet/publish/api/pnpmPublishApi';
2
2
  import { hasPublishedPackageVersion, NpmPackageVersionExistsError, runPnpmWhoami, } from '#auklet/publish/api/pnpmApi';
3
+ import { findNpmrcFiles, findNpmrcWithAuthToken, toNpmrcRegistryKey, validateNpmrcAuthEnv, } from '#auklet/publish/api/npmrc';
3
4
  import { getPublishRegistry } from '#auklet/publish/api/registry';
4
5
  import { logAuthenticationError } from '#auklet/publish/runner/packagePublisher';
5
6
  import { PublishTargetError } from '#auklet/publish/runner/publishTargetError';
@@ -15,11 +16,31 @@ export class PublishPreflight {
15
16
  await this.verifyPnpmPublishDryRun(plan);
16
17
  }
17
18
  async verifyBeforeBuild(plan) {
19
+ this.verifyNpmrcAuthEnv(plan);
20
+ this.verifyTokenConfig(plan);
18
21
  if (plan.dryRun)
19
22
  return;
20
23
  await this.verifyAuthentication(plan);
21
24
  await this.verifyPackageVersions(plan);
22
25
  }
26
+ verifyNpmrcAuthEnv(plan) {
27
+ for (const target of plan.targets) {
28
+ validateNpmrcAuthEnv(target.packageRoot, plan.root, {
29
+ token: this.options.token,
30
+ });
31
+ }
32
+ }
33
+ verifyTokenConfig(plan) {
34
+ if (!this.options.token)
35
+ return;
36
+ for (const target of plan.targets) {
37
+ const registry = getPublishRegistry(target.packageJson.publishConfig);
38
+ const npmrc = findNpmrcWithAuthToken(target.packageRoot, plan.root, registry);
39
+ if (npmrc)
40
+ continue;
41
+ throw new PublishTargetError(target, 'preflight', new Error(createMissingNpmrcAuthMessage(target, plan.root, registry)), []);
42
+ }
43
+ }
23
44
  async verifyAuthentication(plan) {
24
45
  const checked = new Set();
25
46
  for (const target of plan.targets) {
@@ -30,6 +51,7 @@ export class PublishPreflight {
30
51
  await runPnpmWhoami(target.packageRoot, {
31
52
  packageName: target.packageName,
32
53
  registry,
54
+ token: this.options.token,
33
55
  });
34
56
  checked.add(key);
35
57
  }
@@ -52,7 +74,7 @@ export class PublishPreflight {
52
74
  async verifyPackageVersions(plan) {
53
75
  for (const target of plan.targets) {
54
76
  const registry = getPublishRegistry(target.packageJson.publishConfig);
55
- const exists = await hasPublishedPackageVersion(target.packageRoot, target.packageName, target.publishVersion, { registry });
77
+ const exists = await hasPublishedPackageVersion(target.packageRoot, target.packageName, target.publishVersion, { registry, token: this.options.token });
56
78
  if (!exists)
57
79
  continue;
58
80
  this.logExistingVersion(target, registry);
@@ -66,3 +88,20 @@ export class PublishPreflight {
66
88
  }
67
89
  }
68
90
  }
91
+ function createMissingNpmrcAuthMessage(target, root, registry) {
92
+ const npmrcFiles = findNpmrcFiles(target.packageRoot, root);
93
+ const authTarget = registry
94
+ ? `${toNpmrcRegistryKey(registry)}:_authToken`
95
+ : '_authToken';
96
+ const registryHint = registry
97
+ ? `[publish] ${target.packageName} uses publishConfig.registry: ${registry}.\n`
98
+ : '';
99
+ const location = npmrcFiles.length
100
+ ? 'found npmrc files, but none declares'
101
+ : 'could not find an npmrc file declaring';
102
+ return (`[publish] --token requires npmrc auth config for ${target.packageName}.\n` +
103
+ registryHint +
104
+ `[publish] ${location} ${authTarget}.\n` +
105
+ '[publish] Add an npmrc entry such as:\n' +
106
+ ` ${authTarget}=\${NODE_AUTH_TOKEN}`);
107
+ }
@@ -1,6 +1,6 @@
1
1
  import { type AukletLogger } from '#auklet/logger';
2
2
  import type { OwnerOptions, PublishOptions, PublishPlan } from '#auklet/publish/types';
3
- type ResolvePublishTargetsOptions = Pick<PublishOptions, 'cwd' | 'filters' | 'version' | 'dryRun'>;
3
+ type ResolvePublishTargetsOptions = Pick<PublishOptions, 'cwd' | 'filters' | 'version' | 'dryRun' | 'token'>;
4
4
  type ResolveOwnerTargetsOptions = Pick<OwnerOptions, 'cwd' | 'filters' | 'packages'>;
5
5
  export declare function resolvePublishPlan(options: ResolvePublishTargetsOptions, logger?: AukletLogger): Promise<PublishPlan>;
6
6
  export declare function resolveOwnerPackageNames(options: ResolveOwnerTargetsOptions): Promise<string[]>;
@@ -59,7 +59,9 @@ const resolveMonorepoPublishPlan = async (options, logger) => {
59
59
  const root = requireWorkspaceRoot(options.cwd);
60
60
  const rootPackageJson = readPackageJson(root);
61
61
  const rootVersion = requirePackageVersion(root, rootPackageJson);
62
- const workspacePackages = await readPnpmWorkspacePackages(root);
62
+ const workspacePackages = await readPnpmWorkspacePackages(root, {
63
+ token: options.token,
64
+ });
63
65
  const selectedPackages = filterWorkspacePackages(workspacePackages, options.filters);
64
66
  const targets = selectedPackages
65
67
  .filter((item) => {
@@ -50,6 +50,7 @@ export type PublishOptions = {
50
50
  filters: Array<string>;
51
51
  git?: boolean;
52
52
  otp?: string;
53
+ token?: string;
53
54
  version?: string;
54
55
  };
55
56
  export type OwnerOptions = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auklet",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "author": "chentao.arthur",
6
6
  "description": "Build utilities for TypeScript packages and module CSS output.",