auklet 0.1.1 → 0.1.2
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 +14 -3
- package/dist/config.d.ts +1 -2
- package/dist/config.js +0 -8
- package/dist/publish/api/npmrc.d.ts +4 -0
- package/dist/publish/api/npmrc.js +52 -0
- package/dist/publish/api/pnpmApi.d.ts +9 -1
- package/dist/publish/api/pnpmApi.js +12 -1
- package/dist/publish/api/pnpmPublishApi.js +6 -1
- package/dist/publish/cli.d.ts +1 -0
- package/dist/publish/cli.js +3 -1
- package/dist/publish/inspect.js +1 -0
- package/dist/publish/inspectRegistry.d.ts +2 -1
- package/dist/publish/inspectRegistry.js +2 -0
- package/dist/publish/runner/publishPreflight.d.ts +1 -0
- package/dist/publish/runner/publishPreflight.js +32 -1
- package/dist/publish/types.d.ts +1 -0
- package/package.json +1 -1
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.
|
|
165
|
-
|
|
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
|
|
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,4 @@
|
|
|
1
|
+
export declare function findNpmrcWithAuthToken(packageRoot: string, root: string, registry?: string): string | undefined;
|
|
2
|
+
export declare function findNpmrcFiles(packageRoot: string, root: string): string[];
|
|
3
|
+
export declare function hasAuthToken(content: string, registry?: string): boolean;
|
|
4
|
+
export declare function toNpmrcRegistryKey(registry: string): string;
|
|
@@ -0,0 +1,52 @@
|
|
|
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 hasAuthToken(content, registry) {
|
|
27
|
+
const lines = content
|
|
28
|
+
.split(/\r?\n/)
|
|
29
|
+
.map((line) => line.trim())
|
|
30
|
+
.filter((line) => line && !line.startsWith('#') && !line.startsWith(';'));
|
|
31
|
+
if (!registry)
|
|
32
|
+
return lines.some((line) => line.includes('_authToken'));
|
|
33
|
+
const authKey = `${toNpmrcRegistryKey(registry)}:_authToken`;
|
|
34
|
+
return lines.some((line) => line.startsWith(authKey));
|
|
35
|
+
}
|
|
36
|
+
export function toNpmrcRegistryKey(registry) {
|
|
37
|
+
const url = parseRegistryUrl(registry);
|
|
38
|
+
const pathname = url.pathname.endsWith('/')
|
|
39
|
+
? url.pathname
|
|
40
|
+
: `${url.pathname}/`;
|
|
41
|
+
return `//${url.host}${pathname}`;
|
|
42
|
+
}
|
|
43
|
+
const parseRegistryUrl = (registry) => {
|
|
44
|
+
try {
|
|
45
|
+
return new URL(registry);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
throw new Error(`[publish] invalid publishConfig.registry: ${registry}`, {
|
|
49
|
+
cause: error,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
};
|
|
@@ -11,20 +11,28 @@ export declare function withPnpmTimeout(subprocess: ReturnType<typeof execa>, ti
|
|
|
11
11
|
export declare function ensurePnpm(): Promise<string>;
|
|
12
12
|
export declare function readPnpmWorkspacePackages(root: string): Promise<WorkspacePackage[]>;
|
|
13
13
|
export declare function runPnpmBuild(packageRoot: string): Promise<void>;
|
|
14
|
-
export declare function runPnpmPublish(packageRoot: string, args: Array<string
|
|
14
|
+
export declare function runPnpmPublish(packageRoot: string, args: Array<string>, options?: {
|
|
15
|
+
token?: string;
|
|
16
|
+
}): Promise<void>;
|
|
15
17
|
export declare function runPnpmWhoami(packageRoot: string, options?: {
|
|
16
18
|
packageName?: string;
|
|
17
19
|
registry?: string;
|
|
18
20
|
timeout?: number;
|
|
21
|
+
token?: string;
|
|
19
22
|
}): Promise<string>;
|
|
20
23
|
export declare function hasPublishedPackageVersion(packageRoot: string, packageName: string, version: string, options?: {
|
|
21
24
|
registry?: string;
|
|
22
25
|
timeout?: number;
|
|
26
|
+
token?: string;
|
|
23
27
|
}): Promise<boolean>;
|
|
24
28
|
export declare function runPnpmOwnerAdd(packageName: string, user: string, options: {
|
|
25
29
|
cwd: string;
|
|
26
30
|
otp?: string;
|
|
27
31
|
}): Promise<void>;
|
|
32
|
+
export declare function createPnpmAuthEnv(token?: string): {
|
|
33
|
+
NODE_AUTH_TOKEN: string;
|
|
34
|
+
NPM_TOKEN: string;
|
|
35
|
+
} | undefined;
|
|
28
36
|
export declare function hasNpmAuthChallenge(result: {
|
|
29
37
|
stdout?: unknown;
|
|
30
38
|
stderr?: unknown;
|
|
@@ -89,10 +89,11 @@ export async function runPnpmBuild(packageRoot) {
|
|
|
89
89
|
throw new Error(`[publish] build failed at ${packageRoot}.`);
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
|
-
export async function runPnpmPublish(packageRoot, args) {
|
|
92
|
+
export async function runPnpmPublish(packageRoot, args, options = {}) {
|
|
93
93
|
const isDryRun = args.includes('--dry-run');
|
|
94
94
|
const result = await runPnpm(['publish', ...args], {
|
|
95
95
|
cwd: packageRoot,
|
|
96
|
+
env: createPnpmAuthEnv(options.token),
|
|
96
97
|
stdio: isDryRun ? 'pipe' : 'inherit',
|
|
97
98
|
});
|
|
98
99
|
if (isDryRun)
|
|
@@ -110,6 +111,7 @@ export async function runPnpmWhoami(packageRoot, options = {}) {
|
|
|
110
111
|
args.push('--registry', options.registry);
|
|
111
112
|
const result = await runPnpm(args, {
|
|
112
113
|
cwd: packageRoot,
|
|
114
|
+
env: createPnpmAuthEnv(options.token),
|
|
113
115
|
timeout: options.timeout,
|
|
114
116
|
});
|
|
115
117
|
if (hasFailedPnpmResult(result)) {
|
|
@@ -128,6 +130,7 @@ export async function hasPublishedPackageVersion(packageRoot, packageName, versi
|
|
|
128
130
|
args.push('--registry', options.registry);
|
|
129
131
|
const result = await runPnpm(args, {
|
|
130
132
|
cwd: packageRoot,
|
|
133
|
+
env: createPnpmAuthEnv(options.token),
|
|
131
134
|
timeout: options.timeout,
|
|
132
135
|
});
|
|
133
136
|
if (!hasFailedPnpmResult(result)) {
|
|
@@ -151,6 +154,14 @@ export async function runPnpmOwnerAdd(packageName, user, options) {
|
|
|
151
154
|
throw new Error(`[publish] pnpm owner add failed for ${user} -> ${packageName}.`);
|
|
152
155
|
}
|
|
153
156
|
}
|
|
157
|
+
export function createPnpmAuthEnv(token) {
|
|
158
|
+
if (!token)
|
|
159
|
+
return undefined;
|
|
160
|
+
return {
|
|
161
|
+
NODE_AUTH_TOKEN: token,
|
|
162
|
+
NPM_TOKEN: token,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
154
165
|
const isWorkspacePackage = (value) => {
|
|
155
166
|
if (!isPlainObject(value)) {
|
|
156
167
|
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
|
-
|
|
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
|
}
|
package/dist/publish/cli.d.ts
CHANGED
package/dist/publish/cli.js
CHANGED
|
@@ -11,6 +11,7 @@ const publishFlags = new Set([
|
|
|
11
11
|
'format',
|
|
12
12
|
'git',
|
|
13
13
|
'otp',
|
|
14
|
+
'token',
|
|
14
15
|
'ignore-scripts',
|
|
15
16
|
'allow-dirty',
|
|
16
17
|
]);
|
|
@@ -34,13 +35,14 @@ export function resolvePublishCliOptions(args, cwd = process.cwd()) {
|
|
|
34
35
|
dryRun: argv['dry-run'] === true,
|
|
35
36
|
allowDirty: argv['allow-dirty'] === true,
|
|
36
37
|
ignoreScripts: argv['ignore-scripts'] === true,
|
|
38
|
+
token: stringOption(argv.token),
|
|
37
39
|
};
|
|
38
40
|
}
|
|
39
41
|
const parsePublishArgs = (args) => {
|
|
40
42
|
const cliArgs = stripLeadingArgsSeparator(args);
|
|
41
43
|
validateNoPrefixedFlags(cliArgs, new Set(['--no-format', '--no-git']));
|
|
42
44
|
const argv = minimist(cliArgs, {
|
|
43
|
-
string: ['filter', 'version', 'otp'],
|
|
45
|
+
string: ['filter', 'version', 'otp', 'token'],
|
|
44
46
|
boolean: ['dry-run', 'format', 'git', 'ignore-scripts', 'allow-dirty'],
|
|
45
47
|
default: {
|
|
46
48
|
git: true,
|
package/dist/publish/inspect.js
CHANGED
|
@@ -22,6 +22,7 @@ export async function runInspectPublishCli(args) {
|
|
|
22
22
|
const spinner = logger.spinner('Checking publish registry');
|
|
23
23
|
spinner.start();
|
|
24
24
|
const registryChecks = await inspectPublishRegistry(plan, {
|
|
25
|
+
token: options.token,
|
|
25
26
|
onCheck: (info) => {
|
|
26
27
|
spinner.text([
|
|
27
28
|
'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',
|
|
@@ -7,6 +7,7 @@ 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 verifyTokenConfig;
|
|
10
11
|
private verifyAuthentication;
|
|
11
12
|
private verifyPnpmPublishDryRun;
|
|
12
13
|
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, } 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,23 @@ export class PublishPreflight {
|
|
|
15
16
|
await this.verifyPnpmPublishDryRun(plan);
|
|
16
17
|
}
|
|
17
18
|
async verifyBeforeBuild(plan) {
|
|
19
|
+
this.verifyTokenConfig(plan);
|
|
18
20
|
if (plan.dryRun)
|
|
19
21
|
return;
|
|
20
22
|
await this.verifyAuthentication(plan);
|
|
21
23
|
await this.verifyPackageVersions(plan);
|
|
22
24
|
}
|
|
25
|
+
verifyTokenConfig(plan) {
|
|
26
|
+
if (!this.options.token)
|
|
27
|
+
return;
|
|
28
|
+
for (const target of plan.targets) {
|
|
29
|
+
const registry = getPublishRegistry(target.packageJson.publishConfig);
|
|
30
|
+
const npmrc = findNpmrcWithAuthToken(target.packageRoot, plan.root, registry);
|
|
31
|
+
if (npmrc)
|
|
32
|
+
continue;
|
|
33
|
+
throw new PublishTargetError(target, 'preflight', new Error(createMissingNpmrcAuthMessage(target, plan.root, registry)), []);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
23
36
|
async verifyAuthentication(plan) {
|
|
24
37
|
const checked = new Set();
|
|
25
38
|
for (const target of plan.targets) {
|
|
@@ -30,6 +43,7 @@ export class PublishPreflight {
|
|
|
30
43
|
await runPnpmWhoami(target.packageRoot, {
|
|
31
44
|
packageName: target.packageName,
|
|
32
45
|
registry,
|
|
46
|
+
token: this.options.token,
|
|
33
47
|
});
|
|
34
48
|
checked.add(key);
|
|
35
49
|
}
|
|
@@ -52,7 +66,7 @@ export class PublishPreflight {
|
|
|
52
66
|
async verifyPackageVersions(plan) {
|
|
53
67
|
for (const target of plan.targets) {
|
|
54
68
|
const registry = getPublishRegistry(target.packageJson.publishConfig);
|
|
55
|
-
const exists = await hasPublishedPackageVersion(target.packageRoot, target.packageName, target.publishVersion, { registry });
|
|
69
|
+
const exists = await hasPublishedPackageVersion(target.packageRoot, target.packageName, target.publishVersion, { registry, token: this.options.token });
|
|
56
70
|
if (!exists)
|
|
57
71
|
continue;
|
|
58
72
|
this.logExistingVersion(target, registry);
|
|
@@ -66,3 +80,20 @@ export class PublishPreflight {
|
|
|
66
80
|
}
|
|
67
81
|
}
|
|
68
82
|
}
|
|
83
|
+
function createMissingNpmrcAuthMessage(target, root, registry) {
|
|
84
|
+
const npmrcFiles = findNpmrcFiles(target.packageRoot, root);
|
|
85
|
+
const authTarget = registry
|
|
86
|
+
? `${toNpmrcRegistryKey(registry)}:_authToken`
|
|
87
|
+
: '_authToken';
|
|
88
|
+
const registryHint = registry
|
|
89
|
+
? `[publish] ${target.packageName} uses publishConfig.registry: ${registry}.\n`
|
|
90
|
+
: '';
|
|
91
|
+
const location = npmrcFiles.length
|
|
92
|
+
? 'found npmrc files, but none declares'
|
|
93
|
+
: 'could not find an npmrc file declaring';
|
|
94
|
+
return (`[publish] --token requires npmrc auth config for ${target.packageName}.\n` +
|
|
95
|
+
registryHint +
|
|
96
|
+
`[publish] ${location} ${authTarget}.\n` +
|
|
97
|
+
'[publish] Add an npmrc entry such as:\n' +
|
|
98
|
+
` ${authTarget}=\${NODE_AUTH_TOKEN}`);
|
|
99
|
+
}
|
package/dist/publish/types.d.ts
CHANGED