@lpm-registry/cli 0.46.0 → 0.48.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/bin/lpm.js +250 -241
- package/lib/commands/npmrc.js +169 -169
- package/lib/commands/setup.js +192 -188
- package/package.json +6 -6
package/lib/commands/setup.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import fs from "node:fs"
|
|
2
|
-
import path from "node:path"
|
|
3
|
-
import * as p from "@clack/prompts"
|
|
4
|
-
import chalk from "chalk"
|
|
5
|
-
import { getRegistryUrl } from "../config.js"
|
|
6
|
-
import { exchangeOidcInstallToken } from "../oidc.js"
|
|
7
|
-
import { log, printHeader } from "../ui.js"
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import * as p from "@clack/prompts";
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import { getRegistryUrl } from "../config.js";
|
|
6
|
+
import { exchangeOidcInstallToken } from "../oidc.js";
|
|
7
|
+
import { log, printHeader } from "../ui.js";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Remove existing LPM config lines from .npmrc content.
|
|
@@ -13,21 +13,21 @@ import { log, printHeader } from "../ui.js"
|
|
|
13
13
|
* @returns {string}
|
|
14
14
|
*/
|
|
15
15
|
function removeLpmLines(content) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
16
|
+
return content
|
|
17
|
+
.split("\n")
|
|
18
|
+
.filter((line) => {
|
|
19
|
+
return (
|
|
20
|
+
!line.includes("@lpm.dev:registry") &&
|
|
21
|
+
!line.match(/^registry=.*lpm\.dev/) &&
|
|
22
|
+
!line.includes("lpm.dev/api/registry/:_authToken") &&
|
|
23
|
+
!line.includes("_authToken=lpm_") &&
|
|
24
|
+
// biome-ignore lint/suspicious/noTemplateCurlyInString: matching literal npm token placeholder
|
|
25
|
+
!line.includes("_authToken=${LPM_TOKEN}") &&
|
|
26
|
+
!line.includes("# LPM Registry")
|
|
27
|
+
);
|
|
28
|
+
})
|
|
29
|
+
.join("\n")
|
|
30
|
+
.trim();
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
/**
|
|
@@ -36,182 +36,186 @@ function removeLpmLines(content) {
|
|
|
36
36
|
* @returns {string|null} The custom registry line, or null if none found
|
|
37
37
|
*/
|
|
38
38
|
function detectCustomRegistry(content) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
39
|
+
return (
|
|
40
|
+
content
|
|
41
|
+
.split("\n")
|
|
42
|
+
.find(
|
|
43
|
+
(line) =>
|
|
44
|
+
line.match(/^registry=/) &&
|
|
45
|
+
!line.includes("registry.npmjs.org") &&
|
|
46
|
+
!line.includes("lpm.dev"),
|
|
47
|
+
) || null
|
|
48
|
+
);
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
|
-
* Configure .npmrc for LPM packages.
|
|
52
|
+
* Configure CI/CD .npmrc for LPM packages.
|
|
53
53
|
*
|
|
54
54
|
* Default mode: writes ${LPM_TOKEN} placeholder (for CI with env var).
|
|
55
55
|
* --oidc mode: exchanges CI OIDC token for a real short-lived token (no secrets needed).
|
|
56
56
|
*/
|
|
57
57
|
export async function setup(options) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
58
|
+
printHeader();
|
|
59
|
+
|
|
60
|
+
p.intro(chalk.bgCyan(chalk.black(" lpm setup ci ")));
|
|
61
|
+
|
|
62
|
+
const registryUrl = options?.registry || getRegistryUrl();
|
|
63
|
+
const projectRoot = process.cwd();
|
|
64
|
+
const npmrcPath = path.join(projectRoot, ".npmrc");
|
|
65
|
+
|
|
66
|
+
// Check for package.json
|
|
67
|
+
const pkgJsonPath = path.join(projectRoot, "package.json");
|
|
68
|
+
if (!fs.existsSync(pkgJsonPath)) {
|
|
69
|
+
log.warn("No package.json found. Run this command in your project root.");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Build registry URL
|
|
73
|
+
const fullRegistryUrl = registryUrl.endsWith("/api/registry")
|
|
74
|
+
? registryUrl
|
|
75
|
+
: `${registryUrl}/api/registry`;
|
|
76
|
+
const registryHost = fullRegistryUrl.replace(/^https?:/, "");
|
|
77
|
+
|
|
78
|
+
// Default: scoped (only @lpm.dev packages through lpm.dev).
|
|
79
|
+
// --proxy: route all npm traffic through lpm.dev (Pro/Org feature).
|
|
80
|
+
let useScoped = !options?.proxy;
|
|
81
|
+
|
|
82
|
+
// ── OIDC mode: exchange CI token for a real short-lived install token ──
|
|
83
|
+
if (options?.oidc) {
|
|
84
|
+
let oidcToken;
|
|
85
|
+
try {
|
|
86
|
+
oidcToken = await exchangeOidcInstallToken();
|
|
87
|
+
} catch (err) {
|
|
88
|
+
log.warn(`OIDC exchange failed: ${err.message}`);
|
|
89
|
+
// biome-ignore lint/suspicious/noTemplateCurlyInString: literal placeholder name in user-facing message
|
|
90
|
+
log.warn(
|
|
91
|
+
"Falling back to ${LPM_TOKEN} environment variable placeholder.",
|
|
92
|
+
);
|
|
93
|
+
// Fall through to default mode
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (oidcToken) {
|
|
97
|
+
let npmrcContent = "";
|
|
98
|
+
if (fs.existsSync(npmrcPath)) {
|
|
99
|
+
const existingContent = fs.readFileSync(npmrcPath, "utf8");
|
|
100
|
+
|
|
101
|
+
// Detect custom default registry
|
|
102
|
+
if (!useScoped) {
|
|
103
|
+
const customRegistry = detectCustomRegistry(existingContent);
|
|
104
|
+
if (customRegistry) {
|
|
105
|
+
log.warn(
|
|
106
|
+
`Found existing default registry: ${customRegistry.trim()}`,
|
|
107
|
+
);
|
|
108
|
+
log.warn("Using --scoped mode to avoid overriding it.");
|
|
109
|
+
useScoped = true;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
npmrcContent = removeLpmLines(existingContent);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const registryLine = useScoped
|
|
117
|
+
? `@lpm.dev:registry=${fullRegistryUrl}`
|
|
118
|
+
: `registry=${fullRegistryUrl}`;
|
|
119
|
+
|
|
120
|
+
const lpmConfig = `# LPM Registry (OIDC — expires in 30 minutes)
|
|
119
121
|
${registryLine}
|
|
120
|
-
${registryHost}/:_authToken=${oidcToken}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
122
|
+
${registryHost}/:_authToken=${oidcToken}`;
|
|
123
|
+
|
|
124
|
+
npmrcContent = npmrcContent
|
|
125
|
+
? `${npmrcContent}\n\n${lpmConfig}`
|
|
126
|
+
: lpmConfig;
|
|
127
|
+
fs.writeFileSync(npmrcPath, `${npmrcContent}\n`);
|
|
128
|
+
|
|
129
|
+
p.note(
|
|
130
|
+
`${registryLine}\nToken: OIDC read-only (30 min)`,
|
|
131
|
+
".npmrc configuration",
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
console.log("");
|
|
135
|
+
log.success(".npmrc configured with OIDC read-only token.");
|
|
136
|
+
log.info("Token expires in 30 minutes. No LPM_TOKEN secret needed.");
|
|
137
|
+
if (!useScoped) {
|
|
138
|
+
log.info("All packages (LPM + npm) will route through lpm.dev.");
|
|
139
|
+
}
|
|
140
|
+
console.log("");
|
|
141
|
+
|
|
142
|
+
p.outro("Setup complete!");
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ── Default mode: ${LPM_TOKEN} placeholder ──
|
|
148
|
+
|
|
149
|
+
// Check for existing .npmrc
|
|
150
|
+
let npmrcContent = "";
|
|
151
|
+
if (fs.existsSync(npmrcPath)) {
|
|
152
|
+
npmrcContent = fs.readFileSync(npmrcPath, "utf8");
|
|
153
|
+
|
|
154
|
+
// Detect custom default registry
|
|
155
|
+
if (!useScoped) {
|
|
156
|
+
const customRegistry = detectCustomRegistry(npmrcContent);
|
|
157
|
+
if (customRegistry) {
|
|
158
|
+
log.warn(`Found existing default registry: ${customRegistry.trim()}`);
|
|
159
|
+
log.warn("Using --scoped mode to avoid overriding it.");
|
|
160
|
+
log.warn(
|
|
161
|
+
"To use LPM as your default registry, remove the existing registry= line first.",
|
|
162
|
+
);
|
|
163
|
+
useScoped = true;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Check if already configured (both scoped and unscoped formats)
|
|
168
|
+
if (
|
|
169
|
+
npmrcContent.includes("@lpm.dev:registry") ||
|
|
170
|
+
npmrcContent.match(/^registry=.*lpm\.dev/m)
|
|
171
|
+
) {
|
|
172
|
+
const overwrite = await p.confirm({
|
|
173
|
+
message: ".npmrc already has LPM configuration. Overwrite?",
|
|
174
|
+
initialValue: false,
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
if (p.isCancel(overwrite) || !overwrite) {
|
|
178
|
+
p.outro("Setup cancelled.");
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
npmrcContent = removeLpmLines(npmrcContent);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const registryLine = useScoped
|
|
187
|
+
? `@lpm.dev:registry=${fullRegistryUrl}`
|
|
188
|
+
: `registry=${fullRegistryUrl}`;
|
|
189
|
+
|
|
190
|
+
// Add LPM registry config with placeholder
|
|
191
|
+
const lpmConfig = `
|
|
190
192
|
# LPM Registry
|
|
191
193
|
${registryLine}
|
|
192
194
|
${registryHost}/:_authToken=\${LPM_TOKEN}
|
|
193
|
-
`.trim()
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
195
|
+
`.trim();
|
|
196
|
+
|
|
197
|
+
npmrcContent = npmrcContent ? `${npmrcContent}\n\n${lpmConfig}` : lpmConfig;
|
|
198
|
+
fs.writeFileSync(npmrcPath, `${npmrcContent}\n`);
|
|
199
|
+
|
|
200
|
+
p.note(
|
|
201
|
+
`${registryLine}\n${registryHost}/:_authToken=\${LPM_TOKEN}`,
|
|
202
|
+
".npmrc configuration",
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
console.log("");
|
|
206
|
+
log.success(".npmrc configured for LPM registry.");
|
|
207
|
+
if (useScoped) {
|
|
208
|
+
log.info("Only @lpm.dev packages will route through lpm.dev.");
|
|
209
|
+
} else {
|
|
210
|
+
log.info("All packages (LPM + npm) will route through lpm.dev.");
|
|
211
|
+
log.info("Note: First install may update resolved URLs in your lockfile.");
|
|
212
|
+
}
|
|
213
|
+
log.info("For local development: Run `lpm setup local` to generate a token.");
|
|
214
|
+
log.info("For CI/CD: Set the LPM_TOKEN environment variable.");
|
|
215
|
+
log.info(
|
|
216
|
+
"For CI/CD with OIDC: Run `lpm setup ci --oidc` (no secrets needed).",
|
|
217
|
+
);
|
|
218
|
+
console.log("");
|
|
219
|
+
|
|
220
|
+
p.outro("Setup complete!");
|
|
217
221
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lpm-registry/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.48.2",
|
|
4
4
|
"description": "CLI for Licensed Package Manager",
|
|
5
5
|
"author": "LPM <hello@lpm.dev> (https://lpm.dev)",
|
|
6
6
|
"repository": {
|
|
@@ -62,11 +62,11 @@
|
|
|
62
62
|
"xcode": "^3.0.1"
|
|
63
63
|
},
|
|
64
64
|
"optionalDependencies": {
|
|
65
|
-
"@lpm-registry/cli-darwin-arm64": "0.
|
|
66
|
-
"@lpm-registry/cli-darwin-x64": "0.
|
|
67
|
-
"@lpm-registry/cli-linux-x64": "0.
|
|
68
|
-
"@lpm-registry/cli-linux-arm64": "0.
|
|
69
|
-
"@lpm-registry/cli-win32-x64": "0.
|
|
65
|
+
"@lpm-registry/cli-darwin-arm64": "0.48.2",
|
|
66
|
+
"@lpm-registry/cli-darwin-x64": "0.48.2",
|
|
67
|
+
"@lpm-registry/cli-linux-x64": "0.48.2",
|
|
68
|
+
"@lpm-registry/cli-linux-arm64": "0.48.2",
|
|
69
|
+
"@lpm-registry/cli-win32-x64": "0.48.2",
|
|
70
70
|
"keytar": "^7.9.0",
|
|
71
71
|
"sigstore": "^3.0.0"
|
|
72
72
|
},
|