@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.
Files changed (33) hide show
  1. package/CHANGELOG.md +504 -0
  2. package/README.md +192 -0
  3. package/bin/cli.js +8 -0
  4. package/dist/init.d.ts +78 -0
  5. package/dist/init.js +894 -0
  6. package/docs/switch-api/api-versions.md +127 -0
  7. package/docs/switch-api/connection.md +82 -0
  8. package/docs/switch-api/document-classes.md +189 -0
  9. package/docs/switch-api/entry-points.md +185 -0
  10. package/docs/switch-api/enums.md +181 -0
  11. package/docs/switch-api/execution-environment.md +143 -0
  12. package/docs/switch-api/flow-element.md +143 -0
  13. package/docs/switch-api/http.md +96 -0
  14. package/docs/switch-api/job-patterns.md +238 -0
  15. package/docs/switch-api/job.md +187 -0
  16. package/docs/switch-api/logging.md +117 -0
  17. package/docs/switch-api/switch.md +210 -0
  18. package/docs/switch-appstore/app-guidelines.md +281 -0
  19. package/docs/switch-appstore/app-manual.md +84 -0
  20. package/docs/switch-appstore/app-store-listing.md +69 -0
  21. package/docs/switch-appstore/app-store-submission.md +83 -0
  22. package/docs/switch-project/debugging.md +61 -0
  23. package/docs/switch-project/logs-and-dataroot.md +80 -0
  24. package/docs/switch-project/node-versions.md +87 -0
  25. package/docs/switch-project/project-planning.md +149 -0
  26. package/docs/switch-project/property-documentation.md +75 -0
  27. package/docs/switch-project/property-editors.md +249 -0
  28. package/docs/switch-project/script-declaration.md +407 -0
  29. package/docs/switch-project/script-structure.md +157 -0
  30. package/docs/switch-project/tooling.md +165 -0
  31. package/docs/switch-project/vscode.md +90 -0
  32. package/docs/switch-scripting.md +70 -0
  33. 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