@vscode/vsce 3.9.3-10 → 3.9.3-12

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
@@ -17,6 +17,26 @@ Read the [**Documentation**](https://code.visualstudio.com/api/working-with-exte
17
17
 
18
18
  In order to save credentials safely, this project uses [`@napi-rs/keyring`](https://www.npmjs.com/package/@napi-rs/keyring), which uses the system Secret Service and falls back to the Linux kernel keyring. Setting the `VSCE_STORE=file` environment variable will revert back to the file credential store. Using the `VSCE_PAT` environment variable will also avoid using the system credential store.
19
19
 
20
+ ### Upgrading saved PATs
21
+
22
+ When a command needs a saved Personal Access Token and the publisher has none in the current native credential store, `vsce` checks for that publisher's old `keytar` credential. If one is found in an interactive terminal, it offers:
23
+
24
+ ```text
25
+ A saved PAT for publisher 'your-publisher' was found in the previous credential store. Copy it to the new store? [y/N]
26
+ ```
27
+
28
+ Enter `Y` to copy just that publisher's PAT and continue without re-entering it. Enter `N` (or press Enter) to continue to the normal PAT prompt without copying anything. Migration is skipped in non-interactive runs such as CI.
29
+
30
+ - **Windows:** reads the requested Windows Credential Manager entry using the built-in Windows PowerShell. No `keytar` installation is needed.
31
+ - **Linux:** requires `secret-tool` (`libsecret-tools` on Debian/Ubuntu) and access to the same desktop Secret Service used previously. You may be prompted to unlock the keyring.
32
+ - **macOS:** existing Keychain entries are already compatible; no copying is necessary.
33
+
34
+ Existing PATs in the new store take precedence; migration does not run while listing publishers or logging out. Each copied PAT is read back before it is used. **Old keytar entries are never modified or deleted**, so older `vsce` versions can still use them. Declining or logging out does not permanently suppress the offer: the old PAT can be offered again when needed, but copying always requires fresh consent. Logout removes only the new entry and does not revoke the PAT.
35
+
36
+ Credential writes are serialized across `vsce` processes, and the destination is checked again after confirmation to avoid overwriting a newer PAT. The non-secret lock lives under `~/.vsce-keytar-migration`; no PATs or consent decisions are stored there. A command waits up to 30 seconds for the lock; a lock abandoned by a crashed process can be recovered after two minutes.
37
+
38
+ If legacy lookup or copying fails, `vsce` displays a warning and continues to the normal PAT prompt. Install the required helper/unlock the keyring and retry, or enter a PAT to save it normally. Migration helpers time out after 30 seconds. Using `VSCE_STORE=file`, `VSCE_PAT`, or `--pat` does not trigger this native-store migration; the existing plaintext-file migration is unchanged.
39
+
20
40
  ## Usage
21
41
 
22
42
  ```console
@@ -0,0 +1,181 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.LegacyCredentialMigration = void 0;
37
+ const crypto_1 = require("crypto");
38
+ const fs = __importStar(require("fs"));
39
+ const os_1 = require("os");
40
+ const path = __importStar(require("path"));
41
+ const proper_lockfile_1 = require("proper-lockfile");
42
+ const legacyCredentials_1 = require("./legacyCredentials");
43
+ const util_1 = require("./util");
44
+ const validation_1 = require("./validation");
45
+ // Decorate the native store so migration policy and write synchronization stay
46
+ // separate from its ordinary credential operations.
47
+ class LegacyCredentialMigration {
48
+ store;
49
+ openStore;
50
+ static wrap(store, openStore, options = {}) {
51
+ const platform = options.platform ?? process.platform;
52
+ return platform === 'win32' || platform === 'linux'
53
+ ? new LegacyCredentialMigration(store, openStore, options)
54
+ : store;
55
+ }
56
+ serviceName;
57
+ platform;
58
+ lockPath;
59
+ interactive;
60
+ prompt;
61
+ readCredential;
62
+ constructor(store, openStore, options = {}) {
63
+ this.store = store;
64
+ this.openStore = openStore;
65
+ this.serviceName = options.serviceName ?? 'vscode-vsce';
66
+ this.platform = options.platform ?? process.platform;
67
+ this.lockPath = options.lockPath ?? path.join((0, os_1.homedir)(), '.vsce-keytar-migration', (0, crypto_1.createHash)('sha256').update(`${this.platform}:${this.serviceName}`).digest('hex'));
68
+ // read() otherwise answers "y" in tests and non-interactive processes.
69
+ this.interactive = options.interactive ?? Boolean(process.stdin.isTTY && process.stdout.isTTY && !process.env.VSCE_TESTS);
70
+ this.prompt = options.prompt ?? util_1.read;
71
+ this.readCredential = options.readCredential
72
+ ?? ((service, name) => (0, legacyCredentials_1.readLegacyCredential)(service, name, { platform: this.platform }));
73
+ }
74
+ get size() {
75
+ return this.store.size;
76
+ }
77
+ get(name) {
78
+ return this.findPublisher(this.store, name);
79
+ }
80
+ async add(publisher) {
81
+ await this.withLock(() => this.store.add({
82
+ name: this.get(publisher.name)?.name ?? publisher.name,
83
+ pat: publisher.pat,
84
+ }));
85
+ }
86
+ async delete(name) {
87
+ await this.withLock(() => this.store.delete(this.get(name)?.name ?? name));
88
+ }
89
+ [Symbol.iterator]() {
90
+ return this.store[Symbol.iterator]();
91
+ }
92
+ async tryMigratePublisher(name) {
93
+ (0, validation_1.validatePublisher)(name);
94
+ const existing = this.get(name);
95
+ if (existing || !this.interactive || (this.platform !== 'win32' && this.platform !== 'linux')) {
96
+ return existing;
97
+ }
98
+ try {
99
+ const legacy = await this.readCredential(this.serviceName, name);
100
+ if (!legacy) {
101
+ return undefined;
102
+ }
103
+ if (!this.sameAccount(legacy.name, name) || !legacy.pat) {
104
+ throw new legacyCredentials_1.LegacyMigrationError('The legacy credential reader returned an invalid credential.');
105
+ }
106
+ const answer = await this.prompt(`A saved PAT for publisher '${name}' was found in the previous credential store. Copy it to the new store? [y/N] `);
107
+ if (!/^y$/i.test(answer.trim())) {
108
+ return undefined;
109
+ }
110
+ // Do not hold a cross-process lock while waiting for the user's answer.
111
+ return await this.withLock(() => this.copyAndVerify({ name, pat: legacy.pat }));
112
+ }
113
+ catch (error) {
114
+ if (!(error instanceof legacyCredentials_1.LegacyMigrationError)) {
115
+ throw error;
116
+ }
117
+ util_1.log.warn(`${error.message} The previous credential was not changed. `
118
+ + (this.platform === 'linux' ? 'Legacy lookup requires secret-tool (libsecret-tools on Debian/Ubuntu) and an accessible desktop keyring. ' : '')
119
+ + 'Enter a PAT to continue, or retry after resolving the credential-store problem.');
120
+ return undefined;
121
+ }
122
+ }
123
+ async copyAndVerify(publisher) {
124
+ let verified;
125
+ try {
126
+ const destination = await this.openStore();
127
+ const current = this.findPublisher(destination, publisher.name);
128
+ if (current) {
129
+ this.store = destination;
130
+ return current;
131
+ }
132
+ await destination.add(publisher);
133
+ verified = await this.openStore();
134
+ const saved = this.findPublisher(verified, publisher.name);
135
+ if (saved?.pat !== publisher.pat) {
136
+ throw new legacyCredentials_1.LegacyMigrationError('The copied PAT could not be verified.');
137
+ }
138
+ }
139
+ catch (error) {
140
+ if (!(error instanceof Error)) {
141
+ throw error;
142
+ }
143
+ // Native failures must not include secret values in CLI diagnostics.
144
+ throw new legacyCredentials_1.LegacyMigrationError(`Could not copy and verify the previous PAT for publisher '${publisher.name}'.`);
145
+ }
146
+ this.store = verified;
147
+ util_1.log.info(`Copied the saved PAT for publisher '${publisher.name}'. The previous credential was not changed.`);
148
+ return publisher;
149
+ }
150
+ sameAccount(a, b) {
151
+ return this.platform === 'win32' ? a.toLowerCase() === b.toLowerCase() : a === b;
152
+ }
153
+ findPublisher(store, name) {
154
+ return [...store].find(publisher => this.sameAccount(publisher.name, name));
155
+ }
156
+ async withLock(operation) {
157
+ let release;
158
+ try {
159
+ await fs.promises.mkdir(this.lockPath, { recursive: true, mode: 0o700 });
160
+ release = await (0, proper_lockfile_1.lock)(this.lockPath, {
161
+ stale: 120_000,
162
+ update: 5_000,
163
+ retries: { retries: 120, factor: 1, minTimeout: 250, maxTimeout: 250 },
164
+ });
165
+ }
166
+ catch (error) {
167
+ if (error instanceof Error && 'code' in error) {
168
+ throw new legacyCredentials_1.LegacyMigrationError('Could not lock the credential store. Another vsce command may still be using it.');
169
+ }
170
+ throw error;
171
+ }
172
+ try {
173
+ return await operation();
174
+ }
175
+ finally {
176
+ await release();
177
+ }
178
+ }
179
+ }
180
+ exports.LegacyCredentialMigration = LegacyCredentialMigration;
181
+ //# sourceMappingURL=keytarMigration.js.map
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.LegacyMigrationError = void 0;
37
+ exports.readLegacyCredential = readLegacyCredential;
38
+ const child_process_1 = require("child_process");
39
+ const path = __importStar(require("path"));
40
+ const validation_1 = require("./validation");
41
+ const windowsKeytar_1 = require("./windowsKeytar");
42
+ class LegacyMigrationError extends Error {
43
+ }
44
+ exports.LegacyMigrationError = LegacyMigrationError;
45
+ const runCredentialCommand = (file, args, env) => new Promise((resolve, reject) => {
46
+ (0, child_process_1.execFile)(file, args, {
47
+ encoding: 'utf8',
48
+ env,
49
+ windowsHide: true,
50
+ timeout: 30_000,
51
+ maxBuffer: 1024 * 1024,
52
+ }, (error, stdout, stderr) => {
53
+ if (error && (typeof error.code !== 'number' || error.killed)) {
54
+ // Child-process errors can contain stdout/stderr, including PATs.
55
+ const reason = error.code === 'ENOENT' ? 'is not installed'
56
+ : error.killed ? 'timed out or was terminated'
57
+ : 'failed to read the previous credential';
58
+ reject(new LegacyMigrationError(`${path.basename(file)} ${reason}.`));
59
+ }
60
+ else {
61
+ resolve({ stdout, stderr, exitCode: typeof error?.code === 'number' ? error.code : 0 });
62
+ }
63
+ });
64
+ });
65
+ function parseWindowsCredential(stdout, name) {
66
+ let value;
67
+ try {
68
+ value = JSON.parse(stdout);
69
+ }
70
+ catch (error) {
71
+ if (!(error instanceof SyntaxError)) {
72
+ throw error;
73
+ }
74
+ throw new LegacyMigrationError('The Windows credential reader returned an invalid response.');
75
+ }
76
+ if (value === null) {
77
+ return undefined;
78
+ }
79
+ if (!value || typeof value !== 'object'
80
+ || !('name' in value) || typeof value.name !== 'string' || value.name.toLowerCase() !== name.toLowerCase()
81
+ || !('pat' in value) || typeof value.pat !== 'string' || !value.pat) {
82
+ throw new LegacyMigrationError('The Windows credential reader returned an invalid credential.');
83
+ }
84
+ return { name, pat: value.pat };
85
+ }
86
+ async function readLegacyCredential(serviceName, publisherName, { platform = process.platform, run = runCredentialCommand } = {}) {
87
+ (0, validation_1.validatePublisher)(publisherName);
88
+ if (platform === 'win32') {
89
+ const powershell = path.win32.join(process.env.SystemRoot ?? 'C:\\Windows', 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe');
90
+ const { stdout, exitCode } = await run(powershell, [
91
+ '-NoLogo', '-NoProfile', '-NonInteractive', '-Command', windowsKeytar_1.windowsKeytarReadScript,
92
+ ], { ...process.env, VSCE_KEYTAR_SERVICE: serviceName, VSCE_KEYTAR_ACCOUNT: publisherName });
93
+ if (exitCode !== 0) {
94
+ throw new LegacyMigrationError('Windows PowerShell could not read the previous credential.');
95
+ }
96
+ return parseWindowsCredential(stdout, publisherName);
97
+ }
98
+ if (platform !== 'linux') {
99
+ return undefined;
100
+ }
101
+ const { stdout, stderr, exitCode } = await run('secret-tool', [
102
+ 'lookup', 'service', serviceName, 'account', publisherName,
103
+ 'xdg:schema', 'org.freedesktop.Secret.Generic',
104
+ ]);
105
+ // secret-tool exits 1 without output when no item matches; other failures
106
+ // must not masquerade as a missing credential or expose raw diagnostics.
107
+ if (exitCode === 1 && !stdout && !stderr) {
108
+ return undefined;
109
+ }
110
+ if (exitCode !== 0 || !stdout) {
111
+ throw new LegacyMigrationError('secret-tool could not read the previous credential.');
112
+ }
113
+ return { name: publisherName, pat: stdout };
114
+ }
115
+ //# sourceMappingURL=legacyCredentials.js.map
package/out/main.js CHANGED
@@ -32,12 +32,8 @@ var __importStar = (this && this.__importStar) || (function () {
32
32
  return result;
33
33
  };
34
34
  })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
35
  Object.defineProperty(exports, "__esModule", { value: true });
39
36
  const commander_1 = require("commander");
40
- const leven_1 = __importDefault(require("leven"));
41
37
  const package_1 = require("./package");
42
38
  const publish_1 = require("./publish");
43
39
  const show_1 = require("./show");
@@ -311,7 +307,7 @@ module.exports = function (argv) {
311
307
  }
312
308
  program.outputHelp(help => {
313
309
  const availableCommands = program.commands.map(c => c.name());
314
- const suggestion = availableCommands.find(c => (0, leven_1.default)(c, cmd) < c.length * 0.4);
310
+ const suggestion = (0, util_1.findSimilar)(cmd, availableCommands);
315
311
  help = `${help}\n Unknown command '${cmd}'`;
316
312
  return suggestion ? `${help}, did you mean '${suggestion}'?\n` : `${help}.\n`;
317
313
  });
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createMultipartStream = createMultipartStream;
4
+ exports.runWithStreamError = runWithStreamError;
5
+ const stream_1 = require("stream");
6
+ function escapeHeaderParameter(value) {
7
+ return value.replace(/\r/g, '%0D').replace(/\n/g, '%0A').replace(/"/g, '%22');
8
+ }
9
+ function createMultipartStream(parts, boundary) {
10
+ const lineBreak = '\r\n';
11
+ for (const part of parts) {
12
+ // A part can fail before it is reached. Readable stores the error and its async iterator
13
+ // rethrows it when the part is consumed; this listener just keeps it from being unhandled.
14
+ part.stream.on('error', () => { });
15
+ }
16
+ const destroyParts = () => {
17
+ for (const part of parts) {
18
+ part.stream.destroy();
19
+ }
20
+ };
21
+ const stream = stream_1.Readable.from((async function* () {
22
+ try {
23
+ for (const part of parts) {
24
+ yield `--${boundary}${lineBreak}` +
25
+ `Content-Disposition: attachment; name=${escapeHeaderParameter(part.name)}; filename="${escapeHeaderParameter(part.filename)}"${lineBreak}` +
26
+ `Content-Type: application/octet-stream${lineBreak}${lineBreak}`;
27
+ yield* part.stream;
28
+ yield lineBreak;
29
+ }
30
+ yield `--${boundary}--${lineBreak}`;
31
+ }
32
+ finally {
33
+ // Parts after a failed or abandoned one are never consumed, so release them here.
34
+ destroyParts();
35
+ }
36
+ })(),
37
+ // Without this the stream emits 'close' once it ends, which makes consumers that treat
38
+ // 'close' as "the body is complete" end the underlying request a second time.
39
+ { autoDestroy: false });
40
+ // The generator body, and therefore its `finally`, never runs if the stream is destroyed
41
+ // before anything is read from it.
42
+ stream.on('close', destroyParts);
43
+ return stream;
44
+ }
45
+ function runWithStreamError(stream, operation) {
46
+ return new Promise((resolve, reject) => {
47
+ // This listener is deliberately never removed. An error arriving after the operation has
48
+ // settled would otherwise be an unhandled 'error' event, which terminates the process.
49
+ // Settling a promise more than once is a no-op, so the first outcome wins.
50
+ stream.on('error', reject);
51
+ Promise.resolve().then(operation).then(resolve, reject);
52
+ });
53
+ }
54
+ //# sourceMappingURL=multipart.js.map
package/out/package.js CHANGED
@@ -70,10 +70,10 @@ const minimatch_1 = require("minimatch");
70
70
  const parse5_1 = require("parse5");
71
71
  const marked_1 = require("marked");
72
72
  const url = __importStar(require("url"));
73
+ const util_2 = require("util");
73
74
  const mime_1 = __importDefault(require("mime"));
74
75
  const semver = __importStar(require("semver"));
75
76
  const url_join_1 = __importDefault(require("url-join"));
76
- const chalk_1 = __importDefault(require("chalk"));
77
77
  const validation_1 = require("./validation");
78
78
  const npm_1 = require("./npm");
79
79
  const GitHost = __importStar(require("hosted-git-info"));
@@ -1566,7 +1566,7 @@ async function packageCommand(options = {}) {
1566
1566
  }
1567
1567
  const stats = await fs.promises.stat(packagePath);
1568
1568
  const packageSize = util.bytesToString(stats.size);
1569
- util.log.done(`Packaged: ${packagePath} ` + chalk_1.default.bold(`(${files.length} files, ${packageSize})`));
1569
+ util.log.done(`Packaged: ${packagePath} ` + (0, util_2.styleText)('bold', `(${files.length} files, ${packageSize})`));
1570
1570
  }
1571
1571
  /**
1572
1572
  * Lists the files included in the extension's package.
@@ -1602,26 +1602,26 @@ async function printAndValidatePackagedFiles(files, cwd, manifest, options) {
1602
1602
  const jsFiles = files.filter(f => /\.js$/i.test(f.path));
1603
1603
  if (files.length > 5000 || jsFiles.length > 100) {
1604
1604
  let message = '';
1605
- message += `This extension consists of ${chalk_1.default.bold(String(files.length))} files, out of which ${chalk_1.default.bold(String(jsFiles.length))} are JavaScript files. `;
1606
- message += `For performance reasons, you should bundle your extension: ${chalk_1.default.underline('https://aka.ms/vscode-bundle-extension')}. `;
1607
- message += `You should also exclude unnecessary files by adding them to your .vscodeignore: ${chalk_1.default.underline('https://aka.ms/vscode-vscodeignore')}.\n`;
1605
+ message += `This extension consists of ${(0, util_2.styleText)('bold', String(files.length))} files, out of which ${(0, util_2.styleText)('bold', String(jsFiles.length))} are JavaScript files. `;
1606
+ message += `For performance reasons, you should bundle your extension: ${(0, util_2.styleText)('underline', 'https://aka.ms/vscode-bundle-extension')}. `;
1607
+ message += `You should also exclude unnecessary files by adding them to your .vscodeignore: ${(0, util_2.styleText)('underline', 'https://aka.ms/vscode-vscodeignore')}.\n`;
1608
1608
  util.log.warn(message);
1609
1609
  }
1610
1610
  // Warn if the extension does not have a .vscodeignore file or a files property in package.json
1611
1611
  const hasIgnoreFile = fs.existsSync(options.ignoreFile ?? path.join(cwd, '.vscodeignore'));
1612
1612
  if (!hasIgnoreFile && !manifest.files) {
1613
1613
  let message = '';
1614
- message += `Neither a ${chalk_1.default.bold('.vscodeignore')} file nor a ${chalk_1.default.bold('"files"')} property in package.json was found. `;
1614
+ message += `Neither a ${(0, util_2.styleText)('bold', '.vscodeignore')} file nor a ${(0, util_2.styleText)('bold', '"files"')} property in package.json was found. `;
1615
1615
  message += `To ensure only necessary files are included in your extension, `;
1616
- message += `add a .vscodeignore file or specify the "files" property in package.json. More info: ${chalk_1.default.underline('https://aka.ms/vscode-vscodeignore')}\n`;
1616
+ message += `add a .vscodeignore file or specify the "files" property in package.json. More info: ${(0, util_2.styleText)('underline', 'https://aka.ms/vscode-vscodeignore')}\n`;
1617
1617
  util.log.warn(message);
1618
1618
  }
1619
1619
  // Throw an error if the extension uses both a .vscodeignore file and the files property in package.json
1620
1620
  else if (hasIgnoreFile && manifest.files !== undefined && manifest.files.length > 0) {
1621
1621
  let message = '';
1622
- message += `Both a ${chalk_1.default.bold('.vscodeignore')} file and a ${chalk_1.default.bold('"files"')} property in package.json were found. `;
1622
+ message += `Both a ${(0, util_2.styleText)('bold', '.vscodeignore')} file and a ${(0, util_2.styleText)('bold', '"files"')} property in package.json were found. `;
1623
1623
  message += `VSCE does not support combining both strategies. `;
1624
- message += `Either remove the ${chalk_1.default.bold('.vscodeignore')} file or the ${chalk_1.default.bold('"files"')} property in package.json.`;
1624
+ message += `Either remove the ${(0, util_2.styleText)('bold', '.vscodeignore')} file or the ${(0, util_2.styleText)('bold', '"files"')} property in package.json.`;
1625
1625
  util.log.error(message);
1626
1626
  process.exit(1);
1627
1627
  }
@@ -1646,11 +1646,11 @@ async function printAndValidatePackagedFiles(files, cwd, manifest, options) {
1646
1646
  });
1647
1647
  if (unusedIncludePatterns.length > 0) {
1648
1648
  let message = '';
1649
- message += `The following include patterns in the ${chalk_1.default.bold('"files"')} property in package.json do not match any files packaged in the extension:\n`;
1649
+ message += `The following include patterns in the ${(0, util_2.styleText)('bold', '"files"')} property in package.json do not match any files packaged in the extension:\n`;
1650
1650
  message += unusedIncludePatterns.map(p => ` - ${p.relative}`).join('\n');
1651
1651
  message += '\nRemove any include pattern which is not needed.\n';
1652
- message += `\n=> Run ${chalk_1.default.bold('vsce ls --tree')} to see all included files.\n`;
1653
- message += `=> Use ${chalk_1.default.bold('--allow-unused-files-pattern')} to skip this check`;
1652
+ message += `\n=> Run ${(0, util_2.styleText)('bold', 'vsce ls --tree')} to see all included files.\n`;
1653
+ message += `=> Use ${(0, util_2.styleText)('bold', '--allow-unused-files-pattern')} to skip this check`;
1654
1654
  util.log.error(message);
1655
1655
  process.exit(1);
1656
1656
  }
@@ -1664,11 +1664,11 @@ async function printAndValidatePackagedFiles(files, cwd, manifest, options) {
1664
1664
  })), 35 // Print up to 35 files/folders
1665
1665
  );
1666
1666
  let message = '';
1667
- message += chalk_1.default.bold.blue(`Files included in the VSIX:\n`);
1667
+ message += (0, util_2.styleText)(['bold', 'blue'], `Files included in the VSIX:\n`);
1668
1668
  message += printableFileStructure.join('\n');
1669
1669
  // If not all files have been printed, mention how all files can be printed
1670
1670
  if (files.length + 1 > printableFileStructure.length) {
1671
- message += `\n\n=> Run ${chalk_1.default.bold('vsce ls --tree')} to see all included files.`;
1671
+ message += `\n\n=> Run ${(0, util_2.styleText)('bold', 'vsce ls --tree')} to see all included files.`;
1672
1672
  }
1673
1673
  message += '\n';
1674
1674
  util.log.info(message);
@@ -1703,33 +1703,33 @@ async function scanFilesForSecrets(files, fileExclusion, options) {
1703
1703
  if (noneDotEnvSecretsFound.length > 0) {
1704
1704
  const uniqueSecretIds = new Set(noneDotEnvSecretsFound.map(result => result.ruleId));
1705
1705
  const secretsFoundRuleNames = Array.from(uniqueSecretIds).map(secretLint_1.getRuleNameFromRuleId);
1706
- let errorMessage = `${chalk_1.default.bold('Potential security issue detected:')}`;
1706
+ let errorMessage = `${(0, util_2.styleText)('bold', 'Potential security issue detected:')}`;
1707
1707
  errorMessage += ` Your extension package contains sensitive information that should not be published.`;
1708
1708
  errorMessage += ` Please remove these secrets before packaging.`;
1709
1709
  errorMessage += `\n` + noneDotEnvSecretsFound.map(secretLint_1.prettyPrintLintResult).join('\n');
1710
1710
  let hintMessage = `\nIn case of false positives, you can allow specific types of secrets with `;
1711
1711
  hintMessage += secretsFoundRuleNames.map(name => `--allow-package-secrets ${name}`).join(' ');
1712
1712
  hintMessage += ` or use --allow-package-all-secrets to skip this check entirely (not recommended).`;
1713
- util.log.error(errorMessage + chalk_1.default.italic(hintMessage));
1713
+ util.log.error(errorMessage + (0, util_2.styleText)('italic', hintMessage));
1714
1714
  process.exit(1);
1715
1715
  }
1716
1716
  // .env file found
1717
1717
  const allRuleIds = new Set(secretsFound.map(result => result.ruleId).filter(Boolean));
1718
1718
  if (!options.allowPackageEnvFile && allRuleIds.has('@secretlint/secretlint-rule-no-dotenv')) {
1719
- let errorMessage = `${chalk_1.default.bold.red('.env')} files should not be packaged.`;
1719
+ let errorMessage = `${(0, util_2.styleText)(['bold', 'red'], '.env')} files should not be packaged.`;
1720
1720
  switch (fileExclusion) {
1721
1721
  case FileExclusionType.None:
1722
- errorMessage += ` Ignore the file in your ${chalk_1.default.bold('.vscodeignore')} or exclude it from the package.json ${chalk_1.default.bold('files')} property.`;
1722
+ errorMessage += ` Ignore the file in your ${(0, util_2.styleText)('bold', '.vscodeignore')} or exclude it from the package.json ${(0, util_2.styleText)('bold', 'files')} property.`;
1723
1723
  break;
1724
1724
  case FileExclusionType.VSCodeIgnore:
1725
- errorMessage += ` Ignore the file in your ${chalk_1.default.bold('.vscodeignore')}.`;
1725
+ errorMessage += ` Ignore the file in your ${(0, util_2.styleText)('bold', '.vscodeignore')}.`;
1726
1726
  break;
1727
1727
  case FileExclusionType.PackageFiles:
1728
- errorMessage += ` Do not include the file in your package.json ${chalk_1.default.bold('files')} property.`;
1728
+ errorMessage += ` Do not include the file in your package.json ${(0, util_2.styleText)('bold', 'files')} property.`;
1729
1729
  break;
1730
1730
  }
1731
1731
  const hintMessage = `\nTo ignore this check, you can use --allow-package-env-file (not recommended).`;
1732
- util.log.error(errorMessage + chalk_1.default.italic(hintMessage));
1732
+ util.log.error(errorMessage + (0, util_2.styleText)('italic', hintMessage));
1733
1733
  process.exit(1);
1734
1734
  }
1735
1735
  }
package/out/publish.js CHANGED
@@ -32,9 +32,6 @@ var __importStar = (this && this.__importStar) || (function () {
32
32
  return result;
33
33
  };
34
34
  })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
35
  Object.defineProperty(exports, "__esModule", { value: true });
39
36
  exports.publish = publish;
40
37
  exports.unpublish = unpublish;
@@ -47,12 +44,12 @@ const store_1 = require("./store");
47
44
  const util_1 = require("./util");
48
45
  const zip_1 = require("./zip");
49
46
  const validation_1 = require("./validation");
50
- const form_data_1 = __importDefault(require("form-data"));
51
47
  const path_1 = require("path");
52
48
  const os_1 = require("os");
53
49
  const cockatiel_1 = require("cockatiel");
54
50
  const auth_1 = require("./auth");
55
51
  const oidc_1 = require("./oidc");
52
+ const multipart_1 = require("./multipart");
56
53
  async function withTemporaryPackage(fn) {
57
54
  const directory = await fs.promises.mkdtemp((0, path_1.join)((0, os_1.tmpdir)(), 'vsce-'));
58
55
  try {
@@ -143,7 +140,6 @@ async function publish(options = {}) {
143
140
  async function _publish(packagePath, sigzipPath, manifest, options) {
144
141
  const pat = await getPAT(manifest.publisher, options);
145
142
  const api = await (0, util_1.getGalleryAPI)(pat);
146
- const packageStream = fs.createReadStream(packagePath);
147
143
  const name = `${manifest.publisher}.${manifest.name}`;
148
144
  const description = options.target
149
145
  ? `${name} (${options.target}) v${manifest.version}`
@@ -172,11 +168,11 @@ async function _publish(packagePath, sigzipPath, manifest, options) {
172
168
  }
173
169
  }
174
170
  if (sigzipPath) {
175
- await _publishSignedPackage(api, (0, path_1.basename)(packagePath), packageStream, (0, path_1.basename)(sigzipPath), fs.createReadStream(sigzipPath), manifest);
171
+ await _publishSignedPackage(api, packagePath, sigzipPath, manifest);
176
172
  }
177
173
  else {
178
174
  try {
179
- await api.updateExtension(undefined, packageStream, manifest.publisher, manifest.name);
175
+ await api.updateExtension(undefined, fs.createReadStream(packagePath), manifest.publisher, manifest.name);
180
176
  }
181
177
  catch (err) {
182
178
  if (err.statusCode === 409) {
@@ -196,10 +192,10 @@ async function _publish(packagePath, sigzipPath, manifest, options) {
196
192
  }
197
193
  else {
198
194
  if (sigzipPath) {
199
- await _publishSignedPackage(api, (0, path_1.basename)(packagePath), packageStream, (0, path_1.basename)(sigzipPath), fs.createReadStream(sigzipPath), manifest);
195
+ await _publishSignedPackage(api, packagePath, sigzipPath, manifest);
200
196
  }
201
197
  else {
202
- await api.createExtension(undefined, packageStream);
198
+ await api.createExtension(undefined, fs.createReadStream(packagePath));
203
199
  }
204
200
  }
205
201
  }
@@ -217,23 +213,27 @@ async function _publish(packagePath, sigzipPath, manifest, options) {
217
213
  util_1.log.info(`Hub URL: ${(0, util_1.getHubUrl)(manifest.publisher, manifest.name)}`);
218
214
  util_1.log.done(`Published ${description}.`);
219
215
  }
220
- async function _publishSignedPackage(api, packageName, packageStream, sigzipName, sigzipStream, manifest) {
216
+ async function _publishSignedPackage(api, packagePath, sigzipPath, manifest) {
221
217
  const extensionType = 'Visual Studio Code';
222
- const form = new form_data_1.default();
223
- const lineBreak = '\r\n';
224
- form.setBoundary('0f411892-ef48-488f-89d3-4f0546e84723');
225
- form.append('vsix', packageStream, {
226
- header: `--${form.getBoundary()}${lineBreak}Content-Disposition: attachment; name=vsix; filename=\"${packageName}\"${lineBreak}Content-Type: application/octet-stream${lineBreak}${lineBreak}`
227
- });
228
- form.append('sigzip', sigzipStream, {
229
- header: `--${form.getBoundary()}${lineBreak}Content-Disposition: attachment; name=sigzip; filename=\"${sigzipName}\"${lineBreak}Content-Type: application/octet-stream${lineBreak}${lineBreak}`
230
- });
231
218
  const publishWithRetry = (0, cockatiel_1.retry)((0, cockatiel_1.handleWhen)(err => err.message.includes('timeout')), {
232
219
  maxAttempts: 3,
233
220
  backoff: new cockatiel_1.IterableBackoff([5_000, 10_000, 20_000])
234
221
  });
