@youkno/edge-cli 1.20.2314
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/.pnp.cjs +8793 -0
- package/.pnp.loader.mjs +2126 -0
- package/.yarn/install-state.gz +0 -0
- package/README.md +44 -0
- package/dist/commands/config.js +25 -0
- package/dist/commands/healthCheck.js +30 -0
- package/dist/commands/login.js +55 -0
- package/dist/commands/product.js +24 -0
- package/dist/commands/shell.js +180 -0
- package/dist/commands/token.js +23 -0
- package/dist/commands/uploadUsers.js +54 -0
- package/dist/default-edge-api-config.json +61 -0
- package/dist/index.js +40 -0
- package/dist/lib/auth.js +451 -0
- package/dist/lib/config.js +216 -0
- package/dist/lib/http.js +15 -0
- package/dist/lib/request.js +24 -0
- package/dist/lib/types.js +2 -0
- package/package.json +27 -0
- package/src/commands/config.ts +28 -0
- package/src/commands/healthCheck.ts +35 -0
- package/src/commands/login.ts +59 -0
- package/src/commands/product.ts +24 -0
- package/src/commands/shell.ts +213 -0
- package/src/commands/token.ts +26 -0
- package/src/commands/uploadUsers.ts +63 -0
- package/src/default-edge-api-config.json +61 -0
- package/src/index.ts +45 -0
- package/src/lib/auth.ts +527 -0
- package/src/lib/config.ts +253 -0
- package/src/lib/http.ts +12 -0
- package/src/lib/request.ts +23 -0
- package/src/lib/types.ts +35 -0
- package/tsconfig.json +14 -0
|
Binary file
|
package/README.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# edge-cli
|
|
2
|
+
|
|
3
|
+
Node/TypeScript replacement for `edge-api.sh`.
|
|
4
|
+
|
|
5
|
+
## Local usage
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
cd edge-cli
|
|
9
|
+
yarn install
|
|
10
|
+
yarn build
|
|
11
|
+
yarn node dist/index.js --help
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Implemented commands
|
|
15
|
+
|
|
16
|
+
- `config`
|
|
17
|
+
- `health-check`
|
|
18
|
+
- `product:default <product>`
|
|
19
|
+
- `login`
|
|
20
|
+
- `login:list`
|
|
21
|
+
- `login:use <email>`
|
|
22
|
+
- `logout [email]`
|
|
23
|
+
- `token [--refresh] [--header]`
|
|
24
|
+
- `shell [--json] [--dry-run|--validate] [--continue-on-error] [--request-id <id>] [-v key=value] [<command>|<script.esh>]`
|
|
25
|
+
- `upload-users [-q] [-l] [-p] <file>`
|
|
26
|
+
|
|
27
|
+
## Global flags
|
|
28
|
+
|
|
29
|
+
- `--product`
|
|
30
|
+
- `--env` (`devlocal|devel|prod`)
|
|
31
|
+
- `--base-url`
|
|
32
|
+
- `--client`
|
|
33
|
+
- `--auth`
|
|
34
|
+
- `--config-path`
|
|
35
|
+
|
|
36
|
+
`.edge-api` files are read from:
|
|
37
|
+
|
|
38
|
+
1. `/etc/edge-api`
|
|
39
|
+
2. `./.edge-api`
|
|
40
|
+
3. `~/.edge-api`
|
|
41
|
+
|
|
42
|
+
JWT session data is stored at `~/.edge-cli-auth/accounts.json`.
|
|
43
|
+
|
|
44
|
+
If no product is provided (`--product` or `PRODUCT=` in `.edge-api`), `edge-cli` shows an interactive product selector when running in a TTY.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerConfig = registerConfig;
|
|
4
|
+
const config_1 = require("../lib/config");
|
|
5
|
+
function registerConfig(program) {
|
|
6
|
+
program
|
|
7
|
+
.command("config")
|
|
8
|
+
.description("Print effective configuration")
|
|
9
|
+
.option("--json", "Print as JSON")
|
|
10
|
+
.action(async function configAction(commandOptions) {
|
|
11
|
+
const parent = this.parent;
|
|
12
|
+
const opts = (parent?.opts() ?? {});
|
|
13
|
+
const resolved = await (0, config_1.resolveEffectiveConfig)(opts);
|
|
14
|
+
if (commandOptions.json) {
|
|
15
|
+
process.stdout.write(`${JSON.stringify(resolved, null, 2)}\n`);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
process.stdout.write(`product=${resolved.product}\n`);
|
|
19
|
+
process.stdout.write(`env=${resolved.env}\n`);
|
|
20
|
+
process.stdout.write(`baseUrl=${resolved.baseUrl}\n`);
|
|
21
|
+
process.stdout.write(`clientId=${resolved.clientId ?? ""}\n`);
|
|
22
|
+
process.stdout.write(`auth=${resolved.auth ? "<configured>" : ""}\n`);
|
|
23
|
+
process.stdout.write(`configFiles=${resolved.configFiles.join(",") || "<none>"}\n`);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerHealthCheck = registerHealthCheck;
|
|
4
|
+
const config_1 = require("../lib/config");
|
|
5
|
+
const http_1 = require("../lib/http");
|
|
6
|
+
function registerHealthCheck(program) {
|
|
7
|
+
program
|
|
8
|
+
.command("health-check")
|
|
9
|
+
.description("Call /health_check on the selected API")
|
|
10
|
+
.option("--key <key>", "Health check key; can also come from HEALTH_CHECK_KEY")
|
|
11
|
+
.action(async function healthCheckAction(commandOptions) {
|
|
12
|
+
const parent = this.parent;
|
|
13
|
+
const opts = (parent?.opts() ?? {});
|
|
14
|
+
const resolved = await (0, config_1.resolveEffectiveConfig)(opts);
|
|
15
|
+
const key = commandOptions.key ?? process.env.HEALTH_CHECK_KEY;
|
|
16
|
+
if (!key) {
|
|
17
|
+
throw new Error("Missing health check key. Pass --key or set HEALTH_CHECK_KEY.");
|
|
18
|
+
}
|
|
19
|
+
const stateHeader = `${resolved.product}.${resolved.env}`;
|
|
20
|
+
const url = `${resolved.baseUrl.replace(/\/$/, "")}/health_check`;
|
|
21
|
+
const { status, body } = await (0, http_1.getText)(url, {
|
|
22
|
+
"X-edge-state": stateHeader,
|
|
23
|
+
Authorization: (0, http_1.basicAuthHeader)("api_user", key)
|
|
24
|
+
});
|
|
25
|
+
if (status >= 400) {
|
|
26
|
+
throw new Error(`Health check failed (${status}) for ${url}: ${body}`);
|
|
27
|
+
}
|
|
28
|
+
process.stdout.write(body.endsWith("\n") ? body : `${body}\n`);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerLogin = registerLogin;
|
|
4
|
+
const auth_1 = require("../lib/auth");
|
|
5
|
+
const config_1 = require("../lib/config");
|
|
6
|
+
function registerLogin(program) {
|
|
7
|
+
program
|
|
8
|
+
.command("login")
|
|
9
|
+
.description("Authenticate via browser and store JWT tokens")
|
|
10
|
+
.action(async function loginAction() {
|
|
11
|
+
const parent = this.parent;
|
|
12
|
+
const opts = (parent?.opts() ?? {});
|
|
13
|
+
const cfg = await (0, config_1.resolveEffectiveConfig)(opts);
|
|
14
|
+
const email = await (0, auth_1.login)(cfg);
|
|
15
|
+
process.stdout.write(`Successfully authenticated as ${email}\n`);
|
|
16
|
+
});
|
|
17
|
+
program
|
|
18
|
+
.command("login:list")
|
|
19
|
+
.description("List saved accounts for current product/environment")
|
|
20
|
+
.action(async function listAction() {
|
|
21
|
+
const parent = this.parent;
|
|
22
|
+
const opts = (parent?.opts() ?? {});
|
|
23
|
+
const cfg = await (0, config_1.resolveEffectiveConfig)(opts);
|
|
24
|
+
const accounts = (0, auth_1.listLogins)(cfg);
|
|
25
|
+
if (accounts.length === 0) {
|
|
26
|
+
process.stdout.write(`No saved JWT session for ${cfg.product}/${cfg.env}.\n`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
for (const account of accounts) {
|
|
30
|
+
process.stdout.write(`${account.isDefault ? "*" : " "} ${account.email}\n`);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
program
|
|
34
|
+
.command("login:use")
|
|
35
|
+
.description("Set default account for current product/environment")
|
|
36
|
+
.argument("<email>")
|
|
37
|
+
.action(async function useAction(email) {
|
|
38
|
+
const parent = this.parent;
|
|
39
|
+
const opts = (parent?.opts() ?? {});
|
|
40
|
+
const cfg = await (0, config_1.resolveEffectiveConfig)(opts);
|
|
41
|
+
(0, auth_1.setDefaultLogin)(cfg, email);
|
|
42
|
+
process.stdout.write(`Default account: ${email}\n`);
|
|
43
|
+
});
|
|
44
|
+
program
|
|
45
|
+
.command("logout")
|
|
46
|
+
.description("Logout account (default if not provided)")
|
|
47
|
+
.argument("[email]")
|
|
48
|
+
.action(async function logoutAction(email) {
|
|
49
|
+
const parent = this.parent;
|
|
50
|
+
const opts = (parent?.opts() ?? {});
|
|
51
|
+
const cfg = await (0, config_1.resolveEffectiveConfig)(opts);
|
|
52
|
+
const removed = await (0, auth_1.logout)(cfg, email);
|
|
53
|
+
process.stdout.write(`Logged out: ${removed}\n`);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerProduct = registerProduct;
|
|
4
|
+
const config_1 = require("../lib/config");
|
|
5
|
+
function registerProduct(program) {
|
|
6
|
+
program
|
|
7
|
+
.command("product:default")
|
|
8
|
+
.description("Set or clear default PRODUCT in .edge-api")
|
|
9
|
+
.argument("[product]", "Product key (e.g. belong, stash, alleaves)")
|
|
10
|
+
.option("--file <path>", "Target edge-api config file (default: ~/.edge-api)")
|
|
11
|
+
.option("--clear", "Remove PRODUCT from target .edge-api file")
|
|
12
|
+
.action(function productDefaultAction(product, options) {
|
|
13
|
+
if (!options.clear && !product) {
|
|
14
|
+
throw new Error("Missing product. Pass <product> or use --clear.");
|
|
15
|
+
}
|
|
16
|
+
const target = (0, config_1.setDefaultProduct)(options.clear ? undefined : product, options.file);
|
|
17
|
+
if (options.clear) {
|
|
18
|
+
process.stdout.write(`Cleared PRODUCT in ${target}\n`);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
process.stdout.write(`Set PRODUCT=${(product ?? "").toLowerCase()} in ${target}\n`);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.registerShell = registerShell;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const node_readline_1 = __importDefault(require("node:readline"));
|
|
10
|
+
const auth_1 = require("../lib/auth");
|
|
11
|
+
const config_1 = require("../lib/config");
|
|
12
|
+
const request_1 = require("../lib/request");
|
|
13
|
+
function resolveInlineScript(script, vars) {
|
|
14
|
+
const header = (vars ?? []).join("\n");
|
|
15
|
+
return header ? `${header}\n${script}\n` : `${script}\n`;
|
|
16
|
+
}
|
|
17
|
+
function renderEsh(filePath, stack = []) {
|
|
18
|
+
const absolutePath = node_path_1.default.resolve(filePath);
|
|
19
|
+
if (stack.includes(absolutePath)) {
|
|
20
|
+
throw new Error(`Circular include detected: ${absolutePath}`);
|
|
21
|
+
}
|
|
22
|
+
if (!node_fs_1.default.existsSync(absolutePath)) {
|
|
23
|
+
throw new Error(`Script file not found: ${absolutePath}`);
|
|
24
|
+
}
|
|
25
|
+
const lines = node_fs_1.default.readFileSync(absolutePath, "utf8").split(/\r?\n/);
|
|
26
|
+
const out = [];
|
|
27
|
+
const nextStack = [...stack, absolutePath];
|
|
28
|
+
for (let i = 0; i < lines.length; i++) {
|
|
29
|
+
const line = lines[i] ?? "";
|
|
30
|
+
const trimmed = line.trim();
|
|
31
|
+
if (trimmed.startsWith("include ")) {
|
|
32
|
+
let includePath = trimmed.replace(/^include\s+/, "").trim();
|
|
33
|
+
if ((includePath.startsWith('"') && includePath.endsWith('"')) || (includePath.startsWith("'") && includePath.endsWith("'"))) {
|
|
34
|
+
includePath = includePath.slice(1, -1);
|
|
35
|
+
}
|
|
36
|
+
if (!includePath) {
|
|
37
|
+
throw new Error(`Missing include path in ${absolutePath}:${i + 1}`);
|
|
38
|
+
}
|
|
39
|
+
const includeFile = node_path_1.default.isAbsolute(includePath)
|
|
40
|
+
? includePath
|
|
41
|
+
: node_path_1.default.resolve(node_path_1.default.dirname(absolutePath), includePath);
|
|
42
|
+
out.push(renderEsh(includeFile, nextStack));
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
out.push(line);
|
|
46
|
+
}
|
|
47
|
+
return out.join("\n");
|
|
48
|
+
}
|
|
49
|
+
async function shellCmd(cfg, authHeader, cmd, wantJson) {
|
|
50
|
+
const url = new URL(`${cfg.baseUrl.replace(/\/$/, "")}/shell`);
|
|
51
|
+
url.searchParams.set("cmd", cmd);
|
|
52
|
+
const headers = (0, request_1.baseHeaders)(cfg, authHeader);
|
|
53
|
+
if (wantJson) {
|
|
54
|
+
headers.Accept = "application/json";
|
|
55
|
+
}
|
|
56
|
+
const response = await fetch(url, {
|
|
57
|
+
method: "GET",
|
|
58
|
+
headers
|
|
59
|
+
});
|
|
60
|
+
const body = await (0, request_1.checkedText)(response, "shell");
|
|
61
|
+
if (wantJson) {
|
|
62
|
+
try {
|
|
63
|
+
const parsed = JSON.parse(body);
|
|
64
|
+
process.stdout.write(`${JSON.stringify(parsed, null, 2)}\n`);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// fall through
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
process.stdout.write(body.endsWith("\n") ? body : `${body}\n`);
|
|
72
|
+
}
|
|
73
|
+
async function shellScript(cfg, authHeader, scriptText, options, scriptName = "inline.esh") {
|
|
74
|
+
const url = new URL(`${cfg.baseUrl.replace(/\/$/, "")}/shell/script`);
|
|
75
|
+
url.searchParams.set("scriptName", scriptName);
|
|
76
|
+
url.searchParams.set("dryRun", String(Boolean(options.dryRun || options.validate)));
|
|
77
|
+
url.searchParams.set("continueOnError", String(Boolean(options.continueOnError)));
|
|
78
|
+
if (options.requestId) {
|
|
79
|
+
url.searchParams.set("requestId", options.requestId);
|
|
80
|
+
}
|
|
81
|
+
const headers = (0, request_1.baseHeaders)(cfg, authHeader);
|
|
82
|
+
headers["Content-Type"] = "text/plain";
|
|
83
|
+
if (options.json) {
|
|
84
|
+
headers.Accept = "application/json";
|
|
85
|
+
}
|
|
86
|
+
const response = await fetch(url, {
|
|
87
|
+
method: "POST",
|
|
88
|
+
headers,
|
|
89
|
+
body: scriptText
|
|
90
|
+
});
|
|
91
|
+
const body = await (0, request_1.checkedText)(response, "shell script");
|
|
92
|
+
if (options.json) {
|
|
93
|
+
try {
|
|
94
|
+
const parsed = JSON.parse(body);
|
|
95
|
+
process.stdout.write(`${JSON.stringify(parsed, null, 2)}\n`);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// fall through
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
process.stdout.write(body.endsWith("\n") ? body : `${body}\n`);
|
|
103
|
+
}
|
|
104
|
+
async function repl(cfg, authHeader, options) {
|
|
105
|
+
const rl = node_readline_1.default.createInterface({
|
|
106
|
+
input: process.stdin,
|
|
107
|
+
output: process.stdout,
|
|
108
|
+
terminal: true
|
|
109
|
+
});
|
|
110
|
+
process.stdout.write("Type Ctrl-D to exit, 'help' for help\n");
|
|
111
|
+
rl.setPrompt(`${cfg.env}> `);
|
|
112
|
+
rl.prompt();
|
|
113
|
+
rl.on("line", async (line) => {
|
|
114
|
+
const cmd = line.trim();
|
|
115
|
+
if (!cmd) {
|
|
116
|
+
rl.prompt();
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
await shellCmd(cfg, authHeader, cmd, Boolean(options.json));
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
process.stderr.write(`ERROR: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
124
|
+
}
|
|
125
|
+
rl.prompt();
|
|
126
|
+
});
|
|
127
|
+
await new Promise((resolve) => {
|
|
128
|
+
rl.on("close", () => {
|
|
129
|
+
process.stdout.write("\n");
|
|
130
|
+
resolve();
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
function registerShell(program) {
|
|
135
|
+
program
|
|
136
|
+
.command("shell")
|
|
137
|
+
.description("Run shell command/script against Edge API")
|
|
138
|
+
.option("--json", "request JSON output when available")
|
|
139
|
+
.option("--dry-run", "run script in dry-run mode")
|
|
140
|
+
.option("--validate", "alias for --dry-run")
|
|
141
|
+
.option("--continue-on-error", "continue script execution on errors")
|
|
142
|
+
.option("--request-id <id>", "request ID")
|
|
143
|
+
.option("-v, --var <key=value>", "script variable", (value, prev = []) => {
|
|
144
|
+
if (!value.includes("=")) {
|
|
145
|
+
throw new Error(`Invalid variable assignment: ${value} (expected key=value)`);
|
|
146
|
+
}
|
|
147
|
+
prev.push(value);
|
|
148
|
+
return prev;
|
|
149
|
+
})
|
|
150
|
+
.argument("[target]", "Command or .esh file")
|
|
151
|
+
.argument("[inlineScript...]", "Inline script chunks when using --")
|
|
152
|
+
.action(async function shellAction(target, inlineScript) {
|
|
153
|
+
const parent = this.parent;
|
|
154
|
+
const rootOpts = (parent?.opts() ?? {});
|
|
155
|
+
const cfg = await (0, config_1.resolveEffectiveConfig)(rootOpts);
|
|
156
|
+
const options = this.opts();
|
|
157
|
+
const authHeader = await (0, auth_1.resolveAuthHeader)(cfg);
|
|
158
|
+
if (!target && (!inlineScript || inlineScript.length === 0)) {
|
|
159
|
+
await repl(cfg, authHeader, options);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (target?.endsWith(".esh")) {
|
|
163
|
+
const rendered = renderEsh(target);
|
|
164
|
+
const payload = resolveInlineScript(rendered, options.vars);
|
|
165
|
+
await shellScript(cfg, authHeader, payload, options, node_path_1.default.basename(target));
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (inlineScript && inlineScript.length > 0) {
|
|
169
|
+
const payload = resolveInlineScript(inlineScript.join(" "), options.vars);
|
|
170
|
+
await shellScript(cfg, authHeader, payload, options, "inline.esh");
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if (options.dryRun || options.validate || options.continueOnError || options.requestId || (options.vars?.length ?? 0) > 0) {
|
|
174
|
+
const payload = resolveInlineScript(target ?? "", options.vars);
|
|
175
|
+
await shellScript(cfg, authHeader, payload, options, "inline.esh");
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
await shellCmd(cfg, authHeader, target ?? "", Boolean(options.json));
|
|
179
|
+
});
|
|
180
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerToken = registerToken;
|
|
4
|
+
const auth_1 = require("../lib/auth");
|
|
5
|
+
const config_1 = require("../lib/config");
|
|
6
|
+
function registerToken(program) {
|
|
7
|
+
program
|
|
8
|
+
.command("token")
|
|
9
|
+
.description("Print a JWT access token for API calls (e.g. Postman)")
|
|
10
|
+
.option("--refresh", "Force refresh using refresh token when available")
|
|
11
|
+
.option("--header", "Print as Authorization header line")
|
|
12
|
+
.action(async function tokenAction(commandOptions) {
|
|
13
|
+
const parent = this.parent;
|
|
14
|
+
const opts = (parent?.opts() ?? {});
|
|
15
|
+
const cfg = await (0, config_1.resolveEffectiveConfig)(opts);
|
|
16
|
+
const token = await (0, auth_1.resolveAccessToken)(cfg, Boolean(commandOptions.refresh));
|
|
17
|
+
if (commandOptions.header) {
|
|
18
|
+
process.stdout.write(`Authorization: Bearer ${token}\n`);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
process.stdout.write(`${token}\n`);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.registerUploadUsers = registerUploadUsers;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const auth_1 = require("../lib/auth");
|
|
10
|
+
const config_1 = require("../lib/config");
|
|
11
|
+
const request_1 = require("../lib/request");
|
|
12
|
+
function registerUploadUsers(program) {
|
|
13
|
+
program
|
|
14
|
+
.command("upload-users")
|
|
15
|
+
.description("Upload users CSV for a client")
|
|
16
|
+
.option("-q, --quiet", "quiet mode")
|
|
17
|
+
.option("-l, --lenient", "lenient parser mode")
|
|
18
|
+
.option("-p, --partial", "partial mode")
|
|
19
|
+
.argument("<file>", "CSV file")
|
|
20
|
+
.action(async function uploadUsersAction(file, commandOptions) {
|
|
21
|
+
const parent = this.parent;
|
|
22
|
+
const opts = (parent?.opts() ?? {});
|
|
23
|
+
const cfg = await (0, config_1.resolveEffectiveConfig)(opts);
|
|
24
|
+
if (!cfg.clientId) {
|
|
25
|
+
throw new Error("No client ID specified. Pass --client or set CLIENT_ID in .edge-api.");
|
|
26
|
+
}
|
|
27
|
+
const absoluteFile = node_path_1.default.resolve(process.cwd(), file);
|
|
28
|
+
if (!node_fs_1.default.existsSync(absoluteFile)) {
|
|
29
|
+
throw new Error(`File not found: ${absoluteFile}`);
|
|
30
|
+
}
|
|
31
|
+
const authHeader = await (0, auth_1.resolveAuthHeader)(cfg);
|
|
32
|
+
const url = new URL(`${cfg.baseUrl.replace(/\/$/, "")}/api/v1/clients/${cfg.clientId}/users`);
|
|
33
|
+
url.searchParams.set("dummy", "true");
|
|
34
|
+
if (commandOptions.partial) {
|
|
35
|
+
url.searchParams.set("partial", "true");
|
|
36
|
+
}
|
|
37
|
+
if (commandOptions.lenient) {
|
|
38
|
+
url.searchParams.set("lenient", "true");
|
|
39
|
+
}
|
|
40
|
+
if (commandOptions.quiet) {
|
|
41
|
+
url.searchParams.set("quiet", "true");
|
|
42
|
+
}
|
|
43
|
+
const data = node_fs_1.default.readFileSync(absoluteFile);
|
|
44
|
+
const form = new FormData();
|
|
45
|
+
form.append("file", new Blob([data], { type: "text/csv" }), node_path_1.default.basename(absoluteFile));
|
|
46
|
+
const response = await fetch(url, {
|
|
47
|
+
method: "POST",
|
|
48
|
+
headers: (0, request_1.baseHeaders)(cfg, authHeader),
|
|
49
|
+
body: form
|
|
50
|
+
});
|
|
51
|
+
const body = await (0, request_1.checkedText)(response, "upload-users");
|
|
52
|
+
process.stdout.write(body.endsWith("\n") ? body : `${body}\n`);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"api": {
|
|
3
|
+
"defaultBaseUrl": "https://api.youkno.ai",
|
|
4
|
+
"products": {
|
|
5
|
+
"youkno": {
|
|
6
|
+
"baseUrl": "https://api.youkno.ai",
|
|
7
|
+
"active": false,
|
|
8
|
+
"aliases": ["belong"],
|
|
9
|
+
"consoleBaseProd": "https://belong-prod.web.app",
|
|
10
|
+
"consoleBaseTest": "https://belong-prod--testapp-q8kk4dm6.web.app"
|
|
11
|
+
},
|
|
12
|
+
"stash": {
|
|
13
|
+
"baseUrl": "https://api.mystash.co",
|
|
14
|
+
"active": false,
|
|
15
|
+
"aliases": [],
|
|
16
|
+
"consoleBaseProd": "https://stash-prod.web.app",
|
|
17
|
+
"consoleBaseTest": "https://stash-prod--testapp-ef23abcf.web.app"
|
|
18
|
+
},
|
|
19
|
+
"alleaves": {
|
|
20
|
+
"baseUrl": "https://api.alleaves.shop",
|
|
21
|
+
"active": true,
|
|
22
|
+
"aliases": [],
|
|
23
|
+
"consoleBaseProd": "https://console.alleaves.shop",
|
|
24
|
+
"consoleBaseTest": "https://alleaves-prod--testapp-vn1b2q7v.web.app"
|
|
25
|
+
},
|
|
26
|
+
"vera": {
|
|
27
|
+
"baseUrl": "https://edge-server-dfkcix6pxa-uc.a.run.app",
|
|
28
|
+
"active": false,
|
|
29
|
+
"aliases": [],
|
|
30
|
+
"consoleBaseProd": "https://vera-af0c2.web.app",
|
|
31
|
+
"consoleBaseTest": "https://vera-af0c2--testapp-23e7fe3c.web.app"
|
|
32
|
+
},
|
|
33
|
+
"vip": {
|
|
34
|
+
"baseUrl": "https://edge-server-a465iqwona-uc.a.run.app",
|
|
35
|
+
"active": false,
|
|
36
|
+
"aliases": [],
|
|
37
|
+
"consoleBaseProd": "https://vip-app-6a3d4.web.app",
|
|
38
|
+
"consoleBaseTest": "https://vip-app-6a3d4--testapp-h34bc19a.web.app"
|
|
39
|
+
},
|
|
40
|
+
"dinamo1948": {
|
|
41
|
+
"baseUrl": "https://api.dinamo1948.ro",
|
|
42
|
+
"active": true,
|
|
43
|
+
"aliases": [],
|
|
44
|
+
"consoleBaseProd": "https://console.dinamo1948.ro",
|
|
45
|
+
"consoleBaseTest": "https://dinamo1948-prod--testapp-f48fznbf.web.app"
|
|
46
|
+
},
|
|
47
|
+
"propatrimonio": {
|
|
48
|
+
"baseUrl": "https://api.propatrimonio.org",
|
|
49
|
+
"active": true,
|
|
50
|
+
"aliases": []
|
|
51
|
+
},
|
|
52
|
+
"campaigns": {
|
|
53
|
+
"baseUrl": "https://api.getcampaigns.com",
|
|
54
|
+
"active": true,
|
|
55
|
+
"aliases": [],
|
|
56
|
+
"consoleBaseProd": "https://console.getcampaigns.com",
|
|
57
|
+
"consoleBaseTest": "https://campaigns-abd4a--testapp-ht9twxoz.web.app"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const config_1 = require("./commands/config");
|
|
6
|
+
const healthCheck_1 = require("./commands/healthCheck");
|
|
7
|
+
const login_1 = require("./commands/login");
|
|
8
|
+
const product_1 = require("./commands/product");
|
|
9
|
+
const shell_1 = require("./commands/shell");
|
|
10
|
+
const token_1 = require("./commands/token");
|
|
11
|
+
const uploadUsers_1 = require("./commands/uploadUsers");
|
|
12
|
+
const program = new commander_1.Command();
|
|
13
|
+
program
|
|
14
|
+
.name("edge-cli")
|
|
15
|
+
.description("Edge API command line client")
|
|
16
|
+
.version("0.2.0")
|
|
17
|
+
.option("-p, --product <product>", "Product key (youkno, stash, alleaves, ...)")
|
|
18
|
+
.option("--env <env>", "Environment (devlocal|devel|prod)", "prod")
|
|
19
|
+
.option("--base-url <url>", "Override API base URL")
|
|
20
|
+
.option("--client <clientId>", "Client ID")
|
|
21
|
+
.option("--auth <token:secret>", "Client auth token")
|
|
22
|
+
.option("--config-path <path>", "Additional edge-api style config file")
|
|
23
|
+
.hook("preAction", (command) => {
|
|
24
|
+
const env = command.opts().env;
|
|
25
|
+
const validEnvs = ["devlocal", "devel", "prod"];
|
|
26
|
+
if (!validEnvs.includes(env)) {
|
|
27
|
+
throw new Error(`Invalid --env '${env}'. Expected one of: ${validEnvs.join(", ")}`);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
(0, config_1.registerConfig)(program);
|
|
31
|
+
(0, healthCheck_1.registerHealthCheck)(program);
|
|
32
|
+
(0, product_1.registerProduct)(program);
|
|
33
|
+
(0, login_1.registerLogin)(program);
|
|
34
|
+
(0, token_1.registerToken)(program);
|
|
35
|
+
(0, shell_1.registerShell)(program);
|
|
36
|
+
(0, uploadUsers_1.registerUploadUsers)(program);
|
|
37
|
+
program.parseAsync(process.argv).catch((error) => {
|
|
38
|
+
process.stderr.write(`ERROR: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
});
|