@servicetitan/install 36.1.2-canary.4 → 36.1.2-canary.6

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.
Files changed (54) hide show
  1. package/dist/cli/index.js +31 -11
  2. package/dist/cli/index.js.map +1 -1
  3. package/dist/cli/install.d.ts +4 -0
  4. package/dist/cli/install.d.ts.map +1 -1
  5. package/dist/cli/install.js +35 -9
  6. package/dist/cli/install.js.map +1 -1
  7. package/dist/package-manager/__mocks__/index.d.ts +2 -0
  8. package/dist/package-manager/__mocks__/index.d.ts.map +1 -0
  9. package/dist/package-manager/__mocks__/mock-package-manager.d.ts +1 -0
  10. package/dist/package-manager/__mocks__/mock-package-manager.d.ts.map +1 -1
  11. package/dist/package-manager/index.d.ts +1 -1
  12. package/dist/package-manager/index.d.ts.map +1 -1
  13. package/dist/package-manager/index.js.map +1 -1
  14. package/dist/package-manager/npm-package-manager.d.ts +5 -1
  15. package/dist/package-manager/npm-package-manager.d.ts.map +1 -1
  16. package/dist/package-manager/npm-package-manager.js +42 -2
  17. package/dist/package-manager/npm-package-manager.js.map +1 -1
  18. package/dist/package-manager/package-manager.d.ts +3 -1
  19. package/dist/package-manager/package-manager.d.ts.map +1 -1
  20. package/dist/package-manager/package-manager.js +1 -3
  21. package/dist/package-manager/package-manager.js.map +1 -1
  22. package/dist/package-manager/pnpm-package-manager.d.ts +1 -0
  23. package/dist/package-manager/pnpm-package-manager.d.ts.map +1 -1
  24. package/dist/package-manager/pnpm-package-manager.js +7 -1
  25. package/dist/package-manager/pnpm-package-manager.js.map +1 -1
  26. package/dist/utils/get-packages-with-install-scripts.d.ts +8 -0
  27. package/dist/utils/get-packages-with-install-scripts.d.ts.map +1 -0
  28. package/dist/utils/get-packages-with-install-scripts.js +34 -0
  29. package/dist/utils/get-packages-with-install-scripts.js.map +1 -0
  30. package/dist/utils/has-lockfile-changed.d.ts +2 -0
  31. package/dist/utils/has-lockfile-changed.d.ts.map +1 -0
  32. package/dist/utils/has-lockfile-changed.js +27 -0
  33. package/dist/utils/has-lockfile-changed.js.map +1 -0
  34. package/dist/utils/index.d.ts +3 -0
  35. package/dist/utils/index.d.ts.map +1 -1
  36. package/dist/utils/index.js +3 -0
  37. package/dist/utils/index.js.map +1 -1
  38. package/dist/utils/warn-untrusted-install-scripts.d.ts +2 -0
  39. package/dist/utils/warn-untrusted-install-scripts.d.ts.map +1 -0
  40. package/dist/utils/warn-untrusted-install-scripts.js +52 -0
  41. package/dist/utils/warn-untrusted-install-scripts.js.map +1 -0
  42. package/package.json +9 -1
  43. package/src/cli/index.ts +27 -8
  44. package/src/cli/install.ts +34 -8
  45. package/src/package-manager/__mocks__/index.ts +1 -0
  46. package/src/package-manager/__mocks__/mock-package-manager.ts +2 -0
  47. package/src/package-manager/index.ts +1 -1
  48. package/src/package-manager/npm-package-manager.ts +43 -2
  49. package/src/package-manager/package-manager.ts +7 -4
  50. package/src/package-manager/pnpm-package-manager.ts +9 -1
  51. package/src/utils/get-packages-with-install-scripts.ts +24 -0
  52. package/src/utils/has-lockfile-changed.ts +10 -0
  53. package/src/utils/index.ts +3 -0
  54. package/src/utils/warn-untrusted-install-scripts.ts +46 -0
package/dist/cli/index.js CHANGED
@@ -6,9 +6,20 @@ const _util = require("util");
6
6
  const _utils = require("../utils");
7
7
  const _install = require("./install");
