@cxtms/cx-schema 1.7.11 → 1.7.13
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/dist/cli.js
CHANGED
|
@@ -119,6 +119,7 @@ ${chalk_1.default.bold.yellow('COMMANDS:')}
|
|
|
119
119
|
${chalk_1.default.green('publish')} Publish all modules and workflows to a CX server
|
|
120
120
|
${chalk_1.default.green('app')} Manage app manifests (install/upgrade from git, publish to git, list)
|
|
121
121
|
${chalk_1.default.green('query')} Run a GraphQL query against the CX server
|
|
122
|
+
${chalk_1.default.green('gql')} Explore GraphQL schema (types, queries, mutations)
|
|
122
123
|
${chalk_1.default.green('schema')} Show JSON schema for a component or task
|
|
123
124
|
${chalk_1.default.green('example')} Show example YAML for a component or task
|
|
124
125
|
${chalk_1.default.green('list')} List available schemas (modules, workflows, tasks)
|
|
@@ -336,6 +337,20 @@ ${chalk_1.default.bold.yellow('QUERY COMMANDS:')}
|
|
|
336
337
|
${chalk_1.default.gray('# Pass variables as JSON')}
|
|
337
338
|
${chalk_1.default.cyan(`${PROGRAM_NAME} query my-query.graphql --vars '{"id": 42}'`)}
|
|
338
339
|
|
|
340
|
+
${chalk_1.default.bold.yellow('GRAPHQL SCHEMA EXPLORATION:')}
|
|
341
|
+
${chalk_1.default.gray('# List all queries, mutations, and types')}
|
|
342
|
+
${chalk_1.default.cyan(`${PROGRAM_NAME} gql queries`)}
|
|
343
|
+
${chalk_1.default.cyan(`${PROGRAM_NAME} gql mutations`)}
|
|
344
|
+
${chalk_1.default.cyan(`${PROGRAM_NAME} gql types`)}
|
|
345
|
+
|
|
346
|
+
${chalk_1.default.gray('# Filter by name')}
|
|
347
|
+
${chalk_1.default.cyan(`${PROGRAM_NAME} gql types --filter audit`)}
|
|
348
|
+
${chalk_1.default.cyan(`${PROGRAM_NAME} gql queries --filter order`)}
|
|
349
|
+
|
|
350
|
+
${chalk_1.default.gray('# Inspect a specific type')}
|
|
351
|
+
${chalk_1.default.cyan(`${PROGRAM_NAME} gql type OrderGqlDto`)}
|
|
352
|
+
${chalk_1.default.cyan(`${PROGRAM_NAME} gql type AuditChangeEntry`)}
|
|
353
|
+
|
|
339
354
|
${chalk_1.default.bold.yellow('VALIDATION TYPES:')}
|
|
340
355
|
${chalk_1.default.bold('module')} - CargoXplorer UI module definitions (components, routes, entities)
|
|
341
356
|
${chalk_1.default.bold('workflow')} - CargoXplorer workflow definitions (activities, tasks, triggers)
|
|
@@ -2282,10 +2297,64 @@ async function runWorkflowUndeploy(uuid, orgOverride) {
|
|
|
2282
2297
|
});
|
|
2283
2298
|
console.log(chalk_1.default.green(` ✓ Deleted: ${uuid}\n`));
|
|
2284
2299
|
}
|
|
2285
|
-
async function
|
|
2300
|
+
async function uploadFileToServer(domain, token, orgId, localPath) {
|
|
2301
|
+
const fileName = path.basename(localPath);
|
|
2302
|
+
const ext = path.extname(localPath).toLowerCase();
|
|
2303
|
+
const contentTypeMap = {
|
|
2304
|
+
'.csv': 'text/csv', '.json': 'application/json', '.xml': 'application/xml',
|
|
2305
|
+
'.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
2306
|
+
'.xls': 'application/vnd.ms-excel', '.pdf': 'application/pdf',
|
|
2307
|
+
'.txt': 'text/plain', '.zip': 'application/zip',
|
|
2308
|
+
};
|
|
2309
|
+
const contentType = contentTypeMap[ext] || 'application/octet-stream';
|
|
2310
|
+
// Step 1: Get presigned upload URL
|
|
2311
|
+
const data = await graphqlRequest(domain, token, `
|
|
2312
|
+
query ($organizationId: Int!, $fileName: String!, $contentType: String!) {
|
|
2313
|
+
uploadUrl(organizationId: $organizationId, fileName: $fileName, contentType: $contentType) {
|
|
2314
|
+
presignedUrl
|
|
2315
|
+
fileUrl
|
|
2316
|
+
}
|
|
2317
|
+
}
|
|
2318
|
+
`, { organizationId: orgId, fileName, contentType });
|
|
2319
|
+
const presignedUrl = data?.uploadUrl?.presignedUrl;
|
|
2320
|
+
const fileUrl = data?.uploadUrl?.fileUrl;
|
|
2321
|
+
if (!presignedUrl || !fileUrl) {
|
|
2322
|
+
throw new Error('Failed to get upload URL from server');
|
|
2323
|
+
}
|
|
2324
|
+
// Step 2: PUT file content to presigned URL
|
|
2325
|
+
const fileContent = fs.readFileSync(localPath);
|
|
2326
|
+
const url = new URL(presignedUrl);
|
|
2327
|
+
const httpModule = url.protocol === 'https:' ? https : http;
|
|
2328
|
+
await new Promise((resolve, reject) => {
|
|
2329
|
+
const req = httpModule.request(url, {
|
|
2330
|
+
method: 'PUT',
|
|
2331
|
+
headers: {
|
|
2332
|
+
'Content-Type': contentType,
|
|
2333
|
+
'Content-Length': fileContent.length,
|
|
2334
|
+
'x-ms-blob-type': 'BlockBlob',
|
|
2335
|
+
},
|
|
2336
|
+
}, (res) => {
|
|
2337
|
+
let body = '';
|
|
2338
|
+
res.on('data', (chunk) => body += chunk);
|
|
2339
|
+
res.on('end', () => {
|
|
2340
|
+
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
|
|
2341
|
+
resolve();
|
|
2342
|
+
}
|
|
2343
|
+
else {
|
|
2344
|
+
reject(new Error(`File upload failed (${res.statusCode}): ${body}`));
|
|
2345
|
+
}
|
|
2346
|
+
});
|
|
2347
|
+
});
|
|
2348
|
+
req.on('error', reject);
|
|
2349
|
+
req.write(fileContent);
|
|
2350
|
+
req.end();
|
|
2351
|
+
});
|
|
2352
|
+
return fileUrl;
|
|
2353
|
+
}
|
|
2354
|
+
async function runWorkflowExecute(workflowIdOrFile, orgOverride, variables, fileArgs) {
|
|
2286
2355
|
if (!workflowIdOrFile) {
|
|
2287
2356
|
console.error(chalk_1.default.red('Error: Workflow ID or YAML file required'));
|
|
2288
|
-
console.error(chalk_1.default.gray(`Usage: ${PROGRAM_NAME} workflow execute <workflowId|file.yaml> [--org <id>] [--vars '{"key":"value"}']`));
|
|
2357
|
+
console.error(chalk_1.default.gray(`Usage: ${PROGRAM_NAME} workflow execute <workflowId|file.yaml> [--org <id>] [--vars '{"key":"value"}'] [--file varName=path]`));
|
|
2289
2358
|
process.exit(2);
|
|
2290
2359
|
}
|
|
2291
2360
|
const session = resolveSession();
|
|
@@ -2318,6 +2387,28 @@ async function runWorkflowExecute(workflowIdOrFile, orgOverride, variables) {
|
|
|
2318
2387
|
process.exit(2);
|
|
2319
2388
|
}
|
|
2320
2389
|
}
|
|
2390
|
+
// Process --file args: upload files and set URLs as variables
|
|
2391
|
+
if (fileArgs && fileArgs.length > 0) {
|
|
2392
|
+
if (!vars)
|
|
2393
|
+
vars = {};
|
|
2394
|
+
for (const fileArg of fileArgs) {
|
|
2395
|
+
const eqIdx = fileArg.indexOf('=');
|
|
2396
|
+
if (eqIdx < 1) {
|
|
2397
|
+
console.error(chalk_1.default.red(`Error: --file must be in format varName=path (got: ${fileArg})`));
|
|
2398
|
+
process.exit(2);
|
|
2399
|
+
}
|
|
2400
|
+
const varName = fileArg.substring(0, eqIdx);
|
|
2401
|
+
const filePath = fileArg.substring(eqIdx + 1);
|
|
2402
|
+
if (!fs.existsSync(filePath)) {
|
|
2403
|
+
console.error(chalk_1.default.red(`Error: File not found: ${filePath}`));
|
|
2404
|
+
process.exit(2);
|
|
2405
|
+
}
|
|
2406
|
+
console.log(chalk_1.default.gray(` Uploading ${path.basename(filePath)}...`));
|
|
2407
|
+
const fileUrl = await uploadFileToServer(domain, token, orgId, filePath);
|
|
2408
|
+
vars[varName] = fileUrl;
|
|
2409
|
+
console.log(chalk_1.default.gray(` → ${varName} = ${fileUrl}`));
|
|
2410
|
+
}
|
|
2411
|
+
}
|
|
2321
2412
|
console.log(chalk_1.default.bold.cyan('\n Workflow Execute\n'));
|
|
2322
2413
|
console.log(chalk_1.default.gray(` Server: ${new URL(domain).hostname}`));
|
|
2323
2414
|
console.log(chalk_1.default.gray(` Org: ${orgId}`));
|
|
@@ -3112,6 +3203,169 @@ async function runQuery(queryArg, variables) {
|
|
|
3112
3203
|
console.log(JSON.stringify(data, null, 2));
|
|
3113
3204
|
}
|
|
3114
3205
|
// ============================================================================
|
|
3206
|
+
// GQL Schema Exploration Command
|
|
3207
|
+
// ============================================================================
|
|
3208
|
+
async function runGql(sub, filter) {
|
|
3209
|
+
if (!sub) {
|
|
3210
|
+
console.error(chalk_1.default.red('Error: subcommand required'));
|
|
3211
|
+
console.error(chalk_1.default.gray(`Usage: ${PROGRAM_NAME} gql <queries|mutations|types|type> [name] [--filter <text>]`));
|
|
3212
|
+
process.exit(2);
|
|
3213
|
+
}
|
|
3214
|
+
const session = resolveSession();
|
|
3215
|
+
if (sub === 'type') {
|
|
3216
|
+
if (!filter) {
|
|
3217
|
+
console.error(chalk_1.default.red('Error: type name required'));
|
|
3218
|
+
console.error(chalk_1.default.gray(`Usage: ${PROGRAM_NAME} gql type <TypeName>`));
|
|
3219
|
+
process.exit(2);
|
|
3220
|
+
}
|
|
3221
|
+
await runGqlType(session, filter);
|
|
3222
|
+
}
|
|
3223
|
+
else if (sub === 'queries') {
|
|
3224
|
+
await runGqlRootFields(session, 'queryType', filter);
|
|
3225
|
+
}
|
|
3226
|
+
else if (sub === 'mutations') {
|
|
3227
|
+
await runGqlRootFields(session, 'mutationType', filter);
|
|
3228
|
+
}
|
|
3229
|
+
else if (sub === 'types') {
|
|
3230
|
+
await runGqlTypes(session, filter);
|
|
3231
|
+
}
|
|
3232
|
+
else {
|
|
3233
|
+
console.error(chalk_1.default.red(`Unknown gql subcommand: ${sub}`));
|
|
3234
|
+
console.error(chalk_1.default.gray(`Usage: ${PROGRAM_NAME} gql <queries|mutations|types|type> [--filter <text>]`));
|
|
3235
|
+
process.exit(2);
|
|
3236
|
+
}
|
|
3237
|
+
}
|
|
3238
|
+
function formatGqlType(t) {
|
|
3239
|
+
if (!t)
|
|
3240
|
+
return 'unknown';
|
|
3241
|
+
if (t.kind === 'NON_NULL')
|
|
3242
|
+
return `${formatGqlType(t.ofType)}!`;
|
|
3243
|
+
if (t.kind === 'LIST')
|
|
3244
|
+
return `[${formatGqlType(t.ofType)}]`;
|
|
3245
|
+
return t.name || 'unknown';
|
|
3246
|
+
}
|
|
3247
|
+
async function runGqlType(session, typeName) {
|
|
3248
|
+
const query = `{
|
|
3249
|
+
__type(name: "${typeName}") {
|
|
3250
|
+
name kind description
|
|
3251
|
+
fields { name description type { name kind ofType { name kind ofType { name kind ofType { name kind } } } } args { name type { name kind ofType { name kind ofType { name kind } } } defaultValue } }
|
|
3252
|
+
inputFields { name type { name kind ofType { name kind ofType { name kind } } } defaultValue }
|
|
3253
|
+
enumValues { name description }
|
|
3254
|
+
}
|
|
3255
|
+
}`;
|
|
3256
|
+
const data = await graphqlRequest(session.domain, session.access_token, query, {});
|
|
3257
|
+
const type = data.__type;
|
|
3258
|
+
if (!type) {
|
|
3259
|
+
console.error(chalk_1.default.red(`Type "${typeName}" not found`));
|
|
3260
|
+
process.exit(1);
|
|
3261
|
+
}
|
|
3262
|
+
console.log(chalk_1.default.bold.cyan(`${type.name}`) + chalk_1.default.gray(` (${type.kind})`));
|
|
3263
|
+
if (type.description)
|
|
3264
|
+
console.log(chalk_1.default.gray(type.description));
|
|
3265
|
+
console.log('');
|
|
3266
|
+
if (type.fields && type.fields.length > 0) {
|
|
3267
|
+
console.log(chalk_1.default.bold.yellow('Fields:'));
|
|
3268
|
+
for (const f of type.fields) {
|
|
3269
|
+
const typeStr = formatGqlType(f.type);
|
|
3270
|
+
let line = ` ${chalk_1.default.green(f.name)}: ${chalk_1.default.cyan(typeStr)}`;
|
|
3271
|
+
if (f.args && f.args.length > 0) {
|
|
3272
|
+
const argsStr = f.args.map((a) => {
|
|
3273
|
+
const argType = formatGqlType(a.type);
|
|
3274
|
+
return a.defaultValue ? `${a.name}: ${argType} = ${a.defaultValue}` : `${a.name}: ${argType}`;
|
|
3275
|
+
}).join(', ');
|
|
3276
|
+
line += chalk_1.default.gray(` (${argsStr})`);
|
|
3277
|
+
}
|
|
3278
|
+
if (f.description)
|
|
3279
|
+
line += chalk_1.default.gray(` — ${f.description}`);
|
|
3280
|
+
console.log(line);
|
|
3281
|
+
}
|
|
3282
|
+
}
|
|
3283
|
+
if (type.inputFields && type.inputFields.length > 0) {
|
|
3284
|
+
console.log(chalk_1.default.bold.yellow('Input Fields:'));
|
|
3285
|
+
for (const f of type.inputFields) {
|
|
3286
|
+
const typeStr = formatGqlType(f.type);
|
|
3287
|
+
let line = ` ${chalk_1.default.green(f.name)}: ${chalk_1.default.cyan(typeStr)}`;
|
|
3288
|
+
if (f.defaultValue)
|
|
3289
|
+
line += chalk_1.default.gray(` = ${f.defaultValue}`);
|
|
3290
|
+
console.log(line);
|
|
3291
|
+
}
|
|
3292
|
+
}
|
|
3293
|
+
if (type.enumValues && type.enumValues.length > 0) {
|
|
3294
|
+
console.log(chalk_1.default.bold.yellow('Enum Values:'));
|
|
3295
|
+
for (const v of type.enumValues) {
|
|
3296
|
+
let line = ` ${chalk_1.default.green(v.name)}`;
|
|
3297
|
+
if (v.description)
|
|
3298
|
+
line += chalk_1.default.gray(` — ${v.description}`);
|
|
3299
|
+
console.log(line);
|
|
3300
|
+
}
|
|
3301
|
+
}
|
|
3302
|
+
}
|
|
3303
|
+
async function runGqlRootFields(session, rootType, filter) {
|
|
3304
|
+
const query = `{
|
|
3305
|
+
__schema {
|
|
3306
|
+
${rootType} {
|
|
3307
|
+
fields { name description args { name type { name kind ofType { name kind ofType { name kind } } } defaultValue } type { name kind ofType { name kind ofType { name kind } } } }
|
|
3308
|
+
}
|
|
3309
|
+
}
|
|
3310
|
+
}`;
|
|
3311
|
+
const data = await graphqlRequest(session.domain, session.access_token, query, {});
|
|
3312
|
+
const fields = data.__schema?.[rootType]?.fields || [];
|
|
3313
|
+
const filtered = filter
|
|
3314
|
+
? fields.filter((f) => f.name.toLowerCase().includes(filter.toLowerCase()))
|
|
3315
|
+
: fields;
|
|
3316
|
+
const label = rootType === 'queryType' ? 'Queries' : 'Mutations';
|
|
3317
|
+
console.log(chalk_1.default.bold.yellow(`${label}${filter ? ` (filter: "${filter}")` : ''}:`));
|
|
3318
|
+
console.log('');
|
|
3319
|
+
for (const f of filtered) {
|
|
3320
|
+
const returnType = formatGqlType(f.type);
|
|
3321
|
+
console.log(` ${chalk_1.default.green(f.name)}: ${chalk_1.default.cyan(returnType)}`);
|
|
3322
|
+
if (f.description)
|
|
3323
|
+
console.log(` ${chalk_1.default.gray(f.description)}`);
|
|
3324
|
+
if (f.args && f.args.length > 0) {
|
|
3325
|
+
for (const a of f.args) {
|
|
3326
|
+
const argType = formatGqlType(a.type);
|
|
3327
|
+
const def = a.defaultValue ? chalk_1.default.gray(` = ${a.defaultValue}`) : '';
|
|
3328
|
+
console.log(` ${chalk_1.default.white(a.name)}: ${chalk_1.default.cyan(argType)}${def}`);
|
|
3329
|
+
}
|
|
3330
|
+
}
|
|
3331
|
+
console.log('');
|
|
3332
|
+
}
|
|
3333
|
+
console.log(chalk_1.default.gray(`${filtered.length} ${label.toLowerCase()} found`));
|
|
3334
|
+
}
|
|
3335
|
+
async function runGqlTypes(session, filter) {
|
|
3336
|
+
const query = `{
|
|
3337
|
+
__schema {
|
|
3338
|
+
types { name kind description }
|
|
3339
|
+
}
|
|
3340
|
+
}`;
|
|
3341
|
+
const data = await graphqlRequest(session.domain, session.access_token, query, {});
|
|
3342
|
+
const types = (data.__schema?.types || [])
|
|
3343
|
+
.filter((t) => !t.name.startsWith('__'))
|
|
3344
|
+
.filter((t) => !filter || t.name.toLowerCase().includes(filter.toLowerCase()));
|
|
3345
|
+
const grouped = {};
|
|
3346
|
+
for (const t of types) {
|
|
3347
|
+
const kind = t.kind || 'OTHER';
|
|
3348
|
+
if (!grouped[kind])
|
|
3349
|
+
grouped[kind] = [];
|
|
3350
|
+
grouped[kind].push(t);
|
|
3351
|
+
}
|
|
3352
|
+
const kindOrder = ['OBJECT', 'INPUT_OBJECT', 'ENUM', 'INTERFACE', 'UNION', 'SCALAR'];
|
|
3353
|
+
for (const kind of kindOrder) {
|
|
3354
|
+
const items = grouped[kind];
|
|
3355
|
+
if (!items || items.length === 0)
|
|
3356
|
+
continue;
|
|
3357
|
+
console.log(chalk_1.default.bold.yellow(`${kind} (${items.length}):`));
|
|
3358
|
+
for (const t of items.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
3359
|
+
let line = ` ${chalk_1.default.green(t.name)}`;
|
|
3360
|
+
if (t.description)
|
|
3361
|
+
line += chalk_1.default.gray(` — ${t.description}`);
|
|
3362
|
+
console.log(line);
|
|
3363
|
+
}
|
|
3364
|
+
console.log('');
|
|
3365
|
+
}
|
|
3366
|
+
console.log(chalk_1.default.gray(`${types.length} types found${filter ? ` matching "${filter}"` : ''}`));
|
|
3367
|
+
}
|
|
3368
|
+
// ============================================================================
|
|
3115
3369
|
// Extract Command
|
|
3116
3370
|
// ============================================================================
|
|
3117
3371
|
function runExtract(sourceFile, componentName, targetFile, copy) {
|
|
@@ -3322,7 +3576,7 @@ function parseArgs(args) {
|
|
|
3322
3576
|
reportFormat: 'json'
|
|
3323
3577
|
};
|
|
3324
3578
|
// Check for commands
|
|
3325
|
-
const commands = ['validate', 'schema', 'example', 'list', 'help', 'version', 'report', 'init', 'create', 'extract', 'sync-schemas', 'install-skills', 'update', 'setup-claude', 'login', 'logout', 'pat', 'appmodule', 'orgs', 'workflow', 'publish', 'query', 'app'];
|
|
3579
|
+
const commands = ['validate', 'schema', 'example', 'list', 'help', 'version', 'report', 'init', 'create', 'extract', 'sync-schemas', 'install-skills', 'update', 'setup-claude', 'login', 'logout', 'pat', 'appmodule', 'orgs', 'workflow', 'publish', 'query', 'gql', 'app'];
|
|
3326
3580
|
if (args.length > 0 && commands.includes(args[0])) {
|
|
3327
3581
|
command = args[0];
|
|
3328
3582
|
args = args.slice(1);
|
|
@@ -3428,6 +3682,14 @@ function parseArgs(args) {
|
|
|
3428
3682
|
else if (arg === '--branch' || arg === '-b') {
|
|
3429
3683
|
options.branch = args[++i];
|
|
3430
3684
|
}
|
|
3685
|
+
else if (arg === '--file') {
|
|
3686
|
+
if (!options.file)
|
|
3687
|
+
options.file = [];
|
|
3688
|
+
options.file.push(args[++i]);
|
|
3689
|
+
}
|
|
3690
|
+
else if (arg === '--filter') {
|
|
3691
|
+
options.filter = args[++i];
|
|
3692
|
+
}
|
|
3431
3693
|
else if (arg === '--force') {
|
|
3432
3694
|
options.force = true;
|
|
3433
3695
|
}
|
|
@@ -4315,7 +4577,7 @@ async function main() {
|
|
|
4315
4577
|
await runWorkflowUndeploy(files[1], options.orgId);
|
|
4316
4578
|
}
|
|
4317
4579
|
else if (sub === 'execute') {
|
|
4318
|
-
await runWorkflowExecute(files[1], options.orgId, options.vars);
|
|
4580
|
+
await runWorkflowExecute(files[1], options.orgId, options.vars, options.file);
|
|
4319
4581
|
}
|
|
4320
4582
|
else if (sub === 'logs') {
|
|
4321
4583
|
await runWorkflowLogs(files[1], options.orgId, options.from, options.to);
|
|
@@ -4354,6 +4616,14 @@ async function main() {
|
|
|
4354
4616
|
}
|
|
4355
4617
|
process.exit(0);
|
|
4356
4618
|
}
|
|
4619
|
+
// Handle gql command (no schemas needed)
|
|
4620
|
+
if (command === 'gql') {
|
|
4621
|
+
const sub = files[0];
|
|
4622
|
+
// For 'gql type <name>', the type name is in files[1] — use it as filter
|
|
4623
|
+
const filterArg = sub === 'type' ? (files[1] || options.filter) : options.filter;
|
|
4624
|
+
await runGql(sub, filterArg);
|
|
4625
|
+
process.exit(0);
|
|
4626
|
+
}
|
|
4357
4627
|
// Handle query command (no schemas needed)
|
|
4358
4628
|
if (command === 'query') {
|
|
4359
4629
|
await runQuery(files[0], options.vars);
|