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,200 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
## Package Boundary
|
|
4
|
+
|
|
5
|
+
`sdn-flow` is the portable layer between:
|
|
6
|
+
|
|
7
|
+
- UI flow authoring
|
|
8
|
+
- host-side runtime execution
|
|
9
|
+
- signed artifact dependency resolution
|
|
10
|
+
- generated C++ bundle compilation
|
|
11
|
+
- deployment authorization
|
|
12
|
+
- deployment transport
|
|
13
|
+
|
|
14
|
+
It is intentionally host-agnostic so different applications and runtimes can
|
|
15
|
+
consume the same contracts.
|
|
16
|
+
|
|
17
|
+
## Core Rule
|
|
18
|
+
|
|
19
|
+
A deployable flow is a compiled single WASM runtime artifact.
|
|
20
|
+
|
|
21
|
+
The source graph exists for authoring, validation, tracing, and compilation.
|
|
22
|
+
It is not the deployable unit.
|
|
23
|
+
There is no separate interpreted deployment engine.
|
|
24
|
+
There is no JS source generator on the deploy path; source synthesis happens in
|
|
25
|
+
a native C++ generator compiled to WASM.
|
|
26
|
+
|
|
27
|
+
## Single Plugin Rule
|
|
28
|
+
|
|
29
|
+
A single plugin invocation is modeled as a one-node flow with optional triggers
|
|
30
|
+
and zero or more sinks. There is no separate deployment path for "just a
|
|
31
|
+
plugin."
|
|
32
|
+
|
|
33
|
+
## Package Layers
|
|
34
|
+
|
|
35
|
+
### Runtime Contracts
|
|
36
|
+
|
|
37
|
+
The runtime layer defines normalized manifest/program objects used by authoring,
|
|
38
|
+
validation, and host integration:
|
|
39
|
+
|
|
40
|
+
- plugin manifests declare methods, ports, stream limits, and drain policies
|
|
41
|
+
- flow programs declare nodes, edges, triggers, and trigger bindings
|
|
42
|
+
- deployed execution lives in the generated C++ runtime, not in package JS
|
|
43
|
+
|
|
44
|
+
### Designer
|
|
45
|
+
|
|
46
|
+
The designer layer is UI-facing but DOM-free. It owns:
|
|
47
|
+
|
|
48
|
+
- graph mutation helpers
|
|
49
|
+
- external input/output and capability summaries for visual editors
|
|
50
|
+
- single-plugin flow creation
|
|
51
|
+
- compile orchestration through an injected compiler adapter
|
|
52
|
+
- deployment orchestration through an injected deployment client
|
|
53
|
+
|
|
54
|
+
### Host Planning
|
|
55
|
+
|
|
56
|
+
The host-planning layer owns portable hosted-runtime description:
|
|
57
|
+
|
|
58
|
+
- runtime kind (`flow`, `plugin`, `service`)
|
|
59
|
+
- startup phase (`bootstrap`, `early`, `session`, `on-demand`)
|
|
60
|
+
- local vs remote authority
|
|
61
|
+
- runtime dependencies
|
|
62
|
+
- transport bindings (`same-app`, `direct`, `webrtc`, `sdn-protocol`, `http`)
|
|
63
|
+
|
|
64
|
+
This keeps startup-only services such as local licensing in the same runtime
|
|
65
|
+
model as any other flow/plugin deployment.
|
|
66
|
+
|
|
67
|
+
See also:
|
|
68
|
+
|
|
69
|
+
- [Host Capability Model](./HOST_CAPABILITY_MODEL.md)
|
|
70
|
+
|
|
71
|
+
### Compiler
|
|
72
|
+
|
|
73
|
+
The compiler layer owns:
|
|
74
|
+
|
|
75
|
+
- signed artifact catalog resolution
|
|
76
|
+
- single-source C++ runtime generation
|
|
77
|
+
- native C++ source-generator tool compilation and invocation
|
|
78
|
+
- `emception`-compatible compile planning
|
|
79
|
+
- artifact assembly back into the deploy contract
|
|
80
|
+
|
|
81
|
+
### Authorization
|
|
82
|
+
|
|
83
|
+
Deployment permissions are explicit signed envelopes, designed for SDN HD-wallet
|
|
84
|
+
signatures.
|
|
85
|
+
|
|
86
|
+
The package defines:
|
|
87
|
+
|
|
88
|
+
- canonical payload encoding
|
|
89
|
+
- deploy authorization payload shape
|
|
90
|
+
- signer and verifier contracts
|
|
91
|
+
- scope checks against target, artifact, and required capabilities
|
|
92
|
+
|
|
93
|
+
### Transport
|
|
94
|
+
|
|
95
|
+
Remote deployment payloads may be encrypted with PKI. The transport layer
|
|
96
|
+
provides:
|
|
97
|
+
|
|
98
|
+
- X25519 ephemeral key agreement
|
|
99
|
+
- HKDF-derived AES-256-GCM content encryption
|
|
100
|
+
- JSON payload helpers for deployment envelopes
|
|
101
|
+
|
|
102
|
+
### Deploy
|
|
103
|
+
|
|
104
|
+
The deploy layer only ships compiled artifacts. It does not accept raw flow
|
|
105
|
+
graphs as the deployment boundary.
|
|
106
|
+
|
|
107
|
+
## Artifact Contract
|
|
108
|
+
|
|
109
|
+
A compiled flow artifact contains:
|
|
110
|
+
|
|
111
|
+
- `artifactId`
|
|
112
|
+
- `programId`
|
|
113
|
+
- `format`
|
|
114
|
+
- `wasm`
|
|
115
|
+
- `manifestBuffer`
|
|
116
|
+
- `manifestExports.bytesSymbol`
|
|
117
|
+
- `manifestExports.sizeSymbol`
|
|
118
|
+
- `entrypoint`
|
|
119
|
+
- `graphHash`
|
|
120
|
+
- `requiredCapabilities`
|
|
121
|
+
- `pluginVersions`
|
|
122
|
+
- `schemaBindings`
|
|
123
|
+
- `abiVersion`
|
|
124
|
+
|
|
125
|
+
The compile plan that produces that artifact may also include:
|
|
126
|
+
|
|
127
|
+
- generator request bytes consumed by the native generator WASM tool
|
|
128
|
+
- generated `main.cpp`
|
|
129
|
+
- generated runtime topology descriptors and mutable node-state storage
|
|
130
|
+
- signed plugin artifact dependency descriptors
|
|
131
|
+
- signed plugin manifest bytes
|
|
132
|
+
- the exact `em++` command issued to `emception`
|
|
133
|
+
|
|
134
|
+
## Editor And Capability Model
|
|
135
|
+
|
|
136
|
+
Programs may declare:
|
|
137
|
+
|
|
138
|
+
- `externalInterfaces`
|
|
139
|
+
- `artifactDependencies`
|
|
140
|
+
- `editor` layout metadata
|
|
141
|
+
|
|
142
|
+
Plugin manifests may declare:
|
|
143
|
+
|
|
144
|
+
- `capabilities`
|
|
145
|
+
- `externalInterfaces`
|
|
146
|
+
|
|
147
|
+
The designer layer can merge those declarations with trigger bindings and
|
|
148
|
+
resolved plugin manifests so the operator can see:
|
|
149
|
+
|
|
150
|
+
- which network, timer, protocol, filesystem, and database bindings are needed
|
|
151
|
+
- which capabilities must be approved and signed
|
|
152
|
+
- which signed plugin artifacts must exist before compilation
|
|
153
|
+
|
|
154
|
+
## Host Integration
|
|
155
|
+
|
|
156
|
+
Hosts are expected to provide adapters for:
|
|
157
|
+
|
|
158
|
+
- graph validation against host capabilities
|
|
159
|
+
- manifest building into canonical FlatBuffer bytes
|
|
160
|
+
- invoking the native C++ source generator tool
|
|
161
|
+
- compilation via `emception` or equivalent
|
|
162
|
+
- local deployment/install
|
|
163
|
+
- remote deployment endpoint verification and installation
|
|
164
|
+
- protocol/pubsub registration and network transport
|
|
165
|
+
|
|
166
|
+
Hosts may also use the portable host-planning surface to describe early-start
|
|
167
|
+
services, same-app loopback bindings, or WebRTC-connected local runtimes
|
|
168
|
+
without changing the flow/plugin ABI.
|
|
169
|
+
|
|
170
|
+
Capability gaps must be documented at the host-profile level. Do not solve a
|
|
171
|
+
missing runtime capability by inventing a second deploy/runtime model.
|
|
172
|
+
|
|
173
|
+
This package deliberately leaves those host integrations outside the portable
|
|
174
|
+
core.
|
|
175
|
+
|
|
176
|
+
## Manifest Rule
|
|
177
|
+
|
|
178
|
+
Every plugin and every compiled flow artifact must embed a FlatBuffer manifest
|
|
179
|
+
buffer and expose a callable export for it. The default flow export names are:
|
|
180
|
+
|
|
181
|
+
- `flow_get_manifest_flatbuffer`
|
|
182
|
+
- `flow_get_manifest_flatbuffer_size`
|
|
183
|
+
|
|
184
|
+
The default plugin export names are:
|
|
185
|
+
|
|
186
|
+
- `plugin_get_manifest_flatbuffer`
|
|
187
|
+
- `plugin_get_manifest_flatbuffer_size`
|
|
188
|
+
|
|
189
|
+
## Example
|
|
190
|
+
|
|
191
|
+
The repo includes a concrete example in
|
|
192
|
+
[examples/flows/iss-proximity-oem/flow.json](../examples/flows/iss-proximity-oem/flow.json)
|
|
193
|
+
that:
|
|
194
|
+
|
|
195
|
+
- streams OMMs from SDN pubsub
|
|
196
|
+
- ingests them into a FlatSQL storage plugin
|
|
197
|
+
- queries objects within `50 km` of object `25544`
|
|
198
|
+
- propagates `90` samples for one orbit
|
|
199
|
+
- generates OEMs
|
|
200
|
+
- writes and republishes those OEMs through explicit sink nodes
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
# Host Capability Model
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
This document defines how compiled `sdn-flow` runtimes consume the canonical
|
|
6
|
+
module-level host capability model from `space-data-module-sdk` and project it
|
|
7
|
+
onto flow-level runtime artifacts.
|
|
8
|
+
|
|
9
|
+
The canonical module-facing capability vocabulary, module-facing hostcall ABI,
|
|
10
|
+
and single-module conformance rules live in `space-data-module-sdk`.
|
|
11
|
+
This document focuses on how `sdn-flow` composes those module contracts into
|
|
12
|
+
compiled flow runtimes.
|
|
13
|
+
|
|
14
|
+
The goal is to keep one runtime model across OrbPro, `sdn-js`, Go SDN, and
|
|
15
|
+
WASI-style hosts without creating a different flow runtime model or a different
|
|
16
|
+
deploy shape for each environment.
|
|
17
|
+
|
|
18
|
+
## Hard Rules
|
|
19
|
+
|
|
20
|
+
1. Every deployable unit is one compiled WASM runtime artifact.
|
|
21
|
+
2. Every module is a flow. A "single plugin" is a degenerate one-node flow,
|
|
22
|
+
but its standalone artifact contract still comes from `space-data-module-sdk`.
|
|
23
|
+
3. Hosts provide capabilities and placement, not business logic.
|
|
24
|
+
4. Capability requirements must be explicit in manifests, flow programs,
|
|
25
|
+
hosted-runtime plans, or deployment envelopes. Do not hide them in ad hoc
|
|
26
|
+
host config or implicit imports.
|
|
27
|
+
5. Use the minimum host-adapter set needed to cover environment families.
|
|
28
|
+
Do not add a new harness just because one runtime exposes a feature
|
|
29
|
+
differently.
|
|
30
|
+
6. Generic "WASI" is not a sufficient capability claim. If a flow needs more
|
|
31
|
+
than the portable baseline, the required host profile and imports must be
|
|
32
|
+
documented explicitly.
|
|
33
|
+
7. If there is no compiled-host path for a required feature in a target
|
|
34
|
+
environment, treat that as a release-blocking alert. Do not paper over it
|
|
35
|
+
with loose JS wrappers, host cron jobs, or sidecar-only glue.
|
|
36
|
+
|
|
37
|
+
## Capability Declaration Surfaces
|
|
38
|
+
|
|
39
|
+
Use the surfaces below together. They solve different problems.
|
|
40
|
+
|
|
41
|
+
| Surface | Purpose | Example |
|
|
42
|
+
| ----------------------------------------------- | ------------------------------------------ | ------------------------------------------------- |
|
|
43
|
+
| `manifest.capabilities` | coarse approval/signing scope | `["timers", "http", "storage_write"]` |
|
|
44
|
+
| `manifest.externalInterfaces` | concrete plugin-level bindings | outbound HTTP, FlatSQL adapter, filesystem path |
|
|
45
|
+
| `program.externalInterfaces` | flow-level bindings beyond a single plugin | shared HTTPS listener, shared pubsub topic |
|
|
46
|
+
| `program.triggers` | trigger ownership | timer, protocol request, HTTP request |
|
|
47
|
+
| hosted-runtime plan `requiredCapabilities` | runtime placement/startup requirements | early local service needs `protocol_handle` |
|
|
48
|
+
| deployment authorization `requiredCapabilities` | signed approval at deploy time | remote install allowed to use `pubsub` and `ipfs` |
|
|
49
|
+
|
|
50
|
+
Keep capability IDs coarse and stable. Put transport-specific details in the
|
|
51
|
+
interface object, not in a proliferating list of near-duplicate capability
|
|
52
|
+
strings.
|
|
53
|
+
|
|
54
|
+
## Canonical Capability Guidance
|
|
55
|
+
|
|
56
|
+
Recommended coarse capability IDs:
|
|
57
|
+
|
|
58
|
+
- `clock`
|
|
59
|
+
- `random`
|
|
60
|
+
- `timers`
|
|
61
|
+
- `http`
|
|
62
|
+
- `network`
|
|
63
|
+
- `filesystem`
|
|
64
|
+
- `pipe`
|
|
65
|
+
- `pubsub`
|
|
66
|
+
- `protocol_handle`
|
|
67
|
+
- `protocol_dial`
|
|
68
|
+
- `database`
|
|
69
|
+
- `storage_adapter`
|
|
70
|
+
- `storage_query`
|
|
71
|
+
- `storage_write`
|
|
72
|
+
- `wallet_sign`
|
|
73
|
+
- `ipfs`
|
|
74
|
+
- `scene_access`
|
|
75
|
+
- `render_hooks`
|
|
76
|
+
|
|
77
|
+
Guidance:
|
|
78
|
+
|
|
79
|
+
- Use `network` for raw sockets, TCP, UDP, QUIC, or similar transport access.
|
|
80
|
+
- Use `http` for HTTP client/server semantics instead of encoding HTTP as a
|
|
81
|
+
special case of raw sockets.
|
|
82
|
+
- Use `filesystem` for path-backed storage and `database` for logical database
|
|
83
|
+
interfaces such as FlatSQL.
|
|
84
|
+
- Use `pipe` for stdin/stdout/stderr, named pipes, or stream-style host I/O.
|
|
85
|
+
- Keep `ipfs` coarse. Pinning, block get/put, and publish behavior belong in
|
|
86
|
+
interface metadata.
|
|
87
|
+
- Compute-only infrastructure plugins such as DA FlatBuffers usually need no
|
|
88
|
+
host capability at all. `hd-wallet-wasm` style plugins should only declare
|
|
89
|
+
host capabilities such as `random` or `wallet_sign` when they genuinely need
|
|
90
|
+
host-provided entropy or resident key material.
|
|
91
|
+
|
|
92
|
+
## External Interface Patterns
|
|
93
|
+
|
|
94
|
+
External interfaces carry the precise runtime binding details. Keep the
|
|
95
|
+
interface kinds small and use `properties` for specialization.
|
|
96
|
+
|
|
97
|
+
### Timer / Clock / Randomness
|
|
98
|
+
|
|
99
|
+
- Timers normally enter through `program.triggers`.
|
|
100
|
+
- If a plugin needs direct time or entropy outside trigger scheduling, declare
|
|
101
|
+
`clock` and `random` capabilities explicitly.
|
|
102
|
+
- Do not let native code silently reach into browser globals or host globals.
|
|
103
|
+
Entropy and time should enter through explicit host capabilities.
|
|
104
|
+
|
|
105
|
+
### HTTP
|
|
106
|
+
|
|
107
|
+
Use `kind: "http"` for both outbound requests and inbound handlers.
|
|
108
|
+
|
|
109
|
+
Example:
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"interfaceId": "celestrak-fetch",
|
|
114
|
+
"kind": "http",
|
|
115
|
+
"direction": "output",
|
|
116
|
+
"capability": "http",
|
|
117
|
+
"resource": "https://celestrak.org",
|
|
118
|
+
"required": true,
|
|
119
|
+
"properties": {
|
|
120
|
+
"methods": ["GET"],
|
|
121
|
+
"purpose": "Fetch OMM updates"
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Raw Network / TCP / UDP
|
|
127
|
+
|
|
128
|
+
Use `kind: "network"` and put socket details in `properties`.
|
|
129
|
+
|
|
130
|
+
Example:
|
|
131
|
+
|
|
132
|
+
```json
|
|
133
|
+
{
|
|
134
|
+
"interfaceId": "udp-observation-ingest",
|
|
135
|
+
"kind": "network",
|
|
136
|
+
"direction": "input",
|
|
137
|
+
"capability": "network",
|
|
138
|
+
"resource": "udp://0.0.0.0:40123",
|
|
139
|
+
"required": true,
|
|
140
|
+
"properties": {
|
|
141
|
+
"transport": "udp",
|
|
142
|
+
"mode": "listen"
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
This avoids separate ABIs for TCP, UDP, raw sockets, and runtime-specific
|
|
148
|
+
socket APIs.
|
|
149
|
+
|
|
150
|
+
### Filesystem / Pipes
|
|
151
|
+
|
|
152
|
+
Use `kind: "filesystem"` for path-backed files and `kind: "pipe"` for stream
|
|
153
|
+
or pipe semantics.
|
|
154
|
+
|
|
155
|
+
Example:
|
|
156
|
+
|
|
157
|
+
```json
|
|
158
|
+
{
|
|
159
|
+
"interfaceId": "oem-export-dir",
|
|
160
|
+
"kind": "filesystem",
|
|
161
|
+
"direction": "output",
|
|
162
|
+
"capability": "filesystem",
|
|
163
|
+
"resource": "file:///var/lib/sdn/oem",
|
|
164
|
+
"required": true,
|
|
165
|
+
"properties": {
|
|
166
|
+
"access": "read-write"
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
```json
|
|
172
|
+
{
|
|
173
|
+
"interfaceId": "stderr-log",
|
|
174
|
+
"kind": "pipe",
|
|
175
|
+
"direction": "output",
|
|
176
|
+
"capability": "pipe",
|
|
177
|
+
"resource": "stderr",
|
|
178
|
+
"required": false
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Database / FlatSQL
|
|
183
|
+
|
|
184
|
+
Storage engines remain plugins or explicit host services, not hidden host
|
|
185
|
+
subsystems.
|
|
186
|
+
|
|
187
|
+
- Use `kind: "database"` for the logical database surface seen by the flow.
|
|
188
|
+
- Use `kind: "host-service"` when the flow needs a host-provided storage
|
|
189
|
+
adapter contract.
|
|
190
|
+
|
|
191
|
+
### IPFS / SDS Protocol / Other Services
|
|
192
|
+
|
|
193
|
+
If a function is logically a networked platform service rather than a raw
|
|
194
|
+
socket, prefer `kind: "host-service"`, `kind: "protocol"`, or `kind: "pubsub"`
|
|
195
|
+
plus explicit `resource`, `protocolId`, `topic`, or `properties`.
|
|
196
|
+
|
|
197
|
+
Examples:
|
|
198
|
+
|
|
199
|
+
- IPFS pinning service
|
|
200
|
+
- SDS PNM notification channel
|
|
201
|
+
- local orbit-determination service runtime
|
|
202
|
+
- same-app licensing runtime
|
|
203
|
+
|
|
204
|
+
## Environment Profiles
|
|
205
|
+
|
|
206
|
+
The canonical model is shared, but capability availability differs by host
|
|
207
|
+
profile. Document the profile. Do not claim "runs anywhere" unless it is true
|
|
208
|
+
for the declared interfaces.
|
|
209
|
+
|
|
210
|
+
### OrbPro Browser Host
|
|
211
|
+
|
|
212
|
+
Portable expectations:
|
|
213
|
+
|
|
214
|
+
- `clock`, `random`, `timers`
|
|
215
|
+
- outbound HTTP
|
|
216
|
+
- same-app bindings
|
|
217
|
+
- browser-managed storage surfaces
|
|
218
|
+
- scene/render integration
|
|
219
|
+
- `sdn-js` protocol/pubsub integration when configured
|
|
220
|
+
|
|
221
|
+
Non-portable or unavailable by default:
|
|
222
|
+
|
|
223
|
+
- raw TCP/UDP sockets
|
|
224
|
+
- arbitrary listen sockets
|
|
225
|
+
- unrestricted filesystem access
|
|
226
|
+
- OS pipes
|
|
227
|
+
|
|
228
|
+
If a flow needs those features, place that runtime in a different host profile
|
|
229
|
+
instead of pretending the browser host can satisfy them.
|
|
230
|
+
|
|
231
|
+
### Node / Deno / Bun Through The `sdn-js` Host Family
|
|
232
|
+
|
|
233
|
+
Expected direction:
|
|
234
|
+
|
|
235
|
+
- keep one `sdn-js` host family for browser-capable and JS-capable runtimes
|
|
236
|
+
- expose files, pipes, outbound HTTP, protocol/pubsub, IPFS, and local
|
|
237
|
+
listeners through the same capability model
|
|
238
|
+
- document unsupported features per runtime instead of creating a new plugin
|
|
239
|
+
ABI for each JS engine
|
|
240
|
+
|
|
241
|
+
If one engine cannot provide a capability in compiled-host form, mark that
|
|
242
|
+
capability unsupported for that profile.
|
|
243
|
+
|
|
244
|
+
### Go SDN Host
|
|
245
|
+
|
|
246
|
+
This is the preferred profile for long-running service flows such as:
|
|
247
|
+
|
|
248
|
+
- timer-triggered OMM sync
|
|
249
|
+
- FlatSQL-backed local storage
|
|
250
|
+
- HTTPS serving
|
|
251
|
+
- IPFS publish and pin
|
|
252
|
+
- SDS protocol notifications
|
|
253
|
+
- local orbit determination and association jobs
|
|
254
|
+
|
|
255
|
+
The flow still deploys as one compiled WASM artifact. The Go host supplies the
|
|
256
|
+
bindings.
|
|
257
|
+
|
|
258
|
+
### Generic WASI Runtime
|
|
259
|
+
|
|
260
|
+
Treat generic WASI as a narrow portability baseline only.
|
|
261
|
+
|
|
262
|
+
Portable assumptions:
|
|
263
|
+
|
|
264
|
+
- startup entrypoint
|
|
265
|
+
- stdio-like behavior
|
|
266
|
+
- linear memory/exported symbol access
|
|
267
|
+
- whatever explicit imported host functions the host provides
|
|
268
|
+
|
|
269
|
+
Do not assume from "WASI" alone:
|
|
270
|
+
|
|
271
|
+
- outbound HTTP
|
|
272
|
+
- sockets
|
|
273
|
+
- persistent filesystem semantics
|
|
274
|
+
- timers beyond what the host explicitly exposes
|
|
275
|
+
- pubsub, protocol, IPFS, or database services
|
|
276
|
+
|
|
277
|
+
### WasmEdge / Wasmtime / Wasmer / Wazero
|
|
278
|
+
|
|
279
|
+
Vendor or runtime extensions may be used, but they do not change the canonical
|
|
280
|
+
flow ABI.
|
|
281
|
+
|
|
282
|
+
Rules:
|
|
283
|
+
|
|
284
|
+
- declare the same capability IDs and interface shapes
|
|
285
|
+
- document the exact host profile or extension required
|
|
286
|
+
- do not describe the result as generic-WASI portable unless the same compiled
|
|
287
|
+
contract is actually supported elsewhere
|
|
288
|
+
|
|
289
|
+
## Alert Conditions
|
|
290
|
+
|
|
291
|
+
Treat these as architecture failures:
|
|
292
|
+
|
|
293
|
+
- a host-side cron job driving loose plugin calls instead of a timer trigger
|
|
294
|
+
- JSON moving between compiled plugins on flow edges
|
|
295
|
+
- separate deployment of "scheduler" and "plugins" as different runtime models
|
|
296
|
+
- a browser-only JS implementation and a different Go/WASI implementation for
|
|
297
|
+
the same canonical feature
|
|
298
|
+
- a claim that a module runs on "any WASI runtime" when it actually needs
|
|
299
|
+
custom imports or a vendor extension
|
|
300
|
+
- sidecar metadata or sidecar policy as the only source of runtime truth
|
|
301
|
+
|
|
302
|
+
## Example Deployment Shape
|
|
303
|
+
|
|
304
|
+
The following workload is valid in the canonical model:
|
|
305
|
+
|
|
306
|
+
1. A timer-triggered flow wakes on a declared interval.
|
|
307
|
+
2. It fetches OMMs from CelesTrak over an explicit HTTP interface.
|
|
308
|
+
3. It writes aligned records through a FlatSQL storage plugin/runtime.
|
|
309
|
+
4. It exposes a declared HTTPS interface for download.
|
|
310
|
+
5. It publishes content to IPFS and requests pinning through declared host
|
|
311
|
+
services.
|
|
312
|
+
6. It notifies peer SDN nodes over a declared SDS protocol binding.
|
|
313
|
+
7. It kicks off downstream association and orbit-analysis nodes.
|
|
314
|
+
|
|
315
|
+
This still compiles to one signed deployable WASM artifact. Local and remote
|
|
316
|
+
deployment may wrap that artifact in the same signed and optionally encrypted
|
|
317
|
+
deployment envelope.
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Plugin Architecture
|
|
2
|
+
|
|
3
|
+
## Scope
|
|
4
|
+
|
|
5
|
+
This document defines how `sdn-flow` consumes the standalone plugin
|
|
6
|
+
architecture sourced from `space-data-module-sdk`.
|
|
7
|
+
|
|
8
|
+
It covers:
|
|
9
|
+
|
|
10
|
+
- plugin identity and manifest rules
|
|
11
|
+
- streaming method contracts
|
|
12
|
+
- external interface declarations
|
|
13
|
+
- callable manifest exports
|
|
14
|
+
- the relationship between plugins and flows
|
|
15
|
+
- local and remote deployment expectations
|
|
16
|
+
|
|
17
|
+
## Core Rule
|
|
18
|
+
|
|
19
|
+
The runtime does not distinguish between "a plugin" and "a flow" at deployment
|
|
20
|
+
time. A single plugin invocation is a one-node flow.
|
|
21
|
+
|
|
22
|
+
That means:
|
|
23
|
+
|
|
24
|
+
- single-plugin execution uses the same deploy model as multi-node graphs
|
|
25
|
+
- compiled deployment is always one WASM runtime artifact
|
|
26
|
+
- trigger, queueing, and drain semantics stay uniform
|
|
27
|
+
|
|
28
|
+
## Plugin Contract
|
|
29
|
+
|
|
30
|
+
Every plugin participates in the flow system through a manifest-defined method
|
|
31
|
+
surface.
|
|
32
|
+
|
|
33
|
+
A method declares:
|
|
34
|
+
|
|
35
|
+
- stable `methodId`
|
|
36
|
+
- one or more input ports
|
|
37
|
+
- zero or more output ports
|
|
38
|
+
- accepted schema sets per port
|
|
39
|
+
- stream-count limits
|
|
40
|
+
- `maxBatch`
|
|
41
|
+
- `drainPolicy`
|
|
42
|
+
|
|
43
|
+
Methods are invoked over schema-tagged frame streams, not ad hoc JSON payloads.
|
|
44
|
+
|
|
45
|
+
Plugins may also declare `externalInterfaces` so visual editors and deployment
|
|
46
|
+
tooling can show the real network, protocol, filesystem, database, or host
|
|
47
|
+
service bindings required to make the graph run.
|
|
48
|
+
|
|
49
|
+
Keep capability IDs coarse and portable. Use interface metadata to capture
|
|
50
|
+
runtime-specific details such as:
|
|
51
|
+
|
|
52
|
+
- HTTP method sets
|
|
53
|
+
- TCP/UDP/raw-socket transport mode
|
|
54
|
+
- filesystem sandbox or mount location
|
|
55
|
+
- pipe or stream direction
|
|
56
|
+
- IPFS or SDS service operation
|
|
57
|
+
|
|
58
|
+
Storage engines follow the same rule. A FlatSQL database should be represented
|
|
59
|
+
as a storage plugin/runtime that:
|
|
60
|
+
|
|
61
|
+
- ingests aligned FlatBuffer records
|
|
62
|
+
- exposes query methods
|
|
63
|
+
- declares whether it is backed by transient memory or a host-provided storage
|
|
64
|
+
adapter
|
|
65
|
+
|
|
66
|
+
The host should not hide a second engine-owned SQL source of truth behind that
|
|
67
|
+
plugin surface.
|
|
68
|
+
|
|
69
|
+
Infrastructure libraries follow the same rule. If a deployable flow depends on
|
|
70
|
+
`hd-wallet-wasm`, DA FlatBuffers, or similar runtime libraries for signing,
|
|
71
|
+
envelope encryption, field-level encryption, schema transforms, or repacking,
|
|
72
|
+
those surfaces should appear as normal manifest-defined plugins. Do not hide
|
|
73
|
+
them behind host-only helper code.
|
|
74
|
+
|
|
75
|
+
For the canonical host capability rules and environment profiles, see:
|
|
76
|
+
|
|
77
|
+
- [Host Capability Model](./HOST_CAPABILITY_MODEL.md)
|
|
78
|
+
|
|
79
|
+
## Manifest Rule
|
|
80
|
+
|
|
81
|
+
Every plugin must embed a FlatBuffer manifest buffer and expose callable exports
|
|
82
|
+
for it.
|
|
83
|
+
|
|
84
|
+
Default export names:
|
|
85
|
+
|
|
86
|
+
- `plugin_get_manifest_flatbuffer`
|
|
87
|
+
- `plugin_get_manifest_flatbuffer_size`
|
|
88
|
+
|
|
89
|
+
Compiled flow artifacts follow the same rule with flow-scoped export names:
|
|
90
|
+
|
|
91
|
+
- `flow_get_manifest_flatbuffer`
|
|
92
|
+
- `flow_get_manifest_flatbuffer_size`
|
|
93
|
+
|
|
94
|
+
The manifest is part of the runtime contract. Sidecar metadata files are not
|
|
95
|
+
sufficient for deployable artifacts.
|
|
96
|
+
|
|
97
|
+
## Streaming Model
|
|
98
|
+
|
|
99
|
+
Each input port accepts one or more streams of schema-tagged frames.
|
|
100
|
+
|
|
101
|
+
Each frame carries runtime type identity:
|
|
102
|
+
|
|
103
|
+
- `schemaName`
|
|
104
|
+
- `fileIdentifier`
|
|
105
|
+
- optional `schemaHash`
|
|
106
|
+
- `streamId`
|
|
107
|
+
- `sequence`
|
|
108
|
+
- `traceId`
|
|
109
|
+
|
|
110
|
+
If a method only processes one frame per invocation, the runtime keeps invoking
|
|
111
|
+
it until the backlog is drained or the scheduler yields.
|
|
112
|
+
|
|
113
|
+
## Plugin Families
|
|
114
|
+
|
|
115
|
+
`sdn-flow` does not hardcode host-specific plugin classes. Common families
|
|
116
|
+
include:
|
|
117
|
+
|
|
118
|
+
- propagators
|
|
119
|
+
- sensors
|
|
120
|
+
- analyzers
|
|
121
|
+
- publishers
|
|
122
|
+
- responders
|
|
123
|
+
- infrastructure plugins
|
|
124
|
+
|
|
125
|
+
Examples of infrastructure plugins include FlatSQL storage, `hd-wallet-wasm`
|
|
126
|
+
sign/encrypt nodes, and DA FlatBuffers schema/field transform nodes.
|
|
127
|
+
|
|
128
|
+
All of them enter the runtime through the same manifest + method contract.
|
|
129
|
+
|
|
130
|
+
## Host Boundary
|
|
131
|
+
|
|
132
|
+
Hosts are responsible for:
|
|
133
|
+
|
|
134
|
+
- manifest decoding
|
|
135
|
+
- plugin loading and registration
|
|
136
|
+
- capability enforcement
|
|
137
|
+
- editor integration for external interface inspection and approval
|
|
138
|
+
- compilation of flow graphs into deployable WASM artifacts
|
|
139
|
+
- installation and execution of those artifacts
|
|
140
|
+
|
|
141
|
+
`sdn-flow` owns the portable runtime and deployment model, not host-specific
|
|
142
|
+
loading code.
|
|
143
|
+
|
|
144
|
+
Host-specific runtime differences must stay in capability bindings and hosted
|
|
145
|
+
runtime plans. They must not fork the plugin ABI.
|