space-data-module-sdk 0.8.12 → 0.8.13
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/bin/space-data-module.js +52 -0
- package/docs/module-publication-standard.md +7 -3
- package/docs/propagator-abi.md +477 -0
- package/include/orbpro/orbpro_propagator_abi.h +312 -0
- package/package.json +6 -1
- package/schemas/PluginManifest.fbs +46 -1
- package/schemas/orbpro/Propagator.fbs +161 -3
- package/src/bundle/index.js +1 -0
- package/src/bundle/sigdomain.js +22 -0
- package/src/capabilities.js +53 -1
- package/src/compliance/index.js +6 -0
- package/src/compliance/pluginCompliance.js +76 -16
- package/src/flow/flowCompiler.js +30 -14
- package/src/generated/orbpro/manifest/plugin-family.d.ts +9 -1
- package/src/generated/orbpro/manifest/plugin-family.js +8 -0
- package/src/generated/orbpro/manifest/plugin-family.ts +8 -0
- package/src/generated/orbpro/propagator-abi.js +118 -0
- package/src/generated/orbpro/propagator-abi.ts +199 -0
- package/src/manifest/normalize.js +113 -4
- package/src/scaffold/copyTemplate.js +71 -0
- package/src/scaffold/index.js +150 -0
- package/src/scaffold/tokens.js +90 -0
- package/templates/propagator-module/README.md +99 -0
- package/templates/propagator-module/build.js +103 -0
- package/templates/propagator-module/package.json +19 -0
- package/templates/propagator-module/plugin-manifest.json +66 -0
- package/templates/propagator-module/src/__MODULE_NAME_SNAKE__.cpp +450 -0
- package/templates/propagator-module/tests/module.build.test.mjs +103 -0
package/src/capabilities.js
CHANGED
|
@@ -77,12 +77,64 @@ export const BrowserIncompatibleCapabilityIds = Object.freeze([
|
|
|
77
77
|
"process_exec",
|
|
78
78
|
"wallet_sign",
|
|
79
79
|
"ipfs",
|
|
80
|
+
]);
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* ENGINE-HOSTED capabilities: the three that reach into a live 3D engine —
|
|
84
|
+
* its scene graph, its entity collection, its render loop.
|
|
85
|
+
*
|
|
86
|
+
* These used to sit in `BrowserIncompatibleCapabilityIds`, which was exactly
|
|
87
|
+
* backwards and produced a compliance paradox: they are also in
|
|
88
|
+
* `RecommendedCapabilityIds`, so a module was simultaneously told to declare
|
|
89
|
+
* them and refused for declaring them alongside the only runtime where they
|
|
90
|
+
* can possibly work. The flow compiler compounded it by unconditionally
|
|
91
|
+
* subtracting `browser` from any composed flow whose capability union touched
|
|
92
|
+
* one — meaning no flow that needs the engine could ever target the runtime
|
|
93
|
+
* the engine lives in.
|
|
94
|
+
*
|
|
95
|
+
* The truth, established by sweep:
|
|
96
|
+
* - The ONE implementation of `scene_access` in the stack is OrbPro's
|
|
97
|
+
* `ProviderAccessPort` + the SDK's `providerAccessEngineAdapter`, both of
|
|
98
|
+
* which require a live Cesium/OrbPro `Scene`. That is a BROWSER object.
|
|
99
|
+
* - `NodeHostSupportedCapabilities` contains none of the three, and
|
|
100
|
+
* `assertCapability()` fails them closed with `host-capability-unsupported`.
|
|
101
|
+
* - `entity_access` and `render_hooks` have no serving implementation on any
|
|
102
|
+
* runtime yet — only manifest-vocabulary codec entries. They are declared
|
|
103
|
+
* engine-hosted here because that is where they can ever be served, not
|
|
104
|
+
* because they are wired today.
|
|
105
|
+
*
|
|
106
|
+
* So they are wasmedge-incompatible, not browser-incompatible. (The `wasi`
|
|
107
|
+
* portability baseline already refuses them via
|
|
108
|
+
* `StandaloneWasiCapabilityIds` — nothing outside that five-member subset is
|
|
109
|
+
* admitted to a standalone WASI artifact.)
|
|
110
|
+
*
|
|
111
|
+
* Ruling: graph/findings/official-harness-shapes.md §8.4
|
|
112
|
+
* Task: graph/tasks/harness-w0-immediate-fixes.md (W0.4)
|
|
113
|
+
*/
|
|
114
|
+
export const EngineHostedCapabilityIds = Object.freeze([
|
|
80
115
|
"scene_access",
|
|
81
116
|
"entity_access",
|
|
82
117
|
"render_hooks",
|
|
83
118
|
]);
|
|
84
119
|
|
|
85
|
-
/**
|
|
120
|
+
/**
|
|
121
|
+
* Capabilities the headless WasmEdge leg cannot serve. There is no scene, no
|
|
122
|
+
* entity collection and no render loop in a headless server runtime, and no
|
|
123
|
+
* adapter can invent one.
|
|
124
|
+
*/
|
|
125
|
+
export const WasmEdgeIncompatibleCapabilityIds = Object.freeze([
|
|
126
|
+
...EngineHostedCapabilityIds,
|
|
127
|
+
]);
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Which capabilities each runtime leg cannot serve.
|
|
131
|
+
*
|
|
132
|
+
* Consumed by `runtimeTargetGate.js` (load-time admission), the flow compiler's
|
|
133
|
+
* `collectFlowRuntimeTargets` (derived runtimeTargets), and
|
|
134
|
+
* `pluginCompliance.js` (publish-time declaration policy) — all three read
|
|
135
|
+
* THIS table, so a leg's policy is stated once.
|
|
136
|
+
*/
|
|
86
137
|
export const LegIncompatibleCapabilityIds = Object.freeze({
|
|
87
138
|
browser: BrowserIncompatibleCapabilityIds,
|
|
139
|
+
wasmedge: WasmEdgeIncompatibleCapabilityIds,
|
|
88
140
|
});
|
package/src/compliance/index.js
CHANGED
|
@@ -12,8 +12,11 @@ import {
|
|
|
12
12
|
} from "./pluginCompliance.js";
|
|
13
13
|
import {
|
|
14
14
|
BrowserIncompatibleCapabilityIds,
|
|
15
|
+
EngineHostedCapabilityIds,
|
|
16
|
+
LegIncompatibleCapabilityIds,
|
|
15
17
|
RecommendedCapabilityIds,
|
|
16
18
|
StandaloneWasiCapabilityIds,
|
|
19
|
+
WasmEdgeIncompatibleCapabilityIds,
|
|
17
20
|
} from "../capabilities.js";
|
|
18
21
|
import { validateManifestAgainstStandardsCatalog } from "../standards/index.js";
|
|
19
22
|
|
|
@@ -50,6 +53,9 @@ export async function validateArtifactWithStandards(options = {}) {
|
|
|
50
53
|
|
|
51
54
|
export {
|
|
52
55
|
BrowserIncompatibleCapabilityIds,
|
|
56
|
+
EngineHostedCapabilityIds,
|
|
57
|
+
LegIncompatibleCapabilityIds,
|
|
58
|
+
WasmEdgeIncompatibleCapabilityIds,
|
|
53
59
|
findManifestFiles,
|
|
54
60
|
getWasmExportNames,
|
|
55
61
|
getWasmExportNamesFromFile,
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
RuntimeTarget,
|
|
14
14
|
} from "../runtime/constants.js";
|
|
15
15
|
import {
|
|
16
|
-
|
|
16
|
+
LegIncompatibleCapabilityIds,
|
|
17
17
|
RecommendedCapabilityIds,
|
|
18
18
|
StandaloneWasiCapabilityIds,
|
|
19
19
|
} from "../capabilities.js";
|
|
@@ -26,6 +26,10 @@ import {
|
|
|
26
26
|
isPayloadSchemaHashValid,
|
|
27
27
|
payloadSchemaIdentitiesEqual,
|
|
28
28
|
} from "../manifest/typeRefs.js";
|
|
29
|
+
import {
|
|
30
|
+
PluginFamilyNames,
|
|
31
|
+
pluginFamilyByName,
|
|
32
|
+
} from "../manifest/normalize.js";
|
|
29
33
|
import { isLegacyWildcardPort } from "./legacyWildcardPorts.js";
|
|
30
34
|
import { SDS_MANIFEST_SECTION_NAME } from "../bundle/constants.js";
|
|
31
35
|
import {
|
|
@@ -50,7 +54,18 @@ const ExternalInterfaceDirectionSet = new Set(
|
|
|
50
54
|
const ExternalInterfaceKindSet = new Set(Object.values(ExternalInterfaceKind));
|
|
51
55
|
const ProtocolRoleSet = new Set(Object.values(ProtocolRole));
|
|
52
56
|
const ProtocolTransportKindSet = new Set(Object.values(ProtocolTransportKind));
|
|
53
|
-
|
|
57
|
+
// One entry per runtime leg that has a declaration policy, built from the
|
|
58
|
+
// single table in capabilities.js. This used to be a browser-only constant,
|
|
59
|
+
// which is why an engine-hosted capability could only ever be described as
|
|
60
|
+
// "not available in the browser" — the exact inverse of the truth.
|
|
61
|
+
const LegIncompatibleCapabilitySets = Object.freeze(
|
|
62
|
+
Object.fromEntries(
|
|
63
|
+
Object.entries(LegIncompatibleCapabilityIds).map(([leg, ids]) => [
|
|
64
|
+
leg,
|
|
65
|
+
new Set(ids),
|
|
66
|
+
]),
|
|
67
|
+
),
|
|
68
|
+
);
|
|
54
69
|
const StandaloneWasiProtocolTransportKindSet = new Set([
|
|
55
70
|
ProtocolTransportKind.WASI_PIPE,
|
|
56
71
|
]);
|
|
@@ -126,6 +141,45 @@ function validateStringField(issues, value, location, label) {
|
|
|
126
141
|
return true;
|
|
127
142
|
}
|
|
128
143
|
|
|
144
|
+
/**
|
|
145
|
+
* `pluginFamily` is an ENUM, not a free string.
|
|
146
|
+
*
|
|
147
|
+
* This used to be `validateStringField`, so any spelling passed compliance and
|
|
148
|
+
* `normalizePluginFamily` then silently coerced it to ANALYSIS — the two
|
|
149
|
+
* halves of the same defect. Compliance now enforces the same vocabulary the
|
|
150
|
+
* normalizer refuses on, so a bad family is caught at check time with the
|
|
151
|
+
* valid set named, instead of at load time as a mislabelled module.
|
|
152
|
+
*
|
|
153
|
+
* Ruling: graph/findings/official-harness-shapes.md §4.7 / §8.3
|
|
154
|
+
*/
|
|
155
|
+
function validatePluginFamilyField(issues, value, location) {
|
|
156
|
+
if (!isNonEmptyString(value)) {
|
|
157
|
+
pushIssue(
|
|
158
|
+
issues,
|
|
159
|
+
"error",
|
|
160
|
+
"missing-string",
|
|
161
|
+
"pluginFamily must be a non-empty string.",
|
|
162
|
+
location,
|
|
163
|
+
);
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
const normalized = value.trim().toLowerCase();
|
|
167
|
+
if (pluginFamilyByName[normalized] === undefined) {
|
|
168
|
+
pushIssue(
|
|
169
|
+
issues,
|
|
170
|
+
"error",
|
|
171
|
+
"unknown-plugin-family",
|
|
172
|
+
`pluginFamily "${value}" is not a member of the plugin family vocabulary. ` +
|
|
173
|
+
`Valid families: ${PluginFamilyNames.join(", ")}. ` +
|
|
174
|
+
`A new family is appended to schemas/PluginManifest.fbs (a projection ` +
|
|
175
|
+
`of the authoritative SDS pluginCategory), never invented in a manifest.`,
|
|
176
|
+
location,
|
|
177
|
+
);
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
|
|
129
183
|
function validateCapabilityEntry(capability, issues, location) {
|
|
130
184
|
if (isNonEmptyString(capability)) {
|
|
131
185
|
return capability;
|
|
@@ -1412,21 +1466,27 @@ function validateRuntimeTargets(runtimeTargets, declaredCapabilities, issues, so
|
|
|
1412
1466
|
);
|
|
1413
1467
|
}
|
|
1414
1468
|
}
|
|
1415
|
-
if (
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
for (const
|
|
1420
|
-
|
|
1469
|
+
if (Array.isArray(declaredCapabilities)) {
|
|
1470
|
+
// Check EVERY declared leg that has a policy, not just the browser. An
|
|
1471
|
+
// engine-hosted capability (scene_access/entity_access/render_hooks) is
|
|
1472
|
+
// browser-ONLY, so the conflict it can raise is against `wasmedge`.
|
|
1473
|
+
for (const target of seenTargets) {
|
|
1474
|
+
const incompatible = LegIncompatibleCapabilitySets[target];
|
|
1475
|
+
if (!incompatible) {
|
|
1421
1476
|
continue;
|
|
1422
1477
|
}
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1478
|
+
for (const capability of declaredCapabilities) {
|
|
1479
|
+
if (!incompatible.has(capability)) {
|
|
1480
|
+
continue;
|
|
1481
|
+
}
|
|
1482
|
+
pushIssue(
|
|
1483
|
+
issues,
|
|
1484
|
+
"error",
|
|
1485
|
+
"capability-runtime-conflict",
|
|
1486
|
+
`Capability "${capability}" is not available in the canonical ${target} runtime target.`,
|
|
1487
|
+
`${sourceName}.capabilities`,
|
|
1488
|
+
);
|
|
1489
|
+
}
|
|
1430
1490
|
}
|
|
1431
1491
|
}
|
|
1432
1492
|
}
|
|
@@ -1734,7 +1794,7 @@ export function validatePluginManifest(manifest, options = {}) {
|
|
|
1734
1794
|
validateStringField(issues, manifest.pluginId, `${sourceName}.pluginId`, "pluginId");
|
|
1735
1795
|
validateStringField(issues, manifest.name, `${sourceName}.name`, "name");
|
|
1736
1796
|
validateStringField(issues, manifest.version, `${sourceName}.version`, "version");
|
|
1737
|
-
|
|
1797
|
+
validatePluginFamilyField(issues, manifest.pluginFamily, `${sourceName}.pluginFamily`);
|
|
1738
1798
|
|
|
1739
1799
|
const rawDeclaredCapabilities = manifest.capabilities;
|
|
1740
1800
|
let declaredCapabilities = null;
|
package/src/flow/flowCompiler.js
CHANGED
|
@@ -56,7 +56,7 @@ import {
|
|
|
56
56
|
} from "../compiler/pthreadArtifactGuard.js";
|
|
57
57
|
import { resolveWasiThreadsToolchain } from "../compiler/wasiThreadsToolchain.js";
|
|
58
58
|
import {
|
|
59
|
-
|
|
59
|
+
LegIncompatibleCapabilityIds,
|
|
60
60
|
validateArtifactWithStandards,
|
|
61
61
|
validatePluginManifest,
|
|
62
62
|
} from "../compliance/index.js";
|
|
@@ -904,9 +904,19 @@ function collectComponentDependencies({ nodePluginIds, dependencies, issues, cap
|
|
|
904
904
|
return [...components.values()].sort((a, b) => a.pluginId.localeCompare(b.pluginId));
|
|
905
905
|
}
|
|
906
906
|
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
907
|
+
// Per-leg incompatibility, read from the ONE table in capabilities.js rather
|
|
908
|
+
// than a browser-only constant. An engine-hosted capability
|
|
909
|
+
// (scene_access/entity_access/render_hooks) is browser-ONLY, so the leg it
|
|
910
|
+
// narrows away is `wasmedge`; the old browser-only form could only ever
|
|
911
|
+
// subtract `browser`, which is how a flow that needs the engine ended up
|
|
912
|
+
// unable to target the runtime the engine lives in.
|
|
913
|
+
const LegIncompatibleCapabilitySets = Object.freeze(
|
|
914
|
+
Object.fromEntries(
|
|
915
|
+
Object.entries(LegIncompatibleCapabilityIds).map(([leg, ids]) => [
|
|
916
|
+
leg,
|
|
917
|
+
new Set(ids),
|
|
918
|
+
]),
|
|
919
|
+
),
|
|
910
920
|
);
|
|
911
921
|
|
|
912
922
|
function declaredRuntimeTargets(manifest) {
|
|
@@ -938,9 +948,11 @@ function declaredRuntimeTargets(manifest) {
|
|
|
938
948
|
* exactly that capability against a browser target. Deriving only from the
|
|
939
949
|
* declarations left the commonest manifest shape re-creating the original
|
|
940
950
|
* defect — the compiler stamping a target its own compliance pass then
|
|
941
|
-
* rejects. So
|
|
942
|
-
*
|
|
943
|
-
* capability that cost it.
|
|
951
|
+
* rejects. So a leg is also dropped whenever the flow's capability union meets
|
|
952
|
+
* that leg's entry in `LegIncompatibleCapabilityIds`, and the diagnostic names
|
|
953
|
+
* the capability that cost it. That table is per-leg, not browser-only: the
|
|
954
|
+
* engine-hosted capabilities (scene_access/entity_access/render_hooks) narrow
|
|
955
|
+
* away `wasmedge`, in the other direction.
|
|
944
956
|
*
|
|
945
957
|
* This is the difference between a truthful manifest and a wish. The hardcoded
|
|
946
958
|
* ["browser","wasmedge"] made every composition claim the browser, which made
|
|
@@ -1006,16 +1018,20 @@ function collectFlowRuntimeTargets({
|
|
|
1006
1018
|
);
|
|
1007
1019
|
}
|
|
1008
1020
|
|
|
1009
|
-
const
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1021
|
+
const unionCapabilities = [...(capabilities ?? [])];
|
|
1022
|
+
for (const leg of COMPOSED_FLOW_RUNTIME_TARGET_UNIVERSE) {
|
|
1023
|
+
const incompatible = LegIncompatibleCapabilitySets[leg];
|
|
1024
|
+
if (!incompatible) continue;
|
|
1025
|
+
const offending = unionCapabilities
|
|
1026
|
+
.filter((capability) => incompatible.has(capability))
|
|
1027
|
+
.sort();
|
|
1028
|
+
if (offending.length === 0) continue;
|
|
1013
1029
|
narrow(
|
|
1014
|
-
(target) => target !==
|
|
1030
|
+
(target) => target !== leg,
|
|
1015
1031
|
() =>
|
|
1016
|
-
`the flow's capability union contains ${
|
|
1032
|
+
`the flow's capability union contains ${offending
|
|
1017
1033
|
.map((capability) => `"${capability}"`)
|
|
1018
|
-
.join(", ")}, which the canonical
|
|
1034
|
+
.join(", ")}, which the canonical ${leg} runtime target cannot serve`,
|
|
1019
1035
|
);
|
|
1020
1036
|
}
|
|
1021
1037
|
|
|
@@ -12,6 +12,14 @@ export declare enum PluginFamily {
|
|
|
12
12
|
SDF = 7,
|
|
13
13
|
INFRASTRUCTURE = 8,
|
|
14
14
|
FLOW = 9,
|
|
15
|
-
BRIDGE = 10
|
|
15
|
+
BRIDGE = 10,
|
|
16
|
+
MANEUVER = 11,
|
|
17
|
+
ORBIT_DETERMINATION = 12,
|
|
18
|
+
FOUNDATION = 13,
|
|
19
|
+
PARSER = 14,
|
|
20
|
+
VALIDATOR = 15,
|
|
21
|
+
EXPORTER = 16,
|
|
22
|
+
PUBLISHER = 17,
|
|
23
|
+
BASILISK = 18
|
|
16
24
|
}
|
|
17
25
|
//# sourceMappingURL=plugin-family.d.ts.map
|
|
@@ -16,5 +16,13 @@ export var PluginFamily;
|
|
|
16
16
|
PluginFamily[PluginFamily["INFRASTRUCTURE"] = 8] = "INFRASTRUCTURE";
|
|
17
17
|
PluginFamily[PluginFamily["FLOW"] = 9] = "FLOW";
|
|
18
18
|
PluginFamily[PluginFamily["BRIDGE"] = 10] = "BRIDGE";
|
|
19
|
+
PluginFamily[PluginFamily["MANEUVER"] = 11] = "MANEUVER";
|
|
20
|
+
PluginFamily[PluginFamily["ORBIT_DETERMINATION"] = 12] = "ORBIT_DETERMINATION";
|
|
21
|
+
PluginFamily[PluginFamily["FOUNDATION"] = 13] = "FOUNDATION";
|
|
22
|
+
PluginFamily[PluginFamily["PARSER"] = 14] = "PARSER";
|
|
23
|
+
PluginFamily[PluginFamily["VALIDATOR"] = 15] = "VALIDATOR";
|
|
24
|
+
PluginFamily[PluginFamily["EXPORTER"] = 16] = "EXPORTER";
|
|
25
|
+
PluginFamily[PluginFamily["PUBLISHER"] = 17] = "PUBLISHER";
|
|
26
|
+
PluginFamily[PluginFamily["BASILISK"] = 18] = "BASILISK";
|
|
19
27
|
})(PluginFamily || (PluginFamily = {}));
|
|
20
28
|
//# sourceMappingURL=plugin-family.js.map
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// ===========================================================================
|
|
2
|
+
// GENERATED FILE — DO NOT EDIT.
|
|
3
|
+
//
|
|
4
|
+
// Source of truth : schemas/orbpro/Propagator.fbs
|
|
5
|
+
// Generator : scripts/generate-propagator-abi.mjs
|
|
6
|
+
// Drift gate : scripts/check-propagator-abi.mjs (runs in `npm test`)
|
|
7
|
+
// Contract : docs/propagator-abi.md
|
|
8
|
+
//
|
|
9
|
+
// These constants exist so that no JavaScript consumer ever hard-codes a byte
|
|
10
|
+
// offset again. Read a state vector with ORBPRO_STATE_VECTOR.offsets.position,
|
|
11
|
+
// never with the literal 8.
|
|
12
|
+
// ===========================================================================
|
|
13
|
+
|
|
14
|
+
export const ReferenceFrame = Object.freeze({
|
|
15
|
+
TEME: 0,
|
|
16
|
+
J2000: 1,
|
|
17
|
+
ICRF: 2,
|
|
18
|
+
ECEF: 3,
|
|
19
|
+
MCI: 4,
|
|
20
|
+
MCMF: 5,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export const StateFlags = Object.freeze({
|
|
24
|
+
NONE: 0,
|
|
25
|
+
VALID: 1,
|
|
26
|
+
IN_ECLIPSE: 2,
|
|
27
|
+
DECAYED: 4,
|
|
28
|
+
MANEUVERING: 8,
|
|
29
|
+
EXTRAPOLATED: 16,
|
|
30
|
+
HAS_COVARIANCE: 32,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
export const ORBPRO_STATE_VECTOR = Object.freeze({
|
|
34
|
+
name: "StateVector",
|
|
35
|
+
cName: "OrbProStateVector",
|
|
36
|
+
size: 64,
|
|
37
|
+
alignment: 8,
|
|
38
|
+
offsets: Object.freeze({
|
|
39
|
+
epoch: 0,
|
|
40
|
+
position: 8,
|
|
41
|
+
velocity: 32,
|
|
42
|
+
reference_frame: 56,
|
|
43
|
+
flags: 60,
|
|
44
|
+
}),
|
|
45
|
+
fields: Object.freeze({
|
|
46
|
+
epoch: Object.freeze({ offset: 0, size: 8, length: 1, view: "Float64" }),
|
|
47
|
+
position: Object.freeze({ offset: 8, size: 24, length: 3, view: "Float64" }),
|
|
48
|
+
velocity: Object.freeze({ offset: 32, size: 24, length: 3, view: "Float64" }),
|
|
49
|
+
reference_frame: Object.freeze({ offset: 56, size: 1, length: 1, view: "Uint8" }),
|
|
50
|
+
flags: Object.freeze({ offset: 60, size: 4, length: 1, view: "Uint32" }),
|
|
51
|
+
}),
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
export const ORBPRO_ORBITAL_ELEMENTS = Object.freeze({
|
|
55
|
+
name: "OrbitalElements",
|
|
56
|
+
cName: "OrbProOrbitalElements",
|
|
57
|
+
size: 64,
|
|
58
|
+
alignment: 8,
|
|
59
|
+
offsets: Object.freeze({
|
|
60
|
+
semi_major_axis: 0,
|
|
61
|
+
eccentricity: 8,
|
|
62
|
+
inclination: 16,
|
|
63
|
+
raan: 24,
|
|
64
|
+
arg_periapsis: 32,
|
|
65
|
+
true_anomaly: 40,
|
|
66
|
+
epoch: 48,
|
|
67
|
+
reserved: 56,
|
|
68
|
+
}),
|
|
69
|
+
fields: Object.freeze({
|
|
70
|
+
semi_major_axis: Object.freeze({ offset: 0, size: 8, length: 1, view: "Float64" }),
|
|
71
|
+
eccentricity: Object.freeze({ offset: 8, size: 8, length: 1, view: "Float64" }),
|
|
72
|
+
inclination: Object.freeze({ offset: 16, size: 8, length: 1, view: "Float64" }),
|
|
73
|
+
raan: Object.freeze({ offset: 24, size: 8, length: 1, view: "Float64" }),
|
|
74
|
+
arg_periapsis: Object.freeze({ offset: 32, size: 8, length: 1, view: "Float64" }),
|
|
75
|
+
true_anomaly: Object.freeze({ offset: 40, size: 8, length: 1, view: "Float64" }),
|
|
76
|
+
epoch: Object.freeze({ offset: 48, size: 8, length: 1, view: "Float64" }),
|
|
77
|
+
reserved: Object.freeze({ offset: 56, size: 8, length: 1, view: "Float64" }),
|
|
78
|
+
}),
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
export const ORBPRO_OMM_RECORD = Object.freeze({
|
|
82
|
+
name: "OMMRecord",
|
|
83
|
+
cName: "OrbProOMMRecord",
|
|
84
|
+
size: 88,
|
|
85
|
+
alignment: 8,
|
|
86
|
+
offsets: Object.freeze({
|
|
87
|
+
epoch_jd: 0,
|
|
88
|
+
mean_motion: 8,
|
|
89
|
+
eccentricity: 16,
|
|
90
|
+
inclination: 24,
|
|
91
|
+
ra_of_asc_node: 32,
|
|
92
|
+
arg_of_pericenter: 40,
|
|
93
|
+
mean_anomaly: 48,
|
|
94
|
+
bstar: 56,
|
|
95
|
+
mean_motion_dot: 64,
|
|
96
|
+
mean_motion_ddot: 72,
|
|
97
|
+
norad_cat_id: 80,
|
|
98
|
+
}),
|
|
99
|
+
fields: Object.freeze({
|
|
100
|
+
epoch_jd: Object.freeze({ offset: 0, size: 8, length: 1, view: "Float64" }),
|
|
101
|
+
mean_motion: Object.freeze({ offset: 8, size: 8, length: 1, view: "Float64" }),
|
|
102
|
+
eccentricity: Object.freeze({ offset: 16, size: 8, length: 1, view: "Float64" }),
|
|
103
|
+
inclination: Object.freeze({ offset: 24, size: 8, length: 1, view: "Float64" }),
|
|
104
|
+
ra_of_asc_node: Object.freeze({ offset: 32, size: 8, length: 1, view: "Float64" }),
|
|
105
|
+
arg_of_pericenter: Object.freeze({ offset: 40, size: 8, length: 1, view: "Float64" }),
|
|
106
|
+
mean_anomaly: Object.freeze({ offset: 48, size: 8, length: 1, view: "Float64" }),
|
|
107
|
+
bstar: Object.freeze({ offset: 56, size: 8, length: 1, view: "Float64" }),
|
|
108
|
+
mean_motion_dot: Object.freeze({ offset: 64, size: 8, length: 1, view: "Float64" }),
|
|
109
|
+
mean_motion_ddot: Object.freeze({ offset: 72, size: 8, length: 1, view: "Float64" }),
|
|
110
|
+
norad_cat_id: Object.freeze({ offset: 80, size: 4, length: 1, view: "Uint32" }),
|
|
111
|
+
}),
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
export const ORBPRO_PROPAGATOR_ABI = Object.freeze({
|
|
115
|
+
StateVector: ORBPRO_STATE_VECTOR,
|
|
116
|
+
OrbitalElements: ORBPRO_ORBITAL_ELEMENTS,
|
|
117
|
+
OMMRecord: ORBPRO_OMM_RECORD,
|
|
118
|
+
});
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
// ===========================================================================
|
|
2
|
+
// GENERATED FILE — DO NOT EDIT.
|
|
3
|
+
//
|
|
4
|
+
// Source of truth : schemas/orbpro/Propagator.fbs
|
|
5
|
+
// Generator : scripts/generate-propagator-abi.mjs
|
|
6
|
+
// Drift gate : scripts/check-propagator-abi.mjs (runs in `npm test`)
|
|
7
|
+
// Contract : docs/propagator-abi.md
|
|
8
|
+
//
|
|
9
|
+
// These constants exist so that no JavaScript consumer ever hard-codes a byte
|
|
10
|
+
// offset again. Read a state vector with ORBPRO_STATE_VECTOR.offsets.position,
|
|
11
|
+
// never with the literal 8.
|
|
12
|
+
// ===========================================================================
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
export enum ReferenceFrame {
|
|
16
|
+
TEME = 0,
|
|
17
|
+
J2000 = 1,
|
|
18
|
+
ICRF = 2,
|
|
19
|
+
ECEF = 3,
|
|
20
|
+
MCI = 4,
|
|
21
|
+
MCMF = 5,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* StateVector.flags is a BITFIELD carrying any OR-combination of these, so it
|
|
26
|
+
* is declared `uint` on the struct rather than typed to this enum. The C
|
|
27
|
+
* enumerators are generated from here anyway — they are the contract.
|
|
28
|
+
*/
|
|
29
|
+
export enum StateFlags {
|
|
30
|
+
NONE = 0,
|
|
31
|
+
VALID = 1,
|
|
32
|
+
IN_ECLIPSE = 2,
|
|
33
|
+
DECAYED = 4,
|
|
34
|
+
MANEUVERING = 8,
|
|
35
|
+
EXTRAPOLATED = 16,
|
|
36
|
+
HAS_COVARIANCE = 32,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** One field's placement inside an ABI struct. */
|
|
40
|
+
export interface AbiField {
|
|
41
|
+
readonly offset: number;
|
|
42
|
+
readonly size: number;
|
|
43
|
+
/** Element count for array fields, 1 for scalars. */
|
|
44
|
+
readonly length: number;
|
|
45
|
+
/** DataView accessor suffix, e.g. "Float64" for getFloat64. */
|
|
46
|
+
readonly view: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** One ABI struct's byte layout. */
|
|
50
|
+
export interface AbiStruct {
|
|
51
|
+
readonly name: string;
|
|
52
|
+
readonly cName: string;
|
|
53
|
+
readonly size: number;
|
|
54
|
+
readonly alignment: number;
|
|
55
|
+
readonly offsets: Readonly<Record<string, number>>;
|
|
56
|
+
readonly fields: Readonly<Record<string, AbiField>>;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Orbital state vector — 64 bytes, 8-byte aligned. Mirrors
|
|
61
|
+
* `OrbProStateVector` in orbpro-integration/sdk/include/orbpro_propagator.h
|
|
62
|
+
* byte for byte:
|
|
63
|
+
*
|
|
64
|
+
* 0 8 epoch (Julian date, float64)
|
|
65
|
+
* 8 24 position (METERS)
|
|
66
|
+
* 32 24 velocity (METERS/SECOND)
|
|
67
|
+
* 56 1 reference_frame (ubyte)
|
|
68
|
+
* 57 3 padding, MUST be zero
|
|
69
|
+
* 60 4 flags (uint32)
|
|
70
|
+
*
|
|
71
|
+
* NORMATIVE UNITS: position METERS, velocity METERS/SECOND. There is no km
|
|
72
|
+
* variant and no host-side conversion — the engine hands these straight to
|
|
73
|
+
* Cesium Cartesian3, whose unit is metres, and both shipped propagators emit
|
|
74
|
+
* meters. The C header used to declare `reference_frame` as a uint32 at
|
|
75
|
+
* offset 56, wire-identical to this ubyte+padding only by little-endian
|
|
76
|
+
* accident; it now declares ubyte + 3 reserved so the two agree by
|
|
77
|
+
* construction.
|
|
78
|
+
*
|
|
79
|
+
* Ruling: graph/findings/official-harness-shapes.md §4.1 / §4.2
|
|
80
|
+
*/
|
|
81
|
+
export const ORBPRO_STATE_VECTOR: AbiStruct = {
|
|
82
|
+
name: "StateVector",
|
|
83
|
+
cName: "OrbProStateVector",
|
|
84
|
+
size: 64,
|
|
85
|
+
alignment: 8,
|
|
86
|
+
offsets: {
|
|
87
|
+
epoch: 0,
|
|
88
|
+
position: 8,
|
|
89
|
+
velocity: 32,
|
|
90
|
+
reference_frame: 56,
|
|
91
|
+
flags: 60,
|
|
92
|
+
},
|
|
93
|
+
fields: {
|
|
94
|
+
epoch: { offset: 0, size: 8, length: 1, view: "Float64" },
|
|
95
|
+
position: { offset: 8, size: 24, length: 3, view: "Float64" },
|
|
96
|
+
velocity: { offset: 32, size: 24, length: 3, view: "Float64" },
|
|
97
|
+
reference_frame: { offset: 56, size: 1, length: 1, view: "Uint8" },
|
|
98
|
+
flags: { offset: 60, size: 4, length: 1, view: "Uint32" },
|
|
99
|
+
},
|
|
100
|
+
} as const;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Keplerian orbital elements — the OPTIONAL initialization input accepted by
|
|
104
|
+
* `plugin_init_elements`. 64 bytes, 8-byte aligned.
|
|
105
|
+
*
|
|
106
|
+
* UNITS NOTE: `semi_major_axis` is KILOMETRES. That is deliberate and it is
|
|
107
|
+
* NOT an inconsistency with StateVector's metres: this is an INPUT element
|
|
108
|
+
* set, not an output state vector, and the two are different structs on
|
|
109
|
+
* different sides of the call. Do not "unify" them — see the normative units
|
|
110
|
+
* block in the generated C header.
|
|
111
|
+
*/
|
|
112
|
+
export const ORBPRO_ORBITAL_ELEMENTS: AbiStruct = {
|
|
113
|
+
name: "OrbitalElements",
|
|
114
|
+
cName: "OrbProOrbitalElements",
|
|
115
|
+
size: 64,
|
|
116
|
+
alignment: 8,
|
|
117
|
+
offsets: {
|
|
118
|
+
semi_major_axis: 0,
|
|
119
|
+
eccentricity: 8,
|
|
120
|
+
inclination: 16,
|
|
121
|
+
raan: 24,
|
|
122
|
+
arg_periapsis: 32,
|
|
123
|
+
true_anomaly: 40,
|
|
124
|
+
epoch: 48,
|
|
125
|
+
reserved: 56,
|
|
126
|
+
},
|
|
127
|
+
fields: {
|
|
128
|
+
semi_major_axis: { offset: 0, size: 8, length: 1, view: "Float64" },
|
|
129
|
+
eccentricity: { offset: 8, size: 8, length: 1, view: "Float64" },
|
|
130
|
+
inclination: { offset: 16, size: 8, length: 1, view: "Float64" },
|
|
131
|
+
raan: { offset: 24, size: 8, length: 1, view: "Float64" },
|
|
132
|
+
arg_periapsis: { offset: 32, size: 8, length: 1, view: "Float64" },
|
|
133
|
+
true_anomaly: { offset: 40, size: 8, length: 1, view: "Float64" },
|
|
134
|
+
epoch: { offset: 48, size: 8, length: 1, view: "Float64" },
|
|
135
|
+
reserved: { offset: 56, size: 8, length: 1, view: "Float64" },
|
|
136
|
+
},
|
|
137
|
+
} as const;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Binary OMM record — the mean-element ingest struct. 88 bytes, 8-byte
|
|
141
|
+
* aligned.
|
|
142
|
+
*
|
|
143
|
+
* !! THIS STRUCT IS ALSO AN ON-DISK FORMAT !!
|
|
144
|
+
* -----------------------------------------------------------------------
|
|
145
|
+
* It crosses the ABI (`plugin_init_omm`, `plugin_entity_add_omm`) AND is
|
|
146
|
+
* persisted verbatim as a SQLite BLOB by the first-party SGP4 module
|
|
147
|
+
* (`sgp4_plugin.cpp`, `sqlite3_bind_blob(..., &omm, sizeof(OrbProOMMRecord), ...)`).
|
|
148
|
+
* Until W1.1 it carried NO size or offset lock anywhere in the stack, so the
|
|
149
|
+
* layout that every stored blob depends on was held only by the field order
|
|
150
|
+
* of one hand-written C struct in one module.
|
|
151
|
+
*
|
|
152
|
+
* The layout declared here is that layout, EXACTLY as it has been written to
|
|
153
|
+
* disk — the four trailing padding bytes at offset 84 included. This is a
|
|
154
|
+
* description of the wire as it already exists, not a redesign of it; the
|
|
155
|
+
* generated locks now pin it. Migrating the format is explicitly out of
|
|
156
|
+
* scope and would invalidate every stored blob.
|
|
157
|
+
*
|
|
158
|
+
* UNITS: angles in DEGREES, mean motion in REV/DAY, bstar in 1/earth-radii.
|
|
159
|
+
* These are the SDS $OMM units, carried through unconverted.
|
|
160
|
+
*/
|
|
161
|
+
export const ORBPRO_OMM_RECORD: AbiStruct = {
|
|
162
|
+
name: "OMMRecord",
|
|
163
|
+
cName: "OrbProOMMRecord",
|
|
164
|
+
size: 88,
|
|
165
|
+
alignment: 8,
|
|
166
|
+
offsets: {
|
|
167
|
+
epoch_jd: 0,
|
|
168
|
+
mean_motion: 8,
|
|
169
|
+
eccentricity: 16,
|
|
170
|
+
inclination: 24,
|
|
171
|
+
ra_of_asc_node: 32,
|
|
172
|
+
arg_of_pericenter: 40,
|
|
173
|
+
mean_anomaly: 48,
|
|
174
|
+
bstar: 56,
|
|
175
|
+
mean_motion_dot: 64,
|
|
176
|
+
mean_motion_ddot: 72,
|
|
177
|
+
norad_cat_id: 80,
|
|
178
|
+
},
|
|
179
|
+
fields: {
|
|
180
|
+
epoch_jd: { offset: 0, size: 8, length: 1, view: "Float64" },
|
|
181
|
+
mean_motion: { offset: 8, size: 8, length: 1, view: "Float64" },
|
|
182
|
+
eccentricity: { offset: 16, size: 8, length: 1, view: "Float64" },
|
|
183
|
+
inclination: { offset: 24, size: 8, length: 1, view: "Float64" },
|
|
184
|
+
ra_of_asc_node: { offset: 32, size: 8, length: 1, view: "Float64" },
|
|
185
|
+
arg_of_pericenter: { offset: 40, size: 8, length: 1, view: "Float64" },
|
|
186
|
+
mean_anomaly: { offset: 48, size: 8, length: 1, view: "Float64" },
|
|
187
|
+
bstar: { offset: 56, size: 8, length: 1, view: "Float64" },
|
|
188
|
+
mean_motion_dot: { offset: 64, size: 8, length: 1, view: "Float64" },
|
|
189
|
+
mean_motion_ddot: { offset: 72, size: 8, length: 1, view: "Float64" },
|
|
190
|
+
norad_cat_id: { offset: 80, size: 4, length: 1, view: "Uint32" },
|
|
191
|
+
},
|
|
192
|
+
} as const;
|
|
193
|
+
|
|
194
|
+
/** Every ABI struct, keyed by its IDL name. */
|
|
195
|
+
export const ORBPRO_PROPAGATOR_ABI: Readonly<Record<string, AbiStruct>> = {
|
|
196
|
+
StateVector: ORBPRO_STATE_VECTOR,
|
|
197
|
+
OrbitalElements: ORBPRO_ORBITAL_ELEMENTS,
|
|
198
|
+
OMMRecord: ORBPRO_OMM_RECORD,
|
|
199
|
+
} as const;
|