@enfocussw/switch-scripting-context 25.11.0-beta.10 → 25.11.0-beta.11
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/CHANGELOG.md +66 -0
- package/README.md +1 -0
- package/dist/init.js +2 -0
- package/docs/switch-api/api-app-guidelines.md +122 -0
- package/docs/switch-api/api-connection.md +2 -2
- package/docs/switch-api/api-entry-points.md +73 -5
- package/docs/switch-api/api-flow-element.md +4 -4
- package/docs/switch-api/api-job-patterns.md +39 -1
- package/docs/switch-api/api-job.md +3 -3
- package/docs/switch-api/api-logging.md +33 -0
- package/docs/switch-api/api-property-editors.md +40 -2
- package/docs/switch-api/api-script-declaration.md +29 -6
- package/docs/switch-api/api-script-structure.md +27 -2
- package/docs/switch-api/api-tooling.md +77 -0
- package/docs/switch-scripting.md +2 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,72 @@ All notable changes to this package are documented here. Format follows
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [25.11.0-beta.11] - 2026-09-08
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- `api-entry-points.md` — documented that Switch's entry-point scanner is regex-based (not a real
|
|
12
|
+
parser) and can silently drop `function` declarations from certain source shapes: string literals
|
|
13
|
+
ending in a backslash, regex literals (especially ones containing an unescaped `/` inside a
|
|
14
|
+
character class), and division not in a plain `word / word` shape. Applies to every entry point,
|
|
15
|
+
not just the ones checked at load time; `calculateScriptExpression` is the one exception, since
|
|
16
|
+
it's dispatched directly rather than through this scanner. Verified against real
|
|
17
|
+
`SwitchScriptTool --pack` output for each failure mode.
|
|
18
|
+
- `api-tooling.md` — new "Verify entry points before packing" section with a Python/Node.js script
|
|
19
|
+
to check a built `main.js` for the expected entry points before relying on `--pack`, which doesn't
|
|
20
|
+
validate this itself.
|
|
21
|
+
- `api-script-structure.md` — cross-linked the entry-point scanner constraints from the "Agent
|
|
22
|
+
editing policy" callout.
|
|
23
|
+
- `api-app-guidelines.md` — new pre-publish checklist for scripts submitted to the Enfocus Appstore,
|
|
24
|
+
covering property naming/tooltip/editor/default requirements, entry point and `sendTo*()`
|
|
25
|
+
consistency with declared connections, logging quality, temp file/path handling, and app-only
|
|
26
|
+
packaging rules (no embedded Oracle JRE, universal signed macOS Mach-O binaries in extra files,
|
|
27
|
+
immutable extra files, translation completeness). Registered in the routing table, both `init.ts`
|
|
28
|
+
doc-file arrays, and the README's included-docs list.
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
- `switch-scripting.md` — broadened the `api-entry-points.md` routing-table trigger to any edit to
|
|
32
|
+
`main.ts`/`main.js`, not just adding a new entry point.
|
|
33
|
+
- `api-property-editors.md` — documented that the `nofiles`/`allfiles`/`allotherfiles` and
|
|
34
|
+
`nofolders`/`allfolders`/`allotherfolders` literal editors are specifically for connection
|
|
35
|
+
include/exclude filter mask properties, with the exact `Editor`/`Default`/`Subtype` chain verified
|
|
36
|
+
against Switch's own built-in connection filter declarations; added the matching rows to Common
|
|
37
|
+
practices. Noted that `next`/`current` have no confirmed script-facing use case. Noted that `none`
|
|
38
|
+
is the sanctioned way to allow an empty value under `Validation="Standard"`.
|
|
39
|
+
- `api-script-declaration.md` — cross-linked the `Validation` row to the `none` literal editor for
|
|
40
|
+
allowing empty values under `Standard` validation.
|
|
41
|
+
- `api-app-guidelines.md`, `api-script-declaration.md`, `api-property-editors.md`,
|
|
42
|
+
`api-entry-points.md`, `api-job-patterns.md`, `api-logging.md`, `api-script-structure.md` —
|
|
43
|
+
reclassified the Appstore submission rules added previously: most turned out to be universal
|
|
44
|
+
correctness rules (functional requirements or bugs if violated) rather than app-specific policy,
|
|
45
|
+
so their "App guideline" framing was removed and they're now stated as plain rules that apply to
|
|
46
|
+
every script. Only a handful remain "mandatory for apps, recommended for scripts" (property
|
|
47
|
+
naming/tooltip/default, non-module-editor requirement, log volume, platform-independent paths).
|
|
48
|
+
"No embedded Oracle JRE" moved out of the app-only section entirely, since it applies to any
|
|
49
|
+
script bundling extra files. `api-app-guidelines.md` is now organized into three explicit tiers
|
|
50
|
+
(Universal / Apps required-scripts recommended / Apps only) instead of one flat list.
|
|
51
|
+
- `api-script-declaration.md`, `api-property-editors.md`, `api-entry-points.md`, `api-job-patterns.md`,
|
|
52
|
+
`api-job.md`, `api-logging.md`, `api-script-structure.md` — wove the individual Appstore submission
|
|
53
|
+
rules (above) directly into the relevant existing sections (property attributes, editor tables,
|
|
54
|
+
entry point signatures, `sendTo*()`/`ConnectionType` rules, logging conventions, packaging), each
|
|
55
|
+
cross-linked to and from the new checklist, so they're followed from the start rather than caught
|
|
56
|
+
only at a pre-publish review.
|
|
57
|
+
- `api-script-declaration.md` — fixed the `Validation="Custom"` row, which named a nonexistent
|
|
58
|
+
`isPropertyValid` entry point; the actual entry point (per `api-entry-points.md`) is
|
|
59
|
+
`validateProperties`/`validateConnectionProperties`.
|
|
60
|
+
- `api-job-patterns.md` — clarified that the automatic executor-refresh cleanup only applies to
|
|
61
|
+
temp files created via `flowElement.createPathWithName()` (the recommended default); temp files
|
|
62
|
+
created any other way must be cleaned up explicitly by the script. Also notes that the `tmp` npm
|
|
63
|
+
package is not recommended, and if used anyway, its `setGracefulCleanup()` is not always reliable
|
|
64
|
+
in the Switch execution environment and `discardDescriptor: true` should be set.
|
|
65
|
+
- `api-flow-element.md`, `api-connection.md`, `api-script-declaration.md` — cross-linked and made
|
|
66
|
+
explicit that `getPropertyStringValue()`/`connection.getPropertyStringValue()` throws
|
|
67
|
+
`"Invalid tag: <tag>"` for a `Dependency` dependent property currently hidden by its master's
|
|
68
|
+
value, and that `hasProperty()`/`connection.hasProperty()` should be used to guard against this
|
|
69
|
+
(e.g. before fetching properties dependent on a drop-down/enum master). Also notes that the shown
|
|
70
|
+
set can vary per job if the master's value is dynamic, and that a hidden dependent's value cannot
|
|
71
|
+
be read at all — a script needing more than one dependency group's data at once must use a
|
|
72
|
+
different property structure, not `Dependency`-based hiding.
|
|
73
|
+
|
|
8
74
|
## [25.11.0-beta.10] - 2026-09-03
|
|
9
75
|
|
|
10
76
|
### Added
|
package/README.md
CHANGED
|
@@ -149,3 +149,4 @@ The `switch-docs/` folder contains:
|
|
|
149
149
|
- `switch-api/api-property-editors.md` — property editor types and string return values
|
|
150
150
|
- `switch-api/api-job-patterns.md` — file access semantics, routing rules, child jobs, executor limits
|
|
151
151
|
- `switch-api/api-execution-environment.md` — process model, state persistence across jobs, error handling, npm/native module constraints
|
|
152
|
+
- `switch-api/api-app-guidelines.md` — pre-publish checklist for Appstore apps: property naming/tooltips/editors, entry point and sendTo consistency, logging quality, packaging
|
package/dist/init.js
CHANGED
|
@@ -95,6 +95,7 @@ function generateCursorMdc(docsDir) {
|
|
|
95
95
|
'api-execution-environment.md',
|
|
96
96
|
'api-logging.md',
|
|
97
97
|
'api-logs-and-dataroot.md',
|
|
98
|
+
'api-app-guidelines.md',
|
|
98
99
|
];
|
|
99
100
|
const fileList = apiFiles.map(f => `- \`${docsDir}/switch-api/${f}\``).join('\n');
|
|
100
101
|
return `---
|
|
@@ -152,6 +153,7 @@ const API_FILES = [
|
|
|
152
153
|
'api-execution-environment.md',
|
|
153
154
|
'api-logging.md',
|
|
154
155
|
'api-logs-and-dataroot.md',
|
|
156
|
+
'api-app-guidelines.md',
|
|
155
157
|
];
|
|
156
158
|
function inlineApiFileList(docsDir) {
|
|
157
159
|
return API_FILES.map(f => `- \`${docsDir}/switch-api/${f}\``).join('\n');
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# App Publishing Guidelines
|
|
2
|
+
|
|
3
|
+
A pre-publish checklist for a script intended for the Enfocus Appstore (`ScriptPackageType="App"`
|
|
4
|
+
— see [api-script-structure.md § Script vs App](api-script-structure.md#script-vs-app)). Each item
|
|
5
|
+
here is enforced in more detail at the linked section — this page exists to be read top-to-bottom
|
|
6
|
+
right before submission, not as the primary source for any individual rule.
|
|
7
|
+
|
|
8
|
+
Items fall into three tiers, marked on each one:
|
|
9
|
+
|
|
10
|
+
- **Universal** — a correctness rule for every script, app or not. Violating it is a bug, not a
|
|
11
|
+
style choice.
|
|
12
|
+
- **Apps required / scripts recommended** — mandatory for Appstore review; worth following in a
|
|
13
|
+
plain `Script` too, but not enforced there.
|
|
14
|
+
- **Apps only** — doesn't apply to a plain `Script` package at all.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Properties
|
|
19
|
+
|
|
20
|
+
- [ ] **Apps required / scripts recommended.** Every property name (`LocalizedTagName`) is 30
|
|
21
|
+
characters or fewer and uses sentence-style capitalization ("Customer name", not "Customer
|
|
22
|
+
Name") — see [api-script-declaration.md](api-script-declaration.md#custom-property-elements-elementfields).
|
|
23
|
+
- [ ] **Apps required / scripts recommended.** Every property has a `Tooltip`, unless it's fully
|
|
24
|
+
self-explanatory with no extra constraints (e.g. "Number of copies" with no min/max) — see
|
|
25
|
+
[api-script-declaration.md](api-script-declaration.md#custom-property-elements-elementfields).
|
|
26
|
+
- [ ] **Universal.** Dynamic editors (`sltextwithvar`/`mltextwithvar`, `conditionwithvar`,
|
|
27
|
+
`scriptexp`) are enabled wherever the value could plausibly vary per job, and omitted where the
|
|
28
|
+
value is inherently static (e.g. a dataset name) — see
|
|
29
|
+
[api-property-editors.md § Common practices](api-property-editors.md#common-practices).
|
|
30
|
+
- [ ] **Universal.** Keyword-style default values ("Default", "None", "Automatic", …) use the
|
|
31
|
+
matching literal editor (`default`, `none`, `automatic`, …), not a typed string default — see
|
|
32
|
+
[api-property-editors.md § Literal editors](api-property-editors.md#literal-editors).
|
|
33
|
+
- [ ] **Universal.** Every property using `askplugin`/`askplugin2` ("Select from library"/"Select
|
|
34
|
+
many from library") has a matching `getLibraryForProperty`/`getLibraryForConnectionProperty`
|
|
35
|
+
entry point — see [api-entry-points.md § Property UI callbacks](api-entry-points.md#property-ui-callbacks).
|
|
36
|
+
- [ ] **Apps required / scripts recommended.** Every property's editor chain includes at least one
|
|
37
|
+
editor that doesn't require an add-on Switch module — e.g. never offer `scriptexp` (Scripting
|
|
38
|
+
Module) as the only editor — see
|
|
39
|
+
[api-property-editors.md § Common practices](api-property-editors.md#common-practices).
|
|
40
|
+
- [ ] **Universal.** Every property using the `external`/`external2`/… editor has either a
|
|
41
|
+
non-empty dependent `Application` property or a `findExternalEditorPath` entry point — see
|
|
42
|
+
[api-property-editors.md § Notes](api-property-editors.md#notes).
|
|
43
|
+
- [ ] **Apps required / scripts recommended.** Every property has a default value unless one
|
|
44
|
+
genuinely isn't possible, in which case the `Tooltip` gives an example value instead — see
|
|
45
|
+
[api-script-declaration.md](api-script-declaration.md#custom-property-elements-elementfields).
|
|
46
|
+
- [ ] **Universal.** Every property/connection field declaring `Validation="Custom"` or `"Standard
|
|
47
|
+
and custom"` has a matching `validateProperties`/`validateConnectionProperties` entry point —
|
|
48
|
+
see [api-entry-points.md § Property UI callbacks](api-entry-points.md#property-ui-callbacks).
|
|
49
|
+
|
|
50
|
+
## Entry points
|
|
51
|
+
|
|
52
|
+
- [ ] **Universal.** `jobArrived` is present when `IncomingConnections="Yes"`; `timerFired` is
|
|
53
|
+
present when `IncomingConnections="No"` (and may additionally be present alongside `jobArrived`)
|
|
54
|
+
— see [api-entry-points.md § Job processing](api-entry-points.md#job-processing).
|
|
55
|
+
- [ ] **Universal.** No empty `jobArrived` or `timerFired` — an entry point that does nothing is
|
|
56
|
+
removed entirely, not left in place — see
|
|
57
|
+
[api-entry-points.md § Job processing](api-entry-points.md#job-processing).
|
|
58
|
+
|
|
59
|
+
## Sending jobs
|
|
60
|
+
|
|
61
|
+
All **universal** — see
|
|
62
|
+
[api-job-patterns.md § Sending jobs](api-job-patterns.md#sending-jobs) and
|
|
63
|
+
[api-script-declaration.md § ConnectionFields](api-script-declaration.md#connectionfields) for full
|
|
64
|
+
detail.
|
|
65
|
+
|
|
66
|
+
- [ ] If `OutgoingConnections` is not `No`, some `sendTo*()` method is called at least once for
|
|
67
|
+
any job actually routed (a purely timer/event-driven script that never touches a job is a
|
|
68
|
+
legitimate exception).
|
|
69
|
+
- [ ] If `OutgoingConnections="Unlimited"`, `job.sendToSingle()` is never used.
|
|
70
|
+
- [ ] `ConnectionType="Move"` never uses `job.sendToData()`/`job.sendToLog()`.
|
|
71
|
+
- [ ] `ConnectionType="TrafficLight"` uses only `job.sendToData()`/`job.sendToLog()`; `sendToData`
|
|
72
|
+
is used when a Data Success/Warning/Error connection is enabled, `sendToLog` when the
|
|
73
|
+
corresponding Log connection is enabled.
|
|
74
|
+
- [ ] An unused Success/Warning/Error connection is omitted from `ConnectionFields` entirely, not
|
|
75
|
+
left declared but unrouted.
|
|
76
|
+
- [ ] A job with no output calls `job.sendToNull()`.
|
|
77
|
+
- [ ] `job.fail()`/`flowElement.failProcess()` is used for genuine processing errors; an error
|
|
78
|
+
`TrafficLight` connection isn't used as a substitute for `fail()`.
|
|
79
|
+
|
|
80
|
+
## Logging
|
|
81
|
+
|
|
82
|
+
- [ ] **Universal.** An `Error` is logged when a custom
|
|
83
|
+
`validateProperties`/`validateConnectionProperties` check returns `valid: false` for a tag, and
|
|
84
|
+
when `getLibraryForProperty`/`getLibraryForConnectionProperty` would otherwise return an empty
|
|
85
|
+
list — see [api-logging.md § Message quality](api-logging.md#message-quality).
|
|
86
|
+
- [ ] **Universal.** Log messages are free of grammatical errors and typos — see
|
|
87
|
+
[api-logging.md § Message quality](api-logging.md#message-quality).
|
|
88
|
+
- [ ] **Universal.** Log messages use `%1`/`%2`/… placeholders with `messageParams`, not string
|
|
89
|
+
concatenation or interpolation of dynamic values — required for correct translation. See
|
|
90
|
+
[api-logging.md § Placeholders instead of concatenation](api-logging.md#placeholders-instead-of-concatenation),
|
|
91
|
+
which also covers the separate, narrower literal-`%` escaping gotcha.
|
|
92
|
+
- [ ] **Apps required / scripts recommended.** Logging isn't excessive — no `Info`/`Debug` calls
|
|
93
|
+
that don't help a flow operator or support engineer understand what happened — see
|
|
94
|
+
[api-logging.md § Log volume](api-logging.md#log-volume).
|
|
95
|
+
|
|
96
|
+
## Temp files and paths
|
|
97
|
+
|
|
98
|
+
- [ ] **Universal.** All temporary files and folders are removed by the script before it finishes,
|
|
99
|
+
rather than relying on Switch's executor-refresh cleanup — see
|
|
100
|
+
[api-job-patterns.md § Temp file cleanup](api-job-patterns.md#temp-file-cleanup).
|
|
101
|
+
- [ ] **Universal.** No Oracle JRE is embedded as an extra file, in a script or an app — see
|
|
102
|
+
[api-script-structure.md § Script folder files](api-script-structure.md#script-folder-files).
|
|
103
|
+
- [ ] **Apps required / scripts recommended.** File system path strings are built with Node's
|
|
104
|
+
`path` module, not hardcoded separators or string concatenation — see
|
|
105
|
+
[api-job-patterns.md § Platform-independent paths](api-job-patterns.md#platform-independent-paths).
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## App-only
|
|
110
|
+
|
|
111
|
+
The following apply only to `ScriptPackageType="App"`, not to a plain `Script` package at all. See
|
|
112
|
+
[api-script-structure.md § App Store submission guidelines](api-script-structure.md#app-store-submission-guidelines)
|
|
113
|
+
for full detail.
|
|
114
|
+
|
|
115
|
+
- [ ] The app is preferably available in more languages than just English.
|
|
116
|
+
- [ ] Where translations are used, they're complete (every shipped language has every string), and
|
|
117
|
+
logging goes through the translation mechanism rather than hardcoded English.
|
|
118
|
+
- [ ] Any macOS Mach-O binaries (executables or dynamic libraries) in extra files are built for
|
|
119
|
+
both `x86_64` and `arm64`.
|
|
120
|
+
- [ ] Any macOS Mach-O binaries in extra files are signed.
|
|
121
|
+
- [ ] No file that might be modified or regenerated at runtime is placed inside the app's own
|
|
122
|
+
package folder — that would fail the app's signature validation and cause Switch to remove it.
|
|
@@ -26,7 +26,7 @@ Connection properties are declared in the script's XML declaration (`ConnectionF
|
|
|
26
26
|
```ts
|
|
27
27
|
connection.getPropertyStringValue(tag: string): Promise<string | string[]>
|
|
28
28
|
```
|
|
29
|
-
Returns the connection property value as a string.
|
|
29
|
+
Returns the connection property value as a string. Throws `"Invalid tag: <tag>"` if the tag is unknown **or if it's a `Dependency` dependent currently hidden by its master's value** — see [api-script-declaration.md § Dependency](api-script-declaration.md#custom-property-elements-elementfields). Before fetching a dependent property, confirm its condition holds (from the already-read master value, or via `hasProperty(tag)` below) rather than fetching it unconditionally.
|
|
30
30
|
|
|
31
31
|
```ts
|
|
32
32
|
connection.getPropertyType(tag: string): PropertyType
|
|
@@ -41,7 +41,7 @@ Returns the English display name of the property (for use in log messages).
|
|
|
41
41
|
```ts
|
|
42
42
|
connection.hasProperty(tag: string): boolean
|
|
43
43
|
```
|
|
44
|
-
Returns `true` if the property exists and is visible for the current configuration.
|
|
44
|
+
Returns `true` if the property exists and is visible for the current configuration. Use this to guard `getPropertyStringValue(tag)` calls on `Dependency` dependents — see the note above.
|
|
45
45
|
|
|
46
46
|
## File count
|
|
47
47
|
|
|
@@ -2,6 +2,54 @@
|
|
|
2
2
|
|
|
3
3
|
Entry points are top-level `async` functions with specific names. They are **not exported**. Switch calls them automatically based on flow events.
|
|
4
4
|
|
|
5
|
+
## Entry-point scanner constraints
|
|
6
|
+
|
|
7
|
+
Switch discovers a script's entry points by regex, not by parsing. Before matching
|
|
8
|
+
`function\s+(name)\s*\(` it strips comments and literals with a regex that doesn't understand JS
|
|
9
|
+
escaping. Certain source shapes make that strip regex delete large spans of real code — and every
|
|
10
|
+
`function` declaration inside the deleted span becomes invisible to Switch, whether or not that
|
|
11
|
+
function is itself well-formed.
|
|
12
|
+
|
|
13
|
+
This applies to **every** entry point on this page, not only the four checked below — a swallowed
|
|
14
|
+
`validateProperties` or `getLibraryForProperty` fails silently (the callback just never runs, no
|
|
15
|
+
error anywhere), which is worse than the loud failure the four below produce. The one exception is
|
|
16
|
+
`calculateScriptExpression`: it's invoked directly at runtime rather than through this scanner, so
|
|
17
|
+
it isn't at risk.
|
|
18
|
+
|
|
19
|
+
If none of `jobArrived`, `timerFired`, `flowStopTriggered`, `httpRequestTriggeredAsync` survives,
|
|
20
|
+
Switch fails with `Cannot open script '<name>': no entry points found` — `httpRequestTriggeredSync`
|
|
21
|
+
alone does not satisfy this check. Both the packed `.sscript` (the entry-point list is baked in at
|
|
22
|
+
pack time) and the unpacked script folder (`main.js` is rescanned by this same scanner every time
|
|
23
|
+
Switch loads it, e.g. running or debugging from Designer) are affected. Packing does not validate
|
|
24
|
+
or warn about any of this — a script that packs cleanly can still fail to load.
|
|
25
|
+
|
|
26
|
+
**Rules for writing entry points in `main.ts`/`main.js`:**
|
|
27
|
+
|
|
28
|
+
1. Never write a string literal whose content ends with a backslash: `"\\"`, `'\\'`, `` `\\` ``,
|
|
29
|
+
`"C:\\Temp\\"`. This is the highest-frequency trigger — the strip regex hunts for the next
|
|
30
|
+
matching quote character anywhere later in the file to close the literal (a backslash right
|
|
31
|
+
before the real closing quote makes it skip past that quote), and deletes everything in between.
|
|
32
|
+
Use `"\x5c"`, `"\u005C"`, `String.fromCharCode(92)`, or restructure (e.g.
|
|
33
|
+
`JSON.stringify(v).slice(1, -1)` for backslash/quote escaping) instead. A backslash elsewhere in
|
|
34
|
+
the literal is fine: `"\\n is newline"`, `"a\\b"`.
|
|
35
|
+
2. Avoid regex literals — including ones that look properly closed, like `/[^/]+/` (a character
|
|
36
|
+
class containing an unescaped `/`). The strip regex doesn't understand character classes, so it
|
|
37
|
+
closes the "literal" early at the inner `/` and leaves a dangling `/` that swallows forward to
|
|
38
|
+
the next `/` anywhere later in the file. Use `new RegExp("...")` instead.
|
|
39
|
+
3. Avoid division that isn't in the plain `word / word` shape. `a / b` is recognised and stripped
|
|
40
|
+
safely; `) / 2`, `] / 2`, and `/=` are not, and the leftover `/` swallows forward exactly like an
|
|
41
|
+
unclosed regex literal. Rewrite as `Math.floor(x / y)` with plain identifiers, or hoist to a
|
|
42
|
+
named variable first.
|
|
43
|
+
4. Declare every entry point with the literal `function` keyword at top level:
|
|
44
|
+
`function jobArrived(...)` or `async function jobArrived(...)`. Arrow functions,
|
|
45
|
+
`exports.jobArrived = function (...)`, and class methods are invisible to the scanner.
|
|
46
|
+
5. Entry-point names are matched case-sensitively. `JobArrived` is silently dropped during
|
|
47
|
+
extraction — if another valid entry point is also present the script packs and loads without
|
|
48
|
+
error, the misnamed function just never runs.
|
|
49
|
+
|
|
50
|
+
See [api-tooling.md § Verify entry points before packing](api-tooling.md#verify-entry-points-before-packing)
|
|
51
|
+
for a script to catch this before it reaches Switch.
|
|
52
|
+
|
|
5
53
|
## Flow lifecycle
|
|
6
54
|
|
|
7
55
|
```ts
|
|
@@ -21,6 +69,10 @@ async function timerFired(s: Switch, flowElement: FlowElement): Promise<void>
|
|
|
21
69
|
```
|
|
22
70
|
Called on a recurring timer. First fires after `flowStartTriggered`. Set the interval via `flowElement.setTimerInterval(seconds)`. Cannot coexist with `flowStartTriggered` as the sole entry point.
|
|
23
71
|
|
|
72
|
+
Required when `IncomingConnections="No"`; optional (alongside `jobArrived`) when
|
|
73
|
+
`IncomingConnections="Yes"`. Never leave it present but empty — remove it entirely if it does
|
|
74
|
+
nothing.
|
|
75
|
+
|
|
24
76
|
## Job processing
|
|
25
77
|
|
|
26
78
|
```ts
|
|
@@ -28,6 +80,12 @@ async function jobArrived(s: Switch, flowElement: FlowElement, job: Job): Promis
|
|
|
28
80
|
```
|
|
29
81
|
Called when a job arrives. Must eventually call a `job.sendTo*()` or `job.fail()`. Can run concurrently if configured in the script XML declaration.
|
|
30
82
|
|
|
83
|
+
`jobArrived` and `timerFired` presence must match the declared connections — present when
|
|
84
|
+
`IncomingConnections="Yes"` (`timerFired` may additionally be present); when
|
|
85
|
+
`IncomingConnections="No"`, `timerFired` must be present instead. See
|
|
86
|
+
[api-script-declaration.md](api-script-declaration.md#built-in-elementfields). Never leave an empty
|
|
87
|
+
`jobArrived` or `timerFired` in the script — remove the function entirely if it does nothing.
|
|
88
|
+
|
|
31
89
|
```ts
|
|
32
90
|
async function abort(s: Switch, flowElement: FlowElement, job: Job, abortData: any): Promise<void>
|
|
33
91
|
```
|
|
@@ -59,24 +117,34 @@ Not available for debugging.
|
|
|
59
117
|
```ts
|
|
60
118
|
async function getLibraryForProperty(s: Switch, flowElement: FlowElement, tag: string): Promise<string[]>
|
|
61
119
|
```
|
|
62
|
-
Returns a dynamic list of values for a property's library dropdown.
|
|
120
|
+
Returns a dynamic list of values for a property's library dropdown. Mandatory if any property uses
|
|
121
|
+
the `askplugin`/`askplugin2` editor (see
|
|
122
|
+
[api-property-editors.md](api-property-editors.md#modal-editors)). Log an error via `flowElement.log()`
|
|
123
|
+
if the list would otherwise come back empty, so the user can see why the dropdown has nothing in it.
|
|
63
124
|
|
|
64
125
|
```ts
|
|
65
126
|
async function getLibraryForConnectionProperty(s: Switch, flowElement: FlowElement, c: Connection, tag: string): Promise<string[]>
|
|
66
127
|
```
|
|
67
|
-
Returns a dynamic list of values for a connection property's library dropdown.
|
|
128
|
+
Returns a dynamic list of values for a connection property's library dropdown. Same guidance as
|
|
129
|
+
`getLibraryForProperty` above, for connection fields using `askplugin`/`askplugin2`.
|
|
68
130
|
|
|
69
131
|
```ts
|
|
70
132
|
async function validateProperties(s: Switch, flowElement: FlowElement, tags: string[]): Promise<{ tag: string, valid: boolean }[]>
|
|
71
133
|
```
|
|
72
|
-
Validates one or more property values. Return one result object per tag.
|
|
134
|
+
Validates one or more property values. Return one result object per tag. Mandatory if any property
|
|
135
|
+
declares `Validation="Custom"` or `"Standard and custom"` (see
|
|
136
|
+
[api-script-declaration.md](api-script-declaration.md#custom-property-elements-elementfields)). Log
|
|
137
|
+
an error via `flowElement.log()` for any tag returned with `valid: false`, so the user sees why.
|
|
73
138
|
|
|
74
139
|
```ts
|
|
75
140
|
async function validateConnectionProperties(s: Switch, flowElement: FlowElement, c: Connection, tags: string[]): Promise<{ tag: string, valid: boolean }[]>
|
|
76
141
|
```
|
|
77
|
-
Validates one or more connection property values.
|
|
142
|
+
Validates one or more connection property values. Same guidance as `validateProperties` above, for
|
|
143
|
+
connection fields declaring `Validation="Custom"`/`"Standard and custom"`.
|
|
78
144
|
|
|
79
145
|
```ts
|
|
80
146
|
async function findExternalEditorPath(s: Switch, flowElement: FlowElement, tag: string): Promise<string>
|
|
81
147
|
```
|
|
82
|
-
Resolves the path to an external editor for a property.
|
|
148
|
+
Resolves the path to an external editor for a property. Required whenever the
|
|
149
|
+
`external`/`external2`/… editor is used, unless the dependent `Application` property is non-empty —
|
|
150
|
+
see [api-property-editors.md § Notes](api-property-editors.md#notes).
|
|
@@ -21,7 +21,7 @@ Properties are configured by the user in the Switch canvas and declared in the s
|
|
|
21
21
|
```ts
|
|
22
22
|
flowElement.getPropertyStringValue(tag: string): Promise<string | string[]>
|
|
23
23
|
```
|
|
24
|
-
Returns the property value as a string (or array for multi-value properties). For `OAuthToken` properties, returns a valid refreshed token. Throws `"Invalid tag: <tag>"` if the tag is unknown or a hidden dependent property. See [api-property-editors.md](api-property-editors.md) for editor types and their return value formats.
|
|
24
|
+
Returns the property value as a string (or array for multi-value properties). For `OAuthToken` properties, returns a valid refreshed token. Throws `"Invalid tag: <tag>"` if the tag is unknown **or if it's a `Dependency` dependent currently hidden by its master's value** — see [api-script-declaration.md § Dependency](api-script-declaration.md#custom-property-elements-elementfields). Before fetching a dependent property, confirm its condition holds (from the already-read master value, or via `hasProperty(tag)` below) rather than fetching it unconditionally. See [api-property-editors.md](api-property-editors.md) for editor types and their return value formats.
|
|
25
25
|
|
|
26
26
|
> **Dynamic values (Switch variables and script expressions) are only resolved when `getPropertyStringValue()` is called from `jobArrived`.** In any other entry point (e.g. `timerFired`) the raw unresolved string is returned.
|
|
27
27
|
>
|
|
@@ -40,7 +40,7 @@ Returns the English display name of the property (for use in log messages).
|
|
|
40
40
|
```ts
|
|
41
41
|
flowElement.hasProperty(tag: string): boolean
|
|
42
42
|
```
|
|
43
|
-
Returns `true` if the property exists and is visible for the current configuration.
|
|
43
|
+
Returns `true` if the property exists and is visible for the current configuration. Use this to guard `getPropertyStringValue(tag)` calls on `Dependency` dependents — see the note above.
|
|
44
44
|
|
|
45
45
|
## Connections
|
|
46
46
|
|
|
@@ -75,7 +75,7 @@ Logs a fatal error and puts the element into the "problem process" state. `messa
|
|
|
75
75
|
```ts
|
|
76
76
|
flowElement.createJob(path: string): Promise<Job>
|
|
77
77
|
```
|
|
78
|
-
Creates a new job from an existing file/folder path. Valid only in `jobArrived` and `timerFired`. The new job has default properties (no parent). The caller is responsible for cleaning up the source file after routing. See [api-job-patterns.md](api-job-patterns.md) for temp file cleanup rules and routing constraints.
|
|
78
|
+
Creates a new job from an existing file/folder path. Valid only in `jobArrived` and `timerFired`. The new job has default properties (no parent). The caller is responsible for cleaning up the source file after routing. See [api-job-patterns.md](api-job-patterns.md#temp-file-cleanup) for temp file cleanup rules and [api-job-patterns.md](api-job-patterns.md#sending-jobs) for routing constraints.
|
|
79
79
|
|
|
80
80
|
```ts
|
|
81
81
|
flowElement.getJobs(ids: string[]): Promise<Job[]>
|
|
@@ -94,7 +94,7 @@ Subscribes to a channel to receive jobs from it. Only one subscriber per channel
|
|
|
94
94
|
```ts
|
|
95
95
|
flowElement.createPathWithName(name: string, createFolder: boolean): Promise<any>
|
|
96
96
|
```
|
|
97
|
-
Creates a temporary path (optionally as a folder — `createFolder` is required, not optional). Returns an empty string only if creating the folder throws (e.g. a permissions error); it does not check whether the path already exists first.
|
|
97
|
+
Creates a temporary path (optionally as a folder — `createFolder` is required, not optional). Returns an empty string only if creating the folder throws (e.g. a permissions error); it does not check whether the path already exists first. This is the recommended way to create temp files — see [api-job-patterns.md](api-job-patterns.md#temp-file-cleanup) for cleanup rules, including why this method should be preferred over ad hoc temp-file approaches like the `tmp` npm package.
|
|
98
98
|
|
|
99
99
|
```ts
|
|
100
100
|
flowElement.getFileCount(nested?: boolean): Promise<number>
|
|
@@ -25,7 +25,24 @@ Switch does **not** automatically clean up files you create or pass to job-creat
|
|
|
25
25
|
- Files/folders passed to `job.createChild(path)` — delete after routing.
|
|
26
26
|
- Files/folders passed to `job.createDataset(name, filePath, model)` — delete after routing.
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
Use `flowElement.createPathWithName()` to create temp files by default — its output lives in the executor's temp area, which Switch removes automatically on executor refresh. Even so, delete explicitly after routing rather than relying on that refresh (see below).
|
|
29
|
+
|
|
30
|
+
If a temp file is created some other way (e.g. `fs`/`path` writing outside the temp area, or a library that writes its own scratch files), the same rule applies: the script must delete it explicitly. Don't rely on Switch's executor-refresh cleanup for files outside the temp area — it only removes what it put there, so anything else creates a permanent leak.
|
|
31
|
+
|
|
32
|
+
The [`tmp`](https://www.npmjs.com/package/tmp) npm package is common in scripts written by app creators, but it is **not recommended** here — prefer `flowElement.createPathWithName()` instead. If `tmp` is used anyway: its `setGracefulCleanup()` is not always reliable in the Switch script execution environment, so don't depend on it for cleanup — delete the file explicitly after routing regardless. Also pass `discardDescriptor: true` when creating a temp path (e.g. `tmp.fileSync({ discardDescriptor: true })`), or the open file descriptor can leak.
|
|
33
|
+
|
|
34
|
+
> Files accumulate between executor refreshes if not cleaned up. The executor is refreshed after 5 min idle, 5,000 tasks, 150 MB memory, or 1,024 open file handles — at which point accumulated files **created via `createPathWithName()`** are removed automatically, but do not rely on this.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Platform-independent paths
|
|
39
|
+
|
|
40
|
+
Switch Server runs on both Windows and macOS. **App guideline (mandatory for apps, recommended for
|
|
41
|
+
scripts):** a script package should work unmodified on either — paths returned by `job.get()`,
|
|
42
|
+
`flowElement.createPathWithName()`, and similar methods use the host OS's native separator, so avoid
|
|
43
|
+
hardcoding `/` or `\` when building or splitting a path, and don't assume one form when comparing or
|
|
44
|
+
matching paths. Use Node's `path` module (`path.join`, `path.resolve`, `path.sep`, `path.basename`,
|
|
45
|
+
etc.) instead of string concatenation.
|
|
29
46
|
|
|
30
47
|
---
|
|
31
48
|
|
|
@@ -49,6 +66,27 @@ await child.sendTo(conn2);
|
|
|
49
66
|
await fs.promises.rm(tempPath);
|
|
50
67
|
```
|
|
51
68
|
|
|
69
|
+
**Consistency with declared connections** (applies to every script, not just apps):
|
|
70
|
+
- If `OutgoingConnections` is not `No`, the script must call some `sendTo*()` method at least once
|
|
71
|
+
for any job it actually routes. A purely timer/event-driven script that never touches a job
|
|
72
|
+
(polling an API, rotating logs, etc.) is a legitimate exception.
|
|
73
|
+
- If `OutgoingConnections="Unlimited"` (more than one outgoing connection allowed), never use
|
|
74
|
+
`job.sendToSingle()` — it only makes sense when exactly one outgoing connection exists.
|
|
75
|
+
- If no output is produced for a job, call `job.sendToNull()` rather than leaving it unrouted.
|
|
76
|
+
- `ConnectionType="Move"` (see [api-script-declaration.md](api-script-declaration.md#connectionfields)):
|
|
77
|
+
never use `job.sendToData()`/`job.sendToLog()` — those are for `TrafficLight` connections only. Use
|
|
78
|
+
`job.sendTo()`/`job.sendToSingle()`.
|
|
79
|
+
- `ConnectionType="TrafficLight"`: use only `job.sendToData()`/`job.sendToLog()` — never
|
|
80
|
+
`job.sendTo()`/`job.sendToSingle()`. Use `sendToData` when a Data Success/Warning/Error connection
|
|
81
|
+
is enabled in the declaration, and `sendToLog` when the corresponding Log connection is enabled.
|
|
82
|
+
Conversely, don't declare a Success/Warning/Error element the script never routes to — omit it from
|
|
83
|
+
`ConnectionFields` entirely (see the TrafficLight example in
|
|
84
|
+
[api-script-declaration.md](api-script-declaration.md#connectionfields)).
|
|
85
|
+
- Prefer `job.fail()`/`flowElement.failProcess()` for genuine processing errors (see
|
|
86
|
+
[api-logging.md](api-logging.md)) over silently routing a failed job to a generic error connection —
|
|
87
|
+
reserve an error `TrafficLight` connection for cases the flow author should be able to reroute
|
|
88
|
+
downstream, not as a substitute for `fail()`.
|
|
89
|
+
|
|
52
90
|
---
|
|
53
91
|
|
|
54
92
|
## Dataset writes must precede child job creation
|
|
@@ -36,7 +36,7 @@ Returns the local filesystem path to the job. Use `AccessLevel.ReadOnly` to read
|
|
|
36
36
|
|
|
37
37
|
## Routing
|
|
38
38
|
|
|
39
|
-
Every job must be routed exactly once.
|
|
39
|
+
Every job must be routed exactly once. See [api-job-patterns.md § Sending jobs](api-job-patterns.md#sending-jobs) for which `sendTo*()` method is appropriate for a given `ConnectionType`/`OutgoingConnections` declaration.
|
|
40
40
|
|
|
41
41
|
```ts
|
|
42
42
|
job.sendToNull(): Promise<void>
|
|
@@ -92,7 +92,7 @@ Log a message including job context. To log a literal `%`, pass it as a param: `
|
|
|
92
92
|
```ts
|
|
93
93
|
job.createChild(path: string): Promise<Job>
|
|
94
94
|
```
|
|
95
|
-
Creates a new job inheriting the processing history, metadata, and private data of the parent. Takes effect immediately: the child's datasets are copied from the parent's *current* server-side state, so any pending `createDataset()` write not yet flushed by a `sendTo*()` call is not reflected in it. See [api-job-patterns.md](api-job-patterns.md#dataset-writes-must-precede-child-job-creation) — creating a child before writing a dataset is a common source of bugs. The caller is responsible for cleaning up the source file after routing.
|
|
95
|
+
Creates a new job inheriting the processing history, metadata, and private data of the parent. Takes effect immediately: the child's datasets are copied from the parent's *current* server-side state, so any pending `createDataset()` write not yet flushed by a `sendTo*()` call is not reflected in it. See [api-job-patterns.md](api-job-patterns.md#dataset-writes-must-precede-child-job-creation) — creating a child before writing a dataset is a common source of bugs. The caller is responsible for cleaning up the source file after routing (see [api-job-patterns.md](api-job-patterns.md#temp-file-cleanup)).
|
|
96
96
|
|
|
97
97
|
## Private data
|
|
98
98
|
|
|
@@ -128,7 +128,7 @@ List all datasets attached to the job. **Immediate**: reads server state at once
|
|
|
128
128
|
```ts
|
|
129
129
|
job.createDataset(name: string, filePath: string, model: DatasetModel): Promise<void>
|
|
130
130
|
```
|
|
131
|
-
Attach a new dataset. **Deferred**: registers in-memory only; the file is not uploaded until the next `sendTo*()` call. Caller must clean up the source file.
|
|
131
|
+
Attach a new dataset. **Deferred**: registers in-memory only; the file is not uploaded until the next `sendTo*()` call. Caller must clean up the source file after routing — see [api-job-patterns.md](api-job-patterns.md#temp-file-cleanup).
|
|
132
132
|
|
|
133
133
|
```ts
|
|
134
134
|
job.getDataset(name: string, accessLevel: AccessLevel): Promise<string>
|
|
@@ -51,3 +51,36 @@ job.log(LogLevel.Info, '%1', [urlThatMightContainPercent]);
|
|
|
51
51
|
`job.fail(message, messageParams?: (string | number | boolean)[])` takes an **array**.
|
|
52
52
|
`flowElement.failProcess(message, messageParam?: string | number | boolean)` takes a **single
|
|
53
53
|
value**, not an array. Passing an array to `failProcess` is a common mistake.
|
|
54
|
+
|
|
55
|
+
## Placeholders instead of concatenation
|
|
56
|
+
|
|
57
|
+
Build log messages with `%1`, `%2`, … placeholders and pass the dynamic values as
|
|
58
|
+
`messageParams`/`messageParam`, rather than concatenating or interpolating them into the message
|
|
59
|
+
string (beyond the literal-`%` escaping case above). A concatenated message can't be translated
|
|
60
|
+
correctly — word order and pluralization vary by language, so a translator needs the message
|
|
61
|
+
template and the substituted values kept separate. This matters even for a script that only ships in
|
|
62
|
+
English today if it might ever be localized later.
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
// Avoid — can't be translated correctly, and hits the literal-% gotcha if fileName contains one
|
|
66
|
+
job.log(LogLevel.Info, `Processed file ${fileName} in ${seconds}s`);
|
|
67
|
+
|
|
68
|
+
// Prefer
|
|
69
|
+
job.log(LogLevel.Info, 'Processed file %1 in %2s', [fileName, seconds]);
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Message quality
|
|
73
|
+
|
|
74
|
+
- Log messages are user-facing text — proofread them. A message with grammatical errors or typos
|
|
75
|
+
looks unfinished and undermines trust.
|
|
76
|
+
- Log an `Error` when a custom `validateProperties`/`validateConnectionProperties` check returns
|
|
77
|
+
`valid: false` for a tag, and when `getLibraryForProperty`/`getLibraryForConnectionProperty` would
|
|
78
|
+
otherwise return an empty list — see [api-entry-points.md § Property UI callbacks](api-entry-points.md#property-ui-callbacks).
|
|
79
|
+
Silently returning `false`/`[]` with no log line leaves the user without any explanation.
|
|
80
|
+
|
|
81
|
+
## Log volume
|
|
82
|
+
|
|
83
|
+
**App guideline (mandatory for apps, recommended for scripts):** don't over-log. Beyond the
|
|
84
|
+
[Logging in loops](#logging-in-loops) guidance, avoid `Info`/`Debug` calls that don't help a flow
|
|
85
|
+
operator or support engineer understand what happened — every extra message adds noise (and
|
|
86
|
+
translation burden, for an app) without adding signal.
|
|
@@ -48,8 +48,8 @@ open a dialog when the user clicks the editor button. All have `Type="string"` u
|
|
|
48
48
|
| `regexp` | Regular expression string as entered |
|
|
49
49
|
| `filetype` | Filename pattern(s) for the selected file type |
|
|
50
50
|
| `types` (`Type="filefilter"`) | `string[]` — one pattern string per selected file type |
|
|
51
|
-
| `askplugin` | String value selected from the library dialog (calls `getLibraryForProperty`) |
|
|
52
|
-
| `askplugin2` | `string[]` — one string per selected library item (calls `getLibraryForMultipleProperty`) |
|
|
51
|
+
| `askplugin` | String value selected from the library dialog (calls `getLibraryForProperty`) — **requires the script to implement `getLibraryForProperty`** (`getLibraryForConnectionProperty` for a connection field), see [api-entry-points.md](api-entry-points.md#property-ui-callbacks) |
|
|
52
|
+
| `askplugin2` | `string[]` — one string per selected library item (calls `getLibraryForMultipleProperty`) — **requires a matching library-callback entry point**, same as `askplugin` above. ⚠ `getLibraryForMultipleProperty` isn't documented anywhere in [api-entry-points.md](api-entry-points.md#property-ui-callbacks), which only lists `getLibraryForProperty`/`getLibraryForConnectionProperty` — this may be the same entry point handling both single- and multi-select, or a genuinely separate, undocumented one; needs verifying against source before relying on the name here. |
|
|
53
53
|
| `description` | Multi-line text as a single string (may include newlines) |
|
|
54
54
|
| `scriptexp` | Result of script expression evaluated in job context, as a string |
|
|
55
55
|
| `sltextwithvar` | Single-line text with variables substituted, as a string |
|
|
@@ -75,6 +75,14 @@ constant as one of the choices; all literal tokens have `Type="string"`.
|
|
|
75
75
|
Always call `getPropertyType()` first to check whether the value is a literal before comparing the
|
|
76
76
|
string.
|
|
77
77
|
|
|
78
|
+
Use the matching literal editor for a keyword-style value like "Default", "None", or "Automatic"
|
|
79
|
+
instead of making it a typed string default — e.g. `default` instead of a `Default`
|
|
80
|
+
attribute set to the literal text `"Default"`. Typing the keyword as an ordinary string default lets
|
|
81
|
+
a user accidentally change it to arbitrary text and loses the `PropertyType.Literal` signal the
|
|
82
|
+
script relies on. `none` is specifically the sanctioned way to let a property hold an empty value
|
|
83
|
+
under `Validation="Standard"` — combine it into the `Editor` chain instead of relaxing to
|
|
84
|
+
`Validation="None"` just to permit emptiness.
|
|
85
|
+
|
|
78
86
|
| `Editor` token | `getPropertyStringValue()` returns |
|
|
79
87
|
|---|---|
|
|
80
88
|
| `default` | `"Default"` |
|
|
@@ -89,6 +97,19 @@ string.
|
|
|
89
97
|
| `next` | `"Next"` |
|
|
90
98
|
| `current` | `"Current"` |
|
|
91
99
|
|
|
100
|
+
`nofiles`/`allfiles`/`allotherfiles` and `nofolders`/`allfolders`/`allotherfolders` are not
|
|
101
|
+
general-purpose — every real use of them is a connection **include/exclude filter mask** (an
|
|
102
|
+
`IncludeMask`/`ExcludeMask`, or `IncludeFolderMask`/`ExcludeFolderMask`, on a `ConnectionType="Filter"`
|
|
103
|
+
connection). Switch Designer labels them "No/All/All other jobs" and "No/All folders" in that
|
|
104
|
+
context, not the XML token names above. See [Common practices](#common-practices) below for the
|
|
105
|
+
exact chain.
|
|
106
|
+
|
|
107
|
+
`next` and `current` exist in the editor grammar but have no confirmed script-facing use case — no
|
|
108
|
+
built-in Switch flow element declares a property using them, and Enfocus's own property-editor
|
|
109
|
+
documentation omits both (along with `allotherfolders`, apparently by oversight, since it's used the
|
|
110
|
+
same way as `allotherfiles`). Don't reach for `next`/`current` without confirming a concrete need
|
|
111
|
+
first.
|
|
112
|
+
|
|
92
113
|
---
|
|
93
114
|
|
|
94
115
|
## Extra XML attributes for certain editors
|
|
@@ -115,6 +136,17 @@ flow is exported.
|
|
|
115
136
|
The following are recommended conventions for pairing property kinds with editor chains, not
|
|
116
137
|
restrictions enforced by Switch — a script writer can combine editors differently if asked to.
|
|
117
138
|
|
|
139
|
+
Enable the dynamic editors (`sltextwithvar`/`mltextwithvar` and `conditionwithvar`, `scriptexp`)
|
|
140
|
+
wherever the value could plausibly vary per job — the rows below already reflect this. Conversely,
|
|
141
|
+
don't add them to a property whose value is inherently static (e.g. a dataset name, or anything a
|
|
142
|
+
`Dependency` master needs to read at flow-configuration time) — offering a variable/script option
|
|
143
|
+
there just invites a value the script can't sensibly use.
|
|
144
|
+
|
|
145
|
+
**App guideline (mandatory for apps, recommended for scripts):** make sure at least one editor in
|
|
146
|
+
the chain works without an add-on Switch module: `scriptexp` requires the Scripting Module, so never
|
|
147
|
+
offer it as the property's only editor — pair it with a module-free option (e.g. `inline` or
|
|
148
|
+
`sltextwithvar`) so the property still works for a user without that module.
|
|
149
|
+
|
|
118
150
|
| Property kind | Recommended `Editor` chain | Why |
|
|
119
151
|
|---|---|---|
|
|
120
152
|
| Secret (password, token, API key) | `password` only | Masks the value and avoids leaking it via logs or variable inspection if a var/expression editor were combined. |
|
|
@@ -126,6 +158,8 @@ restrictions enforced by Switch — a script writer can combine editors differen
|
|
|
126
158
|
| Enum (`Type="enum:..."`) | `inline` only, always | No editor guarantees a var/expression result matches one of the declared items. |
|
|
127
159
|
| File/folder path that must exist for the app to work | `choosefile`/`choosefolder` only | Switch validates the picked path exists at flow start. |
|
|
128
160
|
| File/folder path that legitimately varies per job | `choosefile`/`choosefolder` + `sltextwithvar` + `scriptexp` | Dynamic values only resolve when read during `jobArrived` — see the "Workaround for deferred processing" note in [api-flow-element.md](api-flow-element.md#properties) if the path is needed later in the flow. |
|
|
161
|
+
| Connection include-mask filter (which jobs pass through) | `allfiles;allotherfiles;types;filepatterns;regexp;scriptexp`, `Default="All Files"`, `Subtype="allfiles"` | Matches Switch's own built-in connection filter properties exactly — `Default`/`Subtype` must hold the chosen literal's exact rendered string. Folder version: `allfolders;allotherfolders;folderpatterns;regexp;scriptexp` with `Default="All Folders"`, `Subtype="allfolders"`. |
|
|
162
|
+
| Connection exclude-mask filter (which jobs are blocked) | `nofiles;types;filepatterns;regexp;scriptexp`, `Default="No Files"`, `Subtype="nofiles"` | Same reasoning as the include mask, starting from `nofiles` instead since there's no "exclude all/all other" case. Folder version: `nofolders;folderpatterns;regexp;scriptexp` with `Default="No Folders"`, `Subtype="nofolders"`. |
|
|
129
163
|
|
|
130
164
|
`regexp`, `filetype`/`types`, `askplugin`/`askplugin2`, `oauth`, and `external` can technically be
|
|
131
165
|
combined with `sltextwithvar`/`scriptexp` too, but this is uncommon in practice and not covered by a
|
|
@@ -142,3 +176,7 @@ dedicated row above.
|
|
|
142
176
|
`getPropertyStringValue()`.
|
|
143
177
|
- **External editor**: requires a separate companion application. The script receives a file path to
|
|
144
178
|
the property set file. Entry point `findExternalEditorPath` resolves the editor executable path.
|
|
179
|
+
One of these two must be true — either a dependent property named `Application` (see
|
|
180
|
+
[Dependency](api-script-declaration.md#custom-property-elements-elementfields)) is non-empty, or
|
|
181
|
+
the script implements `findExternalEditorPath` — see
|
|
182
|
+
[api-entry-points.md](api-entry-points.md#property-ui-callbacks).
|
|
@@ -57,8 +57,8 @@ value is non-string (see the table); an empty string field can omit `Type`.
|
|
|
57
57
|
| `Version` | number | Format `[1-9][0-9]*(\.(0\|[1-9][0-9]*))*`, e.g. `1`, `2.1`. Bump on every declaration change. |
|
|
58
58
|
| `Keywords` | string | Space/comma/semicolon-separated. Elements pane search. |
|
|
59
59
|
| `Tooltip` | string | Elements pane tooltip. |
|
|
60
|
-
| `IncomingConnections` | `Yes` \| `No` | Add `RequireAtLeastOne="Yes"` when `Yes`. |
|
|
61
|
-
| `OutgoingConnections` | `No` \| `One` \| `Unlimited` | Add `RequireAtLeastOne="Yes"` when `One`/`Unlimited`. Always carries `DetailedInfo=""` (or a prose description of the connections, for generated docs). |
|
|
60
|
+
| `IncomingConnections` | `Yes` \| `No` | Add `RequireAtLeastOne="Yes"` when `Yes`. When `Yes`, the script must implement `jobArrived` (optionally `timerFired` too); when `No`, it must implement `timerFired` instead — see [api-entry-points.md](api-entry-points.md#job-processing). |
|
|
61
|
+
| `OutgoingConnections` | `No` \| `One` \| `Unlimited` | Add `RequireAtLeastOne="Yes"` when `One`/`Unlimited`. Always carries `DetailedInfo=""` (or a prose description of the connections, for generated docs). When not `No`, the script must call a `sendTo*()` method at least once for any job it actually routes (a purely timer/event-driven script that never touches a job — polling an API, rotating logs, etc. — is a legitimate exception); when `Unlimited`, never use `job.sendToSingle()` — see [api-job-patterns.md § Sending jobs](api-job-patterns.md#sending-jobs). |
|
|
62
62
|
| `ConnectionType` | `Move` \| `Filter` \| `TrafficLight` | Governs which `ConnectionFields` children are legal — see [ConnectionFields](#connectionfields). |
|
|
63
63
|
| `FunctionsNodeJSScript` | `;`-separated names | Entry point function names found in the script. Omit the element entirely if there is no Node.js program. |
|
|
64
64
|
| `ExecutionMode` | `Concurrent` \| `Serialized` | |
|
|
@@ -110,11 +110,11 @@ Key attributes:
|
|
|
110
110
|
| `Type` | Value type discriminator — see [Type reference](#type-reference). |
|
|
111
111
|
| `Editor` | `;`-joined chain of editor tokens (inline editor first, then modal editors) — see [api-property-editors.md](api-property-editors.md). |
|
|
112
112
|
| `Subtype` | Which editor in the `Editor` chain is currently active for the stored value. For a single-editor property this equals that editor's token (e.g. `"inline"`); for a bare modal editor with no inline component, leave it `""`. This attribute is read by Switch's validator at runtime, not just bookkeeping — keep it consistent with `Editor`. |
|
|
113
|
-
| `LocalizedTagName` | Display name shown in the Properties pane. |
|
|
114
|
-
| `Tooltip` | Tooltip shown in the Properties pane. |
|
|
113
|
+
| `LocalizedTagName` | Display name shown in the Properties pane. **App guideline (mandatory for apps, recommended for scripts):** 30 characters max, sentence-style capitalization (`"Customer name"`, not `"Customer Name"`). |
|
|
114
|
+
| `Tooltip` | Tooltip shown in the Properties pane. **App guideline (mandatory for apps, recommended for scripts):** give every property a tooltip. The only exception is a property that's fully self-explanatory from its name alone with no extra constraints (e.g. "Number of copies" with no min/max) — if there's anything a user would need to know (units, valid range, format, an example value), put it in the tooltip. |
|
|
115
115
|
| `DetailedInfo` | Long-form description for generated docs. Always include the attribute (empty string `""` is fine) — omitting it makes the property non-editable in Switch Designer. |
|
|
116
|
-
| `Validation` | `None` (skip validation) \| `Standard` (built-in validator) \| `Custom` (needs
|
|
117
|
-
| `Default` | Default value string. Omit only if the value is emitted as CDATA instead. |
|
|
116
|
+
| `Validation` | `None` (skip validation) \| `Standard` (built-in validator) \| `Custom` (needs a `validateProperties` entry point) \| `Standard and custom` (both, custom only runs if standard passes). If any property uses `Custom` or `Standard and custom`, the script must implement `validateProperties` (or `validateConnectionProperties` for a connection field) — see [api-entry-points.md](api-entry-points.md#property-ui-callbacks). To let a property hold an empty value under `Standard` validation, add the `none` literal editor to the `Editor` chain (see [api-property-editors.md § Literal editors](api-property-editors.md#literal-editors)) instead of relaxing to `Validation="None"` just to permit emptiness. |
|
|
117
|
+
| `Default` | Default value string. Omit only if the value is emitted as CDATA instead. **App guideline (mandatory for apps, recommended for scripts):** always provide a default unless there's genuinely no sensible one; if a default truly isn't possible, give an example value in the `Tooltip` instead. |
|
|
118
118
|
| `Dependency` | Tag of the master property this one depends on. Written flat (not nested) — the dependent element is a sibling of its master, not a child. |
|
|
119
119
|
| `DependencyCondition` | One of: `Not-empty`, `Equals`, `Not-equals`, `Contains`, `Does not contain`, `Matches`, `Does not match`, `Starts with`, `Does not start with`. |
|
|
120
120
|
| `Dependencyvalue` | Value(s) to compare against — `;`-separated for multiple. Note the lowercase `v`. |
|
|
@@ -131,6 +131,24 @@ Key attributes:
|
|
|
131
131
|
Validation="Standard" Default=""></OutputFolder>
|
|
132
132
|
```
|
|
133
133
|
|
|
134
|
+
**Runtime pitfall:** when a dependent property is hidden (its master's current value doesn't satisfy
|
|
135
|
+
`DependencyCondition`/`Dependencyvalue`), Switch treats the tag as if it doesn't exist. Calling
|
|
136
|
+
`flowElement.getPropertyStringValue(tag)` on it throws `"Invalid tag: <tag>"` — see
|
|
137
|
+
[api-flow-element.md](api-flow-element.md#properties). Only fetch a dependent property once you know
|
|
138
|
+
its condition holds, either by checking the already-read master value yourself, or by calling
|
|
139
|
+
`flowElement.hasProperty(tag)` first (it returns `false` for a hidden dependent). This matters most
|
|
140
|
+
for an enum/drop-down master with several dependents keyed off different values — fetch only the
|
|
141
|
+
ones actually shown for the current selection, not all of them.
|
|
142
|
+
|
|
143
|
+
A script must never assume the set of fetchable dependents is fixed once at flow configuration
|
|
144
|
+
time: if the master's own value is dynamic (a Switch variable or script expression, resolved per
|
|
145
|
+
job in `jobArrived`), which dependents are shown can differ from job to job in the same flow
|
|
146
|
+
execution. Re-check the condition (or call `hasProperty()`) on every invocation rather than caching
|
|
147
|
+
an earlier "shown" determination. There is no way to read a currently-hidden dependent's value for
|
|
148
|
+
a given job — if a script genuinely needs data from more than one dependency group at once (e.g.
|
|
149
|
+
values entered while the master previously pointed elsewhere), this pattern cannot provide it, and
|
|
150
|
+
a different property structure (not `Dependency`-based hiding) is needed instead.
|
|
151
|
+
|
|
134
152
|
Attribute order in the file doesn't matter functionally — SwitchScripter's own output happens to be
|
|
135
153
|
alphabetical (QDom sorts attributes on write), but any order parses correctly.
|
|
136
154
|
|
|
@@ -172,6 +190,11 @@ most important thing to get right when hand-editing this section:
|
|
|
172
190
|
|
|
173
191
|
Custom (author-defined) connection properties may be added regardless of `ConnectionType`.
|
|
174
192
|
|
|
193
|
+
The declared connections and the script's `sendTo*()` calls must agree with each other — see
|
|
194
|
+
[api-job-patterns.md § Sending jobs](api-job-patterns.md#sending-jobs) for the exact rules per
|
|
195
|
+
`ConnectionType`. In particular, omit a `Success`/`Warning`/`Error` element entirely (as shown
|
|
196
|
+
above) if the script never routes to it, rather than leaving an unused connection declared.
|
|
197
|
+
|
|
175
198
|
**Caution — package-swap connection preservation:** Switch Designer decides whether existing flow
|
|
176
199
|
connections survive a script package replace by comparing the serialised `ConnectionFields` and
|
|
177
200
|
`IncomingConnections` text **byte-for-byte** between old and new declarations, and additionally
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
A Switch script project lives in a **script folder** during development and is distributed as a `.sscript` package (ZIP).
|
|
4
4
|
|
|
5
|
-
> **Agent editing policy**: Edit TypeScript/JavaScript source files (`main.ts`, `main.js`) and the XML declaration (`<ScriptID>.xml`) freely — see [api-script-declaration.md](api-script-declaration.md) for the declaration's rules. Leave `manifest.xml` to the user unless explicitly asked.
|
|
5
|
+
> **Agent editing policy**: Edit TypeScript/JavaScript source files (`main.ts`, `main.js`) and the XML declaration (`<ScriptID>.xml`) freely — see [api-script-declaration.md](api-script-declaration.md) for the declaration's rules, and [api-entry-points.md § Entry-point scanner constraints](api-entry-points.md#entry-point-scanner-constraints) before writing any string/regex literal or division, since certain shapes make Switch's entry-point scanner silently drop functions. Leave `manifest.xml` to the user unless explicitly asked.
|
|
6
6
|
|
|
7
7
|
## Script folder files
|
|
8
8
|
|
|
@@ -17,7 +17,7 @@ A Switch script project lives in a **script folder** during development and is d
|
|
|
17
17
|
| `tsconfig.json` | Yes (TypeScript) | TypeScript transpilation options. |
|
|
18
18
|
| `<IconFileName>.png` | No | 32×32 px, RGB, not interlaced. Extension must be `.png`. |
|
|
19
19
|
| `node_modules/` | No | Local npm packages. |
|
|
20
|
-
| `Resources/` | No | Extra resource files bundled when packing with SwitchScriptTool. |
|
|
20
|
+
| `Resources/` | No | Extra resource files bundled when packing with SwitchScriptTool. Never bundle an Oracle Java Runtime Environment here — licensing terms don't permit redistributing it, in a script or an app. |
|
|
21
21
|
| `<LanguageCode>.ts` | No | Translation files (Switch App SDK). |
|
|
22
22
|
| `.vscode/launch.json` | No | Debug config (created by SwitchScriptTool). |
|
|
23
23
|
| `.vscode/switch.code-snippets` | No | Entry point snippets (TypeScript only). |
|
|
@@ -72,6 +72,31 @@ A Switch script project lives in a **script folder** during development and is d
|
|
|
72
72
|
| Distribution | Freely | Enfocus Appstore only |
|
|
73
73
|
| Position in pane | — | Configured via `PositionInElementPane` in XML |
|
|
74
74
|
|
|
75
|
+
## App Store submission guidelines
|
|
76
|
+
|
|
77
|
+
The following apply **only** to `ScriptPackageType="App"` (Appstore submission) — not to a plain
|
|
78
|
+
`Script` package — beyond the general property/entry-point/logging conventions covered elsewhere in
|
|
79
|
+
these docs:
|
|
80
|
+
|
|
81
|
+
- **Prefer more than one language.** An app is preferably localized beyond English — see
|
|
82
|
+
[Translation files](#script-folder-files) (`<LanguageCode>.ts`) and
|
|
83
|
+
`SwitchScriptTool --generate-translations` in [api-tooling.md](api-tooling.md).
|
|
84
|
+
- **Translations must be complete, and logging must go through the translation mechanism.** A
|
|
85
|
+
partially-translated app (some strings translated, others not) is not acceptable — every
|
|
86
|
+
user-facing message needs an entry in each shipped language file, and log calls must go through
|
|
87
|
+
that mechanism (see [api-switch.md](api-switch.md) for `Switch.translate`) rather than
|
|
88
|
+
hardcoding English text that bypasses it.
|
|
89
|
+
- **macOS Mach-O binaries in extra files (`Resources/`) must be universal.** Any bundled macOS
|
|
90
|
+
application, framework bundle, executable, or dynamic library must include both `x86_64` and
|
|
91
|
+
`arm64` architectures.
|
|
92
|
+
- **macOS Mach-O binaries in extra files must be signed.** An unsigned executable or dynamic
|
|
93
|
+
library bundled as an extra file will fail Appstore review.
|
|
94
|
+
- **Extra files must not change at runtime.** Don't place files the script might modify or
|
|
95
|
+
regenerate at runtime inside the app's own package folder — Switch validates the app package's
|
|
96
|
+
signature, and content that changes after signing fails that validation, causing Switch to remove
|
|
97
|
+
the app. Write runtime-mutable data (temp files, caches, generated output) outside the app
|
|
98
|
+
folder — see [api-job-patterns.md § Temp file cleanup](api-job-patterns.md#temp-file-cleanup).
|
|
99
|
+
|
|
75
100
|
## Execution modes
|
|
76
101
|
|
|
77
102
|
Set in the XML declaration via SwitchScripter. Applies to all instances of the script.
|
|
@@ -40,6 +40,83 @@ location for the current OS if the bare command isn't found.
|
|
|
40
40
|
|
|
41
41
|
**Unpack** prints package metadata (`Type`, `Protection`, `Status`) before extracting. For a TypeScript-sourced package it extracts only `main.ts` — the compiled `main.js`/`main.js.map` are not written back out, so a pack → unpack round trip returns a clean, editable script folder rather than a compiled snapshot.
|
|
42
42
|
|
|
43
|
+
## Verify entry points before packing
|
|
44
|
+
|
|
45
|
+
Switch's entry-point scanner is regex-based, not a real parser, and can silently drop entry-point
|
|
46
|
+
functions from certain string/regex/division shapes — see
|
|
47
|
+
[api-entry-points.md § Entry-point scanner constraints](api-entry-points.md#entry-point-scanner-constraints).
|
|
48
|
+
`--pack` does not validate or warn about this: a script that packs cleanly can still fail to load,
|
|
49
|
+
or load with a property callback that silently never runs. Compiling and passing tests doesn't
|
|
50
|
+
catch it either, since the source is syntactically valid JS/TS — only extraction against the built
|
|
51
|
+
`main.js` does.
|
|
52
|
+
|
|
53
|
+
After any edit to `main.ts`/`main.js`, run the extracted entry points against the **built**
|
|
54
|
+
`main.js` and confirm the expected names come back. Python:
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
#!/usr/bin/env python3
|
|
58
|
+
import re, sys
|
|
59
|
+
|
|
60
|
+
STRIP_PATTERN = re.compile(
|
|
61
|
+
r'(?:/\*.*?\*/)'
|
|
62
|
+
r'|(?:(["\'`])\1)'
|
|
63
|
+
r'|(?://.*?$)'
|
|
64
|
+
r'|(?:([/"\'`]).*?[^\\]\2)'
|
|
65
|
+
r'|(?:/(?:\\.|[^/\n])*/)'
|
|
66
|
+
r'|(?:\(\s*\w+\s*/\s*\w+\s*\))'
|
|
67
|
+
r'|(?:\w+\s*/\s*\w+)',
|
|
68
|
+
re.DOTALL | re.MULTILINE,
|
|
69
|
+
)
|
|
70
|
+
FUNC_PATTERN = re.compile(r'function[\s\n\r]+(\$?\w+)[\s\n\r]*\(', re.MULTILINE)
|
|
71
|
+
NODE_ENTRY_POINTS = {
|
|
72
|
+
'timerFired', 'jobArrived', 'getLibraryForProperty', 'getLibraryForConnectionProperty',
|
|
73
|
+
'findExternalEditorPath', 'validateProperties', 'validateConnectionProperties',
|
|
74
|
+
'httpRequestTriggeredSync', 'httpRequestTriggeredAsync', 'flowStopTriggered',
|
|
75
|
+
'flowStartTriggered', 'abort',
|
|
76
|
+
}
|
|
77
|
+
REQUIRED_ANY = {'jobArrived', 'timerFired', 'flowStopTriggered', 'httpRequestTriggeredAsync'}
|
|
78
|
+
|
|
79
|
+
code = open(sys.argv[1], encoding='utf-8').read()
|
|
80
|
+
stripped = STRIP_PATTERN.sub('', code)
|
|
81
|
+
found = [m.group(1) for m in FUNC_PATTERN.finditer(stripped) if m.group(1) in NODE_ENTRY_POINTS]
|
|
82
|
+
print('Entry points found:', found or '(none)')
|
|
83
|
+
if not (REQUIRED_ANY & set(found)):
|
|
84
|
+
sys.exit('FAIL: none of ' + str(sorted(REQUIRED_ANY)) + ' survived extraction.')
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Or Node.js:
|
|
88
|
+
|
|
89
|
+
```js
|
|
90
|
+
#!/usr/bin/env node
|
|
91
|
+
const fs = require('fs');
|
|
92
|
+
|
|
93
|
+
const STRIP_PATTERN = /(?:\/\*[\s\S]*?\*\/)|(?:(["'`])\1)|(?:\/\/.*?$)|(?:([/"'`])[\s\S]*?[^\\]\2)|(?:\/(?:\\.|[^/\n])*\/)|(?:\(\s*\w+\s*\/\s*\w+\s*\))|(?:\w+\s*\/\s*\w+)/gm;
|
|
94
|
+
const FUNC_PATTERN = /function[\s\n\r]+(\$?\w+)[\s\n\r]*\(/gm;
|
|
95
|
+
const NODE_ENTRY_POINTS = new Set([
|
|
96
|
+
'timerFired', 'jobArrived', 'getLibraryForProperty', 'getLibraryForConnectionProperty',
|
|
97
|
+
'findExternalEditorPath', 'validateProperties', 'validateConnectionProperties',
|
|
98
|
+
'httpRequestTriggeredSync', 'httpRequestTriggeredAsync', 'flowStopTriggered',
|
|
99
|
+
'flowStartTriggered', 'abort',
|
|
100
|
+
]);
|
|
101
|
+
const REQUIRED_ANY = ['jobArrived', 'timerFired', 'flowStopTriggered', 'httpRequestTriggeredAsync'];
|
|
102
|
+
|
|
103
|
+
const stripped = fs.readFileSync(process.argv[2], 'utf8').replace(STRIP_PATTERN, '');
|
|
104
|
+
const found = [];
|
|
105
|
+
let m;
|
|
106
|
+
while ((m = FUNC_PATTERN.exec(stripped)) !== null) {
|
|
107
|
+
if (NODE_ENTRY_POINTS.has(m[1])) found.push(m[1]);
|
|
108
|
+
}
|
|
109
|
+
console.log('Entry points found:', found.length ? found : '(none)');
|
|
110
|
+
if (!found.some((f) => REQUIRED_ANY.includes(f))) {
|
|
111
|
+
console.error('FAIL: none of', REQUIRED_ANY, 'survived extraction.');
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
If the required entry point is missing, dump `stripped`/the stripped output and diff it against
|
|
117
|
+
`main.js` — the first swallowed region starts at the string, regex, or division literal identified
|
|
118
|
+
in the rules above.
|
|
119
|
+
|
|
43
120
|
## Deployment
|
|
44
121
|
|
|
45
122
|
Before packing, remove dev dependencies to reduce package size — this matters because `--pack` bundles `node_modules` as-is, and the scaffolded `package.json` puts type-only packages (`@types/node`, `@types/switch-scripting`, `undici-types`) under `devDependencies`:
|
package/docs/switch-scripting.md
CHANGED
|
@@ -11,7 +11,7 @@ Detailed API docs are in `docs/switch-api/`:
|
|
|
11
11
|
|
|
12
12
|
| File | Contents | Load when |
|
|
13
13
|
|---|---|---|
|
|
14
|
-
| `switch-api/api-entry-points.md` | All entry point signatures, constraints, and when each is called | Scaffolding a
|
|
14
|
+
| `switch-api/api-entry-points.md` | All entry point signatures, constraints, and when each is called | Scaffolding a script, adding/editing an entry point, or making any edit to main.ts/main.js |
|
|
15
15
|
| `switch-api/api-switch.md` | `Switch` (`s`) — global data, webhooks, abort, server utilities | Using global data, webhooks, abort, or server settings |
|
|
16
16
|
| `switch-api/api-flow-element.md` | `FlowElement` — properties, connections, job creation, logging | Reading properties, creating jobs, logging, connections |
|
|
17
17
|
| `switch-api/api-job.md` | `Job` — routing, file access, child jobs, private data, datasets | Processing/routing jobs, file access, private data, datasets |
|
|
@@ -29,6 +29,7 @@ Detailed API docs are in `docs/switch-api/`:
|
|
|
29
29
|
| `switch-api/api-execution-environment.md` | Process/concurrency model, state persistence across job invocations, unhandled-rejection behavior, npm/native module constraints | Relying on module-level state across jobs, handling errors/rejections, or using third-party npm packages |
|
|
30
30
|
| `switch-api/api-logging.md` | Log level semantics, logging practice, `console.log` limitation, common gotchas | Adding or reviewing `job.log()`/`flowElement.log()`/`job.fail()`/`failProcess()` calls |
|
|
31
31
|
| `switch-api/api-logs-and-dataroot.md` | Locating the Application Data Root, querying `ServerLogs.db3` directly | Diagnosing or validating a script from its actual log output rather than by reading the code |
|
|
32
|
+
| `switch-api/api-app-guidelines.md` | Pre-publish checklist for Appstore apps: property naming/tooltips/editors, entry point and sendTo consistency, logging quality, packaging | Preparing a script for publication as an app, or reviewing one against Appstore submission criteria |
|
|
32
33
|
|
|
33
34
|
## Key rules
|
|
34
35
|
- Always consult the API reference files above before writing or modifying script code.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enfocussw/switch-scripting-context",
|
|
3
|
-
"version": "25.11.0-beta.
|
|
3
|
+
"version": "25.11.0-beta.11",
|
|
4
4
|
"description": "AI coding assistant context for Enfocus Switch scripting (Node.js/TypeScript)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"switch",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"license": "ISC",
|
|
41
41
|
"repository": {
|
|
42
42
|
"type": "git",
|
|
43
|
-
"url": "git+https://github.com/
|
|
43
|
+
"url": "git+https://github.com/esko-bv/enf-switch-scripting-context.git"
|
|
44
44
|
},
|
|
45
45
|
"publishConfig": {
|
|
46
46
|
"registry": "https://registry.npmjs.org/",
|
|
@@ -50,9 +50,9 @@
|
|
|
50
50
|
"@types/node": "^20.0.0",
|
|
51
51
|
"typescript": "^5.0.0"
|
|
52
52
|
},
|
|
53
|
-
"homepage": "https://github.com/
|
|
53
|
+
"homepage": "https://github.com/esko-bv/enf-switch-scripting-context#readme",
|
|
54
54
|
"bugs": {
|
|
55
|
-
"url": "https://github.com/
|
|
55
|
+
"url": "https://github.com/esko-bv/enf-switch-scripting-context/issues"
|
|
56
56
|
},
|
|
57
57
|
"engines": {
|
|
58
58
|
"node": ">=18"
|