235
222
  return await publishWithRetry.execute(async () => {
236
- return await api.publishExtensionWithPublisherSignature(undefined, form, manifest.publisher, manifest.name, extensionType);
223
+ const form = (0, multipart_1.createMultipartStream)([
224
+ { name: 'vsix', filename: (0, path_1.basename)(packagePath), stream: fs.createReadStream(packagePath) },
225
+ { name: 'sigzip', filename: (0, path_1.basename)(sigzipPath), stream: fs.createReadStream(sigzipPath) },
226
+ ], '0f411892-ef48-488f-89d3-4f0546e84723');
227
+ try {
228
+ return await (0, multipart_1.runWithStreamError)(form, () => api.publishExtensionWithPublisherSignature(undefined, form, manifest.publisher, manifest.name, extensionType));
229
+ }
230
+ finally {
231
+ // Release the file handles when the request did not consume the whole form, which
232
+ // otherwise keeps the package locked until the process exits.
233
+ if (!form.readableEnded) {
234
+ form.destroy();
235
+ }
236
+ }
237
237
  });
238
238
  }
239
239
  async function unpublish(options = {}) {
package/out/secretLint.js CHANGED
@@ -32,19 +32,16 @@ var __importStar = (this && this.__importStar) || (function () {
32
32
  return result;
33
33
  };
34
34
  })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
