sdn-flow 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/SKILLS.md +7 -0
- package/.claude/skills/sdn-plugin-abi-compliance/SKILL.md +56 -0
- package/.claude/todo/001-js-host-startup-and-deno.md +85 -0
- package/LICENSE +21 -0
- package/README.md +223 -0
- package/bin/sdn-flow-host.js +169 -0
- package/docs/.nojekyll +0 -0
- package/docs/ARCHITECTURE.md +200 -0
- package/docs/HOST_CAPABILITY_MODEL.md +317 -0
- package/docs/PLUGIN_ARCHITECTURE.md +145 -0
- package/docs/PLUGIN_COMPATIBILITY.md +61 -0
- package/docs/PLUGIN_COMPLIANCE_CHECKS.md +82 -0
- package/docs/PLUGIN_MANIFEST.md +94 -0
- package/docs/css/style.css +465 -0
- package/docs/index.html +218 -0
- package/docs/js/app.mjs +751 -0
- package/docs/js/editor-panel.mjs +203 -0
- package/docs/js/flow-canvas.mjs +515 -0
- package/docs/js/flow-model.mjs +391 -0
- package/docs/js/workers/emception.worker.js +146 -0
- package/docs/js/workers/pyodide.worker.js +134 -0
- package/native/flow_source_generator.cpp +1958 -0
- package/package.json +67 -0
- package/schemas/FlowRuntimeAbi.fbs +91 -0
- package/src/auth/canonicalize.js +5 -0
- package/src/auth/index.js +11 -0
- package/src/auth/permissions.js +8 -0
- package/src/compiler/CppFlowSourceGenerator.js +475 -0
- package/src/compiler/EmceptionCompilerAdapter.js +244 -0
- package/src/compiler/SignedArtifactCatalog.js +152 -0
- package/src/compiler/index.js +8 -0
- package/src/compiler/nativeFlowSourceGeneratorTool.js +144 -0
- package/src/compliance/index.js +13 -0
- package/src/compliance/pluginCompliance.js +11 -0
- package/src/deploy/FlowDeploymentClient.js +532 -0
- package/src/deploy/index.js +8 -0
- package/src/designer/FlowDesignerSession.js +158 -0
- package/src/designer/index.js +2 -0
- package/src/designer/requirements.js +184 -0
- package/src/generated/runtimeAbiLayouts.js +544 -0
- package/src/host/appHost.js +105 -0
- package/src/host/autoHost.js +113 -0
- package/src/host/browserHostAdapters.js +108 -0
- package/src/host/compiledFlowRuntimeHost.js +703 -0
- package/src/host/constants.js +55 -0
- package/src/host/dependencyRuntime.js +227 -0
- package/src/host/descriptorAbi.js +351 -0
- package/src/host/fetchService.js +237 -0
- package/src/host/httpHostAdapters.js +280 -0
- package/src/host/index.js +91 -0
- package/src/host/installedFlowHost.js +885 -0
- package/src/host/invocationAbi.js +440 -0
- package/src/host/normalize.js +372 -0
- package/src/host/packageManagers.js +369 -0
- package/src/host/profile.js +134 -0
- package/src/host/runtimeAbi.js +106 -0
- package/src/host/workspace.js +895 -0
- package/src/index.js +8 -0
- package/src/runtime/FlowRuntime.js +273 -0
- package/src/runtime/MethodRegistry.js +295 -0
- package/src/runtime/constants.js +44 -0
- package/src/runtime/index.js +19 -0
- package/src/runtime/normalize.js +377 -0
- package/src/transport/index.js +7 -0
- package/src/transport/pki.js +7 -0
- package/src/utils/crypto.js +7 -0
- package/src/utils/encoding.js +65 -0
- package/src/utils/wasmCrypto.js +69 -0
- package/tools/run-plugin-compliance-check.mjs +153 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Shared SDN Skills
|
|
2
|
+
|
|
3
|
+
## Available skills
|
|
4
|
+
|
|
5
|
+
1. SDN Plugin ABI & Compliance
|
|
6
|
+
- Path: `.claude/skills/sdn-plugin-abi-compliance/SKILL.md`
|
|
7
|
+
- Use when touching plugin manifests, plugin API/ABI exports, compiled artifact compliance, or cross-repo SDN plugin architecture.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# SDN Plugin ABI & Compliance
|
|
2
|
+
|
|
3
|
+
Use this skill whenever a task touches:
|
|
4
|
+
|
|
5
|
+
- plugin API/ABI rules
|
|
6
|
+
- manifest shape
|
|
7
|
+
- embedded manifest exports
|
|
8
|
+
- plugin compliance gates
|
|
9
|
+
- cross-repo SDN plugin architecture
|
|
10
|
+
|
|
11
|
+
## Canonical source of truth
|
|
12
|
+
|
|
13
|
+
- `docs/PLUGIN_ARCHITECTURE.md`
|
|
14
|
+
- `docs/PLUGIN_MANIFEST.md`
|
|
15
|
+
- `docs/HOST_CAPABILITY_MODEL.md`
|
|
16
|
+
- `docs/PLUGIN_COMPATIBILITY.md`
|
|
17
|
+
- `docs/PLUGIN_COMPLIANCE_CHECKS.md`
|
|
18
|
+
|
|
19
|
+
## Hard rules
|
|
20
|
+
|
|
21
|
+
1. A plugin is a degenerate one-node flow.
|
|
22
|
+
2. Deployable artifacts embed a FlatBuffer manifest.
|
|
23
|
+
3. Plugin artifacts expose:
|
|
24
|
+
- `plugin_get_manifest_flatbuffer`
|
|
25
|
+
- `plugin_get_manifest_flatbuffer_size`
|
|
26
|
+
4. Hosts bridge capabilities; they do not fork the plugin ABI.
|
|
27
|
+
5. Capability and external-interface requirements must be explicit.
|
|
28
|
+
|
|
29
|
+
## Compliance workflow
|
|
30
|
+
|
|
31
|
+
1. Validate the manifest contract first.
|
|
32
|
+
2. Validate compiled ABI exports when a `.wasm` artifact exists.
|
|
33
|
+
3. Do not invent repo-local ABI variants.
|
|
34
|
+
4. Use the shared checker in this repo instead of copying new compliance logic elsewhere.
|
|
35
|
+
|
|
36
|
+
## Commands
|
|
37
|
+
|
|
38
|
+
Repo scan:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
node tools/run-plugin-compliance-check.mjs --repo-root .
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
If a repo needs targeted scanning, add `sdn-plugin-compliance.json` at its root
|
|
45
|
+
and keep only manifest paths or scan directories there.
|
|
46
|
+
|
|
47
|
+
Manifest plus wasm artifact:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
node tools/run-plugin-compliance-check.mjs --manifest ./manifest.json --wasm ./dist/plugin.wasm
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Cross-repo rule
|
|
54
|
+
|
|
55
|
+
Other Space Data Network repos should call this checker through thin wrapper
|
|
56
|
+
scripts only. The actual API/ABI logic must live here in `sdn-flow`.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
1. Add explicit JS-host engine modeling for `node`, `deno`, `bun`, and `browser`. (done)
|
|
2
|
+
|
|
3
|
+
2. Keep one `sdn-js` adapter family while allowing environment-specific compatibility summaries. (done)
|
|
4
|
+
|
|
5
|
+
3. Add installed plugin package discovery for Node/JS hosts so packages can be scanned from directories with `manifest.json` and optional `plugin.js`. (done)
|
|
6
|
+
|
|
7
|
+
4. Add environment-neutral installed plugin loading so browser/Deno hosts can supply in-memory manifests/modules instead of filesystem discovery. (done)
|
|
8
|
+
|
|
9
|
+
5. Add a bootstrap API that discovers/registers installed plugins and loads a flow program into a runtime. (done)
|
|
10
|
+
|
|
11
|
+
6. Make the bootstrap API usable for Node-RED-style “install nodes and startup” flows. (done)
|
|
12
|
+
Done:
|
|
13
|
+
- `createInstalledFlowHost(...)`
|
|
14
|
+
- package discovery and registration
|
|
15
|
+
- flow program load + runtime drain bootstrap
|
|
16
|
+
- `createInstalledFlowService(...)`
|
|
17
|
+
- portable timer trigger scheduling
|
|
18
|
+
- portable HTTP request trigger dispatch
|
|
19
|
+
- `host.refreshPlugins(...)`
|
|
20
|
+
- `service.refresh(...)`
|
|
21
|
+
- runnable top-level bootstrap examples and scripts for each concrete host adapter
|
|
22
|
+
- persisted package catalog plus package-manager-driven install/update/remove flows
|
|
23
|
+
|
|
24
|
+
7. Add Deno-oriented host-plan support so `sdn-js` deployments can declare `engine: "deno"` and document single-file deployment intent. (done)
|
|
25
|
+
|
|
26
|
+
8. Add compatibility reporting so the same flow can be evaluated against `browser`, `deno`, `node`, and other supported engines with explicit unsupported capabilities. (done)
|
|
27
|
+
|
|
28
|
+
9. Add tests for plugin discovery, installed-package registration, startup bootstrap, and browser/deno compatibility summaries. (done)
|
|
29
|
+
|
|
30
|
+
10. Update README and environment examples once the bootstrap and engine model land. (done)
|
|
31
|
+
|
|
32
|
+
11. Add a fetch-style host adapter so Deno/browser/Bun/modern Node can bind installed flows to a shared `Request`/`Response` entrypoint. (done)
|
|
33
|
+
|
|
34
|
+
12. Add a persisted workspace/bootstrap layer so installed-flow hosts can boot from one workspace file with flow paths, plugin roots, and host defaults. (done)
|
|
35
|
+
|
|
36
|
+
13. Add explicit workspace package-catalog mutation so hosts can persist install/uninstall operations and refresh the runtime against that state. (done)
|
|
37
|
+
|
|
38
|
+
14. Add a host-plan launcher that can auto-bind installed-flow HTTP listeners through an injected serve adapter. (done)
|
|
39
|
+
|
|
40
|
+
15. Add concrete Deno- and Node-oriented HTTP host adapters on top of the installed-flow launcher surface. (done)
|
|
41
|
+
|
|
42
|
+
16. Add concrete browser/worker fetch-host adapters on top of the installed-flow launcher surface. (done)
|
|
43
|
+
|
|
44
|
+
17. Add concrete Bun HTTP host adapters on top of the installed-flow launcher surface. (done)
|
|
45
|
+
|
|
46
|
+
18. Add runnable top-level bootstrap examples/scripts for Deno, Node, Bun, and browser worker hosts. (done)
|
|
47
|
+
Goal:
|
|
48
|
+
- one small checked-in startup entrypoint per concrete host adapter
|
|
49
|
+
- direct use of `workspace.json` plus the new host adapter surfaces
|
|
50
|
+
- clear examples of how a host actually boots and stays up in each environment
|
|
51
|
+
|
|
52
|
+
19. Add external package-manager and persistence integration beyond the local workspace catalog. (done)
|
|
53
|
+
Done:
|
|
54
|
+
- persisted `packageCatalog` / `installedPackages` normalization in workspace state
|
|
55
|
+
- `installWorkspacePackageReference(...)`, `updateWorkspacePackageReference(...)`, and `removeWorkspacePackageReference(...)`
|
|
56
|
+
- `app.installPackageReference(...)`, `app.updatePackageReference(...)`, and `app.removePackageReference(...)`
|
|
57
|
+
- generic `createCommandPackageManager(...)` adapter
|
|
58
|
+
- concrete `createNpmPackageManager(...)` adapter
|
|
59
|
+
- workspace tests for package-reference persistence and runtime refresh alignment
|
|
60
|
+
|
|
61
|
+
20. Add one environment-neutral installed-flow startup entrypoint that can select the concrete host adapter from workspace/runtime metadata. (done)
|
|
62
|
+
Done:
|
|
63
|
+
- `resolveInstalledFlowAutoHostEngine(...)`
|
|
64
|
+
- `startInstalledFlowAutoHost(...)`
|
|
65
|
+
- dispatch to browser, Deno, Bun, and Node startup surfaces
|
|
66
|
+
- explicit starter injection hooks for tests and embedded hosts
|
|
67
|
+
|
|
68
|
+
21. Add a checked-in auto-host bootstrap script that starts from `workspace.json` through the environment-neutral startup surface. (done)
|
|
69
|
+
Done:
|
|
70
|
+
- `examples/bootstrap/start-auto-host.mjs`
|
|
71
|
+
- direct startup from the checked-in `sdn-js-catalog-gateway/workspace.json`
|
|
72
|
+
- bootstrap coverage proving the example dispatches through `startInstalledFlowAutoHost(...)`
|
|
73
|
+
|
|
74
|
+
22. Add a simple host CLI that boots one workspace through the auto-host surface. (done)
|
|
75
|
+
Done:
|
|
76
|
+
- `bin/sdn-flow-host.js`
|
|
77
|
+
- `--workspace` and optional `--engine` override support
|
|
78
|
+
- startup summary plus `SIGINT`/`SIGTERM` shutdown hooks
|
|
79
|
+
- CLI coverage for parsing, help text, and startup dispatch
|
|
80
|
+
|
|
81
|
+
23. Publish root AGENTS guidance for module and flow builders. (done)
|
|
82
|
+
Done:
|
|
83
|
+
- root `AGENTS.md` in `space-data-module-sdk` for compliant module authors
|
|
84
|
+
- rewritten root `AGENTS.md` in `sdn-flow` for compliant flow and host authors
|
|
85
|
+
- explicit integration-test lists for module, bundle, compiler, startup, and environment changes
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DigitalArsenal.io, Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# sdn-flow
|
|
2
|
+
|
|
3
|
+
`sdn-flow` composes signed modules into typed flow graphs,
|
|
4
|
+
compiles those graphs into deployable WebAssembly runtimes, and provides host
|
|
5
|
+
surfaces for loading, starting, and serving those flows.
|
|
6
|
+
|
|
7
|
+
It builds on `space-data-module-sdk`, which defines the module artifact,
|
|
8
|
+
single-file bundle, capability vocabulary, and module ABI. `sdn-flow` owns the
|
|
9
|
+
flow graph, compiled flow descriptors, hosted runtime planning, deployment
|
|
10
|
+
client, and installed-flow startup layers.
|
|
11
|
+
|
|
12
|
+
## Project Scope
|
|
13
|
+
|
|
14
|
+
This repo covers the full flow path:
|
|
15
|
+
|
|
16
|
+
- normalized flow programs and runtime descriptors
|
|
17
|
+
- designer-facing graph inspection and requirement summaries
|
|
18
|
+
- compilation from flow graph to one generated C++ translation unit
|
|
19
|
+
- `emception`-backed compilation to one deployable `.wasm` runtime artifact
|
|
20
|
+
- deployment packaging built on canonical module auth and transport records
|
|
21
|
+
- hosted runtime planning for browser, JS server, Go-oriented, and vendor
|
|
22
|
+
runtime profiles
|
|
23
|
+
- installed-flow startup surfaces for browser, Deno, Bun, and Node hosts
|
|
24
|
+
|
|
25
|
+
## Flow Artifact
|
|
26
|
+
|
|
27
|
+
A compiled flow is one runtime artifact with:
|
|
28
|
+
|
|
29
|
+
- WebAssembly bytes
|
|
30
|
+
- an embedded FlatBuffer manifest
|
|
31
|
+
- exported runtime, invocation, and descriptor symbols
|
|
32
|
+
- embedded signed module dependencies
|
|
33
|
+
- deployment metadata for local or remote rollout
|
|
34
|
+
|
|
35
|
+
The compiler path uses a native C++ source generator compiled to WebAssembly
|
|
36
|
+
plus an `emception`-compatible compiler adapter, so the flow graph always
|
|
37
|
+
converges on the same runtime artifact format.
|
|
38
|
+
|
|
39
|
+
## Runtime Portability
|
|
40
|
+
|
|
41
|
+
Flows generated by `sdn-flow` are runtime-neutral compiled WebAssembly
|
|
42
|
+
artifacts. A host can run the output anywhere it can:
|
|
43
|
+
|
|
44
|
+
- instantiate WebAssembly
|
|
45
|
+
- read FlatBuffers
|
|
46
|
+
- implement the canonical module and flow ABI surface
|
|
47
|
+
|
|
48
|
+
That is the same runtime family already exercised in the companion
|
|
49
|
+
`flatbuffers/wasm` work:
|
|
50
|
+
|
|
51
|
+
- browser
|
|
52
|
+
- Node.js
|
|
53
|
+
- C#
|
|
54
|
+
- Go
|
|
55
|
+
- Java
|
|
56
|
+
- Kotlin
|
|
57
|
+
- Python
|
|
58
|
+
- Rust
|
|
59
|
+
- Swift
|
|
60
|
+
|
|
61
|
+
This repo currently ships turnkey startup surfaces for browser, Deno, Bun, and
|
|
62
|
+
Node, and it includes environment profiles for `go-sdn` and WasmEdge-style
|
|
63
|
+
hosts. Non-JS runtimes consume the same compiled artifact through the runtime,
|
|
64
|
+
invocation, and descriptor ABIs exposed from `src/host`.
|
|
65
|
+
|
|
66
|
+
## Relationship To Module SDK
|
|
67
|
+
|
|
68
|
+
`space-data-module-sdk` is the canonical module contract:
|
|
69
|
+
|
|
70
|
+
- manifest schema and embedded manifest exports
|
|
71
|
+
- module capability vocabulary
|
|
72
|
+
- compliance rules
|
|
73
|
+
- module signing and transport envelopes
|
|
74
|
+
- `sds.bundle` single-file packaging
|
|
75
|
+
- module hostcall/import ABI
|
|
76
|
+
|
|
77
|
+
`sdn-flow` layers flow composition on top of that contract:
|
|
78
|
+
|
|
79
|
+
- program structure and graph normalization
|
|
80
|
+
- compiled flow runtime descriptor and invocation ABI
|
|
81
|
+
- dependency composition for multi-module runtimes
|
|
82
|
+
- deployment clients and hosted runtime plans
|
|
83
|
+
- startup surfaces for hosts that launch compiled flows
|
|
84
|
+
|
|
85
|
+
## Install
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npm install sdn-flow
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Compile A Flow
|
|
92
|
+
|
|
93
|
+
```js
|
|
94
|
+
import {
|
|
95
|
+
EmceptionCompilerAdapter,
|
|
96
|
+
SignedArtifactCatalog,
|
|
97
|
+
normalizeProgram,
|
|
98
|
+
} from "sdn-flow";
|
|
99
|
+
|
|
100
|
+
const program = normalizeProgram(flowJson);
|
|
101
|
+
|
|
102
|
+
const compiler = new EmceptionCompilerAdapter({
|
|
103
|
+
emception,
|
|
104
|
+
artifactCatalog: new SignedArtifactCatalog(),
|
|
105
|
+
manifestBuilder: async () => manifestBytes,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const artifact = await compiler.compile({
|
|
109
|
+
program,
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The compiled artifact carries the exported symbols needed by hosts to inspect
|
|
114
|
+
and run the flow without reinterpreting the source graph.
|
|
115
|
+
|
|
116
|
+
## Start A Host
|
|
117
|
+
|
|
118
|
+
For JS-family hosts, the quickest path is a workspace file plus the
|
|
119
|
+
environment-neutral auto-host entrypoint:
|
|
120
|
+
|
|
121
|
+
```js
|
|
122
|
+
import { startInstalledFlowAutoHost } from "sdn-flow";
|
|
123
|
+
|
|
124
|
+
await startInstalledFlowAutoHost({
|
|
125
|
+
workspacePath: "./workspace.json",
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
For Node-based startup from the command line:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
sdn-flow-host --workspace ./workspace.json
|
|
133
|
+
sdn-flow-host --workspace ./workspace.json --engine node
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
That CLI is a thin wrapper over `startInstalledFlowAutoHost(...)` with startup
|
|
137
|
+
summary output and `SIGINT` / `SIGTERM` shutdown handling.
|
|
138
|
+
|
|
139
|
+
## Host Surfaces
|
|
140
|
+
|
|
141
|
+
The host package is organized around a few layers:
|
|
142
|
+
|
|
143
|
+
- `createInstalledFlowHost(...)`
|
|
144
|
+
Discover or register plugin packages, load a program, and start the runtime.
|
|
145
|
+
- `createInstalledFlowService(...)`
|
|
146
|
+
Keep timer and HTTP-trigger services running for a loaded flow.
|
|
147
|
+
- `createInstalledFlowApp(...)`
|
|
148
|
+
Boot from `workspace.json`, persist startup state, and refresh the runtime
|
|
149
|
+
against workspace changes.
|
|
150
|
+
- `startInstalledFlowAutoHost(...)`
|
|
151
|
+
Select the matching startup surface for browser, Deno, Bun, or Node from
|
|
152
|
+
workspace metadata.
|
|
153
|
+
- `createNpmPackageManager(...)`
|
|
154
|
+
Tie workspace package references to real install, update, and remove flows.
|
|
155
|
+
|
|
156
|
+
For hosts that load compiled artifacts directly, `bindCompiledRuntimeAbi(...)`,
|
|
157
|
+
`bindCompiledInvocationAbi(...)`, and `bindCompiledDescriptorAbi(...)` expose
|
|
158
|
+
the low-level contract used to inspect and execute a compiled flow artifact.
|
|
159
|
+
|
|
160
|
+
## Runtime Families
|
|
161
|
+
|
|
162
|
+
| Layer | Coverage |
|
|
163
|
+
|---|---|
|
|
164
|
+
| Compiled flow artifact | Browser, Node.js, C#, Go, Java, Kotlin, Python, Rust, Swift |
|
|
165
|
+
| Turnkey startup surfaces in this repo | Browser, Deno, Bun, Node |
|
|
166
|
+
| Checked-in environment profiles | `sdn-js`, `go-sdn`, WasmEdge-style vendor profile |
|
|
167
|
+
|
|
168
|
+
The built-in host planners focus on the engines exercised by the current
|
|
169
|
+
examples and startup helpers. The compiled flow artifact itself stays portable
|
|
170
|
+
across the broader runtime set above.
|
|
171
|
+
|
|
172
|
+
## Examples
|
|
173
|
+
|
|
174
|
+
- [Bootstrap Examples](./examples/bootstrap/README.md)
|
|
175
|
+
- [Environment Demos](./examples/environments/README.md)
|
|
176
|
+
- [Single-Plugin Flow](./examples/flows/single-plugin-flow.json)
|
|
177
|
+
- [Field-Protected Catalog Entry Flow](./examples/flows/field-protected-catalog-entry/README.md)
|
|
178
|
+
- [ISS Proximity OEM Flow](./examples/flows/iss-proximity-oem/README.md)
|
|
179
|
+
|
|
180
|
+
Notable environment profiles:
|
|
181
|
+
|
|
182
|
+
- [`sdn-js-catalog-gateway`](./examples/environments/sdn-js-catalog-gateway/README.md)
|
|
183
|
+
Shared JS-host profile with Deno as the preferred single-file deployment
|
|
184
|
+
target.
|
|
185
|
+
- [`go-sdn-omm-service`](./examples/environments/go-sdn-omm-service/README.md)
|
|
186
|
+
Go-oriented service deployment profile.
|
|
187
|
+
- [`wasmedge-udp-spooler`](./examples/environments/wasmedge-udp-spooler/README.md)
|
|
188
|
+
Vendor-profile example for extension-backed UDP and filesystem handling.
|
|
189
|
+
|
|
190
|
+
## Package Surface
|
|
191
|
+
|
|
192
|
+
- `sdn-flow`
|
|
193
|
+
- `sdn-flow/runtime`
|
|
194
|
+
- `sdn-flow/designer`
|
|
195
|
+
- `sdn-flow/host`
|
|
196
|
+
- `sdn-flow/auth`
|
|
197
|
+
- `sdn-flow/transport`
|
|
198
|
+
- `sdn-flow/deploy`
|
|
199
|
+
- `sdn-flow/compiler`
|
|
200
|
+
- `sdn-flow/compliance`
|
|
201
|
+
|
|
202
|
+
## Documentation
|
|
203
|
+
|
|
204
|
+
- [Architecture](./docs/ARCHITECTURE.md)
|
|
205
|
+
- [Host Capability Model](./docs/HOST_CAPABILITY_MODEL.md)
|
|
206
|
+
- [Plugin Architecture](./docs/PLUGIN_ARCHITECTURE.md)
|
|
207
|
+
- [Plugin Manifest](./docs/PLUGIN_MANIFEST.md)
|
|
208
|
+
- [Compatibility Model](./docs/PLUGIN_COMPATIBILITY.md)
|
|
209
|
+
- [Plugin Compliance Checks](./docs/PLUGIN_COMPLIANCE_CHECKS.md)
|
|
210
|
+
|
|
211
|
+
## Development
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
npm install
|
|
215
|
+
npm test
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Node.js `>=20` is required. The compile path uses `../emception` for generated
|
|
219
|
+
C++ to WebAssembly builds.
|
|
220
|
+
|
|
221
|
+
## License
|
|
222
|
+
|
|
223
|
+
[MIT](./LICENSE)
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import process from "node:process";
|
|
4
|
+
|
|
5
|
+
import { startInstalledFlowAutoHost } from "../src/index.js";
|
|
6
|
+
|
|
7
|
+
function normalizeString(value, fallback = null) {
|
|
8
|
+
if (typeof value !== "string") {
|
|
9
|
+
return fallback;
|
|
10
|
+
}
|
|
11
|
+
const normalized = value.trim();
|
|
12
|
+
return normalized.length > 0 ? normalized : fallback;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function formatSdnFlowHostUsage() {
|
|
16
|
+
return [
|
|
17
|
+
"Usage: sdn-flow-host --workspace <workspace.json> [--engine <engine>]",
|
|
18
|
+
"",
|
|
19
|
+
"Options:",
|
|
20
|
+
" -w, --workspace <path> Path to the installed-flow workspace.json file.",
|
|
21
|
+
" -e, --engine <engine> Optional runtime override: node, deno, bun, browser.",
|
|
22
|
+
" -h, --help Show this help text.",
|
|
23
|
+
].join("\n");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function parseSdnFlowHostCliArgs(argv = []) {
|
|
27
|
+
const args = Array.isArray(argv) ? [...argv] : [];
|
|
28
|
+
let workspacePath = null;
|
|
29
|
+
let engine = null;
|
|
30
|
+
let help = false;
|
|
31
|
+
|
|
32
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
33
|
+
const token = args[index];
|
|
34
|
+
if (token === "-h" || token === "--help") {
|
|
35
|
+
help = true;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (token === "-w" || token === "--workspace") {
|
|
39
|
+
workspacePath = normalizeString(args[index + 1], null);
|
|
40
|
+
index += 1;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (token === "-e" || token === "--engine") {
|
|
44
|
+
engine = normalizeString(args[index + 1], null);
|
|
45
|
+
index += 1;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (!token.startsWith("-") && workspacePath === null) {
|
|
49
|
+
workspacePath = normalizeString(token, null);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
throw new Error(`Unknown argument: ${token}`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
workspacePath,
|
|
57
|
+
engine,
|
|
58
|
+
help,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function summarizeStartedHost(host) {
|
|
63
|
+
const startupSummary = host?.startup?.workspace ?? null;
|
|
64
|
+
const listenerCount = Array.isArray(host?.listeners)
|
|
65
|
+
? host.listeners.length
|
|
66
|
+
: Array.isArray(host?.bindingContexts)
|
|
67
|
+
? host.bindingContexts.length
|
|
68
|
+
: 0;
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
workspaceId:
|
|
72
|
+
startupSummary?.workspaceId ?? host?.app?.getSummary?.().workspaceId ?? null,
|
|
73
|
+
programId:
|
|
74
|
+
startupSummary?.programId ?? host?.app?.getSummary?.().programId ?? null,
|
|
75
|
+
engine: startupSummary?.engine ?? host?.app?.getSummary?.().engine ?? null,
|
|
76
|
+
listenerCount,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function installShutdownHooks(host, options = {}) {
|
|
81
|
+
if (
|
|
82
|
+
options.registerSignalHandlers === false ||
|
|
83
|
+
typeof host?.stop !== "function" ||
|
|
84
|
+
typeof process.on !== "function"
|
|
85
|
+
) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
let stopping = false;
|
|
90
|
+
const stopHost = async () => {
|
|
91
|
+
if (stopping) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
stopping = true;
|
|
95
|
+
await host.stop();
|
|
96
|
+
if (options.exitProcess !== false) {
|
|
97
|
+
process.exit(0);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
process.on("SIGINT", () => {
|
|
102
|
+
void stopHost();
|
|
103
|
+
});
|
|
104
|
+
process.on("SIGTERM", () => {
|
|
105
|
+
void stopHost();
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export async function runSdnFlowHostCli(argv = process.argv.slice(2), options = {}) {
|
|
110
|
+
const parsed = parseSdnFlowHostCliArgs(argv);
|
|
111
|
+
const log = options.log ?? console.log.bind(console);
|
|
112
|
+
|
|
113
|
+
if (parsed.help) {
|
|
114
|
+
log(formatSdnFlowHostUsage());
|
|
115
|
+
return {
|
|
116
|
+
kind: "help",
|
|
117
|
+
args: parsed,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (!parsed.workspacePath) {
|
|
122
|
+
throw new Error("sdn-flow-host requires --workspace <workspace.json>.");
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const resolvedWorkspacePath = path.resolve(parsed.workspacePath);
|
|
126
|
+
const host = await (
|
|
127
|
+
options.startInstalledFlowAutoHost ?? startInstalledFlowAutoHost
|
|
128
|
+
)({
|
|
129
|
+
...options.startOptions,
|
|
130
|
+
workspacePath: resolvedWorkspacePath,
|
|
131
|
+
...(parsed.engine ? { engine: parsed.engine } : {}),
|
|
132
|
+
});
|
|
133
|
+
const summary = summarizeStartedHost(host);
|
|
134
|
+
|
|
135
|
+
if (options.quiet !== true) {
|
|
136
|
+
log(
|
|
137
|
+
`Started ${summary.workspaceId ?? "installed-flow workspace"} (${summary.engine ?? "unknown"}) from ${resolvedWorkspacePath}${
|
|
138
|
+
summary.listenerCount > 0
|
|
139
|
+
? ` with ${summary.listenerCount} listener${summary.listenerCount === 1 ? "" : "s"}`
|
|
140
|
+
: ""
|
|
141
|
+
}.`,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
installShutdownHooks(host, options);
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
kind: "started",
|
|
149
|
+
args: {
|
|
150
|
+
...parsed,
|
|
151
|
+
workspacePath: resolvedWorkspacePath,
|
|
152
|
+
},
|
|
153
|
+
host,
|
|
154
|
+
summary,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (import.meta.main) {
|
|
159
|
+
try {
|
|
160
|
+
await runSdnFlowHostCli();
|
|
161
|
+
} catch (error) {
|
|
162
|
+
console.error(
|
|
163
|
+
typeof error?.message === "string" ? error.message : String(error),
|
|
164
|
+
);
|
|
165
|
+
console.error("");
|
|
166
|
+
console.error(formatSdnFlowHostUsage());
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
169
|
+
}
|
package/docs/.nojekyll
ADDED
|
File without changes
|