switch-profile 1.1.0 → 2.0.0

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/index.js CHANGED
@@ -1,411 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // NOTE: The official inquirer documentation is really good. To know more about the different question types,
4
- // please refer to https://www.npmjs.com/package/inquirer#prompt-types
5
-
6
- const program = require('commander')
7
- const inquirer = require('inquirer')
8
- const { EOL } = require('os')
9
- const IS_WINDOWS = process.platform === 'win32'
10
- const { listProfiles, getCredentials, getDefaultProfile, updateDefaultProfile, deleteProfiles, createProfile, regions, createSsoProfile, awsCliV2Exists } = require('./src/aws')
11
- const { printAWSerrors } = require('./src/core')
12
- require('colors')
13
- const { version } = require('./package.json')
14
- program.version(version) // This is required is you wish to support the --version option.
15
-
16
- const OPTIONS_KEY = '_options_4s2s3a'
17
- const ABORT_KEY = '_abort_rfewq1'
18
-
19
- inquirer.registerPrompt('autocomplete', require('inquirer-autocomplete-prompt'))
20
-
21
- const chooseProfileName = async (denyList) => {
22
- let { name } = await inquirer.prompt([
23
- {
24
- type: 'input',
25
- name: 'name',
26
- message: 'Enter a profile name (alphanumerical lowercase and \'-\' characters only)'
27
- }
28
- ])
29
-
30
- if (!name) {
31
- console.log('Profile name is required. Please try again.'.red)
32
- name = await chooseProfileName()
33
- }
34
-
35
- if (/[^a-z0-9_-]/.test(name)) {
36
- console.log('Profile name contained invalid characters. Only alphanumerical lowercase and \'-\' characters are allowed. Please try again.'.red)
37
- name = await chooseProfileName()
38
- }
39
-
40
- if (name.length < 2) {
41
- console.log('Profile name is not long enough. The profile name must be longer or equal to 2 characters. Please try again.'.red)
42
- name = await chooseProfileName()
43
- }
44
-
45
- if (denyList && denyList.some(n => n == name)) {
46
- console.log(`Profile name ${name.bold} already exist. Please try again.`.red)
47
- name = await chooseProfileName()
48
- }
49
-
50
- return name
51
- }
52
-
53
- const chooseNonEmpty = async (prop, message) => {
54
- let { value } = await inquirer.prompt([
55
- {
56
- type: 'input',
57
- name: 'value',
58
- message
59
- }
60
- ])
61
-
62
- if (!value) {
63
- console.log(`${prop} cannot be empty. Please try again.`.red)
64
- value = await chooseNonEmpty(prop, message)
65
- }
66
-
67
- return value
68
- }
69
-
70
- const chooseRegions = async () => {
71
- const { region } = await inquirer.prompt([
72
- {
73
- type: 'autocomplete',
74
- name: 'region',
75
- message: 'Select a region:',
76
- pageSize: 20,
77
- source: function(answersSoFar, input) {
78
- if (input)
79
- return regions.filter(r => `${r.code} - ${r.name}`.toLowerCase().indexOf(input.toLowerCase()) >= 0).map(r => ({
80
- name: `${r.code} - ${r.name}`,
81
- value:r.code
82
- }))
83
- else
84
- return regions.map(r => ({
85
- name: `${r.code} - ${r.name}`,
86
- value:r.code
87
- }))
88
- }
89
- }
90
- ])
91
-
92
- return region
93
- }
94
-
95
- const createNewProfile = async (profiles, makeItDefault) => {
96
- const name = await chooseProfileName(profiles.map(p => p.name))
97
- const { type } = await inquirer.prompt([
98
- {
99
- type: 'list',
100
- name: 'type',
101
- message: 'Choose an AWS profile type: ',
102
- choices: ['standard','sso']
103
- }
104
- ])
105
-
106
- if (type == 'standard') {
107
- const aws_access_key_id = await chooseNonEmpty('aws_access_key_id', 'Enter the profile\'s access key:')
108
- const aws_secret_access_key = await chooseNonEmpty('aws_secret_access_key', 'Enter the profile\'s access secret key:')
109
- const region = await chooseRegions()
110
- const [profileErrors] = await createProfile({ name, aws_access_key_id, aws_secret_access_key, region })
111
- if (profileErrors)
112
- return printAWSerrors([new Error('Fail to create profile'), ...profileErrors])
113
- } else {
114
- console.log('')
115
- console.log('┌─────────────────────────────────────────────────────────────────────┐'.cyan)
116
- console.log('│ SSO Profile Setup Guide │'.cyan)
117
- console.log('├─────────────────────────────────────────────────────────────────────┤'.cyan)
118
- console.log('│ │'.cyan)
119
- console.log('│ You\'re about to run \'aws configure sso\'. Here\'s what to expect: │'.cyan)
120
- console.log('│ │'.cyan)
121
- console.log('│ 1. SSO session name'.bold + ' │'.cyan)
122
- console.log('│ Provide a name (e.g., "my-company-sso"). │'.cyan)
123
- console.log('│ This enables token reuse across profiles and automatic refresh. │'.cyan)
124
- console.log('│ Skipping this uses the legacy format (no auto-refresh). │'.cyan)
125
- console.log('│ │'.cyan)
126
- console.log('│ 2. SSO start URL'.bold + ' │'.cyan)
127
- console.log('│ Your AWS SSO portal URL (e.g., https://my-co.awsapps.com/start) │'.cyan)
128
- console.log('│ Ask your AWS administrator if you don\'t have it. │'.cyan)
129
- console.log('│ │'.cyan)
130
- console.log('│ 3. SSO region'.bold + ' │'.cyan)
131
- console.log('│ The region where your SSO instance is configured. │'.cyan)
132
- console.log('│ WARNING: This is NOT your deployment region. │'.yellow)
133
- console.log('│ Using the wrong region causes "invalid_grant" errors. │'.yellow)
134
- console.log('│ │'.cyan)
135
- console.log('│ Docs: https://docs.aws.amazon.com/cli/latest/userguide/ │'.cyan)
136
- console.log('│ cli-configure-sso.html │'.cyan)
137
- console.log('│ │'.cyan)
138
- console.log('└─────────────────────────────────────────────────────────────────────┘'.cyan)
139
- console.log('')
140
-
141
- const [ssoErrors] = await createSsoProfile(name)
142
- if (ssoErrors)
143
- return printAWSerrors([new Error(`Fail to create SSO profile ${name}`), ...ssoErrors])
144
- }
145
-
146
- console.log(`New profile ${name.bold} successfully created 🚀`.green)
147
-
148
- if (makeItDefault === false)
149
- return
150
-
151
- if (makeItDefault === undefined) {
152
- const { setAsDefault } = await inquirer.prompt([
153
- {
154
- type: 'confirm',
155
- name: 'setAsDefault',
156
- message: 'Do you wish to set this new profile as the default?',
157
- }
158
- ])
159
-
160
- if (!setAsDefault)
161
- return
162
- }
163
-
164
- const [listErrors2, profiles2] = await listProfiles()
165
- if (listErrors2)
166
- return printAWSerrors([new Error('Fail to list profiles'), ...listErrors2])
167
-
168
- await setProfileToDefault(name, profiles2)
169
- }
170
-
171
- const switchCmd = async () => {
172
- const [awsCliErrors, awsCliExists] = await awsCliV2Exists(true)
173
- if (awsCliErrors)
174
- return printAWSerrors(awsCliErrors, { noStack:true })
175
-
176
- if (!awsCliExists) {
177
- if (process.platform == 'darwin') {
178
- console.log('AWS CLI seems to not be installed. Try installing it as follow\n'.red)
179
- console.log('brew install awscli')
180
- console.log('brew link --overwrite awscli')
181
- return
182
- } else if (process.platform == 'win32') {
183
- console.log('AWS CLI seems to not be installed. Download the installer from:\n'.red)
184
- console.log('https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html')
185
- return
186
- } else {
187
- console.log('AWS CLI seems to not be installed. Try installing it as follow\n'.red)
188
- console.log('curl "https://s3.amazonaws.com/aws-cli/awscli-bundle.zip" -o "awscli-bundle.zip"')
189
- console.log('unzip awscli-bundle.zip')
190
- console.log('sudo ./awscli-bundle/install -i /usr/local/aws -b /usr/local/bin/aws')
191
- return
192
- }
193
- }
194
-
195
- const [defaultProfileErrors, defaultProfile] = await getDefaultProfile()
196
- if (defaultProfileErrors)
197
- return printAWSerrors([new Error('Fail to get default profile'), ...defaultProfileErrors])
198
-
199
- const defaultProfileName = defaultProfile && defaultProfile.profile ? defaultProfile.profile : ''
200
- let defaultProfileExpired = false
201
- if (defaultProfileName) {
202
- const expiryDate = defaultProfile.expiry_date ? new Date(defaultProfile.expiry_date) : null
203
- const messages = [EOL,`Current default profile: ${defaultProfileName.bold}`.cyan]
204
- if (expiryDate) {
205
- const exp = expiryDate.getTime()
206
- const now = Date.now()
207
- if (now > exp) {
208
- defaultProfileExpired = true
209
- messages.push(' WARNING: Expired'.yellow)
210
- } else if (now+2*60*1000 > exp)
211
- messages.push(' WARNING: Expires in less than 2 minutes'.yellow)
212
- else {
213
- const timeLeftInMin = ((exp-now)/60000).toFixed(2)
214
- messages.push(` INFO: This profile expires in ${timeLeftInMin} minutes`.cyan)
215
- }
216
- }
217
- messages.push(EOL)
218
- console.log(messages.join(''))
219
- } else
220
- console.log(`${EOL}Current default profile: ${'unknown'.bold} (pick one up in the list below and we'll remember next time)${EOL}`.cyan)
221
-
222
- const [listErrors, profiles] = await listProfiles()
223
- if (listErrors)
224
- return printAWSerrors([new Error('Fail to list profiles'), ...listErrors])
225
-
226
- const profileCount = profiles.length
227
-
228
- if (!profileCount) {
229
- const { create } = await inquirer.prompt([
230
- {
231
- type: 'confirm',
232
- name: 'create',
233
- message: 'There no profiles yet. Do you wish to create one now? ',
234
- }
235
- ])
236
-
237
- if (!create)
238
- return
239
-
240
- console.log('Ooh yeah ✨! I like your style. Let\'s do this!'.cyan)
241
- await createNewProfile([], true)
242
- } else {
243
- const { friendlyName } = await inquirer.prompt([
244
- {
245
- type: 'list',
246
- name: 'friendlyName',
247
- message: `Choose one of the following ${profileCount} profiles:`,
248
- pageSize:20,
249
- default: 2,
250
- choices: [
251
- { name:'More options', value:OPTIONS_KEY },
252
- { name: 'Abort', value:ABORT_KEY },
253
- new inquirer.Separator(), ...profiles.map((p,i) => {
254
- return {
255
- name: `${i+1}. ${p.friendlyName}`,
256
- value: p.friendlyName
257
- }
258
- })]
259
- }
260
- ])
261
-
262
- if (!friendlyName || friendlyName == ABORT_KEY)
263
- return
264
-
265
- if (friendlyName == OPTIONS_KEY) {
266
- const { option } = await inquirer.prompt([
267
- {
268
- type: 'list',
269
- name: 'option',
270
- message: 'Options:',
271
- pageSize:20,
272
- choices: [
273
- ...(defaultProfileExpired ? [{ name: `Refresh default profile ${defaultProfileName.bold}` ,value:'refresh' }] : []),
274
- { name: 'Create profile', value:'new' },
275
- { name: 'Delete profiles', value:'delete' },
276
- { name: 'Abort', value:ABORT_KEY }
277
- ]
278
- }
279
- ])
280
-
281
- if (option == 'refresh')
282
- await setProfileToDefault(defaultProfileName, profiles, `AWS profile ${defaultProfileName.bold} successfully refreshed.`)
283
- else if (option == 'delete') {
284
- const { delProfiles } = await inquirer.prompt([
285
- {
286
- type: 'checkbox',
287
- name: 'delProfiles',
288
- message: 'Select the profiles you wish to delete (SPACE to select, ENTER to confirm):',
289
- pageSize: 20,
290
- choices: profiles.map((p,i) => {
291
- return {
292
- name: `${i+1}. ${p.friendlyName}`,
293
- value: p.name
294
- }
295
- })
296
- }
297
- ])
298
-
299
- if (!delProfiles.length)
300
- return
301
-
302
- const label = delProfiles.length > 1 ? 'profiles' : 'profile'
303
- const labelText = delProfiles.length > 1 ? `those ${delProfiles.length} profiles` : 'this profile'
304
- const { delConfirm } = await inquirer.prompt([
305
- {
306
- type: 'confirm',
307
- name: 'delConfirm',
308
- message: `Are you sure you want to delete ${labelText}? `,
309
- }
310
- ])
311
-
312
- if (!delConfirm)
313
- return
314
-
315
- if (defaultProfileName && delProfiles.some(p => p == defaultProfileName)) {
316
- return printAWSerrors([new Error(`Fail to delete ${label}. Profile ${defaultProfileName.bold} is the current default. Set another profile as the default, then try deleting again.`)], { noStack:true })
317
- }
318
-
319
- const [delErrors] = await deleteProfiles(delProfiles)
320
- if (delErrors)
321
- return printAWSerrors([new Error(`Fail to delete ${label}`), ...delErrors])
322
-
323
- console.log(`AWS profile${delProfiles.length > 1 ? 's' : ''} successfully deleted.`.green)
324
- } else if (option == 'new')
325
- await createNewProfile(profiles)
326
- else if (option == ABORT_KEY)
327
- return
328
-
329
- return
330
- } else
331
- await setProfileToDefault(friendlyName, profiles)
332
- }
333
- }
334
-
335
- const printExportHint = (profileName) => {
336
- const lines = IS_WINDOWS ? [
337
- ' To lock this profile to this terminal session, run: ',
338
- '',
339
- ` PowerShell: $env:AWS_PROFILE = "${profileName}"`,
340
- ` CMD: set AWS_PROFILE=${profileName}`,
341
- '',
342
- ' This prevents other terminals from affecting this one. '
343
- ] : [
344
- ' To lock this profile to this terminal session, run: ',
345
- '',
346
- ` export AWS_PROFILE=${profileName}`,
347
- '',
348
- ' This prevents other terminals from affecting this one. '
349
- ]
350
- const width = Math.max(...lines.map(l => l.length))
351
- const pad = s => s + ' '.repeat(width - s.length)
352
- console.log('')
353
- console.log(('┌' + '─'.repeat(width) + '┐').cyan)
354
- const boldStart = IS_WINDOWS ? 2 : 2
355
- const boldEnd = IS_WINDOWS ? 3 : 2
356
- for (let i = 0; i < lines.length; i++) {
357
- const content = '│' + pad(lines[i]) + '│'
358
- console.log(i >= boldStart && i <= boldEnd ? content.cyan.bold : content.cyan)
359
- }
360
- console.log(('└' + '─'.repeat(width) + '┘').cyan)
361
- console.log('')
362
- }
363
-
364
- const setProfileToDefault = async (profileName, profileList, successMsg) => {
365
- const profile = profileList.find(p => p.friendlyName == profileName || p.name == profileName)
366
-
367
- if (!profile)
368
- return printAWSerrors([new Error(`Profile ${profileName.bold} was not found in ~/.aws/config. It may not have been created correctly. Try creating it again.`)], { noStack:true })
369
-
370
- // Gets the AWS credentials for a specific profile. If that profile is an SSO profile, this function has a series of
371
- // side-effects:
372
- // - If the local SSO session stored under ~/.aws/sso/cache has expired, then it will redirect the user to the SSO portal and eventually refresh that ~/.aws/sso/cache.
373
- // - If the local SSO creds stored under ~/.aws/cli/cache have expired (AWS_KEY, AWS_SECRET, AWS_SESSION), then they will be refreshed using the session stored under the ~/.aws/sso/cache.
374
- const [credsErrors, creds] = await getCredentials(profile.name, profile.sso_start_url)
375
- if (credsErrors)
376
- return printAWSerrors([new Error(`Fail to get credentials for profile ${profile.name}`), ...credsErrors])
377
-
378
- // console.log(profile)
379
- // console.log(creds)
380
-
381
- const [errors] = await updateDefaultProfile({
382
- ...creds,
383
- profile: profile.name,
384
- region: profile.region
385
- })
386
-
387
- if (errors)
388
- return printAWSerrors([new Error('Fail to update the default profile'), ...errors])
389
-
390
- console.log((successMsg || `AWS profile ${profile.name.bold} successfully set up as default.`).green)
391
- printExportHint(profile.name)
392
- }
393
-
394
- // 1. Creates your first command. This example shows an 'order' command with a required argument
395
- // called 'product' and an optional argument called 'option'.
396
- program
397
- .command('switch')
398
- .description('Default behavior. List the existing configuration and help select one. Equivalent to `npx switch-cloud`') // Optional description
399
- .action(switchCmd)
400
-
401
- // 2. Deals with cases where no command is passed.
402
- if (process.argv.length == 2)
403
- process.argv.push('switch')
404
-
405
- // 3. Starts the commander program
406
- program.parse(process.argv)
407
-
408
-
409
-
410
-
411
-
3
+ // Checked before anything else is loaded, so old Node versions get a clear message instead of a syntax error.
4
+ const [major, minor] = process.versions.node.split('.').map(Number)
5
+ if (major < 20 || (major == 20 && minor < 12)) {
6
+ console.error(`switch-profile needs Node.js 20.12 or later (you have ${process.versions.node}).\nUpdate Node.js (e.g. with nvm or fnm) and try again.`)
7
+ process.exit(1)
8
+ }
9
+
10
+ // A source checkout runs the sources; the published package runs the bundle.
11
+ const { existsSync } = require('fs')
12
+ const { join } = require('path')
13
+ const entry = existsSync(join(__dirname, 'src', 'cli.js')) && !process.env.SWITCH_PROFILE_DIST ? './src/cli.js' : './dist/cli.js'
14
+ require(entry).main(process.argv)
package/package.json CHANGED
@@ -1,15 +1,20 @@
1
1
  {
2
2
  "name": "switch-profile",
3
- "version": "1.1.0",
3
+ "version": "2.0.0",
4
4
  "main": "index.js",
5
- "bin": "index.js",
6
- "description": "NPX script that exposes terminal shortcut to easily switch between cloud configuration (aws, gcp).",
5
+ "bin": {
6
+ "switch-profile": "index.js"
7
+ },
8
+ "description": "Switch between AWS profiles from your terminal: fuzzy search, SSO login (device code over SSH), per-terminal AWS_PROFILE and tab-completion.",
7
9
  "keywords": [
8
- "aws-cli",
9
10
  "aws",
11
+ "aws-cli",
12
+ "aws-sso",
13
+ "iam-identity-center",
10
14
  "profile",
11
- "sso-profile",
12
- "sso"
15
+ "sso",
16
+ "cli",
17
+ "device-code"
13
18
  ],
14
19
  "repository": {
15
20
  "type": "git",
@@ -20,34 +25,35 @@
20
25
  },
21
26
  "homepage": "https://github.com/nicolasdao/switch-profile#readme",
22
27
  "scripts": {
23
- "dev": "TZ=UTC NODE_ENV=dev node index.js",
24
- "lint": "eslint index.js src/ test/ --fix",
25
- "push": "git push --follow-tags origin master && npm publish --access=public",
26
- "rls": "standard-version --release-as",
27
- "start": "TZ=UTC NODE_ENV=production node index.js",
28
+ "build": "esbuild src/cli.js --bundle --platform=node --target=node20.12 --format=cjs --minify-syntax --legal-comments=none --outfile=dist/cli.js",
29
+ "dev": "node index.js",
30
+ "lint": "eslint . --fix",
28
31
  "test": "mocha --exit",
32
+ "test:dist": "npm run build && SWITCH_PROFILE_DIST=1 mocha --exit test/cli.js",
33
+ "prepublishOnly": "npm run lint && npm test && npm run test:dist",
29
34
  "v": "node -e \"console.log(require('./package.json').version)\""
30
35
  },
31
36
  "author": "Nicolas Dao",
32
37
  "license": "BSD-3-Clause",
33
38
  "devDependencies": {
39
+ "@clack/prompts": "^1.8.1",
40
+ "@eslint/js": "^10.0.1",
34
41
  "chai": "^4.1.2",
42
+ "commander": "^14.0.3",
43
+ "esbuild": "^0.28.2",
35
44
  "eslint": "^10.0.0",
45
+ "fuzzysort": "^3.1.0",
46
+ "globals": "^17.13.0",
36
47
  "mocha": "^8.2.1",
37
- "standard-version": "^9.3.0"
48
+ "uqr": "^0.1.3"
38
49
  },
39
- "dependencies": {
40
- "archiver": "^5.3.0",
41
- "colors": "^1.4.0",
42
- "commander": "^8.0.0",
43
- "convert-stream": "^1.0.2",
44
- "core-async": "^2.0.4",
45
- "fast-glob": "^3.2.7",
46
- "inquirer": "^8.1.2",
47
- "inquirer-autocomplete-prompt": "^1.4.0",
48
- "mime-types": "^2.1.31",
49
- "puffy": "^1.6.0",
50
- "rimraf": "^3.0.2",
51
- "tar-stream": "^2.2.0"
50
+ "files": [
51
+ "index.js",
52
+ "dist/",
53
+ "LICENSE",
54
+ "README.md"
55
+ ],
56
+ "engines": {
57
+ "node": ">=20.12"
52
58
  }
53
59
  }
package/.eslintrc.json DELETED
@@ -1,39 +0,0 @@
1
- {
2
- "env": {
3
- "browser": true,
4
- "commonjs": true,
5
- "es6": true
6
- },
7
- "extends": "eslint:recommended",
8
- "globals": {
9
- "process": false,
10
- "describe": false,
11
- "it": false,
12
- "xit": false,
13
- "Buffer": false,
14
- "__dirname": false
15
- },
16
- "parserOptions": {
17
- "sourceType": "module",
18
- "ecmaVersion": 2018
19
- },
20
- "rules": {
21
- "no-console":0,
22
- "indent": [
23
- "error",
24
- "tab"
25
- ],
26
- "linebreak-style": [
27
- "error",
28
- "unix"
29
- ],
30
- "quotes": [
31
- "error",
32
- "single"
33
- ],
34
- "semi": [
35
- "error",
36
- "never"
37
- ]
38
- }
39
- }
package/CHANGELOG.md DELETED
@@ -1,120 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
-
5
- ## [1.1.0](https://github.com/nicolasdao/switch-profile/compare/v1.0.0...v1.1.0) (2026-03-21)
6
-
7
-
8
- ### Features
9
-
10
- * add Windows compatibility for profile switching, config parsing, and shell hints ([16ce46b](https://github.com/nicolasdao/switch-profile/commit/16ce46bc5cb1d92fc6d882358eaabc718a157f22))
11
-
12
- ## [1.0.0](https://github.com/nicolasdao/switch-profile/compare/v0.2.3...v1.0.0) (2026-03-21)
13
-
14
-
15
- ### Features
16
-
17
- * Display export AWS_PROFILE hint after profile switch for per-terminal isolation ([7dd09c8](https://github.com/nicolasdao/switch-profile/commit/7dd09c882708fcafd66fefc6139cd97a13d9b2fb))
18
-
19
- ### [0.2.3](https://github.com/nicolasdao/switch-profile/compare/v0.2.2...v0.2.3) (2026-02-11)
20
-
21
-
22
- ### Bug Fixes
23
-
24
- * Add support for AWS CLI v2 SSO session format and improve profile deletion UX ([4eb7366](https://github.com/nicolasdao/switch-profile/commit/4eb7366d6ed1f50f024128d94da213515a4ff9da))
25
-
26
- ### [0.2.2](https://github.com/nicolasdao/switch-profile/compare/v0.2.1...v0.2.2) (2026-02-10)
27
-
28
-
29
- ### Bug Fixes
30
-
31
- * SSO profile credentials written as undefined by falling back to aws configure export-credentials ([7067eff](https://github.com/nicolasdao/switch-profile/commit/7067eff15d376a3dd902ee4a03f5db7cfa539918))
32
-
33
- ### [0.2.1](https://github.com/nicolasdao/switch-profile/compare/v0.2.0...v0.2.1) (2026-02-08)
34
-
35
- ## [0.2.0](https://github.com/nicolasdao/switch-profile/compare/v0.1.2...v0.2.0) (2026-02-08)
36
-
37
-
38
- ### Bug Fixes
39
-
40
- * handle SSO profile creation failure and improve SSO setup UX ([b0ee837](https://github.com/nicolasdao/switch-profile/commit/b0ee83791bfbc1208cc5fb6b6f2850d4cbd160c9))
41
- * vulnerabilities ([3fa2575](https://github.com/nicolasdao/switch-profile/commit/3fa2575156f3e07a6de9cd077f3f8f75f9bceafa))
42
-
43
- ### [0.1.2](https://github.com/nicolasdao/switch-profile/compare/v0.1.1...v0.1.2) (2022-05-14)
44
-
45
-
46
- ### Bug Fixes
47
-
48
- * Multiple SSO profiles are not supported. It only uses one. ([b9d9d03](https://github.com/nicolasdao/switch-profile/commit/b9d9d03b4edfa048cc157376222378513138e257))
49
-
50
- ### [0.1.1](https://github.com/nicolasdao/switch-profile/compare/v0.1.0...v0.1.1) (2021-08-03)
51
-
52
-
53
- ### Bug Fixes
54
-
55
- * Edge cases where the SSO session expires and a forde login is required ([67f3667](https://github.com/nicolasdao/switch-profile/commit/67f36678f29f2ab5f02c4d4630eb1c7c41ccebbf))
56
-
57
- ## [0.1.0](https://github.com/nicolasdao/switch-profile/compare/v0.0.9...v0.1.0) (2021-08-03)
58
-
59
-
60
- ### Bug Fixes
61
-
62
- * Switching to an SSO profile adds an incorrect 'sso_' prefix to the default region in ~/.aws/config file ([384c17e](https://github.com/nicolasdao/switch-profile/commit/384c17e26b368754a5bfdb5ca47fd9996181f3b7))
63
-
64
- ### [0.0.9](https://github.com/nicolasdao/switch-profile/compare/v0.0.8...v0.0.9) (2021-07-19)
65
-
66
-
67
- ### Bug Fixes
68
-
69
- * Switching does not update the region in the ~/.aws/config ([14d6724](https://github.com/nicolasdao/switch-profile/commit/14d672429d81e3c421273d1e090fa4d444a09b5b))
70
-
71
- ### [0.0.8](https://github.com/nicolasdao/switch-profile/compare/v0.0.7...v0.0.8) (2021-07-19)
72
-
73
- ### [0.0.7](https://github.com/nicolasdao/switch-profile/compare/v0.0.6...v0.0.7) (2021-07-18)
74
-
75
-
76
- ### Features
77
-
78
- * Add ability to set up the new profile as default ([c667c3c](https://github.com/nicolasdao/switch-profile/commit/c667c3c29db2b43c86c083da36b67d6c27c737f8))
79
-
80
- ### [0.0.6](https://github.com/nicolasdao/switch-profile/compare/v0.0.5...v0.0.6) (2021-07-18)
81
-
82
-
83
- ### Features
84
-
85
- * Add support for congrats message ([a8a14dd](https://github.com/nicolasdao/switch-profile/commit/a8a14ddb4536c3fe6a153716f605796e436626bb))
86
-
87
- ### [0.0.5](https://github.com/nicolasdao/switch-profile/compare/v0.0.1...v0.0.5) (2021-07-18)
88
-
89
-
90
- ### Features
91
-
92
- * Add support for creating and deleting profiles ([cdbb115](https://github.com/nicolasdao/switch-profile/commit/cdbb115386536ce1d38d4de13d71b0e8dc1e4c68))
93
-
94
- ### [0.0.4](https://github.com/nicolasdao/switch-profile/compare/v0.0.1...v0.0.4) (2021-07-18)
95
-
96
-
97
- ### Features
98
-
99
- * Add support for creating and deleting profiles ([cdbb115](https://github.com/nicolasdao/switch-profile/commit/cdbb115386536ce1d38d4de13d71b0e8dc1e4c68))
100
-
101
- ### [0.0.3](https://github.com/nicolasdao/switch-profile/compare/v0.0.1...v0.0.3) (2021-07-18)
102
-
103
-
104
- ### Features
105
-
106
- * Add support for creating and deleting profiles ([cdbb115](https://github.com/nicolasdao/switch-profile/commit/cdbb115386536ce1d38d4de13d71b0e8dc1e4c68))
107
-
108
- ### [0.0.2](https://github.com/nicolasdao/switch-profile/compare/v0.0.1...v0.0.2) (2021-07-18)
109
-
110
-
111
- ### Features
112
-
113
- * Add support for creating and deleting profiles ([cdbb115](https://github.com/nicolasdao/switch-profile/commit/cdbb115386536ce1d38d4de13d71b0e8dc1e4c68))
114
-
115
- ### [0.0.1](https://github.com/nicolasdao/switch-profile/compare/v0.0.4...v0.0.1) (2021-07-18)
116
-
117
-
118
- ### Features
119
-
120
- * Add support for choosing a default profile ([73d936f](https://github.com/nicolasdao/switch-profile/commit/73d936fa95d5240dbbeb12e3f640e7436f1cc76f))