35
  Object.defineProperty(exports, "__esModule", { value: true });
39
36
  exports.lintFiles = lintFiles;
40
37
  exports.lintText = lintText;
41
38
  exports.getRuleNameFromRuleId = getRuleNameFromRuleId;
42
39
  exports.prettyPrintLintResult = prettyPrintLintResult;
43
- const chalk_1 = __importDefault(require("chalk"));
44
40
  const os = __importStar(require("os"));
45
41
  const path = __importStar(require("path"));
42
+ const util_1 = require("util");
46
43
  const url_1 = require("url");
47
- const util_1 = require("./util");
44
+ const util_2 = require("./util");
48
45
  const secretsScanningRules = [
49
46
  {
50
47
  id: "@secretlint/secretlint-rule-preset-recommend",
@@ -133,7 +130,7 @@ async function lintFiles(filePaths, scanSecrets, scanDotEnv) {
133
130
  }));
134
131
  }
135
132
  catch (error) {
136
- util_1.log.error('Error occurred while scanning secrets (files):', error);
133
+ util_2.log.error('Error occurred while scanning secrets (files):', error);
137
134
  process.exit(1);
138
135
  }
139
136
  return parseResult(results);
@@ -159,7 +156,7 @@ async function lintText(content, fileName, scanSecrets, scanDotEnv) {
159
156
  });
