@enfocussw/switch-scripting-context 25.11.0-beta.14 → 25.11.0-beta.16
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 +39 -0
- package/README.md +28 -22
- package/dist/init.d.ts +1 -1
- package/dist/init.js +18 -7
- package/docs/switch-api/{api-connection.md → connection.md} +18 -3
- package/docs/switch-api/{api-document-classes.md → document-classes.md} +10 -1
- package/docs/switch-api/{api-entry-points.md → entry-points.md} +14 -5
- package/docs/switch-api/{api-enums.md → enums.md} +12 -1
- package/docs/switch-api/{api-execution-environment.md → execution-environment.md} +16 -7
- package/docs/switch-api/{api-flow-element.md → flow-element.md} +13 -4
- package/docs/switch-api/{api-http.md → http.md} +9 -0
- package/docs/switch-api/{api-job-patterns.md → job-patterns.md} +23 -8
- package/docs/switch-api/{api-job.md → job.md} +13 -4
- package/docs/switch-api/{api-logging.md → logging.md} +15 -6
- package/docs/switch-api/{api-switch.md → switch.md} +10 -1
- package/docs/{switch-api/api-app-guidelines.md → switch-appstore/app-guidelines.md} +50 -33
- 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-api/api-debugging.md → switch-project/debugging.md} +9 -0
- package/docs/{switch-api/api-logs-and-dataroot.md → switch-project/logs-and-dataroot.md} +10 -1
- package/docs/{switch-api/api-project-planning.md → switch-project/project-planning.md} +22 -13
- package/docs/switch-project/property-documentation.md +75 -0
- package/docs/{switch-api/api-property-editors.md → switch-project/property-editors.md} +19 -10
- package/docs/{switch-api/api-script-declaration.md → switch-project/script-declaration.md} +18 -9
- package/docs/{switch-api/api-script-structure.md → switch-project/script-structure.md} +14 -5
- package/docs/{switch-api/api-tooling.md → switch-project/tooling.md} +10 -1
- package/docs/{switch-api/api-vscode.md → switch-project/vscode.md} +9 -0
- package/docs/switch-scripting.md +35 -27
- package/package.json +4 -3
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,45 @@ All notable changes to this package are documented here. Format follows
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [25.11.0-beta.16] - 2026-09-10
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Connection docs clarify that traffic light levels (`Connection.Level.Success`/`Warning`/`Error`)
|
|
12
|
+
only select where `sendToData()`/`sendToLog()` route a job; they cannot be read back from a
|
|
13
|
+
connection object, and `sendToData()` fails the job if no connected level matches. Scripts that
|
|
14
|
+
need optional traffic light routing should expose a custom property and fall back to
|
|
15
|
+
`sendToNull()`.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
- `switch-scripting.md`'s own text told agents to grep a `docs/` prefix that only exists in this
|
|
19
|
+
repo's source tree, not in a consuming project's copied docs folder. Agents following that
|
|
20
|
+
instruction literally hit a folder that doesn't exist. The text now describes the copied layout.
|
|
21
|
+
|
|
22
|
+
## [25.11.0-beta.15] - 2026-09-10
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
- `property-documentation.md`, `app-store-listing.md`, `app-manual.md`, and
|
|
26
|
+
`app-store-submission.md`: writing guidance for the four separate places app documentation
|
|
27
|
+
ends up (per-property `Tooltip`/`DetailedInfo`, the declaration's listing fields, the uploaded
|
|
28
|
+
app manual document, and the Appstore website submission forms), including which content is
|
|
29
|
+
reused between them, icon specs, and a shared checklist against generic-sounding text.
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
- Docs reorganized under `docs/`: the scripting API stays in `docs/switch-api/`; project structure
|
|
33
|
+
and tooling docs moved to `docs/switch-project/`; Appstore publishing guidance moved to
|
|
34
|
+
`docs/switch-appstore/`. Update any bookmarked doc paths after upgrading.
|
|
35
|
+
- Dropped the `api-` prefix from doc filenames, for example `switch-api/job.md`, since each file's
|
|
36
|
+
folder already says what kind of doc it is.
|
|
37
|
+
- Each doc file now carries its own routing metadata (trigger and summary) as YAML frontmatter,
|
|
38
|
+
generated into the routing table and README's doc list instead of hand-duplicated in both.
|
|
39
|
+
README's descriptions now match the table's wording exactly; a few had drifted apart.
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
- `init` now removes the destination docs folder before copying, instead of only adding and
|
|
43
|
+
overwriting. Previously, a doc renamed or moved between versions left the old file behind
|
|
44
|
+
permanently after an upgrade, since the destination folder is gitignored and nothing surfaced
|
|
45
|
+
the stale copy.
|
|
46
|
+
|
|
8
47
|
## [25.11.0-beta.14] - 2026-09-09
|
|
9
48
|
|
|
10
49
|
### Added
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ AI coding assistant context for [Enfocus Switch](https://www.enfocus.com/en/swit
|
|
|
4
4
|
|
|
5
5
|
Installs curated API reference docs and generates config files for 8 AI coding agents (Claude Code, GitHub Copilot, Cursor, Codex CLI/OpenCode, Gemini CLI, Windsurf, Zed, and Cline) so AI assistants understand the Switch scripting API out of the box.
|
|
6
6
|
|
|
7
|
-
See [CHANGELOG.md](https://cdn.jsdelivr.net/npm/@enfocussw/switch-scripting-context@25.11.0-beta.
|
|
7
|
+
See [CHANGELOG.md](https://cdn.jsdelivr.net/npm/@enfocussw/switch-scripting-context@25.11.0-beta.16/CHANGELOG.md) (also included in this package) for what's changed between versions.
|
|
8
8
|
|
|
9
9
|
## Usage
|
|
10
10
|
|
|
@@ -84,7 +84,7 @@ A few things this gets you without asking for them by name:
|
|
|
84
84
|
properties (app path/licence) are off-limits and left to SwitchScripter's GUI instead.
|
|
85
85
|
|
|
86
86
|
Re-run `init` after upgrading this package so the copied docs and generated config files catch up.
|
|
87
|
-
See [CHANGELOG.md](https://cdn.jsdelivr.net/npm/@enfocussw/switch-scripting-context@25.11.0-beta.
|
|
87
|
+
See [CHANGELOG.md](https://cdn.jsdelivr.net/npm/@enfocussw/switch-scripting-context@25.11.0-beta.16/CHANGELOG.md) for what changed.
|
|
88
88
|
|
|
89
89
|
## Options
|
|
90
90
|
|
|
@@ -131,23 +131,29 @@ npm install --save-dev "https://github.com/enfocus-switch/types-switch-scripting
|
|
|
131
131
|
The `switch-docs/` folder contains:
|
|
132
132
|
|
|
133
133
|
- `switch-scripting.md`: master index with execution environment rules and "load when" routing table
|
|
134
|
-
|
|
135
|
-
- `switch-
|
|
136
|
-
- `switch-api/
|
|
137
|
-
- `switch-api/
|
|
138
|
-
- `switch-api/
|
|
139
|
-
- `switch-api/
|
|
140
|
-
- `switch-api/
|
|
141
|
-
- `switch-api/
|
|
142
|
-
- `switch-api/
|
|
143
|
-
- `switch-api/
|
|
144
|
-
- `switch-
|
|
145
|
-
- `switch-
|
|
146
|
-
- `switch-
|
|
147
|
-
- `switch-
|
|
148
|
-
- `switch-
|
|
149
|
-
- `switch-
|
|
150
|
-
- `switch-api/
|
|
151
|
-
- `switch-api/
|
|
152
|
-
- `switch-api/
|
|
153
|
-
- `switch-
|
|
134
|
+
<!-- docs-index:readme begin -->
|
|
135
|
+
- `switch-project/project-planning.md`: Pre-scaffolding checklist: Script vs App, job-processing approach, target OS, Switch version baseline, concurrency, native/binary npm dependencies, Appstore competition risk
|
|
136
|
+
- `switch-api/entry-points.md`: All entry point signatures, constraints, and when each is called
|
|
137
|
+
- `switch-api/switch.md`: `Switch` (`s`): global data, webhooks, abort, server utilities
|
|
138
|
+
- `switch-api/flow-element.md`: `FlowElement`: properties, connections, job creation, logging
|
|
139
|
+
- `switch-api/job.md`: `Job` **signatures**: routing, file access, child jobs, private data, datasets
|
|
140
|
+
- `switch-api/connection.md`: `Connection`: type, properties, file count
|
|
141
|
+
- `switch-api/http.md`: `HttpRequest` / `HttpResponse` + webhook pattern
|
|
142
|
+
- `switch-api/enums.md`: All enums with string values (`LogLevel`, `AccessLevel`, `DatasetModel`, `Scope`, `Priority`, `Connection.Level`, etc.)
|
|
143
|
+
- `switch-api/document-classes.md`: `PdfDocument`, `PdfPage`, `ImageDocument`, `XmlDocument`, `XmpDocument`: read-only file introspection
|
|
144
|
+
- `switch-project/script-structure.md`: What files a script folder contains, `manifest.xml` format, Node.js version per Switch release, Script vs App
|
|
145
|
+
- `switch-project/tooling.md`: SwitchScriptTool commands and install paths, folder vs `.sscript` trade-offs, deployment
|
|
146
|
+
- `switch-project/debugging.md`: Enabling debug mode in Switch Designer, debuggable entry points, VS Code attach
|
|
147
|
+
- `switch-project/vscode.md`: Type declarations, tsconfig for TypeScript 6, ESLint rules
|
|
148
|
+
- `switch-project/script-declaration.md`: XML declaration reference: properties, connections, execution config; agents may edit this file directly
|
|
149
|
+
- `switch-project/property-editors.md`: Property editor types, string return values, literal editors, dropdowns
|
|
150
|
+
- `switch-api/job-patterns.md`: `Job` **rules and gotchas**: file access semantics, temp cleanup, which `sendTo*()` suits which connection type, dataset/child ordering, executor limits
|
|
151
|
+
- `switch-api/execution-environment.md`: Execution modes (`Concurrent`/`Serialized`, `ExecutionGroup`, `NumberOfSlots`), process/concurrency model, state persistence across job invocations, unhandled-rejection behavior, npm/native module constraints
|
|
152
|
+
- `switch-api/logging.md`: Log level semantics, logging practice, `console.log` limitation, common gotchas
|
|
153
|
+
- `switch-project/logs-and-dataroot.md`: Locating the Application Data Root, querying `ServerLogs.db3` directly
|
|
154
|
+
- `switch-appstore/app-guidelines.md`: Pre-publish checklist for Appstore apps: property naming/tooltips/editors, entry point and sendTo consistency, logging quality, packaging, and the app-only submission rules (localization, signed universal macOS binaries)
|
|
155
|
+
- `switch-project/property-documentation.md`: Writing guidance for `Tooltip` and `DetailedInfo` content on properties/connections
|
|
156
|
+
- `switch-appstore/app-store-listing.md`: Writing guidance for the declaration's Appstore listing fields: `Description`, `Compatibility`, `SupportInfo`, `AppDiscovery`, `Connections`
|
|
157
|
+
- `switch-appstore/app-manual.md`: Writing guidance for the separate app manual document uploaded during Appstore review (`documentation-app_name.docx` template)
|
|
158
|
+
- `switch-appstore/app-store-submission.md`: Writing guidance for the Create Appstore App / Create Appstore App Version web forms: Short Description, What's new, Eula, icon specs, and which fields reuse content already written elsewhere
|
|
159
|
+
<!-- docs-index:readme end -->
|
package/dist/init.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export interface ToolDefinition {
|
|
|
10
10
|
files: ToolFile[];
|
|
11
11
|
}
|
|
12
12
|
export interface ApiDoc {
|
|
13
|
-
/**
|
|
13
|
+
/** Path within docs/, e.g. "switch-api/job.md". */
|
|
14
14
|
file: string;
|
|
15
15
|
/** The routing table's "Load when" text, verbatim. */
|
|
16
16
|
loadWhen: string;
|
package/dist/init.js
CHANGED
|
@@ -64,10 +64,10 @@ function parseRoutingTable(root = packageRoot()) {
|
|
|
64
64
|
const hub = fs.readFileSync(path.join(root, 'docs', 'switch-scripting.md'), 'utf8');
|
|
65
65
|
const docs = [];
|
|
66
66
|
for (const line of hub.split('\n')) {
|
|
67
|
-
// |
|
|
68
|
-
const m = /^\|\s*`switch-api\/(
|
|
67
|
+
// | `<switch-api|switch-project|switch-appstore>/<file>.md` | <contents> | <load when> |
|
|
68
|
+
const m = /^\|\s*`(switch-api|switch-project|switch-appstore)\/([a-z0-9-]+\.md)`\s*\|(.*)\|(.*)\|\s*$/.exec(line);
|
|
69
69
|
if (m)
|
|
70
|
-
docs.push({ file: m[1]
|
|
70
|
+
docs.push({ file: `${m[1]}/${m[2]}`, loadWhen: m[4].trim() });
|
|
71
71
|
}
|
|
72
72
|
if (docs.length === 0) {
|
|
73
73
|
throw new Error('No API docs found in docs/switch-scripting.md — the routing table format changed. ' +
|
|
@@ -82,11 +82,11 @@ function apiFiles(root) {
|
|
|
82
82
|
const INLINE_CORE_RULES = `## Core rules
|
|
83
83
|
|
|
84
84
|
- Entry point functions are top-level async functions — do NOT use \`export\`, arrow functions, or class methods; declare them with the literal \`function\` keyword.
|
|
85
|
-
- Switch finds entry points with a regex, not a parser. Never write a string literal whose content ends with a backslash, a regex literal, or division outside the plain \`word / word\` shape — each silently deletes a span of real code and the entry points inside it, with no error. Read \`
|
|
85
|
+
- Switch finds entry points with a regex, not a parser. Never write a string literal whose content ends with a backslash, a regex literal, or division outside the plain \`word / word\` shape — each silently deletes a span of real code and the entry points inside it, with no error. Read \`entry-points.md\` § Entry-point scanner constraints before editing \`main.ts\`/\`main.js\`.
|
|
86
86
|
- Every \`jobArrived\` must end with exactly one \`job.sendTo*()\` or \`job.fail()\`.
|
|
87
87
|
- Use \`AccessLevel.ReadOnly\` for \`job.get()\` unless the file content will be modified.
|
|
88
88
|
- After \`createJob()\`, \`createChild()\`, or \`createDataset()\` with a file path, delete the source file after routing — Switch does not auto-remove it.
|
|
89
|
-
- The XML declaration (\`<ScriptID>.xml\`) can be edited directly — read \`
|
|
89
|
+
- The XML declaration (\`<ScriptID>.xml\`) can be edited directly — read \`script-declaration.md\` first and follow its rules exactly (nothing validates this format, so mistakes fail silently). Never change an existing script's \`Name\`; bump \`Version\` on every declaration edit. Leave \`manifest.xml\` to the user unless explicitly asked.
|
|
90
90
|
- After editing \`main.ts\`, transpile with \`SwitchScriptTool --transpile <folder>\` — do not use \`tsc\` directly.
|
|
91
91
|
- Never use a script folder in production — pack with \`SwitchScriptTool --pack\` first; folders are excluded from flow exports.`;
|
|
92
92
|
// ─── Content generators ──────────────────────────────────────────────────────
|
|
@@ -140,7 +140,7 @@ ${MARKER_END}`;
|
|
|
140
140
|
// ─── Inline block (for tools without @file import support) ──────────────────
|
|
141
141
|
function inlineApiFileList(docsDir) {
|
|
142
142
|
return parseRoutingTable()
|
|
143
|
-
.map(d => `- \`${docsDir}
|
|
143
|
+
.map(d => `- \`${docsDir}/${d.file}\` — ${d.loadWhen}`)
|
|
144
144
|
.join('\n');
|
|
145
145
|
}
|
|
146
146
|
function generateInlineBlock(docsDir) {
|
|
@@ -337,10 +337,21 @@ function applyFileAction(action, dryRun) {
|
|
|
337
337
|
const DOCS_EXCLUDE = ['superpowers', 'temp'];
|
|
338
338
|
function copyDocs(packageRoot, destDir, dryRun) {
|
|
339
339
|
const src = path.join(packageRoot, 'docs');
|
|
340
|
+
const rel = path.relative(process.cwd(), destDir);
|
|
340
341
|
if (dryRun) {
|
|
341
|
-
|
|
342
|
+
if (fs.existsSync(destDir)) {
|
|
343
|
+
console.log(` [dry-run] ${rel}/ → wiped (removes files from a previous version, e.g. after a doc was renamed or moved)`);
|
|
344
|
+
}
|
|
345
|
+
console.log(` [dry-run] Copying docs/ → ${rel}/`);
|
|
342
346
|
return;
|
|
343
347
|
}
|
|
348
|
+
// destDir is entirely owned by this tool (see the .gitignore comment it writes), so wiping
|
|
349
|
+
// it first is safe. Without this, a doc renamed or moved between versions (e.g. a docs/
|
|
350
|
+
// folder restructuring) would leave the old file behind forever: cpSync only adds/overwrites,
|
|
351
|
+
// it never removes, and destDir is gitignored so nothing would surface the staleness.
|
|
352
|
+
if (fs.existsSync(destDir)) {
|
|
353
|
+
fs.rmSync(destDir, { recursive: true, force: true });
|
|
354
|
+
}
|
|
344
355
|
// The published tarball already omits these, but init may run from a git clone.
|
|
345
356
|
fs.cpSync(src, destDir, {
|
|
346
357
|
recursive: true,
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: connection
|
|
3
|
+
category: switch-api
|
|
4
|
+
order: 6
|
|
5
|
+
summary: "`Connection`: type, properties, file count"
|
|
6
|
+
triggers:
|
|
7
|
+
- "Routing to specific connections or reading connection properties"
|
|
8
|
+
---
|
|
9
|
+
|
|
1
10
|
# Connection Class
|
|
2
11
|
|
|
3
12
|
A `Connection` represents an outgoing connection from the flow element. Obtain instances via `flowElement.getOutConnections()`.
|
|
@@ -21,12 +30,12 @@ Connection type. One of: `"Move"`, `"Filter"`, `"Traffic-data"`, `"Traffic-log"`
|
|
|
21
30
|
|
|
22
31
|
## Connection properties
|
|
23
32
|
|
|
24
|
-
Connection properties are declared in the script's XML declaration (`ConnectionFields`) and configured per-connection in the canvas. See [
|
|
33
|
+
Connection properties are declared in the script's XML declaration (`ConnectionFields`) and configured per-connection in the canvas. See [script-declaration.md](../switch-project/script-declaration.md) for how to declare them (via SwitchScripter).
|
|
25
34
|
|
|
26
35
|
```ts
|
|
27
36
|
connection.getPropertyStringValue(tag: string): Promise<string | string[]>
|
|
28
37
|
```
|
|
29
|
-
Returns the connection property value as a string. Throws `"Invalid tag: <tag>"` if the tag is unknown **or if it's a `Dependency` dependent currently hidden by its master's value** — see [
|
|
38
|
+
Returns the connection property value as a string. Throws `"Invalid tag: <tag>"` if the tag is unknown **or if it's a `Dependency` dependent currently hidden by its master's value** — see [script-declaration.md § Dependency](../switch-project/script-declaration.md#custom-property-elements-elementfields). Before fetching a dependent property, confirm its condition holds (from the already-read master value, or via `hasProperty(tag)` below) rather than fetching it unconditionally.
|
|
30
39
|
|
|
31
40
|
```ts
|
|
32
41
|
connection.getPropertyType(tag: string): PropertyType
|
|
@@ -52,7 +61,7 @@ Returns the number of files in the folder at the other end of this connection. I
|
|
|
52
61
|
|
|
53
62
|
## Connection.Level enum
|
|
54
63
|
|
|
55
|
-
Used with `job.sendToData()` and `job.sendToLog()`
|
|
64
|
+
Used with `job.sendToData()` and `job.sendToLog()` to select which traffic light connection a job routes to.
|
|
56
65
|
|
|
57
66
|
| Value | String |
|
|
58
67
|
|---|---|
|
|
@@ -61,3 +70,9 @@ Used with `job.sendToData()` and `job.sendToLog()` for traffic light connections
|
|
|
61
70
|
| `Connection.Level.Error` | `"error"` |
|
|
62
71
|
|
|
63
72
|
Available as `EnfocusSwitch.Connection.Level.*` outside `main.ts`.
|
|
73
|
+
|
|
74
|
+
**Traffic light levels are not a readable connection property.** `flowElement.getOutConnections()`
|
|
75
|
+
returns the outgoing `Connection` objects, but the supported API has no way to determine which
|
|
76
|
+
level(s) a given connection accepts. Don't call `connection.getPropertyStringValue("Success")`, `"Warning"`, or `"Error"` expecting to
|
|
77
|
+
read this back; those are not valid property tags for a traffic light connection. To route
|
|
78
|
+
optionally, see [job-patterns.md § Sending jobs](job-patterns.md#sending-jobs).
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: document-classes
|
|
3
|
+
category: switch-api
|
|
4
|
+
order: 9
|
|
5
|
+
summary: "`PdfDocument`, `PdfPage`, `ImageDocument`, `XmlDocument`, `XmpDocument`: read-only file introspection"
|
|
6
|
+
triggers:
|
|
7
|
+
- "Inspecting PDF, image, XML, or XMP file contents"
|
|
8
|
+
---
|
|
9
|
+
|
|
1
10
|
# Document Classes
|
|
2
11
|
|
|
3
12
|
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.
|
|
@@ -121,7 +130,7 @@ img.getSamplesPerPixel(): number
|
|
|
121
130
|
ImageDocument.getSamplesPerPixel(path: string): Promise<number>
|
|
122
131
|
```
|
|
123
132
|
|
|
124
|
-
See [
|
|
133
|
+
See [enums.md](enums.md) for `ImageDocument.ColorMode` and `ImageDocument.ColorSpace` values.
|
|
125
134
|
|
|
126
135
|
---
|
|
127
136
|
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: entry-points
|
|
3
|
+
category: switch-api
|
|
4
|
+
order: 2
|
|
5
|
+
summary: "All entry point signatures, constraints, and when each is called"
|
|
6
|
+
triggers:
|
|
7
|
+
- "Scaffolding a script, adding/editing an entry point, or making any edit to main.ts/main.js"
|
|
8
|
+
---
|
|
9
|
+
|
|
1
10
|
# Switch Script Entry Points
|
|
2
11
|
|
|
3
12
|
Entry points are top-level `async` functions with specific names. They are **not exported**. Switch calls them automatically based on flow events.
|
|
@@ -47,7 +56,7 @@ or warn about any of this — a script that packs cleanly can still fail to load
|
|
|
47
56
|
extraction — if another valid entry point is also present the script packs and loads without
|
|
48
57
|
error, the misnamed function just never runs.
|
|
49
58
|
|
|
50
|
-
See [
|
|
59
|
+
See [tooling.md § Verify entry points before packing](../switch-project/tooling.md#verify-entry-points-before-packing)
|
|
51
60
|
for a script to catch this before it reaches Switch.
|
|
52
61
|
|
|
53
62
|
## Flow lifecycle
|
|
@@ -83,7 +92,7 @@ Called when a job arrives. Must eventually call a `job.sendTo*()` or `job.fail()
|
|
|
83
92
|
`jobArrived` and `timerFired` presence must match the declared connections — present when
|
|
84
93
|
`IncomingConnections="Yes"` (`timerFired` may additionally be present); when
|
|
85
94
|
`IncomingConnections="No"`, `timerFired` must be present instead. See
|
|
86
|
-
[
|
|
95
|
+
[script-declaration.md](../switch-project/script-declaration.md#built-in-elementfields). Never leave an empty
|
|
87
96
|
`jobArrived` or `timerFired` in the script — remove the function entirely if it does nothing.
|
|
88
97
|
|
|
89
98
|
**Gotcha: a flow restart replays every queued job through `jobArrived` again.** This includes a job
|
|
@@ -129,7 +138,7 @@ async function getLibraryForProperty(s: Switch, flowElement: FlowElement, tag: s
|
|
|
129
138
|
```
|
|
130
139
|
Returns a dynamic list of values for a property's library dropdown. Mandatory if any property uses
|
|
131
140
|
the `askplugin`/`askplugin2` editor (see
|
|
132
|
-
[
|
|
141
|
+
[property-editors.md](../switch-project/property-editors.md#modal-editors)). Log an error via `flowElement.log()`
|
|
133
142
|
if the list would otherwise come back empty, so the user can see why the dropdown has nothing in it.
|
|
134
143
|
|
|
135
144
|
```ts
|
|
@@ -143,7 +152,7 @@ async function validateProperties(s: Switch, flowElement: FlowElement, tags: str
|
|
|
143
152
|
```
|
|
144
153
|
Validates one or more property values. Return one result object per tag. Mandatory if any property
|
|
145
154
|
declares `Validation="Custom"` or `"Standard and custom"` (see
|
|
146
|
-
[
|
|
155
|
+
[script-declaration.md](../switch-project/script-declaration.md#custom-property-elements-elementfields)). Log
|
|
147
156
|
an error via `flowElement.log()` for any tag returned with `valid: false`, so the user sees why.
|
|
148
157
|
|
|
149
158
|
```ts
|
|
@@ -157,4 +166,4 @@ async function findExternalEditorPath(s: Switch, flowElement: FlowElement, tag:
|
|
|
157
166
|
```
|
|
158
167
|
Resolves the path to an external editor for a property. Required whenever the
|
|
159
168
|
`external`/`external2`/… editor is used, unless the dependent `Application` property is non-empty —
|
|
160
|
-
see [
|
|
169
|
+
see [property-editors.md § Notes](../switch-project/property-editors.md#notes).
|
|
@@ -1,3 +1,12 @@
|
|
|
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
|
+
|
|
1
10
|
# Switch Scripting Enums
|
|
2
11
|
|
|
3
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).
|
|
@@ -68,7 +77,9 @@ Used with `job.sendToData()` and `job.sendToLog()` for traffic light connections
|
|
|
68
77
|
| `Connection.Level.Warning` | `"warning"` |
|
|
69
78
|
| `Connection.Level.Error` | `"error"` |
|
|
70
79
|
|
|
71
|
-
Also available as `EnfocusSwitch.Connection.Level.*` outside `main.ts`.
|
|
80
|
+
Also available as `EnfocusSwitch.Connection.Level.*` outside `main.ts`. It selects which level to
|
|
81
|
+
route to; it is not a property you can read back from a `Connection` object, see
|
|
82
|
+
[connection.md § Connection.Level enum](connection.md#connectionlevel-enum).
|
|
72
83
|
|
|
73
84
|
## HttpRequest.Method
|
|
74
85
|
|
|
@@ -1,3 +1,12 @@
|
|
|
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
|
+
|
|
1
10
|
# Execution Environment
|
|
2
11
|
|
|
3
12
|
How the Node.js process a script runs in behaves, beyond the entry point API itself. Apart from the
|
|
@@ -7,7 +16,7 @@ configures — understanding them avoids subtle bugs around state persistence an
|
|
|
7
16
|
## Execution modes
|
|
8
17
|
|
|
9
18
|
Set in the XML declaration via SwitchScripter, or by editing it directly (see
|
|
10
|
-
[
|
|
19
|
+
[script-declaration.md](../switch-project/script-declaration.md#built-in-elementfields)). Applies to all
|
|
11
20
|
instances of the script.
|
|
12
21
|
|
|
13
22
|
**Concurrent** — entry points for the same or different instances may run in parallel. Scripts must
|
|
@@ -39,7 +48,7 @@ them:
|
|
|
39
48
|
whichever pooled executor is free (or a new one is spawned if none are); executors are reused
|
|
40
49
|
across many jobs and across different flow elements running the same Node.js version, until
|
|
41
50
|
recycled (see
|
|
42
|
-
[Executor cleanup thresholds](
|
|
51
|
+
[Executor cleanup thresholds](job-patterns.md#executor-cleanup-thresholds)).
|
|
43
52
|
|
|
44
53
|
## Module-level state persists across jobs on the same executor
|
|
45
54
|
|
|
@@ -62,15 +71,15 @@ underlying executor process is **not** killed and continues serving subsequent j
|
|
|
62
71
|
including for other flow elements pooled onto the same executor. Don't rely on an unhandled
|
|
63
72
|
rejection to surface as a hard failure of the whole executor; always catch and handle errors
|
|
64
73
|
explicitly (e.g. via `job.fail()`/`flowElement.failProcess()` — see
|
|
65
|
-
[
|
|
74
|
+
[logging.md](logging.md)) rather than letting a promise reject unhandled.
|
|
66
75
|
|
|
67
76
|
## Third-party npm modules: file-based scripts only
|
|
68
77
|
|
|
69
78
|
A script **expression** (entered inline in a flow element property, not a file-based script/app —
|
|
70
|
-
see [Script expression](
|
|
79
|
+
see [Script expression](entry-points.md#script-expression)) cannot use third-party npm modules
|
|
71
80
|
at all; only Node.js built-ins are available via `require`. A file-based script/app can use
|
|
72
81
|
third-party modules from its own `node_modules` folder (see
|
|
73
|
-
[Script folder files](
|
|
82
|
+
[Script folder files](../switch-project/script-structure.md#script-folder-files)).
|
|
74
83
|
|
|
75
84
|
## Native (binary) addons are not supported
|
|
76
85
|
|
|
@@ -80,7 +89,7 @@ native/binary Node addons (`.node` files). Stick to pure-JavaScript/TypeScript d
|
|
|
80
89
|
## No explicit CPU or memory cap beyond the documented thresholds
|
|
81
90
|
|
|
82
91
|
Beyond the entry-point abort timeout and executor recycling thresholds already documented (see
|
|
83
|
-
[Job processing](
|
|
84
|
-
[Executor cleanup thresholds](
|
|
92
|
+
[Job processing](entry-points.md#job-processing) and
|
|
93
|
+
[Executor cleanup thresholds](job-patterns.md#executor-cleanup-thresholds)), there is no
|
|
85
94
|
additional CPU-time or memory limit enforced on a script's own code. A runaway loop or leak is
|
|
86
95
|
bounded only by those thresholds, not stopped proactively.
|
|
@@ -1,3 +1,12 @@
|
|
|
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
|
+
|
|
1
10
|
# FlowElement Class
|
|
2
11
|
|
|
3
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.
|
|
@@ -21,7 +30,7 @@ Properties are configured by the user in the Switch canvas and declared in the s
|
|
|
21
30
|
```ts
|
|
22
31
|
flowElement.getPropertyStringValue(tag: string): Promise<string | string[]>
|
|
23
32
|
```
|
|
24
|
-
Returns the property value as a string (or array for multi-value properties). For `OAuthToken` properties, returns a valid refreshed token. Throws `"Invalid tag: <tag>"` if the tag is unknown **or if it's a `Dependency` dependent currently hidden by its master's value** — see [
|
|
33
|
+
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). 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.
|
|
25
34
|
|
|
26
35
|
> **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
36
|
>
|
|
@@ -58,7 +67,7 @@ Sets the interval between `timerFired` invocations. Default is 300 s. The actual
|
|
|
58
67
|
|
|
59
68
|
## Logging
|
|
60
69
|
|
|
61
|
-
See [
|
|
70
|
+
See [logging.md](logging.md) for log level semantics and logging practice.
|
|
62
71
|
|
|
63
72
|
```ts
|
|
64
73
|
flowElement.log(level: LogLevel, message: string, messageParams?: (string | number | boolean)[]): Promise<void>
|
|
@@ -75,7 +84,7 @@ Logs a fatal error and puts the element into the "problem process" state. `messa
|
|
|
75
84
|
```ts
|
|
76
85
|
flowElement.createJob(path: string): Promise<Job>
|
|
77
86
|
```
|
|
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 [
|
|
87
|
+
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 [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.
|
|
79
88
|
|
|
80
89
|
```ts
|
|
81
90
|
flowElement.getJobs(ids: string[]): Promise<Job[]>
|
|
@@ -94,7 +103,7 @@ Subscribes to a channel to receive jobs from it. Only one subscriber per channel
|
|
|
94
103
|
```ts
|
|
95
104
|
flowElement.createPathWithName(name: string, createFolder: boolean): Promise<any>
|
|
96
105
|
```
|
|
97
|
-
Creates a temporary path (optionally as a folder — `createFolder` is required, not optional). Returns an empty string only if creating the folder throws (e.g. a permissions error); it does not check whether the path already exists first. This is the recommended way to create temp files — see [
|
|
106
|
+
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.
|
|
98
107
|
|
|
99
108
|
```ts
|
|
100
109
|
flowElement.getFileCount(nested?: boolean): Promise<number>
|
|
@@ -1,3 +1,12 @@
|
|
|
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
|
+
|
|
1
10
|
# HttpRequest & HttpResponse Classes
|
|
2
11
|
|
|
3
12
|
Used in the `httpRequestTriggeredSync` and `httpRequestTriggeredAsync` entry points. Webhook subscriptions are registered via `s.httpRequestSubscribe()` in `flowStartTriggered`.
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: job-patterns
|
|
3
|
+
category: switch-api
|
|
4
|
+
order: 16
|
|
5
|
+
summary: "`Job` **rules and gotchas**: file access semantics, temp cleanup, which `sendTo*()` suits which connection type, dataset/child ordering, executor limits"
|
|
6
|
+
triggers:
|
|
7
|
+
- "Writing or reviewing job-handling code. Pair with `job.md` when you also need signatures"
|
|
8
|
+
---
|
|
9
|
+
|
|
1
10
|
# Job Patterns and Behavioral Rules
|
|
2
11
|
|
|
3
12
|
Common behavioral rules for file access, routing, temp file cleanup, and child jobs. These are the most frequent sources of bugs.
|
|
@@ -73,7 +82,7 @@ await fs.promises.rm(tempPath);
|
|
|
73
82
|
- If `OutgoingConnections="Unlimited"` (more than one outgoing connection allowed), never use
|
|
74
83
|
`job.sendToSingle()` — it only makes sense when exactly one outgoing connection exists.
|
|
75
84
|
- If no output is produced for a job, call `job.sendToNull()` rather than leaving it unrouted.
|
|
76
|
-
- `ConnectionType="Move"` (see [
|
|
85
|
+
- `ConnectionType="Move"` (see [script-declaration.md](../switch-project/script-declaration.md#connectionfields)):
|
|
77
86
|
never use `job.sendToData()`/`job.sendToLog()` — those are for `TrafficLight` connections only. Use
|
|
78
87
|
`job.sendTo()`/`job.sendToSingle()`.
|
|
79
88
|
- `ConnectionType="TrafficLight"`: use only `job.sendToData()`/`job.sendToLog()` — never
|
|
@@ -81,9 +90,15 @@ await fs.promises.rm(tempPath);
|
|
|
81
90
|
is enabled in the declaration, and `sendToLog` when the corresponding Log connection is enabled.
|
|
82
91
|
Conversely, don't declare a Success/Warning/Error element the script never routes to — omit it from
|
|
83
92
|
`ConnectionFields` entirely (see the TrafficLight example in
|
|
84
|
-
[
|
|
93
|
+
[script-declaration.md](../switch-project/script-declaration.md#connectionfields)).
|
|
94
|
+
`sendToData(level)` fails the job if no connected outgoing data connection accepts that level,
|
|
95
|
+
and there is no supported way to check in advance which levels are wired up (see
|
|
96
|
+
[connection.md § Connection.Level enum](connection.md#connectionlevel-enum)). If routing at a
|
|
97
|
+
given level is optional rather than guaranteed by the flow design, expose an explicit custom
|
|
98
|
+
property that lets the flow author opt in or out, and call `job.sendToNull()` when opted out
|
|
99
|
+
instead of guessing whether `sendToData()` will succeed.
|
|
85
100
|
- Prefer `job.fail()`/`flowElement.failProcess()` for genuine processing errors (see
|
|
86
|
-
[
|
|
101
|
+
[logging.md](logging.md)) over silently routing a failed job to a generic error connection —
|
|
87
102
|
reserve an error `TrafficLight` connection for cases the flow author should be able to reroute
|
|
88
103
|
downstream, not as a substitute for `fail()`.
|
|
89
104
|
|
|
@@ -93,7 +108,7 @@ await fs.promises.rm(tempPath);
|
|
|
93
108
|
|
|
94
109
|
**Known issue — pending a server-side fix; remove this section once fixed.** Applies to all current versions.
|
|
95
110
|
|
|
96
|
-
`job.createChild()` copies the parent's *current* datasets immediately (see [
|
|
111
|
+
`job.createChild()` copies the parent's *current* datasets immediately (see [job.md](job.md#child-jobs)); `job.createDataset()` only registers a pending write, flushed to disk at the next `sendTo*()` call (see [job.md](job.md#datasets-metadata)). If a child is created *before* a dataset is written, the child inherits the job's existing dataset under that name instead. At flush time, the pending write fans out concurrently to the parent and to every child created so far, all reading from the same source file on disk — targets that already have a dataset by that name get the file **moved** into place, while targets that don't get it **copied**. When a mix of both happens against a single source file, the move wins the race and the copies fail with errors like `Could not place the file with the decoded data '...' into the datasets folder`, deterministically and on every retry (the source file is gone after the first attempt).
|
|
97
112
|
|
|
98
113
|
**Rule:** perform every dataset write on a job before creating any child of it. Where a script's structure naturally interleaves the two, iterate the dataset outputs first, then the child-job outputs, rather than handling each output in one pass.
|
|
99
114
|
|
|
@@ -131,14 +146,14 @@ The Node.js executor process is recycled when any of the following thresholds is
|
|
|
131
146
|
|
|
132
147
|
On cleanup, any files/folders created in the temp area are removed. Always close file handles and database connections before the entry point returns.
|
|
133
148
|
|
|
134
|
-
See [
|
|
149
|
+
See [execution-environment.md](execution-environment.md) for how this process model affects state persistence and error handling across job invocations.
|
|
135
150
|
|
|
136
151
|
## Driving a third-party CLI application
|
|
137
152
|
|
|
138
153
|
`findApplicationPath` and the `ApplicationPath` property are the legacy-scripting mechanism for
|
|
139
154
|
locating a third-party application; neither is available to Node.js scripts, and `ApplicationPath`
|
|
140
155
|
is a reserved name Switch silently drops from the declaration (see
|
|
141
|
-
[
|
|
156
|
+
[script-declaration.md](../switch-project/script-declaration.md#built-in-elementfields)). A Node.js script or
|
|
142
157
|
app that shells out to an external binary resolves the path itself, using the following pattern.
|
|
143
158
|
|
|
144
159
|
1. Declare an ordinary custom property for the path under a name of your own — `cliPath`, not
|
|
@@ -147,7 +162,7 @@ app that shells out to an external binary resolves the path itself, using the fo
|
|
|
147
162
|
`Default="Automatic"` and `Subtype="automatic"`. The `automatic` literal editor is what lets the
|
|
148
163
|
user express "find it yourself" without typing a magic string, and `getPropertyStringValue()`
|
|
149
164
|
returns the literal `"Automatic"` for it — see
|
|
150
|
-
[
|
|
165
|
+
[property-editors.md § Literal editors](../switch-project/property-editors.md#literal-editors).
|
|
151
166
|
3. Resolve the path once per flow start, in `flowStartTriggered`: if the property reads
|
|
152
167
|
`Automatic`, run whatever discovery the application needs; otherwise take
|
|
153
168
|
`flowElement.getPropertyStringValue('cliPath')`. Verify the resulting path actually exists, then
|
|
@@ -157,7 +172,7 @@ app that shells out to an external binary resolves the path itself, using the fo
|
|
|
157
172
|
discovery failed: call `flowElement.failProcess()` so the element goes into an error state,
|
|
158
173
|
instead of failing every individual job.
|
|
159
174
|
5. Remove the global data entry in `flowStopTriggered` — global data is never cleaned up
|
|
160
|
-
automatically (see [
|
|
175
|
+
automatically (see [switch.md § Global data](switch.md#global-data)).
|
|
161
176
|
|
|
162
177
|
Doing discovery once at flow start rather than per job keeps a filesystem search off the job path,
|
|
163
178
|
and gives the operator a single clear element-level error when the application is missing.
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: job
|
|
3
|
+
category: switch-api
|
|
4
|
+
order: 5
|
|
5
|
+
summary: "`Job` **signatures**: routing, file access, child jobs, private data, datasets"
|
|
6
|
+
triggers:
|
|
7
|
+
- "Looking up what a `job.*` method takes, returns, or throws"
|
|
8
|
+
---
|
|
9
|
+
|
|
1
10
|
# Job Class
|
|
2
11
|
|
|
3
12
|
A `Job` represents a file or folder moving through the flow. It is passed to `jobArrived` and can be created via `flowElement.createJob()` or `job.createChild()`. Every job must be routed with a `sendTo*()` call or `fail()` before the entry point ends (or at a later time via `timerFired`).
|
|
@@ -36,7 +45,7 @@ Returns the local filesystem path to the job. Use `AccessLevel.ReadOnly` to read
|
|
|
36
45
|
|
|
37
46
|
## Routing
|
|
38
47
|
|
|
39
|
-
Every job must be routed exactly once. See [
|
|
48
|
+
Every job must be routed exactly once. See [job-patterns.md § Sending jobs](job-patterns.md#sending-jobs) for which `sendTo*()` method is appropriate for a given `ConnectionType`/`OutgoingConnections` declaration.
|
|
40
49
|
|
|
41
50
|
```ts
|
|
42
51
|
job.sendToNull(): Promise<void>
|
|
@@ -75,7 +84,7 @@ Re-queue the job for `jobArrived` after a minimum delay (re-evaluates dynamic pr
|
|
|
75
84
|
|
|
76
85
|
## Failure & logging
|
|
77
86
|
|
|
78
|
-
See [
|
|
87
|
+
See [logging.md](logging.md) for log level semantics and logging practice.
|
|
79
88
|
|
|
80
89
|
```ts
|
|
81
90
|
job.fail(message: string, messageParams?: (string | number | boolean)[]): void
|
|
@@ -92,7 +101,7 @@ Log a message including job context. To log a literal `%`, pass it as a param: `
|
|
|
92
101
|
```ts
|
|
93
102
|
job.createChild(path: string): Promise<Job>
|
|
94
103
|
```
|
|
95
|
-
Creates a new job inheriting the processing history, metadata, and private data of the parent. Takes effect immediately: the child's datasets are copied from the parent's *current* server-side state, so any pending `createDataset()` write not yet flushed by a `sendTo*()` call is not reflected in it. See [
|
|
104
|
+
Creates a new job inheriting the processing history, metadata, and private data of the parent. Takes effect immediately: the child's datasets are copied from the parent's *current* server-side state, so any pending `createDataset()` write not yet flushed by a `sendTo*()` call is not reflected in it. See [job-patterns.md](job-patterns.md#dataset-writes-must-precede-child-job-creation) — creating a child before writing a dataset is a common source of bugs. The caller is responsible for cleaning up the source file after routing (see [job-patterns.md](job-patterns.md#temp-file-cleanup)).
|
|
96
105
|
|
|
97
106
|
## Private data
|
|
98
107
|
|
|
@@ -128,7 +137,7 @@ List all datasets attached to the job. **Immediate**: reads server state at once
|
|
|
128
137
|
```ts
|
|
129
138
|
job.createDataset(name: string, filePath: string, model: DatasetModel): Promise<void>
|
|
130
139
|
```
|
|
131
|
-
Attach a new dataset. **Deferred**: registers in-memory only; the file is not uploaded until the next `sendTo*()` call. Caller must clean up the source file after routing — see [
|
|
140
|
+
Attach a new dataset. **Deferred**: registers in-memory only; the file is not uploaded until the next `sendTo*()` call. Caller must clean up the source file after routing — see [job-patterns.md](job-patterns.md#temp-file-cleanup).
|
|
132
141
|
|
|
133
142
|
```ts
|
|
134
143
|
job.getDataset(name: string, accessLevel: AccessLevel): Promise<string>
|