@enfocussw/switch-scripting-context 25.11.0-beta.10
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 +81 -0
- package/README.md +151 -0
- package/bin/cli.js +8 -0
- package/dist/init.d.ts +19 -0
- package/dist/init.js +616 -0
- package/docs/switch-api/api-connection.md +63 -0
- package/docs/switch-api/api-debugging.md +51 -0
- package/docs/switch-api/api-document-classes.md +167 -0
- package/docs/switch-api/api-entry-points.md +82 -0
- package/docs/switch-api/api-enums.md +153 -0
- package/docs/switch-api/api-execution-environment.md +70 -0
- package/docs/switch-api/api-flow-element.md +112 -0
- package/docs/switch-api/api-http.md +87 -0
- package/docs/switch-api/api-job-patterns.md +96 -0
- package/docs/switch-api/api-job.md +156 -0
- package/docs/switch-api/api-logging.md +53 -0
- package/docs/switch-api/api-logs-and-dataroot.md +71 -0
- package/docs/switch-api/api-property-editors.md +144 -0
- package/docs/switch-api/api-script-declaration.md +351 -0
- package/docs/switch-api/api-script-structure.md +85 -0
- package/docs/switch-api/api-switch.md +75 -0
- package/docs/switch-api/api-tooling.md +61 -0
- package/docs/switch-api/api-vscode.md +62 -0
- package/docs/switch-scripting.md +40 -0
- package/package.json +60 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Debugging Scripts
|
|
2
|
+
|
|
3
|
+
Debugging requires configuring the Script element in Switch Designer — the agent cannot do this directly but can guide the user through the steps.
|
|
4
|
+
|
|
5
|
+
## Constraints
|
|
6
|
+
|
|
7
|
+
- Only works with script folders and non-password-protected packages
|
|
8
|
+
- Only one script can be in debug mode at a time
|
|
9
|
+
- Execution mode is forced to Serialized while debug is enabled
|
|
10
|
+
- Only these four entry points can be debugged: `jobArrived`, `timerFired`, `httpRequestTriggeredAsync`, `findExternalEditorPath`
|
|
11
|
+
|
|
12
|
+
## Enabling debug mode in Switch Designer
|
|
13
|
+
|
|
14
|
+
In the Script element properties, once a script folder or package is selected, three extra properties appear:
|
|
15
|
+
|
|
16
|
+
| Property | Value |
|
|
17
|
+
|---|---|
|
|
18
|
+
| Enable debug mode | Yes |
|
|
19
|
+
| Port | 9229 (default) |
|
|
20
|
+
| Debug entry points | Select from the supported entry points above |
|
|
21
|
+
|
|
22
|
+
## Attaching VS Code
|
|
23
|
+
|
|
24
|
+
**Script folder:** Open the script folder in VS Code and press F5. The `.vscode/launch.json` created by `SwitchScriptTool --create` is pre-configured for attach mode.
|
|
25
|
+
|
|
26
|
+
**Package (no `launch.json`):** Create `launch.json` manually:
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"version": "0.2.0",
|
|
31
|
+
"configurations": [
|
|
32
|
+
{
|
|
33
|
+
"type": "node",
|
|
34
|
+
"request": "attach",
|
|
35
|
+
"name": "Attach",
|
|
36
|
+
"port": 9229,
|
|
37
|
+
"skipFiles": ["<node_internals>/**"]
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Use the port number set in the Script element properties.
|
|
44
|
+
|
|
45
|
+
After attaching, VS Code stops in internal Switch code first — press F5 once more to reach the script entry point. Set breakpoints anywhere in the entry point being debugged.
|
|
46
|
+
|
|
47
|
+
## Critical warning
|
|
48
|
+
|
|
49
|
+
**Disable debug mode in Switch Designer when the debug session is finished.**
|
|
50
|
+
|
|
51
|
+
If left enabled, the flow hangs silently — `jobArrived` leaves jobs stuck in the input folder, other entry points hang with no visible error or indication.
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Document Classes
|
|
2
|
+
|
|
3
|
+
Read-only document introspection utilities. All methods may throw — wrap in `try/catch`. Load this file when working with PDF, image, XML, or XMP documents.
|
|
4
|
+
|
|
5
|
+
## PdfDocument
|
|
6
|
+
|
|
7
|
+
Open a PDF to inspect metadata and page geometry.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
PdfDocument.open(path: string): PdfDocument
|
|
11
|
+
```
|
|
12
|
+
Opens the PDF. Call `close()` when done.
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
doc.close(): void
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
doc.getNumberOfPages(): number
|
|
20
|
+
PdfDocument.getNumberOfPages(path: string): number
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
doc.getPDFVersion(): string // e.g. "1.6"
|
|
25
|
+
PdfDocument.getPDFVersion(path: string): string
|
|
26
|
+
|
|
27
|
+
doc.getPDFXVersion(): string // empty string if not PDF/X
|
|
28
|
+
PdfDocument.getPDFXVersion(path: string): string
|
|
29
|
+
|
|
30
|
+
doc.getSecurityMethod(): string
|
|
31
|
+
PdfDocument.getSecurityMethod(path: string): string
|
|
32
|
+
|
|
33
|
+
doc.getPage(pageNumber?: number): PdfPage // 1-based; defaults to page 1
|
|
34
|
+
doc.getXMP(): XmpDocument
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Static page dimension methods
|
|
38
|
+
|
|
39
|
+
All take `(path: string, pageNumber?: number, effective?: boolean)` — page numbers are 1-based, `effective` defaults to `true` (applies rotation and scaling). All return `number` in points.
|
|
40
|
+
|
|
41
|
+
| Method | Description |
|
|
42
|
+
|---|---|
|
|
43
|
+
| `PdfDocument.getPageHeight` | Alias for media box height |
|
|
44
|
+
| `PdfDocument.getPageWidth` | Alias for media box width |
|
|
45
|
+
| `PdfDocument.getPageMediaBoxHeight` / `Width` | Media box |
|
|
46
|
+
| `PdfDocument.getPageCropBoxHeight` / `Width` | Crop box |
|
|
47
|
+
| `PdfDocument.getPageBleedBoxHeight` / `Width` | Bleed box |
|
|
48
|
+
| `PdfDocument.getPageTrimBoxHeight` / `Width` | Trim box |
|
|
49
|
+
| `PdfDocument.getPageArtBoxHeight` / `Width` | Art box — **known issue:** currently returns the crop box value instead (not expected to be fixed soon) |
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
PdfDocument.getPageRotation(path: string, pageNumber?: number): number // degrees
|
|
53
|
+
PdfDocument.getPageScaling(path: string, pageNumber?: number): number
|
|
54
|
+
PdfDocument.getPageLabel(path: string, pageNumber?: number): string // empty if none
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## PdfPage
|
|
60
|
+
|
|
61
|
+
Obtained via `PdfDocument.getPage()`. Instance-level page geometry. All dimensions in points.
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
page.getHeight(effective?: boolean): number // alias for getMediaBoxHeight
|
|
65
|
+
page.getWidth(effective?: boolean): number // alias for getMediaBoxWidth
|
|
66
|
+
|
|
67
|
+
page.getMediaBoxHeight(effective?: boolean): number
|
|
68
|
+
page.getMediaBoxWidth(effective?: boolean): number
|
|
69
|
+
page.getCropBoxHeight(effective?: boolean): number
|
|
70
|
+
page.getCropBoxWidth(effective?: boolean): number
|
|
71
|
+
page.getBleedBoxHeight(effective?: boolean): number
|
|
72
|
+
page.getBleedBoxWidth(effective?: boolean): number
|
|
73
|
+
page.getTrimBoxHeight(effective?: boolean): number
|
|
74
|
+
page.getTrimBoxWidth(effective?: boolean): number
|
|
75
|
+
page.getArtBoxHeight(effective?: boolean): number // known issue: currently returns the crop box value
|
|
76
|
+
page.getArtBoxWidth(effective?: boolean): number // known issue: currently returns the crop box value
|
|
77
|
+
|
|
78
|
+
page.getRotation(): number // degrees
|
|
79
|
+
page.getScaling(): number
|
|
80
|
+
page.getPageLabel(): string // empty if none
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`effective` defaults to `true` — applies rotation and scaling.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## ImageDocument
|
|
88
|
+
|
|
89
|
+
Supported formats: JPEG, TIFF, PNG. Reads values from EXIF and XMP.
|
|
90
|
+
|
|
91
|
+
**`open` is async** — use `await`:
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
const img = await ImageDocument.open(path);
|
|
95
|
+
// ...
|
|
96
|
+
img.close();
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
All static methods also return `Promise<T>`.
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
ImageDocument.open(path: string): Promise<ImageDocument>
|
|
103
|
+
img.close(): void
|
|
104
|
+
|
|
105
|
+
img.getWidth(): number
|
|
106
|
+
ImageDocument.getWidth(path: string): Promise<number>
|
|
107
|
+
|
|
108
|
+
img.getHeight(): number
|
|
109
|
+
ImageDocument.getHeight(path: string): Promise<number>
|
|
110
|
+
|
|
111
|
+
img.getColorMode(): ImageDocument.ColorMode
|
|
112
|
+
ImageDocument.getColorMode(path: string): Promise<ImageDocument.ColorMode>
|
|
113
|
+
|
|
114
|
+
img.getColorSpace(): ImageDocument.ColorSpace
|
|
115
|
+
ImageDocument.getColorSpace(path: string): Promise<ImageDocument.ColorSpace>
|
|
116
|
+
|
|
117
|
+
img.getICCProfile(): string // Photoshop, falling back to the EXIF ProfileDescription if absent
|
|
118
|
+
ImageDocument.getICCProfile(path: string): Promise<string>
|
|
119
|
+
|
|
120
|
+
img.getSamplesPerPixel(): number
|
|
121
|
+
ImageDocument.getSamplesPerPixel(path: string): Promise<number>
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
See [api-enums.md](api-enums.md) for `ImageDocument.ColorMode` and `ImageDocument.ColorSpace` values.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## XmlDocument
|
|
129
|
+
|
|
130
|
+
XPath 1.0 queries against XML files or strings.
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
XmlDocument.open(path: string): XmlDocument
|
|
134
|
+
XmlDocument.parse(xmlString: string): XmlDocument
|
|
135
|
+
|
|
136
|
+
doc.evaluate(xpath: string, prefixMap?: { [prefix: string]: string }): boolean | number | string | object | undefined
|
|
137
|
+
doc.getDefaultNSMap(): { [prefix: string]: string }
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
XPath does not support default namespaces — always use a prefix. `getDefaultNSMap()` returns all namespace mappings occurring in the document; the default namespace (if any) is accessible via the special prefixes `default_switch_ns`, `dn`, and `jdf`. `evaluate()` can also return an `object` (e.g. a node-set result), not just the primitive types.
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
const doc = XmlDocument.open(path);
|
|
144
|
+
const map = doc.getDefaultNSMap();
|
|
145
|
+
const result = doc.evaluate('/dn:root/dn:item/@id', map);
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## XmpDocument
|
|
151
|
+
|
|
152
|
+
Evaluate XMP location paths (not XPath) against XMP-only files. Obtained from `PdfDocument.getXMP()` or opened directly.
|
|
153
|
+
|
|
154
|
+
> **Note**: `open()` requires an XMP-only file — do not pass a PDF or image path.
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
XmpDocument.open(path: string): XmpDocument
|
|
158
|
+
|
|
159
|
+
doc.evaluate(
|
|
160
|
+
xmpLocationPath: string,
|
|
161
|
+
additionalPrefixMap?: { [prefix: string]: string }
|
|
162
|
+
): boolean | number | string | undefined
|
|
163
|
+
|
|
164
|
+
doc.save(path: string): void
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
If `additionalPrefixMap` is omitted, the default prefix map (all standard XMP namespaces plus any extras in the file) is used.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Switch Script Entry Points
|
|
2
|
+
|
|
3
|
+
Entry points are top-level `async` functions with specific names. They are **not exported**. Switch calls them automatically based on flow events.
|
|
4
|
+
|
|
5
|
+
## Flow lifecycle
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
async function flowStartTriggered(s: Switch, flowElement: FlowElement): Promise<void>
|
|
9
|
+
```
|
|
10
|
+
Called when the flow starts. Use to subscribe to webhooks (`s.httpRequestSubscribe`) or channels (`flowElement.subscribeToChannel`). Cannot coexist with `timerFired` or `jobArrived` as the sole entry point. May execute in parallel for concurrent elements. Not available for debugging.
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
async function flowStopTriggered(s: Switch, flowElement: FlowElement): Promise<void>
|
|
14
|
+
```
|
|
15
|
+
Called when the flow stops. May execute in parallel for concurrent elements. Not available for debugging.
|
|
16
|
+
|
|
17
|
+
## Timer
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
async function timerFired(s: Switch, flowElement: FlowElement): Promise<void>
|
|
21
|
+
```
|
|
22
|
+
Called on a recurring timer. First fires after `flowStartTriggered`. Set the interval via `flowElement.setTimerInterval(seconds)`. Cannot coexist with `flowStartTriggered` as the sole entry point.
|
|
23
|
+
|
|
24
|
+
## Job processing
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
async function jobArrived(s: Switch, flowElement: FlowElement, job: Job): Promise<void>
|
|
28
|
+
```
|
|
29
|
+
Called when a job arrives. Must eventually call a `job.sendTo*()` or `job.fail()`. Can run concurrently if configured in the script XML declaration.
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
async function abort(s: Switch, flowElement: FlowElement, job: Job, abortData: any): Promise<void>
|
|
33
|
+
```
|
|
34
|
+
Called when an entry point exceeds its configured timeout. The `abortData` value was set beforehand via `s.setAbortData()`. Maximum execution: 60 seconds, after which the script executor is killed. Applies to: `jobArrived`, `timerFired`, `httpRequestTriggeredSync`, `httpRequestTriggeredAsync`, `flowStartTriggered`, `flowStopTriggered`.
|
|
35
|
+
|
|
36
|
+
## Webhooks
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
async function httpRequestTriggeredSync(request: HttpRequest, args: any[], response: HttpResponse, s: Switch): Promise<void>
|
|
40
|
+
```
|
|
41
|
+
Synchronous webhook handler. A response **must** be sent before the function returns. Registered via `s.httpRequestSubscribe()` in `flowStartTriggered`. Executes in concurrent mode. Request body limit: 1 MB (HTTP 413). Queue limit: 10,000 pending requests (HTTP 429). Execution timeout: 1 minute (HTTP 524). Default response if none set: HTTP 200 with `{"status": true}`.
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
async function httpRequestTriggeredAsync(request: HttpRequest, args: any[], s: Switch, flowElement: FlowElement): Promise<void>
|
|
45
|
+
```
|
|
46
|
+
Asynchronous webhook handler. No response is required. Registered via `s.httpRequestSubscribe()` in `flowStartTriggered`. Only invoked if `httpRequestTriggeredSync` is not defined, or if the sync handler returned a 2xx status.
|
|
47
|
+
|
|
48
|
+
## Script expression
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
async function calculateScriptExpression(s: Switch, flowElement: FlowElement, job: Job): Promise<string | number | boolean>
|
|
52
|
+
```
|
|
53
|
+
Called to evaluate a script expression for the flow element. The return value is used as the expression result.
|
|
54
|
+
|
|
55
|
+
## Property UI callbacks
|
|
56
|
+
|
|
57
|
+
Not available for debugging.
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
async function getLibraryForProperty(s: Switch, flowElement: FlowElement, tag: string): Promise<string[]>
|
|
61
|
+
```
|
|
62
|
+
Returns a dynamic list of values for a property's library dropdown.
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
async function getLibraryForConnectionProperty(s: Switch, flowElement: FlowElement, c: Connection, tag: string): Promise<string[]>
|
|
66
|
+
```
|
|
67
|
+
Returns a dynamic list of values for a connection property's library dropdown.
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
async function validateProperties(s: Switch, flowElement: FlowElement, tags: string[]): Promise<{ tag: string, valid: boolean }[]>
|
|
71
|
+
```
|
|
72
|
+
Validates one or more property values. Return one result object per tag.
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
async function validateConnectionProperties(s: Switch, flowElement: FlowElement, c: Connection, tags: string[]): Promise<{ tag: string, valid: boolean }[]>
|
|
76
|
+
```
|
|
77
|
+
Validates one or more connection property values.
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
async function findExternalEditorPath(s: Switch, flowElement: FlowElement, tag: string): Promise<string>
|
|
81
|
+
```
|
|
82
|
+
Resolves the path to an external editor for a property.
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Switch Scripting Enums
|
|
2
|
+
|
|
3
|
+
All enums are available globally in `main.ts`. They are also accessible via `EnfocusSwitch.*` when used outside `main.ts` (e.g. in imported modules).
|
|
4
|
+
|
|
5
|
+
## LogLevel
|
|
6
|
+
|
|
7
|
+
Used with `job.log()` and `flowElement.log()`.
|
|
8
|
+
|
|
9
|
+
| Value | String |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `LogLevel.Info` | `"info"` |
|
|
12
|
+
| `LogLevel.Warning` | `"warning"` |
|
|
13
|
+
| `LogLevel.Error` | `"error"` |
|
|
14
|
+
| `LogLevel.Debug` | `"debug"` |
|
|
15
|
+
|
|
16
|
+
## AccessLevel
|
|
17
|
+
|
|
18
|
+
Used with `job.get()` and `job.getDataset()`.
|
|
19
|
+
|
|
20
|
+
| Value | String |
|
|
21
|
+
|---|---|
|
|
22
|
+
| `AccessLevel.ReadOnly` | `"readOnly"` |
|
|
23
|
+
| `AccessLevel.ReadWrite` | `"readWrite"` |
|
|
24
|
+
|
|
25
|
+
## DatasetModel
|
|
26
|
+
|
|
27
|
+
Used with `job.createDataset()`, `job.sendToLog()`, and `job.listDatasets()`.
|
|
28
|
+
|
|
29
|
+
| Value | String |
|
|
30
|
+
|---|---|
|
|
31
|
+
| `DatasetModel.Opaque` | `"Opaque"` |
|
|
32
|
+
| `DatasetModel.XML` | `"XML"` |
|
|
33
|
+
| `DatasetModel.XMP` | `"XMP"` |
|
|
34
|
+
| `DatasetModel.JDF` | `"JDF"` |
|
|
35
|
+
| `DatasetModel.JSON` | `"JSON"` |
|
|
36
|
+
|
|
37
|
+
## Scope
|
|
38
|
+
|
|
39
|
+
Used with `s.getGlobalData()`, `s.setGlobalData()`, `s.removeGlobalData()`.
|
|
40
|
+
|
|
41
|
+
| Value | String |
|
|
42
|
+
|---|---|
|
|
43
|
+
| `Scope.Element` | `"element"` |
|
|
44
|
+
| `Scope.Flow` | `"flow"` |
|
|
45
|
+
| `Scope.FlowElement` | `"flowElement"` |
|
|
46
|
+
| `Scope.FlowElements` | `"flowElements"` |
|
|
47
|
+
| `Scope.Global` | `"global"` |
|
|
48
|
+
|
|
49
|
+
## Priority
|
|
50
|
+
|
|
51
|
+
Used with `job.setPriority()` / `job.getPriority()`.
|
|
52
|
+
|
|
53
|
+
| Value | Number |
|
|
54
|
+
|---|---|
|
|
55
|
+
| `Priority.Low` | `-100000` |
|
|
56
|
+
| `Priority.BelowNormal` | `-10000` |
|
|
57
|
+
| `Priority.Normal` | `0` |
|
|
58
|
+
| `Priority.AboveNormal` | `10000` |
|
|
59
|
+
| `Priority.High` | `100000` |
|
|
60
|
+
|
|
61
|
+
## Connection.Level
|
|
62
|
+
|
|
63
|
+
Used with `job.sendToData()` and `job.sendToLog()` for traffic light connections.
|
|
64
|
+
|
|
65
|
+
| Value | String |
|
|
66
|
+
|---|---|
|
|
67
|
+
| `Connection.Level.Success` | `"success"` |
|
|
68
|
+
| `Connection.Level.Warning` | `"warning"` |
|
|
69
|
+
| `Connection.Level.Error` | `"error"` |
|
|
70
|
+
|
|
71
|
+
Also available as `EnfocusSwitch.Connection.Level.*` outside `main.ts`.
|
|
72
|
+
|
|
73
|
+
## HttpRequest.Method
|
|
74
|
+
|
|
75
|
+
Used with `s.httpRequestSubscribe()` and `s.httpRequestUnsubscribe()`.
|
|
76
|
+
|
|
77
|
+
| Value | String |
|
|
78
|
+
|---|---|
|
|
79
|
+
| `HttpRequest.Method.POST` | `"POST"` |
|
|
80
|
+
| `HttpRequest.Method.PUT` | `"PUT"` |
|
|
81
|
+
| `HttpRequest.Method.DELETE` | `"DELETE"` |
|
|
82
|
+
|
|
83
|
+
Also available as `EnfocusSwitch.HttpRequest.Method.*` outside `main.ts`.
|
|
84
|
+
|
|
85
|
+
## PropertyType
|
|
86
|
+
|
|
87
|
+
Returned by `flowElement.getPropertyType()` and `connection.getPropertyType()`.
|
|
88
|
+
|
|
89
|
+
| Value | String |
|
|
90
|
+
|---|---|
|
|
91
|
+
| `PropertyType.Literal` | `"literal"` |
|
|
92
|
+
| `PropertyType.Number` | `"number"` |
|
|
93
|
+
| `PropertyType.Date` | `"date"` |
|
|
94
|
+
| `PropertyType.HoursAndMinutes` | `"hoursandminutes"` |
|
|
95
|
+
| `PropertyType.Boolean` | `"boolean"` |
|
|
96
|
+
| `PropertyType.String` | `"string"` |
|
|
97
|
+
| `PropertyType.FilePath` | `"filepath"` |
|
|
98
|
+
| `PropertyType.FolderPath` | `"folderpath"` |
|
|
99
|
+
| `PropertyType.FileType` | `"filetype"` |
|
|
100
|
+
| `PropertyType.FolderPattern` | `"folderpattern"` |
|
|
101
|
+
| `PropertyType.Regex` | `"regex"` |
|
|
102
|
+
| `PropertyType.OAuthToken` | `"oauthtoken"` |
|
|
103
|
+
|
|
104
|
+
## NoYesListPropertyStringValue
|
|
105
|
+
|
|
106
|
+
Convenience for `Boolean`-typed properties returned as strings.
|
|
107
|
+
|
|
108
|
+
| Value | String |
|
|
109
|
+
|---|---|
|
|
110
|
+
| `NoYesListPropertyStringValue.No` | `"No"` |
|
|
111
|
+
| `NoYesListPropertyStringValue.Yes` | `"Yes"` |
|
|
112
|
+
|
|
113
|
+
## EnfocusSwitchPrivateDataTag
|
|
114
|
+
|
|
115
|
+
Well-known tags for `job.getPrivateData()` / `job.setPrivateData()`.
|
|
116
|
+
|
|
117
|
+
| Value | String |
|
|
118
|
+
|---|---|
|
|
119
|
+
| `EnfocusSwitchPrivateDataTag.hierarchy` | `"EnfocusSwitch.hierarchy"` |
|
|
120
|
+
| `EnfocusSwitchPrivateDataTag.emailAddresses` | `"EnfocusSwitch.emailAddresses"` |
|
|
121
|
+
| `EnfocusSwitchPrivateDataTag.emailBody` | `"EnfocusSwitch.emailBody"` |
|
|
122
|
+
| `EnfocusSwitchPrivateDataTag.userName` | `"EnfocusSwitch.userName"` |
|
|
123
|
+
| `EnfocusSwitchPrivateDataTag.userFullName` | `"EnfocusSwitch.userFullName"` |
|
|
124
|
+
| `EnfocusSwitchPrivateDataTag.userEmail` | `"EnfocusSwitch.userEmail"` |
|
|
125
|
+
| `EnfocusSwitchPrivateDataTag.origin` | `"EnfocusSwitch.origin"` |
|
|
126
|
+
| `EnfocusSwitchPrivateDataTag.initiated` | `"EnfocusSwitch.initiated"` |
|
|
127
|
+
| `EnfocusSwitchPrivateDataTag.submittedTo` | `"EnfocusSwitch.submittedTo"` |
|
|
128
|
+
| `EnfocusSwitchPrivateDataTag.state` | `"EnfocusSwitch.state"` |
|
|
129
|
+
|
|
130
|
+
## ImageDocument.ColorMode
|
|
131
|
+
|
|
132
|
+
Used with `ImageDocument.getColorMode()`. Available as `EnfocusSwitch.ImageDocument.ColorMode.*` outside `main.ts`.
|
|
133
|
+
|
|
134
|
+
| Value | String |
|
|
135
|
+
|---|---|
|
|
136
|
+
| `ImageDocument.ColorMode.Bitmap` | `"Bitmap"` |
|
|
137
|
+
| `ImageDocument.ColorMode.Gray` | `"Gray"` |
|
|
138
|
+
| `ImageDocument.ColorMode.IndexedColor` | `"Indexed color"` |
|
|
139
|
+
| `ImageDocument.ColorMode.RGB` | `"RGB"` |
|
|
140
|
+
| `ImageDocument.ColorMode.CMYK` | `"CMYK"` |
|
|
141
|
+
| `ImageDocument.ColorMode.Multichannel` | `"Multichannel"` |
|
|
142
|
+
| `ImageDocument.ColorMode.Duotone` | `"Duotone"` |
|
|
143
|
+
| `ImageDocument.ColorMode.LabColor` | `"Lab color"` |
|
|
144
|
+
| `ImageDocument.ColorMode.Unknown` | `"Unknown"` |
|
|
145
|
+
|
|
146
|
+
## ImageDocument.ColorSpace
|
|
147
|
+
|
|
148
|
+
Used with `ImageDocument.getColorSpace()`. Available as `EnfocusSwitch.ImageDocument.ColorSpace.*` outside `main.ts`.
|
|
149
|
+
|
|
150
|
+
| Value | String |
|
|
151
|
+
|---|---|
|
|
152
|
+
| `ImageDocument.ColorSpace.SRGB` | `"sRGB"` |
|
|
153
|
+
| `ImageDocument.ColorSpace.Uncalibrated` | `"uncalibrated"` |
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Execution Environment
|
|
2
|
+
|
|
3
|
+
How the Node.js process a script runs in behaves, beyond the entry point API itself. These are
|
|
4
|
+
consequences of the host process model, not things a script configures — understanding them avoids
|
|
5
|
+
subtle bugs around state persistence and error handling.
|
|
6
|
+
|
|
7
|
+
## Two independent concurrency tiers
|
|
8
|
+
|
|
9
|
+
`NumberOfSlots`/`ExecutionGroup` (see
|
|
10
|
+
[Execution modes](api-script-structure.md#execution-modes)) and the pool of Node.js processes that
|
|
11
|
+
actually run script code are governed completely separately — there is no one-to-one mapping between
|
|
12
|
+
them:
|
|
13
|
+
|
|
14
|
+
- **`NumberOfSlots`** is a job-admission throttle on the Switch Server, scoped to that one flow
|
|
15
|
+
element instance (keyed by flow + element id): it limits how many jobs may be dispatched to that
|
|
16
|
+
instance at once, falling back to a server-wide default if left as `Default`. **`ExecutionGroup`**
|
|
17
|
+
(meaningful only for `Serialized` mode) is a true cross-flow-element named lock — every flow
|
|
18
|
+
element that declares the same group string, anywhere on the server, contends for one shared lock.
|
|
19
|
+
Neither is a count of OS processes.
|
|
20
|
+
- Separately, a shared pool of long-lived Node.js executor processes actually runs the script code
|
|
21
|
+
for every script element on the server, sized by a single server-wide concurrency setting — not
|
|
22
|
+
one process per slot, per instance, or per script. A job dispatched by the Server is handed to
|
|
23
|
+
whichever pooled executor is free (or a new one is spawned if none are); executors are reused
|
|
24
|
+
across many jobs and across different flow elements running the same Node.js version, until
|
|
25
|
+
recycled (see
|
|
26
|
+
[Executor cleanup thresholds](api-job-patterns.md#executor-cleanup-thresholds)).
|
|
27
|
+
|
|
28
|
+
## Module-level state persists across jobs on the same executor
|
|
29
|
+
|
|
30
|
+
Because executor processes are long-lived and reused, any state held outside an entry point function
|
|
31
|
+
— module-level `let`/`const`/`var`, an in-memory cache, a counter — can survive from one job
|
|
32
|
+
invocation to the next if the same executor happens to service both. It is **not** reset before each
|
|
33
|
+
`jobArrived`/`timerFired`/etc. call, and which executor services a given job is not something a
|
|
34
|
+
script controls or can predict. This is useful for caching (e.g. a parsed config file, a pooled
|
|
35
|
+
connection) but also a common source of bugs: don't assume module-level state starts fresh for every
|
|
36
|
+
job, and don't assume it's shared with an *arbitrary* other job either — reset explicitly at the
|
|
37
|
+
start of an entry point if a fresh value is required per job.
|
|
38
|
+
|
|
39
|
+
`getInitialize()`/`getFinalize()` (if the script uses them) run once per script per process
|
|
40
|
+
lifetime, not once per job — the same caveat applies to anything they set up.
|
|
41
|
+
|
|
42
|
+
## Unhandled promise rejections end the run, not the process
|
|
43
|
+
|
|
44
|
+
An unhandled promise rejection inside an entry point call ends that job's/run's execution — but the
|
|
45
|
+
underlying executor process is **not** killed and continues serving subsequent job invocations,
|
|
46
|
+
including for other flow elements pooled onto the same executor. Don't rely on an unhandled
|
|
47
|
+
rejection to surface as a hard failure of the whole executor; always catch and handle errors
|
|
48
|
+
explicitly (e.g. via `job.fail()`/`flowElement.failProcess()` — see
|
|
49
|
+
[api-logging.md](api-logging.md)) rather than letting a promise reject unhandled.
|
|
50
|
+
|
|
51
|
+
## Third-party npm modules: file-based scripts only
|
|
52
|
+
|
|
53
|
+
A script **expression** (entered inline in a flow element property, not a file-based script/app —
|
|
54
|
+
see [Script expression](api-entry-points.md#script-expression)) cannot use third-party npm modules
|
|
55
|
+
at all; only Node.js built-ins are available via `require`. A file-based script/app can use
|
|
56
|
+
third-party modules from its own `node_modules` folder (see
|
|
57
|
+
[Script folder files](api-script-structure.md#script-folder-files)).
|
|
58
|
+
|
|
59
|
+
## Native (binary) addons are not supported
|
|
60
|
+
|
|
61
|
+
Scripts with ESM dependencies are bundled before execution; this bundling path does not support
|
|
62
|
+
native/binary Node addons (`.node` files). Stick to pure-JavaScript/TypeScript dependencies.
|
|
63
|
+
|
|
64
|
+
## No explicit CPU or memory cap beyond the documented thresholds
|
|
65
|
+
|
|
66
|
+
Beyond the entry-point abort timeout and executor recycling thresholds already documented (see
|
|
67
|
+
[Job processing](api-entry-points.md#job-processing) and
|
|
68
|
+
[Executor cleanup thresholds](api-job-patterns.md#executor-cleanup-thresholds)), there is no
|
|
69
|
+
additional CPU-time or memory limit enforced on a script's own code. A runaway loop or leak is
|
|
70
|
+
bounded only by those thresholds, not stopped proactively.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# FlowElement Class
|
|
2
|
+
|
|
3
|
+
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.
|
|
4
|
+
|
|
5
|
+
## Identity
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
flowElement.getName(): string
|
|
9
|
+
```
|
|
10
|
+
Returns the name of this flow element.
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
flowElement.getFlowName(): string
|
|
14
|
+
```
|
|
15
|
+
Returns the name of the flow containing this element.
|
|
16
|
+
|
|
17
|
+
## Properties
|
|
18
|
+
|
|
19
|
+
Properties are configured by the user in the Switch canvas and declared in the script's XML declaration.
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
flowElement.getPropertyStringValue(tag: string): Promise<string | string[]>
|
|
23
|
+
```
|
|
24
|
+
Returns the property value as a string (or array for multi-value properties). For `OAuthToken` properties, returns a valid refreshed token. Throws `"Invalid tag: <tag>"` if the tag is unknown or a hidden dependent property. See [api-property-editors.md](api-property-editors.md) for editor types and their return value formats.
|
|
25
|
+
|
|
26
|
+
> **Dynamic values (Switch variables and script expressions) are only resolved when `getPropertyStringValue()` is called from `jobArrived`.** In any other entry point (e.g. `timerFired`) the raw unresolved string is returned.
|
|
27
|
+
>
|
|
28
|
+
> **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)`.
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
flowElement.getPropertyType(tag: string): PropertyType
|
|
32
|
+
```
|
|
33
|
+
Returns the `PropertyType` of the property — required to correctly interpret the string value when multiple input types are possible.
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
flowElement.getPropertyDisplayName(tag: string): string
|
|
37
|
+
```
|
|
38
|
+
Returns the English display name of the property (for use in log messages).
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
flowElement.hasProperty(tag: string): boolean
|
|
42
|
+
```
|
|
43
|
+
Returns `true` if the property exists and is visible for the current configuration.
|
|
44
|
+
|
|
45
|
+
## Connections
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
flowElement.getOutConnections(): Connection[]
|
|
49
|
+
```
|
|
50
|
+
Returns all outgoing connections (arbitrary order). Empty array if none.
|
|
51
|
+
|
|
52
|
+
## Timer
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
flowElement.setTimerInterval(seconds: number): void
|
|
56
|
+
```
|
|
57
|
+
Sets the interval between `timerFired` invocations. Default is 300 s. The actual interval may be longer under load.
|
|
58
|
+
|
|
59
|
+
## Logging
|
|
60
|
+
|
|
61
|
+
See [api-logging.md](api-logging.md) for log level semantics and logging practice.
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
flowElement.log(level: LogLevel, message: string, messageParams?: (string | number | boolean)[]): Promise<void>
|
|
65
|
+
```
|
|
66
|
+
Logs a message for the flow element. Use `%1`, `%2`, etc. in the message string for substitution via `messageParams`.
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
flowElement.failProcess(message: string, messageParam?: string | number | boolean): void
|
|
70
|
+
```
|
|
71
|
+
Logs a fatal error and puts the element into the "problem process" state. `messageParam` substitutes `%1`. Throws `"Job routing is not allowed in this entry point."` if called from an entry point where routing isn't permitted.
|
|
72
|
+
|
|
73
|
+
## Job creation (jobArrived / timerFired)
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
flowElement.createJob(path: string): Promise<Job>
|
|
77
|
+
```
|
|
78
|
+
Creates a new job from an existing file/folder path. Valid only in `jobArrived` and `timerFired`. The new job has default properties (no parent). The caller is responsible for cleaning up the source file after routing. See [api-job-patterns.md](api-job-patterns.md) for temp file cleanup rules and routing constraints.
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
flowElement.getJobs(ids: string[]): Promise<Job[]>
|
|
82
|
+
```
|
|
83
|
+
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.
|
|
84
|
+
|
|
85
|
+
## Channels
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
flowElement.subscribeToChannel(channelId: string, backingFolderPath: string): void
|
|
89
|
+
```
|
|
90
|
+
Subscribes to a channel to receive jobs from it. Only one subscriber per channel at a time. Must be called inside `flowStartTriggered`.
|
|
91
|
+
|
|
92
|
+
## Utilities
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
flowElement.createPathWithName(name: string, createFolder: boolean): Promise<any>
|
|
96
|
+
```
|
|
97
|
+
Creates a temporary path (optionally as a folder — `createFolder` is required, not optional). Returns an empty string only if creating the folder throws (e.g. a permissions error); it does not check whether the path already exists first.
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
flowElement.getFileCount(nested?: boolean): Promise<number>
|
|
101
|
+
```
|
|
102
|
+
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).
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
flowElement.getScriptDataPath(): string
|
|
106
|
+
```
|
|
107
|
+
Returns the path to the ScriptData folder for this element.
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
flowElement.getPluginResourcesPath(): string
|
|
111
|
+
```
|
|
112
|
+
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.
|