@enfocussw/switch-scripting-context 25.11.0-beta.8

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.
@@ -0,0 +1,351 @@
1
+ # Script Declaration (XML)
2
+
3
+ The file `<ScriptID>.xml` defines the script's metadata, custom properties, connection properties,
4
+ and execution configuration. It is normally written by **SwitchScripter**, but the format is fully
5
+ documented below — you can edit it directly.
6
+
7
+ ## Agent editing policy
8
+
9
+ - Editing this file directly is safe as long as you follow the rules on this page exactly — the
10
+ format has no schema, so Switch will silently misbehave (not error) on a malformed attribute.
11
+ - Preserve every attribute you don't intend to change. Don't reformat, reorder attributes, or drop
12
+ fields you don't understand.
13
+ - `Name` is the script's stable ID — never change it on an existing script (it's used as the flow
14
+ element type and referenced by installed flows). `DisplayName`, tooltips, defaults, adding/removing
15
+ custom properties, and connection topology are all safe to change directly.
16
+ - After editing, `Version` should be bumped (integer, no leading zeros necessary beyond `1`) so
17
+ Switch treats it as an update.
18
+ - Custom property tag names must match `^[A-Za-z][A-Za-z0-9]*$`, must not start with `xml`
19
+ (case-insensitive), and must not collide with a [reserved tag](#reserved-tag-names) below. Switch
20
+ does **not** sanitize or rewrite bad tag names on load — it just fails to work correctly.
21
+ - `manifest.xml` (declares the package's program file(s) and type) rarely needs edits; treat it as
22
+ low-risk to read but confirm with the user before changing `ScriptPackageType`,
23
+ `ScriptDeclarationFile`, or `ScriptProgramFiles`.
24
+ - Never add or edit `ApplicationPath` or `ApplicationLicense` — these are app-only properties that
25
+ point Switch at a third-party application's install location and license. They must be set by the
26
+ user from the Switch Scripter GUI after the script package has been packed; Switch silently drops
27
+ them if written into the declaration file directly.
28
+
29
+ ---
30
+
31
+ ## XML structure overview
32
+
33
+ ```xml
34
+ <?xml version="1.0" encoding="UTF-8"?>
35
+ <Object>
36
+ <ElementFields> <!-- required: built-in fields + custom property elements -->
37
+ <ConnectionFields> <!-- optional: custom outgoing-connection property elements -->
38
+ <ExtraProperties> <!-- optional: OAuth 2.0 editor config only -->
39
+ </Object>
40
+ ```
41
+
42
+ `ElementFields` is required — Switch rejects the whole declaration without it. `ConnectionFields`
43
+ and `ExtraProperties` may be omitted or left empty.
44
+
45
+ ---
46
+
47
+ ## Built-in ElementFields
48
+
49
+ These configure the flow element (name, topology, execution, pane placement, docs). All carry
50
+ `Editor="hide"` and are never shown to the user directly. Add `Type="..."` to a field only when the
51
+ value is non-string (see the table); an empty string field can omit `Type`.
52
+
53
+ | Element | Values | Notes |
54
+ |---|---|---|
55
+ | `Name` | string | Stable script ID — **never change on an existing script**. Becomes the flow element `Type`. |
56
+ | `DisplayName` | string | Shown in Switch. Empty falls back to `Name`. A `~` splits "Vendor~Element" — Switch shows the part after `~` as the short name and the whole string (space-joined) as the full name. |
57
+ | `Version` | number | Format `[1-9][0-9]*(\.(0\|[1-9][0-9]*))*`, e.g. `1`, `2.1`. Bump on every declaration change. |
58
+ | `Keywords` | string | Space/comma/semicolon-separated. Elements pane search. |
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). |
62
+ | `ConnectionType` | `Move` \| `Filter` \| `TrafficLight` | Governs which `ConnectionFields` children are legal — see [ConnectionFields](#connectionfields). |
63
+ | `FunctionsNodeJSScript` | `;`-separated names | Entry point function names found in the script. Omit the element entirely if there is no Node.js program. |
64
+ | `ExecutionMode` | `Concurrent` \| `Serialized` | |
65
+ | `NumberOfSlots` | `Default` \| integer | Only meaningful when `Concurrent`. |
66
+ | `ExecutionGroup` | string | Only meaningful when `Serialized`. Empty falls back to `Name`. |
67
+ | `PerformanceTuning` | `Yes` \| `No` | When `Yes`, `IdleAfterJob` (and `NumberOfSlots` if concurrent) become visible/editable in Switch. |
68
+ | `IdleAfterJob` | number (seconds) | |
69
+ | `PositionInElementPane` | `Basics` \| `Tools` \| `Communication` \| `Apps` \| `Configurators` \| `Metadata` \| `Database` | Which section of the Elements pane the script appears under. |
70
+ | `SubcategoryInElementPane` | escaped XML, see [§ escaped payloads](#escaped-valuedescription-payloads) | Apps/Configurators only. |
71
+ | `DispositionInElementPane` | numeric string or empty | Sort position within the category. Empty = alphabetical. |
72
+ | `Description` | string | Long description. |
73
+ | `Compatibility` | string | Configurator only: third-party app compatibility notes. |
74
+ | `SupportInfo` | string | Configurator only: support email/URL. |
75
+ | `AppDiscovery` | string | Configurator only: how the app is located on disk. |
76
+ | `FlowUpgradeWarning` | string | Warning shown during flow upgrade. |
77
+ | `UpgradeMaximumVersion` | number | Previous version up to which the upgrade warning is shown. Optional. |
78
+ | `Connections` | string | Prose description of outgoing connections, for generated docs. |
79
+ | `SwitchModule` | `Configurator` \| `Metadata` \| `Scripting` \| `Database` \| `SwitchClient` \| `SwitchClientSDK` | Licensing module. |
80
+ | `ObsoleteProperties` | `;`/`,`/whitespace-separated tag names | Suppresses "unknown property" warnings when a flow already has properties you removed. Add old tag names here when removing a custom property. |
81
+ | `ObsoleteConnectionProperties` | same | Same, for removed connection properties. |
82
+
83
+ Do **not** add `ApplicationPath` or `ApplicationLicense` as element names — Switch silently drops
84
+ them. These app-only properties must be configured by the user from the Switch Scripter GUI after
85
+ the package is packed, not written into the declaration file.
86
+
87
+ ---
88
+
89
+ ## Custom property elements (ElementFields)
90
+
91
+ Each user-defined property is a child element of `<ElementFields>` with `UserDefined="true"`. The
92
+ element name is the property's **tag** (used as the `tag` argument in `getPropertyStringValue()`)
93
+ and must follow the [tag name rules](#reserved-tag-names).
94
+
95
+ The element must **never be self-closing**. Its text content holds the property's *current value*
96
+ — e.g. `<Count ...>8</Count>`, not `<Count ... Default="8" />`. A self-closing custom property is
97
+ non-editable in Switch Designer.
98
+
99
+ ```xml
100
+ <MyProperty UserDefined="true" Type="string" Editor="choosefolder" LocalizedTagName="My Property"
101
+ Tooltip="Select the output folder" DetailedInfo="" Validation="Standard" Default=""
102
+ Subtype="">Default value goes here</MyProperty>
103
+ ```
104
+
105
+ Key attributes:
106
+
107
+ | Attribute | Description |
108
+ |---|---|
109
+ | `UserDefined` | Always `"true"` for custom properties. |
110
+ | `Type` | Value type discriminator — see [Type reference](#type-reference). |
111
+ | `Editor` | `;`-joined chain of editor tokens (inline editor first, then modal editors) — see [api-property-editors.md](api-property-editors.md). |
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. |
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 an `isPropertyValid` entry point) \| `Standard and custom` (both, custom only runs if standard passes). |
117
+ | `Default` | Default value string. Omit only if the value is emitted as CDATA instead. |
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
+ | `DependencyCondition` | One of: `Not-empty`, `Equals`, `Not-equals`, `Contains`, `Does not contain`, `Matches`, `Does not match`, `Starts with`, `Does not start with`. |
120
+ | `Dependencyvalue` | Value(s) to compare against — `;`-separated for multiple. Note the lowercase `v`. |
121
+
122
+ **Dependency example** — show `OutputFolder` only when `Mode` equals `"Custom"`:
123
+
124
+ ```xml
125
+ <Mode UserDefined="true" Type="enum:Default;Custom" Editor="inline" Subtype="inline"
126
+ LocalizedTagName="Mode" Tooltip="" DetailedInfo="" Validation="Standard"
127
+ Default="Default">Default</Mode>
128
+ <OutputFolder UserDefined="true" Type="string" Editor="choosefolder" Subtype=""
129
+ Dependency="Mode" DependencyCondition="Equals" Dependencyvalue="Custom"
130
+ LocalizedTagName="Output folder" Tooltip="" DetailedInfo=""
131
+ Validation="Standard" Default=""></OutputFolder>
132
+ ```
133
+
134
+ Attribute order in the file doesn't matter functionally — SwitchScripter's own output happens to be
135
+ alphabetical (QDom sorts attributes on write), but any order parses correctly.
136
+
137
+ ---
138
+
139
+ ## ConnectionFields
140
+
141
+ Custom outgoing-connection properties follow the same attribute pattern as element properties, with
142
+ one addition: `AvailableFor="Data"` or `AvailableFor="Log"` restricts which connection kind shows the
143
+ property; omit the attribute for both.
144
+
145
+ ```xml
146
+ <ConnectionFields>
147
+ <TargetFolder AvailableFor="Data" UserDefined="true" Type="string" Editor="choosefolder"
148
+ Subtype="" LocalizedTagName="Target folder" Tooltip="" DetailedInfo=""
149
+ Validation="Standard" Default=""></TargetFolder>
150
+ </ConnectionFields>
151
+ ```
152
+
153
+ Connection property values are read at runtime via `connection.getPropertyStringValue(tag)`.
154
+
155
+ **`ConnectionType` gates which built-in connection fields may appear here** — this is the single
156
+ most important thing to get right when hand-editing this section:
157
+
158
+ | `ConnectionType` | Legal built-in children |
159
+ |---|---|
160
+ | `Move` | none — `<ConnectionFields/>` must be empty of built-ins |
161
+ | `Filter` | `IncludeFolderMask`, `ExcludeFolderMask` (both or neither) |
162
+ | `TrafficLight` | `Success`, `Warning`, `Error`, each optionally with `AvailableFor="Data"` or `AvailableFor="Log"` (omit the attribute if available for both; omit the whole element if available for neither) |
163
+
164
+ ```xml
165
+ <!-- ConnectionType = TrafficLight -->
166
+ <ConnectionFields>
167
+ <Success AvailableFor="Data" LocalizedTagName="Success out" Type="bool" Editor="inline" Default="Yes">Yes</Success>
168
+ <Error AvailableFor="Data" LocalizedTagName="Error out" Type="bool" Editor="inline" Default="Yes">Yes</Error>
169
+ <!-- no Warning element: not available for Data or Log -->
170
+ </ConnectionFields>
171
+ ```
172
+
173
+ Custom (author-defined) connection properties may be added regardless of `ConnectionType`.
174
+
175
+ **Caution — package-swap connection preservation:** Switch Designer decides whether existing flow
176
+ connections survive a script package replace by comparing the serialised `ConnectionFields` and
177
+ `IncomingConnections` text **byte-for-byte** between old and new declarations, and additionally
178
+ checks whether `ConnectionType`/`OutgoingConnections` changed. Don't make cosmetic whitespace or
179
+ attribute-order changes to those sections without expecting existing flows' outgoing connection
180
+ properties to reset on next package update.
181
+
182
+ ---
183
+
184
+ ## ExtraProperties
185
+
186
+ Only used for OAuth 2.0 (`Editor` containing `oauth`, see
187
+ [api-property-editors.md](api-property-editors.md)). One child element per OAuth property, named
188
+ identically to the property's tag, in `ElementFields` or `ConnectionFields`:
189
+
190
+ ```xml
191
+ <ElementFields>
192
+ <OAuth1 UserDefined="true" Type="string" Editor="oauth" Subtype="" LocalizedTagName="OAuth1"
193
+ Tooltip="" DetailedInfo="" Validation="Standard" Default=""></OAuth1>
194
+ </ElementFields>
195
+ <ExtraProperties>
196
+ <OAuth1 OAuthAuthorizationEndpoint="http://auth-url"
197
+ OAuthClientID="AppID1"
198
+ OAuthClientSecret="Application Password 123"
199
+ OAuthClientSecretEditor="inline"
200
+ OAuthRedirPorts="666"
201
+ OAuthRedirPortsEditor="inline"
202
+ OAuthScope="some-random-scope"
203
+ OAuthScopeEditor="inline"
204
+ OAuthTokenEndpoint="http://token-url"/>
205
+ </ExtraProperties>
206
+ ```
207
+
208
+ Attributes: `OAuthAuthorizationEndpoint`, `OAuthClientID`, `OAuthClientSecret`, `OAuthRedirPorts`,
209
+ `OAuthTokenEndpoint`, `OAuthScope`. A companion `<Attr>Editor` attribute is only needed when that
210
+ attribute has more than one valid input mode; otherwise omit it. If the package is
211
+ password-protected, `OAuthClientSecret` must be stored encrypted — leave OAuth secret edits to the
212
+ user rather than writing a plaintext secret into a password-protected package.
213
+
214
+ If no OAuth property exists on the script, omit `ExtraProperties` entirely or leave it empty
215
+ (`<ExtraProperties/>`).
216
+
217
+ ---
218
+
219
+ ## Type reference
220
+
221
+ `Type` is a single token, except for enums:
222
+
223
+ | Token | Meaning |
224
+ |---|---|
225
+ | `string` | Text |
226
+ | `number` | Integer |
227
+ | `rational` | Decimal |
228
+ | `password` | Masked text |
229
+ | `bool` | `Yes`/`No` |
230
+ | `date`, `datetime`, `time` | `time` is hours-and-minutes |
231
+ | `path` | Filesystem path |
232
+ | `enum:A;B;C` | Closed choice list, `;`-separated (a trailing `;` is tolerated) |
233
+ | `filefilter`, `folderfilter` | File / folder filter values |
234
+ | `stringlist` | List of strings |
235
+ | `accountlist` | Account list |
236
+
237
+ This is the *authoring* vocabulary written into the XML `Type` attribute. It does not map one-to-one
238
+ onto the runtime `PropertyType` returned by `getPropertyType()` (see
239
+ [api-property-editors.md](api-property-editors.md) and [api-enums.md](api-enums.md)) — e.g. XML
240
+ `bool` becomes runtime `boolean`, XML `path` splits into runtime `filepath`/`folderpath`, and several
241
+ XML types (`rational`, `stringlist`, `accountlist`, `enum:...`, `datetime`, `time`) have no direct
242
+ `PropertyType` counterpart while several runtime values (`filetype`, `folderpattern`, `regex`,
243
+ `oauthtoken`, `literal`) have no direct XML `Type` counterpart. Don't assume the two vocabularies are
244
+ interchangeable.
245
+
246
+ `Type` is not independently authored on properties with a modal editor chain — it follows from
247
+ which editor(s) you choose, per [api-property-editors.md](api-property-editors.md). When combining
248
+ an inline editor with modal editors (e.g. `Editor="inline;sltextwithvar;scriptexp"`), the inline
249
+ editor's type wins: an inline Number editor plus those modal editors still yields `Type="number"`.
250
+
251
+ ---
252
+
253
+ ## Escaped `ValueDescription` payloads
254
+
255
+ `SubcategoryInElementPane` (and a couple of internal-only fields) store a nested XML fragment,
256
+ escaped into the text node:
257
+
258
+ ```xml
259
+ <SubcategoryInElementPane Editor="hide">&lt;ValueDescription Type="stringlist">
260
+ &lt;Value>Communication&lt;/Value>
261
+ &lt;/ValueDescription>
262
+ </SubcategoryInElementPane>
263
+ ```
264
+
265
+ Decodes to:
266
+
267
+ ```xml
268
+ <ValueDescription Type="stringlist">
269
+ <Value>Communication</Value>
270
+ </ValueDescription>
271
+ ```
272
+
273
+ One `Value` child per subcategory string. Escaping only `<` (not also `&quot;`) is fine — both forms
274
+ parse.
275
+
276
+ ---
277
+
278
+ ## Reserved tag names
279
+
280
+ A custom property or connection property tag must not collide with any built-in field name. Do not
281
+ use any of:
282
+
283
+ - Any [built-in `ElementFields` name](#built-in-elementfields) above.
284
+ - Any built-in `ConnectionFields` name: `IncludeFolderMask`, `ExcludeFolderMask`, `Success`,
285
+ `Warning`, `Error`.
286
+ - `Type`, `Category`, `ElementDescription`, `LogDebugMessages`, `SPSDebugMode`, `SPSDebugPort`,
287
+ `SPSDebugEntryPoints`, `AbortTimeoutMinutes`, `ScriptPackagePath`, `Xpos`, `Ypos`, `ElementIcon`,
288
+ `LastModified`, `Path`, `customExecutionMode`, `AdvancedTuningEnabled`, `Hold`, `TrafficType`,
289
+ `CorneringFactor`, `ElementType`.
290
+ - `ApplicationPath`, `ApplicationLicense` (legal as a tag, but Switch silently drops these two from
291
+ the flow element's property set, so don't use them). These are app-only properties, set by the
292
+ user from the Switch Scripter GUI after packing — never modify them directly.
293
+
294
+ Also required: tag matches `^[A-Za-z][A-Za-z0-9]*$` and does not start with `xml` (case-insensitive).
295
+
296
+ ---
297
+
298
+ ## Annotated example
299
+
300
+ Representative declaration with Move connections, custom properties, and a dependency chain:
301
+
302
+ ```xml
303
+ <Object>
304
+ <ElementFields>
305
+ <Name Editor="hide" Type="string">depositJob</Name>
306
+ <DisplayName Editor="hide" Type="string"></DisplayName>
307
+ <Version Editor="hide" Type="number">1</Version>
308
+ <Keywords Editor="hide" Type="string"></Keywords>
309
+ <Tooltip Editor="hide" Type="string"></Tooltip>
310
+ <IncomingConnections RequireAtLeastOne="Yes" Editor="hide">Yes</IncomingConnections>
311
+ <OutgoingConnections RequireAtLeastOne="Yes" DetailedInfo="" Editor="hide">Unlimited</OutgoingConnections>
312
+ <ConnectionType Editor="hide">Move</ConnectionType>
313
+ <FunctionsNodeJSScript Editor="hide">jobArrived</FunctionsNodeJSScript>
314
+ <ExecutionMode Editor="hide">Concurrent</ExecutionMode>
315
+ <NumberOfSlots Editor="hide">Default</NumberOfSlots>
316
+ <ExecutionGroup Editor="hide"></ExecutionGroup>
317
+ <PerformanceTuning Editor="hide">No</PerformanceTuning>
318
+ <IdleAfterJob Editor="hide" Type="number">0</IdleAfterJob>
319
+ <PositionInElementPane Editor="hide">Tools</PositionInElementPane>
320
+ <DispositionInElementPane Editor="hide" Type="number"></DispositionInElementPane>
321
+ <Description Editor="hide" Type="string"></Description>
322
+ <Connections Editor="hide" Type="string"></Connections>
323
+ <SwitchModule Editor="hide" Type="string">Scripting</SwitchModule>
324
+ <ObsoleteProperties Editor="hide" Type="string"></ObsoleteProperties>
325
+ <ObsoleteConnectionProperties Editor="hide" Type="string"></ObsoleteConnectionProperties>
326
+
327
+ <!-- Custom property: folder chooser -->
328
+ <DepositFolder UserDefined="true" Type="string" Editor="choosefolder" Subtype=""
329
+ LocalizedTagName="Deposit folder" Tooltip="" DetailedInfo=""
330
+ Validation="Standard" Default=""></DepositFolder>
331
+
332
+ <!-- Custom property: dropdown enum -->
333
+ <AttachAs UserDefined="true" Type="enum:Job;Dataset" Editor="inline" Subtype="inline"
334
+ LocalizedTagName="Attach as" Tooltip="" DetailedInfo="" Validation="Standard"
335
+ Default="Job">Job</AttachAs>
336
+
337
+ <!-- Custom property: bool, depends on AttachAs = "Dataset" -->
338
+ <IncludeMetadata UserDefined="true" Type="bool" Editor="inline" Subtype="inline"
339
+ Dependency="AttachAs" DependencyCondition="Equals" Dependencyvalue="Dataset"
340
+ LocalizedTagName="Include metadata" Tooltip="" DetailedInfo=""
341
+ Validation="Standard" Default="No">No</IncludeMetadata>
342
+
343
+ <!-- Custom property: literal "Default" editor combined with a modal editor -->
344
+ <FallbackFolder UserDefined="true" Type="string" Editor="default;choosefolder" Subtype=""
345
+ LocalizedTagName="Fallback folder" Tooltip="" DetailedInfo=""
346
+ Validation="Standard" Default="Default">Default</FallbackFolder>
347
+ </ElementFields>
348
+ <ConnectionFields/>
349
+ <ExtraProperties/>
350
+ </Object>
351
+ ```
@@ -0,0 +1,85 @@
1
+ # Script Project Structure
2
+
3
+ A Switch script project lives in a **script folder** during development and is distributed as a `.sscript` package (ZIP).
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.
6
+
7
+ ## Script folder files
8
+
9
+ | File | Required | Notes |
10
+ |---|---|---|
11
+ | `manifest.xml` | Yes | Switch internal use only. Do not edit manually. |
12
+ | `<ScriptID>.xml` | Yes | Script declaration (properties, connections, execution config). See [api-script-declaration.md](api-script-declaration.md). |
13
+ | `main.ts` | Yes (TypeScript) | Source file. Edit this. |
14
+ | `main.js` | Yes | Compiled output executed by Switch. Generated by transpiling `main.ts`. |
15
+ | `main.js.map` | No | Source map, generated alongside `main.js`. |
16
+ | `package.json` | Yes (TypeScript) | NPM config for type declarations. |
17
+ | `tsconfig.json` | Yes (TypeScript) | TypeScript transpilation options. |
18
+ | `<IconFileName>.png` | No | 32×32 px, RGB, not interlaced. Extension must be `.png`. |
19
+ | `node_modules/` | No | Local npm packages. |
20
+ | `Resources/` | No | Extra resource files bundled when packing with SwitchScriptTool. |
21
+ | `<LanguageCode>.ts` | No | Translation files (Switch App SDK). |
22
+ | `.vscode/launch.json` | No | Debug config (created by SwitchScriptTool). |
23
+ | `.vscode/switch.code-snippets` | No | Entry point snippets (TypeScript only). |
24
+
25
+ > After editing `main.ts`, transpile with SwitchScriptTool to regenerate `main.js` before testing in Switch.
26
+
27
+ ## manifest.xml format
28
+
29
+ ```xml
30
+ <Manifest>
31
+ <ScripterInstanceName>myScript</ScripterInstanceName>
32
+ <SwitchVersion>24.0</SwitchVersion>
33
+ <ScriptPackageFormatVersion>1.0</ScriptPackageFormatVersion>
34
+ <ScriptPasswordProtected>No</ScriptPasswordProtected>
35
+ <ScriptPackageType>Script</ScriptPackageType>
36
+ <ScriptDeclarationFile>myScript.xml</ScriptDeclarationFile>
37
+ <ScriptProgramFiles>
38
+ <ScriptProgramFile ScriptLanguage="NodeJSScript">main.ts</ScriptProgramFile>
39
+ </ScriptProgramFiles>
40
+ <ScriptIconFile>myScript_32.png</ScriptIconFile>
41
+ <LocalizationItems/>
42
+ </Manifest>
43
+ ```
44
+
45
+ `ScriptPackageType` is either `Script` (regular) or `App` (scripted plug-in).
46
+
47
+ ## Node.js version per Switch version
48
+
49
+ `SwitchVersion` in `manifest.xml` determines which Node.js version executes the script — Switch uses the **latest** Node.js version bundled with the Switch release that created the script.
50
+
51
+ | Switch version | `SwitchVersion` | Node.js used |
52
+ |---|---|---|
53
+ | Switch 2020 Spring | `20.0` | 12 |
54
+ | Switch 2020 Fall | `20.1` | 12 |
55
+ | Switch 2021 Spring | `21.0` | 14 |
56
+ | Switch 2021 Fall | `21.1` | 16 |
57
+ | Switch 2022 Spring | `22.0` | 16 |
58
+ | Switch 2022 Fall | `22.1` | 16 |
59
+ | Switch 2023 Fall | `23.1` | 18 |
60
+ | Switch 2024 Spring | `24.0` | 18 |
61
+ | Switch 2024 Fall | `24.1` | 20 |
62
+ | Switch 25.11 | `25.11` | 20 |
63
+
64
+ > **Mac (Apple Silicon):** For scripts created in Switch 2021 Fall or later, Switch runs the native ARM build of Node.js on Apple Silicon. Scripts created in earlier versions run under Rosetta using the Intel Node.js build. If a script bundles platform-specific binaries, ship both Intel and ARM variants.
65
+
66
+ ## Script vs App
67
+
68
+ | | Script | App |
69
+ |---|---|---|
70
+ | `ScriptPackageType` | `Script` | `App` |
71
+ | Appears in Elements pane | No (used via Script element) | Yes, as its own element |
72
+ | Distribution | Freely | Enfocus Appstore only |
73
+ | Position in pane | — | Configured via `PositionInElementPane` in XML |
74
+
75
+ ## Execution modes
76
+
77
+ Set in the XML declaration via SwitchScripter. Applies to all instances of the script.
78
+
79
+ **Concurrent** — entry points for the same or different instances may run in parallel. Scripts must synchronize access to any shared resources.
80
+
81
+ **Serialized** — entry points within the same **execution group** are never concurrent. Instances in different execution groups may still run in parallel.
82
+
83
+ **Execution group** — only relevant for Serialized mode. Should be a reverse-domain string (e.g. `com.mycompany.myScript`) to avoid collisions. Defaults to the Script ID if left empty.
84
+
85
+ See [api-execution-environment.md](api-execution-environment.md#two-independent-concurrency-tiers) — neither `NumberOfSlots` nor execution group maps to a count of Node.js OS processes; they gate job dispatch on the Switch Server, separate from the pooled executor processes that actually run script code.
@@ -0,0 +1,75 @@
1
+ # Switch Class
2
+
3
+ The `Switch` instance `s` is passed to every entry point. It provides global data storage, webhook subscription, abort handling, and server utilities.
4
+
5
+ ## Global data
6
+
7
+ Global data is key/value storage shared across entry point invocations, scoped by `Scope`.
8
+
9
+ | Scope | Shared across |
10
+ |---|---|
11
+ | `Scope.FlowElement` | This script element instance only |
12
+ | `Scope.FlowElements` | All instances of the same script in the same flow |
13
+ | `Scope.Element` | All instances of the same script across all flows |
14
+ | `Scope.Flow` | All elements in the same flow |
15
+ | `Scope.Global` | Any element in any flow — use sparingly; prefix tags with your company name |
16
+
17
+ Dates stored via `setGlobalData` are returned as strings by `getGlobalData` — parse them in your script.
18
+
19
+ ```ts
20
+ s.getGlobalData(scope: Scope, tag: string, lock?: boolean): Promise<any>
21
+ s.getGlobalData(scope: Scope, tags: string[], lock?: boolean): Promise<{ tag: string, value: any }[]>
22
+ ```
23
+ Read one or multiple values. Returns `''` (empty string) for a tag that doesn't exist, not `undefined`. Optional `lock` (default `false`) prevents concurrent writes until `setGlobalData` is called or the entry point ends.
24
+
25
+ More than 100 global data calls (`getGlobalData`/`setGlobalData` combined) in a single entry point invocation logs a warning — this is an advisory client-side counter, not an enforced server-side limit, but a sign the script should batch reads/writes.
26
+
27
+ ```ts
28
+ s.setGlobalData(scope: Scope, tag: string, value: any): Promise<void>
29
+ s.setGlobalData(scope: Scope, globalData: { tag: string, value: any }[]): Promise<void>
30
+ ```
31
+ Write one or multiple values. Releases any lock held for the same scope/tag.
32
+
33
+ ```ts
34
+ s.removeGlobalData(scope: Scope, tag: string): Promise<void>
35
+ s.removeGlobalData(scope: Scope, tags: string[]): Promise<void>
36
+ ```
37
+ Delete one or multiple global data entries.
38
+
39
+ > **Global data is never removed automatically.** Entries persist in Switch's database until explicitly deleted with `removeGlobalData`. Scripts that skip cleanup accumulate entries indefinitely and can fill the database. Always remove global data as soon as it is no longer needed.
40
+
41
+ ## Webhooks
42
+
43
+ ```ts
44
+ s.httpRequestSubscribe(method: HttpRequest.Method, path: string, args: any[]): Promise<void>
45
+ ```
46
+ Subscribe to incoming HTTP requests. Call inside `flowStartTriggered`. The absolute URL is `https://<host>:51088/scripting/${path}`. `path` must start with `/` (e.g. `/my-path`) or the call throws `"Wrong format of the subscription path."`. The `args` array is forwarded to the `httpRequestTriggeredSync` / `httpRequestTriggeredAsync` entry points.
47
+
48
+ ```ts
49
+ s.httpRequestUnsubscribe(method: HttpRequest.Method, path: string): Promise<void>
50
+ ```
51
+ Unsubscribe a previously registered webhook.
52
+
53
+ ## Abort
54
+
55
+ ```ts
56
+ s.setAbortData(abortData: any): void
57
+ ```
58
+ Store a value that will be passed to the `abort` entry point when the configured abort timeout expires.
59
+
60
+ ## Server utilities
61
+
62
+ ```ts
63
+ s.getPreferenceSetting(settingKey: string): Promise<any>
64
+ ```
65
+ Retrieve a Switch preference setting. `settingKey` format: `"settingGroup"` or `"settingGroup/settingName"`. Returns `''` if the setting/group doesn't exist. Any field whose name contains `password`, `pwd`, or `secret` is redacted in the result. The returned value is JSON-stringified, not a raw object.
66
+
67
+ ```ts
68
+ s.getServerVersion(): number
69
+ ```
70
+ Returns the Switch server version as `majorVersion + updateNumber/100` (e.g. Switch 25.11 → `25.11`), not a literal version string — don't parse it as one.
71
+
72
+ ```ts
73
+ Switch.tr(str: string): string
74
+ ```
75
+ Static method. Marks a string literal for translation (used by SwitchScriptTool). Returns the string unchanged at runtime.
@@ -0,0 +1,61 @@
1
+ # Script Folders, Packages & SwitchScriptTool
2
+
3
+ ## Script folder vs script package
4
+
5
+ | | Script folder | Script package (`.sscript`) |
6
+ |---|---|---|
7
+ | Use for | Development, version control | Production, deployment |
8
+ | Included in flow export | **No** | Yes |
9
+ | TypeScript transpile | Manual — `SwitchScriptTool --transpile` | Automatic in SwitchScripter |
10
+ | Password protection | Not supported | Optional |
11
+ | Can be used as App | No — must pack first | Yes |
12
+
13
+ Script folders are not included in flow exports or backups. Never use a script folder in production — pack it to a `.sscript` package first.
14
+
15
+ ## SwitchScriptTool
16
+
17
+ Command-line tool included with Switch. May not be on `PATH` — fall back to the known install
18
+ location for the current OS if the bare command isn't found.
19
+
20
+ **Windows:** `C:\Program Files\Enfocus\Enfocus Switch\SwitchScriptTool\SwitchScriptTool.exe` (add to PATH to avoid typing the full path)
21
+
22
+ **macOS:** symlinked to `/usr/local/bin/SwitchScriptTool` by the installer. If the symlink is missing, the real binary is bundled inside the SwitchScripter app: `/Applications/Enfocus/Enfocus Switch/SwitchScripter.app/Contents/MacOS/SwitchScriptTool/SwitchScriptTool`.
23
+
24
+ ## Commands
25
+
26
+ | Mode | Command | Purpose |
27
+ |---|---|---|
28
+ | Create | `SwitchScriptTool --create <ScriptID> <Path> [--JavaScript]` | Scaffold a new script folder with all required files |
29
+ | Transpile | `SwitchScriptTool --transpile <Path>` | Compile `main.ts` → `main.js`. **Must use this, not `tsc` directly** |
30
+ | Pack | `SwitchScriptTool --pack <Folder> <Output> [--password <pwd>] [--verbose]` | Create `.sscript` package for deployment |
31
+ | Unpack | `SwitchScriptTool --unpack <file.sscript> <Folder> [--password <pwd>]` | Extract package to folder |
32
+ | List | `SwitchScriptTool --list <file.sscript>` | List package contents (no password needed) |
33
+ | Generate translations | `SwitchScriptTool --generate-translations <ScriptFolder> <ResultFolder>` | Generate translation files for the script package |
34
+
35
+ **Create** scaffolds: `manifest.xml`, `<ScriptID>.xml`, `<ScriptID>.sscript`, `main.ts` (or `main.js` with `--JavaScript`), `.vscode/launch.json`, `Resources/`, plus `package.json`, `tsconfig.json`, `.vscode/switch.code-snippets`, and type declarations for TypeScript. Creates `<Path>/<ScriptID>/` — it does not write into `<Path>` directly. `ScriptID` may only contain letters, digits, hyphens, and underscores.
36
+
37
+ **Transpile** is required after every edit to `main.ts` before testing a **script folder** directly in Switch. Switch executes `main.js` only — `main.ts` is never run directly. Using SwitchScriptTool (not `tsc`) ensures the same transpile options as SwitchScripter, which is required for consistent behavior. This step is **not** needed before packing — see Pack below.
38
+
39
+ **Pack** transpiles `main.ts` fresh into the package on every run; it never reads or modifies any `main.js` already sitting in the source folder (a stale hand-edited `main.js` there is ignored and left untouched — see the excluded-files note below). It always excludes `package.json` and `.vscode/` from the packed output, printed as an "Info: will not be packed" list even without `--verbose`; `--verbose` additionally prints the full list of what *will* be packed. `node_modules` is packed as-is, so run `npm prune --production` first (see Deployment) — otherwise `devDependencies` (including `@types/*` packages, which the scaffolded `package.json` puts there) get bundled into the package for no runtime benefit. One harmless quirk: the placeholder `<ScriptID>.sscript` file scaffolded by `--create` is not excluded and ends up packed inside the real `.sscript` too.
40
+
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
+
43
+ ## Deployment
44
+
45
+ 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`:
46
+
47
+ ```
48
+ npm prune --production
49
+ ```
50
+
51
+ Then pack:
52
+
53
+ ```
54
+ SwitchScriptTool --pack <ScriptFolder> <OutputFolder>
55
+ ```
56
+
57
+ Reasons not to use a script folder in production:
58
+ - Not included in flow exports or backups
59
+ - Slower execution than a package
60
+ - Any syntax error saved to `main.js` immediately breaks the running script
61
+ - No password protection available
@@ -0,0 +1,62 @@
1
+ # VS Code Setup
2
+
3
+ ## Type declarations
4
+
5
+ Enables autocomplete and type checking for `Switch`, `Job`, `FlowElement` and all Switch API globals.
6
+
7
+ **Via npm (preferred):** Add to `devDependencies` in `package.json` and run `npm install`:
8
+
9
+ ```json
10
+ "@types/switch-scripting": "https://github.com/enfocus-switch/types-switch-scripting/archive/refs/tags/v24.1.1-final.tar.gz"
11
+ ```
12
+
13
+ **Manual fallback:** Download `index.d.ts` from the types repo and place it at `node_modules/@types/switch-scripting/index.d.ts` inside the script folder.
14
+
15
+ > `SwitchScriptTool --create` sets this up automatically for new TypeScript script folders.
16
+
17
+ ## TypeScript 6 / VS Code 1.114+
18
+
19
+ From VS Code 1.114, TypeScript 6 is used. Ambient/global types are no longer auto-included — without explicit configuration, `@types/node` and `@types/switch-scripting` globals (`Switch`, `Job`, etc.) will not be recognised.
20
+
21
+ Add a `types` array to `compilerOptions` in `tsconfig.json`:
22
+
23
+ ```json
24
+ {
25
+ "compilerOptions": {
26
+ "types": ["node", "switch-scripting"]
27
+ }
28
+ }
29
+ ```
30
+
31
+ ## ESLint rules
32
+
33
+ Two rules that catch Switch-specific async bugs before runtime:
34
+
35
+ - **`require-await`** — flags `async` functions that never actually `await`, catching accidentally dropped API call promises
36
+ - **`@typescript-eslint/no-floating-promises`** — errors on any unawaited promise; in Switch scripts these cause silent race conditions that are very difficult to diagnose
37
+
38
+ Example `.eslintrc`:
39
+
40
+ ```json
41
+ {
42
+ "root": true,
43
+ "parser": "@typescript-eslint/parser",
44
+ "parserOptions": { "project": "./tsconfig.json" },
45
+ "plugins": ["@typescript-eslint", "prettier"],
46
+ "extends": [
47
+ "eslint:recommended",
48
+ "plugin:@typescript-eslint/eslint-recommended",
49
+ "plugin:@typescript-eslint/recommended",
50
+ "prettier"
51
+ ],
52
+ "rules": {
53
+ "require-await": 2,
54
+ "@typescript-eslint/no-floating-promises": 2,
55
+ "prettier/prettier": 2
56
+ }
57
+ }
58
+ ```
59
+
60
+ ## Snippets
61
+
62
+ `SwitchScriptTool --create` generates `.vscode/switch.code-snippets` with entry point scaffolding (prefix `switch…`). See the hub doc for details.