160
157
  }
161
158
  catch (error) {
162
- util_1.log.error('Error occurred while scanning secrets (content):', error);
159
+ util_2.log.error('Error occurred while scanning secrets (content):', error);
163
160
  process.exit(1);
164
161
  }
165
162
  return parseResult([result]);
@@ -194,10 +191,9 @@ function getRuleNameFromRuleId(ruleId) {
194
191
  }
195
192
  function prettyPrintLintResult(result) {
196
193
  const text = result.message;
197
- const titleColor = result.level === "error" ? chalk_1.default.bold.red : chalk_1.default.bold.yellow;
198
194
  const title = text.length > 54 ? text.slice(0, 50) + '...' : text;
199
195
  const ruleName = getRuleNameFromRuleId(result.ruleId);
200
- let output = `\t${titleColor(title)} [${ruleName}]\n`;
196
+ let output = `\t${(0, util_1.styleText)(['bold', result.level === "error" ? 'red' : 'yellow'], title)} [${ruleName}]\n`;
201
197
  output += `\t${prettyPrintLocation(result)}\n`;
202
198
  return output;
203
199
  }
package/out/store.js CHANGED
@@ -47,6 +47,7 @@ const util_1 = require("./util");
47
47
  const validation_1 = require("./validation");
48
48
  const package_1 = require("./package");
