@quonfig/cli 0.0.6 → 0.0.8
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/README.md +128 -80
- package/dist/codegen/local-config-reader.d.ts +6 -0
- package/dist/codegen/local-config-reader.js +113 -0
- package/dist/commands/create.js +3 -0
- package/dist/commands/generate.d.ts +3 -2
- package/dist/commands/generate.js +18 -10
- package/dist/commands/get.js +1 -1
- package/dist/commands/login.js +5 -2
- package/dist/commands/sdk-key/create.d.ts +11 -0
- package/dist/commands/sdk-key/create.js +100 -0
- package/dist/commands/sdk-key/list.d.ts +10 -0
- package/dist/commands/sdk-key/list.js +48 -0
- package/dist/commands/sdk-key/revoke.d.ts +10 -0
- package/dist/commands/sdk-key/revoke.js +30 -0
- package/dist/commands/sdk-key.d.ts +6 -0
- package/dist/commands/sdk-key.js +15 -0
- package/dist/interactive-prompt.js +0 -4
- package/dist/ui/get-value.js +4 -1
- package/dist/verify/validate.js +28 -8
- package/oclif.manifest.json +277 -128
- package/package.json +1 -1
- package/dist/codegen/config-downloader.d.ts +0 -7
- package/dist/codegen/config-downloader.js +0 -26
- package/dist/commands/download.d.ts +0 -13
- package/dist/commands/download.js +0 -63
- package/dist/commands/serve.d.ts +0 -13
- package/dist/commands/serve.js +0 -101
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import { select } from '@inquirer/prompts';
|
|
3
|
+
import { APICommand } from '../../index.js';
|
|
4
|
+
import { getEnvironments } from '../../api/get-environments.js';
|
|
5
|
+
export default class SdkKeyCreate extends APICommand {
|
|
6
|
+
static description = 'Create a new SDK key';
|
|
7
|
+
static examples = [
|
|
8
|
+
'<%= config.bin %> <%= command.id %> --environment production --type server',
|
|
9
|
+
'<%= config.bin %> <%= command.id %> --environment staging --type browser',
|
|
10
|
+
];
|
|
11
|
+
static flags = {
|
|
12
|
+
environment: Flags.string({
|
|
13
|
+
char: 'e',
|
|
14
|
+
description: 'Environment name (e.g. production, staging)',
|
|
15
|
+
required: false,
|
|
16
|
+
}),
|
|
17
|
+
type: Flags.string({
|
|
18
|
+
char: 't',
|
|
19
|
+
description: 'Key type: server (backend) or browser (frontend)',
|
|
20
|
+
options: ['server', 'browser'],
|
|
21
|
+
required: false,
|
|
22
|
+
}),
|
|
23
|
+
};
|
|
24
|
+
async run() {
|
|
25
|
+
const { flags } = await this.parse(SdkKeyCreate);
|
|
26
|
+
// Fetch available environments
|
|
27
|
+
const environments = await getEnvironments(this);
|
|
28
|
+
if (environments.length === 0) {
|
|
29
|
+
return this.err('No environments found for this workspace.');
|
|
30
|
+
}
|
|
31
|
+
// Resolve environment
|
|
32
|
+
let environmentId;
|
|
33
|
+
let environmentName;
|
|
34
|
+
if (flags.environment) {
|
|
35
|
+
const match = environments.find((e) => e.name.toLowerCase() === flags.environment.toLowerCase());
|
|
36
|
+
if (!match) {
|
|
37
|
+
const names = environments.map((e) => e.name).join(', ');
|
|
38
|
+
return this.err(`Environment "${flags.environment}" not found. Available: ${names}`);
|
|
39
|
+
}
|
|
40
|
+
environmentId = match.id;
|
|
41
|
+
environmentName = match.name;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
if (environments.length === 1) {
|
|
45
|
+
environmentId = environments[0].id;
|
|
46
|
+
environmentName = environments[0].name;
|
|
47
|
+
this.log(`Using environment: ${environmentName}`);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
const chosen = await select({
|
|
51
|
+
choices: environments.map((e) => ({ name: e.name, value: e.id })),
|
|
52
|
+
message: 'Select environment:',
|
|
53
|
+
});
|
|
54
|
+
const match = environments.find((e) => e.id === chosen);
|
|
55
|
+
environmentId = match.id;
|
|
56
|
+
environmentName = match.name;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Resolve key type
|
|
60
|
+
let keyType;
|
|
61
|
+
if (flags.type) {
|
|
62
|
+
keyType = flags.type === 'server' ? 'backend' : 'frontend';
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
const chosen = await select({
|
|
66
|
+
choices: [
|
|
67
|
+
{ name: 'server (backend SDK — Node.js, Go, etc.)', value: 'backend' },
|
|
68
|
+
{ name: 'browser (frontend SDK — JavaScript/React)', value: 'frontend' },
|
|
69
|
+
],
|
|
70
|
+
message: 'Select key type:',
|
|
71
|
+
});
|
|
72
|
+
keyType = chosen;
|
|
73
|
+
}
|
|
74
|
+
const request = await this.apiClient.post('/api/v1/sdkKeys/create', {
|
|
75
|
+
workspaceId: this.workspaceId,
|
|
76
|
+
environmentId,
|
|
77
|
+
keyType,
|
|
78
|
+
});
|
|
79
|
+
if (!request.ok) {
|
|
80
|
+
const errorMsg = request.error?.error || `Failed to create SDK key: ${request.status}`;
|
|
81
|
+
return this.err(errorMsg, { serverError: request.error });
|
|
82
|
+
}
|
|
83
|
+
const key = request.json;
|
|
84
|
+
const typeLabel = keyType === 'backend' ? 'server' : 'browser';
|
|
85
|
+
this.log(`\nSDK key created successfully!\n`);
|
|
86
|
+
this.log(`Environment: ${environmentName}`);
|
|
87
|
+
this.log(`Type: ${typeLabel}`);
|
|
88
|
+
this.log(`Key ID: ${key.id}`);
|
|
89
|
+
this.log(`\nYour SDK key (shown only once — copy it now):\n`);
|
|
90
|
+
this.log(` ${key.rawKey}\n`);
|
|
91
|
+
this.log(`To revoke this key: qfg sdk-key revoke ${key.id}`);
|
|
92
|
+
return {
|
|
93
|
+
environmentId: key.environmentId,
|
|
94
|
+
environmentName: key.environmentName,
|
|
95
|
+
id: key.id,
|
|
96
|
+
keyType: typeLabel,
|
|
97
|
+
rawKey: key.rawKey,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { JsonObj } from '../../result.js';
|
|
2
|
+
import { APICommand } from '../../index.js';
|
|
3
|
+
export default class SdkKeyList extends APICommand {
|
|
4
|
+
static description: string;
|
|
5
|
+
static examples: string[];
|
|
6
|
+
static flags: {
|
|
7
|
+
environment: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
8
|
+
};
|
|
9
|
+
run(): Promise<JsonObj | void>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import { APICommand } from '../../index.js';
|
|
3
|
+
export default class SdkKeyList extends APICommand {
|
|
4
|
+
static description = 'List SDK keys for your workspace';
|
|
5
|
+
static examples = [
|
|
6
|
+
'<%= config.bin %> <%= command.id %>',
|
|
7
|
+
'<%= config.bin %> <%= command.id %> --environment production',
|
|
8
|
+
];
|
|
9
|
+
static flags = {
|
|
10
|
+
environment: Flags.string({
|
|
11
|
+
char: 'e',
|
|
12
|
+
description: 'Filter by environment name',
|
|
13
|
+
required: false,
|
|
14
|
+
}),
|
|
15
|
+
};
|
|
16
|
+
async run() {
|
|
17
|
+
const { flags } = await this.parse(SdkKeyList);
|
|
18
|
+
const request = await this.apiClient.post('/api/v1/sdkKeys/list', { workspaceId: this.workspaceId });
|
|
19
|
+
if (!request.ok) {
|
|
20
|
+
const errorMsg = request.error?.error || `Failed to fetch SDK keys: ${request.status}`;
|
|
21
|
+
return this.err(errorMsg, { serverError: request.error });
|
|
22
|
+
}
|
|
23
|
+
let keys = (Array.isArray(request.json) ? request.json : []);
|
|
24
|
+
if (flags.environment) {
|
|
25
|
+
const envFilter = flags.environment.toLowerCase();
|
|
26
|
+
keys = keys.filter((k) => k.environmentName.toLowerCase() === envFilter);
|
|
27
|
+
}
|
|
28
|
+
if (keys.length === 0) {
|
|
29
|
+
const envSuffix = flags.environment ? ` for environment "${flags.environment}"` : '';
|
|
30
|
+
this.log(`No SDK keys found${envSuffix}.`);
|
|
31
|
+
this.log(`\nCreate one with: qfg sdk-key create --environment <name> --type server|browser`);
|
|
32
|
+
return { keys: [] };
|
|
33
|
+
}
|
|
34
|
+
const maxEnvLength = Math.max(11, ...keys.map((k) => k.environmentName.length));
|
|
35
|
+
const maxTypeLength = 7; // "browser" is longest
|
|
36
|
+
const maxIdLength = Math.max(2, ...keys.map((k) => k.id.length));
|
|
37
|
+
const header = `${'ID'.padEnd(maxIdLength)} ${'ENVIRONMENT'.padEnd(maxEnvLength)} ${'TYPE'.padEnd(maxTypeLength)} ${'PREFIX'.padEnd(28)} CREATED`;
|
|
38
|
+
const separator = `${'-'.repeat(maxIdLength)} ${'-'.repeat(maxEnvLength)} ${'-'.repeat(maxTypeLength)} ${'-'.repeat(28)} ${'-'.repeat(24)}`;
|
|
39
|
+
const rows = keys.map((k) => {
|
|
40
|
+
const typeLabel = k.keyType === 'backend' ? 'server' : 'browser';
|
|
41
|
+
const prefix = k.keyType === 'backend' ? `qf_sk_${k.environmentName}_...` : `qf_pk_${k.environmentName}_...`;
|
|
42
|
+
const created = k.createdAt ? new Date(k.createdAt).toISOString().slice(0, 10) : 'unknown';
|
|
43
|
+
return `${k.id.padEnd(maxIdLength)} ${k.environmentName.padEnd(maxEnvLength)} ${typeLabel.padEnd(maxTypeLength)} ${prefix.padEnd(28)} ${created}`;
|
|
44
|
+
});
|
|
45
|
+
this.log([header, separator, ...rows].join('\n'));
|
|
46
|
+
return { keys };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { JsonObj } from '../../result.js';
|
|
2
|
+
import { APICommand } from '../../index.js';
|
|
3
|
+
export default class SdkKeyRevoke extends APICommand {
|
|
4
|
+
static description: string;
|
|
5
|
+
static args: {
|
|
6
|
+
keyId: import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
|
|
7
|
+
};
|
|
8
|
+
static examples: string[];
|
|
9
|
+
run(): Promise<JsonObj | void>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Args } from '@oclif/core';
|
|
2
|
+
import { APICommand } from '../../index.js';
|
|
3
|
+
export default class SdkKeyRevoke extends APICommand {
|
|
4
|
+
static description = 'Revoke an SDK key by its ID';
|
|
5
|
+
static args = {
|
|
6
|
+
keyId: Args.string({
|
|
7
|
+
description: 'ID of the SDK key to revoke',
|
|
8
|
+
required: true,
|
|
9
|
+
}),
|
|
10
|
+
};
|
|
11
|
+
static examples = [
|
|
12
|
+
'<%= config.bin %> <%= command.id %> a1b2c3d4-e5f6-7890-abcd-ef1234567890',
|
|
13
|
+
];
|
|
14
|
+
async run() {
|
|
15
|
+
const { args } = await this.parse(SdkKeyRevoke);
|
|
16
|
+
const request = await this.apiClient.post('/api/v1/sdkKeys/delete', {
|
|
17
|
+
workspaceId: this.workspaceId,
|
|
18
|
+
keyId: args.keyId,
|
|
19
|
+
});
|
|
20
|
+
if (!request.ok) {
|
|
21
|
+
if (request.status === 404) {
|
|
22
|
+
return this.err(`SDK key "${args.keyId}" not found or already revoked.`);
|
|
23
|
+
}
|
|
24
|
+
const errorMsg = request.error?.error || `Failed to revoke SDK key: ${request.status}`;
|
|
25
|
+
return this.err(errorMsg, { serverError: request.error });
|
|
26
|
+
}
|
|
27
|
+
this.log(`SDK key ${args.keyId} has been revoked.`);
|
|
28
|
+
return { keyId: args.keyId, revoked: true };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BaseCommand } from '../index.js';
|
|
2
|
+
export default class SdkKey extends BaseCommand {
|
|
3
|
+
static description = 'Manage SDK keys for your workspace';
|
|
4
|
+
static examples = [
|
|
5
|
+
'<%= config.bin %> sdk-key list',
|
|
6
|
+
'<%= config.bin %> sdk-key create --environment production --type server',
|
|
7
|
+
'<%= config.bin %> sdk-key revoke <key-id>',
|
|
8
|
+
];
|
|
9
|
+
async run() {
|
|
10
|
+
this.log('Use one of the sdk-key subcommands:');
|
|
11
|
+
this.log(' qfg sdk-key list');
|
|
12
|
+
this.log(' qfg sdk-key create --environment <name> --type server|browser');
|
|
13
|
+
this.log(' qfg sdk-key revoke <key-id>');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import Create from './commands/create.js';
|
|
2
|
-
import Download from './commands/download.js';
|
|
3
2
|
import GenerateNewHexKey from './commands/generate-new-hex-key.js';
|
|
4
3
|
import Get from './commands/get.js';
|
|
5
4
|
import Info from './commands/info.js';
|
|
6
5
|
import List from './commands/list.js';
|
|
7
6
|
import Mcp from './commands/mcp.js';
|
|
8
7
|
import Override from './commands/override.js';
|
|
9
|
-
import Serve from './commands/serve.js';
|
|
10
8
|
import SetDefault from './commands/set-default.js';
|
|
11
9
|
import { APICommand } from './index.js';
|
|
12
10
|
import getString from './ui/get-string.js';
|
|
@@ -23,11 +21,9 @@ const commands = [
|
|
|
23
21
|
Create,
|
|
24
22
|
Get,
|
|
25
23
|
Info,
|
|
26
|
-
Download,
|
|
27
24
|
Mcp,
|
|
28
25
|
Override,
|
|
29
26
|
List,
|
|
30
|
-
Serve,
|
|
31
27
|
].map((command) => {
|
|
32
28
|
const id = convertToKebabCase(command.name);
|
|
33
29
|
return {
|
package/dist/ui/get-value.js
CHANGED
|
@@ -7,7 +7,10 @@ const getValue = async ({ allowBlank = true, desiredValue, environment, flags, k
|
|
|
7
7
|
return failure(`No value provided for ${key}`);
|
|
8
8
|
}
|
|
9
9
|
if (!key) {
|
|
10
|
-
|
|
10
|
+
if (desiredValue !== undefined) {
|
|
11
|
+
return success(desiredValue);
|
|
12
|
+
}
|
|
13
|
+
const value = await promptForValue({ allowBlank, message });
|
|
11
14
|
if (value === undefined || value === null) {
|
|
12
15
|
return noop();
|
|
13
16
|
}
|
package/dist/verify/validate.js
CHANGED
|
@@ -387,12 +387,22 @@ export function validateWorkspace(workspaceDir) {
|
|
|
387
387
|
}
|
|
388
388
|
segmentKeys.add(config.key);
|
|
389
389
|
}
|
|
390
|
-
if (config.type === "log_level"
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
390
|
+
if (config.type === "log_level") {
|
|
391
|
+
if (config.valueType !== "log_level") {
|
|
392
|
+
issues.push({
|
|
393
|
+
file: relPath,
|
|
394
|
+
message: `Log level must have valueType "log_level", got "${config.valueType}"`,
|
|
395
|
+
severity: "error",
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
if (!config.key.startsWith("log-level.")) {
|
|
399
|
+
issues.push({
|
|
400
|
+
file: relPath,
|
|
401
|
+
message: `Log level key "${config.key}" must start with "log-level."`,
|
|
402
|
+
severity: "error",
|
|
403
|
+
suggestion: `Rename to "log-level.${config.key}" (and rename the file to "log-level.${config.key}.json")`,
|
|
404
|
+
});
|
|
405
|
+
}
|
|
396
406
|
}
|
|
397
407
|
// Validate environment IDs are slugs, not UUIDs
|
|
398
408
|
validateEnvironmentIds(config.environments, relPath, issues);
|
|
@@ -661,8 +671,18 @@ export function validateFileMap(files) {
|
|
|
661
671
|
}
|
|
662
672
|
segmentKeys.add(config.key);
|
|
663
673
|
}
|
|
664
|
-
if (config.type === "log_level"
|
|
665
|
-
|
|
674
|
+
if (config.type === "log_level") {
|
|
675
|
+
if (config.valueType !== "log_level") {
|
|
676
|
+
issues.push({ file: relPath, message: `Log level must have valueType "log_level", got "${config.valueType}"`, severity: "error" });
|
|
677
|
+
}
|
|
678
|
+
if (!config.key.startsWith("log-level.")) {
|
|
679
|
+
issues.push({
|
|
680
|
+
file: relPath,
|
|
681
|
+
message: `Log level key "${config.key}" must start with "log-level."`,
|
|
682
|
+
severity: "error",
|
|
683
|
+
suggestion: `Rename to "log-level.${config.key}" (and rename the file to "log-level.${config.key}.json")`,
|
|
684
|
+
});
|
|
685
|
+
}
|
|
666
686
|
}
|
|
667
687
|
validateEnvironmentIds(config.environments, relPath, issues);
|
|
668
688
|
validateRules(config.default.rules, relPath, "default", config.valueType, issues, config.variants);
|