@cxtms/cx-schema 1.7.12 → 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/.claude/skills/cx-core/SKILL.md +4 -0
- package/.claude/skills/cx-core/ref-graphql-query.md +320 -0
- package/dist/cli.js +190 -1
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
|
@@ -12,6 +12,10 @@ Shared domain reference for CargoXplorer entities. Used by `cx-workflow` and `cx
|
|
|
12
12
|
|
|
13
13
|
For CLI authentication, PAT tokens, org management, and publishing: see [ref-cli-auth.md](ref-cli-auth.md)
|
|
14
14
|
|
|
15
|
+
## GraphQL Querying & Audit History
|
|
16
|
+
|
|
17
|
+
For running GraphQL queries via CLI, filter syntax (Lucene), pagination, audit change history, and field discovery: see [ref-graphql-query.md](ref-graphql-query.md)
|
|
18
|
+
|
|
15
19
|
## Feature File Layout
|
|
16
20
|
|
|
17
21
|
All modules and workflows are organized under feature directories:
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
# GraphQL Query Reference
|
|
2
|
+
|
|
3
|
+
## CLI Query Command
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npx cxtms query '<graphql-query>' # Inline query
|
|
7
|
+
npx cxtms query my-query.graphql # From file
|
|
8
|
+
npx cxtms query '<query>' --vars '{"key":"v"}' # With variables
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Requires active login (`npx cxtms login`). Uses the active organization.
|
|
12
|
+
|
|
13
|
+
## Query Arguments
|
|
14
|
+
|
|
15
|
+
All root entity queries follow this pattern:
|
|
16
|
+
|
|
17
|
+
```graphql
|
|
18
|
+
orders(
|
|
19
|
+
organizationId: Int! # Required — active org ID
|
|
20
|
+
filter: String # Lucene query syntax (see below)
|
|
21
|
+
search: String # Full-text search across key fields
|
|
22
|
+
orderBy: String # Comma-separated sort fields
|
|
23
|
+
take: Int # Page size (alias: limit)
|
|
24
|
+
skip: Int # Offset (alias: offset)
|
|
25
|
+
)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Entity-specific extras:
|
|
29
|
+
- `orders` — `includeDraft: Boolean` (default false)
|
|
30
|
+
|
|
31
|
+
Available root queries: `orders`, `contacts`, `commodities`, `accountingTransactions`, `jobs`, and others.
|
|
32
|
+
|
|
33
|
+
## Filter Syntax (Lucene Query)
|
|
34
|
+
|
|
35
|
+
Filters use **Lucene Query syntax** (not OData, not NCalc).
|
|
36
|
+
|
|
37
|
+
### Basic field matching
|
|
38
|
+
```
|
|
39
|
+
filter: "orderId:196596"
|
|
40
|
+
filter: "orderType:ParcelShipment"
|
|
41
|
+
filter: "status:Active"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Wildcards
|
|
45
|
+
```
|
|
46
|
+
filter: "name:*pending*" # Contains
|
|
47
|
+
filter: "code:ABC*" # Starts with
|
|
48
|
+
filter: "status:*Active" # Ends with
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Logical operators
|
|
52
|
+
```
|
|
53
|
+
filter: "countryCode:US AND name:Test"
|
|
54
|
+
filter: "status:Active OR status:Pending"
|
|
55
|
+
filter: "NOT customValues.po:123"
|
|
56
|
+
filter: "orderType:ParcelShipment AND (status:Active OR status:Pending)"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Nested paths (dot notation)
|
|
60
|
+
```
|
|
61
|
+
filter: "orderEntities.entityType:Consignee"
|
|
62
|
+
filter: "orderEntities.contactId:7128"
|
|
63
|
+
filter: "jobs.orders.orderNumber:16*"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Range queries
|
|
67
|
+
```
|
|
68
|
+
filter: "lastModified:[\"2026-01-01\" TO \"2026-03-15\"]"
|
|
69
|
+
filter: "lastModified:[\"2026-01-01\" TO *]" # >= date
|
|
70
|
+
filter: "amount:[100 TO 500]"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### NULL checks
|
|
74
|
+
```
|
|
75
|
+
filter: "customValues.po:NULL"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### CustomValues (JSONB fields)
|
|
79
|
+
```
|
|
80
|
+
filter: "customValues.fieldName:value"
|
|
81
|
+
filter: "customValues.fieldName:\"exact match\""
|
|
82
|
+
filter: "customValues.fieldName:NULL"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Filtered collections (bracket notation)
|
|
86
|
+
```
|
|
87
|
+
filter: "children[category:CatA].name:test"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## OrderBy Syntax
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
orderBy: "orderNumber" # Ascending
|
|
94
|
+
orderBy: "-orderNumber" # Descending
|
|
95
|
+
orderBy: "-created,orderNumber" # Multi-field
|
|
96
|
+
orderBy: "customValues.fieldName" # Custom field sort
|
|
97
|
+
orderBy: "orderNumber~ToInt32" # Type conversion during sort
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Pagination
|
|
101
|
+
|
|
102
|
+
```graphql
|
|
103
|
+
{
|
|
104
|
+
orders(organizationId: 1, take: 50, skip: 0) {
|
|
105
|
+
items { orderId orderNumber }
|
|
106
|
+
totalCount
|
|
107
|
+
pageInfo { hasNextPage hasPreviousPage }
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Audit Change History
|
|
113
|
+
|
|
114
|
+
### Entity-level: `changeHistory` computed field
|
|
115
|
+
|
|
116
|
+
Available on: **Order**, **Contact**, **Commodity**, **AccountingTransaction**
|
|
117
|
+
|
|
118
|
+
```graphql
|
|
119
|
+
{
|
|
120
|
+
orders(organizationId: 1, filter: "orderId:196596", take: 1) {
|
|
121
|
+
items {
|
|
122
|
+
orderId
|
|
123
|
+
changeHistory(maxResults: 20) {
|
|
124
|
+
entityName
|
|
125
|
+
hasMoreRecords
|
|
126
|
+
continuationToken
|
|
127
|
+
changes {
|
|
128
|
+
state # "Added" | "Modified" | "Deleted"
|
|
129
|
+
userId
|
|
130
|
+
timestamp
|
|
131
|
+
user {
|
|
132
|
+
fullName
|
|
133
|
+
email
|
|
134
|
+
}
|
|
135
|
+
changedFields {
|
|
136
|
+
fieldName
|
|
137
|
+
originalValue
|
|
138
|
+
currentValue
|
|
139
|
+
fieldType
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Arguments: `startDate: DateTime`, `endDate: DateTime`, `maxResults: Int` (default 10)
|
|
149
|
+
|
|
150
|
+
### Root-level: `auditChanges` query
|
|
151
|
+
|
|
152
|
+
Query audit changes directly without fetching the entity first:
|
|
153
|
+
|
|
154
|
+
```graphql
|
|
155
|
+
{
|
|
156
|
+
auditChanges(
|
|
157
|
+
organizationId: 1
|
|
158
|
+
filter: "entityName:Order AND primaryKey:196596"
|
|
159
|
+
take: 20
|
|
160
|
+
) {
|
|
161
|
+
items {
|
|
162
|
+
state
|
|
163
|
+
userId
|
|
164
|
+
timestamp
|
|
165
|
+
user { fullName email }
|
|
166
|
+
changedFields {
|
|
167
|
+
fieldName
|
|
168
|
+
originalValue
|
|
169
|
+
currentValue
|
|
170
|
+
fieldType
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Arguments: `organizationId: Int!`, `filter: String`, `search: String`, `take: Int`, `skip: Int`, `orderBy: String`
|
|
178
|
+
|
|
179
|
+
Filter fields: `entityName`, `primaryKey`, `userId`, `state`
|
|
180
|
+
|
|
181
|
+
### Root-level: `auditChangeSummaries` query
|
|
182
|
+
|
|
183
|
+
High-level summary of changes (grouped by change event):
|
|
184
|
+
|
|
185
|
+
```graphql
|
|
186
|
+
{
|
|
187
|
+
auditChangeSummaries(
|
|
188
|
+
organizationId: 1
|
|
189
|
+
startDate: "2026-03-01T00:00:00Z"
|
|
190
|
+
endDate: "2026-03-15T23:59:59Z"
|
|
191
|
+
maxResults: 50
|
|
192
|
+
) {
|
|
193
|
+
items {
|
|
194
|
+
changeId
|
|
195
|
+
userId
|
|
196
|
+
timestamp
|
|
197
|
+
changePaths
|
|
198
|
+
organizationId
|
|
199
|
+
}
|
|
200
|
+
continuationToken
|
|
201
|
+
hasMoreRecords
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Root-level: `auditChange` — single change detail
|
|
207
|
+
|
|
208
|
+
```graphql
|
|
209
|
+
{
|
|
210
|
+
auditChange(filePath: "<s3-file-path>") {
|
|
211
|
+
entityName
|
|
212
|
+
state
|
|
213
|
+
primaryKey
|
|
214
|
+
userId
|
|
215
|
+
timestamp
|
|
216
|
+
originalValues
|
|
217
|
+
currentValues
|
|
218
|
+
fields {
|
|
219
|
+
fieldName
|
|
220
|
+
originalValue
|
|
221
|
+
currentValue
|
|
222
|
+
fieldType
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## GraphQL Type Reference
|
|
229
|
+
|
|
230
|
+
### EntityAuditHistoryLightResult
|
|
231
|
+
| Field | Type |
|
|
232
|
+
|-------|------|
|
|
233
|
+
| `entityName` | `String` |
|
|
234
|
+
| `primaryKey` | `String` |
|
|
235
|
+
| `organizationId` | `Int` |
|
|
236
|
+
| `changes` | `[AuditChangeEntry!]!` |
|
|
237
|
+
| `continuationToken` | `String` |
|
|
238
|
+
| `hasMoreRecords` | `Boolean!` |
|
|
239
|
+
|
|
240
|
+
### AuditChangeEntry
|
|
241
|
+
| Field | Type | Notes |
|
|
242
|
+
|-------|------|-------|
|
|
243
|
+
| `state` | `String` | "Added", "Modified", "Deleted" |
|
|
244
|
+
| `userId` | `String` | |
|
|
245
|
+
| `timestamp` | `DateTime!` | |
|
|
246
|
+
| `user` | `AuditUser` | Lazy-loaded resolver |
|
|
247
|
+
| `changedFields` | `[AuditChangeField!]!` | Lazy-loaded resolver |
|
|
248
|
+
|
|
249
|
+
### AuditChangeField
|
|
250
|
+
| Field | Type |
|
|
251
|
+
|-------|------|
|
|
252
|
+
| `fieldName` | `String!` |
|
|
253
|
+
| `originalValue` | `Any` |
|
|
254
|
+
| `currentValue` | `Any` |
|
|
255
|
+
| `fieldType` | `String!` |
|
|
256
|
+
|
|
257
|
+
### AuditUser
|
|
258
|
+
| Field | Type |
|
|
259
|
+
|-------|------|
|
|
260
|
+
| `id` | `String` |
|
|
261
|
+
| `firstName` | `String` |
|
|
262
|
+
| `lastName` | `String` |
|
|
263
|
+
| `fullName` | `String` |
|
|
264
|
+
| `userName` | `String` |
|
|
265
|
+
| `email` | `String` |
|
|
266
|
+
|
|
267
|
+
## Discovering Fields
|
|
268
|
+
|
|
269
|
+
**Always discover field names before building a query.** Do not guess field names — use the tools below.
|
|
270
|
+
|
|
271
|
+
### CLI: `cxtms gql` — schema exploration commands
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
# List all query root fields (what you can query)
|
|
275
|
+
npx cxtms gql queries
|
|
276
|
+
npx cxtms gql queries --filter order
|
|
277
|
+
|
|
278
|
+
# List all mutation root fields
|
|
279
|
+
npx cxtms gql mutations
|
|
280
|
+
npx cxtms gql mutations --filter order
|
|
281
|
+
|
|
282
|
+
# List all types (filter by name)
|
|
283
|
+
npx cxtms gql types --filter audit
|
|
284
|
+
npx cxtms gql types --filter order
|
|
285
|
+
|
|
286
|
+
# Inspect a specific type — shows fields, arguments, input fields, enum values
|
|
287
|
+
npx cxtms gql type OrderGqlDto
|
|
288
|
+
npx cxtms gql type AuditChangeEntry
|
|
289
|
+
npx cxtms gql type EntityAuditHistoryLightResult
|
|
290
|
+
npx cxtms gql type CreateOrderInput
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### TMS MCP: `graphql_schema` / `graphql_type` — equivalent MCP tools
|
|
294
|
+
|
|
295
|
+
When TMS MCP is available, the same discovery is available via MCP tools:
|
|
296
|
+
|
|
297
|
+
```
|
|
298
|
+
graphql_schema(section: "queries", filter: "order")
|
|
299
|
+
graphql_schema(section: "types", filter: "audit")
|
|
300
|
+
graphql_type(typeName: "OrderGqlDto")
|
|
301
|
+
graphql_execute(query: "{ orders(organizationId: 1, take: 1) { items { orderId } } }")
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### Workflow: discover → query
|
|
305
|
+
|
|
306
|
+
1. **Find the type** — `cxtms gql types --filter order` to find type names
|
|
307
|
+
2. **Inspect the type** — `cxtms gql type OrderGqlDto` to see all fields and their types
|
|
308
|
+
3. **Check query args** — `cxtms gql queries --filter order` to see arguments
|
|
309
|
+
4. **Build and run** — `cxtms query '<graphql-query>'`
|
|
310
|
+
|
|
311
|
+
### Fallback: error-driven discovery
|
|
312
|
+
|
|
313
|
+
GraphQL error messages reveal valid field/type names:
|
|
314
|
+
- "The field `foo` does not exist on the type `BarType`" — tells you the type name
|
|
315
|
+
- "The argument `bar` does not exist" — tells you valid argument patterns
|
|
316
|
+
|
|
317
|
+
### Other sources
|
|
318
|
+
|
|
319
|
+
- `npx cxtms schema <name>` — shows workflow/module JSON schema fields (not GraphQL)
|
|
320
|
+
- Entity reference files (`ref-entity-*.md`) — document common fields, computed properties, and enums
|
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)
|
|
@@ -3188,6 +3203,169 @@ async function runQuery(queryArg, variables) {
|
|
|
3188
3203
|
console.log(JSON.stringify(data, null, 2));
|
|
3189
3204
|
}
|
|
3190
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
|
+
// ============================================================================
|
|
3191
3369
|
// Extract Command
|
|
3192
3370
|
// ============================================================================
|
|
3193
3371
|
function runExtract(sourceFile, componentName, targetFile, copy) {
|
|
@@ -3398,7 +3576,7 @@ function parseArgs(args) {
|
|
|
3398
3576
|
reportFormat: 'json'
|
|
3399
3577
|
};
|
|
3400
3578
|
// Check for commands
|
|
3401
|
-
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'];
|
|
3402
3580
|
if (args.length > 0 && commands.includes(args[0])) {
|
|
3403
3581
|
command = args[0];
|
|
3404
3582
|
args = args.slice(1);
|
|
@@ -3509,6 +3687,9 @@ function parseArgs(args) {
|
|
|
3509
3687
|
options.file = [];
|
|
3510
3688
|
options.file.push(args[++i]);
|
|
3511
3689
|
}
|
|
3690
|
+
else if (arg === '--filter') {
|
|
3691
|
+
options.filter = args[++i];
|
|
3692
|
+
}
|
|
3512
3693
|
else if (arg === '--force') {
|
|
3513
3694
|
options.force = true;
|
|
3514
3695
|
}
|
|
@@ -4435,6 +4616,14 @@ async function main() {
|
|
|
4435
4616
|
}
|
|
4436
4617
|
process.exit(0);
|
|
4437
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
|
+
}
|
|
4438
4627
|
// Handle query command (no schemas needed)
|
|
4439
4628
|
if (command === 'query') {
|
|
4440
4629
|
await runQuery(files[0], options.vars);
|