@dotenvx/dotenvx-vlt 0.49.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/CHANGELOG.md +652 -0
- package/LICENSE +71 -0
- package/README.md +11 -0
- package/package.json +77 -0
- package/src/cli/actions/armor/down.js +37 -0
- package/src/cli/actions/armor/move.js +42 -0
- package/src/cli/actions/armor/pull.js +37 -0
- package/src/cli/actions/armor/push.js +37 -0
- package/src/cli/actions/armor/rotate.js +25 -0
- package/src/cli/actions/armor/up.js +37 -0
- package/src/cli/actions/backup.js +93 -0
- package/src/cli/actions/gateway/start.js +17 -0
- package/src/cli/actions/get.js +34 -0
- package/src/cli/actions/keypair.js +59 -0
- package/src/cli/actions/login.js +110 -0
- package/src/cli/actions/logout.js +36 -0
- package/src/cli/actions/observe.js +36 -0
- package/src/cli/actions/open.js +37 -0
- package/src/cli/actions/rotate/github/connect.js +84 -0
- package/src/cli/actions/rotate/npm/connect.js +84 -0
- package/src/cli/actions/rotate/openai/connect.js +84 -0
- package/src/cli/actions/rotate.js +44 -0
- package/src/cli/actions/set.js +34 -0
- package/src/cli/actions/settings/device.js +24 -0
- package/src/cli/actions/settings/hostname.js +20 -0
- package/src/cli/actions/settings/off.js +17 -0
- package/src/cli/actions/settings/on.js +17 -0
- package/src/cli/actions/settings/path.js +21 -0
- package/src/cli/actions/settings/token.js +24 -0
- package/src/cli/actions/settings/username.js +22 -0
- package/src/cli/actions/status.js +13 -0
- package/src/cli/actions/sync.js +104 -0
- package/src/cli/commands/armor.js +73 -0
- package/src/cli/commands/gateway.js +16 -0
- package/src/cli/commands/rotate/github.js +26 -0
- package/src/cli/commands/rotate/npm.js +26 -0
- package/src/cli/commands/rotate/openai.js +26 -0
- package/src/cli/commands/rotate.js +32 -0
- package/src/cli/commands/settings.js +60 -0
- package/src/cli/dotenvx-ops.js +163 -0
- package/src/cli/postinstall.js +16 -0
- package/src/db/device.js +73 -0
- package/src/db/session.js +193 -0
- package/src/lib/api/getAccount.js +32 -0
- package/src/lib/api/getSynchronization.js +34 -0
- package/src/lib/api/getVersion.js +24 -0
- package/src/lib/api/postArmorDown.js +48 -0
- package/src/lib/api/postArmorMove.js +48 -0
- package/src/lib/api/postArmorPull.js +48 -0
- package/src/lib/api/postArmorPush.js +48 -0
- package/src/lib/api/postArmorUp.js +51 -0
- package/src/lib/api/postBackup.js +68 -0
- package/src/lib/api/postGet.js +37 -0
- package/src/lib/api/postKeypair.js +60 -0
- package/src/lib/api/postLogout.js +34 -0
- package/src/lib/api/postOauthDeviceCode.js +45 -0
- package/src/lib/api/postOauthToken.js +38 -0
- package/src/lib/api/postObserve.js +62 -0
- package/src/lib/api/postRotate.js +39 -0
- package/src/lib/api/postRotateConnect.js +54 -0
- package/src/lib/api/postSet.js +43 -0
- package/src/lib/api/postSync.js +68 -0
- package/src/lib/helpers/armoredKeyDisplay.js +10 -0
- package/src/lib/helpers/buildApiError.js +16 -0
- package/src/lib/helpers/buildOauthError.js +13 -0
- package/src/lib/helpers/canonicalEnvFilename.js +13 -0
- package/src/lib/helpers/clipboardy/fallbacks/linux/xsel +0 -0
- package/src/lib/helpers/clipboardy/fallbacks/windows/clipboard_i686.exe +0 -0
- package/src/lib/helpers/clipboardy/fallbacks/windows/clipboard_x86_64.exe +0 -0
- package/src/lib/helpers/clipboardy/linux.js +57 -0
- package/src/lib/helpers/clipboardy/macos.js +14 -0
- package/src/lib/helpers/clipboardy/termux.js +41 -0
- package/src/lib/helpers/clipboardy/windows.js +16 -0
- package/src/lib/helpers/clipboardy.js +51 -0
- package/src/lib/helpers/confirm.js +17 -0
- package/src/lib/helpers/createSpinner.js +101 -0
- package/src/lib/helpers/createSpinner2.js +24 -0
- package/src/lib/helpers/decryptValue.js +10 -0
- package/src/lib/helpers/dotenvxProjectId.js +36 -0
- package/src/lib/helpers/encryptValue.js +9 -0
- package/src/lib/helpers/errors.js +30 -0
- package/src/lib/helpers/formatCode.js +11 -0
- package/src/lib/helpers/gitBranch.js +13 -0
- package/src/lib/helpers/gitUrl.js +13 -0
- package/src/lib/helpers/http.js +17 -0
- package/src/lib/helpers/jsonToEnv.js +7 -0
- package/src/lib/helpers/keyNamesForEnvFile.js +43 -0
- package/src/lib/helpers/keypairMetadata.js +88 -0
- package/src/lib/helpers/likelyUpdateCommand.js +33 -0
- package/src/lib/helpers/localKeypair.js +12 -0
- package/src/lib/helpers/mask.js +12 -0
- package/src/lib/helpers/normalizePath.js +5 -0
- package/src/lib/helpers/normalizeToken.js +5 -0
- package/src/lib/helpers/openUrl.js +7 -0
- package/src/lib/helpers/packageJson.js +3 -0
- package/src/lib/helpers/playwrightConnect.js +29 -0
- package/src/lib/helpers/pluralize.js +10 -0
- package/src/lib/helpers/prompts.js +68 -0
- package/src/lib/helpers/removeEnvKey.js +50 -0
- package/src/lib/helpers/safeRealpath.js +13 -0
- package/src/lib/helpers/sha256File.js +9 -0
- package/src/lib/helpers/smartMask.js +11 -0
- package/src/lib/helpers/truncate.js +10 -0
- package/src/lib/helpers/upsertEnvKey.js +61 -0
- package/src/lib/main.d.ts +152 -0
- package/src/lib/main.js +114 -0
- package/src/lib/services/armorDown.js +77 -0
- package/src/lib/services/armorMove.js +54 -0
- package/src/lib/services/armorPull.js +77 -0
- package/src/lib/services/armorPush.js +82 -0
- package/src/lib/services/armorUp.js +79 -0
- package/src/lib/services/backup.js +105 -0
- package/src/lib/services/gatewayStart.js +132 -0
- package/src/lib/services/keypair.js +59 -0
- package/src/lib/services/loggedIn.js +24 -0
- package/src/lib/services/login.js +28 -0
- package/src/lib/services/loginPoll.js +43 -0
- package/src/lib/services/logout.js +28 -0
- package/src/lib/services/rotate.js +28 -0
- package/src/lib/services/rotateGithubConnect.js +56 -0
- package/src/lib/services/rotateNpmConnect.js +56 -0
- package/src/lib/services/rotateOpenaiConnect.js +60 -0
- package/src/lib/services/status.js +11 -0
- package/src/lib/services/sync.js +70 -0
- package/src/lib/services/syncConflict.js +36 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
const { getColor, bold } = require('@dotenvx/dotenvx')
|
|
2
|
+
|
|
3
|
+
const FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
|
|
4
|
+
const HIDE_CURSOR = '\u001B[?25l'
|
|
5
|
+
const SHOW_CURSOR = '\u001B[?25h'
|
|
6
|
+
const CLEAR_LINE = '\r\x1b[K'
|
|
7
|
+
const SYMBOL_INFO = 'ℹ'
|
|
8
|
+
const SYMBOL_WARN = '⚠'
|
|
9
|
+
const SYMBOL_ERROR = '✖'
|
|
10
|
+
const SYMBOL_SUCCESS = '✔'
|
|
11
|
+
|
|
12
|
+
class Spinner {
|
|
13
|
+
text
|
|
14
|
+
interval
|
|
15
|
+
frameIndex = 0
|
|
16
|
+
symbol = getColor('blue')(FRAMES[0])
|
|
17
|
+
|
|
18
|
+
constructor (text) {
|
|
19
|
+
this.text = text
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
start (text) {
|
|
23
|
+
if (text) {
|
|
24
|
+
this.text = text
|
|
25
|
+
}
|
|
26
|
+
this.render()
|
|
27
|
+
this.interval = setInterval(() => this.tick(), 50)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
tick () {
|
|
31
|
+
this.symbol = getColor('blue')(FRAMES[this.frameIndex++])
|
|
32
|
+
if (this.frameIndex >= FRAMES.length) this.frameIndex = 0
|
|
33
|
+
this.render()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
render () {
|
|
37
|
+
process.stdout.write(CLEAR_LINE + HIDE_CURSOR + (this.symbol ? this.symbol + ' ' : '') + this.text)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
succeed (text) {
|
|
41
|
+
if (text) {
|
|
42
|
+
this.text = text
|
|
43
|
+
}
|
|
44
|
+
this.symbol = getColor('green')(SYMBOL_SUCCESS)
|
|
45
|
+
this._end()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
info (text) {
|
|
49
|
+
if (text) {
|
|
50
|
+
this.text = text
|
|
51
|
+
}
|
|
52
|
+
this.symbol = getColor('blue')(SYMBOL_INFO)
|
|
53
|
+
this._end()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
warn (text) {
|
|
57
|
+
if (text) {
|
|
58
|
+
this.text = text
|
|
59
|
+
}
|
|
60
|
+
this.symbol = getColor('orangered')(SYMBOL_WARN)
|
|
61
|
+
this._end()
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
fail (text) {
|
|
65
|
+
if (text) {
|
|
66
|
+
this.text = text
|
|
67
|
+
}
|
|
68
|
+
this.symbol = getColor('red')(SYMBOL_ERROR)
|
|
69
|
+
this._end()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
stop () {
|
|
73
|
+
this.symbol = ''
|
|
74
|
+
this.text = ''
|
|
75
|
+
clearInterval(this.interval)
|
|
76
|
+
process.stdout.write(CLEAR_LINE + HIDE_CURSOR + (this.symbol ? this.symbol + ' ' : '') + this.text)
|
|
77
|
+
process.stdout.write(SHOW_CURSOR)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
_end () {
|
|
81
|
+
this.render()
|
|
82
|
+
clearInterval(this.interval)
|
|
83
|
+
process.stdout.write(SHOW_CURSOR + '\n')
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const createSpinner = (initialMessage = '') => {
|
|
88
|
+
const spinner = new Spinner(initialMessage)
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
start: (message) => spinner.start(message),
|
|
92
|
+
succeed: (message) => spinner.succeed(getColor('green')(message)),
|
|
93
|
+
warn: (message) => spinner.warn(getColor('orangered')(message)),
|
|
94
|
+
info: (message) => spinner.info(getColor('blue')(message)),
|
|
95
|
+
done: (message) => spinner.succeed(message),
|
|
96
|
+
fail: (message) => spinner.fail(bold(getColor('red')(message))),
|
|
97
|
+
stop: () => spinner.stop()
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
module.exports = { createSpinner, Spinner }
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const FRAMES = ['◇', '⬖', '◆', '⬗']
|
|
2
|
+
const FRAME_INTERVAL_MS = 80
|
|
3
|
+
|
|
4
|
+
async function createSpinner2 (options = {}) {
|
|
5
|
+
const stream = process.stderr
|
|
6
|
+
const hasCursorControls = typeof stream.cursorTo === 'function' && typeof stream.clearLine === 'function'
|
|
7
|
+
const enabled = Boolean(stream.isTTY && hasCursorControls && options.spinner !== false && !options.quiet && !options.verbose && !options.debug)
|
|
8
|
+
if (!enabled) return null
|
|
9
|
+
|
|
10
|
+
const text = options.text || 'thinking'
|
|
11
|
+
const frames = options.frames || FRAMES
|
|
12
|
+
|
|
13
|
+
const { default: yoctoSpinner } = await import('yocto-spinner')
|
|
14
|
+
return yoctoSpinner({
|
|
15
|
+
text,
|
|
16
|
+
spinner: {
|
|
17
|
+
frames,
|
|
18
|
+
interval: FRAME_INTERVAL_MS
|
|
19
|
+
},
|
|
20
|
+
stream
|
|
21
|
+
}).start()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
module.exports = createSpinner2
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const { decrypt } = require('eciesjs')
|
|
2
|
+
|
|
3
|
+
function decryptValue (value, privateKey) {
|
|
4
|
+
const secret = Buffer.from(privateKey, 'hex')
|
|
5
|
+
const ciphertext = Buffer.from(value, 'base64')
|
|
6
|
+
|
|
7
|
+
return decrypt(secret, ciphertext).toString()
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
module.exports = decryptValue
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const path = require('path')
|
|
3
|
+
const dotenvx = require('@dotenvx/dotenvx')
|
|
4
|
+
const Errors = require('./errors')
|
|
5
|
+
|
|
6
|
+
function dotenvxProjectId (cwd = process.cwd(), raiseErrors = true) {
|
|
7
|
+
// 1. Prefer environment variable
|
|
8
|
+
if (process.env.DOTENVX_PROJECT_ID && process.env.DOTENVX_PROJECT_ID.trim()) {
|
|
9
|
+
return process.env.DOTENVX_PROJECT_ID.trim()
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// 2. Otherwise, parse .env.x contents
|
|
13
|
+
const filepath = path.join(cwd, '.env.x')
|
|
14
|
+
// file must exist
|
|
15
|
+
if (!fs.existsSync(filepath)) {
|
|
16
|
+
const filename = path.basename(filepath)
|
|
17
|
+
if (raiseErrors) {
|
|
18
|
+
throw new Errors({ filename, filepath }).envXFileMissing()
|
|
19
|
+
} else {
|
|
20
|
+
return null
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (fs.existsSync(filepath)) {
|
|
25
|
+
const src = fs.readFileSync(filepath, 'utf8')
|
|
26
|
+
const parsed = dotenvx.parse(src)
|
|
27
|
+
if (parsed.DOTENVX_PROJECT_ID && parsed.DOTENVX_PROJECT_ID.trim()) {
|
|
28
|
+
return parsed.DOTENVX_PROJECT_ID.trim()
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// 3. Nothing found
|
|
33
|
+
return null
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module.exports = dotenvxProjectId
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const { encrypt } = require('eciesjs')
|
|
2
|
+
|
|
3
|
+
function encryptValue (value, publicKey) {
|
|
4
|
+
const ciphertext = encrypt(publicKey, Buffer.from(value))
|
|
5
|
+
|
|
6
|
+
return Buffer.from(ciphertext, 'hex').toString('base64') // base64 encode ciphertext
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
module.exports = encryptValue
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
class Errors {
|
|
2
|
+
constructor (options = {}) {
|
|
3
|
+
this.filename = options.filename
|
|
4
|
+
this.filepath = options.filepath
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
econnrefused () {
|
|
8
|
+
const code = 'ECONNREFUSED'
|
|
9
|
+
const message = `[${code}] connection refused`
|
|
10
|
+
const help = `[${code}] check your internet connection`
|
|
11
|
+
|
|
12
|
+
const e = new Error(message)
|
|
13
|
+
e.code = code
|
|
14
|
+
e.help = help
|
|
15
|
+
return e
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
envXFileMissing () {
|
|
19
|
+
const code = 'ENV_X_FILE_MISSING'
|
|
20
|
+
const message = `[${code}] missing ${this.filename} file (${this.filepath})`
|
|
21
|
+
const help = `[${code}] https://github.com/dotenvx/dotenvx/issues/664`
|
|
22
|
+
|
|
23
|
+
const e = new Error(message)
|
|
24
|
+
e.code = code
|
|
25
|
+
e.help = help
|
|
26
|
+
return e
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = Errors
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const execa = require('execa')
|
|
2
|
+
|
|
3
|
+
function gitBranch () {
|
|
4
|
+
try {
|
|
5
|
+
const raw = execa.sync('git', ['rev-parse', '--abbrev-ref', 'HEAD'])
|
|
6
|
+
|
|
7
|
+
return raw.stdout.toString().trim()
|
|
8
|
+
} catch (_error) {
|
|
9
|
+
return null
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
module.exports = gitBranch
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const { request } = require('undici')
|
|
2
|
+
|
|
3
|
+
const Errors = require('./errors')
|
|
4
|
+
|
|
5
|
+
async function http (url, opts = {}) {
|
|
6
|
+
try {
|
|
7
|
+
return await request(url, opts)
|
|
8
|
+
} catch (err) {
|
|
9
|
+
if (err.code === 'econnrefused') {
|
|
10
|
+
throw new Errors().econnrefused()
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
throw err
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
module.exports = { http }
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const canonicalEnvFilename = require('./canonicalEnvFilename')
|
|
2
|
+
|
|
3
|
+
function environment (filepath) {
|
|
4
|
+
const filename = canonicalEnvFilename(filepath)
|
|
5
|
+
|
|
6
|
+
const parts = filename.split('.')
|
|
7
|
+
const possibleEnvironmentList = [...parts.slice(2)]
|
|
8
|
+
|
|
9
|
+
if (possibleEnvironmentList.length === 0) {
|
|
10
|
+
// handle .env1 -> development1
|
|
11
|
+
return filename.replace('.env', 'development')
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (possibleEnvironmentList.length === 1) {
|
|
15
|
+
return possibleEnvironmentList[0]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (possibleEnvironmentList.length === 2) {
|
|
19
|
+
return possibleEnvironmentList.join('_')
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return possibleEnvironmentList.slice(0, 2).join('_')
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function keyNamesForEnvFile (filepath = '.env') {
|
|
26
|
+
const filename = canonicalEnvFilename(filepath)
|
|
27
|
+
|
|
28
|
+
if (filename === '.env') {
|
|
29
|
+
return {
|
|
30
|
+
publicKeyName: 'DOTENV_PUBLIC_KEY',
|
|
31
|
+
privateKeyName: 'DOTENV_PRIVATE_KEY'
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const resolvedEnvironment = environment(filename).toUpperCase()
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
publicKeyName: `DOTENV_PUBLIC_KEY_${resolvedEnvironment}`,
|
|
39
|
+
privateKeyName: `DOTENV_PRIVATE_KEY_${resolvedEnvironment}`
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = keyNamesForEnvFile
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
const path = require('path')
|
|
2
|
+
const fs = require('fs')
|
|
3
|
+
const execa = require('execa')
|
|
4
|
+
const dotenvx = require('@dotenvx/dotenvx')
|
|
5
|
+
|
|
6
|
+
const canonicalEnvFilename = require('./canonicalEnvFilename')
|
|
7
|
+
|
|
8
|
+
function compact (object) {
|
|
9
|
+
return Object.entries(object).reduce((acc, [key, value]) => {
|
|
10
|
+
if (value !== undefined && value !== null && value !== '') {
|
|
11
|
+
acc[key] = value
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return acc
|
|
15
|
+
}, {})
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function gitRoot () {
|
|
19
|
+
try {
|
|
20
|
+
return execa.sync('git', ['rev-parse', '--show-toplevel']).stdout.toString().trim()
|
|
21
|
+
} catch (_error) {
|
|
22
|
+
return null
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function normalizeFilepath (envFile) {
|
|
27
|
+
const root = gitRoot()
|
|
28
|
+
const filepath = path.resolve(envFile)
|
|
29
|
+
|
|
30
|
+
if (root) {
|
|
31
|
+
return path.relative(root, filepath).replace(/\\/g, '/')
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return path.relative(process.cwd(), filepath).replace(/\\/g, '/')
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function environment (envFile) {
|
|
38
|
+
const filename = canonicalEnvFilename(envFile)
|
|
39
|
+
const parts = filename.split('.')
|
|
40
|
+
const possibleEnvironmentList = [...parts.slice(2)]
|
|
41
|
+
|
|
42
|
+
if (possibleEnvironmentList.length === 0) {
|
|
43
|
+
return filename.replace('.env', 'development')
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (possibleEnvironmentList.length === 1) {
|
|
47
|
+
return possibleEnvironmentList[0]
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (possibleEnvironmentList.length === 2) {
|
|
51
|
+
return possibleEnvironmentList.join('_')
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return possibleEnvironmentList.slice(0, 2).join('_')
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function projectName () {
|
|
58
|
+
return path.basename(gitRoot() || process.cwd())
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function envKeys (envFile) {
|
|
62
|
+
let src
|
|
63
|
+
try {
|
|
64
|
+
src = fs.readFileSync(envFile)
|
|
65
|
+
} catch (_error) {
|
|
66
|
+
return null
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const parsed = dotenvx.parse(src, {
|
|
70
|
+
ignore: ['MISSING_PRIVATE_KEY', 'WRONG_PRIVATE_KEY', 'INVALID_PRIVATE_KEY']
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
if (!parsed || Object.keys(parsed).length === 0) return null
|
|
74
|
+
|
|
75
|
+
return Object.keys(parsed)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function keypairMetadata (envFile = '.env') {
|
|
79
|
+
return compact({
|
|
80
|
+
filepath: normalizeFilepath(envFile),
|
|
81
|
+
filename: canonicalEnvFilename(envFile),
|
|
82
|
+
environment: environment(envFile),
|
|
83
|
+
project_name: projectName(),
|
|
84
|
+
keys: envKeys(envFile)
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
module.exports = keypairMetadata
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const normalizePath = require('./normalizePath')
|
|
2
|
+
const safeRealpath = require('./safeRealpath')
|
|
3
|
+
|
|
4
|
+
const NPM_COMMAND = 'npm i @dotenvx/dotenvx-ops'
|
|
5
|
+
const CURL_COMMAND = 'curl -sfS https://dotenvx.sh/ops | sh'
|
|
6
|
+
|
|
7
|
+
function likelyUpdateCommand () {
|
|
8
|
+
const isPackaged = Boolean(process.pkg)
|
|
9
|
+
const executablePath = isPackaged ? process.execPath : (process.argv[1] || process.execPath)
|
|
10
|
+
const resolvedExecutablePath = safeRealpath(executablePath)
|
|
11
|
+
const normalizedPath = normalizePath(resolvedExecutablePath || executablePath || '')
|
|
12
|
+
|
|
13
|
+
if (
|
|
14
|
+
normalizedPath.includes('/node_modules/@dotenvx/dotenvx-ops/') ||
|
|
15
|
+
normalizedPath.includes('/node_modules/.bin/dotenvx-ops')
|
|
16
|
+
) {
|
|
17
|
+
return NPM_COMMAND
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (
|
|
21
|
+
isPackaged ||
|
|
22
|
+
normalizedPath.endsWith('/usr/local/bin/dotenvx-ops') ||
|
|
23
|
+
normalizedPath.endsWith('/opt/homebrew/bin/dotenvx-ops') ||
|
|
24
|
+
normalizedPath.endsWith('/usr/bin/dotenvx-ops') ||
|
|
25
|
+
normalizedPath.endsWith('/bin/dotenvx-ops')
|
|
26
|
+
) {
|
|
27
|
+
return CURL_COMMAND
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return NPM_COMMAND
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
module.exports = likelyUpdateCommand
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const { logger } = require('@dotenvx/dotenvx')
|
|
2
|
+
const { chromium } = require('playwright')
|
|
3
|
+
|
|
4
|
+
const VIEWPORT_WIDTH = 1200
|
|
5
|
+
const VIEWPORT_HEIGHT = 742
|
|
6
|
+
const VIEWPORT = { width: VIEWPORT_WIDTH, height: VIEWPORT_HEIGHT }
|
|
7
|
+
|
|
8
|
+
async function playwrightConnect (channel = 'chrome') {
|
|
9
|
+
const browser = await ensurePlaywrightBrowser(channel)
|
|
10
|
+
const context = await browser.newContext({ viewport: VIEWPORT })
|
|
11
|
+
const page = await context.newPage()
|
|
12
|
+
|
|
13
|
+
return { browser, context, page }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async function ensurePlaywrightBrowser (channel = 'chrome') {
|
|
17
|
+
try {
|
|
18
|
+
return await chromium.launch({ headless: false, channel })
|
|
19
|
+
} catch (err) {
|
|
20
|
+
if (String(err).includes('Executable doesn\'t exist')) {
|
|
21
|
+
logger.info('Installing chromium...')
|
|
22
|
+
const cp = require('child_process')
|
|
23
|
+
cp.execSync('npx playwright install chromium', { stdio: 'inherit' })
|
|
24
|
+
return await chromium.launch({ headless: false })
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
module.exports = playwrightConnect
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const Enquirer = require('enquirer')
|
|
2
|
+
|
|
3
|
+
const enquirer = new Enquirer()
|
|
4
|
+
|
|
5
|
+
function choicesForSelect (choices) {
|
|
6
|
+
return choices.map(choice => {
|
|
7
|
+
if (typeof choice === 'string') return choice
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
name: choice.value,
|
|
11
|
+
message: choice.name || choice.value
|
|
12
|
+
}
|
|
13
|
+
})
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function enquirerOptions (context = {}) {
|
|
17
|
+
const options = {}
|
|
18
|
+
|
|
19
|
+
if (context.input) {
|
|
20
|
+
options.stdin = context.input
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (context.output) {
|
|
24
|
+
options.stdout = context.output
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return options
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function select ({ message, choices }, context) {
|
|
31
|
+
const answer = await enquirer.prompt({
|
|
32
|
+
type: 'select',
|
|
33
|
+
name: 'value',
|
|
34
|
+
message,
|
|
35
|
+
choices: choicesForSelect(choices),
|
|
36
|
+
...enquirerOptions(context)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
return answer.value
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function input ({ message }, context) {
|
|
43
|
+
const answer = await enquirer.prompt({
|
|
44
|
+
type: 'input',
|
|
45
|
+
name: 'value',
|
|
46
|
+
message,
|
|
47
|
+
...enquirerOptions(context)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
return answer.value
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function password ({ message }, context) {
|
|
54
|
+
const answer = await enquirer.prompt({
|
|
55
|
+
type: 'password',
|
|
56
|
+
name: 'value',
|
|
57
|
+
message,
|
|
58
|
+
...enquirerOptions(context)
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
return answer.value
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
module.exports = {
|
|
65
|
+
select,
|
|
66
|
+
input,
|
|
67
|
+
password
|
|
68
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const path = require('path')
|
|
3
|
+
|
|
4
|
+
function escapeForRegex (value) {
|
|
5
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function removeEnvKey (key, keysFilepath = '.env.keys') {
|
|
9
|
+
const resolvedKeysFilepath = path.resolve(keysFilepath)
|
|
10
|
+
|
|
11
|
+
if (!fs.existsSync(resolvedKeysFilepath)) {
|
|
12
|
+
return {
|
|
13
|
+
changed: false,
|
|
14
|
+
key,
|
|
15
|
+
filepath: keysFilepath
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const src = fs.readFileSync(resolvedKeysFilepath, 'utf8')
|
|
20
|
+
const eol = src.includes('\r\n') ? '\r\n' : '\n'
|
|
21
|
+
const keyPattern = new RegExp(`^\\s*(?:export\\s+)?${escapeForRegex(key)}\\s*=`)
|
|
22
|
+
const envKeyPattern = /^\s*(?:export\s+)?[A-Za-z_][A-Za-z0-9_]*\s*=/
|
|
23
|
+
const lines = src.length > 0 ? src.split(/\r?\n/) : []
|
|
24
|
+
|
|
25
|
+
while (lines.length > 0 && lines[lines.length - 1] === '') {
|
|
26
|
+
lines.pop()
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const nextLines = lines.filter((line) => !keyPattern.test(line))
|
|
30
|
+
const changed = nextLines.length !== lines.length
|
|
31
|
+
|
|
32
|
+
if (changed) {
|
|
33
|
+
const hasRemainingKeys = nextLines.some((line) => envKeyPattern.test(line))
|
|
34
|
+
|
|
35
|
+
if (hasRemainingKeys) {
|
|
36
|
+
const nextSrc = `${nextLines.join(eol)}${eol}`
|
|
37
|
+
fs.writeFileSync(resolvedKeysFilepath, nextSrc, 'utf8')
|
|
38
|
+
} else {
|
|
39
|
+
fs.rmSync(resolvedKeysFilepath, { force: true })
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
changed,
|
|
45
|
+
key,
|
|
46
|
+
filepath: keysFilepath
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports = removeEnvKey
|