@qui-cli/env 4.0.1 → 5.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/CHANGELOG.md +26 -0
- package/README.md +1 -9
- package/package.json +5 -5
- package/1Password.d.ts +0 -2
- package/1Password.js +0 -6
- package/dist/1Password.d.ts +0 -15
- package/dist/1Password.js +0 -129
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [5.0.0](https://github.com/battis/qui-cli/compare/env/4.1.0...env/5.0.0) (2025-11-07)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### ⚠ BREAKING CHANGES
|
|
9
|
+
|
|
10
|
+
* expose env-1password as a separate plugin
|
|
11
|
+
* separate 1Password without requiring knowledge of module structure
|
|
12
|
+
* no longer accepting 1Password service account token as environment variable
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
* expose env-1password as a separate plugin ([90ecb79](https://github.com/battis/qui-cli/commit/90ecb7900b85ade45113fc5a5999f2a2ff87f580))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Bug Fixes
|
|
20
|
+
|
|
21
|
+
* no longer accepting 1Password service account token as environment variable ([db7ae6a](https://github.com/battis/qui-cli/commit/db7ae6ac615c51a9966f201c85a8388bf4ebd76a))
|
|
22
|
+
* separate 1Password without requiring knowledge of module structure ([c21fe44](https://github.com/battis/qui-cli/commit/c21fe44d7d72d5d6bc4d092cb869164117378ab2))
|
|
23
|
+
|
|
24
|
+
## [4.1.0](https://github.com/battis/qui-cli/compare/env/4.0.1...env/4.1.0) (2025-11-04)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### Features
|
|
28
|
+
|
|
29
|
+
* standardize on modules labeling the options that they add to the usage man page ([eba86cd](https://github.com/battis/qui-cli/commit/eba86cd8a22a93aa6b6f19a3979272d87fe59274))
|
|
30
|
+
|
|
5
31
|
## [4.0.1](https://github.com/battis/qui-cli/compare/env/4.0.0...env/4.0.1) (2025-08-04)
|
|
6
32
|
|
|
7
33
|
|
package/README.md
CHANGED
|
@@ -31,15 +31,7 @@ Any plugin that depends on this plugin can assume that the `.env` file environem
|
|
|
31
31
|
|
|
32
32
|
### 1Password integration
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
1. Follow [the 1Password CLI directions to create a service account](https://developer.1password.com/docs/service-accounts/get-started/).
|
|
37
|
-
2. Install [@1password/sdk](https://www.npmjs.com/package/@1password/sdk) as a peer of `@qui-cli/env`.
|
|
38
|
-
3. Update environment variables to be [secret references](https://developer.1password.com/docs/cli/secret-references)
|
|
39
|
-
4. Inject the Service Account Token into the environment with the name `OP_SERVICE_ACCOUNT_TOKEN`.
|
|
40
|
-
5. Run!
|
|
41
|
-
|
|
42
|
-
See [dev-1password-env](https://github.com/battis/qui-cli/tree/main/examples/dev-1password-env#readme) for an example using the 1Password implementation of this package.
|
|
34
|
+
For 1Password integration supporting secret references in `.env`, use [@qui-cli/env-1password](https://npmjs.com/package/@qui-cli/env-1password) in place of this package.
|
|
43
35
|
|
|
44
36
|
## Configuration
|
|
45
37
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qui-cli/env",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "@qui-cli Plugin: Standardized environment configuration",
|
|
5
5
|
"homepage": "https://github.com/battis/qui-cli/tree/main/packages/env#readme",
|
|
6
6
|
"repository": {
|
|
@@ -19,15 +19,15 @@
|
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@1password/sdk": "^0.3.1",
|
|
21
21
|
"@battis/import-package-json": "^0.1.7",
|
|
22
|
-
"dotenv": "^17.2.
|
|
22
|
+
"dotenv": "^17.2.3"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@tsconfig/node20": "^20.1.6",
|
|
26
|
-
"@types/node": "^24.
|
|
27
|
-
"commit-and-tag-version": "^12.
|
|
26
|
+
"@types/node": "^24.10.0",
|
|
27
|
+
"commit-and-tag-version": "^12.6.0",
|
|
28
28
|
"del-cli": "^6.0.0",
|
|
29
29
|
"npm-run-all": "^4.1.5",
|
|
30
|
-
"typescript": "^5.9.
|
|
30
|
+
"typescript": "^5.9.3",
|
|
31
31
|
"@qui-cli/plugin": "3.0.0",
|
|
32
32
|
"@qui-cli/root": "3.0.1"
|
|
33
33
|
},
|
package/1Password.d.ts
DELETED
package/1Password.js
DELETED
package/dist/1Password.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import * as Plugin from '@qui-cli/plugin';
|
|
2
|
-
import * as Env from './Env.js';
|
|
3
|
-
export type Configuration = Plugin.Configuration & Env.Configuration & {
|
|
4
|
-
serviceAccountToken?: string;
|
|
5
|
-
};
|
|
6
|
-
export declare const name = "env";
|
|
7
|
-
export declare function configure(config?: Configuration): Promise<void>;
|
|
8
|
-
export declare function options(): Plugin.Options;
|
|
9
|
-
export declare function init({ values }: Plugin.ExpectedArguments<typeof options>): Promise<void>;
|
|
10
|
-
export declare function parse(file?: string): Promise<import("dotenv").DotenvParseOutput>;
|
|
11
|
-
export declare function get({ key, file }: Env.GetOptions): Promise<string>;
|
|
12
|
-
export declare function exists({ key, file }: Parameters<(typeof Env)['exists']>[0]): Promise<boolean>;
|
|
13
|
-
/** Requires a service account with write privileges */
|
|
14
|
-
export declare function set({ key, value, file, ...rest }: Env.SetOptions): Promise<void>;
|
|
15
|
-
export declare const remove: typeof Env.remove;
|
package/dist/1Password.js
DELETED
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import { createClient } from '@1password/sdk';
|
|
2
|
-
import { importLocal } from '@battis/import-package-json';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import * as Env from './Env.js';
|
|
5
|
-
const OP_SERVICE_ACCOUNT_TOKEN = 'OP_SERVICE_ACCOUNT_TOKEN';
|
|
6
|
-
export const name = Env.name;
|
|
7
|
-
let client = undefined;
|
|
8
|
-
export async function configure(config = {}) {
|
|
9
|
-
const { serviceAccountToken, load = true, ...rest } = config;
|
|
10
|
-
await Env.configure({ ...rest, load: false });
|
|
11
|
-
const auth = serviceAccountToken || process.env[OP_SERVICE_ACCOUNT_TOKEN];
|
|
12
|
-
if (auth) {
|
|
13
|
-
const pkg = await importLocal(path.join(import.meta.dirname, '../package.json'));
|
|
14
|
-
client = await createClient({
|
|
15
|
-
auth,
|
|
16
|
-
integrationName: pkg.name.replace(/^(\/|@)/, '').replace(/[/@]+/g, '-'),
|
|
17
|
-
integrationVersion: pkg.version
|
|
18
|
-
});
|
|
19
|
-
if (load) {
|
|
20
|
-
await parse();
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
else if (load) {
|
|
24
|
-
await Env.parse();
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
export function options() {
|
|
28
|
-
return {
|
|
29
|
-
opt: {
|
|
30
|
-
serviceAccountToken: {
|
|
31
|
-
description: `1Password service account token (defaults to ${OP_SERVICE_ACCOUNT_TOKEN}} environment variable, if present)`
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
export async function init({ values }) {
|
|
37
|
-
await configure(values);
|
|
38
|
-
parse();
|
|
39
|
-
}
|
|
40
|
-
function isSecretReference(value) {
|
|
41
|
-
return (value &&
|
|
42
|
-
value !== null &&
|
|
43
|
-
typeof value === 'string' &&
|
|
44
|
-
/^op:\/\//.test(value));
|
|
45
|
-
}
|
|
46
|
-
function secretReferences(parsed) {
|
|
47
|
-
return Object.fromEntries(Object.entries(parsed).filter((entry) => isSecretReference(entry[1])));
|
|
48
|
-
}
|
|
49
|
-
export async function parse(file) {
|
|
50
|
-
const parsed = await Env.parse(file);
|
|
51
|
-
if (client) {
|
|
52
|
-
for (const key in secretReferences(parsed)) {
|
|
53
|
-
parsed[key] = await client.secrets.resolve(parsed[key]);
|
|
54
|
-
process.env[key] = parsed[key];
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
else if (Object.keys(secretReferences(parsed)).length) {
|
|
58
|
-
throw new Error('Attempt to parse .env file containing secret reference without a 1Password client');
|
|
59
|
-
}
|
|
60
|
-
return parsed;
|
|
61
|
-
}
|
|
62
|
-
export async function get({ key, file }) {
|
|
63
|
-
return (await parse(file))[key];
|
|
64
|
-
}
|
|
65
|
-
export async function exists({ key, file }) {
|
|
66
|
-
return Env.exists({ key, file });
|
|
67
|
-
}
|
|
68
|
-
function secretFrom(secretReference) {
|
|
69
|
-
const [vault, item, section, field] = secretReference
|
|
70
|
-
.replace('op://', '')
|
|
71
|
-
.split('/');
|
|
72
|
-
return { vault, item, section, field };
|
|
73
|
-
}
|
|
74
|
-
async function itemFrom(secret) {
|
|
75
|
-
if (client) {
|
|
76
|
-
const vault = (await client.vaults.list())
|
|
77
|
-
.filter((vault) => vault.title == secret.vault)
|
|
78
|
-
.shift();
|
|
79
|
-
if (vault) {
|
|
80
|
-
const item = (await client.items.list(vault.id))
|
|
81
|
-
.filter((item) => item.title === secret.item || item.id === secret.item)
|
|
82
|
-
.shift();
|
|
83
|
-
if (item) {
|
|
84
|
-
return await client.items.get(vault.id, item.id);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
return undefined;
|
|
89
|
-
}
|
|
90
|
-
/** Requires a service account with write privileges */
|
|
91
|
-
export async function set({ key, value, file, ...rest }) {
|
|
92
|
-
const prev = await Env.get({ key, file });
|
|
93
|
-
if (prev && isSecretReference(prev)) {
|
|
94
|
-
if (client) {
|
|
95
|
-
const secret = secretFrom(prev);
|
|
96
|
-
const item = await itemFrom(secret);
|
|
97
|
-
if (item) {
|
|
98
|
-
const updated = {
|
|
99
|
-
...item,
|
|
100
|
-
fields: item.fields.map((field) => {
|
|
101
|
-
if (field.title === secret.field &&
|
|
102
|
-
((/^Section_.+/.test(secret.section) &&
|
|
103
|
-
field.sectionId == secret.section.replace(/^Section_/, '')) ||
|
|
104
|
-
field.sectionId ==
|
|
105
|
-
item.sections
|
|
106
|
-
.filter((section) => section.title === secret.section)
|
|
107
|
-
.shift()?.id)) {
|
|
108
|
-
return { ...field, value };
|
|
109
|
-
}
|
|
110
|
-
return field;
|
|
111
|
-
})
|
|
112
|
-
};
|
|
113
|
-
await client.items.put(updated);
|
|
114
|
-
}
|
|
115
|
-
else {
|
|
116
|
-
throw new Error('1Password item could not be found');
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
else {
|
|
120
|
-
throw new Error('Attempt to update .env file value that is currently a secret reference without a 1Password client');
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
else {
|
|
124
|
-
// FIXME handle creating a new secret reference
|
|
125
|
-
// Issue URL: https://github.com/battis/qui-cli/issues/63
|
|
126
|
-
return await Env.set({ key, value, file, ...rest });
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
export const remove = Env.remove;
|