49
49
  const publish_1 = require("./publish");
50
+ const keytarMigration_1 = require("./keytarMigration");
50
51
  ;
51
52
  class FileStore {
52
53
  path;
@@ -105,8 +106,7 @@ class KeytarStore {
105
106
  keytar;
106
107
  serviceName;
107
108
  publishers;
108
- static async open(serviceName = 'vscode-vsce') {
109
- const keytar = require('@napi-rs/keyring/keytar.js');
109
+ static async open(serviceName = 'vscode-vsce', keytar = require('@napi-rs/keyring/keytar.js')) {
110
110
  const creds = await keytar.findCredentials(serviceName);
111
111
  return new KeytarStore(keytar, serviceName, creds.map(({ account, password }) => ({ name: account, pat: password })));
112
112
  }
@@ -122,12 +122,14 @@ class KeytarStore {
122
122
  return this.publishers.filter(p => p.name === name)[0];
123
123
  }
124
124
  async add(publisher) {
125
- this.publishers = [...this.publishers.filter(p => p.name !== publisher.name), publisher];
126
125
  await this.keytar.setPassword(this.serviceName, publisher.name, publisher.pat);
126
+ this.publishers = [...this.publishers.filter(p => p.name !== publisher.name), publisher];
127
127
  }
128
128
  async delete(name) {
129
+ if (!await this.keytar.deletePassword(this.serviceName, name)) {
130
+ throw new Error(`Could not remove the saved PAT for publisher '${name}'.`);
131
+ }
129
132
  this.publishers = this.publishers.filter(p => p.name !== name);
130
- await this.keytar.deletePassword(this.serviceName, name);
131
133
  }
132
134
  [Symbol.iterator]() {
133
135
  return this.publishers[Symbol.iterator]();
@@ -171,6 +173,7 @@ async function openDefaultStore() {
171
173
  util_1.log.warn(`Failed to open credential store. Falling back to storing secrets clear-text in: ${store.path}`);
172
174
  return store;
173
175
  }
176
+ keytarStore = keytarMigration_1.LegacyCredentialMigration.wrap(keytarStore, () => KeytarStore.open());
174
177
  const fileStore = await FileStore.open();
175
178
  // migrate from file store
176
179
  if (fileStore.size) {
@@ -185,7 +188,7 @@ async function openDefaultStore() {
185
188
  async function getPublisher(publisherName) {
186
189
  (0, validation_1.validatePublisher)(publisherName);
187
190
  const store = await openDefaultStore();
188
- let publisher = store.get(publisherName);
191
+ let publisher = store.get(publisherName) ?? await store.tryMigratePublisher?.(publisherName);
189
192
  if (publisher) {
190
193
  return publisher;
191
194
  }
@@ -205,6 +208,12 @@ async function loginPublisher(publisherName) {
205
208
  throw new Error('Aborted');
206
209
  }
207
210
  }
211
+ else {
212
+ publisher = await store.tryMigratePublisher?.(publisherName);
213
+ if (publisher) {
214
+ return publisher;
215
+ }
216
+ }
208
217
  const pat = await requestPAT(publisherName);
209
218
  publisher = { name: publisherName, pat };
210
219
  await store.add(publisher);
package/out/util.js CHANGED
@@ -48,6 +48,8 @@ exports.normalize = normalize;
48
48
  exports.chain = chain;
49
49
  exports.flatten = flatten;
50
50
  exports.nonnull = nonnull;
51
+ exports.levenshtein = levenshtein;
52
+ exports.findSimilar = findSimilar;
51
53
  exports.isCancelledError = isCancelledError;
52
54
  exports.sequence = sequence;
53
55
  exports.patchOptionsWithManifest = patchOptionsWithManifest;
@@ -60,7 +62,6 @@ const fs = __importStar(require("fs"));
60
62
  const read_1 = __importDefault(require("read"));
61
63
  const WebApi_1 = require("azure-devops-node-api/WebApi");
62
64
  const GalleryApi_1 = require("azure-devops-node-api/GalleryApi");
63
- const chalk_1 = __importDefault(require("chalk"));
64
65
  const publicgalleryapi_1 = require("./publicgalleryapi");
65
66
  const os_1 = require("os");
66
67
  const __read = (0, util_1.promisify)(read_1.default);
@@ -113,6 +114,51 @@ function flatten(arr) {
113
114
  function nonnull(arg) {
114
115
  return !!arg;
115
116
  }
117
+ /**
118
+ * Computes the Levenshtein distance between `a` and `b`, ie. the minimum number of
119
+ * single character insertions, deletions or substitutions needed to turn one into the
120
+ * other. Comparison happens on UTF-16 code units.
121
+ */
122
+ function levenshtein(a, b) {
123
+ if (a === b) {
124
+ return 0;
125
+ }
126
+ // The distance is symmetric, so keep the shorter string in `b` to bound the row size.
127
+ if (b.length > a.length) {
128
+ [a, b] = [b, a];
129
+ }
130
+ // A single row of the edit distance matrix, seeded with the distance between the
131
+ // empty prefix of `a` and every prefix of `b`.
132
+ const row = Array.from({ length: b.length + 1 }, (_, j) => j);
133
+ for (let i = 1; i <= a.length; i++) {
134
+ // The value of `row[j - 1]` before this row started being overwritten.
135
+ let diagonal = row[0];
136
+ row[0] = i;
137
+ for (let j = 1; j <= b.length; j++) {
138
+ const above = row[j];
139
+ row[j] = Math.min(row[j - 1] + 1, above + 1, diagonal + (a[i - 1] === b[j - 1] ? 0 : 1));
140
+ diagonal = above;
141
+ }
142
+ }
143
+ return row[b.length];
144
+ }
145
+ /**
146
+ * Returns the candidate closest to `target`, or `undefined` when none of them is a
147
+ * plausible correction of it. A candidate qualifies when fewer than 40% of the characters
148
+ * of `target` have to be edited to reach it; ties are broken by iteration order.
149
+ */
150
+ function findSimilar(target, candidates) {
151
+ let best;
152
+ let bestDistance = Math.ceil(target.length * 0.4);
153
+ for (const candidate of candidates) {
154
+ const distance = levenshtein(candidate, target);
155
+ if (distance < bestDistance) {
156
+ best = candidate;
157
+ bestDistance = distance;
158
+ }
159
+ }
160
+ return best;
161
+ }
116
162
  const CancelledError = 'Cancelled';
117
163
  function isCancelledError(error) {
118
164
  return error === CancelledError;
@@ -155,10 +201,10 @@ var LogMessageType;
155
201
  LogMessageType[LogMessageType["ERROR"] = 3] = "ERROR";
156
202
  })(LogMessageType || (LogMessageType = {}));
157
203
  const LogPrefix = {
158
- [LogMessageType.DONE]: chalk_1.default.bgGreen.black(' DONE '),
159
- [LogMessageType.INFO]: chalk_1.default.bgBlueBright.black(' INFO '),
160
- [LogMessageType.WARNING]: chalk_1.default.bgYellow.black(' WARNING '),
161
- [LogMessageType.ERROR]: chalk_1.default.bgRed.black(' ERROR '),
204
+ [LogMessageType.DONE]: (0, util_1.styleText)(['bgGreen', 'black'], ' DONE '),
205
+ [LogMessageType.INFO]: (0, util_1.styleText)(['bgBlueBright', 'black'], ' INFO '),
206
+ [LogMessageType.WARNING]: (0, util_1.styleText)(['bgYellow', 'black'], ' WARNING '),
207
+ [LogMessageType.ERROR]: (0, util_1.styleText)(['bgRed', 'black'], ' ERROR '),
162
208
  };
163
209
  function _log(type, msg, ...args) {
164
210
  args = [LogPrefix[type], msg, ...args];
@@ -303,11 +349,11 @@ async function generateFileStructureTree(rootFolder, filePaths, printLinesLimit
303
349
  });
304
350
  });
305
351
  let output = [];
306
- output.push(chalk_1.default.bold(rootFolder));
352
+ output.push((0, util_1.styleText)('bold', rootFolder));
307
353
  output.push(...createTreeOutput(folderTree, maxDepth, totalFileSizes));
308
354
  for (const [size, filePath] of fileSizes) {
309
355
  if (size > FILE_SIZE_WARNING_THRESHOLD * totalFileSizes) {
310
- output.push(`\nThe file ${filePath} is ${chalk_1.default.red('large')} (${bytesToString(size)})`);
356
+ output.push(`\nThe file ${filePath} is ${(0, util_1.styleText)('red', 'large')} (${bytesToString(size)})`);
311
357
  break;
312
358
  }
313
359
  }
@@ -316,20 +362,20 @@ async function generateFileStructureTree(rootFolder, filePaths, printLinesLimit
316
362
  function createTreeOutput(fileSystem, maxDepth, totalFileSizes) {
317
363
  const getColorFromSize = (size) => {
318
364
  if (size > FILE_SIZE_WARNING_THRESHOLD * totalFileSizes) {
319
- return chalk_1.default.red;
365
+ return 'red';
320
366
  }
321
367
  else if (size > FILE_SIZE_LARGE_THRESHOLD * totalFileSizes) {
322
- return chalk_1.default.yellow;
368
+ return 'yellow';
323
369
  }
324
370
  else {
325
- return chalk_1.default.grey;
371
+ return 'gray';
326
372
  }
327
373
  };
328
374
  const createFileOutput = (prefix, fileName, fileSize) => {
329
375
  let fileSizeColored = '';
330
376
  if (fileSize > 0) {
331
377
  const fileSizeString = `[${bytesToString(fileSize)}]`;
332
- fileSizeColored = getColorFromSize(fileSize)(fileSizeString);
378
+ fileSizeColored = (0, util_1.styleText)(getColorFromSize(fileSize), fileSizeString);
333
379
  }
334
380
  return `${prefix}${fileName} ${fileSizeColored}`;
335
381
  };
@@ -337,14 +383,14 @@ function createTreeOutput(fileSystem, maxDepth, totalFileSizes) {
337
383
  if (depth < maxDepth) {
338
384
  // Max depth is not reached, print only the folder
339
385
  // as children will be printed
340
- return prefix + chalk_1.default.bold(`${folderName}/`);
386
+ return prefix + (0, util_1.styleText)('bold', `${folderName}/`);
341
387
  }
342
388
  // Max depth is reached, print the folder name and additional metadata
343
389
  // as children will not be printed
344
390
  const folderSizeString = bytesToString(folderSize);
345
- const folder = chalk_1.default.bold(`${folderName}/`);
346
- const numFilesString = chalk_1.default.green(`(${filesCount} ${filesCount === 1 ? 'file' : 'files'})`);
347
- const folderSizeColored = getColorFromSize(folderSize)(`[${folderSizeString}]`);
391
+ const folder = (0, util_1.styleText)('bold', `${folderName}/`);
392
+ const numFilesString = (0, util_1.styleText)('green', `(${filesCount} ${filesCount === 1 ? 'file' : 'files'})`);
393
+ const folderSizeColored = (0, util_1.styleText)(getColorFromSize(folderSize), `[${folderSizeString}]`);
348
394
  return `${prefix}${folder} ${numFilesString} ${folderSizeColored}`;
349
395
  };
350
396
  const createTreeLayerOutput = (tree, depth, prefix, path) => {
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.windowsKeytarReadScript = void 0;
4
+ // Read keytar's UTF-8 credentials without constructing a keyring Entry.withTarget,
5
+ // which overwrites the target credential even when only used to read a secret.
6
+ exports.windowsKeytarReadScript = String.raw `
7
+ $ErrorActionPreference = 'Stop'
8
+ [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)
9
+ Add-Type -TypeDefinition @'
10
+ using System;
11
+ using System.ComponentModel;
12
+ using System.Runtime.InteropServices;
13
+ using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
14
+ using System.Text;
15
+
16
+ public static class VsceKeytarReader {
17
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
18
+ private struct Credential {
19
+ public uint Flags;
20
+ public uint Type;
21
+ public string TargetName;
22
+ public string Comment;
23
+ public FILETIME LastWritten;
24
+ public uint CredentialBlobSize;
25
+ public IntPtr CredentialBlob;
26
+ public uint Persist;
27
+ public uint AttributeCount;
28
+ public IntPtr Attributes;
29
+ public string TargetAlias;
30
+ public string UserName;
31
+ }
32
+
33
+ public class Publisher {
34
+ public string name;
35
+ public string pat;
36
+ }
37
+
38
+ [DllImport("advapi32.dll", EntryPoint = "CredReadW", CharSet = CharSet.Unicode, SetLastError = true)]
39
+ [return: MarshalAs(UnmanagedType.Bool)]
40
+ private static extern bool CredRead(string target, uint type, uint flags, out IntPtr credential);
41
+
42
+ [DllImport("advapi32.dll")]
43
+ private static extern void CredFree(IntPtr credentials);
44
+
45
+ public static Publisher Read(string service, string account) {
46
+ IntPtr pointer;
47
+ if (!CredRead(service + "/" + account, 1, 0, out pointer)) {
48
+ int error = Marshal.GetLastWin32Error();
49
+ if (error == 1168) {
50
+ return null;
51
+ }
52
+ throw new Win32Exception(error);
53
+ }
54
+
55
+ try {
56
+ var credential = (Credential)Marshal.PtrToStructure(pointer, typeof(Credential));
57
+ if (!String.Equals(credential.UserName, account, StringComparison.OrdinalIgnoreCase)) {
58
+ throw new InvalidOperationException("The credential account does not match.");
59
+ }
60
+ var secret = new byte[checked((int)credential.CredentialBlobSize)];
61
+ try {
62
+ if (secret.Length > 0) {
63
+ Marshal.Copy(credential.CredentialBlob, secret, 0, secret.Length);
64
+ }
65
+ return new Publisher {
66
+ name = credential.UserName,
67
+ pat = new UTF8Encoding(false, true).GetString(secret)
68
+ };
69
+ } finally {
70
+ Array.Clear(secret, 0, secret.Length);
71
+ }
72
+ } finally {
73
+ CredFree(pointer);
74
+ }
75
+ }
76
+ }
77
+ '@
78
+ $credential = [VsceKeytarReader]::Read($env:VSCE_KEYTAR_SERVICE, $env:VSCE_KEYTAR_ACCOUNT)
79
+ if ($null -eq $credential) {
80
+ [Console]::WriteLine('null')
81
+ } else {
82
+ ConvertTo-Json -InputObject $credential -Compress
83
+ }
84
+ `;
85
+ //# sourceMappingURL=windowsKeytar.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vscode/vsce",
3
- "version": "3.9.3-10",
3
+ "version": "3.9.3-12",
4
4
  "description": "VS Code Extensions Manager",
5
5
  "repository": {
6
6
  "type": "git",
@@ -39,51 +39,50 @@
39
39
  "node": ">= 22"
40
40
  },
41
41
  "dependencies": {
42
- "@azure/identity": "^4.1.0",
42
+ "@azure/identity": "^4.13.2",
43
43
  "@napi-rs/keyring": "^1.3.0",
44
- "@secretlint/core": "^10.1.2",
45
- "@secretlint/secretlint-rule-no-dotenv": "^10.1.2",
46
- "@secretlint/secretlint-rule-preset-recommend": "^10.1.2",
47
- "@secretlint/source-creator": "^10.1.2",
48
- "@secretlint/types": "^10.1.2",
49
- "@vscode/vsce-sign": "^2.0.0",
44
+ "@secretlint/core": "^10.2.2",
45
+ "@secretlint/secretlint-rule-no-dotenv": "^10.2.2",
46
+ "@secretlint/secretlint-rule-preset-recommend": "^10.2.2",
47
+ "@secretlint/source-creator": "^10.2.2",
48
+ "@secretlint/types": "^10.2.2",
49
+ "@vscode/vsce-sign": "^2.1.0",
50
50
  "azure-devops-node-api": "^12.5.0",
51
- "chalk": "^4.1.2",
52
- "cockatiel": "^3.1.2",
51
+ "cockatiel": "^3.2.1",
53
52
  "commander": "^12.1.0",
54
- "form-data": "^4.0.0",
55
- "hosted-git-info": "^4.0.2",
56
- "jsonc-parser": "^3.2.0",
57
- "leven": "^3.1.0",
58
- "marked": "^18.0.10",
59
- "mime": "^1.3.4",
60
- "minimatch": "^10.2.2",
53
+ "hosted-git-info": "^4.1.0",
54
+ "jsonc-parser": "^3.3.1",
55
+ "marked": "^18.0.11",
56
+ "mime": "^1.6.0",
57
+ "minimatch": "^10.2.6",
61
58
  "parse5": "^8.0.1",
59
+ "proper-lockfile": "^4.1.2",
62
60
  "read": "^1.0.7",
63
- "semver": "^7.5.2",
61
+ "semver": "^7.8.5",
64
62
  "tinyglobby": "^0.2.17",
65
- "typed-rest-client": "^1.8.4",
63
+ "typed-rest-client": "^1.8.11",
66
64
  "url-join": "^4.0.1",
67
65
  "xml2js": "^0.5.0",
68
- "yauzl": "^3.2.1",
69
- "yazl": "^2.2.2"
66
+ "yauzl": "^3.4.0",
67
+ "yazl": "^2.5.1"
70
68
  },
71
69
  "devDependencies": {
72
- "@microsoft/api-extractor": "^7.33.7",
73
- "@types/hosted-git-info": "^3.0.2",
74
- "@types/mime": "^1",
70
+ "@microsoft/api-extractor": "^7.59.0",
71
+ "@types/hosted-git-info": "^3.0.5",
72
+ "@types/mime": "^1.3.5",
75
73
  "@types/mocha": "^7.0.2",
76
- "@types/node": "^22.0.0",
74
+ "@types/node": "^22.20.1",
77
75
  "@types/picomatch": "^4.0.3",
76
+ "@types/proper-lockfile": "^4.1.4",
78
77
  "@types/read": "^0.0.28",
79
- "@types/semver": "^6.0.0",
80
- "@types/url-join": "^4.0.1",
81
- "@types/xml2js": "^0.4.4",
82
- "@types/yauzl": "^2.9.2",
83
- "@types/yazl": "^2.4.2",
84
- "mocha": "^11.1.0",
85
- "ts-node": "^10.9.1",
86
- "typescript": "~5.9.0"
78
+ "@types/semver": "^6.2.7",
79
+ "@types/url-join": "^4.0.3",
80
+ "@types/xml2js": "^0.4.14",
81
+ "@types/yauzl": "^2.10.3",
82
+ "@types/yazl": "^2.4.6",
83
+ "mocha": "^11.8.0",
84
+ "ts-node": "^10.9.2",
85
+ "typescript": "~5.9.3"
87
86
  },
88
87
  "mocha": {
89
88
  "require": [
@@ -94,6 +93,7 @@
94
93
  },
95
94
  "overrides": {
96
95
  "serialize-javascript": "7.x",
97
- "diff": "^9.0.0"
96
+ "diff": "^9.0.0",
97
+ "@azure/msal-common": "16.14.0"
98
98
  }
99
99
  }