@constructive-io/cli 5.6.25 → 5.8.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/commands/codegen.js +45 -7
- package/commands/jobs.d.ts +3 -0
- package/commands/jobs.js +167 -0
- package/commands.js +2 -0
- package/esm/commands/codegen.js +47 -9
- package/esm/commands/jobs.js +165 -0
- package/esm/commands.js +2 -0
- package/esm/utils/display.js +4 -0
- package/package.json +13 -12
- package/utils/display.d.ts +1 -1
- package/utils/display.js +4 -0
package/commands/codegen.js
CHANGED
|
@@ -37,6 +37,7 @@ const fs = __importStar(require("node:fs"));
|
|
|
37
37
|
const path = __importStar(require("node:path"));
|
|
38
38
|
const graphql_server_1 = require("@constructive-io/graphql-server");
|
|
39
39
|
const generate_1 = require("@constructive-io/graphql-codegen/cli/commands/generate");
|
|
40
|
+
const init_1 = require("@constructive-io/graphql-codegen/cli/commands/init");
|
|
40
41
|
const graphql_env_1 = require("@constructive-io/graphql-env");
|
|
41
42
|
const usage = `
|
|
42
43
|
Constructive GraphQL Codegen:
|
|
@@ -46,6 +47,7 @@ Constructive GraphQL Codegen:
|
|
|
46
47
|
Options:
|
|
47
48
|
--help, -h Show this help message
|
|
48
49
|
--config <path> Path to graphql-codegen config file
|
|
50
|
+
--target <name> Target name in config file
|
|
49
51
|
--endpoint <url> GraphQL endpoint URL
|
|
50
52
|
--auth <token> Authorization header value (e.g., "Bearer 123")
|
|
51
53
|
--out <dir> Output directory (default: graphql/codegen/dist)
|
|
@@ -61,33 +63,66 @@ exports.default = async (argv, _prompter, _options) => {
|
|
|
61
63
|
process.exit(0);
|
|
62
64
|
}
|
|
63
65
|
const endpointArg = argv.endpoint || '';
|
|
64
|
-
const
|
|
66
|
+
const outputArg = argv.out;
|
|
67
|
+
const outDir = outputArg || 'codegen';
|
|
65
68
|
const auth = argv.auth || '';
|
|
66
69
|
const configPath = argv.config || '';
|
|
70
|
+
const target = argv.target || '';
|
|
67
71
|
const dryRun = !!(argv['dry-run'] || argv.dryRun);
|
|
68
72
|
const verbose = !!(argv.verbose || argv.v);
|
|
73
|
+
const resolvedConfigPath = configPath || (0, init_1.findConfigFile)() || '';
|
|
74
|
+
const hasConfigFile = Boolean(resolvedConfigPath);
|
|
75
|
+
const outputForGenerate = outputArg || !hasConfigFile ? outDir : undefined;
|
|
69
76
|
const selectedDb = argv.database || undefined;
|
|
70
|
-
const options = selectedDb
|
|
77
|
+
const options = selectedDb
|
|
78
|
+
? (0, graphql_env_1.getEnvOptions)({ pg: { database: selectedDb } })
|
|
79
|
+
: (0, graphql_env_1.getEnvOptions)();
|
|
71
80
|
const schemasArg = argv.schemas || '';
|
|
72
|
-
const runGenerate = async ({ endpoint, schema }) => {
|
|
81
|
+
const runGenerate = async ({ endpoint, schema, }) => {
|
|
73
82
|
const result = await (0, generate_1.generateCommand)({
|
|
74
83
|
config: configPath || undefined,
|
|
84
|
+
target: target || undefined,
|
|
75
85
|
endpoint,
|
|
76
86
|
schema,
|
|
77
|
-
output:
|
|
87
|
+
output: outputForGenerate,
|
|
78
88
|
authorization: auth || undefined,
|
|
79
89
|
verbose,
|
|
80
90
|
dryRun,
|
|
81
91
|
});
|
|
92
|
+
const targetResults = result.targets ?? [];
|
|
93
|
+
const hasNamedTargets = targetResults.length > 0 &&
|
|
94
|
+
(targetResults.length > 1 || targetResults[0]?.name !== 'default');
|
|
95
|
+
if (hasNamedTargets) {
|
|
96
|
+
console.log(result.message);
|
|
97
|
+
targetResults.forEach((target) => {
|
|
98
|
+
const status = target.success ? '[ok]' : 'x';
|
|
99
|
+
console.log(`\n${status} ${target.message}`);
|
|
100
|
+
if (target.tables?.length) {
|
|
101
|
+
console.log(' Tables:');
|
|
102
|
+
target.tables.forEach((table) => console.log(` - ${table}`));
|
|
103
|
+
}
|
|
104
|
+
if (target.filesWritten?.length) {
|
|
105
|
+
console.log(' Files written:');
|
|
106
|
+
target.filesWritten.forEach((file) => console.log(` - ${file}`));
|
|
107
|
+
}
|
|
108
|
+
if (!target.success && target.errors?.length) {
|
|
109
|
+
target.errors.forEach((error) => console.error(` - ${error}`));
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
if (!result.success) {
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
82
117
|
if (!result.success) {
|
|
83
118
|
console.error(result.message);
|
|
84
119
|
if (result.errors?.length)
|
|
85
|
-
result.errors.forEach(e => console.error(' -', e));
|
|
120
|
+
result.errors.forEach((e) => console.error(' -', e));
|
|
86
121
|
process.exit(1);
|
|
87
122
|
}
|
|
88
123
|
console.log(result.message);
|
|
89
124
|
if (result.filesWritten?.length) {
|
|
90
|
-
result.filesWritten.forEach(f => console.log(f));
|
|
125
|
+
result.filesWritten.forEach((f) => console.log(f));
|
|
91
126
|
}
|
|
92
127
|
};
|
|
93
128
|
if (endpointArg) {
|
|
@@ -98,7 +133,10 @@ exports.default = async (argv, _prompter, _options) => {
|
|
|
98
133
|
console.error('Error: --schemas is required when building from database. Provide a comma-separated list of schemas.');
|
|
99
134
|
process.exit(1);
|
|
100
135
|
}
|
|
101
|
-
const schemas = schemasArg
|
|
136
|
+
const schemas = schemasArg
|
|
137
|
+
.split(',')
|
|
138
|
+
.map((s) => s.trim())
|
|
139
|
+
.filter(Boolean);
|
|
102
140
|
await fs.promises.mkdir(outDir, { recursive: true });
|
|
103
141
|
const sdl = await (0, graphql_server_1.buildSchemaSDL)({
|
|
104
142
|
database: options.pg.database,
|
package/commands/jobs.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const fs_1 = require("fs");
|
|
4
|
+
const path_1 = require("path");
|
|
5
|
+
const knative_job_service_1 = require("@constructive-io/knative-job-service");
|
|
6
|
+
const utils_1 = require("@inquirerer/utils");
|
|
7
|
+
const jobsUsageText = `
|
|
8
|
+
Constructive Jobs:
|
|
9
|
+
|
|
10
|
+
cnc jobs <subcommand> [OPTIONS]
|
|
11
|
+
|
|
12
|
+
Start or manage Constructive jobs services.
|
|
13
|
+
|
|
14
|
+
Subcommands:
|
|
15
|
+
up Start jobs runtime (jobs + functions)
|
|
16
|
+
|
|
17
|
+
Options:
|
|
18
|
+
--help, -h Show this help message
|
|
19
|
+
--cwd <directory> Working directory (default: current directory)
|
|
20
|
+
--with-jobs-server Enable jobs server (default: disabled; flag-only)
|
|
21
|
+
--functions <list> Comma-separated functions, optionally with ports (e.g. "fn=8080")
|
|
22
|
+
|
|
23
|
+
Examples:
|
|
24
|
+
cnc jobs up
|
|
25
|
+
cnc jobs up --cwd /path/to/constructive
|
|
26
|
+
cnc jobs up --with-jobs-server --functions simple-email,send-email-link=8082
|
|
27
|
+
`;
|
|
28
|
+
const questions = [
|
|
29
|
+
{
|
|
30
|
+
name: 'withJobsServer',
|
|
31
|
+
alias: 'with-jobs-server',
|
|
32
|
+
message: 'Enable jobs server?',
|
|
33
|
+
type: 'confirm',
|
|
34
|
+
required: false,
|
|
35
|
+
default: false,
|
|
36
|
+
useDefault: true
|
|
37
|
+
}
|
|
38
|
+
];
|
|
39
|
+
const ensureCwd = (cwd) => {
|
|
40
|
+
const resolved = (0, path_1.resolve)(cwd);
|
|
41
|
+
if (!(0, fs_1.existsSync)(resolved)) {
|
|
42
|
+
throw new Error(`Working directory does not exist: ${resolved}`);
|
|
43
|
+
}
|
|
44
|
+
process.chdir(resolved);
|
|
45
|
+
return resolved;
|
|
46
|
+
};
|
|
47
|
+
const parseFunctionsArg = (value) => {
|
|
48
|
+
if (value === undefined)
|
|
49
|
+
return undefined;
|
|
50
|
+
const values = Array.isArray(value) ? value : [value];
|
|
51
|
+
const tokens = [];
|
|
52
|
+
for (const value of values) {
|
|
53
|
+
if (value === true) {
|
|
54
|
+
tokens.push('all');
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (value === false || value === undefined || value === null)
|
|
58
|
+
continue;
|
|
59
|
+
const raw = String(value);
|
|
60
|
+
raw
|
|
61
|
+
.split(',')
|
|
62
|
+
.map((part) => part.trim())
|
|
63
|
+
.filter(Boolean)
|
|
64
|
+
.forEach((part) => tokens.push(part));
|
|
65
|
+
}
|
|
66
|
+
if (!tokens.length) {
|
|
67
|
+
return { mode: 'list', names: [], ports: {} };
|
|
68
|
+
}
|
|
69
|
+
const hasAll = tokens.some((token) => {
|
|
70
|
+
const normalized = token.trim().toLowerCase();
|
|
71
|
+
return normalized === 'all' || normalized === '*';
|
|
72
|
+
});
|
|
73
|
+
if (hasAll) {
|
|
74
|
+
if (tokens.length > 1) {
|
|
75
|
+
throw new Error('Use "all" without other function names.');
|
|
76
|
+
}
|
|
77
|
+
return { mode: 'all', names: [], ports: {} };
|
|
78
|
+
}
|
|
79
|
+
const names = [];
|
|
80
|
+
const ports = {};
|
|
81
|
+
for (const token of tokens) {
|
|
82
|
+
const trimmed = token.trim();
|
|
83
|
+
if (!trimmed)
|
|
84
|
+
continue;
|
|
85
|
+
const separatorIndex = trimmed.search(/[:=]/);
|
|
86
|
+
if (separatorIndex === -1) {
|
|
87
|
+
names.push(trimmed);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const name = trimmed.slice(0, separatorIndex).trim();
|
|
91
|
+
const portText = trimmed.slice(separatorIndex + 1).trim();
|
|
92
|
+
if (!name) {
|
|
93
|
+
throw new Error(`Missing function name in "${token}".`);
|
|
94
|
+
}
|
|
95
|
+
if (!portText) {
|
|
96
|
+
throw new Error(`Missing port for function "${name}".`);
|
|
97
|
+
}
|
|
98
|
+
const port = Number(portText);
|
|
99
|
+
if (!Number.isFinite(port) || port <= 0) {
|
|
100
|
+
throw new Error(`Invalid port "${portText}" for function "${name}".`);
|
|
101
|
+
}
|
|
102
|
+
names.push(name);
|
|
103
|
+
ports[name] = port;
|
|
104
|
+
}
|
|
105
|
+
const uniqueNames = [];
|
|
106
|
+
const seen = new Set();
|
|
107
|
+
for (const name of names) {
|
|
108
|
+
if (seen.has(name))
|
|
109
|
+
continue;
|
|
110
|
+
seen.add(name);
|
|
111
|
+
uniqueNames.push(name);
|
|
112
|
+
}
|
|
113
|
+
return { mode: 'list', names: uniqueNames, ports };
|
|
114
|
+
};
|
|
115
|
+
const buildKnativeJobsSvcOptions = (args) => {
|
|
116
|
+
const parsedFunctions = parseFunctionsArg(args.functions);
|
|
117
|
+
let functions;
|
|
118
|
+
if (parsedFunctions) {
|
|
119
|
+
if (parsedFunctions.mode === 'all') {
|
|
120
|
+
functions = { enabled: true };
|
|
121
|
+
}
|
|
122
|
+
else if (parsedFunctions.names.length) {
|
|
123
|
+
const services = parsedFunctions.names.map((name) => ({
|
|
124
|
+
name: name,
|
|
125
|
+
port: parsedFunctions.ports[name]
|
|
126
|
+
}));
|
|
127
|
+
functions = { enabled: true, services };
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
functions = undefined;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return {
|
|
134
|
+
jobs: { enabled: args.withJobsServer === true },
|
|
135
|
+
functions
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
exports.default = async (argv, prompter, _options) => {
|
|
139
|
+
if (argv.help || argv.h) {
|
|
140
|
+
console.log(jobsUsageText);
|
|
141
|
+
process.exit(0);
|
|
142
|
+
}
|
|
143
|
+
const { first: subcommand, newArgv } = (0, utils_1.extractFirst)(argv);
|
|
144
|
+
const args = newArgv;
|
|
145
|
+
if (!subcommand) {
|
|
146
|
+
console.log(jobsUsageText);
|
|
147
|
+
await (0, utils_1.cliExitWithError)('No subcommand provided. Use "up".');
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
switch (subcommand) {
|
|
151
|
+
case 'up': {
|
|
152
|
+
try {
|
|
153
|
+
ensureCwd(args.cwd || process.cwd());
|
|
154
|
+
const promptAnswers = await prompter.prompt(args, questions);
|
|
155
|
+
const server = new knative_job_service_1.KnativeJobsSvc(buildKnativeJobsSvcOptions(promptAnswers));
|
|
156
|
+
await server.start();
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
await (0, utils_1.cliExitWithError)(`Failed to start jobs runtime: ${error.message}`);
|
|
160
|
+
}
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
default:
|
|
164
|
+
console.log(jobsUsageText);
|
|
165
|
+
await (0, utils_1.cliExitWithError)(`Unknown subcommand: ${subcommand}. Use "up".`);
|
|
166
|
+
}
|
|
167
|
+
};
|
package/commands.js
CHANGED
|
@@ -9,6 +9,7 @@ const utils_1 = require("@inquirerer/utils");
|
|
|
9
9
|
const codegen_1 = __importDefault(require("./commands/codegen"));
|
|
10
10
|
const explorer_1 = __importDefault(require("./commands/explorer"));
|
|
11
11
|
const get_graphql_schema_1 = __importDefault(require("./commands/get-graphql-schema"));
|
|
12
|
+
const jobs_1 = __importDefault(require("./commands/jobs"));
|
|
12
13
|
const server_1 = __importDefault(require("./commands/server"));
|
|
13
14
|
const utils_2 = require("./utils");
|
|
14
15
|
const createCommandMap = () => {
|
|
@@ -17,6 +18,7 @@ const createCommandMap = () => {
|
|
|
17
18
|
explorer: explorer_1.default,
|
|
18
19
|
'get-graphql-schema': get_graphql_schema_1.default,
|
|
19
20
|
codegen: codegen_1.default,
|
|
21
|
+
jobs: jobs_1.default,
|
|
20
22
|
};
|
|
21
23
|
};
|
|
22
24
|
const commands = async (argv, prompter, options) => {
|
package/esm/commands/codegen.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import * as fs from 'node:fs';
|
|
2
2
|
import * as path from 'node:path';
|
|
3
3
|
import { buildSchemaSDL } from '@constructive-io/graphql-server';
|
|
4
|
-
import { generateCommand } from '@constructive-io/graphql-codegen/cli/commands/generate';
|
|
5
|
-
import {
|
|
4
|
+
import { generateCommand, } from '@constructive-io/graphql-codegen/cli/commands/generate';
|
|
5
|
+
import { findConfigFile } from '@constructive-io/graphql-codegen/cli/commands/init';
|
|
6
|
+
import { getEnvOptions, } from '@constructive-io/graphql-env';
|
|
6
7
|
const usage = `
|
|
7
8
|
Constructive GraphQL Codegen:
|
|
8
9
|
|
|
@@ -11,6 +12,7 @@ Constructive GraphQL Codegen:
|
|
|
11
12
|
Options:
|
|
12
13
|
--help, -h Show this help message
|
|
13
14
|
--config <path> Path to graphql-codegen config file
|
|
15
|
+
--target <name> Target name in config file
|
|
14
16
|
--endpoint <url> GraphQL endpoint URL
|
|
15
17
|
--auth <token> Authorization header value (e.g., "Bearer 123")
|
|
16
18
|
--out <dir> Output directory (default: graphql/codegen/dist)
|
|
@@ -26,33 +28,66 @@ export default async (argv, _prompter, _options) => {
|
|
|
26
28
|
process.exit(0);
|
|
27
29
|
}
|
|
28
30
|
const endpointArg = argv.endpoint || '';
|
|
29
|
-
const
|
|
31
|
+
const outputArg = argv.out;
|
|
32
|
+
const outDir = outputArg || 'codegen';
|
|
30
33
|
const auth = argv.auth || '';
|
|
31
34
|
const configPath = argv.config || '';
|
|
35
|
+
const target = argv.target || '';
|
|
32
36
|
const dryRun = !!(argv['dry-run'] || argv.dryRun);
|
|
33
37
|
const verbose = !!(argv.verbose || argv.v);
|
|
38
|
+
const resolvedConfigPath = configPath || findConfigFile() || '';
|
|
39
|
+
const hasConfigFile = Boolean(resolvedConfigPath);
|
|
40
|
+
const outputForGenerate = outputArg || !hasConfigFile ? outDir : undefined;
|
|
34
41
|
const selectedDb = argv.database || undefined;
|
|
35
|
-
const options = selectedDb
|
|
42
|
+
const options = selectedDb
|
|
43
|
+
? getEnvOptions({ pg: { database: selectedDb } })
|
|
44
|
+
: getEnvOptions();
|
|
36
45
|
const schemasArg = argv.schemas || '';
|
|
37
|
-
const runGenerate = async ({ endpoint, schema }) => {
|
|
46
|
+
const runGenerate = async ({ endpoint, schema, }) => {
|
|
38
47
|
const result = await generateCommand({
|
|
39
48
|
config: configPath || undefined,
|
|
49
|
+
target: target || undefined,
|
|
40
50
|
endpoint,
|
|
41
51
|
schema,
|
|
42
|
-
output:
|
|
52
|
+
output: outputForGenerate,
|
|
43
53
|
authorization: auth || undefined,
|
|
44
54
|
verbose,
|
|
45
55
|
dryRun,
|
|
46
56
|
});
|
|
57
|
+
const targetResults = result.targets ?? [];
|
|
58
|
+
const hasNamedTargets = targetResults.length > 0 &&
|
|
59
|
+
(targetResults.length > 1 || targetResults[0]?.name !== 'default');
|
|
60
|
+
if (hasNamedTargets) {
|
|
61
|
+
console.log(result.message);
|
|
62
|
+
targetResults.forEach((target) => {
|
|
63
|
+
const status = target.success ? '[ok]' : 'x';
|
|
64
|
+
console.log(`\n${status} ${target.message}`);
|
|
65
|
+
if (target.tables?.length) {
|
|
66
|
+
console.log(' Tables:');
|
|
67
|
+
target.tables.forEach((table) => console.log(` - ${table}`));
|
|
68
|
+
}
|
|
69
|
+
if (target.filesWritten?.length) {
|
|
70
|
+
console.log(' Files written:');
|
|
71
|
+
target.filesWritten.forEach((file) => console.log(` - ${file}`));
|
|
72
|
+
}
|
|
73
|
+
if (!target.success && target.errors?.length) {
|
|
74
|
+
target.errors.forEach((error) => console.error(` - ${error}`));
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
if (!result.success) {
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
47
82
|
if (!result.success) {
|
|
48
83
|
console.error(result.message);
|
|
49
84
|
if (result.errors?.length)
|
|
50
|
-
result.errors.forEach(e => console.error(' -', e));
|
|
85
|
+
result.errors.forEach((e) => console.error(' -', e));
|
|
51
86
|
process.exit(1);
|
|
52
87
|
}
|
|
53
88
|
console.log(result.message);
|
|
54
89
|
if (result.filesWritten?.length) {
|
|
55
|
-
result.filesWritten.forEach(f => console.log(f));
|
|
90
|
+
result.filesWritten.forEach((f) => console.log(f));
|
|
56
91
|
}
|
|
57
92
|
};
|
|
58
93
|
if (endpointArg) {
|
|
@@ -63,7 +98,10 @@ export default async (argv, _prompter, _options) => {
|
|
|
63
98
|
console.error('Error: --schemas is required when building from database. Provide a comma-separated list of schemas.');
|
|
64
99
|
process.exit(1);
|
|
65
100
|
}
|
|
66
|
-
const schemas = schemasArg
|
|
101
|
+
const schemas = schemasArg
|
|
102
|
+
.split(',')
|
|
103
|
+
.map((s) => s.trim())
|
|
104
|
+
.filter(Boolean);
|
|
67
105
|
await fs.promises.mkdir(outDir, { recursive: true });
|
|
68
106
|
const sdl = await buildSchemaSDL({
|
|
69
107
|
database: options.pg.database,
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import { resolve } from 'path';
|
|
3
|
+
import { KnativeJobsSvc } from '@constructive-io/knative-job-service';
|
|
4
|
+
import { cliExitWithError, extractFirst } from '@inquirerer/utils';
|
|
5
|
+
const jobsUsageText = `
|
|
6
|
+
Constructive Jobs:
|
|
7
|
+
|
|
8
|
+
cnc jobs <subcommand> [OPTIONS]
|
|
9
|
+
|
|
10
|
+
Start or manage Constructive jobs services.
|
|
11
|
+
|
|
12
|
+
Subcommands:
|
|
13
|
+
up Start jobs runtime (jobs + functions)
|
|
14
|
+
|
|
15
|
+
Options:
|
|
16
|
+
--help, -h Show this help message
|
|
17
|
+
--cwd <directory> Working directory (default: current directory)
|
|
18
|
+
--with-jobs-server Enable jobs server (default: disabled; flag-only)
|
|
19
|
+
--functions <list> Comma-separated functions, optionally with ports (e.g. "fn=8080")
|
|
20
|
+
|
|
21
|
+
Examples:
|
|
22
|
+
cnc jobs up
|
|
23
|
+
cnc jobs up --cwd /path/to/constructive
|
|
24
|
+
cnc jobs up --with-jobs-server --functions simple-email,send-email-link=8082
|
|
25
|
+
`;
|
|
26
|
+
const questions = [
|
|
27
|
+
{
|
|
28
|
+
name: 'withJobsServer',
|
|
29
|
+
alias: 'with-jobs-server',
|
|
30
|
+
message: 'Enable jobs server?',
|
|
31
|
+
type: 'confirm',
|
|
32
|
+
required: false,
|
|
33
|
+
default: false,
|
|
34
|
+
useDefault: true
|
|
35
|
+
}
|
|
36
|
+
];
|
|
37
|
+
const ensureCwd = (cwd) => {
|
|
38
|
+
const resolved = resolve(cwd);
|
|
39
|
+
if (!existsSync(resolved)) {
|
|
40
|
+
throw new Error(`Working directory does not exist: ${resolved}`);
|
|
41
|
+
}
|
|
42
|
+
process.chdir(resolved);
|
|
43
|
+
return resolved;
|
|
44
|
+
};
|
|
45
|
+
const parseFunctionsArg = (value) => {
|
|
46
|
+
if (value === undefined)
|
|
47
|
+
return undefined;
|
|
48
|
+
const values = Array.isArray(value) ? value : [value];
|
|
49
|
+
const tokens = [];
|
|
50
|
+
for (const value of values) {
|
|
51
|
+
if (value === true) {
|
|
52
|
+
tokens.push('all');
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (value === false || value === undefined || value === null)
|
|
56
|
+
continue;
|
|
57
|
+
const raw = String(value);
|
|
58
|
+
raw
|
|
59
|
+
.split(',')
|
|
60
|
+
.map((part) => part.trim())
|
|
61
|
+
.filter(Boolean)
|
|
62
|
+
.forEach((part) => tokens.push(part));
|
|
63
|
+
}
|
|
64
|
+
if (!tokens.length) {
|
|
65
|
+
return { mode: 'list', names: [], ports: {} };
|
|
66
|
+
}
|
|
67
|
+
const hasAll = tokens.some((token) => {
|
|
68
|
+
const normalized = token.trim().toLowerCase();
|
|
69
|
+
return normalized === 'all' || normalized === '*';
|
|
70
|
+
});
|
|
71
|
+
if (hasAll) {
|
|
72
|
+
if (tokens.length > 1) {
|
|
73
|
+
throw new Error('Use "all" without other function names.');
|
|
74
|
+
}
|
|
75
|
+
return { mode: 'all', names: [], ports: {} };
|
|
76
|
+
}
|
|
77
|
+
const names = [];
|
|
78
|
+
const ports = {};
|
|
79
|
+
for (const token of tokens) {
|
|
80
|
+
const trimmed = token.trim();
|
|
81
|
+
if (!trimmed)
|
|
82
|
+
continue;
|
|
83
|
+
const separatorIndex = trimmed.search(/[:=]/);
|
|
84
|
+
if (separatorIndex === -1) {
|
|
85
|
+
names.push(trimmed);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const name = trimmed.slice(0, separatorIndex).trim();
|
|
89
|
+
const portText = trimmed.slice(separatorIndex + 1).trim();
|
|
90
|
+
if (!name) {
|
|
91
|
+
throw new Error(`Missing function name in "${token}".`);
|
|
92
|
+
}
|
|
93
|
+
if (!portText) {
|
|
94
|
+
throw new Error(`Missing port for function "${name}".`);
|
|
95
|
+
}
|
|
96
|
+
const port = Number(portText);
|
|
97
|
+
if (!Number.isFinite(port) || port <= 0) {
|
|
98
|
+
throw new Error(`Invalid port "${portText}" for function "${name}".`);
|
|
99
|
+
}
|
|
100
|
+
names.push(name);
|
|
101
|
+
ports[name] = port;
|
|
102
|
+
}
|
|
103
|
+
const uniqueNames = [];
|
|
104
|
+
const seen = new Set();
|
|
105
|
+
for (const name of names) {
|
|
106
|
+
if (seen.has(name))
|
|
107
|
+
continue;
|
|
108
|
+
seen.add(name);
|
|
109
|
+
uniqueNames.push(name);
|
|
110
|
+
}
|
|
111
|
+
return { mode: 'list', names: uniqueNames, ports };
|
|
112
|
+
};
|
|
113
|
+
const buildKnativeJobsSvcOptions = (args) => {
|
|
114
|
+
const parsedFunctions = parseFunctionsArg(args.functions);
|
|
115
|
+
let functions;
|
|
116
|
+
if (parsedFunctions) {
|
|
117
|
+
if (parsedFunctions.mode === 'all') {
|
|
118
|
+
functions = { enabled: true };
|
|
119
|
+
}
|
|
120
|
+
else if (parsedFunctions.names.length) {
|
|
121
|
+
const services = parsedFunctions.names.map((name) => ({
|
|
122
|
+
name: name,
|
|
123
|
+
port: parsedFunctions.ports[name]
|
|
124
|
+
}));
|
|
125
|
+
functions = { enabled: true, services };
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
functions = undefined;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
jobs: { enabled: args.withJobsServer === true },
|
|
133
|
+
functions
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
export default async (argv, prompter, _options) => {
|
|
137
|
+
if (argv.help || argv.h) {
|
|
138
|
+
console.log(jobsUsageText);
|
|
139
|
+
process.exit(0);
|
|
140
|
+
}
|
|
141
|
+
const { first: subcommand, newArgv } = extractFirst(argv);
|
|
142
|
+
const args = newArgv;
|
|
143
|
+
if (!subcommand) {
|
|
144
|
+
console.log(jobsUsageText);
|
|
145
|
+
await cliExitWithError('No subcommand provided. Use "up".');
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
switch (subcommand) {
|
|
149
|
+
case 'up': {
|
|
150
|
+
try {
|
|
151
|
+
ensureCwd(args.cwd || process.cwd());
|
|
152
|
+
const promptAnswers = await prompter.prompt(args, questions);
|
|
153
|
+
const server = new KnativeJobsSvc(buildKnativeJobsSvcOptions(promptAnswers));
|
|
154
|
+
await server.start();
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
await cliExitWithError(`Failed to start jobs runtime: ${error.message}`);
|
|
158
|
+
}
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
default:
|
|
162
|
+
console.log(jobsUsageText);
|
|
163
|
+
await cliExitWithError(`Unknown subcommand: ${subcommand}. Use "up".`);
|
|
164
|
+
}
|
|
165
|
+
};
|
package/esm/commands.js
CHANGED
|
@@ -3,6 +3,7 @@ import { cliExitWithError, checkForUpdates, extractFirst } from '@inquirerer/uti
|
|
|
3
3
|
import codegen from './commands/codegen';
|
|
4
4
|
import explorer from './commands/explorer';
|
|
5
5
|
import getGraphqlSchema from './commands/get-graphql-schema';
|
|
6
|
+
import jobs from './commands/jobs';
|
|
6
7
|
import server from './commands/server';
|
|
7
8
|
import { usageText } from './utils';
|
|
8
9
|
const createCommandMap = () => {
|
|
@@ -11,6 +12,7 @@ const createCommandMap = () => {
|
|
|
11
12
|
explorer,
|
|
12
13
|
'get-graphql-schema': getGraphqlSchema,
|
|
13
14
|
codegen,
|
|
15
|
+
jobs,
|
|
14
16
|
};
|
|
15
17
|
};
|
|
16
18
|
export const commands = async (argv, prompter, options) => {
|
package/esm/utils/display.js
CHANGED
|
@@ -12,6 +12,9 @@ export const usageText = `
|
|
|
12
12
|
codegen Generate TypeScript types and SDK from GraphQL schema
|
|
13
13
|
get-graphql-schema Fetch or build GraphQL schema SDL
|
|
14
14
|
|
|
15
|
+
Jobs:
|
|
16
|
+
jobs up Start combined server (jobs runtime)
|
|
17
|
+
|
|
15
18
|
Global Options:
|
|
16
19
|
-h, --help Display this help information
|
|
17
20
|
-v, --version Display version information
|
|
@@ -27,6 +30,7 @@ export const usageText = `
|
|
|
27
30
|
cnc explorer Launch GraphiQL explorer
|
|
28
31
|
cnc codegen --schema schema.graphql Generate types from schema
|
|
29
32
|
cnc get-graphql-schema --out schema.graphql Export schema SDL
|
|
33
|
+
cnc jobs up Start combined server (jobs runtime)
|
|
30
34
|
|
|
31
35
|
Database Operations:
|
|
32
36
|
For database migrations, packages, and deployment, use pgpm:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@constructive-io/cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.8.0",
|
|
4
4
|
"author": "Constructive <developers@constructive.io>",
|
|
5
5
|
"description": "Constructive CLI",
|
|
6
6
|
"main": "index.js",
|
|
@@ -46,22 +46,23 @@
|
|
|
46
46
|
"ts-node": "^10.9.2"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@constructive-io/graphql-codegen": "^2.
|
|
50
|
-
"@constructive-io/graphql-env": "^2.8.
|
|
51
|
-
"@constructive-io/graphql-explorer": "^2.13.
|
|
52
|
-
"@constructive-io/graphql-server": "^2.
|
|
49
|
+
"@constructive-io/graphql-codegen": "^2.26.0",
|
|
50
|
+
"@constructive-io/graphql-env": "^2.8.20",
|
|
51
|
+
"@constructive-io/graphql-explorer": "^2.13.18",
|
|
52
|
+
"@constructive-io/graphql-server": "^2.17.0",
|
|
53
|
+
"@constructive-io/knative-job-service": "^0.7.0",
|
|
53
54
|
"@inquirerer/utils": "^3.1.3",
|
|
54
|
-
"@pgpmjs/core": "^4.15.
|
|
55
|
-
"@pgpmjs/logger": "^1.3.
|
|
56
|
-
"@pgpmjs/server-utils": "^2.8.
|
|
57
|
-
"@pgpmjs/types": "^2.14.
|
|
55
|
+
"@pgpmjs/core": "^4.15.2",
|
|
56
|
+
"@pgpmjs/logger": "^1.3.8",
|
|
57
|
+
"@pgpmjs/server-utils": "^2.8.16",
|
|
58
|
+
"@pgpmjs/types": "^2.14.2",
|
|
58
59
|
"find-and-require-package-json": "^0.8.6",
|
|
59
60
|
"inquirerer": "^4.3.1",
|
|
60
61
|
"js-yaml": "^4.1.0",
|
|
61
62
|
"minimist": "^1.2.8",
|
|
62
|
-
"pg-cache": "^1.6.
|
|
63
|
+
"pg-cache": "^1.6.16",
|
|
63
64
|
"pg-env": "^1.2.5",
|
|
64
|
-
"pgpm": "^2.10.
|
|
65
|
+
"pgpm": "^2.10.16",
|
|
65
66
|
"shelljs": "^0.10.0",
|
|
66
67
|
"yanse": "^0.1.11"
|
|
67
68
|
},
|
|
@@ -76,5 +77,5 @@
|
|
|
76
77
|
"postgres",
|
|
77
78
|
"graphile"
|
|
78
79
|
],
|
|
79
|
-
"gitHead": "
|
|
80
|
+
"gitHead": "b7abf2fdaf0a827d79a80c9c0a29e5c960f227df"
|
|
80
81
|
}
|
package/utils/display.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const usageText = "\n Usage: cnc <command> [options]\n constructive <command> [options]\n\n Constructive CLI - API Server and Development Tools\n\n GraphQL Server:\n server Start a GraphQL server\n explorer Launch GraphiQL explorer interface\n\n Code Generation:\n codegen Generate TypeScript types and SDK from GraphQL schema\n get-graphql-schema Fetch or build GraphQL schema SDL\n\n Global Options:\n -h, --help Display this help information\n -v, --version Display version information\n --cwd <directory> Working directory (default: current directory)\n\n Individual Command Help:\n cnc <command> --help Display detailed help for specific command\n cnc <command> -h Display detailed help for specific command\n\n Examples:\n cnc server Start GraphQL server\n cnc server --port 8080 Start server on custom port\n cnc explorer Launch GraphiQL explorer\n cnc codegen --schema schema.graphql Generate types from schema\n cnc get-graphql-schema --out schema.graphql Export schema SDL\n\n Database Operations:\n For database migrations, packages, and deployment, use pgpm:\n https://pgpm.io\n ";
|
|
1
|
+
export declare const usageText = "\n Usage: cnc <command> [options]\n constructive <command> [options]\n\n Constructive CLI - API Server and Development Tools\n\n GraphQL Server:\n server Start a GraphQL server\n explorer Launch GraphiQL explorer interface\n\n Code Generation:\n codegen Generate TypeScript types and SDK from GraphQL schema\n get-graphql-schema Fetch or build GraphQL schema SDL\n\n Jobs:\n jobs up Start combined server (jobs runtime)\n\n Global Options:\n -h, --help Display this help information\n -v, --version Display version information\n --cwd <directory> Working directory (default: current directory)\n\n Individual Command Help:\n cnc <command> --help Display detailed help for specific command\n cnc <command> -h Display detailed help for specific command\n\n Examples:\n cnc server Start GraphQL server\n cnc server --port 8080 Start server on custom port\n cnc explorer Launch GraphiQL explorer\n cnc codegen --schema schema.graphql Generate types from schema\n cnc get-graphql-schema --out schema.graphql Export schema SDL\n cnc jobs up Start combined server (jobs runtime)\n\n Database Operations:\n For database migrations, packages, and deployment, use pgpm:\n https://pgpm.io\n ";
|
package/utils/display.js
CHANGED
|
@@ -15,6 +15,9 @@ exports.usageText = `
|
|
|
15
15
|
codegen Generate TypeScript types and SDK from GraphQL schema
|
|
16
16
|
get-graphql-schema Fetch or build GraphQL schema SDL
|
|
17
17
|
|
|
18
|
+
Jobs:
|
|
19
|
+
jobs up Start combined server (jobs runtime)
|
|
20
|
+
|
|
18
21
|
Global Options:
|
|
19
22
|
-h, --help Display this help information
|
|
20
23
|
-v, --version Display version information
|
|
@@ -30,6 +33,7 @@ exports.usageText = `
|
|
|
30
33
|
cnc explorer Launch GraphiQL explorer
|
|
31
34
|
cnc codegen --schema schema.graphql Generate types from schema
|
|
32
35
|
cnc get-graphql-schema --out schema.graphql Export schema SDL
|
|
36
|
+
cnc jobs up Start combined server (jobs runtime)
|
|
33
37
|
|
|
34
38
|
Database Operations:
|
|
35
39
|
For database migrations, packages, and deployment, use pgpm:
|