8
8
  const args = function getArgs() {
9
- const { values, tokens } = (0, _util.parseArgs)({
9
+ var _result, _allowScripts;
10
+ const { tokens } = (0, _util.parseArgs)({
10
11
  args: process.argv.slice(2),
11
12
  options: {
13
+ 'allow-scripts': {
14
+ type: 'string',
15
+ multiple: true
16
+ },
17
+ 'no-allow-scripts': {
18
+ type: 'boolean'
19
+ },
20
+ 'allow-all-scripts': {
21
+ type: 'boolean'
22
+ },
12
23
  'fix': {
13
24
  type: 'boolean'
14
25
  },
@@ -24,21 +35,30 @@ const args = function getArgs() {
24
35
  },
25
36
  tokens: true
26
37
  });
38
+ const result = {};
39
+ const allowScripts = [];
27
40
  tokens.forEach((token)=>{
28
41
  if (token.kind === 'option') {
29
- if (token.name.startsWith('no-')) {
30
- const name = token.name.slice(3);
31
- values[name] = false;
32
- delete values[token.name];
33
- } else {
34
- var _token_value;
35
- values[token.name] = (_token_value = token.value) !== null && _token_value !== void 0 ? _token_value : true;
42
+ switch(token.name){
43
+ case 'allow-scripts':
44
+ allowScripts.push(token.value);
45
+ break;
46
+ case 'no-allow-scripts':
47
+ result.allowScripts = false;
48
+ break;
49
+ case 'allow-all-scripts':
50
+ result.allowAllScripts = true;
51
+ break;
52
+ case 'no-token':
53
+ result.token = false;
54
+ break;
55
+ default:
56
+ result[token.name] = true;
36
57
  }
37
58
  }
38
59
  });
39
- return {
40
- ...values
41
- };
60
+ (_allowScripts = (_result = result).allowScripts) !== null && _allowScripts !== void 0 ? _allowScripts : _result.allowScripts = allowScripts;
61
+ return result;
42
62
  }();
43
63
  (0, _utils.debug)('install:args', {
44
64
  args
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/index.ts"],"sourcesContent":["import { parseArgs } from 'util';\nimport { debug } from '../utils';\nimport { Install } from './install';\n\nconst args = (function getArgs() {\n const { values, tokens } = parseArgs({\n args: process.argv.slice(2),\n options: {\n 'fix': { type: 'boolean' },\n 'quiet': { type: 'boolean' },\n 'token': { type: 'boolean' },\n 'no-token': { type: 'boolean' },\n },\n tokens: true,\n });\n\n tokens.forEach(token => {\n if (token.kind === 'option') {\n if (token.name.startsWith('no-')) {\n const name = token.name.slice(3) as keyof typeof values;\n values[name] = false;\n delete values[token.name];\n } else {\n values[token.name] = token.value ?? true;\n }\n }\n });\n\n return { ...values };\n})();\n\ndebug('install:args', { args });\n\nnew Install(args).execute();\n"],"names":["args","getArgs","values","tokens","parseArgs","process","argv","slice","options","type","forEach","token","kind","name","startsWith","value","debug","Install","execute"],"mappings":";;;;sBAA0B;uBACJ;yBACE;AAExB,MAAMA,OAAO,AAAC,SAASC;IACnB,MAAM,EAAEC,MAAM,EAAEC,MAAM,EAAE,GAAGC,IAAAA,eAAS,EAAC;QACjCJ,MAAMK,QAAQC,IAAI,CAACC,KAAK,CAAC;QACzBC,SAAS;YACL,OAAO;gBAAEC,MAAM;YAAU;YACzB,SAAS;gBAAEA,MAAM;YAAU;YAC3B,SAAS;gBAAEA,MAAM;YAAU;YAC3B,YAAY;gBAAEA,MAAM;YAAU;QAClC;QACAN,QAAQ;IACZ;IAEAA,OAAOO,OAAO,CAACC,CAAAA;QACX,IAAIA,MAAMC,IAAI,KAAK,UAAU;YACzB,IAAID,MAAME,IAAI,CAACC,UAAU,CAAC,QAAQ;gBAC9B,MAAMD,OAAOF,MAAME,IAAI,CAACN,KAAK,CAAC;gBAC9BL,MAAM,CAACW,KAAK,GAAG;gBACf,OAAOX,MAAM,CAACS,MAAME,IAAI,CAAC;YAC7B,OAAO;oBACkBF;gBAArBT,MAAM,CAACS,MAAME,IAAI,CAAC,IAAGF,eAAAA,MAAMI,KAAK,cAAXJ,0BAAAA,eAAe;YACxC;QACJ;IACJ;IAEA,OAAO;QAAE,GAAGT,MAAM;IAAC;AACvB;AAEAc,IAAAA,YAAK,EAAC,gBAAgB;IAAEhB;AAAK;AAE7B,IAAIiB,gBAAO,CAACjB,MAAMkB,OAAO"}
1
+ {"version":3,"sources":["../../src/cli/index.ts"],"sourcesContent":["import { parseArgs } from 'util';\nimport { debug } from '../utils';\nimport type { Args } from './install';\nimport { Install } from './install';\n\nconst args = (function getArgs() {\n const { tokens } = parseArgs({\n args: process.argv.slice(2),\n options: {\n 'allow-scripts': { type: 'string', multiple: true },\n 'no-allow-scripts': { type: 'boolean' },\n 'allow-all-scripts': { type: 'boolean' },\n 'fix': { type: 'boolean' },\n 'quiet': { type: 'boolean' },\n 'token': { type: 'boolean' },\n 'no-token': { type: 'boolean' },\n },\n tokens: true,\n });\n\n const result: Args = {};\n\n const allowScripts: string[] = [];\n\n tokens.forEach(token => {\n if (token.kind === 'option') {\n switch (token.name) {\n case 'allow-scripts':\n allowScripts.push(token.value);\n break;\n case 'no-allow-scripts':\n result.allowScripts = false;\n break;\n case 'allow-all-scripts':\n result.allowAllScripts = true;\n break;\n case 'no-token':\n result.token = false;\n break;\n default:\n result[token.name] = true;\n }\n }\n });\n\n result.allowScripts ??= allowScripts;\n\n return result;\n})();\n\ndebug('install:args', { args });\n\nnew Install(args).execute();\n"],"names":["args","getArgs","result","tokens","parseArgs","process","argv","slice","options","type","multiple","allowScripts","forEach","token","kind","name","push","value","allowAllScripts","debug","Install","execute"],"mappings":";;;;sBAA0B;uBACJ;yBAEE;AAExB,MAAMA,OAAO,AAAC,SAASC;QAwCnBC,SAAAA;IAvCA,MAAM,EAAEC,MAAM,EAAE,GAAGC,IAAAA,eAAS,EAAC;QACzBJ,MAAMK,QAAQC,IAAI,CAACC,KAAK,CAAC;QACzBC,SAAS;YACL,iBAAiB;gBAAEC,MAAM;gBAAUC,UAAU;YAAK;YAClD,oBAAoB;gBAAED,MAAM;YAAU;YACtC,qBAAqB;gBAAEA,MAAM;YAAU;YACvC,OAAO;gBAAEA,MAAM;YAAU;YACzB,SAAS;gBAAEA,MAAM;YAAU;YAC3B,SAAS;gBAAEA,MAAM;YAAU;YAC3B,YAAY;gBAAEA,MAAM;YAAU;QAClC;QACAN,QAAQ;IACZ;IAEA,MAAMD,SAAe,CAAC;IAEtB,MAAMS,eAAyB,EAAE;IAEjCR,OAAOS,OAAO,CAACC,CAAAA;QACX,IAAIA,MAAMC,IAAI,KAAK,UAAU;YACzB,OAAQD,MAAME,IAAI;gBACd,KAAK;oBACDJ,aAAaK,IAAI,CAACH,MAAMI,KAAK;oBAC7B;gBACJ,KAAK;oBACDf,OAAOS,YAAY,GAAG;oBACtB;gBACJ,KAAK;oBACDT,OAAOgB,eAAe,GAAG;oBACzB;gBACJ,KAAK;oBACDhB,OAAOW,KAAK,GAAG;oBACf;gBACJ;oBACIX,MAAM,CAACW,MAAME,IAAI,CAAC,GAAG;YAC7B;QACJ;IACJ;KAEAb,gBAAAA,CAAAA,UAAAA,QAAOS,YAAY,cAAnBT,2BAAAA,gBAAAA,QAAOS,YAAY,GAAKA;IAExB,OAAOT;AACX;AAEAiB,IAAAA,YAAK,EAAC,gBAAgB;IAAEnB;AAAK;AAE7B,IAAIoB,gBAAO,CAACpB,MAAMqB,OAAO"}
@@ -1,4 +1,6 @@
1
1
  export interface Args {
2
+ allowAllScripts?: boolean;
3
+ allowScripts?: string[] | false;
2
4
  fix?: boolean;
3
5
  quiet?: boolean;
4
6
  token?: boolean;
@@ -10,5 +12,7 @@ export declare class Install {
10
12
  private configureNpmToken;
11
13
  private fetchNpmToken;
12
14
  private installPackages;
15
+ private log;
16
+ private parseScripts;
13
17
  }
14
18
  //# sourceMappingURL=install.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/cli/install.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,IAAI;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,qBAAa,OAAO;IAChB,IAAI,EAAE,IAAI,CAAC;gBAEC,IAAI,EAAE,IAAI;IAItB,OAAO;IASP,OAAO,CAAC,iBAAiB;IA0CzB,OAAO,CAAC,aAAa;IAmCrB,OAAO,CAAC,eAAe;CAa1B"}
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/cli/install.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,IAAI;IACjB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;IAChC,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,qBAAa,OAAO;IAChB,IAAI,EAAE,IAAI,CAAC;gBAEC,IAAI,EAAE,IAAI;IAItB,OAAO;IAOP,OAAO,CAAC,iBAAiB;IAwCzB,OAAO,CAAC,aAAa;IAmCrB,OAAO,CAAC,eAAe;IA4BvB,OAAO,CAAC,GAAG;IAMX,OAAO,CAAC,YAAY;CAMvB"}
@@ -35,11 +35,15 @@ const REPO_NAME = 'frontend-dev-config';
35
35
  const AUTH_TOKEN_KEY = '//registry.npmjs.org/:_authToken';
36
36
  const AUTH_TOKEN_REGEX = /^\/\/registry\.npmjs\.org\/:_authToken=\s*(?<authToken>.+)/m;
37
37
  const ENVIRONMENT_VARIABLE_REGEX = /\${(?<environmentVariable>[^}]+)}/;
38
+ const ALLOWED_SCRIPTS = [
39
+ '@servicetitan/startup',
40
+ 'cypress',
41
+ 'msw',
42
+ 'nx'
43
+ ];
38
44
  class Install {
39
45
  execute() {
40
- if (!this.args.quiet) {
41
- console.log(`install cli v${(0, _utils.getVersion)()}`);
42
- }
46
+ this.log(`install cli v${(0, _utils.getVersion)()}`);
43
47
  const env = this.configureNpmToken();
44
48
  this.installPackages(env);
45
49
  }
@@ -49,9 +53,7 @@ class Install {
49
53
  if ((0, _utils.isCI)() || this.args.fix || this.args.token === false) {
50
54
  return;
51
55
  }
52
- if (!this.args.quiet) {
53
- console.log('Configuring NPM token ...');
54
- }
56
+ this.log('Configuring NPM token ...');
55
57
  if (this.args.token !== true) {
56
58
  if ((0, _utils.npmWhoAmI)() === 'st-team') {
57
59
  return;
@@ -135,16 +137,40 @@ class Install {
135
137
  return;
136
138
  }
137
139
  const packageManager = (0, _packagemanager.getPackageManager)();
138
- if (!this.args.quiet) {
139
- console.log(`Running ${packageManager.command} install`);
140
+ this.log(`Running ${packageManager.command} install`);
141
+ let allowScripts;
142
+ if (this.args.allowAllScripts) {
143
+ this.log('Allowing all install scripts');
144
+ } else if (this.args.allowScripts === false) {
145
+ allowScripts = false;
146
+ } else {
147
+ allowScripts = [
148
+ ...ALLOWED_SCRIPTS
149
+ ];
150
+ if (Array.isArray(this.args.allowScripts)) {
151
+ const extra = this.parseScripts(this.args.allowScripts);
152
+ if (extra.length) {
153
+ this.log(`Allowing additional install scripts: ${extra.join(', ')}`);
154
+ }
155
+ allowScripts.push(...extra);
156
+ }
140
157
  }
141
158
  packageManager.installPackages({
142
- fix: this.args.fix
159
+ ...this.args,
160
+ allowScripts
143
161
  }, {
144
162
  env,
145
163
  stdio: 'inherit'
146
164
  });
147
165
  }
166
+ log(message) {
167
+ if (!this.args.quiet) {
168
+ console.log(message);
169
+ }
170
+ }
171
+ parseScripts(allowedScripts) {
172
+ return (allowedScripts !== null && allowedScripts !== void 0 ? allowedScripts : []).flatMap((s)=>s.split(',')).map((s)=>s.trim()).filter((s)=>!!s);
173
+ }
148
174
  constructor(args){
149
175
  _define_property(this, "args", void 0);
150
176
  this.args = args;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/install.ts"],"sourcesContent":["/* eslint-disable no-console */\nimport fs from 'fs';\nimport os from 'os';\nimport path from 'path';\nimport { getPackageManager } from '../package-manager';\nimport { debug, getVersion, gitCloneRepo, isCI, npmWhoAmI, readJson, runCommand } from '../utils';\n\nconst REPO_NAME = 'frontend-dev-config';\nconst AUTH_TOKEN_KEY = '//registry.npmjs.org/:_authToken';\nconst AUTH_TOKEN_REGEX = /^\\/\\/registry\\.npmjs\\.org\\/:_authToken=\\s*(?<authToken>.+)/m;\nconst ENVIRONMENT_VARIABLE_REGEX = /\\${(?<environmentVariable>[^}]+)}/;\n\nexport interface Args {\n fix?: boolean;\n quiet?: boolean;\n token?: boolean;\n}\n\nexport class Install {\n args: Args;\n\n constructor(args: Args) {\n this.args = args;\n }\n\n execute() {\n if (!this.args.quiet) {\n console.log(`install cli v${getVersion()}`);\n }\n\n const env = this.configureNpmToken();\n this.installPackages(env);\n }\n\n private configureNpmToken() {\n if (isCI() || this.args.fix || this.args.token === false) {\n return;\n }\n\n if (!this.args.quiet) {\n console.log('Configuring NPM token ...');\n }\n\n if (this.args.token !== true) {\n if (npmWhoAmI() === 'st-team') {\n return;\n }\n }\n\n const token = this.fetchNpmToken();\n if (!token) {\n return;\n }\n\n runCommand('npm', ['config', 'set', `${AUTH_TOKEN_KEY}=${token}`]);\n\n if (!fs.existsSync('.npmrc')) {\n return;\n }\n\n const npmrc = fs.readFileSync('.npmrc', 'utf-8');\n const { authToken } = AUTH_TOKEN_REGEX.exec(npmrc)?.groups ?? {};\n debug({ authToken });\n if (!authToken) {\n return;\n }\n\n const { environmentVariable } = ENVIRONMENT_VARIABLE_REGEX.exec(authToken)?.groups ?? {};\n debug({ environmentVariable });\n if (environmentVariable) {\n return { [environmentVariable]: token };\n }\n\n runCommand('npm', ['config', 'delete', '--location=project', AUTH_TOKEN_KEY]);\n }\n\n private fetchNpmToken() {\n const tempDirPath = fs.mkdtempSync(path.join(os.tmpdir(), 'st-install-'));\n try {\n if (!gitCloneRepo({ destination: tempDirPath, name: REPO_NAME })) {\n throw new Error(`could not clone servicetitan/${REPO_NAME}`);\n }\n\n const npmJson = readJson(path.join(tempDirPath, '.npm.json'));\n debug('install:fetch-npm-token', { npmJson });\n\n if (!((npmJson && typeof npmJson === 'object') || Array.isArray(npmJson))) {\n throw new Error('.npm.json is not an object');\n }\n\n const { readOnlyToken: authToken } = npmJson;\n if (!authToken) {\n throw new Error('.npm.json does not contain auth token');\n }\n\n if (typeof authToken !== 'string') {\n throw new Error('.npm.json auth token is not a string');\n }\n\n return Buffer.from(authToken, 'base64').toString('utf-8');\n } catch (e) {\n console.warn(String(e));\n } finally {\n try {\n fs.rmSync(tempDirPath, { recursive: true, force: true });\n } catch {\n // ignore\n }\n }\n }\n\n private installPackages(env?: Record<string, string>) {\n if (this.args.token) {\n return;\n }\n\n const packageManager = getPackageManager();\n\n if (!this.args.quiet) {\n console.log(`Running ${packageManager.command} install`);\n }\n\n packageManager.installPackages({ fix: this.args.fix }, { env, stdio: 'inherit' });\n }\n}\n"],"names":["Install","REPO_NAME","AUTH_TOKEN_KEY","AUTH_TOKEN_REGEX","ENVIRONMENT_VARIABLE_REGEX","execute","args","quiet","console","log","getVersion","env","configureNpmToken","installPackages","isCI","fix","token","npmWhoAmI","fetchNpmToken","runCommand","fs","existsSync","npmrc","readFileSync","authToken","exec","groups","debug","environmentVariable","tempDirPath","mkdtempSync","path","join","os","tmpdir","gitCloneRepo","destination","name","Error","npmJson","readJson","Array","isArray","readOnlyToken","Buffer","from","toString","e","warn","String","rmSync","recursive","force","packageManager","getPackageManager","command","stdio"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/cli/install.ts"],"sourcesContent":["/* eslint-disable no-console */\nimport fs from 'fs';\nimport os from 'os';\nimport path from 'path';\nimport { getPackageManager } from '../package-manager';\nimport { debug, getVersion, gitCloneRepo, isCI, npmWhoAmI, readJson, runCommand } from '../utils';\n\nconst REPO_NAME = 'frontend-dev-config';\nconst AUTH_TOKEN_KEY = '//registry.npmjs.org/:_authToken';\nconst AUTH_TOKEN_REGEX = /^\\/\\/registry\\.npmjs\\.org\\/:_authToken=\\s*(?<authToken>.+)/m;\nconst ENVIRONMENT_VARIABLE_REGEX = /\\${(?<environmentVariable>[^}]+)}/;\nconst ALLOWED_SCRIPTS = ['@servicetitan/startup', 'cypress', 'msw', 'nx'];\n\nexport interface Args {\n allowAllScripts?: boolean;\n allowScripts?: string[] | false;\n fix?: boolean;\n quiet?: boolean;\n token?: boolean;\n}\n\nexport class Install {\n args: Args;\n\n constructor(args: Args) {\n this.args = args;\n }\n\n execute() {\n this.log(`install cli v${getVersion()}`);\n\n const env = this.configureNpmToken();\n this.installPackages(env);\n }\n\n private configureNpmToken() {\n if (isCI() || this.args.fix || this.args.token === false) {\n return;\n }\n\n this.log('Configuring NPM token ...');\n\n if (this.args.token !== true) {\n if (npmWhoAmI() === 'st-team') {\n return;\n }\n }\n\n const token = this.fetchNpmToken();\n if (!token) {\n return;\n }\n\n runCommand('npm', ['config', 'set', `${AUTH_TOKEN_KEY}=${token}`]);\n\n if (!fs.existsSync('.npmrc')) {\n return;\n }\n\n const npmrc = fs.readFileSync('.npmrc', 'utf-8');\n const { authToken } = AUTH_TOKEN_REGEX.exec(npmrc)?.groups ?? {};\n debug({ authToken });\n if (!authToken) {\n return;\n }\n\n const { environmentVariable } = ENVIRONMENT_VARIABLE_REGEX.exec(authToken)?.groups ?? {};\n debug({ environmentVariable });\n if (environmentVariable) {\n return { [environmentVariable]: token };\n }\n\n runCommand('npm', ['config', 'delete', '--location=project', AUTH_TOKEN_KEY]);\n }\n\n private fetchNpmToken() {\n const tempDirPath = fs.mkdtempSync(path.join(os.tmpdir(), 'st-install-'));\n try {\n if (!gitCloneRepo({ destination: tempDirPath, name: REPO_NAME })) {\n throw new Error(`could not clone servicetitan/${REPO_NAME}`);\n }\n\n const npmJson = readJson(path.join(tempDirPath, '.npm.json'));\n debug('install:fetch-npm-token', { npmJson });\n\n if (!((npmJson && typeof npmJson === 'object') || Array.isArray(npmJson))) {\n throw new Error('.npm.json is not an object');\n }\n\n const { readOnlyToken: authToken } = npmJson;\n if (!authToken) {\n throw new Error('.npm.json does not contain auth token');\n }\n\n if (typeof authToken !== 'string') {\n throw new Error('.npm.json auth token is not a string');\n }\n\n return Buffer.from(authToken, 'base64').toString('utf-8');\n } catch (e) {\n console.warn(String(e));\n } finally {\n try {\n fs.rmSync(tempDirPath, { recursive: true, force: true });\n } catch {\n // ignore\n }\n }\n }\n\n private installPackages(env?: Record<string, string>) {\n if (this.args.token) {\n return;\n }\n\n const packageManager = getPackageManager();\n\n this.log(`Running ${packageManager.command} install`);\n\n let allowScripts: string[] | false | undefined;\n if (this.args.allowAllScripts) {\n this.log('Allowing all install scripts');\n } else if (this.args.allowScripts === false) {\n allowScripts = false;\n } else {\n allowScripts = [...ALLOWED_SCRIPTS];\n if (Array.isArray(this.args.allowScripts)) {\n const extra = this.parseScripts(this.args.allowScripts);\n if (extra.length) {\n this.log(`Allowing additional install scripts: ${extra.join(', ')}`);\n }\n allowScripts.push(...extra);\n }\n }\n\n packageManager.installPackages({ ...this.args, allowScripts }, { env, stdio: 'inherit' });\n }\n\n private log(message: string) {\n if (!this.args.quiet) {\n console.log(message);\n }\n }\n\n private parseScripts(allowedScripts: string[]) {\n return (allowedScripts ?? [])\n .flatMap(s => s.split(','))\n .map(s => s.trim())\n .filter(s => !!s);\n }\n}\n"],"names":["Install","REPO_NAME","AUTH_TOKEN_KEY","AUTH_TOKEN_REGEX","ENVIRONMENT_VARIABLE_REGEX","ALLOWED_SCRIPTS","execute","log","getVersion","env","configureNpmToken","installPackages","isCI","args","fix","token","npmWhoAmI","fetchNpmToken","runCommand","fs","existsSync","npmrc","readFileSync","authToken","exec","groups","debug","environmentVariable","tempDirPath","mkdtempSync","path","join","os","tmpdir","gitCloneRepo","destination","name","Error","npmJson","readJson","Array","isArray","readOnlyToken","Buffer","from","toString","e","console","warn","String","rmSync","recursive","force","packageManager","getPackageManager","command","allowScripts","allowAllScripts","extra","parseScripts","length","push","stdio","message","quiet","allowedScripts","flatMap","s","split","map","trim","filter"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export * from './mock-package-manager';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/package-manager/__mocks__/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC"}
@@ -9,5 +9,6 @@ export declare class MockPackageManager extends PackageManager {
9
9
  getResolvedVersion(_query: ResolvedVersionQuery): string | undefined;
10
10
  protected getInstallArgs(): string[];
11
11
  protected parseLockFile(): unknown;
12
+ protected postInstall(): void;
12
13
  }
13
14
  //# sourceMappingURL=mock-package-manager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mock-package-manager.d.ts","sourceRoot":"","sources":["../../../src/package-manager/__mocks__/mock-package-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAErF,qBAAa,kBAAmB,SAAQ,cAAc;IAClD,QAAQ,CAAC,OAAO,UAAU;IAC1B,QAAQ,CAAC,YAAY,oBAAoB;IACzC,QAAQ,CAAC,WAAW,WAAe;IAEnC,UAAU;IAEV,kBAAkB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS;IAIpE,kBAAkB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS;IAIpE,SAAS,CAAC,cAAc,IAAI,MAAM,EAAE;IAIpC,SAAS,CAAC,aAAa,IAAI,OAAO;CAGrC"}
1
+ {"version":3,"file":"mock-package-manager.d.ts","sourceRoot":"","sources":["../../../src/package-manager/__mocks__/mock-package-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAErF,qBAAa,kBAAmB,SAAQ,cAAc;IAClD,QAAQ,CAAC,OAAO,UAAU;IAC1B,QAAQ,CAAC,YAAY,oBAAoB;IACzC,QAAQ,CAAC,WAAW,WAAe;IAEnC,UAAU;IAEV,kBAAkB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS;IAIpE,kBAAkB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS;IAIpE,SAAS,CAAC,cAAc,IAAI,MAAM,EAAE;IAIpC,SAAS,CAAC,aAAa,IAAI,OAAO;IAIlC,SAAS,CAAC,WAAW,IAAI,IAAI;CAChC"}
@@ -1,4 +1,4 @@
1
1
  export { getPackageManager } from './get-package-manager';
2
2
  export { PackageManager } from './package-manager';
3
- export type { DeclaredVersionQuery, ResolvedVersionQuery } from './package-manager';
3
+ export type { DeclaredVersionQuery, InstallArgs, ResolvedVersionQuery } from './package-manager';
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/package-manager/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,YAAY,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/package-manager/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,YAAY,EAAE,oBAAoB,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/package-manager/index.ts"],"sourcesContent":["export { getPackageManager } from './get-package-manager';\nexport { PackageManager } from './package-manager';\nexport type { DeclaredVersionQuery, ResolvedVersionQuery } from './package-manager';\n"],"names":["PackageManager","getPackageManager"],"mappings":";;;;;;;;;;;QACSA;eAAAA,8BAAc;;QADdC;eAAAA,oCAAiB;;;mCAAQ;gCACH"}
1
+ {"version":3,"sources":["../../src/package-manager/index.ts"],"sourcesContent":["export { getPackageManager } from './get-package-manager';\nexport { PackageManager } from './package-manager';\nexport type { DeclaredVersionQuery, InstallArgs, ResolvedVersionQuery } from './package-manager';\n"],"names":["PackageManager","getPackageManager"],"mappings":";;;;;;;;;;;QACSA;eAAAA,8BAAc;;QADdC;eAAAA,oCAAiB;;;mCAAQ;gCACH"}
@@ -1,3 +1,4 @@
1
+ import { runCommand } from '../utils';
1
2
  import type { DeclaredVersionQuery, InstallArgs, ResolvedVersionQuery } from './package-manager';
2
3
  import { PackageManager } from './package-manager';
3
4
  interface NpmLockFileEntry {
@@ -14,8 +15,11 @@ export declare class NpmPackageManager extends PackageManager<NpmLockFile> {
14
15
  clearCache(): void;
15
16
  getDeclaredVersion({ workspacePackage, declaredBy, dependency, }: DeclaredVersionQuery): string | undefined;
16
17
  getResolvedVersion({ workspacePackage, dependency }: ResolvedVersionQuery): string | undefined;
17
- protected getInstallArgs({ fix }: InstallArgs): string[];
18
+ protected getInstallArgs({ fix, allowScripts }: InstallArgs): string[];
18
19
  protected parseLockFile(): NpmLockFile | undefined;
20
+ protected postInstall(args: InstallArgs, options?: Parameters<typeof runCommand>[2]): void;
21
+ private runAllowedScripts;
22
+ private runProjectPostinstall;
19
23
  /**
20
24
  * Looks up a lockfile entry for the given workspace package, falling back
21
25
  * to the hoisted root entry. `workspacePackage` is the package's relative
@@ -1 +1 @@
1
- {"version":3,"file":"npm-package-manager.d.ts","sourceRoot":"","sources":["../../src/package-manager/npm-package-manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACjG,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,UAAU,gBAAgB;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,WAAW;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CAC/C;AAED,qBAAa,iBAAkB,SAAQ,cAAc,CAAC,WAAW,CAAC;IAC9D,QAAQ,CAAC,OAAO,SAAS;IACzB,QAAQ,CAAC,YAAY,uBAAuB;IAE5C,UAAU;IAIV,kBAAkB,CAAC,EACf,gBAAgB,EAChB,UAAU,EACV,UAAU,GACb,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS;IAK5C,kBAAkB,CAAC,EAAE,gBAAgB,EAAE,UAAU,EAAE,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS;IAI9F,SAAS,CAAC,cAAc,CAAC,EAAE,GAAG,EAAE,EAAE,WAAW,GAAG,MAAM,EAAE;IAUxD,SAAS,CAAC,aAAa,IAAI,WAAW,GAAG,SAAS;IAQlD;;;;;OAKG;IACH,OAAO,CAAC,SAAS;CAapB"}
1
+ {"version":3,"file":"npm-package-manager.d.ts","sourceRoot":"","sources":["../../src/package-manager/npm-package-manager.ts"],"names":[],"mappings":"AAEA,OAAO,EAAQ,UAAU,EAA+B,MAAM,UAAU,CAAC;AACzE,OAAO,KAAK,EAAE,oBAAoB,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACjG,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,UAAU,gBAAgB;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,WAAW;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CAC/C;AAED,qBAAa,iBAAkB,SAAQ,cAAc,CAAC,WAAW,CAAC;IAC9D,QAAQ,CAAC,OAAO,SAAS;IACzB,QAAQ,CAAC,YAAY,uBAAuB;IAE5C,UAAU;IAIV,kBAAkB,CAAC,EACf,gBAAgB,EAChB,UAAU,EACV,UAAU,GACb,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS;IAK5C,kBAAkB,CAAC,EAAE,gBAAgB,EAAE,UAAU,EAAE,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS;IAI9F,SAAS,CAAC,cAAc,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,EAAE,WAAW,GAAG,MAAM,EAAE;IAWtE,SAAS,CAAC,aAAa,IAAI,WAAW,GAAG,SAAS;IAQlD,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;IAS1F,OAAO,CAAC,iBAAiB;IAezB,OAAO,CAAC,qBAAqB;IAe7B;;;;;OAKG;IACH,OAAO,CAAC,SAAS;CAapB"}
@@ -1,4 +1,4 @@
1
- "use strict";
1
+ /* eslint-disable no-console */ "use strict";
2
2
  Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
@@ -53,12 +53,15 @@ class NpmPackageManager extends _packagemanager.PackageManager {
53
53
  package: dependency
54
54
  })) === null || _this_findEntry === void 0 ? void 0 : _this_findEntry.version;
55
55
  }
56
- getInstallArgs({ fix }) {
56
+ getInstallArgs({ fix, allowScripts }) {
57
57
  return [
58
58
  (0, _utils.isCI)() ? 'ci' : 'i',
59
59
  '--audit=false',
60
60
  '--fund=false',
61
61
  '--legacy-peer-deps',
62
+ ...allowScripts === false || (allowScripts === null || allowScripts === void 0 ? void 0 : allowScripts.length) ? [
63
+ '--ignore-scripts'
64
+ ] : [],
62
65
  ...fix ? [
63
66
  '--package-lock-only',
64
67
  '--prefer-dedupe'
@@ -72,6 +75,43 @@ class NpmPackageManager extends _packagemanager.PackageManager {
72
75
  return undefined;
73
76
  }
74
77
  }
78
+ postInstall(args, options) {
79
+ if (args.fix || args.allowAllScripts) {
80
+ return;
81
+ }
82
+ this.runAllowedScripts(args);
83
+ this.runProjectPostinstall(args, options);
84
+ }
85
+ runAllowedScripts(args) {
86
+ var _args_allowScripts;
87
+ if (args.allowScripts === false || !((_args_allowScripts = args.allowScripts) === null || _args_allowScripts === void 0 ? void 0 : _args_allowScripts.length)) {
88
+ return;
89
+ }
90
+ try {
91
+ (0, _utils.runCommand)('npm', [
92
+ 'rebuild',
93
+ ...args.allowScripts
94
+ ]);
95
+ } catch (unused) {
96
+ console.error(`Failed to run allowed scripts: ${args.allowScripts.join(', ')}`);
97
+ process.exitCode = 1;
98
+ }
99
+ (0, _utils.warnUntrustedInstallScripts)(args.allowScripts, this.lockFileName);
100
+ }
101
+ runProjectPostinstall(args, options) {
102
+ if (args.allowScripts === false) {
103
+ return;
104
+ }
105
+ try {
106
+ (0, _utils.runCommand)('npm', [
107
+ 'run',
108
+ 'postinstall',
109
+ '--if-present'
110
+ ], options);
111
+ } catch (unused) {
112
+ process.exitCode = 1;
113
+ }
114
+ }
75
115
  /**
76
116
  * Looks up a lockfile entry for the given workspace package, falling back
77
117
  * to the hoisted root entry. `workspacePackage` is the package's relative
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/package-manager/npm-package-manager.ts"],"sourcesContent":["import fs from 'fs';\nimport { isCI, runCommand } from '../utils';\nimport type { DeclaredVersionQuery, InstallArgs, ResolvedVersionQuery } from './package-manager';\nimport { PackageManager } from './package-manager';\n\ninterface NpmLockFileEntry {\n version?: string;\n dependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n}\n\nexport interface NpmLockFile {\n packages?: Record<string, NpmLockFileEntry>;\n}\n\nexport class NpmPackageManager extends PackageManager<NpmLockFile> {\n readonly command = 'npm';\n readonly lockFileName = 'package-lock.json';\n\n clearCache() {\n runCommand('npm', ['cache', 'clear', '--force']);\n }\n\n getDeclaredVersion({\n workspacePackage,\n declaredBy,\n dependency,\n }: DeclaredVersionQuery): string | undefined {\n const entry = this.findEntry({ workspacePackage, package: declaredBy });\n return entry?.dependencies?.[dependency] ?? entry?.peerDependencies?.[dependency];\n }\n\n getResolvedVersion({ workspacePackage, dependency }: ResolvedVersionQuery): string | undefined {\n return this.findEntry({ workspacePackage, package: dependency })?.version;\n }\n\n protected getInstallArgs({ fix }: InstallArgs): string[] {\n return [\n isCI() ? 'ci' : 'i',\n '--audit=false',\n '--fund=false',\n '--legacy-peer-deps',\n ...(fix ? ['--package-lock-only', '--prefer-dedupe'] : []),\n ];\n }\n\n protected parseLockFile(): NpmLockFile | undefined {\n try {\n return JSON.parse(fs.readFileSync(this.lockFileName, 'utf-8'));\n } catch {\n return undefined;\n }\n }\n\n /**\n * Looks up a lockfile entry for the given workspace package, falling back\n * to the hoisted root entry. `workspacePackage` is the package's relative\n * path from the repo root; the empty string `''` denotes the root\n * workspace package itself, matching npm's own lockfile key convention.\n */\n private findEntry({\n workspacePackage,\n package: packageName,\n }: {\n workspacePackage: string;\n package: string;\n }): NpmLockFileEntry | undefined {\n const packages = this.getLockFile()?.packages;\n return (\n packages?.[`${workspacePackage}/node_modules/${packageName}`] ??\n packages?.[`node_modules/${packageName}`]\n );\n }\n}\n"],"names":["NpmPackageManager","PackageManager","clearCache","runCommand","getDeclaredVersion","workspacePackage","declaredBy","dependency","entry","findEntry","package","dependencies","peerDependencies","getResolvedVersion","version","getInstallArgs","fix","isCI","parseLockFile","JSON","parse","fs","readFileSync","lockFileName","undefined","packageName","packages","getLockFile","command"],"mappings":";;;;+BAeaA;;;eAAAA;;;2DAfE;uBACkB;gCAEF;;;;;;;;;;;;;;;;;;;AAYxB,MAAMA,0BAA0BC,8BAAc;IAIjDC,aAAa;QACTC,IAAAA,iBAAU,EAAC,OAAO;YAAC;YAAS;YAAS;SAAU;IACnD;IAEAC,mBAAmB,EACfC,gBAAgB,EAChBC,UAAU,EACVC,UAAU,EACS,EAAsB;;YAElCC,qBAAqCA;QAD5C,MAAMA,QAAQ,IAAI,CAACC,SAAS,CAAC;YAAEJ;YAAkBK,SAASJ;QAAW;QACrE,eAAOE,kBAAAA,6BAAAA,sBAAAA,MAAOG,YAAY,cAAnBH,0CAAAA,mBAAqB,CAACD,WAAW,uCAAIC,kBAAAA,6BAAAA,0BAAAA,MAAOI,gBAAgB,cAAvBJ,8CAAAA,uBAAyB,CAACD,WAAW;IACrF;IAEAM,mBAAmB,EAAER,gBAAgB,EAAEE,UAAU,EAAwB,EAAsB;YACpF;QAAP,QAAO,kBAAA,IAAI,CAACE,SAAS,CAAC;YAAEJ;YAAkBK,SAASH;QAAW,gBAAvD,sCAAA,gBAA2DO,OAAO;IAC7E;IAEUC,eAAe,EAAEC,GAAG,EAAe,EAAY;QACrD,OAAO;YACHC,IAAAA,WAAI,MAAK,OAAO;YAChB;YACA;YACA;eACID,MAAM;gBAAC;gBAAuB;aAAkB,GAAG,EAAE;SAC5D;IACL;IAEUE,gBAAyC;QAC/C,IAAI;YACA,OAAOC,KAAKC,KAAK,CAACC,WAAE,CAACC,YAAY,CAAC,IAAI,CAACC,YAAY,EAAE;QACzD,EAAE,eAAM;YACJ,OAAOC;QACX;IACJ;IAEA;;;;;KAKC,GACD,AAAQf,UAAU,EACdJ,gBAAgB,EAChBK,SAASe,WAAW,EAIvB,EAAgC;;YACZ;QAAjB,MAAMC,YAAW,oBAAA,IAAI,CAACC,WAAW,gBAAhB,wCAAA,kBAAoBD,QAAQ;QAC7C,eACIA,qBAAAA,+BAAAA,QAAU,CAAC,GAAGrB,iBAAiB,cAAc,EAAEoB,aAAa,CAAC,uCAC7DC,qBAAAA,+BAAAA,QAAU,CAAC,CAAC,aAAa,EAAED,aAAa,CAAC;IAEjD;;QAzDG,gBACH,uBAASG,WAAU,QACnB,uBAASL,gBAAe;;AAwD5B"}
1
+ {"version":3,"sources":["../../src/package-manager/npm-package-manager.ts"],"sourcesContent":["/* eslint-disable no-console */\nimport fs from 'fs';\nimport { isCI, runCommand, warnUntrustedInstallScripts } from '../utils';\nimport type { DeclaredVersionQuery, InstallArgs, ResolvedVersionQuery } from './package-manager';\nimport { PackageManager } from './package-manager';\n\ninterface NpmLockFileEntry {\n version?: string;\n dependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n}\n\nexport interface NpmLockFile {\n packages?: Record<string, NpmLockFileEntry>;\n}\n\nexport class NpmPackageManager extends PackageManager<NpmLockFile> {\n readonly command = 'npm';\n readonly lockFileName = 'package-lock.json';\n\n clearCache() {\n runCommand('npm', ['cache', 'clear', '--force']);\n }\n\n getDeclaredVersion({\n workspacePackage,\n declaredBy,\n dependency,\n }: DeclaredVersionQuery): string | undefined {\n const entry = this.findEntry({ workspacePackage, package: declaredBy });\n return entry?.dependencies?.[dependency] ?? entry?.peerDependencies?.[dependency];\n }\n\n getResolvedVersion({ workspacePackage, dependency }: ResolvedVersionQuery): string | undefined {\n return this.findEntry({ workspacePackage, package: dependency })?.version;\n }\n\n protected getInstallArgs({ fix, allowScripts }: InstallArgs): string[] {\n return [\n isCI() ? 'ci' : 'i',\n '--audit=false',\n '--fund=false',\n '--legacy-peer-deps',\n ...(allowScripts === false || allowScripts?.length ? ['--ignore-scripts'] : []),\n ...(fix ? ['--package-lock-only', '--prefer-dedupe'] : []),\n ];\n }\n\n protected parseLockFile(): NpmLockFile | undefined {\n try {\n return JSON.parse(fs.readFileSync(this.lockFileName, 'utf-8'));\n } catch {\n return undefined;\n }\n }\n\n protected postInstall(args: InstallArgs, options?: Parameters<typeof runCommand>[2]): void {\n if (args.fix || args.allowAllScripts) {\n return;\n }\n\n this.runAllowedScripts(args);\n this.runProjectPostinstall(args, options);\n }\n\n private runAllowedScripts(args: InstallArgs) {\n if (args.allowScripts === false || !args.allowScripts?.length) {\n return;\n }\n\n try {\n runCommand('npm', ['rebuild', ...args.allowScripts]);\n } catch {\n console.error(`Failed to run allowed scripts: ${args.allowScripts.join(', ')}`);\n process.exitCode = 1;\n }\n\n warnUntrustedInstallScripts(args.allowScripts, this.lockFileName);\n }\n\n private runProjectPostinstall(\n args: InstallArgs,\n options?: Parameters<typeof runCommand>[2]\n ): void {\n if (args.allowScripts === false) {\n return;\n }\n\n try {\n runCommand('npm', ['run', 'postinstall', '--if-present'], options);\n } catch {\n process.exitCode = 1;\n }\n }\n\n /**\n * Looks up a lockfile entry for the given workspace package, falling back\n * to the hoisted root entry. `workspacePackage` is the package's relative\n * path from the repo root; the empty string `''` denotes the root\n * workspace package itself, matching npm's own lockfile key convention.\n */\n private findEntry({\n workspacePackage,\n package: packageName,\n }: {\n workspacePackage: string;\n package: string;\n }): NpmLockFileEntry | undefined {\n const packages = this.getLockFile()?.packages;\n return (\n packages?.[`${workspacePackage}/node_modules/${packageName}`] ??\n packages?.[`node_modules/${packageName}`]\n );\n }\n}\n"],"names":["NpmPackageManager","PackageManager","clearCache","runCommand","getDeclaredVersion","workspacePackage","declaredBy","dependency","entry","findEntry","package","dependencies","peerDependencies","getResolvedVersion","version","getInstallArgs","fix","allowScripts","isCI","length","parseLockFile","JSON","parse","fs","readFileSync","lockFileName","undefined","postInstall","args","options","allowAllScripts","runAllowedScripts","runProjectPostinstall","console","error","join","process","exitCode","warnUntrustedInstallScripts","packageName","packages","getLockFile","command"],"mappings":"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"}
@@ -1,5 +1,7 @@
1
1
  import { runCommand } from '../utils';
2
2
  export interface InstallArgs {
3
+ allowAllScripts?: boolean;
4
+ allowScripts?: string[] | false;
3
5
  fix?: boolean;
4
6
  }
5
7
  export interface DeclaredVersionQuery {
@@ -15,7 +17,6 @@ export declare abstract class PackageManager<LockFile = unknown> {
15
17
  #private;
16
18
  abstract readonly command: string;
17
19
  abstract readonly lockFileName: string;
18
- get execCommand(): string;
19
20
  hasValidLockFile(): boolean;
20
21
  installPackages(args?: InstallArgs, options?: Parameters<typeof runCommand>[2]): void;
21
22
  protected getLockFile(): LockFile | undefined;
@@ -25,5 +26,6 @@ export declare abstract class PackageManager<LockFile = unknown> {
25
26
  abstract getResolvedVersion(query: ResolvedVersionQuery): string | undefined;
26
27
  protected abstract getInstallArgs(args: InstallArgs): string[];
27
28
  protected abstract parseLockFile(): LockFile | undefined;
29
+ protected abstract postInstall(args: InstallArgs, options?: Parameters<typeof runCommand>[2]): void;
28
30
  }
29
31
  //# sourceMappingURL=package-manager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"package-manager.d.ts","sourceRoot":"","sources":["../../src/package-manager/package-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,MAAM,WAAW,WAAW;IACxB,GAAG,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACjC,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACjC,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,8BAAsB,cAAc,CAAC,QAAQ,GAAG,OAAO;;IACnD,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAEvC,IAAI,WAAW,IAAI,MAAM,CAExB;IAKD,gBAAgB,IAAI,OAAO;IAI3B,eAAe,CAAC,IAAI,GAAE,WAAgB,EAAE,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC;IAKlF,SAAS,CAAC,WAAW,IAAI,QAAQ,GAAG,SAAS;IAQ7C,SAAS,CAAC,KAAK;IAKf,QAAQ,CAAC,UAAU,IAAI,IAAI;IAC3B,QAAQ,CAAC,kBAAkB,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS;IAC5E,QAAQ,CAAC,kBAAkB,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS;IAE5E,SAAS,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,EAAE;IAC9D,SAAS,CAAC,QAAQ,CAAC,aAAa,IAAI,QAAQ,GAAG,SAAS;CAC3D"}
1
+ {"version":3,"file":"package-manager.d.ts","sourceRoot":"","sources":["../../src/package-manager/package-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,MAAM,WAAW,WAAW;IACxB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;IAChC,GAAG,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACjC,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACjC,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,8BAAsB,cAAc,CAAC,QAAQ,GAAG,OAAO;;IACnD,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAKvC,gBAAgB,IAAI,OAAO;IAI3B,eAAe,CAAC,IAAI,GAAE,WAAgB,EAAE,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC;IAMlF,SAAS,CAAC,WAAW,IAAI,QAAQ,GAAG,SAAS;IAQ7C,SAAS,CAAC,KAAK;IAKf,QAAQ,CAAC,UAAU,IAAI,IAAI;IAC3B,QAAQ,CAAC,kBAAkB,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS;IAC5E,QAAQ,CAAC,kBAAkB,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS;IAE5E,SAAS,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,EAAE;IAC9D,SAAS,CAAC,QAAQ,CAAC,aAAa,IAAI,QAAQ,GAAG,SAAS;IACxD,SAAS,CAAC,QAAQ,CAAC,WAAW,CAC1B,IAAI,EAAE,WAAW,EACjB,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,GAC3C,IAAI;CACV"}
@@ -51,14 +51,12 @@ function _class_private_field_set(receiver, privateMap, value) {
51
51
  }
52
52
  var _lockFile = /*#__PURE__*/ new WeakMap(), _lockFileLoaded = /*#__PURE__*/ new WeakMap();
53
53
  class PackageManager {
54
- get execCommand() {
55
- return `${this.command} exec`;
56
- }
57
54
  hasValidLockFile() {
58
55
  return this.getLockFile() !== undefined;
59
56
  }
60
57
  installPackages(args = {}, options) {
61
58
  (0, _utils.runCommand)(this.command, this.getInstallArgs(args), options);
59
+ this.postInstall(args, options);
62
60
  this.reset();
63
61
  }
64
62
  getLockFile() {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/package-manager/package-manager.ts"],"sourcesContent":["import { runCommand } from '../utils';\n\nexport interface InstallArgs {\n fix?: boolean;\n}\n\nexport interface DeclaredVersionQuery {\n workspacePackage: string;\n declaredBy: string;\n dependency: string;\n}\n\nexport interface ResolvedVersionQuery {\n workspacePackage: string;\n dependency: string;\n}\n\nexport abstract class PackageManager<LockFile = unknown> {\n abstract readonly command: string;\n abstract readonly lockFileName: string;\n\n get execCommand(): string {\n return `${this.command} exec`;\n }\n\n #lockFile: LockFile | undefined;\n #lockFileLoaded = false;\n\n hasValidLockFile(): boolean {\n return this.getLockFile() !== undefined;\n }\n\n installPackages(args: InstallArgs = {}, options?: Parameters<typeof runCommand>[2]) {\n runCommand(this.command, this.getInstallArgs(args), options);\n this.reset();\n }\n\n protected getLockFile(): LockFile | undefined {\n if (!this.#lockFileLoaded) {\n this.#lockFile = this.parseLockFile();\n this.#lockFileLoaded = true;\n }\n return this.#lockFile;\n }\n\n protected reset() {\n this.#lockFile = undefined;\n this.#lockFileLoaded = false;\n }\n\n abstract clearCache(): void;\n abstract getDeclaredVersion(query: DeclaredVersionQuery): string | undefined;\n abstract getResolvedVersion(query: ResolvedVersionQuery): string | undefined;\n\n protected abstract getInstallArgs(args: InstallArgs): string[];\n protected abstract parseLockFile(): LockFile | undefined;\n}\n"],"names":["PackageManager","execCommand","command","hasValidLockFile","getLockFile","undefined","installPackages","args","options","runCommand","getInstallArgs","reset","parseLockFile"],"mappings":";;;;+BAiBsBA;;;eAAAA;;;uBAjBK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAyBvB,yCACA;AATG,MAAeA;IAIlB,IAAIC,cAAsB;QACtB,OAAO,GAAG,IAAI,CAACC,OAAO,CAAC,KAAK,CAAC;IACjC;IAKAC,mBAA4B;QACxB,OAAO,IAAI,CAACC,WAAW,OAAOC;IAClC;IAEAC,gBAAgBC,OAAoB,CAAC,CAAC,EAAEC,OAA0C,EAAE;QAChFC,IAAAA,iBAAU,EAAC,IAAI,CAACP,OAAO,EAAE,IAAI,CAACQ,cAAc,CAACH,OAAOC;QACpD,IAAI,CAACG,KAAK;IACd;IAEUP,cAAoC;QAC1C,IAAI,0BAAC,IAAI,EAAC,kBAAiB;2CAClB,WAAY,IAAI,CAACQ,aAAa;2CAC9B,iBAAkB;QAC3B;QACA,gCAAO,IAAI,EAAC;IAChB;IAEUD,QAAQ;uCACT,WAAYN;uCACZ,iBAAkB;IAC3B;;QAvBA,gCAAA;;mBAAA,KAAA;;QACA,gCAAA;;mBAAkB;;;AA8BtB"}
1
+ {"version":3,"sources":["../../src/package-manager/package-manager.ts"],"sourcesContent":["import { runCommand } from '../utils';\n\nexport interface InstallArgs {\n allowAllScripts?: boolean;\n allowScripts?: string[] | false;\n fix?: boolean;\n}\n\nexport interface DeclaredVersionQuery {\n workspacePackage: string;\n declaredBy: string;\n dependency: string;\n}\n\nexport interface ResolvedVersionQuery {\n workspacePackage: string;\n dependency: string;\n}\n\nexport abstract class PackageManager<LockFile = unknown> {\n abstract readonly command: string;\n abstract readonly lockFileName: string;\n\n #lockFile: LockFile | undefined;\n #lockFileLoaded = false;\n\n hasValidLockFile(): boolean {\n return this.getLockFile() !== undefined;\n }\n\n installPackages(args: InstallArgs = {}, options?: Parameters<typeof runCommand>[2]) {\n runCommand(this.command, this.getInstallArgs(args), options);\n this.postInstall(args, options);\n this.reset();\n }\n\n protected getLockFile(): LockFile | undefined {\n if (!this.#lockFileLoaded) {\n this.#lockFile = this.parseLockFile();\n this.#lockFileLoaded = true;\n }\n return this.#lockFile;\n }\n\n protected reset() {\n this.#lockFile = undefined;\n this.#lockFileLoaded = false;\n }\n\n abstract clearCache(): void;\n abstract getDeclaredVersion(query: DeclaredVersionQuery): string | undefined;\n abstract getResolvedVersion(query: ResolvedVersionQuery): string | undefined;\n\n protected abstract getInstallArgs(args: InstallArgs): string[];\n protected abstract parseLockFile(): LockFile | undefined;\n protected abstract postInstall(\n args: InstallArgs,\n options?: Parameters<typeof runCommand>[2]\n ): void;\n}\n"],"names":["PackageManager","hasValidLockFile","getLockFile","undefined","installPackages","args","options","runCommand","command","getInstallArgs","postInstall","reset","parseLockFile"],"mappings":";;;;+BAmBsBA;;;eAAAA;;;uBAnBK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAuBvB,yCACA;AALG,MAAeA;IAOlBC,mBAA4B;QACxB,OAAO,IAAI,CAACC,WAAW,OAAOC;IAClC;IAEAC,gBAAgBC,OAAoB,CAAC,CAAC,EAAEC,OAA0C,EAAE;QAChFC,IAAAA,iBAAU,EAAC,IAAI,CAACC,OAAO,EAAE,IAAI,CAACC,cAAc,CAACJ,OAAOC;QACpD,IAAI,CAACI,WAAW,CAACL,MAAMC;QACvB,IAAI,CAACK,KAAK;IACd;IAEUT,cAAoC;QAC1C,IAAI,0BAAC,IAAI,EAAC,kBAAiB;2CAClB,WAAY,IAAI,CAACU,aAAa;2CAC9B,iBAAkB;QAC3B;QACA,gCAAO,IAAI,EAAC;IAChB;IAEUD,QAAQ;uCACT,WAAYR;uCACZ,iBAAkB;IAC3B;;QAxBA,gCAAA;;mBAAA,KAAA;;QACA,gCAAA;;mBAAkB;;;AAmCtB"}
@@ -25,6 +25,7 @@ export declare class PnpmPackageManager extends PackageManager<PnpmLockFile> {
25
25
  getResolvedVersion({ workspacePackage, dependency }: ResolvedVersionQuery): string | undefined;
26
26
  protected getInstallArgs({ fix }: InstallArgs): string[];
27
27
  protected parseLockFile(): PnpmLockFile | undefined;
28
+ protected postInstall(): void;
28
29
  private resolveVersion;
29
30
  }
30
31
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"pnpm-package-manager.d.ts","sourceRoot":"","sources":["../../src/package-manager/pnpm-package-manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACjG,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,UAAU,iBAAiB;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,YAAY;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IACjD,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IACpD,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;CAC5D;AAED,UAAU,YAAY;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,YAAY;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CAC5C;AAED,qBAAa,kBAAmB,SAAQ,cAAc,CAAC,YAAY,CAAC;IAChE,QAAQ,CAAC,OAAO,UAAU;IAC1B,QAAQ,CAAC,YAAY,oBAAoB;IAEzC,UAAU;IAIV,kBAAkB,CAAC,EACf,gBAAgB,EAChB,UAAU,EACV,UAAU,GACb,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS;IAS5C,kBAAkB,CAAC,EAAE,gBAAgB,EAAE,UAAU,EAAE,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS;IAI9F,SAAS,CAAC,cAAc,CAAC,EAAE,GAAG,EAAE,EAAE,WAAW,GAAG,MAAM,EAAE;IAQxD,SAAS,CAAC,aAAa,IAAI,YAAY,GAAG,SAAS;IASnD,OAAO,CAAC,cAAc;CAQzB"}
1
+ {"version":3,"file":"pnpm-package-manager.d.ts","sourceRoot":"","sources":["../../src/package-manager/pnpm-package-manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACjG,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,UAAU,iBAAiB;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,YAAY;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IACjD,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IACpD,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;CAC5D;AAED,UAAU,YAAY;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,YAAY;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CAC5C;AAED,qBAAa,kBAAmB,SAAQ,cAAc,CAAC,YAAY,CAAC;IAChE,QAAQ,CAAC,OAAO,UAAU;IAC1B,QAAQ,CAAC,YAAY,oBAAoB;IAEzC,UAAU;IAIV,kBAAkB,CAAC,EACf,gBAAgB,EAChB,UAAU,EACV,UAAU,GACb,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS;IAS5C,kBAAkB,CAAC,EAAE,gBAAgB,EAAE,UAAU,EAAE,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS;IAI9F,SAAS,CAAC,cAAc,CAAC,EAAE,GAAG,EAAE,EAAE,WAAW,GAAG,MAAM,EAAE;IAQxD,SAAS,CAAC,aAAa,IAAI,YAAY,GAAG,SAAS;IAanD,SAAS,CAAC,WAAW,IAAI,IAAI;IAI7B,OAAO,CAAC,cAAc;CAQzB"}
@@ -61,13 +61,19 @@ class PnpmPackageManager extends _packagemanager.PackageManager {
61
61
  ];
62
62
  }
63
63
  parseLockFile() {
64
- const yaml = require('js-yaml'); // eslint-disable-line import/no-extraneous-dependencies
64
+ /*
65
+ * js-yaml is an optional peer; let MODULE_NOT_FOUND surface so a caller
66
+ * missing the dep gets a clear error instead of silent `undefined`.
67
+ */ const yaml = require('js-yaml');
65
68
  try {
66
69
  return yaml.load(_fs.default.readFileSync(this.lockFileName, 'utf-8'));
67
70
  } catch (unused) {
68
71
  return undefined;
69
72
  }
70
73
  }
74
+ postInstall() {
75
+ // no-op
76
+ }
71
77
  resolveVersion(workspacePackage, dependency) {
72
78
  var _ref, _ref1;
73
79
  var _this_getLockFile_importers, _this_getLockFile, _importer_dependencies, _importer_devDependencies, _importer_optionalDependencies;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/package-manager/pnpm-package-manager.ts"],"sourcesContent":["import fs from 'fs';\nimport { isCI, runCommand } from '../utils';\nimport type { DeclaredVersionQuery, InstallArgs, ResolvedVersionQuery } from './package-manager';\nimport { PackageManager } from './package-manager';\n\ninterface PnpmImporterEntry {\n specifier: string;\n version: string;\n}\n\ninterface PnpmImporter {\n dependencies?: Record<string, PnpmImporterEntry>;\n devDependencies?: Record<string, PnpmImporterEntry>;\n optionalDependencies?: Record<string, PnpmImporterEntry>;\n}\n\ninterface PnpmSnapshot {\n dependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n}\n\nexport interface PnpmLockFile {\n importers?: Record<string, PnpmImporter>;\n snapshots?: Record<string, PnpmSnapshot>;\n}\n\nexport class PnpmPackageManager extends PackageManager<PnpmLockFile> {\n readonly command = 'pnpm';\n readonly lockFileName = 'pnpm-lock.yaml';\n\n clearCache() {\n runCommand('pnpm', ['store', 'prune']);\n }\n\n getDeclaredVersion({\n workspacePackage,\n declaredBy,\n dependency,\n }: DeclaredVersionQuery): string | undefined {\n const declaredByVersion = this.resolveVersion(workspacePackage, declaredBy);\n if (!declaredByVersion) {\n return undefined;\n }\n const snapshot = this.getLockFile()?.snapshots?.[`${declaredBy}@${declaredByVersion}`];\n return snapshot?.dependencies?.[dependency] ?? snapshot?.peerDependencies?.[dependency];\n }\n\n getResolvedVersion({ workspacePackage, dependency }: ResolvedVersionQuery): string | undefined {\n return this.resolveVersion(workspacePackage, dependency);\n }\n\n protected getInstallArgs({ fix }: InstallArgs): string[] {\n return [\n 'install',\n ...(isCI() ? ['--frozen-lockfile'] : []),\n ...(fix ? ['--lockfile-only'] : []),\n ];\n }\n\n protected parseLockFile(): PnpmLockFile | undefined {\n const yaml = require('js-yaml'); // eslint-disable-line import/no-extraneous-dependencies\n try {\n return yaml.load(fs.readFileSync(this.lockFileName, 'utf-8'));\n } catch {\n return undefined;\n }\n }\n\n private resolveVersion(workspacePackage: string, dependency: string): string | undefined {\n const importer = this.getLockFile()?.importers?.[workspacePackage];\n const entry =\n importer?.dependencies?.[dependency] ??\n importer?.devDependencies?.[dependency] ??\n importer?.optionalDependencies?.[dependency];\n return entry ? stripPeerDependencySuffix(entry.version) : undefined;\n }\n}\n\nfunction stripPeerDependencySuffix(version: string): string {\n // e.g., \"1.2.3(react@18.2.0)(react-dom@18.2.0)\" → \"1.2.3\"\n return version.split('(')[0];\n}\n"],"names":["PnpmPackageManager","PackageManager","clearCache","runCommand","getDeclaredVersion","workspacePackage","declaredBy","dependency","snapshot","declaredByVersion","resolveVersion","undefined","getLockFile","snapshots","dependencies","peerDependencies","getResolvedVersion","getInstallArgs","fix","isCI","parseLockFile","yaml","require","load","fs","readFileSync","lockFileName","importer","importers","entry","devDependencies","optionalDependencies","stripPeerDependencySuffix","version","command","split"],"mappings":";;;;+BA0BaA;;;eAAAA;;;2DA1BE;uBACkB;gCAEF;;;;;;;;;;;;;;;;;;;AAuBxB,MAAMA,2BAA2BC,8BAAc;IAIlDC,aAAa;QACTC,IAAAA,iBAAU,EAAC,QAAQ;YAAC;YAAS;SAAQ;IACzC;IAEAC,mBAAmB,EACfC,gBAAgB,EAChBC,UAAU,EACVC,UAAU,EACS,EAAsB;;YAKxB,6BAAA,mBACVC,wBAAwCA;QAL/C,MAAMC,oBAAoB,IAAI,CAACC,cAAc,CAACL,kBAAkBC;QAChE,IAAI,CAACG,mBAAmB;YACpB,OAAOE;QACX;QACA,MAAMH,YAAW,oBAAA,IAAI,CAACI,WAAW,gBAAhB,yCAAA,8BAAA,kBAAoBC,SAAS,cAA7B,kDAAA,2BAA+B,CAAC,GAAGP,WAAW,CAAC,EAAEG,mBAAmB,CAAC;QACtF,eAAOD,qBAAAA,gCAAAA,yBAAAA,SAAUM,YAAY,cAAtBN,6CAAAA,sBAAwB,CAACD,WAAW,uCAAIC,qBAAAA,gCAAAA,6BAAAA,SAAUO,gBAAgB,cAA1BP,iDAAAA,0BAA4B,CAACD,WAAW;IAC3F;IAEAS,mBAAmB,EAAEX,gBAAgB,EAAEE,UAAU,EAAwB,EAAsB;QAC3F,OAAO,IAAI,CAACG,cAAc,CAACL,kBAAkBE;IACjD;IAEUU,eAAe,EAAEC,GAAG,EAAe,EAAY;QACrD,OAAO;YACH;eACIC,IAAAA,WAAI,MAAK;gBAAC;aAAoB,GAAG,EAAE;eACnCD,MAAM;gBAAC;aAAkB,GAAG,EAAE;SACrC;IACL;IAEUE,gBAA0C;QAChD,MAAMC,OAAOC,QAAQ,YAAY,wDAAwD;QACzF,IAAI;YACA,OAAOD,KAAKE,IAAI,CAACC,WAAE,CAACC,YAAY,CAAC,IAAI,CAACC,YAAY,EAAE;QACxD,EAAE,eAAM;YACJ,OAAOf;QACX;IACJ;IAEQD,eAAeL,gBAAwB,EAAEE,UAAkB,EAAsB;YAGjFoB;YAFa,6BAAA,mBAEbA,wBACAA,2BACAA;QAJJ,MAAMA,YAAW,oBAAA,IAAI,CAACf,WAAW,gBAAhB,yCAAA,8BAAA,kBAAoBgB,SAAS,cAA7B,kDAAA,2BAA+B,CAACvB,iBAAiB;QAClE,MAAMwB,SACFF,gBAAAA,qBAAAA,gCAAAA,yBAAAA,SAAUb,YAAY,cAAtBa,6CAAAA,sBAAwB,CAACpB,WAAW,yCACpCoB,qBAAAA,gCAAAA,4BAAAA,SAAUG,eAAe,cAAzBH,gDAAAA,yBAA2B,CAACpB,WAAW,cADvCoB,kBAAAA,OAEAA,qBAAAA,gCAAAA,iCAAAA,SAAUI,oBAAoB,cAA9BJ,qDAAAA,8BAAgC,CAACpB,WAAW;QAChD,OAAOsB,QAAQG,0BAA0BH,MAAMI,OAAO,IAAItB;IAC9D;;QAjDG,gBACH,uBAASuB,WAAU,SACnB,uBAASR,gBAAe;;AAgD5B;AAEA,SAASM,0BAA0BC,OAAe;IAC9C,0DAA0D;IAC1D,OAAOA,QAAQE,KAAK,CAAC,IAAI,CAAC,EAAE;AAChC"}
1
+ {"version":3,"sources":["../../src/package-manager/pnpm-package-manager.ts"],"sourcesContent":["import fs from 'fs';\nimport { isCI, runCommand } from '../utils';\nimport type { DeclaredVersionQuery, InstallArgs, ResolvedVersionQuery } from './package-manager';\nimport { PackageManager } from './package-manager';\n\ninterface PnpmImporterEntry {\n specifier: string;\n version: string;\n}\n\ninterface PnpmImporter {\n dependencies?: Record<string, PnpmImporterEntry>;\n devDependencies?: Record<string, PnpmImporterEntry>;\n optionalDependencies?: Record<string, PnpmImporterEntry>;\n}\n\ninterface PnpmSnapshot {\n dependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n}\n\nexport interface PnpmLockFile {\n importers?: Record<string, PnpmImporter>;\n snapshots?: Record<string, PnpmSnapshot>;\n}\n\nexport class PnpmPackageManager extends PackageManager<PnpmLockFile> {\n readonly command = 'pnpm';\n readonly lockFileName = 'pnpm-lock.yaml';\n\n clearCache() {\n runCommand('pnpm', ['store', 'prune']);\n }\n\n getDeclaredVersion({\n workspacePackage,\n declaredBy,\n dependency,\n }: DeclaredVersionQuery): string | undefined {\n const declaredByVersion = this.resolveVersion(workspacePackage, declaredBy);\n if (!declaredByVersion) {\n return undefined;\n }\n const snapshot = this.getLockFile()?.snapshots?.[`${declaredBy}@${declaredByVersion}`];\n return snapshot?.dependencies?.[dependency] ?? snapshot?.peerDependencies?.[dependency];\n }\n\n getResolvedVersion({ workspacePackage, dependency }: ResolvedVersionQuery): string | undefined {\n return this.resolveVersion(workspacePackage, dependency);\n }\n\n protected getInstallArgs({ fix }: InstallArgs): string[] {\n return [\n 'install',\n ...(isCI() ? ['--frozen-lockfile'] : []),\n ...(fix ? ['--lockfile-only'] : []),\n ];\n }\n\n protected parseLockFile(): PnpmLockFile | undefined {\n /*\n * js-yaml is an optional peer; let MODULE_NOT_FOUND surface so a caller\n * missing the dep gets a clear error instead of silent `undefined`.\n */\n const yaml = require('js-yaml');\n try {\n return yaml.load(fs.readFileSync(this.lockFileName, 'utf-8'));\n } catch {\n return undefined;\n }\n }\n\n protected postInstall(): void {\n // no-op\n }\n\n private resolveVersion(workspacePackage: string, dependency: string): string | undefined {\n const importer = this.getLockFile()?.importers?.[workspacePackage];\n const entry =\n importer?.dependencies?.[dependency] ??\n importer?.devDependencies?.[dependency] ??\n importer?.optionalDependencies?.[dependency];\n return entry ? stripPeerDependencySuffix(entry.version) : undefined;\n }\n}\n\nfunction stripPeerDependencySuffix(version: string): string {\n // e.g., \"1.2.3(react@18.2.0)(react-dom@18.2.0)\" → \"1.2.3\"\n return version.split('(')[0];\n}\n"],"names":["PnpmPackageManager","PackageManager","clearCache","runCommand","getDeclaredVersion","workspacePackage","declaredBy","dependency","snapshot","declaredByVersion","resolveVersion","undefined","getLockFile","snapshots","dependencies","peerDependencies","getResolvedVersion","getInstallArgs","fix","isCI","parseLockFile","yaml","require","load","fs","readFileSync","lockFileName","postInstall","importer","importers","entry","devDependencies","optionalDependencies","stripPeerDependencySuffix","version","command","split"],"mappings":";;;;+BA0BaA;;;eAAAA;;;2DA1BE;uBACkB;gCAEF;;;;;;;;;;;;;;;;;;;AAuBxB,MAAMA,2BAA2BC,8BAAc;IAIlDC,aAAa;QACTC,IAAAA,iBAAU,EAAC,QAAQ;YAAC;YAAS;SAAQ;IACzC;IAEAC,mBAAmB,EACfC,gBAAgB,EAChBC,UAAU,EACVC,UAAU,EACS,EAAsB;;YAKxB,6BAAA,mBACVC,wBAAwCA;QAL/C,MAAMC,oBAAoB,IAAI,CAACC,cAAc,CAACL,kBAAkBC;QAChE,IAAI,CAACG,mBAAmB;YACpB,OAAOE;QACX;QACA,MAAMH,YAAW,oBAAA,IAAI,CAACI,WAAW,gBAAhB,yCAAA,8BAAA,kBAAoBC,SAAS,cAA7B,kDAAA,2BAA+B,CAAC,GAAGP,WAAW,CAAC,EAAEG,mBAAmB,CAAC;QACtF,eAAOD,qBAAAA,gCAAAA,yBAAAA,SAAUM,YAAY,cAAtBN,6CAAAA,sBAAwB,CAACD,WAAW,uCAAIC,qBAAAA,gCAAAA,6BAAAA,SAAUO,gBAAgB,cAA1BP,iDAAAA,0BAA4B,CAACD,WAAW;IAC3F;IAEAS,mBAAmB,EAAEX,gBAAgB,EAAEE,UAAU,EAAwB,EAAsB;QAC3F,OAAO,IAAI,CAACG,cAAc,CAACL,kBAAkBE;IACjD;IAEUU,eAAe,EAAEC,GAAG,EAAe,EAAY;QACrD,OAAO;YACH;eACIC,IAAAA,WAAI,MAAK;gBAAC;aAAoB,GAAG,EAAE;eACnCD,MAAM;gBAAC;aAAkB,GAAG,EAAE;SACrC;IACL;IAEUE,gBAA0C;QAChD;;;SAGC,GACD,MAAMC,OAAOC,QAAQ;QACrB,IAAI;YACA,OAAOD,KAAKE,IAAI,CAACC,WAAE,CAACC,YAAY,CAAC,IAAI,CAACC,YAAY,EAAE;QACxD,EAAE,eAAM;YACJ,OAAOf;QACX;IACJ;IAEUgB,cAAoB;IAC1B,QAAQ;IACZ;IAEQjB,eAAeL,gBAAwB,EAAEE,UAAkB,EAAsB;YAGjFqB;YAFa,6BAAA,mBAEbA,wBACAA,2BACAA;QAJJ,MAAMA,YAAW,oBAAA,IAAI,CAAChB,WAAW,gBAAhB,yCAAA,8BAAA,kBAAoBiB,SAAS,cAA7B,kDAAA,2BAA+B,CAACxB,iBAAiB;QAClE,MAAMyB,SACFF,gBAAAA,qBAAAA,gCAAAA,yBAAAA,SAAUd,YAAY,cAAtBc,6CAAAA,sBAAwB,CAACrB,WAAW,yCACpCqB,qBAAAA,gCAAAA,4BAAAA,SAAUG,eAAe,cAAzBH,gDAAAA,yBAA2B,CAACrB,WAAW,cADvCqB,kBAAAA,OAEAA,qBAAAA,gCAAAA,iCAAAA,SAAUI,oBAAoB,cAA9BJ,qDAAAA,8BAAgC,CAACrB,WAAW;QAChD,OAAOuB,QAAQG,0BAA0BH,MAAMI,OAAO,IAAIvB;IAC9D;;QAzDG,gBACH,uBAASwB,WAAU,SACnB,uBAAST,gBAAe;;AAwD5B;AAEA,SAASO,0BAA0BC,OAAe;IAC9C,0DAA0D;IAC1D,OAAOA,QAAQE,KAAK,CAAC,IAAI,CAAC,EAAE;AAChC"}
@@ -0,0 +1,8 @@
1
+ interface PackageWithScript {
2
+ location: string;
3
+ name: string;
4
+ version: string;
5
+ }
6
+ export declare function getPackagesWithInstallScripts(): PackageWithScript[];
7
+ export {};
8
+ //# sourceMappingURL=get-packages-with-install-scripts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-packages-with-install-scripts.d.ts","sourceRoot":"","sources":["../../src/utils/get-packages-with-install-scripts.ts"],"names":[],"mappings":"AAEA,UAAU,iBAAiB;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACnB;AAMD,wBAAgB,6BAA6B,IAAI,iBAAiB,EAAE,CAWnE"}
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "getPackagesWithInstallScripts", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return getPackagesWithInstallScripts;
9
+ }
10
+ });
11
+ const _os = require("./os");
12
+ const SELECTORS = [
13
+ 'preinstall',
14
+ 'install',
15
+ 'postinstall'
16
+ ].map((script)=>`:attr(scripts, [${script}])`).join(', ');
17
+ function getPackagesWithInstallScripts() {
18
+ try {
19
+ const result = (0, _os.runCommand)('npm', [
20
+ 'query',
21
+ SELECTORS,
22
+ '--json'
23
+ ]);
24
+ return JSON.parse(result).map(({ location, name, version })=>({
25
+ location,
26
+ name,
27
+ version
28
+ }));
29
+ } catch (unused) {
30
+ return [];
31
+ }
32
+ }
33
+
34
+ //# sourceMappingURL=get-packages-with-install-scripts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utils/get-packages-with-install-scripts.ts"],"sourcesContent":["import { runCommand } from './os';\n\ninterface PackageWithScript {\n location: string;\n name: string;\n version: string;\n}\n\nconst SELECTORS = ['preinstall', 'install', 'postinstall']\n .map(script => `:attr(scripts, [${script}])`)\n .join(', ');\n\nexport function getPackagesWithInstallScripts(): PackageWithScript[] {\n try {\n const result = runCommand('npm', ['query', SELECTORS, '--json']);\n return JSON.parse(result).map(({ location, name, version }: PackageWithScript) => ({\n location,\n name,\n version,\n }));\n } catch {\n return [];\n }\n}\n"],"names":["getPackagesWithInstallScripts","SELECTORS","map","script","join","result","runCommand","JSON","parse","location","name","version"],"mappings":";;;;+BAYgBA;;;eAAAA;;;oBAZW;AAQ3B,MAAMC,YAAY;IAAC;IAAc;IAAW;CAAc,CACrDC,GAAG,CAACC,CAAAA,SAAU,CAAC,gBAAgB,EAAEA,OAAO,EAAE,CAAC,EAC3CC,IAAI,CAAC;AAEH,SAASJ;IACZ,IAAI;QACA,MAAMK,SAASC,IAAAA,cAAU,EAAC,OAAO;YAAC;YAASL;YAAW;SAAS;QAC/D,OAAOM,KAAKC,KAAK,CAACH,QAAQH,GAAG,CAAC,CAAC,EAAEO,QAAQ,EAAEC,IAAI,EAAEC,OAAO,EAAqB,GAAM,CAAA;gBAC/EF;gBACAC;gBACAC;YACJ,CAAA;IACJ,EAAE,eAAM;QACJ,OAAO,EAAE;IACb;AACJ"}
@@ -0,0 +1,2 @@
1
+ export declare function hasLockfileChanged(lockFileName: string): boolean;
2
+ //# sourceMappingURL=has-lockfile-changed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"has-lockfile-changed.d.ts","sourceRoot":"","sources":["../../src/utils/has-lockfile-changed.ts"],"names":[],"mappings":"AAEA,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,WAOtD"}
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "hasLockfileChanged", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return hasLockfileChanged;
9
+ }
10
+ });
11
+ const _os = require("./os");
12
+ function hasLockfileChanged(lockFileName) {
13
+ try {
14
+ const result = (0, _os.runCommand)('git', [
15
+ 'diff',
16
+ '--name-only',
17
+ 'HEAD',
18
+ '--',
19
+ lockFileName
20
+ ]);
21
+ return result.trim().length > 0;
22
+ } catch (unused) {
23
+ return true;
24
+ }
25
+ }
26
+
27
+ //# sourceMappingURL=has-lockfile-changed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utils/has-lockfile-changed.ts"],"sourcesContent":["import { runCommand } from './os';\n\nexport function hasLockfileChanged(lockFileName: string) {\n try {\n const result = runCommand('git', ['diff', '--name-only', 'HEAD', '--', lockFileName]);\n return result.trim().length > 0;\n } catch {\n return true;\n }\n}\n"],"names":["hasLockfileChanged","lockFileName","result","runCommand","trim","length"],"mappings":";;;;+BAEgBA;;;eAAAA;;;oBAFW;AAEpB,SAASA,mBAAmBC,YAAoB;IACnD,IAAI;QACA,MAAMC,SAASC,IAAAA,cAAU,EAAC,OAAO;YAAC;YAAQ;YAAe;YAAQ;YAAMF;SAAa;QACpF,OAAOC,OAAOE,IAAI,GAAGC,MAAM,GAAG;IAClC,EAAE,eAAM;QACJ,OAAO;IACX;AACJ"}
@@ -1,8 +1,11 @@
1
1
  export * from './ci';
2
2
  export * from './debug';
3
+ export * from './get-packages-with-install-scripts';
3
4
  export * from './get-version';
4
5
  export * from './git';
6
+ export * from './has-lockfile-changed';
5
7
  export * from './npm';
6
8
  export * from './os';
7
9
  export * from './read-json';
10
+ export * from './warn-untrusted-install-scripts';
8
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,MAAM,CAAC;AACrB,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC;AAC9B,cAAc,OAAO,CAAC;AACtB,cAAc,OAAO,CAAC;AACtB,cAAc,MAAM,CAAC;AACrB,cAAc,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,MAAM,CAAC;AACrB,cAAc,SAAS,CAAC;AACxB,cAAc,qCAAqC,CAAC;AACpD,cAAc,eAAe,CAAC;AAC9B,cAAc,OAAO,CAAC;AACtB,cAAc,wBAAwB,CAAC;AACvC,cAAc,OAAO,CAAC;AACtB,cAAc,MAAM,CAAC;AACrB,cAAc,aAAa,CAAC;AAC5B,cAAc,kCAAkC,CAAC"}
@@ -4,11 +4,14 @@ Object.defineProperty(exports, "__esModule", {
4
4
  });
5
5
  _export_star(require("./ci"), exports);
6
6
  _export_star(require("./debug"), exports);
7
+ _export_star(require("./get-packages-with-install-scripts"), exports);
7
8
  _export_star(require("./get-version"), exports);
8
9
  _export_star(require("./git"), exports);
10
+ _export_star(require("./has-lockfile-changed"), exports);
9
11
  _export_star(require("./npm"), exports);
10
12
  _export_star(require("./os"), exports);
11
13
  _export_star(require("./read-json"), exports);
14
+ _export_star(require("./warn-untrusted-install-scripts"), exports);
12
15
  function _export_star(from, to) {
13
16
  Object.keys(from).forEach(function(k) {
14
17
  if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/index.ts"],"sourcesContent":["export * from './ci';\nexport * from './debug';\nexport * from './get-version';\nexport * from './git';\nexport * from './npm';\nexport * from './os';\nexport * from './read-json';\n"],"names":[],"mappings":";;;;qBAAc;qBACA;qBACA;qBACA;qBACA;qBACA;qBACA"}
1
+ {"version":3,"sources":["../../src/utils/index.ts"],"sourcesContent":["export * from './ci';\nexport * from './debug';\nexport * from './get-packages-with-install-scripts';\nexport * from './get-version';\nexport * from './git';\nexport * from './has-lockfile-changed';\nexport * from './npm';\nexport * from './os';\nexport * from './read-json';\nexport * from './warn-untrusted-install-scripts';\n"],"names":[],"mappings":";;;;qBAAc;qBACA;qBACA;qBACA;qBACA;qBACA;qBACA;qBACA;qBACA;qBACA"}
@@ -0,0 +1,2 @@
1
+ export declare function warnUntrustedInstallScripts(allowedScripts: string[], lockFileName: string): void;
2
+ //# sourceMappingURL=warn-untrusted-install-scripts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"warn-untrusted-install-scripts.d.ts","sourceRoot":"","sources":["../../src/utils/warn-untrusted-install-scripts.ts"],"names":[],"mappings":"AAqBA,wBAAgB,2BAA2B,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,MAAM,QAwBzF"}
@@ -0,0 +1,52 @@
1
+ /* eslint-disable no-console */ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "warnUntrustedInstallScripts", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return warnUntrustedInstallScripts;
9
+ }
10
+ });
11
+ const _getpackageswithinstallscripts = require("./get-packages-with-install-scripts");
12
+ const _haslockfilechanged = require("./has-lockfile-changed");
13
+ // These packages have scripts, but don't need them to function correctly.
14
+ const IGNORE = [
15
+ '@parcel/watcher',
16
+ '@progress/kendo-licensing',
17
+ '@scarf/scarf',
18
+ '@swc/core',
19
+ '@vaadin/vaadin-usage-statistics',
20
+ 'contentful',
21
+ 'core-js-pure',
22
+ 'core-js',
23
+ 'es5-ext',
24
+ 'esbuild',
25
+ 'less',
26
+ 'unrs-resolver'
27
+ ];
28
+ function warnUntrustedInstallScripts(allowedScripts, lockFileName) {
29
+ if (!(0, _haslockfilechanged.hasLockfileChanged)(lockFileName)) {
30
+ return;
31
+ }
32
+ const packages = (0, _getpackageswithinstallscripts.getPackagesWithInstallScripts)();
33
+ const trustedOrIgnored = new Set([
34
+ ...allowedScripts,
35
+ ...IGNORE
36
+ ]);
37
+ const untrusted = packages.filter(({ location, name })=>{
38
+ return !!location && !trustedOrIgnored.has(name);
39
+ });
40
+ if (untrusted.length === 0) {
41
+ return;
42
+ }
43
+ const list = untrusted.map(({ name, version })=>` - ${name}@${version}`).join('\n');
44
+ console.warn([
45
+ 'WARNING: The following packages have untrusted install scripts.',
46
+ 'A future release will block them by default.',
47
+ 'Review and add trusted packages to --allow-scripts:',
48
+ list
49
+ ].join('\n'));
50
+ }
51
+
52
+ //# sourceMappingURL=warn-untrusted-install-scripts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utils/warn-untrusted-install-scripts.ts"],"sourcesContent":["/* eslint-disable no-console */\nimport { getPackagesWithInstallScripts } from './get-packages-with-install-scripts';\nimport { hasLockfileChanged } from './has-lockfile-changed';\n\n// These packages have scripts, but don't need them to function correctly.\n\nconst IGNORE = [\n '@parcel/watcher', // Installs platform-specific binary via optionalDependencies, install script is a legacy fallback\n '@progress/kendo-licensing', // Validates Kendo UI license key, not needed for functionality\n '@scarf/scarf', // Sends anonymous analytics/telemetry to Scarf, usage-tracking mechanism with no functional purpose\n '@swc/core', // Installs platform-specific binary via optionalDependencies, postinstall is a legacy fallback\n '@vaadin/vaadin-usage-statistics', // Toggles Vaadin's development-time telemetry, no effect on functionality\n 'contentful', // v9 printed a message announcing that v10 was available, no functional purpose\n 'core-js-pure', // Prints a donation/sponsorship banner to the console, no functional purpose\n 'core-js', // Prints a donation/sponsorship banner to the console, no functional purpose\n 'es5-ext', // Displays politically motivated message targeted at Russian developers, no effect on functionality\n 'esbuild', // Installs platform-specific binary via optionalDependencies, postinstall is a legacy fallback\n 'less', // Installs Playwright browsers for Less's own test suite\n 'unrs-resolver', // Installs platform-specific binary via optionalDependencies, postinstall is a legacy fallback\n];\n\nexport function warnUntrustedInstallScripts(allowedScripts: string[], lockFileName: string) {\n if (!hasLockfileChanged(lockFileName)) {\n return;\n }\n\n const packages = getPackagesWithInstallScripts();\n const trustedOrIgnored = new Set([...allowedScripts, ...IGNORE]);\n const untrusted = packages.filter(({ location, name }) => {\n return !!location && !trustedOrIgnored.has(name);\n });\n\n if (untrusted.length === 0) {\n return;\n }\n\n const list = untrusted.map(({ name, version }) => ` - ${name}@${version}`).join('\\n');\n console.warn(\n [\n 'WARNING: The following packages have untrusted install scripts.',\n 'A future release will block them by default.',\n 'Review and add trusted packages to --allow-scripts:',\n list,\n ].join('\\n')\n );\n}\n"],"names":["warnUntrustedInstallScripts","IGNORE","allowedScripts","lockFileName","hasLockfileChanged","packages","getPackagesWithInstallScripts","trustedOrIgnored","Set","untrusted","filter","location","name","has","length","list","map","version","join","console","warn"],"mappings":"AAAA,6BAA6B;;;;+BAqBbA;;;eAAAA;;;+CApB8B;oCACX;AAEnC,0EAA0E;AAE1E,MAAMC,SAAS;IACX;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACH;AAEM,SAASD,4BAA4BE,cAAwB,EAAEC,YAAoB;IACtF,IAAI,CAACC,IAAAA,sCAAkB,EAACD,eAAe;QACnC;IACJ;IAEA,MAAME,WAAWC,IAAAA,4DAA6B;IAC9C,MAAMC,mBAAmB,IAAIC,IAAI;WAAIN;WAAmBD;KAAO;IAC/D,MAAMQ,YAAYJ,SAASK,MAAM,CAAC,CAAC,EAAEC,QAAQ,EAAEC,IAAI,EAAE;QACjD,OAAO,CAAC,CAACD,YAAY,CAACJ,iBAAiBM,GAAG,CAACD;IAC/C;IAEA,IAAIH,UAAUK,MAAM,KAAK,GAAG;QACxB;IACJ;IAEA,MAAMC,OAAON,UAAUO,GAAG,CAAC,CAAC,EAAEJ,IAAI,EAAEK,OAAO,EAAE,GAAK,CAAC,IAAI,EAAEL,KAAK,CAAC,EAAEK,SAAS,EAAEC,IAAI,CAAC;IACjFC,QAAQC,IAAI,CACR;QACI;QACA;QACA;QACAL;KACH,CAACG,IAAI,CAAC;AAEf"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@servicetitan/install",
3
- "version": "36.1.2-canary.4",
3
+ "version": "36.1.2-canary.6",
4
4
  "description": "Lightweight wrapper around npm install that configures access to private packages",
5
5
  "homepage": "https://docs.st.dev/docs/frontend/uikit/install",
6
6
  "repository": {
@@ -29,6 +29,14 @@
29
29
  "cli": {
30
30
  "webpack": false
31
31
  },
32
+ "peerDependencies": {
33
+ "js-yaml": "~4.1.0"
34
+ },
35
+ "peerDependenciesMeta": {
36
+ "js-yaml": {
37
+ "optional": true
38
+ }
39
+ },
32
40
  "devDependencies": {
33
41
  "ts-node": "~10.9.2"
34
42
  }
package/src/cli/index.ts CHANGED
@@ -1,11 +1,15 @@
1
1
  import { parseArgs } from 'util';
2
2
  import { debug } from '../utils';
3
+ import type { Args } from './install';
3
4
  import { Install } from './install';
4
5
 
5
6
  const args = (function getArgs() {
6
- const { values, tokens } = parseArgs({
7
+ const { tokens } = parseArgs({
7
8
  args: process.argv.slice(2),
8
9
  options: {
10
+ 'allow-scripts': { type: 'string', multiple: true },
11
+ 'no-allow-scripts': { type: 'boolean' },
12
+ 'allow-all-scripts': { type: 'boolean' },
9
13
  'fix': { type: 'boolean' },
10
14
  'quiet': { type: 'boolean' },
11
15
  'token': { type: 'boolean' },
@@ -14,19 +18,34 @@ const args = (function getArgs() {
14
18
  tokens: true,
15
19
  });
16
20
 
21
+ const result: Args = {};
22
+
23
+ const allowScripts: string[] = [];
24
+
17
25
  tokens.forEach(token => {
18
26
  if (token.kind === 'option') {
19
- if (token.name.startsWith('no-')) {
20
- const name = token.name.slice(3) as keyof typeof values;
21
- values[name] = false;
22
- delete values[token.name];
23
- } else {
24
- values[token.name] = token.value ?? true;
27
+ switch (token.name) {
28
+ case 'allow-scripts':
29
+ allowScripts.push(token.value);
30
+ break;
31
+ case 'no-allow-scripts':
32
+ result.allowScripts = false;
33
+ break;
34
+ case 'allow-all-scripts':
35
+ result.allowAllScripts = true;
36
+ break;
37
+ case 'no-token':
38
+ result.token = false;
39
+ break;
40
+ default:
41
+ result[token.name] = true;
25
42
  }
26
43
  }
27
44
  });
28
45
 
29
- return { ...values };
46
+ result.allowScripts ??= allowScripts;
47
+
48
+ return result;
30
49
  })();
31
50
 
32
51
  debug('install:args', { args });
@@ -9,8 +9,11 @@ const REPO_NAME = 'frontend-dev-config';
9
9
  const AUTH_TOKEN_KEY = '//registry.npmjs.org/:_authToken';
10
10
  const AUTH_TOKEN_REGEX = /^\/\/registry\.npmjs\.org\/:_authToken=\s*(?<authToken>.+)/m;
11
11
  const ENVIRONMENT_VARIABLE_REGEX = /\${(?<environmentVariable>[^}]+)}/;
12
+ const ALLOWED_SCRIPTS = ['@servicetitan/startup', 'cypress', 'msw', 'nx'];
12
13
 
13
14
  export interface Args {
15
+ allowAllScripts?: boolean;
16
+ allowScripts?: string[] | false;
14
17
  fix?: boolean;
15
18
  quiet?: boolean;
16
19
  token?: boolean;
@@ -24,9 +27,7 @@ export class Install {
24
27
  }
25
28
 
26
29
  execute() {
27
- if (!this.args.quiet) {
28
- console.log(`install cli v${getVersion()}`);
29
- }
30
+ this.log(`install cli v${getVersion()}`);
30
31
 
31
32
  const env = this.configureNpmToken();
32
33
  this.installPackages(env);
@@ -37,9 +38,7 @@ export class Install {
37
38
  return;
38
39
  }
39
40
 
40
- if (!this.args.quiet) {
41
- console.log('Configuring NPM token ...');
42
- }
41
+ this.log('Configuring NPM token ...');
43
42
 
44
43
  if (this.args.token !== true) {
45
44
  if (npmWhoAmI() === 'st-team') {
@@ -116,10 +115,37 @@ export class Install {
116
115
 
117
116
  const packageManager = getPackageManager();
118
117
 
118
+ this.log(`Running ${packageManager.command} install`);
119
+
120
+ let allowScripts: string[] | false | undefined;
121
+ if (this.args.allowAllScripts) {
122
+ this.log('Allowing all install scripts');
123
+ } else if (this.args.allowScripts === false) {
124
+ allowScripts = false;
125
+ } else {
126
+ allowScripts = [...ALLOWED_SCRIPTS];
127
+ if (Array.isArray(this.args.allowScripts)) {
128
+ const extra = this.parseScripts(this.args.allowScripts);
129
+ if (extra.length) {
130
+ this.log(`Allowing additional install scripts: ${extra.join(', ')}`);
131
+ }
132
+ allowScripts.push(...extra);
133
+ }
134
+ }
135
+
136
+ packageManager.installPackages({ ...this.args, allowScripts }, { env, stdio: 'inherit' });
137
+ }
138
+
139
+ private log(message: string) {
119
140
  if (!this.args.quiet) {
120
- console.log(`Running ${packageManager.command} install`);
141
+ console.log(message);
121
142
  }
143
+ }
122
144
 
123
- packageManager.installPackages({ fix: this.args.fix }, { env, stdio: 'inherit' });
145
+ private parseScripts(allowedScripts: string[]) {
146
+ return (allowedScripts ?? [])
147
+ .flatMap(s => s.split(','))
148
+ .map(s => s.trim())
149
+ .filter(s => !!s);
124
150
  }
125
151
  }
@@ -0,0 +1 @@
1
+ export * from './mock-package-manager';
@@ -23,4 +23,6 @@ export class MockPackageManager extends PackageManager {
23
23
  protected parseLockFile(): unknown {
24
24
  return undefined;
25
25
  }
26
+
27
+ protected postInstall(): void {}
26
28
  }
@@ -1,3 +1,3 @@
1
1
  export { getPackageManager } from './get-package-manager';
2
2
  export { PackageManager } from './package-manager';
3
- export type { DeclaredVersionQuery, ResolvedVersionQuery } from './package-manager';
3
+ export type { DeclaredVersionQuery, InstallArgs, ResolvedVersionQuery } from './package-manager';
@@ -1,5 +1,6 @@
1
+ /* eslint-disable no-console */
1
2
  import fs from 'fs';
2
- import { isCI, runCommand } from '../utils';
3
+ import { isCI, runCommand, warnUntrustedInstallScripts } from '../utils';
3
4
  import type { DeclaredVersionQuery, InstallArgs, ResolvedVersionQuery } from './package-manager';
4
5
  import { PackageManager } from './package-manager';
5
6
 
@@ -34,12 +35,13 @@ export class NpmPackageManager extends PackageManager<NpmLockFile> {
34
35
  return this.findEntry({ workspacePackage, package: dependency })?.version;
35
36
  }
36
37
 
37
- protected getInstallArgs({ fix }: InstallArgs): string[] {
38
+ protected getInstallArgs({ fix, allowScripts }: InstallArgs): string[] {
38
39
  return [
39
40
  isCI() ? 'ci' : 'i',
40
41
  '--audit=false',
41
42
  '--fund=false',
42
43
  '--legacy-peer-deps',
44
+ ...(allowScripts === false || allowScripts?.length ? ['--ignore-scripts'] : []),
43
45
  ...(fix ? ['--package-lock-only', '--prefer-dedupe'] : []),
44
46
  ];
45
47
  }
@@ -52,6 +54,45 @@ export class NpmPackageManager extends PackageManager<NpmLockFile> {
52
54
  }
53
55
  }
54
56
 
57
+ protected postInstall(args: InstallArgs, options?: Parameters<typeof runCommand>[2]): void {
58
+ if (args.fix || args.allowAllScripts) {
59
+ return;
60
+ }
61
+
62
+ this.runAllowedScripts(args);
63
+ this.runProjectPostinstall(args, options);
64
+ }
65
+
66
+ private runAllowedScripts(args: InstallArgs) {
67
+ if (args.allowScripts === false || !args.allowScripts?.length) {
68
+ return;
69
+ }
70
+
71
+ try {
72
+ runCommand('npm', ['rebuild', ...args.allowScripts]);
73
+ } catch {
74
+ console.error(`Failed to run allowed scripts: ${args.allowScripts.join(', ')}`);
75
+ process.exitCode = 1;
76
+ }
77
+
78
+ warnUntrustedInstallScripts(args.allowScripts, this.lockFileName);
79
+ }
80
+
81
+ private runProjectPostinstall(
82
+ args: InstallArgs,
83
+ options?: Parameters<typeof runCommand>[2]
84
+ ): void {
85
+ if (args.allowScripts === false) {
86
+ return;
87
+ }
88
+
89
+ try {
90
+ runCommand('npm', ['run', 'postinstall', '--if-present'], options);
91
+ } catch {
92
+ process.exitCode = 1;
93
+ }
94
+ }
95
+
55
96
  /**
56
97
  * Looks up a lockfile entry for the given workspace package, falling back
57
98
  * to the hoisted root entry. `workspacePackage` is the package's relative
@@ -1,6 +1,8 @@
1
1
  import { runCommand } from '../utils';
2
2
 
3
3
  export interface InstallArgs {
4
+ allowAllScripts?: boolean;
5
+ allowScripts?: string[] | false;
4
6
  fix?: boolean;
5
7
  }
6
8
 
@@ -19,10 +21,6 @@ export abstract class PackageManager<LockFile = unknown> {
19
21
  abstract readonly command: string;
20
22
  abstract readonly lockFileName: string;
21
23
 
22
- get execCommand(): string {
23
- return `${this.command} exec`;
24
- }
25
-
26
24
  #lockFile: LockFile | undefined;
27
25
  #lockFileLoaded = false;
28
26
 
@@ -32,6 +30,7 @@ export abstract class PackageManager<LockFile = unknown> {
32
30
 
33
31
  installPackages(args: InstallArgs = {}, options?: Parameters<typeof runCommand>[2]) {
34
32
  runCommand(this.command, this.getInstallArgs(args), options);
33
+ this.postInstall(args, options);
35
34
  this.reset();
36
35
  }
37
36
 
@@ -54,4 +53,8 @@ export abstract class PackageManager<LockFile = unknown> {
54
53
 
55
54
  protected abstract getInstallArgs(args: InstallArgs): string[];
56
55
  protected abstract parseLockFile(): LockFile | undefined;
56
+ protected abstract postInstall(
57
+ args: InstallArgs,
58
+ options?: Parameters<typeof runCommand>[2]
59
+ ): void;
57
60
  }
@@ -58,7 +58,11 @@ export class PnpmPackageManager extends PackageManager<PnpmLockFile> {
58
58
  }
59
59
 
60
60
  protected parseLockFile(): PnpmLockFile | undefined {
61
- const yaml = require('js-yaml'); // eslint-disable-line import/no-extraneous-dependencies
61
+ /*
62
+ * js-yaml is an optional peer; let MODULE_NOT_FOUND surface so a caller
63
+ * missing the dep gets a clear error instead of silent `undefined`.
64
+ */
65
+ const yaml = require('js-yaml');
62
66
  try {
63
67
  return yaml.load(fs.readFileSync(this.lockFileName, 'utf-8'));
64
68
  } catch {
@@ -66,6 +70,10 @@ export class PnpmPackageManager extends PackageManager<PnpmLockFile> {
66
70
  }
67
71
  }
68
72
 
73
+ protected postInstall(): void {
74
+ // no-op
75
+ }
76
+
69
77
  private resolveVersion(workspacePackage: string, dependency: string): string | undefined {
70
78
  const importer = this.getLockFile()?.importers?.[workspacePackage];
71
79
  const entry =
@@ -0,0 +1,24 @@
1
+ import { runCommand } from './os';
2
+
3
+ interface PackageWithScript {
4
+ location: string;
5
+ name: string;
6
+ version: string;
7
+ }
8
+
9
+ const SELECTORS = ['preinstall', 'install', 'postinstall']
10
+ .map(script => `:attr(scripts, [${script}])`)
11
+ .join(', ');
12
+
13
+ export function getPackagesWithInstallScripts(): PackageWithScript[] {
14
+ try {
15
+ const result = runCommand('npm', ['query', SELECTORS, '--json']);
16
+ return JSON.parse(result).map(({ location, name, version }: PackageWithScript) => ({
17
+ location,
18
+ name,
19
+ version,
20
+ }));
21
+ } catch {
22
+ return [];
23
+ }
24
+ }
@@ -0,0 +1,10 @@
1
+ import { runCommand } from './os';
2
+
3
+ export function hasLockfileChanged(lockFileName: string) {
4
+ try {
5
+ const result = runCommand('git', ['diff', '--name-only', 'HEAD', '--', lockFileName]);
6
+ return result.trim().length > 0;
7
+ } catch {
8
+ return true;
9
+ }
10
+ }
@@ -1,7 +1,10 @@
1
1
  export * from './ci';
2
2
  export * from './debug';
3
+ export * from './get-packages-with-install-scripts';
3
4
  export * from './get-version';
4
5
  export * from './git';
6
+ export * from './has-lockfile-changed';
5
7
  export * from './npm';
6
8
  export * from './os';
7
9
  export * from './read-json';
10
+ export * from './warn-untrusted-install-scripts';
@@ -0,0 +1,46 @@
1
+ /* eslint-disable no-console */
2
+ import { getPackagesWithInstallScripts } from './get-packages-with-install-scripts';
3
+ import { hasLockfileChanged } from './has-lockfile-changed';
4
+
5
+ // These packages have scripts, but don't need them to function correctly.
6
+
7
+ const IGNORE = [
8
+ '@parcel/watcher', // Installs platform-specific binary via optionalDependencies, install script is a legacy fallback
9
+ '@progress/kendo-licensing', // Validates Kendo UI license key, not needed for functionality
10
+ '@scarf/scarf', // Sends anonymous analytics/telemetry to Scarf, usage-tracking mechanism with no functional purpose
11
+ '@swc/core', // Installs platform-specific binary via optionalDependencies, postinstall is a legacy fallback
12
+ '@vaadin/vaadin-usage-statistics', // Toggles Vaadin's development-time telemetry, no effect on functionality
13
+ 'contentful', // v9 printed a message announcing that v10 was available, no functional purpose
14
+ 'core-js-pure', // Prints a donation/sponsorship banner to the console, no functional purpose
15
+ 'core-js', // Prints a donation/sponsorship banner to the console, no functional purpose
16
+ 'es5-ext', // Displays politically motivated message targeted at Russian developers, no effect on functionality
17
+ 'esbuild', // Installs platform-specific binary via optionalDependencies, postinstall is a legacy fallback
18
+ 'less', // Installs Playwright browsers for Less's own test suite
19
+ 'unrs-resolver', // Installs platform-specific binary via optionalDependencies, postinstall is a legacy fallback
20
+ ];
21
+
22
+ export function warnUntrustedInstallScripts(allowedScripts: string[], lockFileName: string) {
23
+ if (!hasLockfileChanged(lockFileName)) {
24
+ return;
25
+ }
26
+
27
+ const packages = getPackagesWithInstallScripts();
28
+ const trustedOrIgnored = new Set([...allowedScripts, ...IGNORE]);
29
+ const untrusted = packages.filter(({ location, name }) => {
30
+ return !!location && !trustedOrIgnored.has(name);
31
+ });
32
+
33
+ if (untrusted.length === 0) {
34
+ return;
35
+ }
36
+
37
+ const list = untrusted.map(({ name, version }) => ` - ${name}@${version}`).join('\n');
38
+ console.warn(
39
+ [
40
+ 'WARNING: The following packages have untrusted install scripts.',
41
+ 'A future release will block them by default.',
42
+ 'Review and add trusted packages to --allow-scripts:',
43
+ list,
44
+ ].join('\n')
45
+ );
46
+ }