@enfocussw/switch-scripting-context 0.1.0
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 +504 -0
- package/README.md +192 -0
- package/bin/cli.js +8 -0
- package/dist/init.d.ts +78 -0
- package/dist/init.js +894 -0
- package/docs/switch-api/api-versions.md +127 -0
- package/docs/switch-api/connection.md +82 -0
- package/docs/switch-api/document-classes.md +189 -0
- package/docs/switch-api/entry-points.md +185 -0
- package/docs/switch-api/enums.md +181 -0
- package/docs/switch-api/execution-environment.md +143 -0
- package/docs/switch-api/flow-element.md +143 -0
- package/docs/switch-api/http.md +96 -0
- package/docs/switch-api/job-patterns.md +238 -0
- package/docs/switch-api/job.md +187 -0
- package/docs/switch-api/logging.md +117 -0
- package/docs/switch-api/switch.md +210 -0
- package/docs/switch-appstore/app-guidelines.md +281 -0
- package/docs/switch-appstore/app-manual.md +84 -0
- package/docs/switch-appstore/app-store-listing.md +69 -0
- package/docs/switch-appstore/app-store-submission.md +83 -0
- package/docs/switch-project/debugging.md +61 -0
- package/docs/switch-project/logs-and-dataroot.md +80 -0
- package/docs/switch-project/node-versions.md +87 -0
- package/docs/switch-project/project-planning.md +149 -0
- package/docs/switch-project/property-documentation.md +75 -0
- package/docs/switch-project/property-editors.md +249 -0
- package/docs/switch-project/script-declaration.md +407 -0
- package/docs/switch-project/script-structure.md +157 -0
- package/docs/switch-project/tooling.md +165 -0
- package/docs/switch-project/vscode.md +90 -0
- package/docs/switch-scripting.md +70 -0
- package/package.json +65 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: enums
|
|
3
|
+
category: switch-api
|
|
4
|
+
order: 8
|
|
5
|
+
summary: "All enums with string values (`LogLevel`, `AccessLevel`, `DatasetModel`, `Scope`, `Priority`, `Connection.Level`, etc.)"
|
|
6
|
+
triggers:
|
|
7
|
+
- "Looking up enum values"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Switch Scripting Enums
|
|
11
|
+
|
|
12
|
+
All enums are available globally in `main.ts`. They are also accessible via `EnfocusSwitch.*` when used outside `main.ts` (e.g. in imported modules). Enums and values without a Switch version below exist in every Switch version with Node.js scripting; see [api-versions.md](api-versions.md).
|
|
13
|
+
|
|
14
|
+
<!-- docs-index:contents begin -->
|
|
15
|
+
## Contents
|
|
16
|
+
|
|
17
|
+
- LogLevel
|
|
18
|
+
- AccessLevel
|
|
19
|
+
- DatasetModel
|
|
20
|
+
- Scope
|
|
21
|
+
- Priority
|
|
22
|
+
- Connection.Level
|
|
23
|
+
- HttpRequest.Method
|
|
24
|
+
- PropertyType
|
|
25
|
+
- NoYesListPropertyStringValue
|
|
26
|
+
- EnfocusSwitchPrivateDataTag
|
|
27
|
+
- ImageDocument.ColorMode
|
|
28
|
+
- ImageDocument.ColorSpace
|
|
29
|
+
<!-- docs-index:contents end -->
|
|
30
|
+
|
|
31
|
+
## LogLevel
|
|
32
|
+
|
|
33
|
+
Used with `job.log()` and `flowElement.log()`.
|
|
34
|
+
|
|
35
|
+
| Value | String |
|
|
36
|
+
|---|---|
|
|
37
|
+
| `LogLevel.Info` | `"info"` |
|
|
38
|
+
| `LogLevel.Warning` | `"warning"` |
|
|
39
|
+
| `LogLevel.Error` | `"error"` |
|
|
40
|
+
| `LogLevel.Debug` | `"debug"` (Switch 21.0+) |
|
|
41
|
+
|
|
42
|
+
## AccessLevel
|
|
43
|
+
|
|
44
|
+
Used with `job.get()` and `job.getDataset()`.
|
|
45
|
+
|
|
46
|
+
| Value | String |
|
|
47
|
+
|---|---|
|
|
48
|
+
| `AccessLevel.ReadOnly` | `"readOnly"` |
|
|
49
|
+
| `AccessLevel.ReadWrite` | `"readWrite"` |
|
|
50
|
+
|
|
51
|
+
## DatasetModel
|
|
52
|
+
|
|
53
|
+
Used with `job.createDataset()`, `job.sendToLog()`, and `job.listDatasets()`.
|
|
54
|
+
|
|
55
|
+
| Value | String |
|
|
56
|
+
|---|---|
|
|
57
|
+
| `DatasetModel.Opaque` | `"Opaque"` |
|
|
58
|
+
| `DatasetModel.XML` | `"XML"` |
|
|
59
|
+
| `DatasetModel.XMP` | `"XMP"` |
|
|
60
|
+
| `DatasetModel.JDF` | `"JDF"` |
|
|
61
|
+
| `DatasetModel.JSON` | `"JSON"` (Switch 22.0+) |
|
|
62
|
+
|
|
63
|
+
## Scope
|
|
64
|
+
|
|
65
|
+
Used with `s.getGlobalData()`, `s.setGlobalData()`, `s.removeGlobalData()`.
|
|
66
|
+
|
|
67
|
+
| Value | String |
|
|
68
|
+
|---|---|
|
|
69
|
+
| `Scope.Element` | `"element"` |
|
|
70
|
+
| `Scope.Flow` | `"flow"` (Switch 22.0+) |
|
|
71
|
+
| `Scope.FlowElement` | `"flowElement"` |
|
|
72
|
+
| `Scope.FlowElements` | `"flowElements"` (Switch 22.0+) |
|
|
73
|
+
| `Scope.Global` | `"global"` |
|
|
74
|
+
|
|
75
|
+
## Priority
|
|
76
|
+
|
|
77
|
+
Used with `job.setPriority()` / `job.getPriority()`. Switch 22.1+.
|
|
78
|
+
|
|
79
|
+
| Value | Number |
|
|
80
|
+
|---|---|
|
|
81
|
+
| `Priority.Low` | `-100000` |
|
|
82
|
+
| `Priority.BelowNormal` | `-10000` |
|
|
83
|
+
| `Priority.Normal` | `0` |
|
|
84
|
+
| `Priority.AboveNormal` | `10000` |
|
|
85
|
+
| `Priority.High` | `100000` |
|
|
86
|
+
|
|
87
|
+
## Connection.Level
|
|
88
|
+
|
|
89
|
+
Used with `job.sendToData()` and `job.sendToLog()` for traffic light connections.
|
|
90
|
+
|
|
91
|
+
| Value | String |
|
|
92
|
+
|---|---|
|
|
93
|
+
| `Connection.Level.Success` | `"success"` |
|
|
94
|
+
| `Connection.Level.Warning` | `"warning"` |
|
|
95
|
+
| `Connection.Level.Error` | `"error"` |
|
|
96
|
+
|
|
97
|
+
Also available as `EnfocusSwitch.Connection.Level.*` outside `main.ts`. It selects which level to
|
|
98
|
+
route to; it is not a property you can read back from a `Connection` object, see
|
|
99
|
+
[connection.md § Connection.Level enum](connection.md#connectionlevel-enum).
|
|
100
|
+
|
|
101
|
+
## HttpRequest.Method
|
|
102
|
+
|
|
103
|
+
Used with `s.httpRequestSubscribe()` and `s.httpRequestUnsubscribe()`. Switch 21.1+.
|
|
104
|
+
|
|
105
|
+
| Value | String |
|
|
106
|
+
|---|---|
|
|
107
|
+
| `HttpRequest.Method.POST` | `"POST"` |
|
|
108
|
+
| `HttpRequest.Method.PUT` | `"PUT"` |
|
|
109
|
+
| `HttpRequest.Method.DELETE` | `"DELETE"` |
|
|
110
|
+
|
|
111
|
+
Also available as `EnfocusSwitch.HttpRequest.Method.*` outside `main.ts`.
|
|
112
|
+
|
|
113
|
+
## PropertyType
|
|
114
|
+
|
|
115
|
+
Returned by `flowElement.getPropertyType()` and `connection.getPropertyType()`.
|
|
116
|
+
|
|
117
|
+
| Value | String |
|
|
118
|
+
|---|---|
|
|
119
|
+
| `PropertyType.Literal` | `"literal"` |
|
|
120
|
+
| `PropertyType.Number` | `"number"` |
|
|
121
|
+
| `PropertyType.Date` | `"date"` |
|
|
122
|
+
| `PropertyType.HoursAndMinutes` | `"hoursandminutes"` |
|
|
123
|
+
| `PropertyType.Boolean` | `"boolean"` |
|
|
124
|
+
| `PropertyType.String` | `"string"` |
|
|
125
|
+
| `PropertyType.FilePath` | `"filepath"` |
|
|
126
|
+
| `PropertyType.FolderPath` | `"folderpath"` |
|
|
127
|
+
| `PropertyType.FileType` | `"filetype"` |
|
|
128
|
+
| `PropertyType.FolderPattern` | `"folderpattern"` |
|
|
129
|
+
| `PropertyType.Regex` | `"regex"` |
|
|
130
|
+
| `PropertyType.OAuthToken` | `"oauthtoken"` |
|
|
131
|
+
|
|
132
|
+
## NoYesListPropertyStringValue
|
|
133
|
+
|
|
134
|
+
Convenience for `Boolean`-typed properties returned as strings. Switch 24.0+.
|
|
135
|
+
|
|
136
|
+
| Value | String |
|
|
137
|
+
|---|---|
|
|
138
|
+
| `NoYesListPropertyStringValue.No` | `"No"` |
|
|
139
|
+
| `NoYesListPropertyStringValue.Yes` | `"Yes"` |
|
|
140
|
+
|
|
141
|
+
## EnfocusSwitchPrivateDataTag
|
|
142
|
+
|
|
143
|
+
Well-known tags for `job.getPrivateData()` / `job.setPrivateData()`. The enum needs Switch 21.0+; `initiated` and `submittedTo` need 21.1+, and `state` needs 22.1+.
|
|
144
|
+
|
|
145
|
+
| Value | String |
|
|
146
|
+
|---|---|
|
|
147
|
+
| `EnfocusSwitchPrivateDataTag.hierarchy` | `"EnfocusSwitch.hierarchy"` |
|
|
148
|
+
| `EnfocusSwitchPrivateDataTag.emailAddresses` | `"EnfocusSwitch.emailAddresses"` |
|
|
149
|
+
| `EnfocusSwitchPrivateDataTag.emailBody` | `"EnfocusSwitch.emailBody"` |
|
|
150
|
+
| `EnfocusSwitchPrivateDataTag.userName` | `"EnfocusSwitch.userName"` |
|
|
151
|
+
| `EnfocusSwitchPrivateDataTag.userFullName` | `"EnfocusSwitch.userFullName"` |
|
|
152
|
+
| `EnfocusSwitchPrivateDataTag.userEmail` | `"EnfocusSwitch.userEmail"` |
|
|
153
|
+
| `EnfocusSwitchPrivateDataTag.origin` | `"EnfocusSwitch.origin"` |
|
|
154
|
+
| `EnfocusSwitchPrivateDataTag.initiated` | `"EnfocusSwitch.initiated"` |
|
|
155
|
+
| `EnfocusSwitchPrivateDataTag.submittedTo` | `"EnfocusSwitch.submittedTo"` |
|
|
156
|
+
| `EnfocusSwitchPrivateDataTag.state` | `"EnfocusSwitch.state"` |
|
|
157
|
+
|
|
158
|
+
## ImageDocument.ColorMode
|
|
159
|
+
|
|
160
|
+
Used with `ImageDocument.getColorMode()`. Available as `EnfocusSwitch.ImageDocument.ColorMode.*` outside `main.ts`. Switch 21.1+.
|
|
161
|
+
|
|
162
|
+
| Value | String |
|
|
163
|
+
|---|---|
|
|
164
|
+
| `ImageDocument.ColorMode.Bitmap` | `"Bitmap"` |
|
|
165
|
+
| `ImageDocument.ColorMode.Gray` | `"Gray"` |
|
|
166
|
+
| `ImageDocument.ColorMode.IndexedColor` | `"Indexed color"` |
|
|
167
|
+
| `ImageDocument.ColorMode.RGB` | `"RGB"` |
|
|
168
|
+
| `ImageDocument.ColorMode.CMYK` | `"CMYK"` |
|
|
169
|
+
| `ImageDocument.ColorMode.Multichannel` | `"Multichannel"` |
|
|
170
|
+
| `ImageDocument.ColorMode.Duotone` | `"Duotone"` |
|
|
171
|
+
| `ImageDocument.ColorMode.LabColor` | `"Lab color"` |
|
|
172
|
+
| `ImageDocument.ColorMode.Unknown` | `"Unknown"` |
|
|
173
|
+
|
|
174
|
+
## ImageDocument.ColorSpace
|
|
175
|
+
|
|
176
|
+
Used with `ImageDocument.getColorSpace()`. Available as `EnfocusSwitch.ImageDocument.ColorSpace.*` outside `main.ts`. Switch 21.1+.
|
|
177
|
+
|
|
178
|
+
| Value | String |
|
|
179
|
+
|---|---|
|
|
180
|
+
| `ImageDocument.ColorSpace.SRGB` | `"sRGB"` |
|
|
181
|
+
| `ImageDocument.ColorSpace.Uncalibrated` | `"uncalibrated"` |
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: execution-environment
|
|
3
|
+
category: switch-api
|
|
4
|
+
order: 17
|
|
5
|
+
summary: "Execution modes (`Concurrent`/`Serialized`, `ExecutionGroup`, `NumberOfSlots`), process/concurrency model, state persistence across job invocations, unhandled-rejection behavior, npm/native module constraints"
|
|
6
|
+
triggers:
|
|
7
|
+
- "Choosing or changing an execution mode, relying on module-level state across jobs, handling errors/rejections, or using third-party npm packages"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Execution Environment
|
|
11
|
+
|
|
12
|
+
How the Node.js process a script runs in behaves, beyond the entry point API itself. Apart from the
|
|
13
|
+
execution mode below, these are consequences of the host process model rather than things a script
|
|
14
|
+
configures — understanding them avoids subtle bugs around state persistence and error handling.
|
|
15
|
+
|
|
16
|
+
<!-- docs-index:contents begin -->
|
|
17
|
+
## Contents
|
|
18
|
+
|
|
19
|
+
- Execution modes
|
|
20
|
+
- Two independent concurrency tiers
|
|
21
|
+
- Don't rely on in-memory state between entry point calls
|
|
22
|
+
- Unhandled promise rejections end the run, not the process
|
|
23
|
+
- Third-party npm modules: file-based scripts only
|
|
24
|
+
- Native (binary) addons are not supported
|
|
25
|
+
- No explicit CPU or memory cap beyond the documented thresholds
|
|
26
|
+
<!-- docs-index:contents end -->
|
|
27
|
+
|
|
28
|
+
## Execution modes
|
|
29
|
+
|
|
30
|
+
Set in the XML declaration via SwitchScripter, or by editing it directly (see
|
|
31
|
+
[script-declaration.md](../switch-project/script-declaration.md#built-in-elementfields)). Applies to all
|
|
32
|
+
instances of the script.
|
|
33
|
+
|
|
34
|
+
**Concurrent** — entry points for the same or different instances may run in parallel. Scripts must
|
|
35
|
+
synchronize access to any shared resources; for global data, use the `lock` parameter of
|
|
36
|
+
`getGlobalData` (see [switch.md § Locking](switch.md#locking)). `NumberOfSlots` is only meaningful in
|
|
37
|
+
this mode.
|
|
38
|
+
|
|
39
|
+
**Serialized** — entry points within the same **execution group** are never concurrent. Instances
|
|
40
|
+
in different execution groups may still run in parallel.
|
|
41
|
+
|
|
42
|
+
**Execution group** — only relevant for Serialized mode. Should be a reverse-domain string (e.g.
|
|
43
|
+
`com.mycompany.myScript`) to avoid collisions. Defaults to the Script ID if left empty.
|
|
44
|
+
|
|
45
|
+
Neither setting maps to a count of Node.js OS processes — see below.
|
|
46
|
+
|
|
47
|
+
## Two independent concurrency tiers
|
|
48
|
+
|
|
49
|
+
`NumberOfSlots`/`ExecutionGroup` (above) and the pool of Node.js processes that
|
|
50
|
+
actually run script code are governed completely separately — there is no one-to-one mapping between
|
|
51
|
+
them:
|
|
52
|
+
|
|
53
|
+
- **`NumberOfSlots`** is a job-admission throttle on the Switch Server, scoped to that one flow
|
|
54
|
+
element instance (keyed by flow + element id): it limits how many jobs may be dispatched to that
|
|
55
|
+
instance at once, falling back to a server-wide default if left as `Default`. **`ExecutionGroup`**
|
|
56
|
+
(meaningful only for `Serialized` mode) is a true cross-flow-element named lock — every flow
|
|
57
|
+
element that declares the same group string, anywhere on the server, contends for one shared lock.
|
|
58
|
+
Neither is a count of OS processes.
|
|
59
|
+
- Separately, a shared pool of long-lived Node.js executor processes actually runs the script code
|
|
60
|
+
for every script element on the server, sized by a single server-wide concurrency setting — not
|
|
61
|
+
one process per slot, per instance, or per script. A job dispatched by the Server is handed to
|
|
62
|
+
whichever pooled executor is free (or a new one is spawned if none are); executors are reused
|
|
63
|
+
across many jobs and across different flow elements running the same Node.js version, until
|
|
64
|
+
recycled (see
|
|
65
|
+
[Executor cleanup thresholds](job-patterns.md#executor-cleanup-thresholds)).
|
|
66
|
+
|
|
67
|
+
## Don't rely on in-memory state between entry point calls
|
|
68
|
+
|
|
69
|
+
Write every entry point so it neither depends on state from an earlier call nor assumes it starts
|
|
70
|
+
from a clean process.
|
|
71
|
+
|
|
72
|
+
The executor evaluates the whole script again before every entry point call. Top-level
|
|
73
|
+
`let`/`const`/`var` declarations and functions in the script file are recreated each time, so a
|
|
74
|
+
counter or cache held in one does not carry over to the next job.
|
|
75
|
+
|
|
76
|
+
Some in-memory state can still outlive a call, because executor processes are long-lived and
|
|
77
|
+
shared:
|
|
78
|
+
|
|
79
|
+
- Properties set on `global`/`globalThis`. One executor runs code for every script element pooled
|
|
80
|
+
onto it, so a global can be read or overwritten by a different script.
|
|
81
|
+
- Internal state of CommonJS packages loaded with `require()`. Node caches a required module for
|
|
82
|
+
the life of the process, so a singleton inside the package (a client, a connection pool, a
|
|
83
|
+
configured default) can be reused by a later call. ES-module packages that are bundled into the
|
|
84
|
+
script (see [Native (binary) addons](#native-binary-addons-are-not-supported)) are evaluated
|
|
85
|
+
again on each call like the script itself.
|
|
86
|
+
- Timers, sockets, and other handles a call leaves open keep running after the entry point returns.
|
|
87
|
+
|
|
88
|
+
Whether any of this reaches a given job depends on which executor the job lands on and whether that
|
|
89
|
+
executor was recycled in between. A script cannot control or predict either. This is a side effect
|
|
90
|
+
of the process model, not a supported feature, and it can change between Switch versions:
|
|
91
|
+
|
|
92
|
+
- Don't use globals or package-level singletons to cache data or pass it between jobs. Store data
|
|
93
|
+
that must outlive a call with `s.setGlobalData()` (see [switch.md](switch.md)) or on the job
|
|
94
|
+
itself.
|
|
95
|
+
- Don't set globals. If a package keeps internal state, configure it explicitly at the start of
|
|
96
|
+
each entry point rather than assuming either a fresh or a previously configured instance.
|
|
97
|
+
- Close connections, clear timers, and release file handles before the entry point returns.
|
|
98
|
+
|
|
99
|
+
Switch logs this message when a call leaves async work pending, as a Warning before Switch 26.11
|
|
100
|
+
and as a Debug message from 26.11: "The script execution has ended while an async function or
|
|
101
|
+
callback in the script might not have finished yet. Please check the script code for unresolved
|
|
102
|
+
promises or missing await statements." On Switch 26.07 it appeared
|
|
103
|
+
when an entry point returned while a `getGlobalData` call was still pending. The
|
|
104
|
+
executor waits one event-loop turn plus 5 ms after the entry point's promise resolves, then logs the
|
|
105
|
+
message if a promise, timer or callback started during the call is still alive, so a timer left
|
|
106
|
+
behind by `Promise.race` triggers it too. From 26.11 it only reaches the log when "Log debug
|
|
107
|
+
messages" is on (see [logging.md](logging.md)); before 26.11 every run that triggers it logs a
|
|
108
|
+
Warning. Treat it as a missing `await` or an unsettled promise: whatever is still pending can keep running after the entry point has returned.
|
|
109
|
+
|
|
110
|
+
The executor also recognises `getInitialize()`/`getFinalize()` functions in a script. They are not
|
|
111
|
+
part of the public scripting API; don't define them.
|
|
112
|
+
|
|
113
|
+
## Unhandled promise rejections end the run, not the process
|
|
114
|
+
|
|
115
|
+
An unhandled promise rejection inside an entry point call ends that job's/run's execution — but the
|
|
116
|
+
underlying executor process is **not** killed and continues serving subsequent job invocations,
|
|
117
|
+
including for other flow elements pooled onto the same executor. Don't rely on an unhandled
|
|
118
|
+
rejection to surface as a hard failure of the whole executor; always catch and handle errors
|
|
119
|
+
explicitly (e.g. via `job.fail()`/`flowElement.failProcess()` — see
|
|
120
|
+
[logging.md](logging.md)) rather than letting a promise reject unhandled.
|
|
121
|
+
|
|
122
|
+
## Third-party npm modules: file-based scripts only
|
|
123
|
+
|
|
124
|
+
A script **expression** (entered inline in a flow element property, not a file-based script/app —
|
|
125
|
+
see [Script expression](entry-points.md#script-expression)) cannot use third-party npm modules
|
|
126
|
+
at all; only Node.js built-ins are available via `require`. A file-based script/app can use
|
|
127
|
+
third-party modules from its own `node_modules` folder (see
|
|
128
|
+
[Script folder files](../switch-project/script-structure.md#script-folder-files)).
|
|
129
|
+
|
|
130
|
+
## Native (binary) addons are not supported
|
|
131
|
+
|
|
132
|
+
Scripts with ESM dependencies are bundled before execution, when `SwitchVersion` in `manifest.xml`
|
|
133
|
+
is `24.0` or higher (see
|
|
134
|
+
[node-versions.md § Other effects of `SwitchVersion`](../switch-project/node-versions.md#other-effects-of-switchversion)); this bundling path does not support
|
|
135
|
+
native/binary Node addons (`.node` files). Stick to pure-JavaScript/TypeScript dependencies.
|
|
136
|
+
|
|
137
|
+
## No explicit CPU or memory cap beyond the documented thresholds
|
|
138
|
+
|
|
139
|
+
Beyond the entry-point abort timeout and executor recycling thresholds already documented (see
|
|
140
|
+
[Job processing](entry-points.md#job-processing) and
|
|
141
|
+
[Executor cleanup thresholds](job-patterns.md#executor-cleanup-thresholds)), there is no
|
|
142
|
+
additional CPU-time or memory limit enforced on a script's own code. A runaway loop or leak is
|
|
143
|
+
bounded only by those thresholds, not stopped proactively.
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: flow-element
|
|
3
|
+
category: switch-api
|
|
4
|
+
order: 4
|
|
5
|
+
summary: "`FlowElement`: properties, connections, job creation, logging"
|
|
6
|
+
triggers:
|
|
7
|
+
- "Reading properties, creating jobs, logging, connections"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# FlowElement Class
|
|
11
|
+
|
|
12
|
+
The `FlowElement` instance `flowElement` is passed to every entry point that operates on a flow element. It provides access to properties, connections, job creation, and logging.
|
|
13
|
+
|
|
14
|
+
<!-- docs-index:contents begin -->
|
|
15
|
+
## Contents
|
|
16
|
+
|
|
17
|
+
- Identity
|
|
18
|
+
- Properties
|
|
19
|
+
- Connections
|
|
20
|
+
- Timer
|
|
21
|
+
- Logging
|
|
22
|
+
- Job creation (jobArrived / timerFired / httpRequestTriggeredAsync)
|
|
23
|
+
- Channels
|
|
24
|
+
- Utilities
|
|
25
|
+
<!-- docs-index:contents end -->
|
|
26
|
+
|
|
27
|
+
## Identity
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
// Switch 21.1+
|
|
31
|
+
flowElement.getName(): string
|
|
32
|
+
```
|
|
33
|
+
Returns the name of this flow element.
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
// Switch 22.0+
|
|
37
|
+
flowElement.getFlowName(): string
|
|
38
|
+
```
|
|
39
|
+
Returns the name of the flow containing this element.
|
|
40
|
+
|
|
41
|
+
## Properties
|
|
42
|
+
|
|
43
|
+
Properties are configured by the user in the Switch canvas and declared in the script's XML declaration.
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
flowElement.getPropertyStringValue(tag: string): Promise<string | string[]>
|
|
47
|
+
```
|
|
48
|
+
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 [script-declaration.md § Dependency](../switch-project/script-declaration.md#custom-property-elements-elementfields). A property just added to the declaration also counts as unknown until the element is reloaded with "Reload script" — see [script-declaration.md § Agent editing policy](../switch-project/script-declaration.md#agent-editing-policy). 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 [property-editors.md](../switch-project/property-editors.md) for editor types and their return value formats.
|
|
49
|
+
|
|
50
|
+
> **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.
|
|
51
|
+
>
|
|
52
|
+
> **Workaround for deferred processing:** Read property values in `jobArrived` and store them with `s.setGlobalData()`. In `timerFired`, retrieve the stored values and fetch the waiting jobs with `flowElement.getJobs(ids)` (Switch 21.0+). Several `jobArrived` invocations can update the stored list at once, so lock it while you change it; see [job-patterns.md § Shared state in global data](job-patterns.md#shared-state-in-global-data).
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
flowElement.getPropertyType(tag: string): PropertyType
|
|
56
|
+
```
|
|
57
|
+
Returns the `PropertyType` of the property — required to correctly interpret the string value when multiple input types are possible.
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
flowElement.getPropertyDisplayName(tag: string): string
|
|
61
|
+
```
|
|
62
|
+
Returns the English display name of the property (for use in log messages).
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
flowElement.hasProperty(tag: string): boolean
|
|
66
|
+
```
|
|
67
|
+
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.
|
|
68
|
+
|
|
69
|
+
## Connections
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
flowElement.getOutConnections(): Connection[]
|
|
73
|
+
```
|
|
74
|
+
Returns all outgoing connections (arbitrary order). Empty array if none.
|
|
75
|
+
|
|
76
|
+
## Timer
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
flowElement.setTimerInterval(seconds: number): void
|
|
80
|
+
```
|
|
81
|
+
Sets the interval between `timerFired` invocations. Default is 300 s. The actual interval may be longer under load.
|
|
82
|
+
|
|
83
|
+
**Only takes effect when called from `timerFired`.** Switch applies the new interval once that invocation returns. Called from any other entry point (`flowStartTriggered`, `jobArrived`, ...), the value is ignored and Switch logs the Warning `A timer interval can only be set inside a 'timerFired' entry point`. The new interval applies from the next `timerFired` call onwards.
|
|
84
|
+
|
|
85
|
+
## Logging
|
|
86
|
+
|
|
87
|
+
See [logging.md](logging.md) for log level semantics and logging practice.
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
flowElement.log(level: LogLevel, message: string, messageParams?: (string | number | boolean)[]): Promise<void>
|
|
91
|
+
```
|
|
92
|
+
Logs a message for the flow element. Use `%1`, `%2`, etc. in the message string for substitution via `messageParams`.
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
flowElement.failProcess(message: string, messageParam?: string | number | boolean): void
|
|
96
|
+
```
|
|
97
|
+
Logs a fatal error and puts the element into the "problem process" state. `messageParam` substitutes `%1`; before Switch 22.1, always pass it, as a string (see [api-versions.md](api-versions.md#declaration-changes-to-existing-methods)). Throws `"Job routing is not allowed in this entry point."` if called from an entry point where routing isn't permitted.
|
|
98
|
+
|
|
99
|
+
## Job creation (jobArrived / timerFired / httpRequestTriggeredAsync)
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
flowElement.createJob(path: string): Promise<Job>
|
|
103
|
+
```
|
|
104
|
+
Creates a new job from an existing file/folder path. Valid in `jobArrived`, `timerFired`, and `httpRequestTriggeredAsync` (confirmed working there; the only webhook entry point that receives `flowElement`). The new job has default properties (no parent). The caller is responsible for cleaning up the source file after routing. See [job-patterns.md](job-patterns.md#temp-file-cleanup) for temp file cleanup rules and [job-patterns.md](job-patterns.md#sending-jobs) for routing constraints.
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
// Switch 21.0+
|
|
108
|
+
flowElement.getJobs(ids: string[]): Promise<Job[]>
|
|
109
|
+
```
|
|
110
|
+
Returns up to 10,000 waiting jobs by ID. Throws if `ids` is not an array, is empty, or exceeds 10,000 entries. Call at most once per entry point. Not available in concurrent `jobArrived`. Private data and metadata of returned jobs cannot be read in the same invocation.
|
|
111
|
+
|
|
112
|
+
## Channels
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
// Switch 22.1+
|
|
116
|
+
flowElement.subscribeToChannel(channelId: string, backingFolderPath: string): void
|
|
117
|
+
```
|
|
118
|
+
Subscribes to a channel to receive jobs from it. Only one subscriber per channel at a time. Must be called inside `flowStartTriggered`.
|
|
119
|
+
|
|
120
|
+
## Utilities
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
// Switch 24.0+
|
|
124
|
+
flowElement.createPathWithName(name: string, createFolder: boolean): Promise<any>
|
|
125
|
+
```
|
|
126
|
+
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 [job-patterns.md](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.
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
// Switch 24.1+
|
|
130
|
+
flowElement.getFileCount(nested?: boolean): Promise<number>
|
|
131
|
+
```
|
|
132
|
+
Returns the number of files in the active flow. If `nested` is `false`, counts only direct children; if `true` (the default, so it can be omitted), counts recursively (folders themselves are not counted).
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
// Switch 24.0+
|
|
136
|
+
flowElement.getScriptDataPath(): string
|
|
137
|
+
```
|
|
138
|
+
Returns the path to the ScriptData folder for this element.
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
flowElement.getPluginResourcesPath(): string
|
|
142
|
+
```
|
|
143
|
+
Returns the script resources folder path. For scripted plug-ins and apps, returns the resources folder. For script folders, returns the folder path. **For a regular script package (`.sscript`) running locally**, returns the parent folder of the deployed package file — external resources are not bundled inside the package itself, so anything the script needs at runtime must be placed in that parent folder alongside the `.sscript`, not referenced from inside it. **Throws** `"flowElement.getPluginResourcesPath() is supported only in App or Configurator."` for a non-local (server-deployed) `.sscript` package.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: http
|
|
3
|
+
category: switch-api
|
|
4
|
+
order: 7
|
|
5
|
+
summary: "`HttpRequest` / `HttpResponse` + webhook pattern"
|
|
6
|
+
triggers:
|
|
7
|
+
- "Handling incoming HTTP webhooks"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# HttpRequest & HttpResponse Classes
|
|
11
|
+
|
|
12
|
+
Used in the `httpRequestTriggeredSync` and `httpRequestTriggeredAsync` entry points (see [entry-points.md § Webhooks](entry-points.md#webhooks)). Webhook subscriptions are registered via `s.httpRequestSubscribe()` (see [switch.md § Webhooks](switch.md#webhooks)) in `flowStartTriggered`. Both classes, `HttpRequest.Method`, and the subscribe methods need Switch 21.1+ (see [api-versions.md](api-versions.md)).
|
|
13
|
+
|
|
14
|
+
## HttpRequest
|
|
15
|
+
|
|
16
|
+
Represents an incoming webhook HTTP request.
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
request.method: HttpRequest.Method // "POST" | "PUT" | "DELETE"
|
|
20
|
+
request.path: string // relative URL path
|
|
21
|
+
request.query: { [key: string]: string | string[] } // query string parameters
|
|
22
|
+
request.headers: { [header: string]: string } // request headers
|
|
23
|
+
request.remoteAddress: string // client IP address
|
|
24
|
+
request.body: ArrayBuffer | undefined // raw request body
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
request.getBodyAsString(): string
|
|
29
|
+
```
|
|
30
|
+
Returns the raw request body decoded as a UTF-8 string.
|
|
31
|
+
|
|
32
|
+
## HttpResponse
|
|
33
|
+
|
|
34
|
+
Used only in `httpRequestTriggeredSync` to send a response before the function returns.
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
response.setStatusCode(statusCode: number): void
|
|
38
|
+
```
|
|
39
|
+
Set the HTTP status code (e.g. `200`, `400`, `500`).
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
response.setHeader(name: string, value: string): void
|
|
43
|
+
```
|
|
44
|
+
Set a response header.
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
response.setBody(data: ArrayBuffer | string): void
|
|
48
|
+
```
|
|
49
|
+
Set the response body.
|
|
50
|
+
|
|
51
|
+
## HttpRequest.Method enum
|
|
52
|
+
|
|
53
|
+
| Value | String |
|
|
54
|
+
|---|---|
|
|
55
|
+
| `HttpRequest.Method.POST` | `"POST"` |
|
|
56
|
+
| `HttpRequest.Method.PUT` | `"PUT"` |
|
|
57
|
+
| `HttpRequest.Method.DELETE` | `"DELETE"` |
|
|
58
|
+
|
|
59
|
+
Available as `EnfocusSwitch.HttpRequest.Method.*` outside `main.ts`.
|
|
60
|
+
|
|
61
|
+
## Webhook pattern
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
// flowStartTriggered — subscribe once when the flow starts
|
|
65
|
+
async function flowStartTriggered(s: Switch, flowElement: FlowElement): Promise<void> {
|
|
66
|
+
await s.httpRequestSubscribe(HttpRequest.Method.POST, '/my-path', []);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// flowStopTriggered — unsubscribe when the flow stops
|
|
70
|
+
async function flowStopTriggered(s: Switch, flowElement: FlowElement): Promise<void> {
|
|
71
|
+
await s.httpRequestUnsubscribe(HttpRequest.Method.POST, '/my-path');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// httpRequestTriggeredSync — handle synchronously, must set response before returning
|
|
75
|
+
async function httpRequestTriggeredSync(request: HttpRequest, args: any[], response: HttpResponse, s: Switch): Promise<void> {
|
|
76
|
+
const body = request.getBodyAsString();
|
|
77
|
+
response.setStatusCode(200);
|
|
78
|
+
response.setHeader('Content-Type', 'application/json');
|
|
79
|
+
response.setBody(JSON.stringify({ received: true }));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// httpRequestTriggeredAsync — handle asynchronously, no response required
|
|
83
|
+
async function httpRequestTriggeredAsync(request: HttpRequest, args: any[], s: Switch, flowElement: FlowElement): Promise<void> {
|
|
84
|
+
const body = request.getBodyAsString();
|
|
85
|
+
// process asynchronously...
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Constraints
|
|
90
|
+
|
|
91
|
+
- Request body limit: 1 MB (server returns HTTP 413 if exceeded)
|
|
92
|
+
- Queue limit: 10,000 pending requests per element (HTTP 429)
|
|
93
|
+
- Sync handler execution timeout: 1 minute (HTTP 524)
|
|
94
|
+
- Default sync response if none set explicitly: HTTP 200 with body `{"status": true}`
|
|
95
|
+
- Async handler only invoked if sync handler is absent or returned a 2xx status
|
|
96
|
+
- Use unpredictable URL paths for security
|