switch-profile 1.0.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,400 +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 { listProfiles, getCredentials, getDefaultProfile, updateDefaultProfile, deleteProfiles, createProfile, regions, createSsoProfile, awsCliV2Exists } = require('./src/aws')
10
- const { printAWSerrors } = require('./src/core')
11
- require('colors')
12
- const { version } = require('./package.json')
13
- program.version(version) // This is required is you wish to support the --version option.
14
-
15
- const OPTIONS_KEY = '_options_4s2s3a'
16
- const ABORT_KEY = '_abort_rfewq1'
17
-
18
- inquirer.registerPrompt('autocomplete', require('inquirer-autocomplete-prompt'))
19
-
20
- const chooseProfileName = async (denyList) => {
21
- let { name } = await inquirer.prompt([
22
- {
23
- type: 'input',
24
- name: 'name',
25
- message: 'Enter a profile name (alphanumerical lowercase and \'-\' characters only)'
26
- }
27
- ])
28
-
29
- if (!name) {
30
- console.log('Profile name is required. Please try again.'.red)
31
- name = await chooseProfileName()
32
- }
33
-
34
- if (/[^a-z0-9_-]/.test(name)) {
35
- console.log('Profile name contained invalid characters. Only alphanumerical lowercase and \'-\' characters are allowed. Please try again.'.red)
36
- name = await chooseProfileName()
37
- }
38
-
39
- if (name.length < 2) {
40
- console.log('Profile name is not long enough. The profile name must be longer or equal to 2 characters. Please try again.'.red)
41
- name = await chooseProfileName()
42
- }
43
-
44
- if (denyList && denyList.some(n => n == name)) {
45
- console.log(`Profile name ${name.bold} already exist. Please try again.`.red)
46
- name = await chooseProfileName()
47
- }
48
-
49
- return name
50
- }
51
-
52
- const chooseNonEmpty = async (prop, message) => {
53
- let { value } = await inquirer.prompt([
54
- {
55
- type: 'input',
56
- name: 'value',
57
- message
58
- }
59
- ])
60
-
61
- if (!value) {
62
- console.log(`${prop} cannot be empty. Please try again.`.red)
63
- value = await chooseNonEmpty(prop, message)
64
- }
65
-
66
- return value
67
- }
68
-
69
- const chooseRegions = async () => {
70
- const { region } = await inquirer.prompt([
71
- {
72
- type: 'autocomplete',
73
- name: 'region',
74
- message: 'Select a region:',
75
- pageSize: 20,
76
- source: function(answersSoFar, input) {
77
- if (input)
78
- return regions.filter(r => `${r.code} - ${r.name}`.toLowerCase().indexOf(input.toLowerCase()) >= 0).map(r => ({
79
- name: `${r.code} - ${r.name}`,
80
- value:r.code
81
- }))
82
- else
83
- return regions.map(r => ({
84
- name: `${r.code} - ${r.name}`,
85
- value:r.code
86
- }))
87
- }
88
- }
89
- ])
90
-
91
- return region
92
- }
93
-
94
- const createNewProfile = async (profiles, makeItDefault) => {
95
- const name = await chooseProfileName(profiles.map(p => p.name))
96
- const { type } = await inquirer.prompt([
97
- {
98
- type: 'list',
99
- name: 'type',
100
- message: 'Choose an AWS profile type: ',
101
- choices: ['standard','sso']
102
- }
103
- ])
104
-
105
- if (type == 'standard') {
106
- const aws_access_key_id = await chooseNonEmpty('aws_access_key_id', 'Enter the profile\'s access key:')
107
- const aws_secret_access_key = await chooseNonEmpty('aws_secret_access_key', 'Enter the profile\'s access secret key:')
108
- const region = await chooseRegions()
109
- const [profileErrors] = await createProfile({ name, aws_access_key_id, aws_secret_access_key, region })
110
- if (profileErrors)
111
- return printAWSerrors([new Error('Fail to create profile'), ...profileErrors])
112
- } else {
113
- console.log('')
114
- console.log('┌─────────────────────────────────────────────────────────────────────┐'.cyan)
115
- console.log('│ SSO Profile Setup Guide │'.cyan)
116
- console.log('├─────────────────────────────────────────────────────────────────────┤'.cyan)
117
- console.log('│ │'.cyan)
118
- console.log('│ You\'re about to run \'aws configure sso\'. Here\'s what to expect: │'.cyan)
119
- console.log('│ │'.cyan)
120
- console.log('│ 1. SSO session name'.bold + ' │'.cyan)
121
- console.log('│ Provide a name (e.g., "my-company-sso"). │'.cyan)
122
- console.log('│ This enables token reuse across profiles and automatic refresh. │'.cyan)
123
- console.log('│ Skipping this uses the legacy format (no auto-refresh). │'.cyan)
124
- console.log('│ │'.cyan)
125
- console.log('│ 2. SSO start URL'.bold + ' │'.cyan)
126
- console.log('│ Your AWS SSO portal URL (e.g., https://my-co.awsapps.com/start) │'.cyan)
127
- console.log('│ Ask your AWS administrator if you don\'t have it. │'.cyan)
128
- console.log('│ │'.cyan)
129
- console.log('│ 3. SSO region'.bold + ' │'.cyan)
130
- console.log('│ The region where your SSO instance is configured. │'.cyan)
131
- console.log('│ WARNING: This is NOT your deployment region. │'.yellow)
132
- console.log('│ Using the wrong region causes "invalid_grant" errors. │'.yellow)
133
- console.log('│ │'.cyan)
134
- console.log('│ Docs: https://docs.aws.amazon.com/cli/latest/userguide/ │'.cyan)
135
- console.log('│ cli-configure-sso.html │'.cyan)
136
- console.log('│ │'.cyan)
137
- console.log('└─────────────────────────────────────────────────────────────────────┘'.cyan)
138
- console.log('')
139
-
140
- const [ssoErrors] = await createSsoProfile(name)
141
- if (ssoErrors)
142
- return printAWSerrors([new Error(`Fail to create SSO profile ${name}`), ...ssoErrors])
143
- }
144
-
145
- console.log(`New profile ${name.bold} successfully created 🚀`.green)
146
-
147
- if (makeItDefault === false)
148
- return
149
-
150
- if (makeItDefault === undefined) {
151
- const { setAsDefault } = await inquirer.prompt([
152
- {
153
- type: 'confirm',
154
- name: 'setAsDefault',
155
- message: 'Do you wish to set this new profile as the default?',
156
- }
157
- ])
158
-
159
- if (!setAsDefault)
160
- return
161
- }
162
-
163
- const [listErrors2, profiles2] = await listProfiles()
164
- if (listErrors2)
165
- return printAWSerrors([new Error('Fail to list profiles'), ...listErrors2])
166
-
167
- await setProfileToDefault(name, profiles2)
168
- }
169
-
170
- const switchCmd = async () => {
171
- const [awsCliErrors, awsCliExists] = await awsCliV2Exists(true)
172
- if (awsCliErrors)
173
- return printAWSerrors(awsCliErrors, { noStack:true })
174
-
175
- if (!awsCliExists) {
176
- if (process.platform == 'darwin') {
177
- console.log('AWS CLI seems to not be installed. Try installing it as follow\n'.red)
178
- console.log('brew install awscli')
179
- console.log('brew link --overwrite awscli')
180
- return
181
- } else if (process.platform == 'win32') {
182
- console.log('AWS CLI seems to not be installed.'.red)
183
- return
184
- } else {
185
- console.log('AWS CLI seems to not be installed. Try installing it as follow\n'.red)
186
- console.log('curl "https://s3.amazonaws.com/aws-cli/awscli-bundle.zip" -o "awscli-bundle.zip"')
187
- console.log('unzip awscli-bundle.zip')
188
- console.log('sudo ./awscli-bundle/install -i /usr/local/aws -b /usr/local/bin/aws')
189
- return
190
- }
191
- }
192
-
193
- const [defaultProfileErrors, defaultProfile] = await getDefaultProfile()
194
- if (defaultProfileErrors)
195
- return printAWSerrors([new Error('Fail to get default profile'), ...defaultProfileErrors])
196
-
197
- const defaultProfileName = defaultProfile && defaultProfile.profile ? defaultProfile.profile : ''
198
- let defaultProfileExpired = false
199
- if (defaultProfileName) {
200
- const expiryDate = defaultProfile.expiry_date ? new Date(defaultProfile.expiry_date) : null
201
- const messages = [EOL,`Current default profile: ${defaultProfileName.bold}`.cyan]
202
- if (expiryDate) {
203
- const exp = expiryDate.getTime()
204
- const now = Date.now()
205
- if (now > exp) {
206
- defaultProfileExpired = true
207
- messages.push(' WARNING: Expired'.yellow)
208
- } else if (now+2*60*1000 > exp)
209
- messages.push(' WARNING: Expires in less than 2 minutes'.yellow)
210
- else {
211
- const timeLeftInMin = ((exp-now)/60000).toFixed(2)
212
- messages.push(` INFO: This profile expires in ${timeLeftInMin} minutes`.cyan)
213
- }
214
- }
215
- messages.push(EOL)
216
- console.log(messages.join(''))
217
- } else
218
- console.log(`${EOL}Current default profile: ${'unknown'.bold} (pick one up in the list below and we'll remember next time)${EOL}`.cyan)
219
-
220
- const [listErrors, profiles] = await listProfiles()
221
- if (listErrors)
222
- return printAWSerrors([new Error('Fail to list profiles'), ...listErrors])
223
-
224
- const profileCount = profiles.length
225
-
226
- if (!profileCount) {
227
- const { create } = await inquirer.prompt([
228
- {
229
- type: 'confirm',
230
- name: 'create',
231
- message: 'There no profiles yet. Do you wish to create one now? ',
232
- }
233
- ])
234
-
235
- if (!create)
236
- return
237
-
238
- console.log('Ooh yeah ✨! I like your style. Let\'s do this!'.cyan)
239
- await createNewProfile([], true)
240
- } else {
241
- const { friendlyName } = await inquirer.prompt([
242
- {
243
- type: 'list',
244
- name: 'friendlyName',
245
- message: `Choose one of the following ${profileCount} profiles:`,
246
- pageSize:20,
247
- default: 2,
248
- choices: [
249
- { name:'More options', value:OPTIONS_KEY },
250
- { name: 'Abort', value:ABORT_KEY },
251
- new inquirer.Separator(), ...profiles.map((p,i) => {
252
- return {
253
- name: `${i+1}. ${p.friendlyName}`,
254
- value: p.friendlyName
255
- }
256
- })]
257
- }
258
- ])
259
-
260
- if (!friendlyName || friendlyName == ABORT_KEY)
261
- return
262
-
263
- if (friendlyName == OPTIONS_KEY) {
264
- const { option } = await inquirer.prompt([
265
- {
266
- type: 'list',
267
- name: 'option',
268
- message: 'Options:',
269
- pageSize:20,
270
- choices: [
271
- ...(defaultProfileExpired ? [{ name: `Refresh default profile ${defaultProfileName.bold}` ,value:'refresh' }] : []),
272
- { name: 'Create profile', value:'new' },
273
- { name: 'Delete profiles', value:'delete' },
274
- { name: 'Abort', value:ABORT_KEY }
275
- ]
276
- }
277
- ])
278
-
279
- if (option == 'refresh')
280
- await setProfileToDefault(defaultProfileName, profiles, `AWS profile ${defaultProfileName.bold} successfully refreshed.`)
281
- else if (option == 'delete') {
282
- const { delProfiles } = await inquirer.prompt([
283
- {
284
- type: 'checkbox',
285
- name: 'delProfiles',
286
- message: 'Select the profiles you wish to delete (SPACE to select, ENTER to confirm):',
287
- pageSize: 20,
288
- choices: profiles.map((p,i) => {
289
- return {
290
- name: `${i+1}. ${p.friendlyName}`,
291
- value: p.name
292
- }
293
- })
294
- }
295
- ])
296
-
297
- if (!delProfiles.length)
298
- return
299
-
300
- const label = delProfiles.length > 1 ? 'profiles' : 'profile'
301
- const labelText = delProfiles.length > 1 ? `those ${delProfiles.length} profiles` : 'this profile'
302
- const { delConfirm } = await inquirer.prompt([
303
- {
304
- type: 'confirm',
305
- name: 'delConfirm',
306
- message: `Are you sure you want to delete ${labelText}? `,
307
- }
308
- ])
309
-
310
- if (!delConfirm)
311
- return
312
-
313
- if (defaultProfileName && delProfiles.some(p => p == defaultProfileName)) {
314
- 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 })
315
- }
316
-
317
- const [delErrors] = await deleteProfiles(delProfiles)
318
- if (delErrors)
319
- return printAWSerrors([new Error(`Fail to delete ${label}`), ...delErrors])
320
-
321
- console.log(`AWS profile${delProfiles.length > 1 ? 's' : ''} successfully deleted.`.green)
322
- } else if (option == 'new')
323
- await createNewProfile(profiles)
324
- else if (option == ABORT_KEY)
325
- return
326
-
327
- return
328
- } else
329
- await setProfileToDefault(friendlyName, profiles)
330
- }
331
- }
332
-
333
- const printExportHint = (profileName) => {
334
- const lines = [
335
- ' To lock this profile to this terminal session, run: ',
336
- '',
337
- ` export AWS_PROFILE=${profileName}`,
338
- '',
339
- ' This prevents other terminals from affecting this one. '
340
- ]
341
- const width = Math.max(...lines.map(l => l.length))
342
- const pad = s => s + ' '.repeat(width - s.length)
343
- console.log('')
344
- console.log(('┌' + '─'.repeat(width) + '┐').cyan)
345
- for (let i = 0; i < lines.length; i++) {
346
- const content = '│' + pad(lines[i]) + '│'
347
- console.log(i === 2 ? content.cyan.bold : content.cyan)
348
- }
349
- console.log(('└' + '─'.repeat(width) + '┘').cyan)
350
- console.log('')
351
- }
352
-
353
- const setProfileToDefault = async (profileName, profileList, successMsg) => {
354
- const profile = profileList.find(p => p.friendlyName == profileName || p.name == profileName)
355
-
356
- if (!profile)
357
- 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 })
358
-
359
- // Gets the AWS credentials for a specific profile. If that profile is an SSO profile, this function has a series of
360
- // side-effects:
361
- // - 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.
362
- // - 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.
363
- const [credsErrors, creds] = await getCredentials(profile.name, profile.sso_start_url)
364
- if (credsErrors)
365
- return printAWSerrors([new Error(`Fail to get credentials for profile ${profile.name}`), ...credsErrors])
366
-
367
- // console.log(profile)
368
- // console.log(creds)
369
-
370
- const [errors] = await updateDefaultProfile({
371
- ...creds,
372
- profile: profile.name,
373
- region: profile.region
374
- })
375
-
376
- if (errors)
377
- return printAWSerrors([new Error('Fail to update the default profile'), ...errors])
378
-
379
- console.log((successMsg || `AWS profile ${profile.name.bold} successfully set up as default.`).green)
380
- printExportHint(profile.name)
381
- }
382
-
383
- // 1. Creates your first command. This example shows an 'order' command with a required argument
384
- // called 'product' and an optional argument called 'option'.
385
- program
386
- .command('switch')
387
- .description('Default behavior. List the existing configuration and help select one. Equivalent to `npx switch-cloud`') // Optional description
388
- .action(switchCmd)
389
-
390
- // 2. Deals with cases where no command is passed.
391
- if (process.argv.length == 2)
392
- process.argv.push('switch')
393
-
394
- // 3. Starts the commander program
395
- program.parse(process.argv)
396
-
397
-
398
-
399
-
400
-
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.0.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,113 +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.0.0](https://github.com/nicolasdao/switch-profile/compare/v0.2.3...v1.0.0) (2026-03-21)
6
-
7
-
8
- ### Features
9
-
10
- * Display export AWS_PROFILE hint after profile switch for per-terminal isolation ([7dd09c8](https://github.com/nicolasdao/switch-profile/commit/7dd09c882708fcafd66fefc6139cd97a13d9b2fb))
11
-
12
- ### [0.2.3](https://github.com/nicolasdao/switch-profile/compare/v0.2.2...v0.2.3) (2026-02-11)
13
-
14
-
15
- ### Bug Fixes
16
-
17
- * Add support for AWS CLI v2 SSO session format and improve profile deletion UX ([4eb7366](https://github.com/nicolasdao/switch-profile/commit/4eb7366d6ed1f50f024128d94da213515a4ff9da))
18
-
19
- ### [0.2.2](https://github.com/nicolasdao/switch-profile/compare/v0.2.1...v0.2.2) (2026-02-10)
20
-
21
-
22
- ### Bug Fixes
23
-
24
- * SSO profile credentials written as undefined by falling back to aws configure export-credentials ([7067eff](https://github.com/nicolasdao/switch-profile/commit/7067eff15d376a3dd902ee4a03f5db7cfa539918))
25
-
26
- ### [0.2.1](https://github.com/nicolasdao/switch-profile/compare/v0.2.0...v0.2.1) (2026-02-08)
27
-
28
- ## [0.2.0](https://github.com/nicolasdao/switch-profile/compare/v0.1.2...v0.2.0) (2026-02-08)
29
-
30
-
31
- ### Bug Fixes
32
-
33
- * handle SSO profile creation failure and improve SSO setup UX ([b0ee837](https://github.com/nicolasdao/switch-profile/commit/b0ee83791bfbc1208cc5fb6b6f2850d4cbd160c9))
34
- * vulnerabilities ([3fa2575](https://github.com/nicolasdao/switch-profile/commit/3fa2575156f3e07a6de9cd077f3f8f75f9bceafa))
35
-
36
- ### [0.1.2](https://github.com/nicolasdao/switch-profile/compare/v0.1.1...v0.1.2) (2022-05-14)
37
-
38
-
39
- ### Bug Fixes
40
-
41
- * Multiple SSO profiles are not supported. It only uses one. ([b9d9d03](https://github.com/nicolasdao/switch-profile/commit/b9d9d03b4edfa048cc157376222378513138e257))
42
-
43
- ### [0.1.1](https://github.com/nicolasdao/switch-profile/compare/v0.1.0...v0.1.1) (2021-08-03)
44
-
45
-
46
- ### Bug Fixes
47
-
48
- * Edge cases where the SSO session expires and a forde login is required ([67f3667](https://github.com/nicolasdao/switch-profile/commit/67f36678f29f2ab5f02c4d4630eb1c7c41ccebbf))
49
-
50
- ## [0.1.0](https://github.com/nicolasdao/switch-profile/compare/v0.0.9...v0.1.0) (2021-08-03)
51
-
52
-
53
- ### Bug Fixes
54
-
55
- * 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))
56
-
57
- ### [0.0.9](https://github.com/nicolasdao/switch-profile/compare/v0.0.8...v0.0.9) (2021-07-19)
58
-
59
-
60
- ### Bug Fixes
61
-
62
- * Switching does not update the region in the ~/.aws/config ([14d6724](https://github.com/nicolasdao/switch-profile/commit/14d672429d81e3c421273d1e090fa4d444a09b5b))
63
-
64
- ### [0.0.8](https://github.com/nicolasdao/switch-profile/compare/v0.0.7...v0.0.8) (2021-07-19)
65
-
66
- ### [0.0.7](https://github.com/nicolasdao/switch-profile/compare/v0.0.6...v0.0.7) (2021-07-18)
67
-
68
-
69
- ### Features
70
-
71
- * Add ability to set up the new profile as default ([c667c3c](https://github.com/nicolasdao/switch-profile/commit/c667c3c29db2b43c86c083da36b67d6c27c737f8))
72
-
73
- ### [0.0.6](https://github.com/nicolasdao/switch-profile/compare/v0.0.5...v0.0.6) (2021-07-18)
74
-
75
-
76
- ### Features
77
-
78
- * Add support for congrats message ([a8a14dd](https://github.com/nicolasdao/switch-profile/commit/a8a14ddb4536c3fe6a153716f605796e436626bb))
79
-
80
- ### [0.0.5](https://github.com/nicolasdao/switch-profile/compare/v0.0.1...v0.0.5) (2021-07-18)
81
-
82
-
83
- ### Features
84
-
85
- * Add support for creating and deleting profiles ([cdbb115](https://github.com/nicolasdao/switch-profile/commit/cdbb115386536ce1d38d4de13d71b0e8dc1e4c68))
86
-
87
- ### [0.0.4](https://github.com/nicolasdao/switch-profile/compare/v0.0.1...v0.0.4) (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.3](https://github.com/nicolasdao/switch-profile/compare/v0.0.1...v0.0.3) (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.2](https://github.com/nicolasdao/switch-profile/compare/v0.0.1...v0.0.2) (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.1](https://github.com/nicolasdao/switch-profile/compare/v0.0.4...v0.0.1) (2021-07-18)
109
-
110
-
111
- ### Features
112
-
113
- * Add support for choosing a default profile ([73d936f](https://github.com/nicolasdao/switch-profile/commit/73d936fa95d5240dbbeb12e3f640e7436f1cc76f))