@cxtms/cx-schema 1.8.0 → 1.8.1
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 +38 -20
- package/.claude/skills/cx-core/ref-entity-accounting.md +0 -7
- package/.claude/skills/cx-core/ref-entity-commodity.md +0 -12
- package/.claude/skills/cx-core/ref-entity-contact.md +0 -10
- package/.claude/skills/cx-core/ref-entity-geography.md +1 -34
- package/.claude/skills/cx-core/ref-entity-notification.md +85 -0
- package/.claude/skills/cx-core/ref-entity-order-sub.md +7 -13
- package/.claude/skills/cx-core/ref-entity-order.md +1 -14
- package/.claude/skills/cx-core/ref-entity-rate.md +0 -8
- package/.claude/skills/cx-core/ref-entity-shared.md +20 -9
- package/.claude/skills/cx-core/ref-entity-warehouse.md +0 -5
- package/.claude/skills/cx-module/SKILL.md +28 -103
- package/.claude/skills/cx-module/ref-components-data.md +0 -7
- package/.claude/skills/cx-module/ref-components-display.md +0 -17
- package/.claude/skills/cx-module/ref-components-forms.md +2 -7
- package/.claude/skills/cx-module/ref-components-interactive.md +0 -11
- package/.claude/skills/cx-module/ref-components-layout.md +0 -11
- package/.claude/skills/cx-module/ref-components-specialized.md +0 -50
- package/.claude/skills/cx-workflow/SKILL.md +21 -130
- package/.claude/skills/cx-workflow/ref-communication.md +0 -8
- package/.claude/skills/cx-workflow/ref-entity.md +62 -43
- package/.claude/skills/cx-workflow/ref-expressions.md +272 -0
- package/.claude/skills/cx-workflow/ref-flow.md +6 -12
- package/.claude/skills/cx-workflow/ref-other.md +33 -14
- package/.claude/skills/cx-workflow/ref-utilities.md +87 -14
- package/README.md +34 -34
- package/dist/cli.js +166 -2394
- package/dist/cli.js.map +1 -1
- package/dist/types.d.ts +0 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/validator.d.ts +0 -8
- package/dist/validator.d.ts.map +1 -1
- package/dist/validator.js +2 -54
- package/dist/validator.js.map +1 -1
- package/dist/workflowValidator.d.ts +0 -4
- package/dist/workflowValidator.d.ts.map +1 -1
- package/dist/workflowValidator.js +2 -28
- package/dist/workflowValidator.js.map +1 -1
- package/package.json +2 -3
- package/schemas/actions/all.json +2 -1
- package/schemas/actions/clipboard.json +46 -0
- package/schemas/components/appComponent.json +0 -8
- package/schemas/components/module.json +2 -31
- package/schemas/components/timelineGrid.json +0 -4
- package/schemas/schemas.json +0 -12
- package/schemas/workflows/flow/entity.json +19 -0
- package/schemas/workflows/tasks/all.json +9 -0
- package/schemas/workflows/tasks/authentication.json +12 -26
- package/schemas/workflows/tasks/edi.json +93 -1
- package/schemas/workflows/tasks/httpRequest.json +4 -0
- package/schemas/workflows/tasks/order.json +45 -0
- package/schemas/workflows/tasks/resolve-timezone.json +65 -0
- package/schemas/workflows/tasks/transmission.json +1 -1
- package/schemas/workflows/tasks/unzip-file.json +68 -0
- package/schemas/workflows/variable.json +5 -1
- package/schemas/workflows/workflow.json +4 -0
- package/scripts/postinstall.js +1 -1
- package/templates/module-configuration.yaml +89 -23
- package/templates/module-form.yaml +3 -3
- package/templates/module-grid.yaml +3 -3
- package/templates/module-select.yaml +3 -3
- package/templates/module.yaml +2 -3
- package/templates/workflow-api-tracking.yaml +1 -1
- package/templates/workflow-basic.yaml +1 -1
- package/templates/workflow-document.yaml +1 -1
- package/templates/workflow-entity-trigger.yaml +1 -1
- package/templates/workflow-ftp-edi.yaml +1 -1
- package/templates/workflow-ftp-tracking.yaml +1 -1
- package/templates/workflow-mcp-tool.yaml +1 -1
- package/templates/workflow-public-api.yaml +1 -1
- package/templates/workflow-scheduled.yaml +1 -1
- package/templates/workflow-utility.yaml +1 -1
- package/templates/workflow-webhook.yaml +1 -1
- package/templates/workflow.yaml +1 -1
- package/.claude/skills/cx-core/ref-cli-auth.md +0 -120
- package/.claude/skills/cx-core/ref-graphql-query.md +0 -320
- package/.claude/skills/cx-workflow/ref-expressions-ncalc.md +0 -112
- package/.claude/skills/cx-workflow/ref-expressions-template.md +0 -149
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
# Variable References & Expressions
|
|
2
|
+
|
|
3
|
+
There are **two distinct syntaxes** for referencing variables, used in different contexts.
|
|
4
|
+
|
|
5
|
+
## Template Expressions: `{{ path }}` (in step inputs)
|
|
6
|
+
|
|
7
|
+
Used in step `inputs` values. Resolves variable paths from scoped variables.
|
|
8
|
+
|
|
9
|
+
```yaml
|
|
10
|
+
inputs:
|
|
11
|
+
orderId: "{{ inputs.orderId }}" # Simple reference
|
|
12
|
+
url: "{{ chopinConfig.baseUrl }}/api/v1" # String interpolation
|
|
13
|
+
order: "{{ Data.GetOrder.order }}" # Raw object (single {{ }})
|
|
14
|
+
name: "Order {{ Data.GetOrder.order.orderNumber }}" # String interpolation (multiple)
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
**Key behavior**: A single `{{ path }}` returns the **raw object** (preserving type). Multiple `{{ }}` in a string returns string interpolation (each resolved value is `.ToString()`).
|
|
18
|
+
|
|
19
|
+
### Type Converters (prefix in {{ }})
|
|
20
|
+
|
|
21
|
+
```yaml
|
|
22
|
+
organizationId: "{{ int organizationId }}"
|
|
23
|
+
amount: "{{ decimal totalAmount }}"
|
|
24
|
+
isActive: "{{ bool isActive }}"
|
|
25
|
+
flag: "{{ boolOrFalse someFlag }}" # null -> false
|
|
26
|
+
flagOn: "{{ boolOrTrue someFlag }}" # null -> true
|
|
27
|
+
notes: "{{ emptyIfNull notes }}" # null -> ""
|
|
28
|
+
notes: "{{ nullIfEmpty notes }}" # "" or whitespace -> null
|
|
29
|
+
config: "{{ fromJson configJsonString }}" # JSON string -> dict/array
|
|
30
|
+
payload: "{{ toJson someObject }}" # object -> JSON string
|
|
31
|
+
name: "{{ trim value }}"
|
|
32
|
+
search: "{{ luceneString query }}" # escape & quote for Lucene
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
| Converter | Returns | Null handling |
|
|
36
|
+
|-----------|---------|---------------|
|
|
37
|
+
| `string` | `string` | null. Reads `Stream` to string if value is Stream |
|
|
38
|
+
| `int` | `int` | Throws on null |
|
|
39
|
+
| `decimal` | `decimal` | Throws on null |
|
|
40
|
+
| `bool` | `bool` | Throws on null |
|
|
41
|
+
| `boolOrFalse` | `bool` | `false` if null |
|
|
42
|
+
| `boolOrTrue` | `bool` | `true` if null |
|
|
43
|
+
| `datetime` | `DateTime` | Throws on null |
|
|
44
|
+
| `emptyIfNull` | same type | `""` if null, `0` for int?, `0m` for decimal? |
|
|
45
|
+
| `nullIfEmpty` | same type | `null` if empty/whitespace string or empty collection |
|
|
46
|
+
| `luceneString` | `string` | null |
|
|
47
|
+
| `transliterate` | `string` | null (Unicode -> ASCII via Unidecode) |
|
|
48
|
+
| `transliterateUa` | `string` | null (Ukrainian-specific rules) |
|
|
49
|
+
| `fromJson` | `dict` or `array` | null. Empty string -> empty dict |
|
|
50
|
+
| `toJson` | `string` | `""` if null |
|
|
51
|
+
| `trim` | `string` | null |
|
|
52
|
+
| `toLocalTime` | `string` | null. Function-style: `{{ toLocalTime datePath 'timezoneId' 'format?' }}` |
|
|
53
|
+
|
|
54
|
+
### Value Directives (in YAML input mappings)
|
|
55
|
+
|
|
56
|
+
**`expression`** -- Evaluate NCalc expression as a value:
|
|
57
|
+
```yaml
|
|
58
|
+
amount:
|
|
59
|
+
expression: "[price] * [quantity]"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**`coalesce`** -- First non-null value from a list:
|
|
63
|
+
```yaml
|
|
64
|
+
displayName:
|
|
65
|
+
coalesce:
|
|
66
|
+
- "{{ customer.name? }}"
|
|
67
|
+
- "{{ customer.email? }}"
|
|
68
|
+
- "Unknown"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**`foreach`** (value context) -- Transform collections inline:
|
|
72
|
+
```yaml
|
|
73
|
+
commodities:
|
|
74
|
+
foreach: "sourceCommodities"
|
|
75
|
+
item: "item" # default: "item"
|
|
76
|
+
conditions: "[item.isActive] = true" # optional NCalc filter per item
|
|
77
|
+
continueOnError: false # optional, skip errors
|
|
78
|
+
mapping: # dict -> List<dict>, string -> List<object>
|
|
79
|
+
name: "{{ item.name }}"
|
|
80
|
+
quantity: "{{ item.qty }}"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**`switch`** (value context) -- Value-based switch (case-insensitive match):
|
|
84
|
+
```yaml
|
|
85
|
+
perLb:
|
|
86
|
+
switch: "{{ contact.commissionTier }}"
|
|
87
|
+
cases:
|
|
88
|
+
"tier1": "{{ rate.customValues.commission_per_lb_tier1 }}"
|
|
89
|
+
"tier2": "{{ rate.customValues.commission_per_lb_tier2 }}"
|
|
90
|
+
default: "0"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**`extends`** -- Extend/merge an existing object or array:
|
|
94
|
+
```yaml
|
|
95
|
+
orderData:
|
|
96
|
+
extends: "{{ existingOrder }}" # base object or array
|
|
97
|
+
defaultIfNull: {} # fallback if extends is null
|
|
98
|
+
mapping: # dict: merge overrides. array: append items
|
|
99
|
+
status: "Updated"
|
|
100
|
+
notes: "{{ newNotes }}"
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**`resolve`** -- Entity ID lookup by querying a GraphQL collection:
|
|
104
|
+
```yaml
|
|
105
|
+
customerId:
|
|
106
|
+
resolve:
|
|
107
|
+
entity: "Contact" # Entity type (auto-pluralized for query)
|
|
108
|
+
filter: "name={{ customerName }}" # Lucene filter (template-parsed)
|
|
109
|
+
field: "contactId" # Field to return (default: <entity>Id)
|
|
110
|
+
```
|
|
111
|
+
Results are batched and cached per unique `entity|filter|field` combination by `ResolvePreProcessor` before step execution. Cache misses return `null`. Useful inside `foreach` mappings where many items reference the same entity — only one query per unique filter value.
|
|
112
|
+
|
|
113
|
+
**`$raw`** -- Prevent template parsing (pass as-is):
|
|
114
|
+
```yaml
|
|
115
|
+
template:
|
|
116
|
+
$raw: "This {{ won't }} be parsed"
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**`$eval`** -- Parse JSON string then evaluate as template:
|
|
120
|
+
```yaml
|
|
121
|
+
dynamicConfig:
|
|
122
|
+
$eval: "{{ configJsonString }}"
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**`decrypt`** / **`encrypt`** -- AES-CBC encryption (optional key/IV, has defaults):
|
|
126
|
+
```yaml
|
|
127
|
+
apiKey:
|
|
128
|
+
decrypt:
|
|
129
|
+
encryptedValue: "{{ encryptedApiKey }}"
|
|
130
|
+
key: "{{ encryptionKey }}" # optional Base64 AES key
|
|
131
|
+
initializationVector: "{{ iv }}" # optional Base64 IV
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## NCalc Expressions: `[variable]` (in conditions and expression directives)
|
|
137
|
+
|
|
138
|
+
Used in `conditions[].expression`, `switch` case `when`, and `expression:` value directives. Variables use **square bracket** `[name]` syntax.
|
|
139
|
+
|
|
140
|
+
```yaml
|
|
141
|
+
conditions:
|
|
142
|
+
- expression: "[status] = 'Active' AND [amount] > 100"
|
|
143
|
+
- expression: "isNullOrEmpty([Data.GetOrder.order?]) = false"
|
|
144
|
+
- expression: "any([changes], [each.key] = 'Status') = true"
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Parameter resolution rules**:
|
|
148
|
+
- Empty strings are converted to `null` (so `""` is treated as no value)
|
|
149
|
+
- Numeric strings are auto-converted to `decimal` when needed (e.g., `[price] > 100` works even if price is the string `"150"`)
|
|
150
|
+
- Dot paths resolve deep: `[Activity.Step.output.nested.field]`
|
|
151
|
+
- Optional suffix `?` prevents errors: `[order.customer?.name?]`
|
|
152
|
+
|
|
153
|
+
### Operators
|
|
154
|
+
|
|
155
|
+
| Type | Operators |
|
|
156
|
+
|------|-----------|
|
|
157
|
+
| Comparison | `=`, `!=`, `<>`, `<`, `>`, `<=`, `>=` |
|
|
158
|
+
| Logical | `AND`, `OR`, `NOT` (also `&&`, `\|\|`, `!`) |
|
|
159
|
+
| Arithmetic | `+`, `-`, `*`, `/`, `%` |
|
|
160
|
+
| Ternary | `if(condition, trueVal, falseVal)` |
|
|
161
|
+
| Membership | `in(value, val1, val2, ...)` |
|
|
162
|
+
|
|
163
|
+
### Iterator Variables
|
|
164
|
+
|
|
165
|
+
Functions use two iterator variable names:
|
|
166
|
+
- **`[each.*]`** -- used by: `any`, `all`, `sum`, `join` (3-arg)
|
|
167
|
+
- **`[item.*]`** -- used by: `first`, `last`, `groupBy`
|
|
168
|
+
|
|
169
|
+
### Collection Functions
|
|
170
|
+
|
|
171
|
+
| Function | Description |
|
|
172
|
+
|----------|-------------|
|
|
173
|
+
| `any([items], [each.prop] = 'val')` | True if any item matches expression. Without expression: checks if collection contains the value |
|
|
174
|
+
| `all([items], [each.prop] > 0)` | True if all items match. Returns `false` for null/empty collections |
|
|
175
|
+
| `count([items])` | Count items in list or JToken. Returns `0` for non-collections |
|
|
176
|
+
| `sum([items], [each.amount])` | Sum values as `decimal`. Optional `[each.*]` accessor. Skips nulls |
|
|
177
|
+
| `first([items])` or `first([items], [item.name])` | First item or evaluate expression on first item. Returns `""` if empty |
|
|
178
|
+
| `last([items])` or `last([items], [item.name])` | Last item or evaluate expression on last item. Returns `""` if empty |
|
|
179
|
+
| `distinct([items])` | Remove duplicates. Uses deep comparison for dictionaries |
|
|
180
|
+
| `reverse([items])` | Reverse collection or string |
|
|
181
|
+
| `contains([source], 'needle')` | String contains, JArray contains, list contains, or dict key/value contains |
|
|
182
|
+
| `removeEmpty([items])` | Remove null and whitespace-only items |
|
|
183
|
+
| `concat([list1], [list2], ...)` | Concatenate multiple collections into flat list. Variadic args. Skips nulls |
|
|
184
|
+
| `groupBy([items], [item.cat])` | Group by one or more key expressions. Returns `[{key, items}]`. Multi-key: keys joined with `\|` |
|
|
185
|
+
| `join([items], [each.name], ',')` | Join collection with `[each.*]` accessor and separator (3-arg) |
|
|
186
|
+
| `join([items], ',')` | Join collection directly with separator (2-arg) |
|
|
187
|
+
| `split([str], ' ')` | Split string by first character of separator. Returns `List<string>` |
|
|
188
|
+
| `elementAt([items], 0)` | Get element at index (zero-based) from list |
|
|
189
|
+
|
|
190
|
+
### String Functions
|
|
191
|
+
|
|
192
|
+
| Function | Description |
|
|
193
|
+
|----------|-------------|
|
|
194
|
+
| `isNullOrEmpty([var])` | True if null, empty string, or empty list |
|
|
195
|
+
| `length([var])` | String length or collection count. `0` for null strings and non-collections |
|
|
196
|
+
| `lower([name])` / `upper([code])` | Case conversion. Handles string, JToken, any `.ToString()` |
|
|
197
|
+
| `left([code], 3)` / `right([code], 3)` | Left/right N characters. Returns full string if shorter than N |
|
|
198
|
+
| `substring([str], 0, 5)` | Extract substring starting at position for given length |
|
|
199
|
+
| `replace([str], 'old', 'new')` | String replacement. Returns null if any arg is null |
|
|
200
|
+
| `trim([value])` | Trim whitespace. Returns `""` for null |
|
|
201
|
+
| `format('{0}-{1}', [prefix], [id])` | String.Format style. Variadic args. Returns null if format is null |
|
|
202
|
+
| `base64([value])` / `fromBase64([encoded])` | Base64 encode/decode. Handles string, byte[], JToken |
|
|
203
|
+
| `bool([value])` | Convert to boolean: null->`false`, empty string->`false`, "true"/"false"->parsed, non-zero number->`true`, any object->`true` |
|
|
204
|
+
| `transliterate([value])` | Unicode to ASCII (Unidecode). Returns `""` for null |
|
|
205
|
+
| `transliterateUa([value])` | Ukrainian-specific transliteration. Returns `""` for null |
|
|
206
|
+
| `parseAddress([address])` | Parse address -> `{StreetNumber, StreetName}`. Handles US and EU formats |
|
|
207
|
+
|
|
208
|
+
### Date Functions
|
|
209
|
+
|
|
210
|
+
| Function | Description |
|
|
211
|
+
|----------|-------------|
|
|
212
|
+
| `parseDate([str])` | Parse date string to DateTime. Supports common formats (ISO, US, etc.) |
|
|
213
|
+
| `now()` | Current UTC `DateTime` |
|
|
214
|
+
| `now('yyyy-MM-dd', 'en-US')` | Formatted current time as string |
|
|
215
|
+
| `addDays([date], 30)` | Add days (decimal, can be negative). Accepts DateTime, DateTimeOffset, string |
|
|
216
|
+
| `addHours([date], 2)` | Add hours (decimal, can be negative). Same type handling |
|
|
217
|
+
| `formatDate([date], 'dd/MM/yyyy', 'en-US')` | Format date with culture. Accepts DateTime or string |
|
|
218
|
+
| `dateFromUnix([unixTime])` | Unix timestamp (seconds) -> `DateTimeOffset`. Accepts int, long, decimal, string |
|
|
219
|
+
| `dateToUtc([date])` or `dateToUtc([date], 'en-US')` | Convert to UTC. Optional culture for string parsing |
|
|
220
|
+
| `toLocalTime([date], 'America/Chicago')` | Convert UTC date to local time in IANA timezone. Returns `DateTimeOffset`. Null-safe |
|
|
221
|
+
|
|
222
|
+
### Business Date Math (in Lucene filter expressions)
|
|
223
|
+
|
|
224
|
+
The filter engine (`FilterBy`) supports business-aware date math units in Lucene date expressions:
|
|
225
|
+
|
|
226
|
+
| Unit | Aliases | Description |
|
|
227
|
+
|------|---------|-------------|
|
|
228
|
+
| `BHOUR` | `BHOURS` | Add/subtract business hours (respects weekly schedule + holidays) |
|
|
229
|
+
| `BDAY` | `BDAYS` | Add/subtract business days (skips non-working days) |
|
|
230
|
+
|
|
231
|
+
**Usage**: These units are used in **Lucene filter strings** (not NCalc expressions). They require an `IBusinessDateMathResolver` and are resolved via the organization's business calendar.
|
|
232
|
+
|
|
233
|
+
```
|
|
234
|
+
dueDate: [NOW TO NOW+3BDAYS]
|
|
235
|
+
pickupDate: [* TO NOW-8BHOURS]
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
The resolver loads `CalendarBusinessHour` (weekly schedule) and `CalendarAvailabilityBlock` (holidays) for the organization's `business`-type calendar, then walks through working time segments to compute the target date.
|
|
239
|
+
|
|
240
|
+
### Math Functions (NCalc built-in)
|
|
241
|
+
|
|
242
|
+
`Abs(x)`, `Ceiling(x)`, `Floor(x)`, `Round(x, decimals)`, `Min(x, y)`, `Max(x, y)`, `Pow(x, y)`, `Sqrt(x)`, `Truncate(x)`
|
|
243
|
+
|
|
244
|
+
Custom: `ceiling([value])` -- same as `Ceiling` but handles type conversion to double.
|
|
245
|
+
|
|
246
|
+
### Domain Functions
|
|
247
|
+
|
|
248
|
+
| Function | Description |
|
|
249
|
+
|----------|-------------|
|
|
250
|
+
| `convertWeight([weight], 'Kg', 'Lb')` | Weight unit conversion. Returns `decimal` rounded to 5 places |
|
|
251
|
+
| `convertDimension([length], 'Cm', 'In')` | Dimension unit conversion. Returns `decimal` rounded to 3 places |
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Property Path Syntax (in collection, mapping, variable paths)
|
|
256
|
+
|
|
257
|
+
Used in `collection:` (foreach), `mapping:` (outputs), and variable resolution.
|
|
258
|
+
|
|
259
|
+
| Pattern | Description | Example |
|
|
260
|
+
|---------|-------------|---------|
|
|
261
|
+
| `a.b.c` | Dot-separated nested path | `order.customer.name` |
|
|
262
|
+
| `prop?` | Optional access (null if missing) | `order.customer?.name?` |
|
|
263
|
+
| `list[0]` | Array index | `items[0]` |
|
|
264
|
+
| `list[^1]` | Index from end (last item) | `items[^1]` |
|
|
265
|
+
| `list[*]` | Flatten/wildcard (all items) | `containers[*].commodities` |
|
|
266
|
+
| `list[**]` | Recursive flatten (all depths) | `containerCommodities[**]` |
|
|
267
|
+
| `list[-1]` | Depth filter (leaves only) | `tree[**][-1]` |
|
|
268
|
+
| `list[condition]` | Filter by condition | `items[status=Active]` |
|
|
269
|
+
| `dict['key']` | Dictionary key access | `customValues['myField']` |
|
|
270
|
+
| `list[*].{f1 f2}` | Field selector (projection) | `items[*].{name description}` |
|
|
271
|
+
| `list[*].{alias:source}` | Field selector with alias | `items[*].{id:commodityId}` |
|
|
272
|
+
| `list[*].{alias:_.parent}` | Field selector referencing parent | `items[*].{parentId:_.orderId}` |
|
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
# Flow Workflow YAML Reference
|
|
2
2
|
|
|
3
|
-
## Contents
|
|
4
|
-
- Flow top-level structure (workflowType, entity, states, transitions, aggregations)
|
|
5
|
-
- Flow entity section (entity name, type, includes, query)
|
|
6
|
-
- Flow states section (initial, final, parent hierarchy, onEnter/onExit steps)
|
|
7
|
-
- Flow transitions section (manual, auto, event triggers; from/to states; conditions)
|
|
8
|
-
- Flow aggregations section (reusable collection expressions: all, any, sum, count)
|
|
9
|
-
|
|
10
3
|
Flow workflows are declarative state machines for entity lifecycle management. Use `workflowType: Flow` in the workflow section.
|
|
11
4
|
|
|
12
5
|
## Top-Level Structure
|
|
@@ -93,7 +86,7 @@ states:
|
|
|
93
86
|
|
|
94
87
|
### State Rules
|
|
95
88
|
- **name**: Required, must be unique across all states
|
|
96
|
-
- **isInitial**: At most one state can be initial
|
|
89
|
+
- **isInitial**: At most one state can be initial
|
|
97
90
|
- **isFinal**: Final states cannot be transition sources
|
|
98
91
|
- **parent**: References another state; parent cannot be initial or final; children inherit parent transitions
|
|
99
92
|
|
|
@@ -152,10 +145,11 @@ transitions:
|
|
|
152
145
|
|
|
153
146
|
### Execution Order
|
|
154
147
|
1. Validate transition from current state
|
|
155
|
-
2.
|
|
156
|
-
3. Execute
|
|
157
|
-
4.
|
|
158
|
-
5.
|
|
148
|
+
2. Evaluate conditions (all must pass)
|
|
149
|
+
3. Execute `onExit` steps (from source state)
|
|
150
|
+
4. Execute transition `steps` (step inputs merged + template expressions resolved)
|
|
151
|
+
5. Update entity status
|
|
152
|
+
6. Execute `onEnter` steps (on target state)
|
|
159
153
|
|
|
160
154
|
## Aggregations Section
|
|
161
155
|
|
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
# Other Tasks Reference
|
|
2
2
|
|
|
3
|
-
## Contents
|
|
4
|
-
- User & Auth tasks (User CRUD, verification codes, OAuth2 authentication)
|
|
5
|
-
- Caching tasks (SetCache and GetCache for in-memory key-value storage)
|
|
6
|
-
- EDI & Structured File Parsing tasks (EDI/Parse for X12/EDIFACT, StructuredFile/Parse)
|
|
7
|
-
- Flow/Transition task (trigger state machine transitions programmatically)
|
|
8
|
-
- Note tasks (Create, Update, Delete, NoteThread/Rename, bulk Import/Export)
|
|
9
|
-
- AppModule tasks (Create, Update, Delete app modules)
|
|
10
|
-
- ActionEvent/Create task (trigger UI notifications or webhooks)
|
|
11
|
-
|
|
12
3
|
## User & Auth
|
|
13
4
|
|
|
14
5
|
| Task | Description |
|
|
@@ -64,20 +55,48 @@
|
|
|
64
55
|
|
|
65
56
|
| Task | Description |
|
|
66
57
|
|------|-------------|
|
|
67
|
-
| `
|
|
58
|
+
| `X12/Parse` | Parse X12 EDI documents (850, 856) |
|
|
59
|
+
| `EDIFACT/Parse` | Parse EDIFACT messages (IFTMIN) |
|
|
60
|
+
| `EDIFACT/Generate` | Generate EDIFACT messages (IFTMIN) |
|
|
61
|
+
| `EDI/Parse` | **Deprecated** — alias for X12/Parse, use `X12/Parse` instead |
|
|
68
62
|
| `StructuredFile/Parse` | Parse structured files |
|
|
69
63
|
|
|
70
64
|
```yaml
|
|
71
|
-
- task: "
|
|
72
|
-
name:
|
|
65
|
+
- task: "X12/Parse@1"
|
|
66
|
+
name: ParseX12
|
|
73
67
|
inputs:
|
|
74
|
-
|
|
75
|
-
|
|
68
|
+
ediData: "{{ Transfer.Download.content }}"
|
|
69
|
+
transactionSet: "850"
|
|
70
|
+
validateSchema: true
|
|
76
71
|
outputs:
|
|
77
72
|
- name: parsed
|
|
78
73
|
mapping: "document"
|
|
79
74
|
```
|
|
80
75
|
|
|
76
|
+
```yaml
|
|
77
|
+
- task: "EDIFACT/Parse@1"
|
|
78
|
+
name: ParseEdifact
|
|
79
|
+
inputs:
|
|
80
|
+
edifactData: "{{ Transfer.Download.content }}"
|
|
81
|
+
messageType: "IFTMIN"
|
|
82
|
+
outputs:
|
|
83
|
+
- name: parsed
|
|
84
|
+
mapping: "document"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
```yaml
|
|
88
|
+
- task: "EDIFACT/Generate@1"
|
|
89
|
+
name: GenerateEdifact
|
|
90
|
+
inputs:
|
|
91
|
+
messageType: "IFTMIN"
|
|
92
|
+
data: "{{ shipmentData }}"
|
|
93
|
+
outputs:
|
|
94
|
+
- name: edifactData
|
|
95
|
+
mapping: "edifactData"
|
|
96
|
+
- name: messageType
|
|
97
|
+
mapping: "messageType"
|
|
98
|
+
```
|
|
99
|
+
|
|
81
100
|
## Flow
|
|
82
101
|
|
|
83
102
|
| Task | Description |
|
|
@@ -1,17 +1,5 @@
|
|
|
1
1
|
# Utilities Tasks Reference
|
|
2
2
|
|
|
3
|
-
## Contents
|
|
4
|
-
- Available utility tasks (summary table of all Utilities/* tasks)
|
|
5
|
-
- SetVariable task (set variables in activity and global scope)
|
|
6
|
-
- Log task (log variables and messages to workflow logger)
|
|
7
|
-
- Error task (throw workflow error to halt execution)
|
|
8
|
-
- HttpRequest task (HTTP calls to external APIs with action events)
|
|
9
|
-
- Map task (extract and reshape data into new variables)
|
|
10
|
-
- Template task (Handlebars template rendering)
|
|
11
|
-
- CsvParse task (parse CSV content into structured data)
|
|
12
|
-
- Export task (export data to file format)
|
|
13
|
-
- Import task (import data from file content)
|
|
14
|
-
|
|
15
3
|
## Available Tasks
|
|
16
4
|
|
|
17
5
|
| Task | Description |
|
|
@@ -28,8 +16,64 @@
|
|
|
28
16
|
| `Utilities/MoveFile@1` | Move file |
|
|
29
17
|
| `Utilities/ValidateReCaptcha` | Validate reCAPTCHA |
|
|
30
18
|
| `Utilities/ValidateHMAC` | Validate HMAC signatures |
|
|
19
|
+
| `Utilities/UnzipFile@1` | Extract files from ZIP archive (local path or URL) |
|
|
31
20
|
| `Utilities/ResolveTimezone@1` | Resolve IANA timezone and UTC offset from lat/lng coordinates |
|
|
32
21
|
|
|
22
|
+
## UnzipFile@1
|
|
23
|
+
|
|
24
|
+
Extracts files from a ZIP archive. Accepts a local file path (from `saveToFile` or previous step) or a URL (`file://`, `http://`, `https://`). Files are extracted to a workflow-scoped temp directory with auto-cleanup.
|
|
25
|
+
|
|
26
|
+
```yaml
|
|
27
|
+
- task: "Utilities/UnzipFile@1"
|
|
28
|
+
name: ExtractArchive
|
|
29
|
+
inputs:
|
|
30
|
+
filePath: "{{ Main?.DownloadArchive?.result?.FilePath? }}"
|
|
31
|
+
filePattern: "*.csv"
|
|
32
|
+
outputs:
|
|
33
|
+
- name: files
|
|
34
|
+
mapping: "Files?"
|
|
35
|
+
- name: count
|
|
36
|
+
mapping: "Count?"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Inputs:** `filePath` (string, local path) OR `fileUrl` (string, URL — `file://`, `http://`, `https://`). Optional: `filePattern` (glob pattern, e.g. `*.csv`, `data_*.json`).
|
|
40
|
+
**Outputs:** `Files` (string[] — full paths to extracted files), `Count` (int — number of matched files).
|
|
41
|
+
Provide one of `filePath` or `fileUrl`. Common pattern: HttpRequest with `saveToFile: true` → UnzipFile with `filePath`.
|
|
42
|
+
|
|
43
|
+
```yaml
|
|
44
|
+
# Download + unzip + import pipeline
|
|
45
|
+
- task: "Utilities/HttpRequest@1"
|
|
46
|
+
name: Download
|
|
47
|
+
inputs:
|
|
48
|
+
url: "{{ downloadUrl }}"
|
|
49
|
+
method: GET
|
|
50
|
+
saveToFile: true
|
|
51
|
+
outputs:
|
|
52
|
+
- name: result
|
|
53
|
+
mapping: "response?"
|
|
54
|
+
|
|
55
|
+
- task: "Utilities/UnzipFile@1"
|
|
56
|
+
name: Unzip
|
|
57
|
+
inputs:
|
|
58
|
+
filePath: "{{ Main?.Download?.result?.FilePath? }}"
|
|
59
|
+
filePattern: "*.csv"
|
|
60
|
+
outputs:
|
|
61
|
+
- name: files
|
|
62
|
+
mapping: "Files?"
|
|
63
|
+
|
|
64
|
+
- task: foreach
|
|
65
|
+
name: ProcessFiles
|
|
66
|
+
collection: "Main?.Unzip?.files?"
|
|
67
|
+
steps:
|
|
68
|
+
- task: "Utilities/Import@1"
|
|
69
|
+
name: ImportFile
|
|
70
|
+
inputs:
|
|
71
|
+
fileUrl: "file://{{ item }}"
|
|
72
|
+
format: "csv"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
33
77
|
## ResolveTimezone@1
|
|
34
78
|
|
|
35
79
|
Resolves IANA timezone ID and current UTC offset from geographic coordinates using offline boundary lookup (GeoTimeZone).
|
|
@@ -127,6 +171,21 @@ Performs HTTP requests to external APIs.
|
|
|
127
171
|
|
|
128
172
|
Response available at `ActivityName?.CallApi?.result?`.
|
|
129
173
|
|
|
174
|
+
**`saveToFile` mode**: When `saveToFile: true`, the response body is saved to a temp file instead of being returned in memory. The response object changes to `{ StatusCode, Headers, FilePath }`. Use this for large file downloads, then pass `FilePath` to downstream tasks like `UnzipFile` or `Import`.
|
|
175
|
+
|
|
176
|
+
```yaml
|
|
177
|
+
- task: "Utilities/HttpRequest@1"
|
|
178
|
+
name: DownloadArchive
|
|
179
|
+
inputs:
|
|
180
|
+
url: "{{ downloadUrl }}"
|
|
181
|
+
method: GET
|
|
182
|
+
saveToFile: true
|
|
183
|
+
outputs:
|
|
184
|
+
- name: result
|
|
185
|
+
mapping: "response?"
|
|
186
|
+
# result.FilePath contains the temp file path
|
|
187
|
+
```
|
|
188
|
+
|
|
130
189
|
**Action events**: When an HTTP request operates on a specific entity (e.g., sending parcel info for an order), enable `actionEvents` in the inputs so the system can track and notify about the request. Include `eventDataExt` with the entity ID to link the event to the entity.
|
|
131
190
|
|
|
132
191
|
```yaml
|
|
@@ -183,7 +242,7 @@ Renders a Handlebars template string with data.
|
|
|
183
242
|
|
|
184
243
|
## CsvParse@1
|
|
185
244
|
|
|
186
|
-
Parses CSV content into structured data.
|
|
245
|
+
Parses CSV content into structured data. CSV headers are automatically trimmed of whitespace, BOM characters, and other special characters to ensure reliable column matching.
|
|
187
246
|
|
|
188
247
|
```yaml
|
|
189
248
|
- task: "Utilities/CsvParse@1"
|
|
@@ -214,7 +273,7 @@ Exports data to file format.
|
|
|
214
273
|
|
|
215
274
|
## Import@1
|
|
216
275
|
|
|
217
|
-
Imports data from file content.
|
|
276
|
+
Imports data from file content or URL. Supports `file://` URLs for local files (e.g. from UnzipFile output).
|
|
218
277
|
|
|
219
278
|
```yaml
|
|
220
279
|
- task: "Utilities/Import@1"
|
|
@@ -226,3 +285,17 @@ Imports data from file content.
|
|
|
226
285
|
- name: data
|
|
227
286
|
mapping: "data?"
|
|
228
287
|
```
|
|
288
|
+
|
|
289
|
+
```yaml
|
|
290
|
+
# Import from local file (e.g. extracted from ZIP)
|
|
291
|
+
- task: "Utilities/Import@1"
|
|
292
|
+
name: ImportLocalFile
|
|
293
|
+
inputs:
|
|
294
|
+
fileUrl: "file://{{ localFilePath }}"
|
|
295
|
+
format: "csv"
|
|
296
|
+
outputs:
|
|
297
|
+
- name: data
|
|
298
|
+
mapping: "data?"
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
**`file://` URL support**: Import, Order/Import, PostalCodes/Import, and Notes/Import all accept `file://` URLs via UrlStreamHelper. This enables pipeline patterns: HttpRequest (saveToFile) → UnzipFile → Import (file://).
|
package/README.md
CHANGED
|
@@ -29,19 +29,19 @@ npm install @cxtms/cx-schema
|
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
31
|
# Initialize a new project
|
|
32
|
-
npx
|
|
32
|
+
npx cx-cli init
|
|
33
33
|
|
|
34
34
|
# Create a new module
|
|
35
|
-
npx
|
|
35
|
+
npx cx-cli create module orders
|
|
36
36
|
|
|
37
37
|
# Create a new workflow
|
|
38
|
-
npx
|
|
38
|
+
npx cx-cli create workflow invoice-processor
|
|
39
39
|
|
|
40
40
|
# Validate files
|
|
41
|
-
npx
|
|
41
|
+
npx cx-cli modules/*.yaml workflows/*.yaml
|
|
42
42
|
|
|
43
43
|
# Generate validation report
|
|
44
|
-
npx
|
|
44
|
+
npx cx-cli report modules/*.yaml --report report.html
|
|
45
45
|
```
|
|
46
46
|
|
|
47
47
|
## CLI Commands
|
|
@@ -51,14 +51,14 @@ npx cxtms report modules/*.yaml --report report.html
|
|
|
51
51
|
Validate YAML file(s) against JSON Schema definitions.
|
|
52
52
|
|
|
53
53
|
```bash
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
cx-cli [files...]
|
|
55
|
+
cx-cli validate [files...]
|
|
56
56
|
|
|
57
57
|
# Examples
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
cx-cli modules/orders-module.yaml
|
|
59
|
+
cx-cli modules/*.yaml workflows/*.yaml
|
|
60
|
+
cx-cli --verbose modules/orders-module.yaml
|
|
61
|
+
cx-cli --format json modules/orders-module.yaml
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
### init
|
|
@@ -66,7 +66,7 @@ cxtms --format json modules/orders-module.yaml
|
|
|
66
66
|
Initialize a new CX project with configuration files.
|
|
67
67
|
|
|
68
68
|
```bash
|
|
69
|
-
|
|
69
|
+
cx-cli init
|
|
70
70
|
```
|
|
71
71
|
|
|
72
72
|
Creates:
|
|
@@ -81,11 +81,11 @@ Creates:
|
|
|
81
81
|
Create a new module or workflow from template.
|
|
82
82
|
|
|
83
83
|
```bash
|
|
84
|
-
|
|
84
|
+
cx-cli create <type> <name>
|
|
85
85
|
|
|
86
86
|
# Examples
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
cx-cli create module orders
|
|
88
|
+
cx-cli create workflow invoice-generator
|
|
89
89
|
```
|
|
90
90
|
|
|
91
91
|
Generated files include:
|
|
@@ -98,12 +98,12 @@ Generated files include:
|
|
|
98
98
|
Generate validation report for multiple files.
|
|
99
99
|
|
|
100
100
|
```bash
|
|
101
|
-
|
|
101
|
+
cx-cli report [files...] --report <output-file>
|
|
102
102
|
|
|
103
103
|
# Examples
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
104
|
+
cx-cli report modules/*.yaml --report report.html
|
|
105
|
+
cx-cli report workflows/*.yaml --report report.md
|
|
106
|
+
cx-cli report modules/*.yaml workflows/*.yaml --report results.json
|
|
107
107
|
```
|
|
108
108
|
|
|
109
109
|
Report formats (auto-detected from extension):
|
|
@@ -116,13 +116,13 @@ Report formats (auto-detected from extension):
|
|
|
116
116
|
Display the JSON Schema definition for a component or task.
|
|
117
117
|
|
|
118
118
|
```bash
|
|
119
|
-
|
|
119
|
+
cx-cli schema <name>
|
|
120
120
|
|
|
121
121
|
# Examples
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
122
|
+
cx-cli schema form
|
|
123
|
+
cx-cli schema dataGrid
|
|
124
|
+
cx-cli schema workflow
|
|
125
|
+
cx-cli schema foreach
|
|
126
126
|
```
|
|
127
127
|
|
|
128
128
|
### example
|
|
@@ -130,11 +130,11 @@ cxtms schema foreach
|
|
|
130
130
|
Show example YAML for a component or task.
|
|
131
131
|
|
|
132
132
|
```bash
|
|
133
|
-
|
|
133
|
+
cx-cli example <name>
|
|
134
134
|
|
|
135
135
|
# Examples
|
|
136
|
-
|
|
137
|
-
|
|
136
|
+
cx-cli example form
|
|
137
|
+
cx-cli example workflow
|
|
138
138
|
```
|
|
139
139
|
|
|
140
140
|
### list
|
|
@@ -142,9 +142,9 @@ cxtms example workflow
|
|
|
142
142
|
List all available schemas for validation.
|
|
143
143
|
|
|
144
144
|
```bash
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
145
|
+
cx-cli list
|
|
146
|
+
cx-cli list --type module
|
|
147
|
+
cx-cli list --type workflow
|
|
148
148
|
```
|
|
149
149
|
|
|
150
150
|
## CLI Options
|
|
@@ -298,11 +298,11 @@ Generated workflows include:
|
|
|
298
298
|
```yaml
|
|
299
299
|
- name: Validate YAML files
|
|
300
300
|
run: |
|
|
301
|
-
npx
|
|
301
|
+
npx cx-cli --format compact modules/*.yaml workflows/*.yaml
|
|
302
302
|
|
|
303
303
|
- name: Generate validation report
|
|
304
304
|
run: |
|
|
305
|
-
npx
|
|
305
|
+
npx cx-cli report modules/*.yaml workflows/*.yaml --report validation-report.html
|
|
306
306
|
|
|
307
307
|
- name: Upload report
|
|
308
308
|
uses: actions/upload-artifact@v3
|
|
@@ -316,7 +316,7 @@ Generated workflows include:
|
|
|
316
316
|
```yaml
|
|
317
317
|
validate:
|
|
318
318
|
script:
|
|
319
|
-
- npx
|
|
319
|
+
- npx cx-cli --format json modules/*.yaml > validation-results.json
|
|
320
320
|
artifacts:
|
|
321
321
|
paths:
|
|
322
322
|
- validation-results.json
|
|
@@ -331,7 +331,7 @@ validate:
|
|
|
331
331
|
staged_files=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(yaml|yml)$')
|
|
332
332
|
|
|
333
333
|
if [ -n "$staged_files" ]; then
|
|
334
|
-
npx
|
|
334
|
+
npx cx-cli --format compact $staged_files
|
|
335
335
|
if [ $? -ne 0 ]; then
|
|
336
336
|
echo "Validation failed. Please fix errors before committing."
|
|
337
337
|
exit 1
|