@celigo/api-specs 0.2.163 → 0.2.164

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/ai-agent.yml CHANGED
@@ -2343,7 +2343,8 @@ components:
2343
2343
  fields. There is no separate `date` enum value.
2344
2344
 
2345
2345
  **Complex Types (require additional configuration)**
2346
- - `object`: Creates a nested object. REQUIRES child mappings in the 'mappings' array
2346
+ - `object`: Creates a nested object from child mappings in the 'mappings' array, or
2347
+ copies a whole object with `extract` (one or the other, not both)
2347
2348
 
2348
2349
  **Array Types**
2349
2350
  - `stringarray`: Array of strings
@@ -2391,7 +2392,7 @@ components:
2391
2392
  string: Text values; converts other types to their string representation.
2392
2393
  number: Numeric values; attempts conversion from strings.
2393
2394
  boolean: True/false values; converts truthy/falsy values.
2394
- object: Nested object that requires child mappings in the `mappings` array.
2395
+ object: Nested object built from child `mappings`, or copied whole with `extract` (not both).
2395
2396
  stringarray: Array of string values.
2396
2397
  numberarray: Array of numeric values.
2397
2398
  booleanarray: Array of boolean values.
@@ -2469,7 +2470,10 @@ components:
2469
2470
  - JSON path patterns ALWAYS execute from the TOP-LEVEL root of the input record
2470
2471
  - The system maintains this context even in deeply nested mappings
2471
2472
  - For object mappings without child mappings, extract should return a complete object
2472
- - When both extract and mappings are defined for objects, extract is applied first
2473
+ - An `object` row takes `extract` (to copy a whole object) or child `mappings`, not
2474
+ both: a row with both fails with 422 (`"extract" should not be present if
2475
+ "mappings" field is present`). A `buildArrayHelper` entry is different: there
2476
+ `extract` and `mappings` work together.
2473
2477
  - The root is the record as it arrives: an object record roots at `$.field`; a
2474
2478
  grouped record (an array of rows — grouped exports, file key columns, NetSuite
2475
2479
  grouped saved searches) roots at the array, so its rows are addressed as
@@ -3423,7 +3427,8 @@ components:
3423
3427
  fields. There is no separate `date` enum value.
3424
3428
 
3425
3429
  **Complex Types (require additional configuration)**
3426
- - `object`: Creates a nested object. REQUIRES child mappings in the 'mappings' array
3430
+ - `object`: Creates a nested object from child mappings in the 'mappings' array, or
3431
+ copies a whole object with `extract` (one or the other, not both)
3427
3432
 
3428
3433
  **Array Types**
3429
3434
  - `stringarray`: Array of strings
@@ -3471,7 +3476,7 @@ components:
3471
3476
  string: Text values; converts other types to their string representation.
3472
3477
  number: Numeric values; attempts conversion from strings.
3473
3478
  boolean: True/false values; converts truthy/falsy values.
3474
- object: Nested object that requires child mappings in the `mappings` array.
3479
+ object: Nested object built from child `mappings`, or copied whole with `extract` (not both).
3475
3480
  stringarray: Array of string values.
3476
3481
  numberarray: Array of numeric values.
3477
3482
  booleanarray: Array of boolean values.
@@ -3549,7 +3554,10 @@ components:
3549
3554
  - JSON path patterns ALWAYS execute from the TOP-LEVEL root of the input record
3550
3555
  - The system maintains this context even in deeply nested mappings
3551
3556
  - For object mappings without child mappings, extract should return a complete object
3552
- - When both extract and mappings are defined for objects, extract is applied first
3557
+ - An `object` row takes `extract` (to copy a whole object) or child `mappings`, not
3558
+ both: a row with both fails with 422 (`"extract" should not be present if
3559
+ "mappings" field is present`). A `buildArrayHelper` entry is different: there
3560
+ `extract` and `mappings` work together.
3553
3561
  - The root is the record as it arrives: an object record roots at `$.field`; a
3554
3562
  grouped record (an array of rows — grouped exports, file key columns, NetSuite
3555
3563
  grouped saved searches) roots at the array, so its rows are addressed as
@@ -5628,10 +5636,11 @@ components:
5628
5636
  ALWAYS reference the `record` root regardless of
5629
5637
  `inputContext` — only JSONPath anchoring flips.
5630
5638
  - |-
5631
- In `envelope` mode a `modify` transform merges its mapped
5632
- fields into `record` and keeps the rest of the envelope
5633
- around it; a `create` transform returns only the mapped
5634
- fields, as a bare record.
5639
+ In `envelope` mode the output is still a bare record: a
5640
+ `modify` transform returns the record with its mapped
5641
+ fields merged in (no `record` wrapper, no `job` or
5642
+ `settings` keys), and a `create` transform returns only
5643
+ the mapped fields.
5635
5644
  - |-
5636
5645
  Emit `inputContext` explicitly on new v2 transforms:
5637
5646
  unset is read as `record`, but stating it makes the
@@ -552,7 +552,8 @@ components:
552
552
  fields. There is no separate `date` enum value.
553
553
 
554
554
  **Complex Types (require additional configuration)**
555
- - `object`: Creates a nested object. REQUIRES child mappings in the 'mappings' array
555
+ - `object`: Creates a nested object from child mappings in the 'mappings' array, or
556
+ copies a whole object with `extract` (one or the other, not both)
556
557
 
557
558
  **Array Types**
558
559
  - `stringarray`: Array of strings
@@ -600,7 +601,7 @@ components:
600
601
  string: Text values; converts other types to their string representation.
601
602
  number: Numeric values; attempts conversion from strings.
602
603
  boolean: True/false values; converts truthy/falsy values.
603
- object: Nested object that requires child mappings in the `mappings` array.
604
+ object: Nested object built from child `mappings`, or copied whole with `extract` (not both).
604
605
  stringarray: Array of string values.
605
606
  numberarray: Array of numeric values.
606
607
  booleanarray: Array of boolean values.
@@ -678,7 +679,10 @@ components:
678
679
  - JSON path patterns ALWAYS execute from the TOP-LEVEL root of the input record
679
680
  - The system maintains this context even in deeply nested mappings
680
681
  - For object mappings without child mappings, extract should return a complete object
681
- - When both extract and mappings are defined for objects, extract is applied first
682
+ - An `object` row takes `extract` (to copy a whole object) or child `mappings`, not
683
+ both: a row with both fails with 422 (`"extract" should not be present if
684
+ "mappings" field is present`). A `buildArrayHelper` entry is different: there
685
+ `extract` and `mappings` work together.
682
686
  - The root is the record as it arrives: an object record roots at `$.field`; a
683
687
  grouped record (an array of rows — grouped exports, file key columns, NetSuite
684
688
  grouped saved searches) roots at the array, so its rows are addressed as
@@ -1632,7 +1636,8 @@ components:
1632
1636
  fields. There is no separate `date` enum value.
1633
1637
 
1634
1638
  **Complex Types (require additional configuration)**
1635
- - `object`: Creates a nested object. REQUIRES child mappings in the 'mappings' array
1639
+ - `object`: Creates a nested object from child mappings in the 'mappings' array, or
1640
+ copies a whole object with `extract` (one or the other, not both)
1636
1641
 
1637
1642
  **Array Types**
1638
1643
  - `stringarray`: Array of strings
@@ -1680,7 +1685,7 @@ components:
1680
1685
  string: Text values; converts other types to their string representation.
1681
1686
  number: Numeric values; attempts conversion from strings.
1682
1687
  boolean: True/false values; converts truthy/falsy values.
1683
- object: Nested object that requires child mappings in the `mappings` array.
1688
+ object: Nested object built from child `mappings`, or copied whole with `extract` (not both).
1684
1689
  stringarray: Array of string values.
1685
1690
  numberarray: Array of numeric values.
1686
1691
  booleanarray: Array of boolean values.
@@ -1758,7 +1763,10 @@ components:
1758
1763
  - JSON path patterns ALWAYS execute from the TOP-LEVEL root of the input record
1759
1764
  - The system maintains this context even in deeply nested mappings
1760
1765
  - For object mappings without child mappings, extract should return a complete object
1761
- - When both extract and mappings are defined for objects, extract is applied first
1766
+ - An `object` row takes `extract` (to copy a whole object) or child `mappings`, not
1767
+ both: a row with both fails with 422 (`"extract" should not be present if
1768
+ "mappings" field is present`). A `buildArrayHelper` entry is different: there
1769
+ `extract` and `mappings` work together.
1762
1770
  - The root is the record as it arrives: an object record roots at `$.field`; a
