@pnpm/registry-access.commands 1100.3.7 → 1100.4.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/CHANGELOG.md +430 -0
- package/lib/access.d.ts +16 -0
- package/lib/access.js +496 -0
- package/lib/index.d.ts +2 -1
- package/lib/index.js +2 -1
- package/package.json +17 -17
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
# @pnpm/registry-access.commands
|
|
2
|
+
|
|
3
|
+
## 1100.4.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- @pnpm/config.reader@1101.11.2
|
|
8
|
+
|
|
9
|
+
## 1100.4.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 508b8c2: Added the `pnpm access` command for managing package access and visibility on the registry, supporting listing packages and collaborators, getting and setting package status and MFA requirements, and granting or revoking team access.
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- Updated dependencies [9318a11]
|
|
18
|
+
- Updated dependencies [5a4daec]
|
|
19
|
+
- @pnpm/config.reader@1101.11.1
|
|
20
|
+
|
|
21
|
+
## 1100.3.7
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- Updated dependencies [3425e80]
|
|
26
|
+
- Updated dependencies [806c3ec]
|
|
27
|
+
- Updated dependencies [c121235]
|
|
28
|
+
- Updated dependencies [1e81761]
|
|
29
|
+
- @pnpm/config.reader@1101.11.0
|
|
30
|
+
- @pnpm/network.web-auth@1101.2.0
|
|
31
|
+
- @pnpm/registry-access.client@1100.1.6
|
|
32
|
+
|
|
33
|
+
## 1100.3.6
|
|
34
|
+
|
|
35
|
+
### Patch Changes
|
|
36
|
+
|
|
37
|
+
- Updated dependencies [05b95ab]
|
|
38
|
+
- Updated dependencies [852d537]
|
|
39
|
+
- @pnpm/network.fetch@1100.1.4
|
|
40
|
+
- @pnpm/error@1100.0.1
|
|
41
|
+
- @pnpm/registry-access.client@1100.1.5
|
|
42
|
+
- @pnpm/cli.utils@1101.0.13
|
|
43
|
+
- @pnpm/config.reader@1101.10.1
|
|
44
|
+
- @pnpm/network.auth-header@1101.1.3
|
|
45
|
+
- @pnpm/network.web-auth@1101.1.2
|
|
46
|
+
|
|
47
|
+
## 1100.3.5
|
|
48
|
+
|
|
49
|
+
### Patch Changes
|
|
50
|
+
|
|
51
|
+
- Updated dependencies [302a2f7]
|
|
52
|
+
- Updated dependencies [0474a9c]
|
|
53
|
+
- @pnpm/config.reader@1101.10.0
|
|
54
|
+
|
|
55
|
+
## 1100.3.4
|
|
56
|
+
|
|
57
|
+
### Patch Changes
|
|
58
|
+
|
|
59
|
+
- a31faa7: Updated dependency ranges. Notably:
|
|
60
|
+
|
|
61
|
+
- `@pnpm/logger` peer dependency range moved to `^1100.0.0`.
|
|
62
|
+
- `msgpackr` 1.11.8 → 2.0.4 (store index files remain byte-compatible in both directions).
|
|
63
|
+
- `open` ^7.4.2 → ^11.0.0, `memoize` ^10 → ^11, `cli-truncate` ^5 → ^6, `pidtree` ^0.6 → ^1.
|
|
64
|
+
- `@yarnpkg/core` 4.5.0 → 4.8.0, `@rushstack/worker-pool` 0.7.7 → 0.7.18, `@cyclonedx/cyclonedx-library` 10.0.0 → 10.1.0, `@pnpm/config.nerf-dart` ^1 → ^2, `@pnpm/log.group` 3.0.2 → 4.0.1, `@pnpm/util.lex-comparator` ^3 → ^4.
|
|
65
|
+
|
|
66
|
+
- Updated dependencies [61810aa]
|
|
67
|
+
- Updated dependencies [681b593]
|
|
68
|
+
- Updated dependencies [a31faa7]
|
|
69
|
+
- @pnpm/config.reader@1101.9.0
|
|
70
|
+
- @pnpm/network.auth-header@1101.1.2
|
|
71
|
+
- @pnpm/types@1101.3.2
|
|
72
|
+
- @pnpm/cli.utils@1101.0.12
|
|
73
|
+
- @pnpm/network.fetch@1100.1.3
|
|
74
|
+
- @pnpm/network.web-auth@1101.1.1
|
|
75
|
+
- @pnpm/config.pick-registry-for-package@1100.0.9
|
|
76
|
+
- @pnpm/resolving.registry.types@1100.1.3
|
|
77
|
+
- @pnpm/registry-access.client@1100.1.4
|
|
78
|
+
|
|
79
|
+
## 1100.3.3
|
|
80
|
+
|
|
81
|
+
### Patch Changes
|
|
82
|
+
|
|
83
|
+
- Updated dependencies [bc9ed78]
|
|
84
|
+
- Updated dependencies [615c669]
|
|
85
|
+
- @pnpm/config.reader@1101.8.0
|
|
86
|
+
- @pnpm/network.fetch@1100.1.2
|
|
87
|
+
- @pnpm/cli.utils@1101.0.11
|
|
88
|
+
- @pnpm/registry-access.client@1100.1.3
|
|
89
|
+
|
|
90
|
+
## 1100.3.2
|
|
91
|
+
|
|
92
|
+
### Patch Changes
|
|
93
|
+
|
|
94
|
+
- Updated dependencies [822beb5]
|
|
95
|
+
- Updated dependencies [3537020]
|
|
96
|
+
- Updated dependencies [894ea6a]
|
|
97
|
+
- Updated dependencies [6b5d91a]
|
|
98
|
+
- Updated dependencies [027196b]
|
|
99
|
+
- Updated dependencies [1017c36]
|
|
100
|
+
- Updated dependencies [bf1b731]
|
|
101
|
+
- @pnpm/config.reader@1101.7.0
|
|
102
|
+
- @pnpm/types@1101.3.1
|
|
103
|
+
- @pnpm/cli.utils@1101.0.10
|
|
104
|
+
- @pnpm/config.pick-registry-for-package@1100.0.8
|
|
105
|
+
- @pnpm/network.auth-header@1101.1.1
|
|
106
|
+
- @pnpm/network.fetch@1100.1.1
|
|
107
|
+
- @pnpm/resolving.registry.types@1100.1.2
|
|
108
|
+
- @pnpm/registry-access.client@1100.1.2
|
|
109
|
+
|
|
110
|
+
## 1100.3.1
|
|
111
|
+
|
|
112
|
+
### Patch Changes
|
|
113
|
+
|
|
114
|
+
- Updated dependencies [60a1eec]
|
|
115
|
+
- Updated dependencies [5192edf]
|
|
116
|
+
- Updated dependencies [a017bf3]
|
|
117
|
+
- @pnpm/network.fetch@1100.1.0
|
|
118
|
+
- @pnpm/network.auth-header@1101.1.0
|
|
119
|
+
- @pnpm/config.reader@1101.6.0
|
|
120
|
+
- @pnpm/types@1101.3.0
|
|
121
|
+
- @pnpm/registry-access.client@1100.1.1
|
|
122
|
+
- @pnpm/cli.utils@1101.0.9
|
|
123
|
+
- @pnpm/config.pick-registry-for-package@1100.0.7
|
|
124
|
+
- @pnpm/resolving.registry.types@1100.1.1
|
|
125
|
+
|
|
126
|
+
## 1100.3.0
|
|
127
|
+
|
|
128
|
+
### Minor Changes
|
|
129
|
+
|
|
130
|
+
- 2cadfb5: Replaced `enquirer` with `@inquirer/prompts` for all interactive prompts. Fixes the `update -i` scrolling overflow bug where long choice lists were clipped in the terminal [#6643](https://github.com/pnpm/pnpm/issues/6643).
|
|
131
|
+
|
|
132
|
+
**User-facing changes:**
|
|
133
|
+
|
|
134
|
+
- `pnpm update -i` / `pnpm update -i --latest`: Scrolling now works correctly when many packages are available; the new library uses visual-line-aware pagination via `usePagination`
|
|
135
|
+
- `pnpm audit --fix -i`: Same scrolling fix for vulnerability selection
|
|
136
|
+
- `pnpm approve-builds`: Interactive build approval prompts updated
|
|
137
|
+
- `pnpm patch`: Version selection and "apply to all" prompts updated
|
|
138
|
+
- `pnpm patch-remove`: Patch removal selection updated
|
|
139
|
+
- `pnpm publish`: Branch confirmation prompt updated
|
|
140
|
+
- `pnpm login`: Credential prompts updated
|
|
141
|
+
- `pnpm run` / `pnpm exec` (with `verifyDepsBeforeRun=prompt`): Confirmation prompt updated
|
|
142
|
+
|
|
143
|
+
Vim-style `j`/`k` keys still work for up/down navigation in all interactive prompts.
|
|
144
|
+
|
|
145
|
+
**Internal:** The `OtpEnquirer` and `LoginEnquirer` DI interfaces changed from `{ prompt }` to `{ input }` / `{ input, password }` respectively. Plugins or custom builds that inject their own enquirer mock will need to update.
|
|
146
|
+
|
|
147
|
+
### Patch Changes
|
|
148
|
+
|
|
149
|
+
- b1fa2d5: Fix `pnpm dist-tag add` and `pnpm dist-tag rm` against npmjs.org failing without `--otp` with `[ERR_PNPM_UNAUTHORIZED] You must be logged in to set dist-tag … "You must provide a one-time pass. Upgrade your client to npm@latest in order to use 2FA."`. pnpm now sends `npm-auth-type: web` on dist-tag writes and surfaces the resulting OTP challenge through the existing browser-based 2FA flow (the same `withOtpHandling` helper used by `pnpm publish`), so the browser opens, the user authenticates, and the dist-tag is set on retry. `--otp=<code>` continues to work via the classic flow.
|
|
150
|
+
- Updated dependencies [b1fa2d5]
|
|
151
|
+
- Updated dependencies [a39a83d]
|
|
152
|
+
- Updated dependencies [2cadfb5]
|
|
153
|
+
- Updated dependencies [1e9ab29]
|
|
154
|
+
- @pnpm/registry-access.client@1100.1.0
|
|
155
|
+
- @pnpm/network.fetch@1100.0.8
|
|
156
|
+
- @pnpm/config.reader@1101.5.0
|
|
157
|
+
- @pnpm/network.web-auth@1101.1.0
|
|
158
|
+
- @pnpm/resolving.registry.types@1100.1.0
|
|
159
|
+
|
|
160
|
+
## 1100.2.16
|
|
161
|
+
|
|
162
|
+
### Patch Changes
|
|
163
|
+
|
|
164
|
+
- ae21758: Refactor the dist-tag-add and login (classic adduser) handlers to delegate their PUTs to a new shared package `@pnpm/registry-access.client`. Downstream tests in this monorepo now use these helpers (via `@pnpm/testing.registry-mock`) instead of `addDistTag` / `addUser` from `@pnpm/registry-mock`, which relied on the unmaintained `anonymous-npm-registry-client`.
|
|
165
|
+
- Updated dependencies [a23956e]
|
|
166
|
+
- Updated dependencies [35d2355]
|
|
167
|
+
- @pnpm/config.reader@1101.4.1
|
|
168
|
+
- @pnpm/network.auth-header@1101.0.0
|
|
169
|
+
- @pnpm/types@1101.2.0
|
|
170
|
+
- @pnpm/cli.utils@1101.0.8
|
|
171
|
+
- @pnpm/config.pick-registry-for-package@1100.0.6
|
|
172
|
+
- @pnpm/network.fetch@1100.0.7
|
|
173
|
+
- @pnpm/resolving.registry.types@1100.0.5
|
|
174
|
+
- @pnpm/registry-access.client@1100.0.1
|
|
175
|
+
|
|
176
|
+
## 1100.2.15
|
|
177
|
+
|
|
178
|
+
### Patch Changes
|
|
179
|
+
|
|
180
|
+
- Updated dependencies [3b62f9d]
|
|
181
|
+
- Updated dependencies [212315d]
|
|
182
|
+
- @pnpm/config.reader@1101.4.0
|
|
183
|
+
- @pnpm/cli.utils@1101.0.7
|
|
184
|
+
|
|
185
|
+
## 1100.2.14
|
|
186
|
+
|
|
187
|
+
### Patch Changes
|
|
188
|
+
|
|
189
|
+
- Updated dependencies [097983f]
|
|
190
|
+
- @pnpm/config.pick-registry-for-package@1100.0.5
|
|
191
|
+
|
|
192
|
+
## 1100.2.13
|
|
193
|
+
|
|
194
|
+
### Patch Changes
|
|
195
|
+
|
|
196
|
+
- d1b340f: Fixed `pnpm login` and `pnpm logout` ignoring `registries.default` from `pnpm-workspace.yaml` [#10099](https://github.com/pnpm/pnpm/issues/10099).
|
|
197
|
+
- Updated dependencies [3687b0e]
|
|
198
|
+
- Updated dependencies [ced20cb]
|
|
199
|
+
- Updated dependencies [d1b340f]
|
|
200
|
+
- Updated dependencies [64afc92]
|
|
201
|
+
- @pnpm/config.reader@1101.3.3
|
|
202
|
+
- @pnpm/types@1101.1.1
|
|
203
|
+
- @pnpm/cli.utils@1101.0.6
|
|
204
|
+
- @pnpm/config.pick-registry-for-package@1100.0.4
|
|
205
|
+
- @pnpm/network.auth-header@1100.0.3
|
|
206
|
+
- @pnpm/network.fetch@1100.0.6
|
|
207
|
+
- @pnpm/resolving.registry.types@1100.0.4
|
|
208
|
+
|
|
209
|
+
## 1100.2.12
|
|
210
|
+
|
|
211
|
+
### Patch Changes
|
|
212
|
+
|
|
213
|
+
- Updated dependencies [020ac45]
|
|
214
|
+
- Updated dependencies [d3f8408]
|
|
215
|
+
- Updated dependencies [a62f959]
|
|
216
|
+
- Updated dependencies [ba2c884]
|
|
217
|
+
- Updated dependencies [8df408c]
|
|
218
|
+
- @pnpm/config.reader@1101.3.2
|
|
219
|
+
- @pnpm/network.fetch@1100.0.5
|
|
220
|
+
- @pnpm/cli.utils@1101.0.5
|
|
221
|
+
|
|
222
|
+
## 1100.2.11
|
|
223
|
+
|
|
224
|
+
### Patch Changes
|
|
225
|
+
|
|
226
|
+
- Updated dependencies [18a464f]
|
|
227
|
+
- @pnpm/network.fetch@1100.0.4
|
|
228
|
+
- @pnpm/cli.utils@1101.0.4
|
|
229
|
+
- @pnpm/config.reader@1101.3.1
|
|
230
|
+
|
|
231
|
+
## 1100.2.10
|
|
232
|
+
|
|
233
|
+
### Patch Changes
|
|
234
|
+
|
|
235
|
+
- 601317e: Added `pnpm owner` command to manage package owners on the registry.
|
|
236
|
+
- Updated dependencies [20e7aff]
|
|
237
|
+
- Updated dependencies [b61e268]
|
|
238
|
+
- Updated dependencies [e1e29c1]
|
|
239
|
+
- @pnpm/network.fetch@1100.0.3
|
|
240
|
+
- @pnpm/config.reader@1101.3.0
|
|
241
|
+
- @pnpm/types@1101.1.0
|
|
242
|
+
- @pnpm/cli.utils@1101.0.3
|
|
243
|
+
- @pnpm/config.pick-registry-for-package@1100.0.3
|
|
244
|
+
- @pnpm/network.auth-header@1100.0.2
|
|
245
|
+
- @pnpm/resolving.registry.types@1100.0.3
|
|
246
|
+
|
|
247
|
+
## 1100.2.9
|
|
248
|
+
|
|
249
|
+
### Patch Changes
|
|
250
|
+
|
|
251
|
+
- Updated dependencies [e9e876c]
|
|
252
|
+
- @pnpm/config.reader@1101.2.2
|
|
253
|
+
|
|
254
|
+
## 1100.2.8
|
|
255
|
+
|
|
256
|
+
### Patch Changes
|
|
257
|
+
|
|
258
|
+
- Updated dependencies [707a879]
|
|
259
|
+
- @pnpm/config.reader@1101.2.1
|
|
260
|
+
|
|
261
|
+
## 1100.2.7
|
|
262
|
+
|
|
263
|
+
### Patch Changes
|
|
264
|
+
|
|
265
|
+
- Updated dependencies [8fdd9a9]
|
|
266
|
+
- Updated dependencies [5f34a8d]
|
|
267
|
+
- Updated dependencies [c969392]
|
|
268
|
+
- Updated dependencies [817b1b4]
|
|
269
|
+
- Updated dependencies [c969392]
|
|
270
|
+
- Updated dependencies [2de318b]
|
|
271
|
+
- @pnpm/config.reader@1101.2.0
|
|
272
|
+
|
|
273
|
+
## 1100.2.6
|
|
274
|
+
|
|
275
|
+
### Patch Changes
|
|
276
|
+
|
|
277
|
+
- Updated dependencies [42a8f29]
|
|
278
|
+
- @pnpm/config.reader@1101.1.4
|
|
279
|
+
|
|
280
|
+
## 1100.2.5
|
|
281
|
+
|
|
282
|
+
### Patch Changes
|
|
283
|
+
|
|
284
|
+
- Updated dependencies [184ce26]
|
|
285
|
+
- @pnpm/config.pick-registry-for-package@1100.0.2
|
|
286
|
+
- @pnpm/resolving.registry.types@1100.0.2
|
|
287
|
+
- @pnpm/config.reader@1101.1.3
|
|
288
|
+
- @pnpm/network.fetch@1100.0.2
|
|
289
|
+
- @pnpm/cli.utils@1101.0.2
|
|
290
|
+
|
|
291
|
+
## 1100.2.4
|
|
292
|
+
|
|
293
|
+
### Patch Changes
|
|
294
|
+
|
|
295
|
+
- @pnpm/cli.utils@1101.0.1
|
|
296
|
+
|
|
297
|
+
## 1100.2.3
|
|
298
|
+
|
|
299
|
+
### Patch Changes
|
|
300
|
+
|
|
301
|
+
- Updated dependencies [0fbcf74]
|
|
302
|
+
- @pnpm/config.reader@1101.1.2
|
|
303
|
+
|
|
304
|
+
## 1100.2.2
|
|
305
|
+
|
|
306
|
+
### Patch Changes
|
|
307
|
+
|
|
308
|
+
- @pnpm/config.reader@1101.1.1
|
|
309
|
+
|
|
310
|
+
## 1100.2.1
|
|
311
|
+
|
|
312
|
+
### Patch Changes
|
|
313
|
+
|
|
314
|
+
- Updated dependencies [7d25bc1]
|
|
315
|
+
- Updated dependencies [9e0833c]
|
|
316
|
+
- @pnpm/config.reader@1101.1.0
|
|
317
|
+
|
|
318
|
+
## 1100.2.0
|
|
319
|
+
|
|
320
|
+
### Minor Changes
|
|
321
|
+
|
|
322
|
+
- 75942bf: Implemented native `star`, `unstar`, `stars`, and `whoami` commands.
|
|
323
|
+
|
|
324
|
+
### Patch Changes
|
|
325
|
+
|
|
326
|
+
- Updated dependencies [cee550a]
|
|
327
|
+
- Updated dependencies [4ab3d9b]
|
|
328
|
+
- Updated dependencies [9af708a]
|
|
329
|
+
- Updated dependencies [ea2a7fb]
|
|
330
|
+
- Updated dependencies [ff7733c]
|
|
331
|
+
- @pnpm/cli.utils@1101.0.0
|
|
332
|
+
- @pnpm/config.reader@1101.0.0
|
|
333
|
+
|
|
334
|
+
## 1100.1.0
|
|
335
|
+
|
|
336
|
+
### Minor Changes
|
|
337
|
+
|
|
338
|
+
- b738043: Add native `pnpm ping` command to test registry connectivity.
|
|
339
|
+
Provides a simple way to verify connectivity to the configured registry without requiring external tools.
|
|
340
|
+
- f2083f4: Implemented native `search` command and its aliases (`s`, `se`, `find`).
|
|
341
|
+
|
|
342
|
+
### Patch Changes
|
|
343
|
+
|
|
344
|
+
- Updated dependencies [ff28085]
|
|
345
|
+
- @pnpm/types@1101.0.0
|
|
346
|
+
- @pnpm/cli.utils@1100.0.1
|
|
347
|
+
- @pnpm/config.pick-registry-for-package@1100.0.1
|
|
348
|
+
- @pnpm/config.reader@1100.0.1
|
|
349
|
+
- @pnpm/network.auth-header@1100.0.1
|
|
350
|
+
- @pnpm/network.fetch@1100.0.1
|
|
351
|
+
- @pnpm/resolving.registry.types@1100.0.1
|
|
352
|
+
|
|
353
|
+
## 1000.1.0
|
|
354
|
+
|
|
355
|
+
### Minor Changes
|
|
356
|
+
|
|
357
|
+
- 853be66: Added native `pnpm dist-tag` command with `ls`, `add`, and `rm` subcommands [#11128](https://github.com/pnpm/pnpm/issues/11128).
|
|
358
|
+
- 2c90d40: Added native `pnpm deprecate` and `pnpm undeprecate` commands that interact with the npm registry directly instead of delegating to the npm CLI [#11120](https://github.com/pnpm/pnpm/pull/11120).
|
|
359
|
+
|
|
360
|
+
### Patch Changes
|
|
361
|
+
|
|
362
|
+
- Updated dependencies [7730a7f]
|
|
363
|
+
- Updated dependencies [ae8b816]
|
|
364
|
+
- Updated dependencies [facdd71]
|
|
365
|
+
- Updated dependencies [3c72b6b]
|
|
366
|
+
- Updated dependencies [9f5c0e3]
|
|
367
|
+
- Updated dependencies [76718b3]
|
|
368
|
+
- Updated dependencies [a8f016c]
|
|
369
|
+
- Updated dependencies [cc1b8e3]
|
|
370
|
+
- Updated dependencies [90bd3c3]
|
|
371
|
+
- Updated dependencies [1cc61e8]
|
|
372
|
+
- Updated dependencies [606f53e]
|
|
373
|
+
- Updated dependencies [c7203b9]
|
|
374
|
+
- Updated dependencies [bb17724]
|
|
375
|
+
- Updated dependencies [da2429d]
|
|
376
|
+
- Updated dependencies [1cc61e8]
|
|
377
|
+
- Updated dependencies [491a84f]
|
|
378
|
+
- Updated dependencies [fb8962f]
|
|
379
|
+
- Updated dependencies [f0ae1b9]
|
|
380
|
+
- Updated dependencies [b1ad9c7]
|
|
381
|
+
- Updated dependencies [0dfa8b8]
|
|
382
|
+
- Updated dependencies [7fab2a2]
|
|
383
|
+
- Updated dependencies [cb367b9]
|
|
384
|
+
- Updated dependencies [543c7e4]
|
|
385
|
+
- Updated dependencies [075aa99]
|
|
386
|
+
- Updated dependencies [ae43ac7]
|
|
387
|
+
- Updated dependencies [ccec8e7]
|
|
388
|
+
- Updated dependencies [4158906]
|
|
389
|
+
- Updated dependencies [ac944ef]
|
|
390
|
+
- Updated dependencies [d3d6938]
|
|
391
|
+
- Updated dependencies [7d2fd48]
|
|
392
|
+
- Updated dependencies [cc7c0d2]
|
|
393
|
+
- Updated dependencies [efb48dc]
|
|
394
|
+
- Updated dependencies [d5d4eed]
|
|
395
|
+
- Updated dependencies [095f659]
|
|
396
|
+
- Updated dependencies [96704a1]
|
|
397
|
+
- Updated dependencies [bb8baa7]
|
|
398
|
+
- Updated dependencies [cb367b9]
|
|
399
|
+
- Updated dependencies [7b1c189]
|
|
400
|
+
- Updated dependencies [51b04c3]
|
|
401
|
+
- Updated dependencies [6c480a4]
|
|
402
|
+
- Updated dependencies [d01b81f]
|
|
403
|
+
- Updated dependencies [3ed41f4]
|
|
404
|
+
- Updated dependencies [8ffb1a7]
|
|
405
|
+
- Updated dependencies [05fb1ae]
|
|
406
|
+
- Updated dependencies [71de2b3]
|
|
407
|
+
- Updated dependencies [10bc391]
|
|
408
|
+
- Updated dependencies [831f574]
|
|
409
|
+
- Updated dependencies [2df8b71]
|
|
410
|
+
- Updated dependencies [ed1a7fe]
|
|
411
|
+
- Updated dependencies [15549a9]
|
|
412
|
+
- Updated dependencies [cc7c0d2]
|
|
413
|
+
- Updated dependencies [5bf7768]
|
|
414
|
+
- Updated dependencies [ae43ac7]
|
|
415
|
+
- Updated dependencies [a5fdbf9]
|
|
416
|
+
- Updated dependencies [9d3f00b]
|
|
417
|
+
- Updated dependencies [efb48dc]
|
|
418
|
+
- Updated dependencies [6b3d87a]
|
|
419
|
+
- Updated dependencies [9587dac]
|
|
420
|
+
- Updated dependencies [09a999a]
|
|
421
|
+
- Updated dependencies [559f903]
|
|
422
|
+
- Updated dependencies [3574905]
|
|
423
|
+
- @pnpm/config.reader@1005.0.0
|
|
424
|
+
- @pnpm/types@1001.0.0
|
|
425
|
+
- @pnpm/cli.utils@1002.0.0
|
|
426
|
+
- @pnpm/config.pick-registry-for-package@1001.0.0
|
|
427
|
+
- @pnpm/network.auth-header@1001.0.0
|
|
428
|
+
- @pnpm/error@1001.0.0
|
|
429
|
+
- @pnpm/network.fetch@1001.0.0
|
|
430
|
+
- @pnpm/resolving.registry.types@1000.1.0
|
package/lib/access.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type CreateFetchFromRegistryOptions } from '@pnpm/network.fetch';
|
|
2
|
+
import type { Registries, RegistryConfig } from '@pnpm/types';
|
|
3
|
+
import { rcOptionsTypes } from './common.js';
|
|
4
|
+
export { rcOptionsTypes };
|
|
5
|
+
export declare function cliOptionsTypes(): Record<string, unknown>;
|
|
6
|
+
export declare const commandNames: string[];
|
|
7
|
+
export declare function help(): string;
|
|
8
|
+
export interface AccessOptions extends CreateFetchFromRegistryOptions {
|
|
9
|
+
cliOptions?: {
|
|
10
|
+
json?: boolean;
|
|
11
|
+
otp?: string;
|
|
12
|
+
};
|
|
13
|
+
configByUri?: Record<string, RegistryConfig>;
|
|
14
|
+
registries?: Registries;
|
|
15
|
+
}
|
|
16
|
+
export declare function handler(opts: AccessOptions, params: string[]): Promise<string>;
|
package/lib/access.js
ADDED
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
import { docsUrl } from '@pnpm/cli.utils';
|
|
2
|
+
import { pickRegistryForPackage } from '@pnpm/config.pick-registry-for-package';
|
|
3
|
+
import { PnpmError } from '@pnpm/error';
|
|
4
|
+
import { createGetAuthHeaderByURI } from '@pnpm/network.auth-header';
|
|
5
|
+
import { createFetchFromRegistry } from '@pnpm/network.fetch';
|
|
6
|
+
import npa from '@pnpm/npm-package-arg';
|
|
7
|
+
import { renderHelp } from 'render-help';
|
|
8
|
+
import { normalizeRegistryUrl, rcOptionsTypes } from './common.js';
|
|
9
|
+
export { rcOptionsTypes };
|
|
10
|
+
const DEFAULT_REGISTRY_URL = 'https://registry.npmjs.org/';
|
|
11
|
+
const ERROR_BODY_LIMIT = 64 * 1024;
|
|
12
|
+
function getRegistries(opts) {
|
|
13
|
+
return opts.registries ?? { default: DEFAULT_REGISTRY_URL };
|
|
14
|
+
}
|
|
15
|
+
export function cliOptionsTypes() {
|
|
16
|
+
return {
|
|
17
|
+
...rcOptionsTypes(),
|
|
18
|
+
json: Boolean,
|
|
19
|
+
otp: String,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export const commandNames = ['access'];
|
|
23
|
+
export function help() {
|
|
24
|
+
return renderHelp({
|
|
25
|
+
description: 'Manages package access and visibility on the registry.',
|
|
26
|
+
descriptionLists: [
|
|
27
|
+
{
|
|
28
|
+
title: 'Commands',
|
|
29
|
+
list: [
|
|
30
|
+
{
|
|
31
|
+
description: 'List packages a user, scope, or team can access.',
|
|
32
|
+
name: 'list packages',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
description: 'List collaborators on a package.',
|
|
36
|
+
name: 'list collaborators',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
description: 'Get the public/restricted status of a package.',
|
|
40
|
+
name: 'get status',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
description: 'Set the package visibility (public/private).',
|
|
44
|
+
name: 'set status',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
description: 'Set the 2FA requirement for a package (none/publish/automation).',
|
|
48
|
+
name: 'set mfa',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
description: 'Grant read-only or read-write access to a team.',
|
|
52
|
+
name: 'grant',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
description: 'Revoke a team\'s access to a package.',
|
|
56
|
+
name: 'revoke',
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
title: 'Options',
|
|
62
|
+
list: [
|
|
63
|
+
{
|
|
64
|
+
description: 'The base URL of the npm registry.',
|
|
65
|
+
name: '--registry <url>',
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
description: 'Output results in JSON format.',
|
|
69
|
+
name: '--json',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
description: 'One-time password for registries that require two-factor authentication.',
|
|
73
|
+
name: '--otp',
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
url: docsUrl('access'),
|
|
79
|
+
usages: [
|
|
80
|
+
'pnpm access list packages [<user>|<scope>|<scope:team>]',
|
|
81
|
+
'pnpm access list collaborators [<package> [<user>]]',
|
|
82
|
+
'pnpm access get status [<package>]',
|
|
83
|
+
'pnpm access set status=public|private [<package>]',
|
|
84
|
+
'pnpm access set mfa=none|publish|automation [<package>]',
|
|
85
|
+
'pnpm access grant <read-only|read-write> <scope:team> [<package>]',
|
|
86
|
+
'pnpm access revoke <scope:team> [<package>]',
|
|
87
|
+
],
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
export async function handler(opts, params) {
|
|
91
|
+
if (params.length === 0) {
|
|
92
|
+
throw new PnpmError('ACCESS_SUBCOMMAND_REQUIRED', 'A subcommand is required (e.g., "list packages", "get status", "set status=public", "grant", "revoke")');
|
|
93
|
+
}
|
|
94
|
+
const first = params[0];
|
|
95
|
+
const second = params[1];
|
|
96
|
+
if (first === 'list' && second === 'packages') {
|
|
97
|
+
return listPackages(opts, params.slice(2));
|
|
98
|
+
}
|
|
99
|
+
if (first === 'list' && second === 'collaborators') {
|
|
100
|
+
return listCollaborators(opts, params.slice(2));
|
|
101
|
+
}
|
|
102
|
+
if (first === 'ls' && (second == null || second === 'packages')) {
|
|
103
|
+
return listPackages(opts, second === 'packages' ? params.slice(2) : params.slice(1));
|
|
104
|
+
}
|
|
105
|
+
if (first === 'get' && second === 'status') {
|
|
106
|
+
return getStatus(opts, params.slice(2));
|
|
107
|
+
}
|
|
108
|
+
if (first === 'set') {
|
|
109
|
+
if (second == null) {
|
|
110
|
+
throw new PnpmError('ACCESS_SET_REQUIRED', 'A value is required (e.g., "status=public" or "mfa=none")');
|
|
111
|
+
}
|
|
112
|
+
if (second.startsWith('status=')) {
|
|
113
|
+
return setStatus(opts, params.slice(1));
|
|
114
|
+
}
|
|
115
|
+
if (second.startsWith('mfa=')) {
|
|
116
|
+
return setMfa(opts, params.slice(1));
|
|
117
|
+
}
|
|
118
|
+
throw new PnpmError('ACCESS_SET_INVALID', `Unknown set parameter "${second}". Use "status=public|private" or "mfa=none|publish|automation".`);
|
|
119
|
+
}
|
|
120
|
+
if (first === 'grant') {
|
|
121
|
+
return grantAccess(opts, params.slice(1));
|
|
122
|
+
}
|
|
123
|
+
if (first === 'revoke') {
|
|
124
|
+
return revokeAccess(opts, params.slice(1));
|
|
125
|
+
}
|
|
126
|
+
// Handle deprecated npm access forms: public/restricted
|
|
127
|
+
if (first === 'public') {
|
|
128
|
+
return setStatus(opts, ['status=public', ...params.slice(1)]);
|
|
129
|
+
}
|
|
130
|
+
if (first === 'restricted') {
|
|
131
|
+
return setStatus(opts, ['status=restricted', ...params.slice(1)]);
|
|
132
|
+
}
|
|
133
|
+
throw new PnpmError('ACCESS_UNKNOWN_SUBCOMMAND', `Unknown subcommand: ${params.join(' ')}. Run "pnpm help access" for available subcommands.`);
|
|
134
|
+
}
|
|
135
|
+
async function listPackages(opts, params) {
|
|
136
|
+
const registries = getRegistries(opts);
|
|
137
|
+
const fetchFromRegistry = createFetchFromRegistry(opts);
|
|
138
|
+
const authHeader = getAuthHeaderForRegistry(opts.configByUri, registries.default ?? DEFAULT_REGISTRY_URL);
|
|
139
|
+
const jsonMode = opts.cliOptions?.json ?? false;
|
|
140
|
+
const ctx = { registries, fetchFromRegistry, authHeader, jsonMode };
|
|
141
|
+
let entity;
|
|
142
|
+
let entityType;
|
|
143
|
+
if (params.length > 0) {
|
|
144
|
+
const raw = params[0];
|
|
145
|
+
if (raw.includes(':')) {
|
|
146
|
+
entityType = 'team';
|
|
147
|
+
entity = raw;
|
|
148
|
+
}
|
|
149
|
+
else if (raw.startsWith('@')) {
|
|
150
|
+
entityType = 'org';
|
|
151
|
+
entity = raw.replace(/^@/, '');
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
entityType = 'user';
|
|
155
|
+
entity = raw;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (entityType == null || entity == null) {
|
|
159
|
+
return listOwnPackages(ctx);
|
|
160
|
+
}
|
|
161
|
+
return listEntityPackages(entityType, entity, ctx);
|
|
162
|
+
}
|
|
163
|
+
async function listOwnPackages(ctx) {
|
|
164
|
+
const registryUrl = normalizeRegistryUrl(ctx.registries.default ?? DEFAULT_REGISTRY_URL);
|
|
165
|
+
const url = new URL('-/-/package?format=cli', registryUrl).href;
|
|
166
|
+
return fetchListResponse(url, ctx);
|
|
167
|
+
}
|
|
168
|
+
async function listEntityPackages(entityType, entity, ctx) {
|
|
169
|
+
const registryUrl = normalizeRegistryUrl(ctx.registries.default ?? DEFAULT_REGISTRY_URL);
|
|
170
|
+
let listUrl;
|
|
171
|
+
if (entityType === 'team') {
|
|
172
|
+
const [scope, team] = entity.split(':');
|
|
173
|
+
listUrl = new URL(`-/team/${encodeURIComponent(scope.startsWith('@') ? scope.slice(1) : scope)}/${encodeURIComponent(team)}/package?format=cli`, registryUrl).href;
|
|
174
|
+
}
|
|
175
|
+
else if (entityType === 'org') {
|
|
176
|
+
listUrl = new URL(`-/org/${encodeURIComponent(entity)}/package?format=cli`, registryUrl).href;
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
listUrl = new URL(`-/user/${encodeURIComponent(entity)}/package?format=cli`, registryUrl).href;
|
|
180
|
+
}
|
|
181
|
+
return fetchListResponse(listUrl, ctx);
|
|
182
|
+
}
|
|
183
|
+
async function fetchListResponse(url, ctx) {
|
|
184
|
+
const response = await ctx.fetchFromRegistry(url, {
|
|
185
|
+
authHeaderValue: ctx.authHeader,
|
|
186
|
+
});
|
|
187
|
+
if (!response.ok) {
|
|
188
|
+
await throwRegistryError(response, 'list packages from');
|
|
189
|
+
}
|
|
190
|
+
const data = await response.json();
|
|
191
|
+
if (ctx.jsonMode) {
|
|
192
|
+
return JSON.stringify(data, null, 2);
|
|
193
|
+
}
|
|
194
|
+
return formatPackagesList(data);
|
|
195
|
+
}
|
|
196
|
+
function formatPackagesList(data) {
|
|
197
|
+
const lines = [];
|
|
198
|
+
for (const [pkg, access] of Object.entries(data)) {
|
|
199
|
+
if (typeof access === 'string') {
|
|
200
|
+
lines.push(`${pkg}: ${access}`);
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
lines.push(pkg);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return lines.sort().join('\n');
|
|
207
|
+
}
|
|
208
|
+
async function listCollaborators(opts, params) {
|
|
209
|
+
if (params.length === 0) {
|
|
210
|
+
throw new PnpmError('ACCESS_LIST_COLLABORATORS_PACKAGE_REQUIRED', 'Package name is required (e.g., pnpm access list collaborators @scope/pkg)');
|
|
211
|
+
}
|
|
212
|
+
const packageName = params[0];
|
|
213
|
+
const user = params[1];
|
|
214
|
+
const registries = getRegistries(opts);
|
|
215
|
+
const registryUrl = pickRegistryForPackage(registries, packageName);
|
|
216
|
+
const authHeader = getAuthHeaderForRegistry(opts.configByUri, registryUrl, packageName);
|
|
217
|
+
const fetchFromRegistry = createFetchFromRegistry(opts);
|
|
218
|
+
const jsonMode = opts.cliOptions?.json ?? false;
|
|
219
|
+
let collaboratorsUrl;
|
|
220
|
+
if (user) {
|
|
221
|
+
collaboratorsUrl = new URL(`-/package/${escapePackageName(packageName)}/collaborators?format=cli&user=${encodeURIComponent(user)}`, normalizeRegistryUrl(registryUrl)).href;
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
collaboratorsUrl = new URL(`-/package/${escapePackageName(packageName)}/collaborators?format=cli`, normalizeRegistryUrl(registryUrl)).href;
|
|
225
|
+
}
|
|
226
|
+
const response = await fetchFromRegistry(collaboratorsUrl, {
|
|
227
|
+
authHeaderValue: authHeader,
|
|
228
|
+
});
|
|
229
|
+
if (!response.ok) {
|
|
230
|
+
if (response.status === 404) {
|
|
231
|
+
throw new PnpmError('PACKAGE_NOT_FOUND', `Package "${packageName}" not found in registry`);
|
|
232
|
+
}
|
|
233
|
+
await throwRegistryError(response, 'list collaborators for');
|
|
234
|
+
}
|
|
235
|
+
const data = await response.json();
|
|
236
|
+
if (jsonMode) {
|
|
237
|
+
return JSON.stringify(data, null, 2);
|
|
238
|
+
}
|
|
239
|
+
return formatCollaboratorsList(data);
|
|
240
|
+
}
|
|
241
|
+
function formatCollaboratorsList(data) {
|
|
242
|
+
const lines = [];
|
|
243
|
+
for (const entry of data) {
|
|
244
|
+
const user = entry.user ?? entry.username ?? 'unknown';
|
|
245
|
+
const email = entry.email ?? '';
|
|
246
|
+
const permissions = entry.permissions ?? 'read-only';
|
|
247
|
+
lines.push(`${String(user)}${email ? ` <${email}>` : ''}: ${permissions}`);
|
|
248
|
+
}
|
|
249
|
+
return lines.sort().join('\n');
|
|
250
|
+
}
|
|
251
|
+
async function getStatus(opts, params) {
|
|
252
|
+
if (params.length === 0) {
|
|
253
|
+
throw new PnpmError('ACCESS_GET_STATUS_PACKAGE_REQUIRED', 'Package name is required (e.g., pnpm access get status @scope/pkg)');
|
|
254
|
+
}
|
|
255
|
+
const packageName = params[0];
|
|
256
|
+
const registries = getRegistries(opts);
|
|
257
|
+
const registryUrl = pickRegistryForPackage(registries, packageName);
|
|
258
|
+
const authHeader = getAuthHeaderForRegistry(opts.configByUri, registryUrl, packageName);
|
|
259
|
+
const fetchFromRegistry = createFetchFromRegistry(opts);
|
|
260
|
+
const jsonMode = opts.cliOptions?.json ?? false;
|
|
261
|
+
const accessUrl = new URL(`-/package/${escapePackageName(packageName)}/access`, normalizeRegistryUrl(registryUrl)).href;
|
|
262
|
+
const response = await fetchFromRegistry(accessUrl, {
|
|
263
|
+
authHeaderValue: authHeader,
|
|
264
|
+
});
|
|
265
|
+
if (!response.ok) {
|
|
266
|
+
if (response.status === 404) {
|
|
267
|
+
throw new PnpmError('PACKAGE_NOT_FOUND', `Package "${packageName}" not found in registry`);
|
|
268
|
+
}
|
|
269
|
+
await throwRegistryError(response, 'get status of');
|
|
270
|
+
}
|
|
271
|
+
const data = await response.json();
|
|
272
|
+
if (jsonMode) {
|
|
273
|
+
return JSON.stringify(data, null, 2);
|
|
274
|
+
}
|
|
275
|
+
const lines = [];
|
|
276
|
+
if (data.access) {
|
|
277
|
+
lines.push(`package: ${packageName}`);
|
|
278
|
+
lines.push(`access: ${data.access}`);
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
lines.push(`package: ${packageName}`);
|
|
282
|
+
lines.push('access: public');
|
|
283
|
+
}
|
|
284
|
+
return lines.join('\n');
|
|
285
|
+
}
|
|
286
|
+
async function setStatus(opts, params) {
|
|
287
|
+
if (params.length === 0 || !params[0].startsWith('status=')) {
|
|
288
|
+
throw new PnpmError('ACCESS_SET_STATUS_REQUIRED', 'Package visibility is required (e.g., pnpm access set status=public @scope/pkg)');
|
|
289
|
+
}
|
|
290
|
+
const accessValue = params[0].slice('status='.length);
|
|
291
|
+
if (accessValue !== 'public' && accessValue !== 'private' && accessValue !== 'restricted') {
|
|
292
|
+
throw new PnpmError('ACCESS_SET_STATUS_INVALID', `Invalid access value "${accessValue}". Must be "public" or "private".`);
|
|
293
|
+
}
|
|
294
|
+
const normalizedAccess = accessValue === 'private' || accessValue === 'restricted' ? 'restricted' : 'public';
|
|
295
|
+
const packageName = params[1];
|
|
296
|
+
if (!packageName) {
|
|
297
|
+
throw new PnpmError('ACCESS_SET_STATUS_PACKAGE_REQUIRED', 'Package name is required (e.g., pnpm access set status=public @scope/pkg)');
|
|
298
|
+
}
|
|
299
|
+
if (!packageName.startsWith('@')) {
|
|
300
|
+
throw new PnpmError('ACCESS_SET_STATUS_UNSCOPED', 'Access settings can only be changed for scoped packages (@scope/name). Unscoped packages are always public.');
|
|
301
|
+
}
|
|
302
|
+
const registries = getRegistries(opts);
|
|
303
|
+
const registryUrl = pickRegistryForPackage(registries, packageName);
|
|
304
|
+
const authHeader = getAuthHeaderForRegistry(opts.configByUri, registryUrl, packageName);
|
|
305
|
+
const fetchFromRegistry = createFetchFromRegistry(opts);
|
|
306
|
+
const otp = opts.cliOptions?.otp;
|
|
307
|
+
const accessUrl = new URL(`-/package/${escapePackageName(packageName)}/access`, normalizeRegistryUrl(registryUrl)).href;
|
|
308
|
+
const response = await fetchFromRegistry(accessUrl, {
|
|
309
|
+
authHeaderValue: authHeader,
|
|
310
|
+
method: 'POST',
|
|
311
|
+
headers: {
|
|
312
|
+
'content-type': 'application/json',
|
|
313
|
+
...(otp ? { 'npm-otp': otp } : {}),
|
|
314
|
+
},
|
|
315
|
+
body: JSON.stringify({ access: normalizedAccess }),
|
|
316
|
+
});
|
|
317
|
+
if (!response.ok) {
|
|
318
|
+
await throwRegistryError(response, `set access to "${normalizedAccess}" for`);
|
|
319
|
+
}
|
|
320
|
+
return `${packageName}: ${normalizedAccess === 'public' ? 'public' : 'restricted'}`;
|
|
321
|
+
}
|
|
322
|
+
async function setMfa(opts, params) {
|
|
323
|
+
if (params.length === 0 || !params[0].startsWith('mfa=')) {
|
|
324
|
+
throw new PnpmError('ACCESS_SET_MFA_REQUIRED', 'MFA level is required (e.g., pnpm access set mfa=automation @scope/pkg)');
|
|
325
|
+
}
|
|
326
|
+
const mfaValue = params[0].slice('mfa='.length);
|
|
327
|
+
if (!['none', 'publish', 'automation'].includes(mfaValue)) {
|
|
328
|
+
throw new PnpmError('ACCESS_SET_MFA_INVALID', `Invalid MFA value "${mfaValue}". Must be "none", "publish", or "automation".`);
|
|
329
|
+
}
|
|
330
|
+
const packageName = params[1];
|
|
331
|
+
if (!packageName) {
|
|
332
|
+
throw new PnpmError('ACCESS_SET_MFA_PACKAGE_REQUIRED', 'Package name is required (e.g., pnpm access set mfa=automation @scope/pkg)');
|
|
333
|
+
}
|
|
334
|
+
const registries = getRegistries(opts);
|
|
335
|
+
const registryUrl = pickRegistryForPackage(registries, packageName);
|
|
336
|
+
const authHeader = getAuthHeaderForRegistry(opts.configByUri, registryUrl, packageName);
|
|
337
|
+
const fetchFromRegistry = createFetchFromRegistry(opts);
|
|
338
|
+
const otp = opts.cliOptions?.otp;
|
|
339
|
+
const accessUrl = new URL(`-/package/${escapePackageName(packageName)}/access`, normalizeRegistryUrl(registryUrl)).href;
|
|
340
|
+
const publishRequiresTfa = mfaValue !== 'none';
|
|
341
|
+
const response = await fetchFromRegistry(accessUrl, {
|
|
342
|
+
authHeaderValue: authHeader,
|
|
343
|
+
method: 'POST',
|
|
344
|
+
headers: {
|
|
345
|
+
'content-type': 'application/json',
|
|
346
|
+
...(otp ? { 'npm-otp': otp } : {}),
|
|
347
|
+
},
|
|
348
|
+
body: JSON.stringify({ publish_requires_tfa: publishRequiresTfa }),
|
|
349
|
+
});
|
|
350
|
+
if (!response.ok) {
|
|
351
|
+
await throwRegistryError(response, 'set MFA for');
|
|
352
|
+
}
|
|
353
|
+
return `${packageName}: mfa=${mfaValue}`;
|
|
354
|
+
}
|
|
355
|
+
async function grantAccess(opts, params) {
|
|
356
|
+
if (params.length < 2) {
|
|
357
|
+
throw new PnpmError('ACCESS_GRANT_ARGS_REQUIRED', 'Permissions and scope:team are required (e.g., pnpm access grant read-only @scope:developers @scope/pkg)');
|
|
358
|
+
}
|
|
359
|
+
const permissions = params[0];
|
|
360
|
+
if (permissions !== 'read-only' && permissions !== 'read-write') {
|
|
361
|
+
throw new PnpmError('ACCESS_GRANT_INVALID_PERMISSIONS', `Invalid permissions "${permissions}". Must be "read-only" or "read-write".`);
|
|
362
|
+
}
|
|
363
|
+
const scopeTeam = params[1];
|
|
364
|
+
if (!scopeTeam.includes(':')) {
|
|
365
|
+
throw new PnpmError('ACCESS_GRANT_INVALID_TEAM', `Invalid team "${scopeTeam}". Format must be "scope:team".`);
|
|
366
|
+
}
|
|
367
|
+
const packageName = params[2];
|
|
368
|
+
if (!packageName) {
|
|
369
|
+
throw new PnpmError('ACCESS_GRANT_PACKAGE_REQUIRED', 'Package name is required (e.g., pnpm access grant read-only @scope:developers @scope/pkg)');
|
|
370
|
+
}
|
|
371
|
+
const [scope, team] = scopeTeam.split(':');
|
|
372
|
+
const registries = getRegistries(opts);
|
|
373
|
+
const registryUrl = pickRegistryForPackage(registries, packageName);
|
|
374
|
+
const authHeader = getAuthHeaderForRegistry(opts.configByUri, registryUrl, packageName);
|
|
375
|
+
const fetchFromRegistry = createFetchFromRegistry(opts);
|
|
376
|
+
const otp = opts.cliOptions?.otp;
|
|
377
|
+
const grantUrl = new URL(`-/team/${encodeURIComponent(scope.startsWith('@') ? scope.slice(1) : scope)}/${encodeURIComponent(team)}/package`, normalizeRegistryUrl(registryUrl)).href;
|
|
378
|
+
const response = await fetchFromRegistry(grantUrl, {
|
|
379
|
+
authHeaderValue: authHeader,
|
|
380
|
+
method: 'PUT',
|
|
381
|
+
headers: {
|
|
382
|
+
'content-type': 'application/json',
|
|
383
|
+
...(otp ? { 'npm-otp': otp } : {}),
|
|
384
|
+
},
|
|
385
|
+
body: JSON.stringify({ package: packageName, permissions }),
|
|
386
|
+
});
|
|
387
|
+
if (!response.ok) {
|
|
388
|
+
await throwRegistryError(response, `grant ${permissions} access for ${scopeTeam} on`);
|
|
389
|
+
}
|
|
390
|
+
return `+${scopeTeam} (${permissions}): ${packageName}`;
|
|
391
|
+
}
|
|
392
|
+
async function revokeAccess(opts, params) {
|
|
393
|
+
if (params.length < 1) {
|
|
394
|
+
throw new PnpmError('ACCESS_REVOKE_ARGS_REQUIRED', 'scope:team and package name are required (e.g., pnpm access revoke @scope:developers @scope/pkg)');
|
|
395
|
+
}
|
|
396
|
+
const scopeTeam = params[0];
|
|
397
|
+
if (!scopeTeam.includes(':')) {
|
|
398
|
+
throw new PnpmError('ACCESS_REVOKE_INVALID_TEAM', `Invalid team "${scopeTeam}". Format must be "scope:team".`);
|
|
399
|
+
}
|
|
400
|
+
const packageName = params[1];
|
|
401
|
+
if (!packageName) {
|
|
402
|
+
throw new PnpmError('ACCESS_REVOKE_PACKAGE_REQUIRED', 'Package name is required (e.g., pnpm access revoke @scope:developers @scope/pkg)');
|
|
403
|
+
}
|
|
404
|
+
const [scope, team] = scopeTeam.split(':');
|
|
405
|
+
const registries = getRegistries(opts);
|
|
406
|
+
const registryUrl = pickRegistryForPackage(registries, packageName);
|
|
407
|
+
const authHeader = getAuthHeaderForRegistry(opts.configByUri, registryUrl, packageName);
|
|
408
|
+
const fetchFromRegistry = createFetchFromRegistry(opts);
|
|
409
|
+
const otp = opts.cliOptions?.otp;
|
|
410
|
+
const revokeUrl = new URL(`-/team/${encodeURIComponent(scope.startsWith('@') ? scope.slice(1) : scope)}/${encodeURIComponent(team)}/package`, normalizeRegistryUrl(registryUrl)).href;
|
|
411
|
+
const response = await fetchFromRegistry(revokeUrl, {
|
|
412
|
+
authHeaderValue: authHeader,
|
|
413
|
+
method: 'DELETE',
|
|
414
|
+
headers: {
|
|
415
|
+
'content-type': 'application/json',
|
|
416
|
+
...(otp ? { 'npm-otp': otp } : {}),
|
|
417
|
+
},
|
|
418
|
+
body: JSON.stringify({ package: packageName }),
|
|
419
|
+
});
|
|
420
|
+
if (!response.ok) {
|
|
421
|
+
await throwRegistryError(response, `revoke ${scopeTeam}'s access to`);
|
|
422
|
+
}
|
|
423
|
+
return `-${scopeTeam}: ${packageName}`;
|
|
424
|
+
}
|
|
425
|
+
function getAuthHeaderForRegistry(configByUri, registryUrl, packageName) {
|
|
426
|
+
const getAuthHeader = createGetAuthHeaderByURI(configByUri ?? {});
|
|
427
|
+
return getAuthHeader(registryUrl, packageName ? { pkgName: packageName } : undefined);
|
|
428
|
+
}
|
|
429
|
+
function escapePackageName(packageName) {
|
|
430
|
+
let parsed;
|
|
431
|
+
try {
|
|
432
|
+
parsed = npa(packageName);
|
|
433
|
+
}
|
|
434
|
+
catch {
|
|
435
|
+
throw new PnpmError('ACCESS_INVALID_PACKAGE_NAME', `Invalid package name "${packageName}"`);
|
|
436
|
+
}
|
|
437
|
+
return parsed.escapedName ?? encodeURIComponent(packageName).replace(/^%40/, '@');
|
|
438
|
+
}
|
|
439
|
+
async function throwRegistryError(response, action) {
|
|
440
|
+
const errorBody = sanitize(await readErrorBody(response));
|
|
441
|
+
if (response.status === 401) {
|
|
442
|
+
throw new PnpmError('UNAUTHORIZED', `You must be logged in to ${action} packages. ${errorBody}`);
|
|
443
|
+
}
|
|
444
|
+
if (response.status === 403) {
|
|
445
|
+
throw new PnpmError('FORBIDDEN', `You do not have permission to ${action} this package. ${errorBody}`);
|
|
446
|
+
}
|
|
447
|
+
if (response.status === 404) {
|
|
448
|
+
throw new PnpmError('PACKAGE_NOT_FOUND', `Package not found in registry. ${errorBody}`);
|
|
449
|
+
}
|
|
450
|
+
if (response.status === 422) {
|
|
451
|
+
throw new PnpmError('ACCESS_VALIDATION_ERROR', `Invalid request: ${errorBody}`);
|
|
452
|
+
}
|
|
453
|
+
throw new PnpmError('REGISTRY_ERROR', `Failed to ${action} package: ${response.status} ${response.statusText}. ${errorBody}`);
|
|
454
|
+
}
|
|
455
|
+
async function readErrorBody(response) {
|
|
456
|
+
const reader = response.body?.getReader();
|
|
457
|
+
if (reader == null)
|
|
458
|
+
return '';
|
|
459
|
+
const chunks = [];
|
|
460
|
+
let total = 0;
|
|
461
|
+
let truncated = false;
|
|
462
|
+
while (total < ERROR_BODY_LIMIT) {
|
|
463
|
+
// eslint-disable-next-line no-await-in-loop
|
|
464
|
+
const { done, value } = await reader.read();
|
|
465
|
+
if (done)
|
|
466
|
+
break;
|
|
467
|
+
const need = ERROR_BODY_LIMIT - total;
|
|
468
|
+
if (value.length > need) {
|
|
469
|
+
chunks.push(value.subarray(0, need));
|
|
470
|
+
truncated = true;
|
|
471
|
+
break;
|
|
472
|
+
}
|
|
473
|
+
chunks.push(value);
|
|
474
|
+
total += value.length;
|
|
475
|
+
}
|
|
476
|
+
reader.cancel().catch(() => { });
|
|
477
|
+
let body = new TextDecoder().decode(Buffer.concat(chunks));
|
|
478
|
+
if (truncated) {
|
|
479
|
+
if (body.length > 0 && !body.endsWith(' ')) {
|
|
480
|
+
body += ' ';
|
|
481
|
+
}
|
|
482
|
+
body += '(response body truncated)';
|
|
483
|
+
}
|
|
484
|
+
return body;
|
|
485
|
+
}
|
|
486
|
+
function sanitize(text) {
|
|
487
|
+
let result = '';
|
|
488
|
+
for (let i = 0; i < text.length; i++) {
|
|
489
|
+
const code = text.charCodeAt(i);
|
|
490
|
+
if ((code > 31 && code !== 127) || code === 9 || code === 10) {
|
|
491
|
+
result += text[i];
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
return result;
|
|
495
|
+
}
|
|
496
|
+
//# sourceMappingURL=access.js.map
|
package/lib/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as access from './access.js';
|
|
1
2
|
import * as deprecate from './deprecation/deprecate.js';
|
|
2
3
|
import * as undeprecate from './deprecation/undeprecate.js';
|
|
3
4
|
import * as distTag from './distTag.js';
|
|
@@ -9,4 +10,4 @@ import * as stars from './star/stars.js';
|
|
|
9
10
|
import * as unstar from './star/unstar.js';
|
|
10
11
|
import * as unpublish from './unpublish.js';
|
|
11
12
|
import * as whoami from './whoami.js';
|
|
12
|
-
export { deprecate, distTag, owner, ping, search, star, stars, undeprecate, unpublish, unstar, whoami };
|
|
13
|
+
export { access, deprecate, distTag, owner, ping, search, star, stars, undeprecate, unpublish, unstar, whoami };
|
package/lib/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as access from './access.js';
|
|
1
2
|
import * as deprecate from './deprecation/deprecate.js';
|
|
2
3
|
import * as undeprecate from './deprecation/undeprecate.js';
|
|
3
4
|
import * as distTag from './distTag.js';
|
|
@@ -9,5 +10,5 @@ import * as stars from './star/stars.js';
|
|
|
9
10
|
import * as unstar from './star/unstar.js';
|
|
10
11
|
import * as unpublish from './unpublish.js';
|
|
11
12
|
import * as whoami from './whoami.js';
|
|
12
|
-
export { deprecate, distTag, owner, ping, search, star, stars, undeprecate, unpublish, unstar, whoami };
|
|
13
|
+
export { access, deprecate, distTag, owner, ping, search, star, stars, undeprecate, unpublish, unstar, whoami };
|
|
13
14
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnpm/registry-access.commands",
|
|
3
|
-
"version": "1100.
|
|
3
|
+
"version": "1100.4.1",
|
|
4
4
|
"description": "Commands for managing packages on the registry",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pnpm",
|
|
@@ -28,37 +28,37 @@
|
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@inquirer/prompts": "^8.4.3",
|
|
31
|
-
"@pnpm/
|
|
32
|
-
"chalk": "^5.6.2",
|
|
33
|
-
"ramda": "npm:@pnpm/ramda@0.28.1",
|
|
34
|
-
"render-help": "^2.0.0",
|
|
35
|
-
"semver": "^7.8.4",
|
|
31
|
+
"@pnpm/cli.utils": "1101.0.13",
|
|
36
32
|
"@pnpm/config.pick-registry-for-package": "1100.0.9",
|
|
33
|
+
"@pnpm/config.reader": "1101.11.2",
|
|
37
34
|
"@pnpm/error": "1100.0.1",
|
|
38
|
-
"@pnpm/cli.utils": "1101.0.13",
|
|
39
|
-
"@pnpm/network.web-auth": "1101.2.0",
|
|
40
|
-
"@pnpm/network.fetch": "1100.1.4",
|
|
41
|
-
"@pnpm/config.reader": "1101.11.0",
|
|
42
35
|
"@pnpm/network.auth-header": "1101.1.3",
|
|
36
|
+
"@pnpm/network.fetch": "1100.1.4",
|
|
37
|
+
"@pnpm/network.web-auth": "1101.2.0",
|
|
38
|
+
"@pnpm/npm-package-arg": "^2.0.0",
|
|
43
39
|
"@pnpm/registry-access.client": "1100.1.6",
|
|
40
|
+
"@pnpm/resolving.registry.types": "1100.1.3",
|
|
44
41
|
"@pnpm/types": "1101.3.2",
|
|
45
|
-
"
|
|
42
|
+
"chalk": "^5.6.2",
|
|
43
|
+
"ramda": "npm:@pnpm/ramda@0.28.1",
|
|
44
|
+
"render-help": "^2.0.0",
|
|
45
|
+
"semver": "^7.8.4"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"@pnpm/logger": "^1100.0.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@jest/globals": "30.4.1",
|
|
52
|
-
"@types/ramda": "0.31.1",
|
|
53
|
-
"@types/semver": "7.7.1",
|
|
54
|
-
"execa": "npm:safe-execa@0.3.0",
|
|
55
52
|
"@pnpm/logger": "1100.0.0",
|
|
56
|
-
"@pnpm/
|
|
53
|
+
"@pnpm/prepare": "1100.0.18",
|
|
54
|
+
"@pnpm/registry-access.commands": "1100.4.1",
|
|
55
|
+
"@pnpm/releasing.commands": "1100.5.5",
|
|
57
56
|
"@pnpm/testing.command-defaults": "1100.0.8",
|
|
58
57
|
"@pnpm/testing.mock-agent": "1101.0.4",
|
|
59
|
-
"@pnpm/prepare": "1100.0.18",
|
|
60
58
|
"@pnpm/testing.registry-mock": "1100.0.8",
|
|
61
|
-
"@
|
|
59
|
+
"@types/ramda": "0.31.1",
|
|
60
|
+
"@types/semver": "7.7.1",
|
|
61
|
+
"execa": "npm:safe-execa@0.3.0"
|
|
62
62
|
},
|
|
63
63
|
"engines": {
|
|
64
64
|
"node": ">=22.13"
|