@dotenvx/dotenvx-ops 0.45.0 → 0.45.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,7 +2,19 @@
2
2
 
3
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
4
 
5
- [Unreleased](https://github.com/dotenvx/dotenvx-ops/compare/v0.45.0...main)
5
+ [Unreleased](https://github.com/dotenvx/dotenvx-ops/compare/v0.45.2...main)
6
+
7
+ ## [0.45.2](https://github.com/dotenvx/dotenvx-ops/compare/v0.45.1...v0.45.2) (2026-05-07)
8
+
9
+ ### Changed
10
+
11
+ * Surface team selector for `down|pull` ([#68](https://github.com/dotenvx/dotenvx-ops/pull/68))
12
+
13
+ ## [0.45.1](https://github.com/dotenvx/dotenvx-ops/compare/v0.45.0...v0.45.1) (2026-05-07)
14
+
15
+ ### Changed
16
+
17
+ * Surface team selector for `up|push` only when member of multiple teams ([#67](https://github.com/dotenvx/dotenvx-ops/pull/66))
6
18
 
7
19
  ## [0.45.0](https://github.com/dotenvx/dotenvx-ops/compare/v0.44.0...v0.45.0) (2026-05-07)
8
20
 
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.45.0",
2
+ "version": "0.45.2",
3
3
  "name": "@dotenvx/dotenvx-ops",
4
4
  "description": "Secrets for agents–from the creator of `dotenv` and `dotenvx`",
5
5
  "author": "@motdotla",
@@ -17,7 +17,7 @@ async function down () {
17
17
  try {
18
18
  const devicePublicKey = sesh.devicePublicKey()
19
19
 
20
- const { changed, privateKeyName } = await new ArmorDown(hostname, token, devicePublicKey, options.envFile).run()
20
+ const { changed, privateKeyName } = await new ArmorDown(hostname, token, devicePublicKey, options.envFile, options.team).run()
21
21
 
22
22
  if (spinner) spinner.stop()
23
23
  if (changed) {
@@ -17,7 +17,7 @@ async function pull () {
17
17
  try {
18
18
  const devicePublicKey = sesh.devicePublicKey()
19
19
 
20
- const { changed, privateKeyName } = await new ArmorPull(hostname, token, devicePublicKey, options.envFile).run()
20
+ const { changed, privateKeyName } = await new ArmorPull(hostname, token, devicePublicKey, options.envFile, options.team).run()
21
21
 
22
22
  if (spinner) spinner.stop()
23
23
  if (changed) {
@@ -17,7 +17,7 @@ async function push () {
17
17
  try {
18
18
  const devicePublicKey = sesh.devicePublicKey()
19
19
 
20
- const { changed, privateKeyName } = await new ArmorPush(hostname, token, devicePublicKey, options.envFile).run()
20
+ const { changed, privateKeyName } = await new ArmorPush(hostname, token, devicePublicKey, options.envFile, options.team).run()
21
21
 
22
22
  if (spinner) spinner.stop()
23
23
  if (changed) {
@@ -17,7 +17,7 @@ async function up () {
17
17
  try {
18
18
  const devicePublicKey = sesh.devicePublicKey()
19
19
 
20
- const { changed, privateKeyName } = await new ArmorUp(hostname, token, devicePublicKey, options.envFile).run()
20
+ const { changed, privateKeyName } = await new ArmorUp(hostname, token, devicePublicKey, options.envFile, options.team).run()
21
21
 
22
22
  if (spinner) spinner.stop()
23
23
  if (changed) {
@@ -18,6 +18,7 @@ armor
18
18
  .command('up')
19
19
  .description('armor private key')
20
20
  .option('-f, --env-file <path>', 'path to your env file')
21
+ .option('--team <team>', 'team to armor private key for')
21
22
  .action(upAction)
22
23
 
23
24
  // dotenvx-ops armor down
@@ -26,6 +27,7 @@ armor
26
27
  .command('down')
27
28
  .description('dearmor private key')
28
29
  .option('-f, --env-file <path>', 'path to your env file')
30
+ .option('--team <team>', 'team to dearmor private key from')
29
31
  .action(downAction)
30
32
 
31
33
  // dotenvx-ops armor push
@@ -34,6 +36,7 @@ armor
34
36
  .command('push')
35
37
  .description('push armored key (from .env.keys)')
36
38
  .option('-f, --env-file <path>', 'path to your env file')
39
+ .option('--team <team>', 'team to push armored private key for')
37
40
  .action(pushAction)
38
41
 
39
42
  // dotenvx-ops armor pull
@@ -42,6 +45,7 @@ armor
42
45
  .command('pull')
43
46
  .description('pull armored key (into .env.keys)')
44
47
  .option('-f, --env-file <path>', 'path to your env file')
48
+ .option('--team <team>', 'team to pull armored private key from')
45
49
  .action(pullAction)
46
50
 
47
51
  // dotenvx-ops armor rotate
@@ -4,23 +4,26 @@ const packageJson = require('../../lib/helpers/packageJson')
4
4
  const normalizeToken = require('../../lib/helpers/normalizeToken')
5
5
 
6
6
  class PostArmorDown {
7
- constructor (hostname, token, devicePublicKey, publicKey) {
7
+ constructor (hostname, token, devicePublicKey, publicKey, team) {
8
8
  this.hostname = hostname || 'https://ops.dotenvx.com'
9
9
  this.token = token
10
10
  this.devicePublicKey = devicePublicKey
11
11
  this.publicKey = publicKey
12
+ this.team = team
12
13
  }
13
14
 
14
15
  async run () {
15
16
  const token = normalizeToken(this.token)
16
17
  const devicePublicKey = this.devicePublicKey
17
18
  const publicKey = this.publicKey
19
+ const team = this.team
18
20
  const url = `${this.hostname}/api/armor/down`
19
21
 
20
22
  const body = {
21
23
  device_public_key: devicePublicKey,
22
24
  cli_version: packageJson.version,
23
- public_key: publicKey
25
+ public_key: publicKey,
26
+ team
24
27
  }
25
28
 
26
29
  const resp = await http(url, {
@@ -4,23 +4,26 @@ const packageJson = require('../../lib/helpers/packageJson')
4
4
  const normalizeToken = require('../../lib/helpers/normalizeToken')
5
5
 
6
6
  class PostArmorPull {
7
- constructor (hostname, token, devicePublicKey, publicKey) {
7
+ constructor (hostname, token, devicePublicKey, publicKey, team) {
8
8
  this.hostname = hostname || 'https://ops.dotenvx.com'
9
9
  this.token = token
10
10
  this.devicePublicKey = devicePublicKey
11
11
  this.publicKey = publicKey
12
+ this.team = team
12
13
  }
13
14
 
14
15
  async run () {
15
16
  const token = normalizeToken(this.token)
16
17
  const devicePublicKey = this.devicePublicKey
17
18
  const publicKey = this.publicKey
19
+ const team = this.team
18
20
  const url = `${this.hostname}/api/armor/pull`
19
21
 
20
22
  const body = {
21
23
  device_public_key: devicePublicKey,
22
24
  cli_version: packageJson.version,
23
- public_key: publicKey
25
+ public_key: publicKey,
26
+ team
24
27
  }
25
28
 
26
29
  const resp = await http(url, {
@@ -1,14 +1,23 @@
1
1
  const dotenvx = require('@dotenvx/dotenvx')
2
+ const prompts = require('@inquirer/prompts')
2
3
  const PostArmorDown = require('../api/postArmorDown')
3
4
  const keyNamesForEnvFile = require('../helpers/keyNamesForEnvFile')
4
5
  const upsertEnvKey = require('../helpers/upsertEnvKey')
5
6
 
7
+ function teamChoicesFromMeta (meta) {
8
+ return meta.organizations.map(org => ({
9
+ name: org.provider_slug,
10
+ value: org.provider_slug
11
+ }))
12
+ }
13
+
6
14
  class ArmorDown {
7
- constructor (hostname, token, devicePublicKey, envFile = '.env') {
15
+ constructor (hostname, token, devicePublicKey, envFile = '.env', team = undefined) {
8
16
  this.hostname = hostname
9
17
  this.token = token
10
18
  this.devicePublicKey = devicePublicKey
11
19
  this.envFile = envFile
20
+ this.team = team
12
21
  }
13
22
 
14
23
  async run () {
@@ -16,6 +25,7 @@ class ArmorDown {
16
25
  const token = this.token
17
26
  const devicePublicKey = this.devicePublicKey
18
27
  const envFile = this.envFile
28
+ const team = this.team
19
29
 
20
30
  const {
21
31
  publicKeyName,
@@ -23,7 +33,31 @@ class ArmorDown {
23
33
  } = keyNamesForEnvFile(envFile)
24
34
 
25
35
  const publicKey = dotenvx.get(publicKeyName, { path: envFile, strict: true, ignore: ['MISSING_PRIVATE_KEY'], noOps: true })
26
- const json = await new PostArmorDown(hostname, token, devicePublicKey, publicKey).run()
36
+ let json
37
+
38
+ if (team) {
39
+ json = await new PostArmorDown(hostname, token, devicePublicKey, publicKey, team).run()
40
+ } else {
41
+ try {
42
+ json = await new PostArmorDown(hostname, token, devicePublicKey, publicKey, undefined).run()
43
+ } catch (error) {
44
+ if (error.code !== 'DOTENVX_TEAM_REQUIRED') {
45
+ throw error
46
+ }
47
+
48
+ const choices = teamChoicesFromMeta(error.meta)
49
+
50
+ let team = choices[0].value
51
+ if (choices.length > 1) {
52
+ team = await prompts.select({
53
+ message: 'Select team',
54
+ choices
55
+ })
56
+ }
57
+
58
+ json = await new PostArmorDown(hostname, token, devicePublicKey, publicKey, team).run()
59
+ }
60
+ }
27
61
 
28
62
  upsertEnvKey(privateKeyName, json.private_key)
29
63
 
@@ -1,14 +1,23 @@
1
1
  const dotenvx = require('@dotenvx/dotenvx')
2
+ const prompts = require('@inquirer/prompts')
2
3
  const PostArmorPull = require('../api/postArmorPull')
3
4
  const upsertEnvKey = require('../helpers/upsertEnvKey')
4
5
  const keyNamesForEnvFile = require('../helpers/keyNamesForEnvFile')
5
6
 
7
+ function teamChoicesFromMeta (meta) {
8
+ return meta.organizations.map(org => ({
9
+ name: org.provider_slug,
10
+ value: org.provider_slug
11
+ }))
12
+ }
13
+
6
14
  class ArmorPull {
7
- constructor (hostname, token, devicePublicKey, envFile = '.env') {
15
+ constructor (hostname, token, devicePublicKey, envFile = '.env', team = undefined) {
8
16
  this.hostname = hostname
9
17
  this.token = token
10
18
  this.devicePublicKey = devicePublicKey
11
19
  this.envFile = envFile
20
+ this.team = team
12
21
  }
13
22
 
14
23
  async run () {
@@ -16,6 +25,7 @@ class ArmorPull {
16
25
  const token = this.token
17
26
  const devicePublicKey = this.devicePublicKey
18
27
  const envFile = this.envFile
28
+ const team = this.team
19
29
 
20
30
  const {
21
31
  publicKeyName,
@@ -23,7 +33,31 @@ class ArmorPull {
23
33
  } = keyNamesForEnvFile(envFile)
24
34
 
25
35
  const publicKey = dotenvx.get(publicKeyName, { path: envFile, strict: true, ignore: ['MISSING_PRIVATE_KEY'], noOps: true })
26
- const json = await new PostArmorPull(hostname, token, devicePublicKey, publicKey).run()
36
+ let json
37
+
38
+ if (team) {
39
+ json = await new PostArmorPull(hostname, token, devicePublicKey, publicKey, team).run()
40
+ } else {
41
+ try {
42
+ json = await new PostArmorPull(hostname, token, devicePublicKey, publicKey, undefined).run()
43
+ } catch (error) {
44
+ if (error.code !== 'DOTENVX_TEAM_REQUIRED') {
45
+ throw error
46
+ }
47
+
48
+ const choices = teamChoicesFromMeta(error.meta)
49
+
50
+ let team = choices[0].value
51
+ if (choices.length > 1) {
52
+ team = await prompts.select({
53
+ message: 'Select team',
54
+ choices
55
+ })
56
+ }
57
+
58
+ json = await new PostArmorPull(hostname, token, devicePublicKey, publicKey, team).run()
59
+ }
60
+ }
27
61
 
28
62
  const result = upsertEnvKey(privateKeyName, json.private_key)
29
63
 
@@ -1,15 +1,22 @@
1
1
  const dotenvx = require('@dotenvx/dotenvx')
2
2
  const prompts = require('@inquirer/prompts')
3
3
  const PostArmorPush = require('../api/postArmorPush')
4
- const GetAccount = require('../api/getAccount')
5
4
  const keyNamesForEnvFile = require('../helpers/keyNamesForEnvFile')
6
5
 
6
+ function teamChoicesFromMeta (meta) {
7
+ return meta.organizations.map(org => ({
8
+ name: org.provider_slug,
9
+ value: org.provider_slug
10
+ }))
11
+ }
12
+
7
13
  class ArmorPush {
8
- constructor (hostname, token, devicePublicKey, envFile = '.env') {
14
+ constructor (hostname, token, devicePublicKey, envFile = '.env', team = undefined) {
9
15
  this.hostname = hostname
10
16
  this.token = token
11
17
  this.devicePublicKey = devicePublicKey
12
18
  this.envFile = envFile
19
+ this.team = team
13
20
  }
14
21
 
15
22
  async run () {
@@ -17,25 +24,37 @@ class ArmorPush {
17
24
  const token = this.token
18
25
  const devicePublicKey = this.devicePublicKey
19
26
  const envFile = this.envFile
27
+ const team = this.team
20
28
 
21
29
  const { privateKeyName } = keyNamesForEnvFile(envFile)
22
30
 
23
31
  const privateKey = dotenvx.get(privateKeyName, { path: '.env.keys', strict: true, noOps: true })
24
32
 
25
- const accountJson = await new GetAccount(hostname, token).run()
26
- const choices = accountJson.organizations.map(o => ({
27
- name: o.provider_slug,
28
- value: o.provider_slug
29
- }))
30
- let team = choices[0] && choices[0].value
31
- if (choices.length > 1) {
32
- team = await prompts.select({
33
- message: 'Select team',
34
- choices
35
- })
36
- }
33
+ let json
34
+
35
+ if (team) {
36
+ json = await new PostArmorPush(hostname, token, devicePublicKey, privateKey, team).run()
37
+ } else {
38
+ try {
39
+ json = await new PostArmorPush(hostname, token, devicePublicKey, privateKey, undefined).run()
40
+ } catch (error) {
41
+ if (error.code !== 'DOTENVX_TEAM_REQUIRED') {
42
+ throw error
43
+ }
37
44
 
38
- const json = await new PostArmorPush(hostname, token, devicePublicKey, privateKey, team).run()
45
+ const choices = teamChoicesFromMeta(error.meta)
46
+
47
+ let team = choices[0].value
48
+ if (choices.length > 1) {
49
+ team = await prompts.select({
50
+ message: 'Select team',
51
+ choices
52
+ })
53
+ }
54
+
55
+ json = await new PostArmorPush(hostname, token, devicePublicKey, privateKey, team).run()
56
+ }
57
+ }
39
58
 
40
59
  return {
41
60
  ...json,
@@ -1,16 +1,23 @@
1
1
  const dotenvx = require('@dotenvx/dotenvx')
2
2
  const prompts = require('@inquirer/prompts')
3
3
  const PostArmorUp = require('../api/postArmorUp')
4
- const GetAccount = require('../api/getAccount')
5
4
  const keyNamesForEnvFile = require('../helpers/keyNamesForEnvFile')
6
5
  const removeEnvKey = require('../helpers/removeEnvKey')
7
6
 
7
+ function teamChoicesFromMeta (meta) {
8
+ return meta.organizations.map(org => ({
9
+ name: org.provider_slug,
10
+ value: org.provider_slug
11
+ }))
12
+ }
13
+
8
14
  class ArmorUp {
9
- constructor (hostname, token, devicePublicKey, envFile = '.env') {
15
+ constructor (hostname, token, devicePublicKey, envFile = '.env', team = undefined) {
10
16
  this.hostname = hostname
11
17
  this.token = token
12
18
  this.devicePublicKey = devicePublicKey
13
19
  this.envFile = envFile
20
+ this.team = team
14
21
  }
15
22
 
16
23
  async run () {
@@ -18,6 +25,7 @@ class ArmorUp {
18
25
  const token = this.token
19
26
  const devicePublicKey = this.devicePublicKey
20
27
  const envFile = this.envFile
28
+ const team = this.team
21
29
 
22
30
  const {
23
31
  publicKeyName,
@@ -27,20 +35,32 @@ class ArmorUp {
27
35
  const publicKey = dotenvx.get(publicKeyName, { path: envFile, strict: true, ignore: ['MISSING_PRIVATE_KEY'], noOps: true })
28
36
  const privateKey = dotenvx.get(privateKeyName, { path: '.env.keys', strict: true, ignore: ['MISSING_KEY'], noOps: true })
29
37
 
30
- const accountJson = await new GetAccount(hostname, token).run()
31
- const choices = accountJson.organizations.map(o => ({
32
- name: o.provider_slug,
33
- value: o.provider_slug
34
- }))
35
- let team = choices[0] && choices[0].value
36
- if (choices.length > 1) {
37
- team = await prompts.select({
38
- message: 'Select team',
39
- choices
40
- })
38
+ let json
39
+
40
+ if (team) {
41
+ json = await new PostArmorUp(hostname, token, devicePublicKey, publicKey, privateKey, team).run()
42
+ } else {
43
+ try {
44
+ json = await new PostArmorUp(hostname, token, devicePublicKey, publicKey, privateKey, undefined).run()
45
+ } catch (error) {
46
+ if (error.code !== 'DOTENVX_TEAM_REQUIRED') {
47
+ throw error
48
+ }
49
+
50
+ const choices = teamChoicesFromMeta(error.meta)
51
+
52
+ let team = choices[0].value
53
+ if (choices.length > 1) {
54
+ team = await prompts.select({
55
+ message: 'Select team',
56
+ choices
57
+ })
58
+ }
59
+
60
+ json = await new PostArmorUp(hostname, token, devicePublicKey, publicKey, privateKey, team).run()
61
+ }
41
62
  }
42
63
 
43
- const json = await new PostArmorUp(hostname, token, devicePublicKey, publicKey, privateKey, team).run()
44
64
  removeEnvKey(privateKeyName)
45
65
 
46
66
  return {