1763
1771
  grouped record (an array of rows — grouped exports, file key columns, NetSuite
1764
1772
  grouped saved searches) roots at the array, so its rows are addressed as
@@ -3173,10 +3181,11 @@ components:
3173
3181
  ALWAYS reference the `record` root regardless of
3174
3182
  `inputContext` — only JSONPath anchoring flips.
3175
3183
  - |-
3176
- In `envelope` mode a `modify` transform merges its mapped
3177
- fields into `record` and keeps the rest of the envelope
3178
- around it; a `create` transform returns only the mapped
3179
- fields, as a bare record.
3184
+ In `envelope` mode the output is still a bare record: a
3185
+ `modify` transform returns the record with its mapped
3186
+ fields merged in (no `record` wrapper, no `job` or
3187
+ `settings` keys), and a `create` transform returns only
3188
+ the mapped fields.
3180
3189
  - |-
3181
3190
  Emit `inputContext` explicitly on new v2 transforms:
3182
3191
  unset is read as `record`, but stating it makes the
package/dist/audit.yml CHANGED
@@ -145,7 +145,7 @@ paths:
145
145
  script: Script resource for custom JavaScript hooks.
146
146
  ssoclient: SSO client configuration resource.
147
147
  stack: Stack resource for on-premise or Lambda execution environments.
148
- supportshare: Support share access grant resource.
148
+ supportshare: Celigo Support access grant, made in the integrator.io UI. The API has no support-share route, so these audit entries are its only API view.
149
149
  sync: Sync resource.
150
150
  tool: Tool resource for reusable building blocks.
151
151
  topic: Event Streams topic resource.
@@ -577,7 +577,7 @@ paths:
577
577
  script: Script resource for custom JavaScript hooks.
578
578
  ssoclient: SSO client configuration resource.
579
579
  stack: Stack resource for on-premise or Lambda execution environments.
580
- supportshare: Support share access grant resource.
580
+ supportshare: Celigo Support access grant, made in the integrator.io UI. The API has no support-share route, so these audit entries are its only API view.
581
581
  sync: Sync resource.
582
582
  tool: Tool resource for reusable building blocks.
583
583
  topic: Event Streams topic resource.
@@ -1513,7 +1513,7 @@ components:
1513
1513
  script: Script resource for custom JavaScript hooks.
1514
1514
  ssoclient: SSO client configuration resource.
1515
1515
  stack: Stack resource for on-premise or Lambda execution environments.
1516
- supportshare: Support share access grant resource.
1516
+ supportshare: Celigo Support access grant, made in the integrator.io UI. The API has no support-share route, so these audit entries are its only API view.
1517
1517
  sync: Sync resource.
1518
1518
  tool: Tool resource for reusable building blocks.
1519
1519
  topic: Event Streams topic resource.
@@ -1720,7 +1720,7 @@ components:
1720
1720
  script: Script resource for custom JavaScript hooks.
1721
1721
  ssoclient: SSO client configuration resource.
1722
1722
  stack: Stack resource for on-premise or Lambda execution environments.
1723
- supportshare: Support share access grant resource.
1723
+ supportshare: Celigo Support access grant, made in the integrator.io UI. The API has no support-share route, so these audit entries are its only API view.
1724
1724
  sync: Sync resource.
1725
1725
  tool: Tool resource for reusable building blocks.
1726
1726
  topic: Event Streams topic resource.
@@ -1943,7 +1943,7 @@ components:
1943
1943
  script: Script resource for custom JavaScript hooks.
1944
1944
  ssoclient: SSO client configuration resource.
1945
1945
  stack: Stack resource for on-premise or Lambda execution environments.
1946
- supportshare: Support share access grant resource.
1946
+ supportshare: Celigo Support access grant, made in the integrator.io UI. The API has no support-share route, so these audit entries are its only API view.
1947
1947
  sync: Sync resource.
1948
1948
  tool: Tool resource for reusable building blocks.
1949
1949
  topic: Event Streams topic resource.
package/dist/export.yml CHANGED
@@ -11875,10 +11875,12 @@ components:
11875
11875
 
11876
11876
  **Delta exports (type: "delta")**
11877
11877
  For delta/incremental exports, do NOT populate a `delta` object inside `rdbms`.
