@cloud-cli/env 1.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/.github/workflows/cicd.yml +13 -0
- package/README.md +3 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +104 -0
- package/package.json +41 -0
- package/src/index.spec.js +28 -0
- package/src/index.ts +140 -0
- package/tsconfig.json +14 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
name: CICD
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches:
|
|
5
|
+
- main
|
|
6
|
+
jobs:
|
|
7
|
+
release:
|
|
8
|
+
uses: homebots/workflows/.github/workflows/node-build-release.yml@master
|
|
9
|
+
with:
|
|
10
|
+
branches: main
|
|
11
|
+
secrets:
|
|
12
|
+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
13
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
package/README.md
ADDED
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface App {
|
|
2
|
+
app: string;
|
|
3
|
+
}
|
|
4
|
+
export interface KeyValue {
|
|
5
|
+
key: string;
|
|
6
|
+
value?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface AppKeyValue extends App, KeyValue {
|
|
9
|
+
}
|
|
10
|
+
declare function reload(): void;
|
|
11
|
+
declare function show(options: App): Promise<unknown>;
|
|
12
|
+
declare function set(options: AppKeyValue): Promise<unknown>;
|
|
13
|
+
declare function remove(options: AppKeyValue): Promise<unknown>;
|
|
14
|
+
declare function get(options: Omit<AppKeyValue, 'value'>): Promise<unknown>;
|
|
15
|
+
declare const _default: {
|
|
16
|
+
reload: typeof reload;
|
|
17
|
+
show: typeof show;
|
|
18
|
+
get: typeof get;
|
|
19
|
+
set: typeof set;
|
|
20
|
+
delete: typeof remove;
|
|
21
|
+
};
|
|
22
|
+
export default _default;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import sqlite from 'sqlite3';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
const appNotSpecifiedError = new Error('App not specified');
|
|
4
|
+
const keyNotSpecifiedError = new Error('Key not specified');
|
|
5
|
+
let db;
|
|
6
|
+
const columns = {
|
|
7
|
+
App: 'app',
|
|
8
|
+
Key: 'key',
|
|
9
|
+
Value: 'value',
|
|
10
|
+
};
|
|
11
|
+
function close() {
|
|
12
|
+
try {
|
|
13
|
+
if (db) {
|
|
14
|
+
db.close();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
catch { }
|
|
18
|
+
;
|
|
19
|
+
}
|
|
20
|
+
function reload() {
|
|
21
|
+
close();
|
|
22
|
+
const inMemory = !!process.env.IN_MEMORY_DB;
|
|
23
|
+
if (inMemory) {
|
|
24
|
+
sqlite.verbose();
|
|
25
|
+
}
|
|
26
|
+
const databasePath = inMemory ? ':memory:' : join(process.cwd(), 'env.db');
|
|
27
|
+
db = new sqlite.Database(databasePath);
|
|
28
|
+
db.run(`CREATE TABLE IF NOT EXISTS env (
|
|
29
|
+
${columns.App} TEXT,
|
|
30
|
+
${columns.Key} TEXT,
|
|
31
|
+
${columns.Value} TEXT,
|
|
32
|
+
UNIQUE (${columns.App}, ${columns.Key})
|
|
33
|
+
)`);
|
|
34
|
+
}
|
|
35
|
+
async function show(options) {
|
|
36
|
+
return new Promise((resolve, reject) => {
|
|
37
|
+
const { app } = options;
|
|
38
|
+
if (!app) {
|
|
39
|
+
return reject(appNotSpecifiedError);
|
|
40
|
+
}
|
|
41
|
+
db
|
|
42
|
+
.prepare(`
|
|
43
|
+
SELECT
|
|
44
|
+
${columns.App},
|
|
45
|
+
${columns.Key},
|
|
46
|
+
${columns.Value}
|
|
47
|
+
FROM env WHERE
|
|
48
|
+
${columns.App} = ?`)
|
|
49
|
+
.all([app], (error, rows) => error ? reject(error) : resolve(rows));
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
async function set(options) {
|
|
53
|
+
const { app, key, value } = options;
|
|
54
|
+
if (!app) {
|
|
55
|
+
return Promise.reject(appNotSpecifiedError);
|
|
56
|
+
}
|
|
57
|
+
if (!key) {
|
|
58
|
+
return Promise.reject(keyNotSpecifiedError);
|
|
59
|
+
}
|
|
60
|
+
return query('REPLACE INTO env VALUES (?, ?, ?)', [app, key, value]);
|
|
61
|
+
}
|
|
62
|
+
async function remove(options) {
|
|
63
|
+
const { app, key } = options;
|
|
64
|
+
if (!app) {
|
|
65
|
+
return Promise.reject(appNotSpecifiedError);
|
|
66
|
+
}
|
|
67
|
+
if (!key) {
|
|
68
|
+
return Promise.reject(keyNotSpecifiedError);
|
|
69
|
+
}
|
|
70
|
+
return query(`DELETE FROM env WHERE ${columns.App} = ? AND ${columns.Key} = ?`, [app, key]);
|
|
71
|
+
}
|
|
72
|
+
async function get(options) {
|
|
73
|
+
return new Promise((resolve, reject) => {
|
|
74
|
+
const { app, key } = options;
|
|
75
|
+
if (!app) {
|
|
76
|
+
return reject(appNotSpecifiedError);
|
|
77
|
+
}
|
|
78
|
+
if (!key) {
|
|
79
|
+
return reject(keyNotSpecifiedError);
|
|
80
|
+
}
|
|
81
|
+
db.serialize(() => {
|
|
82
|
+
db
|
|
83
|
+
.prepare(`
|
|
84
|
+
SELECT
|
|
85
|
+
${columns.App},
|
|
86
|
+
${columns.Key},
|
|
87
|
+
${columns.Value}
|
|
88
|
+
FROM env WHERE
|
|
89
|
+
${columns.App} = ? AND ${columns.Key} = ?`)
|
|
90
|
+
.all([app, key], (error, rows) => (error ? reject(error) : resolve(rows[0])));
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
async function query(statement, inputs) {
|
|
95
|
+
return new Promise((resolve, reject) => {
|
|
96
|
+
db.serialize(() => {
|
|
97
|
+
db
|
|
98
|
+
.prepare(statement)
|
|
99
|
+
.run(inputs)
|
|
100
|
+
.finalize((error) => (error ? reject(error) : resolve(null)));
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
export default { reload, show, get, set, delete: remove };
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cloud-cli/env",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Storage for app environment variables",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"test": "jest",
|
|
10
|
+
"tdd": "jest --watchAll",
|
|
11
|
+
"build": "rm -rf ./dist/* && tsc --project ./tsconfig.json"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"cloudy"
|
|
15
|
+
],
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@babel/core": "^7.21.0",
|
|
19
|
+
"@babel/preset-env": "^7.20.2",
|
|
20
|
+
"@babel/preset-typescript": "^7.21.0",
|
|
21
|
+
"@types/jest": "^27.0.1",
|
|
22
|
+
"@types/node": "^14.18.21",
|
|
23
|
+
"babel-jest": "^29.4.3",
|
|
24
|
+
"jest": "^29.4.3",
|
|
25
|
+
"nodemon": "^2.0.16",
|
|
26
|
+
"ts-jest": "^29.0.5",
|
|
27
|
+
"ts-jest-resolver": "^2.0.0",
|
|
28
|
+
"ts-node": "^9.1.1",
|
|
29
|
+
"typescript": "^4.8.2"
|
|
30
|
+
},
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/cloud-cli/env.git"
|
|
34
|
+
},
|
|
35
|
+
"publishConfig": {
|
|
36
|
+
"access": "public"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"sqlite3": "^5.1.4"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import env from './index';
|
|
2
|
+
|
|
3
|
+
beforeAll(() => {
|
|
4
|
+
process.env.IN_MEMORY_DB = true;
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
const app = { app: 'test' };
|
|
8
|
+
const envVariable = { app: 'test', key: 'key', value: 'ok' };
|
|
9
|
+
|
|
10
|
+
describe('env', () => {
|
|
11
|
+
it('should store variables for an app', async () => {
|
|
12
|
+
env.reload();
|
|
13
|
+
await expect(env.set({ app: '', key: '' })).rejects.toEqual(new Error('App not specified'));
|
|
14
|
+
await expect(env.set({ app: 'test', key: '' })).rejects.toEqual(new Error('Key not specified'));
|
|
15
|
+
await expect(env.get({ app: 'test', key: 'key' })).resolves.toEqual(undefined);
|
|
16
|
+
|
|
17
|
+
// upsert
|
|
18
|
+
await expect(env.set(envVariable)).resolves.toBeNull();
|
|
19
|
+
await expect(env.set(envVariable)).resolves.toBeNull();
|
|
20
|
+
|
|
21
|
+
await expect(env.get({ app: 'test', key: 'key' })).resolves.toEqual(envVariable);
|
|
22
|
+
|
|
23
|
+
await expect(env.show(app)).resolves.toEqual([envVariable]);
|
|
24
|
+
|
|
25
|
+
await expect(env.delete(envVariable)).resolves.toBeNull();
|
|
26
|
+
await expect(env.show(app)).resolves.toEqual([]);
|
|
27
|
+
});
|
|
28
|
+
});
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import sqlite from 'sqlite3';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
|
|
4
|
+
const appNotSpecifiedError = new Error('App not specified');
|
|
5
|
+
const keyNotSpecifiedError = new Error('Key not specified');
|
|
6
|
+
let db: sqlite.Database;
|
|
7
|
+
|
|
8
|
+
const columns = {
|
|
9
|
+
App: 'app',
|
|
10
|
+
Key: 'key',
|
|
11
|
+
Value: 'value',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export interface App {
|
|
15
|
+
app: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface KeyValue {
|
|
19
|
+
key: string;
|
|
20
|
+
value?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface AppKeyValue extends App, KeyValue { }
|
|
24
|
+
|
|
25
|
+
function close() {
|
|
26
|
+
try {
|
|
27
|
+
if (db) {
|
|
28
|
+
db.close();
|
|
29
|
+
}
|
|
30
|
+
} catch { };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function reload() {
|
|
34
|
+
close();
|
|
35
|
+
|
|
36
|
+
const inMemory = !!process.env.IN_MEMORY_DB;
|
|
37
|
+
|
|
38
|
+
if (inMemory) {
|
|
39
|
+
sqlite.verbose();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const databasePath = inMemory ? ':memory:' : join(process.cwd(), 'env.db');
|
|
43
|
+
|
|
44
|
+
db = new sqlite.Database(databasePath);
|
|
45
|
+
db.run(`CREATE TABLE IF NOT EXISTS env (
|
|
46
|
+
${columns.App} TEXT,
|
|
47
|
+
${columns.Key} TEXT,
|
|
48
|
+
${columns.Value} TEXT,
|
|
49
|
+
UNIQUE (${columns.App}, ${columns.Key})
|
|
50
|
+
)`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function show(options: App) {
|
|
54
|
+
return new Promise((resolve, reject) => {
|
|
55
|
+
const { app } = options;
|
|
56
|
+
|
|
57
|
+
if (!app) {
|
|
58
|
+
return reject(appNotSpecifiedError);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
db
|
|
62
|
+
.prepare(`
|
|
63
|
+
SELECT
|
|
64
|
+
${columns.App},
|
|
65
|
+
${columns.Key},
|
|
66
|
+
${columns.Value}
|
|
67
|
+
FROM env WHERE
|
|
68
|
+
${columns.App} = ?`
|
|
69
|
+
)
|
|
70
|
+
.all([app], (error, rows) => error ? reject(error) : resolve(rows));
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function set(options: AppKeyValue) {
|
|
75
|
+
const { app, key, value } = options;
|
|
76
|
+
|
|
77
|
+
if (!app) {
|
|
78
|
+
return Promise.reject(appNotSpecifiedError);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (!key) {
|
|
82
|
+
return Promise.reject(keyNotSpecifiedError);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return query('REPLACE INTO env VALUES (?, ?, ?)', [app, key, value]);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async function remove(options: AppKeyValue) {
|
|
89
|
+
const { app, key } = options;
|
|
90
|
+
|
|
91
|
+
if (!app) {
|
|
92
|
+
return Promise.reject(appNotSpecifiedError);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (!key) {
|
|
96
|
+
return Promise.reject(keyNotSpecifiedError);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return query(`DELETE FROM env WHERE ${columns.App} = ? AND ${columns.Key} = ?`, [app, key])
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async function get(options: Omit<AppKeyValue, 'value'>) {
|
|
103
|
+
return new Promise((resolve, reject) => {
|
|
104
|
+
const { app, key } = options;
|
|
105
|
+
|
|
106
|
+
if (!app) {
|
|
107
|
+
return reject(appNotSpecifiedError);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (!key) {
|
|
111
|
+
return reject(keyNotSpecifiedError);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
db.serialize(() => {
|
|
115
|
+
db
|
|
116
|
+
.prepare(`
|
|
117
|
+
SELECT
|
|
118
|
+
${columns.App},
|
|
119
|
+
${columns.Key},
|
|
120
|
+
${columns.Value}
|
|
121
|
+
FROM env WHERE
|
|
122
|
+
${columns.App} = ? AND ${columns.Key} = ?`
|
|
123
|
+
)
|
|
124
|
+
.all([app, key], (error, rows) => (error ? reject(error) : resolve(rows[0])));
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async function query(statement, inputs) {
|
|
130
|
+
return new Promise((resolve, reject) => {
|
|
131
|
+
db.serialize(() => {
|
|
132
|
+
db
|
|
133
|
+
.prepare(statement)
|
|
134
|
+
.run(inputs)
|
|
135
|
+
.finalize((error) => (error ? reject(error) : resolve(null)));
|
|
136
|
+
});
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export default { reload, show, get, set, delete: remove };
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"moduleResolution": "node",
|
|
4
|
+
"module": "esnext",
|
|
5
|
+
"target": "es2020",
|
|
6
|
+
"lib": ["ESNext"],
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"noUnusedLocals": true,
|
|
9
|
+
"noUnusedParameters": true,
|
|
10
|
+
"outDir": "./dist",
|
|
11
|
+
"declaration": true
|
|
12
|
+
},
|
|
13
|
+
"include": ["./src/**/*.ts"]
|
|
14
|
+
}
|