11878
- Instead, use `{{lastExportDateTime}}` or `{{currentExportDateTime}}` directly in the query:
11878
+ Instead, use `{{lastExportDateTime}}` or `{{currentExportDateTime}}` directly in the query, and
11879
+ set the export's top-level `delta.startDate`: without it the first run's window is empty.
11879
11880
  ```json
11880
11881
  {
11881
11882
  "type": "delta",
11883
+ "delta": { "startDate": "2026-01-01T00:00:00.000Z" },
11882
11884
  "rdbms": {
11883
11885
  "query": "SELECT * FROM customers WHERE updatedAt > {{lastExportDateTime}}"
11884
11886
  }
@@ -11951,6 +11953,24 @@ components:
11951
11953
  only — real-time stream listeners (`type` is `stream`) have no SQL query. For delta exports,
11952
11954
  reference {{lastExportDateTime}}/{{currentExportDateTime}} directly in the query rather
11953
11955
  than configuring a separate delta object.
11956
+
11957
+ Double braces render a string as a quoted SQL literal with its apostrophes escaped, and
11958
+ triple braces insert a value raw. Observed in Snowflake queries:
11959
+
11960
+ - String helper output (`dateFormat`, `jsonSerialize`) and both delta variables are
11961
+ quoted the same way; a number or boolean renders bare, whether it is a JSON value or a
11962
+ numeric helper's result (`{{add 2 3}}` renders `5`).
11963
+ - In a run, {{lastExportDateTime}} and {{currentExportDateTime}} arrive as quoted ISO 8601
11964
+ UTC literals with milliseconds (`'2026-01-15T00:00:00.000Z'`), or in `delta.dateFormat`
11965
+ when it is set: add no quotes of your own, and don't parse them with a format mask
11966
+ written for another format.
11967
+ - A preview of an unsaved export document renders both as empty, unquoted text, so a
11968
+ delta query fails to compile there unless the document carries both in `postData`.
11969
+ - The quoting leaves backslashes, which Snowflake reads as escape sequences, so a
11970
+ double-brace value holding a backslash arrives changed. Pass such a value in a
11971
+ dollar-quoted constant with triple braces (`$${{{record.field}}}$$`), which Snowflake
11972
+ reads as is, but only when it can't contain `$$`: a `$$` ends the constant, and the rest
11973
+ is read as SQL.
11954
11974
  x-celigo-ai-guidance:
11955
11975
  - |-
11956
11976
  This field contains the SQL SELECT statement that will be executed to fetch data
@@ -12498,7 +12518,8 @@ components:
12498
12518
  fields. There is no separate `date` enum value.
12499
12519
 
12500
12520
  **Complex Types (require additional configuration)**
12501
- - `object`: Creates a nested object. REQUIRES child mappings in the 'mappings' array
12521
+ - `object`: Creates a nested object from child mappings in the 'mappings' array, or
12522
+ copies a whole object with `extract` (one or the other, not both)
12502
12523
 
12503
12524
  **Array Types**
12504
12525
  - `stringarray`: Array of strings
@@ -12546,7 +12567,7 @@ components:
12546
12567
  string: Text values; converts other types to their string representation.
12547
12568
  number: Numeric values; attempts conversion from strings.
12548
12569
  boolean: True/false values; converts truthy/falsy values.
12549
- object: Nested object that requires child mappings in the `mappings` array.
12570
+ object: Nested object built from child `mappings`, or copied whole with `extract` (not both).
12550
12571
  stringarray: Array of string values.
12551
12572
  numberarray: Array of numeric values.
12552
12573
  booleanarray: Array of boolean values.
@@ -12624,7 +12645,10 @@ components:
12624
12645
  - JSON path patterns ALWAYS execute from the TOP-LEVEL root of the input record
12625
12646
  - The system maintains this context even in deeply nested mappings
12626
12647
  - For object mappings without child mappings, extract should return a complete object
12627
- - When both extract and mappings are defined for objects, extract is applied first
12648
+ - An `object` row takes `extract` (to copy a whole object) or child `mappings`, not
12649
+ both: a row with both fails with 422 (`"extract" should not be present if
12650
+ "mappings" field is present`). A `buildArrayHelper` entry is different: there
12651
+ `extract` and `mappings` work together.
12628
12652
  - The root is the record as it arrives: an object record roots at `$.field`; a
12629
12653
  grouped record (an array of rows — grouped exports, file key columns, NetSuite
12630
12654
  grouped saved searches) roots at the array, so its rows are addressed as
@@ -13578,7 +13602,8 @@ components:
13578
13602
  fields. There is no separate `date` enum value.
13579
13603
 
13580
13604
  **Complex Types (require additional configuration)**
13581
- - `object`: Creates a nested object. REQUIRES child mappings in the 'mappings' array
13605
+ - `object`: Creates a nested object from child mappings in the 'mappings' array, or
13606
+ copies a whole object with `extract` (one or the other, not both)
13582
13607
 
13583
13608
  **Array Types**
13584
13609
  - `stringarray`: Array of strings
@@ -13626,7 +13651,7 @@ components:
13626
13651
  string: Text values; converts other types to their string representation.
13627
13652
  number: Numeric values; attempts conversion from strings.
13628
13653
  boolean: True/false values; converts truthy/falsy values.
13629
- object: Nested object that requires child mappings in the `mappings` array.
13654
+ object: Nested object built from child `mappings`, or copied whole with `extract` (not both).
13630
13655
  stringarray: Array of string values.
13631
13656
  numberarray: Array of numeric values.
13632
13657
  booleanarray: Array of boolean values.
@@ -13704,7 +13729,10 @@ components:
13704
13729
  - JSON path patterns ALWAYS execute from the TOP-LEVEL root of the input record
13705
13730
  - The system maintains this context even in deeply nested mappings
13706
13731
  - For object mappings without child mappings, extract should return a complete object
13707
- - When both extract and mappings are defined for objects, extract is applied first
13732
+ - An `object` row takes `extract` (to copy a whole object) or child `mappings`, not
13733
+ both: a row with both fails with 422 (`"extract" should not be present if
13734
+ "mappings" field is present`). A `buildArrayHelper` entry is different: there
13735
+ `extract` and `mappings` work together.
13708
13736
  - The root is the record as it arrives: an object record roots at `$.field`; a
13709
13737
  grouped record (an array of rows — grouped exports, file key columns, NetSuite
13710
13738
  grouped saved searches) roots at the array, so its rows are addressed as
@@ -15119,10 +15147,11 @@ components:
15119
15147
  ALWAYS reference the `record` root regardless of
15120
15148
  `inputContext` — only JSONPath anchoring flips.
15121
15149
  - |-
15122
- In `envelope` mode a `modify` transform merges its mapped
15123
- fields into `record` and keeps the rest of the envelope
15124
- around it; a `create` transform returns only the mapped
15125
- fields, as a bare record.
15150
+ In `envelope` mode the output is still a bare record: a
15151
+ `modify` transform returns the record with its mapped
15152
+ fields merged in (no `record` wrapper, no `job` or
15153
+ `settings` keys), and a `create` transform returns only
15154
+ the mapped fields.
15126
15155
  - |-
15127
15156
  Emit `inputContext` explicitly on new v2 transforms:
15128
15157
  unset is read as `record`, but stating it makes the
@@ -17475,11 +17504,14 @@ components:
17475
17504
  type: object
17476
17505
  description: |-
17477
17506
  Delta window for this preview. Without it, a document preview renders
17478
- `{{lastExportDateTime}}` and `{{currentExportDateTime}}` as empty strings (observed on
17479
- HTTP and RDBMS exports), so the preview doesn't reflect the export's delta window. On an
17480
- HTTP export these strings are substituted exactly as given; other adaptors weren't
17481
- checked. On an export without `delta.dateFormat`, a real run renders both as ISO 8601 UTC
17482
- with milliseconds, so pass them in that form to preview the request such a run would send.
17507
+ `{{lastExportDateTime}}` and `{{currentExportDateTime}}` empty, so the preview doesn't
17508
+ reflect the export's delta window: an HTTP request gets empty strings, and an RDBMS
17509
+ query gets empty, unquoted text, so a delta query fails to parse (observed on Snowflake;
17510
+ `delta.startDate` doesn't set them either). With it, an HTTP export inserts each value
17511
+ exactly as given, and an RDBMS query receives each wrapped in single quotes
17512
+ (`'2026-01-15T00:00:00.000Z'`, observed on Snowflake); other adaptors weren't checked.
17513
+ On an export without `delta.dateFormat`, a real run renders both as ISO 8601 UTC with
17514
+ milliseconds, so pass them in that form to preview the request such a run would send.
17483
17515
  properties:
17484
17516
  currentExportDateTime:
17485
17517
  type: string
@@ -1938,13 +1938,14 @@ components:
1938
1938
  type: string
1939
1939
  description: |
1940
1940
  Source expression. Accepts:
1941
- - JSONPath starting with `$.` (e.g. `$.customer.firstName`).
1941
+ - A dot path from the record root (e.g. `email`, `address.city`), read from the
1942
+ incoming record. A path that matches no field writes nothing.
1942
1943
  - Handlebars template (contains `{{`) for concatenation /
1943
1944
  formatting / conditional logic (e.g.
1944
1945
  `{{record.firstName}} {{record.lastName}}`).
1945
- - A literal string (any value not starting with `$.` and not
1946
- containing `{{`) — treated as a hardcoded value.
1947
1946
 
1947
+ A `$.` JSONPath (the Mapper 2.0 `mappings` syntax) reads nothing here, and a bare
1948
+ string is read as a field path, not a constant: set constants in `hardCodedValue`.
1948
1949
  Omit when using `hardCodedValue`.
1949
1950
  examples:
1950
1951
  - address.city
@@ -1955,9 +1956,9 @@ components:
1955
1956
  description: Static value written to `generate` instead of extracting from the source record.
1956
1957
  x-celigo-ai-guidance:
1957
1958
  - |-
1958
- Static value written verbatim. Equivalent to setting ``extract``
1959
- to a literal string; choose whichever reads more clearly. Mutually
1960
- exclusive with ``extract``.
1959
+ Static value written verbatim. Use it for every constant: a bare
1960
+ string in ``extract`` is read as a field path. Mutually exclusive
1961
+ with ``extract``.
1961
1962
  dataType:
1962
1963
  type: string
1963
1964
  enum:
package/dist/import.yml CHANGED
@@ -1978,6 +1978,12 @@ components:
1978
1978
  Avoid bare ``{{{jsonSerialize record}}}`` with no wrapper — leave the field undefined instead.
1979
1979
  Also avoid wrapping a single post-mapped scalar field in ``jsonSerialize`` (e.g.
1980
1980
  ``{{{jsonSerialize record.<scalar>}}}``) — that pattern is brittle.
1981
+ - |-
1982
+ In a JSON body, write a string value with double braces inside the quotes
1983
+ (``"{{record.name}}"``): double braces JSON-escape the value at run time, with no HTML
1984
+ escaping. Triple braces insert the raw text, so a value holding a double quote,
1985
+ backslash, newline or tab fails that record with 422 ``invalid_json`` before anything
1986
+ is sent.
1981
1987
  - |-
1982
1988
  Every request context carries two data roots: ``data`` — the list of records in
1983
1989
  the request, always present (Pattern B) — and ONE shape-specific root that follows
@@ -2107,10 +2113,12 @@ components:
2107
2113
  is almost certainly the "leave body undefined" case (the
2108
2114
  destination just wants the mapped record as JSON) or Pattern C
2109
2115
  (use ``{{sku}}`` / ``{{quantity}}`` directly without
2110
- ``jsonSerialize`` inside a per-message envelope). Plain
2111
- ``{{{record.<field>}}}`` WITHOUT ``jsonSerialize`` is fine for
2112
- embedding a scalar into a string literal; the anti-pattern is
2113
- specifically the ``jsonSerialize`` wrap.
2116
+ ``jsonSerialize`` inside a per-message envelope). To embed a
2117
+ scalar in a JSON string literal, use double braces inside the
2118
+ quotes (``"{{record.<field>}}"``) WITHOUT ``jsonSerialize``;
2119
+ triple braces there fail on a quote, backslash, newline or tab
2120
+ in the value. The anti-pattern is specifically the
2121
+ ``jsonSerialize`` wrap.
2114
2122
  - |-
2115
2123
  ## Multipart/form-data uploads are a different body contract
2116
2124
 
@@ -5188,8 +5196,10 @@ components:
5188
5196
  `extract` to pick the column when the query returns multiple.
5189
5197
  Inject values from the incoming record with Handlebars and the
5190
5198
  `record.` prefix — double braces for strings, which the platform
5191
- quotes and escapes, and triple braces for numbers:
5192
- `SELECT id FROM users WHERE email = {{record.email}}`.
5199
+ quotes, escaping their apostrophes, and triple braces for numbers:
5200
+ `SELECT id FROM users WHERE email = {{record.email}}`. On Snowflake
5201
+ the quoting leaves backslashes, which Snowflake reads as escape
5202
+ sequences (see `query`).
5193
5203
  extract:
5194
5204
  type: string
5195
5205
  description: |
@@ -5237,10 +5247,11 @@ components:
5237
5247
  description: |-
5238
5248
  SQL statements to execute; required when queryType is `["per_record"]`, `["per_page"]`, or `["first_page"]`, and typically contains a single statement.
5239
5249
  Each element is a complete SQL statement as a plain string — never a single bare string and never an array of objects (objects cause a Cast error).
5240
- Inject values from the incoming record with Handlebars using the `record.` prefix: double braces for strings and dates (`{{record.name}}`; the platform quotes and escapes the value) and triple braces for numbers (`{{{record.quantity}}}`).
5250
+ Inject values from the incoming record with Handlebars using the `record.` prefix: double braces for strings and dates (`{{record.name}}`; the platform quotes the value and escapes its apostrophes) and triple braces for numbers (`{{{record.quantity}}}`).
5241
5251
  Rendering is strict: a reference the render model cannot resolve (a bare `{{name}}` without prefix, or `record.*` when the arriving record is a grouped array) fails the step with `cannot_evaluate_handlebars` — it does not render an empty value.
5242
5252
  `record` and `rows` are aliases chosen by the arriving data's shape: an object record binds `record` (`rows` undefined); a grouped array-record (e.g. upstream `groupByFields`) binds `rows` (`record` undefined) — address grouped rows as `{{rows.0.field}}` or iterate `{{#each rows}}`.
5243
- Double braces (`{{record.field}}`) output the value wrapped in single quotes with embedded quotes doubled, while triple braces output it raw; block helpers such as `{{#each}}` and `{{#if}}` use double braces as normal.
5253
+ Double braces (`{{record.field}}`) output a string value wrapped in single quotes with embedded quotes doubled, while triple braces output it raw; block helpers such as `{{#each}}` and `{{#if}}` use double braces as normal. In Snowflake queries a JSON number or boolean renders bare under double braces too (observed in export queries).
5254
+ On Snowflake, the quoting leaves backslashes, which Snowflake reads as escape sequences: a double-brace value holding a backslash arrives changed, and `PARSE_JSON({{jsonSerialize …}})` fails on a double quote or line break in the data (observed in export queries). Pass such values in a dollar-quoted constant with triple braces (`$${{{record.field}}}$$`), which Snowflake reads as is, but only when the value can't contain `$$`: a `$$` in it ends the constant, and the rest is read as SQL.
5244
5255
  x-celigo-ai-guidance:
5245
5256
  - |-
5246
5257
  Use Handlebars to inject values from incoming records.
@@ -5268,14 +5279,18 @@ components:
5268
5279
  - **Double-brace `{{record.field}}` vs. triple-brace `{{{record.field}}}`
5269
5280
  is a QUOTING CHOICE, not a syntax rule.** In RDBMS context the
5270
5281
  platform's Handlebars renderer treats double-brace specially: it
5271
- auto-wraps the value as a SQL string literal (single-quoted, with
5272
- embedded quotes escaped). Triple-brace emits the raw value with
5273
- no quoting.
5282
+ wraps a string value as a SQL string literal (single-quoted, with
5283
+ its apostrophes escaped), and in Snowflake export queries a number
5284
+ or boolean rendered bare, whether a JSON value or a numeric
5285
+ helper's result (`{{add 2 3}}`). Triple-brace emits the raw value
5286
+ with no quoting. In the same queries the wrapping was also seen on
5287
+ string helper output (`dateFormat`, `jsonSerialize`) and on
5288
+ `{{this}}` inside `{{#each}}`.
5274
5289
 
5275
5290
  - `{{record.name}}` → `'Alice'` (auto-single-quoted, embedded `'` doubled to `''`)
5276
- - `{{{record.name}}}` → `Alice` (raw, no quoting — you must add your own)
5277
- - `{{record.qty}}` → `'5'` (numbers are also string-wrapped under double-brace)
5278
- - `{{{record.qty}}}` → `5` (numeric literal — what you usually want for INT columns)
5291
+ - `{{{record.name}}}` → `Alice` (raw — never wrap it in single quotes of your own: the first apostrophe in the data ends the literal)
5292
+ - `{{record.qty}}` → `'5'` when `qty` arrives as the string `"5"`; a JSON number rendered bare in Snowflake export queries
5293
+ - `{{{record.qty}}}` → `5` (numeric literal either way — what you usually want for INT columns)
5279
5294
 
5280
5295
  Pick by what the SQL needs at that slot:
5281
5296
 
@@ -5285,8 +5300,21 @@ components:
5285
5300
  | Numeric column value (INT, DECIMAL, ...) | `{{{record.field}}}` |
5286
5301
  | Stored procedure raw arg (already typed) | `{{{record.field}}}` |
5287
5302
  | Identifier (table/column name) | `{{{record.field}}}` |
5288
- | JSON literal (`PARSE_JSON`/JSONB) | `{{jsonSerialize record.subobject}}` (renders the JSON as a quoted string) |
5289
-
5303
+ | JSON literal, Snowflake (`PARSE_JSON`) | `PARSE_JSON($${{{jsonSerialize record.subobject}}}$$)` (a dollar-quoted constant, read as is; only for data that can't contain `$$`, which ends it) |
5304
+ | JSON literal, PostgreSQL (`JSONB`) | `{{jsonSerialize record.subobject}}` (renders the JSON as a quoted string; not yet verified on PostgreSQL) |
5305
+
5306
+ - **Snowflake reads backslashes as escapes.** The double-brace
5307
+ quoting doubles embedded apostrophes but leaves backslashes, and
5308
+ Snowflake interprets backslash sequences inside a single-quoted
5309
+ literal: a value holding `C:\temp` arrives with a tab in it, with
5310
+ no error, and `PARSE_JSON({{jsonSerialize …}})` fails with
5311
+ `Error parsing JSON` whenever a string in the object holds a double
5312
+ quote or a line break, because `jsonSerialize` escapes those with
5313
+ backslashes (observed in export queries). For values that can hold
5314
+ these characters, use a dollar-quoted constant with triple braces
5315
+ (`$${{{record.field}}}$$`), which Snowflake reads as is, but only
5316
+ when the value can't contain `$$`: a `$$` in it ends the constant,
5317
+ and the rest is read as SQL.
5290
5318
  - **Block helpers** (`{{#each}}`, `{{#if}}`, `{{/each}}`,
5291
5319
  `{{#unless}}`) use double braces as normal — they emit no value.
5292
5320
  - **Nested fields**: `{{record.properties.email}}` (auto-quoted)
@@ -5300,7 +5328,7 @@ components:
5300
5328
  - UPSERT (MySQL): `["INSERT INTO users (id, name) VALUES ({{{record.id}}}, {{record.name}}) ON DUPLICATE KEY UPDATE name = {{record.name}}"]`
5301
5329
  - MERGE (Snowflake): `["MERGE INTO target USING (SELECT {{record.email}} AS email) AS src ON target.email = src.email WHEN MATCHED THEN UPDATE SET name = {{record.name}}"]`
5302
5330
  - Stored procedure (raw args): `["call netsuite.transformation_data_import({{record.record_type}}, 20)"]`
5303
- - JSON literal column (Snowflake VARIANT): `["INSERT INTO events (payload) SELECT PARSE_JSON({{jsonSerialize record.financialEvents}})"]`
5331
+ - JSON literal column (Snowflake VARIANT; the data must not contain `$$`): `["INSERT INTO events (payload) SELECT PARSE_JSON($${{{jsonSerialize record.financialEvents}}}$$)"]`
5304
5332
  - Per-page batch (different Handlebars context — see `queryType: per_page` below): `["{{#each batch_of_records}}UPDATE staging SET done=1 WHERE id={{{this.record.id}}};{{/each}}"]`
5305
5333
  examples:
5306
5334
  - - INSERT INTO orders (id, total) VALUES ({{{record.id}}}, {{{record.total}}})
@@ -12655,7 +12683,8 @@ components:
12655
12683
  fields. There is no separate `date` enum value.
12656
12684
 
12657
12685
  **Complex Types (require additional configuration)**
12658
- - `object`: Creates a nested object. REQUIRES child mappings in the 'mappings' array
12686
+ - `object`: Creates a nested object from child mappings in the 'mappings' array, or
12687
+ copies a whole object with `extract` (one or the other, not both)
12659
12688
 
12660
12689
  **Array Types**
12661
12690
  - `stringarray`: Array of strings
@@ -12703,7 +12732,7 @@ components:
12703
12732
  string: Text values; converts other types to their string representation.
12704
12733
  number: Numeric values; attempts conversion from strings.
12705
12734
  boolean: True/false values; converts truthy/falsy values.
12706
- object: Nested object that requires child mappings in the `mappings` array.
12735
+ object: Nested object built from child `mappings`, or copied whole with `extract` (not both).
12707
12736
  stringarray: Array of string values.
12708
12737
  numberarray: Array of numeric values.
12709
12738
  booleanarray: Array of boolean values.
@@ -12781,7 +12810,10 @@ components:
12781
12810
  - JSON path patterns ALWAYS execute from the TOP-LEVEL root of the input record
12782
12811
  - The system maintains this context even in deeply nested mappings
12783
12812
  - For object mappings without child mappings, extract should return a complete object
12784
- - When both extract and mappings are defined for objects, extract is applied first
12813
+ - An `object` row takes `extract` (to copy a whole object) or child `mappings`, not
12814
+ both: a row with both fails with 422 (`"extract" should not be present if
12815
+ "mappings" field is present`). A `buildArrayHelper` entry is different: there
12816
+ `extract` and `mappings` work together.
12785
12817
  - The root is the record as it arrives: an object record roots at `$.field`; a
12786
12818
  grouped record (an array of rows — grouped exports, file key columns, NetSuite
12787
12819
  grouped saved searches) roots at the array, so its rows are addressed as
@@ -13735,7 +13767,8 @@ components:
13735
13767
  fields. There is no separate `date` enum value.
13736
13768
 
13737
13769
  **Complex Types (require additional configuration)**
13738
- - `object`: Creates a nested object. REQUIRES child mappings in the 'mappings' array
13770
+ - `object`: Creates a nested object from child mappings in the 'mappings' array, or
13771
+ copies a whole object with `extract` (one or the other, not both)
13739
13772
 
13740
13773
  **Array Types**
13741
13774
  - `stringarray`: Array of strings
@@ -13783,7 +13816,7 @@ components:
13783
13816
  string: Text values; converts other types to their string representation.
13784
13817
  number: Numeric values; attempts conversion from strings.
13785
13818
  boolean: True/false values; converts truthy/falsy values.
13786
- object: Nested object that requires child mappings in the `mappings` array.
13819
+ object: Nested object built from child `mappings`, or copied whole with `extract` (not both).
13787
13820
  stringarray: Array of string values.
13788
13821
  numberarray: Array of numeric values.
13789
13822
  booleanarray: Array of boolean values.
@@ -13861,7 +13894,10 @@ components:
13861
13894
  - JSON path patterns ALWAYS execute from the TOP-LEVEL root of the input record
13862
13895
  - The system maintains this context even in deeply nested mappings
13863
13896
  - For object mappings without child mappings, extract should return a complete object
13864
- - When both extract and mappings are defined for objects, extract is applied first
13897
+ - An `object` row takes `extract` (to copy a whole object) or child `mappings`, not
13898
+ both: a row with both fails with 422 (`"extract" should not be present if
13899
+ "mappings" field is present`). A `buildArrayHelper` entry is different: there
13900
+ `extract` and `mappings` work together.
13865
13901
  - The root is the record as it arrives: an object record roots at `$.field`; a
13866
13902
  grouped record (an array of rows — grouped exports, file key columns, NetSuite
13867
13903
  grouped saved searches) roots at the array, so its rows are addressed as
@@ -15000,10 +15036,11 @@ components:
15000
15036
  ALWAYS reference the `record` root regardless of
15001
15037
  `inputContext` — only JSONPath anchoring flips.
15002
15038
  - |-
15003
- In `envelope` mode a `modify` transform merges its mapped
15004
- fields into `record` and keeps the rest of the envelope
15005
- around it; a `create` transform returns only the mapped
15006
- fields, as a bare record.
15039
+ In `envelope` mode the output is still a bare record: a
15040
+ `modify` transform returns the record with its mapped
15041
+ fields merged in (no `record` wrapper, no `job` or
15042
+ `settings` keys), and a `create` transform returns only
15043
+ the mapped fields.
15007
15044
  - |-
15008
15045
  Emit `inputContext` explicitly on new v2 transforms:
15009
15046
  unset is read as `record`, but stating it makes the
@@ -15183,13 +15220,14 @@ components:
15183
15220
  type: string
15184
15221
  description: |
15185
15222
  Source expression. Accepts:
15186
- - JSONPath starting with `$.` (e.g. `$.customer.firstName`).
15223
+ - A dot path from the record root (e.g. `email`, `address.city`), read from the
15224
+ incoming record. A path that matches no field writes nothing.
15187
15225
  - Handlebars template (contains `{{`) for concatenation /
15188
15226
  formatting / conditional logic (e.g.
15189
15227
  `{{record.firstName}} {{record.lastName}}`).
15190
- - A literal string (any value not starting with `$.` and not
15191
- containing `{{`) — treated as a hardcoded value.
15192
15228
 
15229
+ A `$.` JSONPath (the Mapper 2.0 `mappings` syntax) reads nothing here, and a bare
15230
+ string is read as a field path, not a constant: set constants in `hardCodedValue`.
15193
15231
  Omit when using `hardCodedValue`.
15194
15232
  examples:
15195
15233
  - address.city
@@ -15200,9 +15238,9 @@ components:
15200
15238
  description: Static value written to `generate` instead of extracting from the source record.
15201
15239
  x-celigo-ai-guidance:
15202
15240
  - |-
15203
- Static value written verbatim. Equivalent to setting ``extract``
15204
- to a literal string; choose whichever reads more clearly. Mutually
15205
- exclusive with ``extract``.
15241
+ Static value written verbatim. Use it for every constant: a bare
15242
+ string in ``extract`` is read as a field path. Mutually exclusive
15243
+ with ``extract``.
15206
15244
  dataType:
15207
15245
  type: string
15208
15246
  enum:
@@ -15965,7 +16003,10 @@ components:
15965
16003
  type: string
15966
16004
  format: objectId
15967
16005
  x-celigo-refModel: connectors
15968
- description: Connector this import was created from, set when the import is part of an installed integration app.
16006
+ description: |-
16007
+ Connector this import was created from, set when the import is part of an installed
16008
+ integration app. The app's install sets it: a create that sends it is refused with 403
16009
+ ("Cannot create an Integration App resource").
15969
16010
  examples:
15970
16011
  - 60a2c4e6f321d800129a1a3c
15971
16012
  adaptorType:
@@ -16507,7 +16548,8 @@ components:
16507
16548
  description: |-
16508
16549
  Custom JavaScript hooks that run at fixed points in the import lifecycle for
16509
16550
  transformations, validation, and custom result handling beyond what configuration alone
16510
- can express.
16551
+ can express. A hook name not listed here (an export's `preSavePage`, for example) is
16552
+ dropped on save without an error, so read `hooks` back after saving.
16511
16553
  x-celigo-ai-guidance:
16512
16554
  - |-
16513
16555
  JavaScript hook references attached to lifecycle stages of the import.
package/dist/script.yml CHANGED
@@ -376,7 +376,8 @@ paths:
376
376
  `nextPageURL` means that slice held nothing while the rest of the window is still
377
377
  unread — follow the cursor until a response arrives without one. Only an empty
378
378
  `logs` array with no `nextPageURL` means the window holds no entries. To read a
379
- known run in one call, set `time_lte` a few seconds after the run ended.
379
+ known run in one call, set `time_lte` a few seconds after the run ended and
380
+ `time_gt` just before it started (`time_lte` needs `time_gt`).
380
381
  tags:
381
382
  - Scripts
382
383
  operationId: getScriptLogs
@@ -394,7 +395,8 @@ paths:
394
395
  required: false
395
396
  description: |-
396
397
  Upper bound of the time window (inclusive), as epoch milliseconds. Defaults to now if
397
- omitted. Reading starts here and proceeds backward.
398
+ omitted. Reading starts here and proceeds backward. Send it with `time_gt`: `time_lte`
399
+ alone fails with 422 ("Invalid or Missing Field: time_gt").
398
400
  schema:
399
401
  type: integer
400
402
  format: int64
@@ -513,6 +515,17 @@ paths:
513
515
  $ref: '#/components/responses/401-unauthorized'
514
516
  '404':
515
517
  $ref: '#/components/responses/404-not-found'
518
+ '422':
519
+ description: Invalid time window — `time_lte` without `time_gt`.
520
+ content:
521
+ application/json:
522
+ schema:
523
+ $ref: '#/components/schemas/Error'
524
+ examples:
525
+ missing_time_gt:
526
+ value:
527
+ errors:
528
+ - message: 'Invalid or Missing Field: time_gt'
516
529
  delete:
517
530
  x-internal: false
518
531
  operationId: deleteScriptLogs
package/dist/tool.yml CHANGED
@@ -2426,8 +2426,11 @@ paths:
2426
2426
  input, and its `response` stage holds the saved records. Remove `mockOutput` from the export
2427
2427
  to call the source again. `POST /v1/tools/{_id}/invoke` neither reads nor writes it. Imports
2428
2428
  never send; each returns its saved `mockResponse`, or a placeholder response when none is
2429
- saved (see `mockResponse` on imports). A second test run started while one is still running
2430
- is refused with `test_run_not_allowed`.
2429
+ saved (see `mockResponse` on imports). A test run is keyed by the request's `triggeredAt`:
2430
+ one sent with a `triggeredAt` that an earlier test run of the tool already used is refused
2431
+ with 400 `test_run_not_allowed` ("Cannot run the test tool when it is already in the running
2432
+ state."), even after that run has finished. Runs with different `triggeredAt` values run at
2433
+ the same time, each returning its own result.
2431
2434
 
2432
2435
  Test runs are a separate, short-lived history from normal runs — capture
2433
2436
  any follow-up step or log details soon after the run completes.
@@ -2463,6 +2466,13 @@ paths:
2463
2466
  the tool's saved `input.mockInput` — when this key is
2464
2467
  absent, the input step receives an empty record.
2465
2468
  additionalProperties: true
2469
+ triggeredAt:
2470
+ type: string
2471
+ format: date-time
2472
+ description: |-
2473
+ Identifies the test run; send the current time. A value an earlier
2474
+ test run of the tool already used is refused with 400
2475
+ `test_run_not_allowed`.
2466
2476
  additionalProperties: true
2467
2477
  x-celigo-ai-guidance:
2468
2478
  - 'Always wrap the test input as {"input": {...}} — a bare input object is ignored and the input step receives an empty record, which fails with tool_input_schema_validation_failed when the tool''s input schema has required fields.'
@@ -2554,7 +2564,8 @@ paths:
2554
2564
  description: |-
2555
2565
  The run was refused before any step ran. A Tool with no steps fails with
2556
2566
  `tool_empty_router`, and one whose branches don't all merge back with
2557
- `tool_dangling_branch`; re-running the same document fails the same way.
2567
+ `tool_dangling_branch`; re-running the same document fails the same way. A
2568
+ `triggeredAt` an earlier test run already used fails with `test_run_not_allowed`.
2558
2569
  content:
2559
2570
  application/json:
2560
2571
  schema:
@@ -3576,7 +3587,8 @@ components:
3576
3587
  fields. There is no separate `date` enum value.
3577
3588
 
3578
3589
  **Complex Types (require additional configuration)**
3579
- - `object`: Creates a nested object. REQUIRES child mappings in the 'mappings' array
3590
+ - `object`: Creates a nested object from child mappings in the 'mappings' array, or
3591
+ copies a whole object with `extract` (one or the other, not both)
3580
3592
 
3581
3593
  **Array Types**
3582
3594
  - `stringarray`: Array of strings
@@ -3624,7 +3636,7 @@ components:
3624
3636
  string: Text values; converts other types to their string representation.
3625
3637
  number: Numeric values; attempts conversion from strings.
3626
3638
  boolean: True/false values; converts truthy/falsy values.
3627
- object: Nested object that requires child mappings in the `mappings` array.
3639
+ object: Nested object built from child `mappings`, or copied whole with `extract` (not both).
3628
3640
  stringarray: Array of string values.
3629
3641
  numberarray: Array of numeric values.
3630
3642
  booleanarray: Array of boolean values.
@@ -3702,7 +3714,10 @@ components:
3702
3714
  - JSON path patterns ALWAYS execute from the TOP-LEVEL root of the input record
3703
3715
  - The system maintains this context even in deeply nested mappings
3704
3716
  - For object mappings without child mappings, extract should return a complete object
3705
- - When both extract and mappings are defined for objects, extract is applied first
3717
+ - An `object` row takes `extract` (to copy a whole object) or child `mappings`, not
3718
+ both: a row with both fails with 422 (`"extract" should not be present if
3719
+ "mappings" field is present`). A `buildArrayHelper` entry is different: there
3720
+ `extract` and `mappings` work together.
3706
3721
  - The root is the record as it arrives: an object record roots at `$.field`; a
3707
3722
  grouped record (an array of rows — grouped exports, file key columns, NetSuite
3708
3723
  grouped saved searches) roots at the array, so its rows are addressed as
@@ -4656,7 +4671,8 @@ components:
4656
4671
  fields. There is no separate `date` enum value.
4657
4672
 
4658
4673
  **Complex Types (require additional configuration)**
4659
- - `object`: Creates a nested object. REQUIRES child mappings in the 'mappings' array
4674
+ - `object`: Creates a nested object from child mappings in the 'mappings' array, or
4675
+ copies a whole object with `extract` (one or the other, not both)
4660
4676
 
4661
4677
  **Array Types**
4662
4678
  - `stringarray`: Array of strings
@@ -4704,7 +4720,7 @@ components:
4704
4720
  string: Text values; converts other types to their string representation.
4705
4721
  number: Numeric values; attempts conversion from strings.
4706
4722
  boolean: True/false values; converts truthy/falsy values.
4707
- object: Nested object that requires child mappings in the `mappings` array.
4723
+ object: Nested object built from child `mappings`, or copied whole with `extract` (not both).
4708
4724
  stringarray: Array of string values.
4709
4725
  numberarray: Array of numeric values.
4710
4726
  booleanarray: Array of boolean values.
@@ -4782,7 +4798,10 @@ components:
4782
4798
  - JSON path patterns ALWAYS execute from the TOP-LEVEL root of the input record
4783
4799
  - The system maintains this context even in deeply nested mappings
4784
4800
  - For object mappings without child mappings, extract should return a complete object
4785
- - When both extract and mappings are defined for objects, extract is applied first
4801
+ - An `object` row takes `extract` (to copy a whole object) or child `mappings`, not
4802
+ both: a row with both fails with 422 (`"extract" should not be present if
4803
+ "mappings" field is present`). A `buildArrayHelper` entry is different: there
4804
+ `extract` and `mappings` work together.
4786
4805
  - The root is the record as it arrives: an object record roots at `$.field`; a
4787
4806
  grouped record (an array of rows — grouped exports, file key columns, NetSuite
4788
4807
  grouped saved searches) roots at the array, so its rows are addressed as
@@ -6197,10 +6216,11 @@ components:
6197
6216
  ALWAYS reference the `record` root regardless of
6198
6217
  `inputContext` — only JSONPath anchoring flips.
6199
6218
  - |-
6200
- In `envelope` mode a `modify` transform merges its mapped
6201
- fields into `record` and keeps the rest of the envelope
6202
- around it; a `create` transform returns only the mapped
6203
- fields, as a bare record.
6219
+ In `envelope` mode the output is still a bare record: a
6220
+ `modify` transform returns the record with its mapped
6221
+ fields merged in (no `record` wrapper, no `job` or
6222
+ `settings` keys), and a `create` transform returns only
6223
+ the mapped fields.
6204
6224
  - |-
6205
6225
  Emit `inputContext` explicitly on new v2 transforms:
6206
6226
  unset is read as `record`, but stating it makes the
@@ -13767,6 +13787,12 @@ components:
13767
13787
  Avoid bare ``{{{jsonSerialize record}}}`` with no wrapper — leave the field undefined instead.
13768
13788
  Also avoid wrapping a single post-mapped scalar field in ``jsonSerialize`` (e.g.
13769
13789
  ``{{{jsonSerialize record.<scalar>}}}``) — that pattern is brittle.
13790
+ - |-
13791
+ In a JSON body, write a string value with double braces inside the quotes
13792
+ (``"{{record.name}}"``): double braces JSON-escape the value at run time, with no HTML
13793
+ escaping. Triple braces insert the raw text, so a value holding a double quote,
13794
+ backslash, newline or tab fails that record with 422 ``invalid_json`` before anything
13795
+ is sent.
13770
13796
  - |-
13771
13797
  Every request context carries two data roots: ``data`` — the list of records in
13772
13798
  the request, always present (Pattern B) — and ONE shape-specific root that follows
@@ -13896,10 +13922,12 @@ components:
13896
13922
  is almost certainly the "leave body undefined" case (the
13897
13923
  destination just wants the mapped record as JSON) or Pattern C
13898
13924
  (use ``{{sku}}`` / ``{{quantity}}`` directly without
13899
- ``jsonSerialize`` inside a per-message envelope). Plain
13900
- ``{{{record.<field>}}}`` WITHOUT ``jsonSerialize`` is fine for
13901
- embedding a scalar into a string literal; the anti-pattern is
13902
- specifically the ``jsonSerialize`` wrap.
13925
+ ``jsonSerialize`` inside a per-message envelope). To embed a
13926
+ scalar in a JSON string literal, use double braces inside the
13927
+ quotes (``"{{record.<field>}}"``) WITHOUT ``jsonSerialize``;
13928
+ triple braces there fail on a quote, backslash, newline or tab
13929
+ in the value. The anti-pattern is specifically the
13930
+ ``jsonSerialize`` wrap.
13903
13931
  - |-
13904
13932
  ## Multipart/form-data uploads are a different body contract
13905
13933
 
@@ -16701,8 +16729,10 @@ components:
16701
16729
  `extract` to pick the column when the query returns multiple.
16702
16730
  Inject values from the incoming record with Handlebars and the
16703
16731
  `record.` prefix — double braces for strings, which the platform
16704
- quotes and escapes, and triple braces for numbers:
16705
- `SELECT id FROM users WHERE email = {{record.email}}`.
16732
+ quotes, escaping their apostrophes, and triple braces for numbers:
16733
+ `SELECT id FROM users WHERE email = {{record.email}}`. On Snowflake
16734
+ the quoting leaves backslashes, which Snowflake reads as escape
16735
+ sequences (see `query`).
16706
16736
  extract:
16707
16737
  type: string
16708
16738
  description: |
@@ -16750,10 +16780,11 @@ components:
16750
16780
  description: |-
16751
16781
  SQL statements to execute; required when queryType is `["per_record"]`, `["per_page"]`, or `["first_page"]`, and typically contains a single statement.
16752
16782
  Each element is a complete SQL statement as a plain string — never a single bare string and never an array of objects (objects cause a Cast error).
16753
- Inject values from the incoming record with Handlebars using the `record.` prefix: double braces for strings and dates (`{{record.name}}`; the platform quotes and escapes the value) and triple braces for numbers (`{{{record.quantity}}}`).
16783
+ Inject values from the incoming record with Handlebars using the `record.` prefix: double braces for strings and dates (`{{record.name}}`; the platform quotes the value and escapes its apostrophes) and triple braces for numbers (`{{{record.quantity}}}`).
16754
16784
  Rendering is strict: a reference the render model cannot resolve (a bare `{{name}}` without prefix, or `record.*` when the arriving record is a grouped array) fails the step with `cannot_evaluate_handlebars` — it does not render an empty value.
16755
16785
  `record` and `rows` are aliases chosen by the arriving data's shape: an object record binds `record` (`rows` undefined); a grouped array-record (e.g. upstream `groupByFields`) binds `rows` (`record` undefined) — address grouped rows as `{{rows.0.field}}` or iterate `{{#each rows}}`.
16756
- Double braces (`{{record.field}}`) output the value wrapped in single quotes with embedded quotes doubled, while triple braces output it raw; block helpers such as `{{#each}}` and `{{#if}}` use double braces as normal.
16786
+ Double braces (`{{record.field}}`) output a string value wrapped in single quotes with embedded quotes doubled, while triple braces output it raw; block helpers such as `{{#each}}` and `{{#if}}` use double braces as normal. In Snowflake queries a JSON number or boolean renders bare under double braces too (observed in export queries).
16787
+ On Snowflake, the quoting leaves backslashes, which Snowflake reads as escape sequences: a double-brace value holding a backslash arrives changed, and `PARSE_JSON({{jsonSerialize …}})` fails on a double quote or line break in the data (observed in export queries). Pass such values in a dollar-quoted constant with triple braces (`$${{{record.field}}}$$`), which Snowflake reads as is, but only when the value can't contain `$$`: a `$$` in it ends the constant, and the rest is read as SQL.
16757
16788
  x-celigo-ai-guidance:
16758
16789
  - |-
16759
16790
  Use Handlebars to inject values from incoming records.
@@ -16781,14 +16812,18 @@ components:
16781
16812
  - **Double-brace `{{record.field}}` vs. triple-brace `{{{record.field}}}`
16782
16813
  is a QUOTING CHOICE, not a syntax rule.** In RDBMS context the
16783
16814
  platform's Handlebars renderer treats double-brace specially: it
16784
- auto-wraps the value as a SQL string literal (single-quoted, with
16785
- embedded quotes escaped). Triple-brace emits the raw value with
16786
- no quoting.
16815
+ wraps a string value as a SQL string literal (single-quoted, with
16816
+ its apostrophes escaped), and in Snowflake export queries a number
16817
+ or boolean rendered bare, whether a JSON value or a numeric
16818
+ helper's result (`{{add 2 3}}`). Triple-brace emits the raw value
16819
+ with no quoting. In the same queries the wrapping was also seen on
16820
+ string helper output (`dateFormat`, `jsonSerialize`) and on
16821
+ `{{this}}` inside `{{#each}}`.
16787
16822
 
16788
16823
  - `{{record.name}}` → `'Alice'` (auto-single-quoted, embedded `'` doubled to `''`)
16789
- - `{{{record.name}}}` → `Alice` (raw, no quoting — you must add your own)
16790
- - `{{record.qty}}` → `'5'` (numbers are also string-wrapped under double-brace)
16791
- - `{{{record.qty}}}` → `5` (numeric literal — what you usually want for INT columns)
16824
+ - `{{{record.name}}}` → `Alice` (raw — never wrap it in single quotes of your own: the first apostrophe in the data ends the literal)
16825
+ - `{{record.qty}}` → `'5'` when `qty` arrives as the string `"5"`; a JSON number rendered bare in Snowflake export queries
16826
+ - `{{{record.qty}}}` → `5` (numeric literal either way — what you usually want for INT columns)
16792
16827
 
16793
16828
  Pick by what the SQL needs at that slot:
16794
16829
 
@@ -16798,8 +16833,21 @@ components:
16798
16833
  | Numeric column value (INT, DECIMAL, ...) | `{{{record.field}}}` |
16799
16834
  | Stored procedure raw arg (already typed) | `{{{record.field}}}` |
16800
16835
  | Identifier (table/column name) | `{{{record.field}}}` |
16801
- | JSON literal (`PARSE_JSON`/JSONB) | `{{jsonSerialize record.subobject}}` (renders the JSON as a quoted string) |
16802
-
16836
+ | JSON literal, Snowflake (`PARSE_JSON`) | `PARSE_JSON($${{{jsonSerialize record.subobject}}}$$)` (a dollar-quoted constant, read as is; only for data that can't contain `$$`, which ends it) |
16837
+ | JSON literal, PostgreSQL (`JSONB`) | `{{jsonSerialize record.subobject}}` (renders the JSON as a quoted string; not yet verified on PostgreSQL) |
16838
+
16839
+ - **Snowflake reads backslashes as escapes.** The double-brace
16840
+ quoting doubles embedded apostrophes but leaves backslashes, and
16841
+ Snowflake interprets backslash sequences inside a single-quoted
16842
+ literal: a value holding `C:\temp` arrives with a tab in it, with
16843
+ no error, and `PARSE_JSON({{jsonSerialize …}})` fails with
16844
+ `Error parsing JSON` whenever a string in the object holds a double
16845
+ quote or a line break, because `jsonSerialize` escapes those with
16846
+ backslashes (observed in export queries). For values that can hold
16847
+ these characters, use a dollar-quoted constant with triple braces
16848
+ (`$${{{record.field}}}$$`), which Snowflake reads as is, but only
16849
+ when the value can't contain `$$`: a `$$` in it ends the constant,
16850
+ and the rest is read as SQL.
16803
16851
  - **Block helpers** (`{{#each}}`, `{{#if}}`, `{{/each}}`,
16804
16852
  `{{#unless}}`) use double braces as normal — they emit no value.
16805
16853
  - **Nested fields**: `{{record.properties.email}}` (auto-quoted)
@@ -16813,7 +16861,7 @@ components:
16813
16861
  - UPSERT (MySQL): `["INSERT INTO users (id, name) VALUES ({{{record.id}}}, {{record.name}}) ON DUPLICATE KEY UPDATE name = {{record.name}}"]`
16814
16862
  - MERGE (Snowflake): `["MERGE INTO target USING (SELECT {{record.email}} AS email) AS src ON target.email = src.email WHEN MATCHED THEN UPDATE SET name = {{record.name}}"]`
16815
16863
  - Stored procedure (raw args): `["call netsuite.transformation_data_import({{record.record_type}}, 20)"]`
16816
- - JSON literal column (Snowflake VARIANT): `["INSERT INTO events (payload) SELECT PARSE_JSON({{jsonSerialize record.financialEvents}})"]`
16864
+ - JSON literal column (Snowflake VARIANT; the data must not contain `$$`): `["INSERT INTO events (payload) SELECT PARSE_JSON($${{{jsonSerialize record.financialEvents}}}$$)"]`
16817
16865
  - Per-page batch (different Handlebars context — see `queryType: per_page` below): `["{{#each batch_of_records}}UPDATE staging SET done=1 WHERE id={{{this.record.id}}};{{/each}}"]`
16818
16866
  examples:
16819
16867
  - - INSERT INTO orders (id, total) VALUES ({{{record.id}}}, {{{record.total}}})
@@ -24156,13 +24204,14 @@ components:
24156
24204
  type: string
24157
24205
  description: |
24158
24206
  Source expression. Accepts:
24159
- - JSONPath starting with `$.` (e.g. `$.customer.firstName`).
24207
+ - A dot path from the record root (e.g. `email`, `address.city`), read from the
24208
+ incoming record. A path that matches no field writes nothing.
24160
24209
  - Handlebars template (contains `{{`) for concatenation /
24161
24210
  formatting / conditional logic (e.g.
24162
24211
  `{{record.firstName}} {{record.lastName}}`).
24163
- - A literal string (any value not starting with `$.` and not
24164
- containing `{{`) — treated as a hardcoded value.
24165
24212
 
24213
+ A `$.` JSONPath (the Mapper 2.0 `mappings` syntax) reads nothing here, and a bare
24214
+ string is read as a field path, not a constant: set constants in `hardCodedValue`.
24166
24215
  Omit when using `hardCodedValue`.
24167
24216
  examples:
24168
24217
  - address.city
@@ -24173,9 +24222,9 @@ components:
24173
24222
  description: Static value written to `generate` instead of extracting from the source record.
24174
24223
  x-celigo-ai-guidance:
24175
24224
  - |-
24176
- Static value written verbatim. Equivalent to setting ``extract``
24177
- to a literal string; choose whichever reads more clearly. Mutually
24178
- exclusive with ``extract``.
24225
+ Static value written verbatim. Use it for every constant: a bare
24226
+ string in ``extract`` is read as a field path. Mutually exclusive
24227
+ with ``extract``.
24179
24228
  dataType:
24180
24229
  type: string
24181
24230
  enum:
@@ -24938,7 +24987,10 @@ components:
24938
24987
  type: string
24939
24988
  format: objectId
24940
24989
  x-celigo-refModel: connectors
24941
- description: Connector this import was created from, set when the import is part of an installed integration app.
24990
+ description: |-
24991
+ Connector this import was created from, set when the import is part of an installed
24992
+ integration app. The app's install sets it: a create that sends it is refused with 403
24993
+ ("Cannot create an Integration App resource").
24942
24994
  examples:
24943
24995
  - 60a2c4e6f321d800129a1a3c
24944
24996
  adaptorType:
@@ -25480,7 +25532,8 @@ components:
25480
25532
  description: |-
25481
25533
  Custom JavaScript hooks that run at fixed points in the import lifecycle for
25482
25534
  transformations, validation, and custom result handling beyond what configuration alone
25483
- can express.
25535
+ can express. A hook name not listed here (an export's `preSavePage`, for example) is
25536
+ dropped on save without an error, so read `hooks` back after saving.
25484
25537
  x-celigo-ai-guidance:
25485
25538
  - |-
25486
25539
  JavaScript hook references attached to lifecycle stages of the import.
@@ -36498,10 +36551,12 @@ components:
36498
36551
 
36499
36552
  **Delta exports (type: "delta")**
36500
36553
  For delta/incremental exports, do NOT populate a `delta` object inside `rdbms`.
36501
- Instead, use `{{lastExportDateTime}}` or `{{currentExportDateTime}}` directly in the query:
36554
+ Instead, use `{{lastExportDateTime}}` or `{{currentExportDateTime}}` directly in the query, and
36555
+ set the export's top-level `delta.startDate`: without it the first run's window is empty.
36502
36556
  ```json
36503
36557
  {
36504
36558
  "type": "delta",
36559
+ "delta": { "startDate": "2026-01-01T00:00:00.000Z" },
36505
36560
  "rdbms": {
36506
36561
  "query": "SELECT * FROM customers WHERE updatedAt > {{lastExportDateTime}}"
36507
36562
  }
@@ -36574,6 +36629,24 @@ components:
36574
36629
  only — real-time stream listeners (`type` is `stream`) have no SQL query. For delta exports,
36575
36630
  reference {{lastExportDateTime}}/{{currentExportDateTime}} directly in the query rather
36576
36631
  than configuring a separate delta object.
36632
+
36633
+ Double braces render a string as a quoted SQL literal with its apostrophes escaped, and
36634
+ triple braces insert a value raw. Observed in Snowflake queries:
36635
+
36636
+ - String helper output (`dateFormat`, `jsonSerialize`) and both delta variables are
36637
+ quoted the same way; a number or boolean renders bare, whether it is a JSON value or a
36638
+ numeric helper's result (`{{add 2 3}}` renders `5`).
36639
+ - In a run, {{lastExportDateTime}} and {{currentExportDateTime}} arrive as quoted ISO 8601
36640
+ UTC literals with milliseconds (`'2026-01-15T00:00:00.000Z'`), or in `delta.dateFormat`
36641
+ when it is set: add no quotes of your own, and don't parse them with a format mask
36642
+ written for another format.
36643
+ - A preview of an unsaved export document renders both as empty, unquoted text, so a
36644
+ delta query fails to compile there unless the document carries both in `postData`.
36645
+ - The quoting leaves backslashes, which Snowflake reads as escape sequences, so a
36646
+ double-brace value holding a backslash arrives changed. Pass such a value in a
36647
+ dollar-quoted constant with triple braces (`$${{{record.field}}}$$`), which Snowflake
36648
+ reads as is, but only when it can't contain `$$`: a `$$` ends the constant, and the rest
36649
+ is read as SQL.
36577
36650
  x-celigo-ai-guidance:
36578
36651
  - |-
36579
36652
  This field contains the SQL SELECT statement that will be executed to fetch data
@@ -447,7 +447,9 @@ paths:
447
447
  delete:
448
448
  x-internal: false
449
449
  summary: Delete a trading partner connector
450
- description: Soft-deletes a trading partner connector.
450
+ description: |-
451
+ Deletes a trading partner connector. The recycle bin doesn't take trading partner
452
+ connectors, so there is no route to restore a deleted one.
451
453
  operationId: deleteTradingPartnerConnector
452
454
  tags:
453
455
  - Trading Partner Connectors
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@celigo/api-specs",
3
- "version": "0.2.163",
3
+ "version": "0.2.164",
4
4
  "private": false,
5
5
  "description": "Public OpenAPI bundles (dist/) and the celigo-cli lint schema pack (schemas.json).",
6
6
  "keywords": [
package/schemas.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "provenance": {
3
3
  "repo": "celigo/integrator-api-specs",
4
- "iasCommit": "39e1123a",
4
+ "iasCommit": "30ef0495",
5
5
  "generatedAt": "2026-10-22"
6
6
  },
7
7
  "roots": {