space-data-module-sdk 0.8.4 → 0.8.5
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/README.md +117 -20
- package/bin/space-data-module.js +263 -0
- package/docs/.nojekyll +1 -0
- package/docs/AGENTS.md +34 -0
- package/docs/architecture.svg +141 -0
- package/docs/browser-wasmedge-isomorphic.md +179 -0
- package/docs/flatsql-streaming-standard.md +341 -0
- package/docs/gpu-module-abi.md +193 -0
- package/docs/index.html +125 -0
- package/docs/isomorphic-pthreads.md +188 -0
- package/docs/isomorphic-sdn-runtime-plan.md +167 -0
- package/docs/language-runtime-matrix.md +82 -0
- package/docs/manifest-structure.svg +114 -0
- package/docs/module-bundle-runtime-plan.md +19 -0
- package/docs/module-lifecycle.svg +70 -0
- package/docs/module-publication-standard.md +540 -0
- package/docs/node-red-default-node-parity.md +88 -0
- package/docs/protocol-installation.md +196 -0
- package/docs/secrets-capability.md +152 -0
- package/docs/styles.css +288 -0
- package/docs/testing-harness.md +408 -0
- package/docs/tri-runtime-parity.md +132 -0
- package/docs/wallet-callback.html +2 -0
- package/package.json +25 -6
- package/schemas/HttpRequestAbi.fbs +41 -0
- package/schemas/HttpResponseAbi.fbs +36 -0
- package/schemas/PluginManifest.fbs +2 -1
- package/src/AGENTS.md +1 -1
- package/src/app/codec.js +548 -0
- package/src/app/index.js +6 -0
- package/src/browser.js +5 -0
- package/src/bundle/constants.js +1 -0
- package/src/bundle/index.js +15 -0
- package/src/bundle/sigdomain.js +179 -0
- package/src/bundle/signing.js +767 -0
- package/src/bundle/wasm.js +3 -2
- package/src/capabilities.js +3 -0
- package/src/compat/index.js +7 -0
- package/src/compat/sdnLegacy.js +449 -0
- package/src/compiler/compileModule.js +556 -55
- package/src/compiler/flatcSupport.js +41 -27
- package/src/compiler/index.d.ts +2 -0
- package/src/compiler/index.js +18 -0
- package/src/compiler/invokeGlue.js +1212 -183
- package/src/compiler/pthreadArtifactGuard.js +910 -0
- package/src/compiler/sdnShimGenerator.js +323 -0
- package/src/compiler/wasiThreadsToolchain.js +150 -0
- package/src/compliance/index.js +11 -1
- package/src/compliance/legacyWildcardPorts.js +228 -0
- package/src/compliance/pluginCompliance.js +1000 -96
- package/src/field-stream/index.d.ts +31 -0
- package/src/field-stream/index.js +119 -0
- package/src/flow/dependencyStreamBridge.js +234 -0
- package/src/flow/flatsqlLinkShim.js +304 -0
- package/src/flow/flowCodec.js +107 -0
- package/src/flow/flowCompiler.js +2900 -0
- package/src/flow/flowRuntimeHost.js +877 -0
- package/src/flow/index.d.ts +117 -0
- package/src/flow/index.js +31 -0
- package/src/flow/isomorphicFlowHost.js +384 -0
- package/src/flow/jsFlowRuntime.js +275 -0
- package/src/flow/normalize.js +294 -0
- package/src/flow/runtime-src/flow_runtime.cpp +1699 -0
- package/src/flow/vendor/sdn-flow/MethodRegistry.js +400 -0
- package/src/flow/vendor/sdn-flow/constants.js +39 -0
- package/src/flow/vendor/sdn-flow/index.js +29 -0
- package/src/flow/vendor/sdn-flow/normalize.js +506 -0
- package/src/flow/vendor/sdn-flow/wasmCompatibility.js +189 -0
- package/src/generated/http/cpp/HttpRequestAbi_generated.h +285 -0
- package/src/generated/http/cpp/HttpResponseAbi_generated.h +192 -0
- package/src/generated/http/sdn/http/http-header.js +53 -0
- package/src/generated/http/sdn/http/http-header.ts +67 -0
- package/src/generated/http/sdn/http/http-request.js +132 -0
- package/src/generated/http/sdn/http/http-request.ts +179 -0
- package/src/generated/http/sdn/http/http-response.js +144 -0
- package/src/generated/http/sdn/http/http-response.ts +168 -0
- package/src/generated/http/sdn/http.js +11 -0
- package/src/generated/http/sdn/http.ts +4 -0
- package/src/generated/orbpro/flow/backpressure-policy.d.ts +12 -0
- package/src/generated/orbpro/flow/backpressure-policy.d.ts.map +1 -0
- package/src/generated/orbpro/flow/backpressure-policy.js +17 -0
- package/src/generated/orbpro/flow/backpressure-policy.js.map +1 -0
- package/src/generated/orbpro/flow/backpressure-policy.ts +15 -0
- package/src/generated/orbpro/flow/flow-bundle-manifest.d.ts +142 -0
- package/src/generated/orbpro/flow/flow-bundle-manifest.d.ts.map +1 -0
- package/src/generated/orbpro/flow/flow-bundle-manifest.js +304 -0
- package/src/generated/orbpro/flow/flow-bundle-manifest.js.map +1 -0
- package/src/generated/orbpro/flow/flow-bundle-manifest.ts +399 -0
- package/src/generated/orbpro/flow/flow-edge.d.ts +113 -0
- package/src/generated/orbpro/flow/flow-edge.d.ts.map +1 -0
- package/src/generated/orbpro/flow/flow-edge.js +221 -0
- package/src/generated/orbpro/flow/flow-edge.js.map +1 -0
- package/src/generated/orbpro/flow/flow-edge.ts +292 -0
- package/src/generated/orbpro/flow/flow-node.d.ts +80 -0
- package/src/generated/orbpro/flow/flow-node.d.ts.map +1 -0
- package/src/generated/orbpro/flow/flow-node.js +158 -0
- package/src/generated/orbpro/flow/flow-node.js.map +1 -0
- package/src/generated/orbpro/flow/flow-node.ts +202 -0
- package/src/generated/orbpro/flow/flow-program.d.ts +164 -0
- package/src/generated/orbpro/flow/flow-program.d.ts.map +1 -0
- package/src/generated/orbpro/flow/flow-program.js +350 -0
- package/src/generated/orbpro/flow/flow-program.js.map +1 -0
- package/src/generated/orbpro/flow/flow-program.ts +477 -0
- package/src/generated/orbpro/flow/flow-trigger.d.ts +108 -0
- package/src/generated/orbpro/flow/flow-trigger.d.ts.map +1 -0
- package/src/generated/orbpro/flow/flow-trigger.js +207 -0
- package/src/generated/orbpro/flow/flow-trigger.js.map +1 -0
- package/src/generated/orbpro/flow/flow-trigger.ts +276 -0
- package/src/generated/orbpro/flow/node-kind.d.ts +13 -0
- package/src/generated/orbpro/flow/node-kind.d.ts.map +1 -0
- package/src/generated/orbpro/flow/node-kind.js +16 -0
- package/src/generated/orbpro/flow/node-kind.js.map +1 -0
- package/src/generated/orbpro/{invoke.ts → flow/node-kind.ts} +12 -2
- package/src/generated/orbpro/flow/plugin-version-binding.d.ts +52 -0
- package/src/generated/orbpro/flow/plugin-version-binding.d.ts.map +1 -0
- package/src/generated/orbpro/flow/plugin-version-binding.js +85 -0
- package/src/generated/orbpro/flow/plugin-version-binding.js.map +1 -0
- package/src/generated/orbpro/flow/plugin-version-binding.ts +121 -0
- package/src/generated/orbpro/flow/schema-hash-binding.d.ts +70 -0
- package/src/generated/orbpro/flow/schema-hash-binding.d.ts.map +1 -0
- package/src/generated/orbpro/flow/schema-hash-binding.js +143 -0
- package/src/generated/orbpro/flow/schema-hash-binding.js.map +1 -0
- package/src/generated/orbpro/flow/schema-hash-binding.ts +189 -0
- package/src/generated/orbpro/flow/trigger-binding.d.ts +71 -0
- package/src/generated/orbpro/flow/trigger-binding.d.ts.map +1 -0
- package/src/generated/orbpro/flow/trigger-binding.js +142 -0
- package/src/generated/orbpro/flow/trigger-binding.js.map +1 -0
- package/src/generated/orbpro/flow/trigger-binding.ts +181 -0
- package/src/generated/orbpro/flow/trigger-kind.d.ts +14 -0
- package/src/generated/orbpro/flow/trigger-kind.d.ts.map +1 -0
- package/src/generated/orbpro/flow/trigger-kind.js +17 -0
- package/src/generated/orbpro/flow/trigger-kind.js.map +1 -0
- package/src/generated/orbpro/flow/trigger-kind.ts +17 -0
- package/src/generated/orbpro/flow.d.ts +21 -0
- package/src/generated/orbpro/flow.d.ts.map +1 -0
- package/src/generated/orbpro/flow.js +23 -0
- package/src/generated/orbpro/flow.js.map +1 -0
- package/src/generated/orbpro/flow.ts +24 -0
- package/src/generated/orbpro/manifest/capability-kind.d.ts +2 -1
- package/src/generated/orbpro/manifest/capability-kind.js +1 -0
- package/src/generated/orbpro/manifest/capability-kind.ts +1 -0
- package/src/generated/orbpro/plugin/stream-invoke-request.d.ts +93 -0
- package/src/generated/orbpro/plugin/stream-invoke-request.js +160 -0
- package/src/generated/orbpro/plugin/stream-invoke-request.ts +211 -0
- package/src/generated/orbpro/plugin/stream-invoke-response.d.ts +99 -0
- package/src/generated/orbpro/plugin/stream-invoke-response.js +175 -0
- package/src/generated/orbpro/plugin/stream-invoke-response.ts +226 -0
- package/src/generated/orbpro/plugin.js +8 -0
- package/src/generated/orbpro/stream.d.ts +12 -0
- package/src/generated/orbpro/stream.js +14 -0
- package/src/generated/orbpro/stream.ts +15 -0
- package/src/generated/spacedatastandards/plg/EntryFunction.d.ts +52 -0
- package/src/generated/spacedatastandards/plg/EntryFunction.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/EntryFunction.js +106 -0
- package/src/generated/spacedatastandards/plg/EntryFunction.ts +162 -0
- package/src/generated/spacedatastandards/plg/FlatBufferTypeRef.d.ts +90 -0
- package/src/generated/spacedatastandards/plg/FlatBufferTypeRef.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/FlatBufferTypeRef.js +189 -0
- package/src/generated/spacedatastandards/plg/FlatBufferTypeRef.ts +270 -0
- package/src/generated/spacedatastandards/plg/PLG.d.ts +492 -0
- package/src/generated/spacedatastandards/plg/PLG.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLG.js +1139 -0
- package/src/generated/spacedatastandards/plg/PLG.ts +1600 -0
- package/src/generated/spacedatastandards/plg/PLGAcceptedTypeSet.d.ts +63 -0
- package/src/generated/spacedatastandards/plg/PLGAcceptedTypeSet.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGAcceptedTypeSet.js +138 -0
- package/src/generated/spacedatastandards/plg/PLGAcceptedTypeSet.ts +189 -0
- package/src/generated/spacedatastandards/plg/PLGBuildArtifact.d.ts +41 -0
- package/src/generated/spacedatastandards/plg/PLGBuildArtifact.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGBuildArtifact.js +104 -0
- package/src/generated/spacedatastandards/plg/PLGBuildArtifact.ts +151 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdge.d.ts +68 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdge.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdge.js +124 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdge.ts +184 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdgeContract.d.ts +58 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdgeContract.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdgeContract.js +126 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdgeContract.ts +161 -0
- package/src/generated/spacedatastandards/plg/PLGFlowNode.d.ts +82 -0
- package/src/generated/spacedatastandards/plg/PLGFlowNode.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGFlowNode.js +164 -0
- package/src/generated/spacedatastandards/plg/PLGFlowNode.ts +244 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTrigger.d.ts +55 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTrigger.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTrigger.js +105 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTrigger.ts +162 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTriggerBinding.d.ts +42 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTriggerBinding.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTriggerBinding.js +83 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTriggerBinding.ts +127 -0
- package/src/generated/spacedatastandards/plg/PLGHostCapability.d.ts +36 -0
- package/src/generated/spacedatastandards/plg/PLGHostCapability.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGHostCapability.js +90 -0
- package/src/generated/spacedatastandards/plg/PLGHostCapability.ts +127 -0
- package/src/generated/spacedatastandards/plg/PLGMethodManifest.d.ts +53 -0
- package/src/generated/spacedatastandards/plg/PLGMethodManifest.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGMethodManifest.js +153 -0
- package/src/generated/spacedatastandards/plg/PLGMethodManifest.ts +210 -0
- package/src/generated/spacedatastandards/plg/PLGPortManifest.d.ts +70 -0
- package/src/generated/spacedatastandards/plg/PLGPortManifest.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGPortManifest.js +149 -0
- package/src/generated/spacedatastandards/plg/PLGPortManifest.ts +212 -0
- package/src/generated/spacedatastandards/plg/PLGProtocolSpec.d.ts +73 -0
- package/src/generated/spacedatastandards/plg/PLGProtocolSpec.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGProtocolSpec.js +199 -0
- package/src/generated/spacedatastandards/plg/PLGProtocolSpec.ts +292 -0
- package/src/generated/spacedatastandards/plg/PLGTimerSpec.d.ts +40 -0
- package/src/generated/spacedatastandards/plg/PLGTimerSpec.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGTimerSpec.js +103 -0
- package/src/generated/spacedatastandards/plg/PLGTimerSpec.ts +148 -0
- package/src/generated/spacedatastandards/plg/PluginCapability.d.ts +41 -0
- package/src/generated/spacedatastandards/plg/PluginCapability.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PluginCapability.js +82 -0
- package/src/generated/spacedatastandards/plg/{plugin-capability.ts → PluginCapability.ts} +55 -18
- package/src/generated/spacedatastandards/plg/PluginDependency.d.ts +42 -0
- package/src/generated/spacedatastandards/plg/PluginDependency.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PluginDependency.js +80 -0
- package/src/generated/spacedatastandards/plg/PluginDependency.ts +124 -0
- package/src/generated/spacedatastandards/plg/TAB.d.ts +85 -0
- package/src/generated/spacedatastandards/plg/TAB.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/TAB.js +173 -0
- package/src/generated/spacedatastandards/plg/TAB.ts +228 -0
- package/src/generated/spacedatastandards/plg/bufferMutability.d.ts +18 -0
- package/src/generated/spacedatastandards/plg/bufferMutability.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/bufferMutability.js +20 -0
- package/src/generated/spacedatastandards/plg/bufferMutability.ts +23 -0
- package/src/generated/spacedatastandards/plg/bufferOwnership.d.ts +18 -0
- package/src/generated/spacedatastandards/plg/bufferOwnership.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/bufferOwnership.js +20 -0
- package/src/generated/spacedatastandards/plg/bufferOwnership.ts +23 -0
- package/src/generated/spacedatastandards/plg/drainBehavior.d.ts +20 -0
- package/src/generated/spacedatastandards/plg/drainBehavior.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/drainBehavior.js +22 -0
- package/src/generated/spacedatastandards/plg/drainBehavior.ts +25 -0
- package/src/generated/spacedatastandards/plg/flowEdgeRoutePolicy.d.ts +10 -0
- package/src/generated/spacedatastandards/plg/flowEdgeRoutePolicy.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/flowEdgeRoutePolicy.js +12 -0
- package/src/generated/spacedatastandards/plg/flowEdgeRoutePolicy.ts +13 -0
- package/src/generated/spacedatastandards/plg/hostCapabilityKind.d.ts +51 -0
- package/src/generated/spacedatastandards/plg/hostCapabilityKind.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/hostCapabilityKind.js +53 -0
- package/src/generated/spacedatastandards/plg/hostCapabilityKind.ts +55 -0
- package/src/generated/spacedatastandards/plg/invokeSurfaceKind.d.ts +15 -0
- package/src/generated/spacedatastandards/plg/invokeSurfaceKind.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/invokeSurfaceKind.js +17 -0
- package/src/generated/spacedatastandards/plg/invokeSurfaceKind.ts +19 -0
- package/src/generated/spacedatastandards/plg/main.d.ts +29 -0
- package/src/generated/spacedatastandards/plg/main.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/main.js +30 -0
- package/src/generated/spacedatastandards/plg/main.ts +32 -0
- package/src/generated/spacedatastandards/plg/payloadWireFormat.d.ts +17 -0
- package/src/generated/spacedatastandards/plg/payloadWireFormat.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/payloadWireFormat.js +19 -0
- package/src/generated/spacedatastandards/plg/payloadWireFormat.ts +21 -0
- package/src/generated/spacedatastandards/plg/pluginCategory.d.ts +82 -0
- package/src/generated/spacedatastandards/plg/pluginCategory.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/pluginCategory.js +84 -0
- package/src/generated/spacedatastandards/plg/pluginCategory.ts +103 -0
- package/src/generated/spacedatastandards/plg/publicationState.d.ts +18 -0
- package/src/generated/spacedatastandards/plg/publicationState.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/publicationState.js +20 -0
- package/src/generated/spacedatastandards/plg/purchaseTier.d.ts +18 -0
- package/src/generated/spacedatastandards/plg/purchaseTier.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/purchaseTier.js +20 -0
- package/src/host/AGENTS.md +2 -2
- package/src/host/abi.js +53 -66
- package/src/host/browserHost.js +355 -8
- package/src/host/cpp/keyslotClient.hpp +231 -0
- package/src/host/cpp/secretsClient.hpp +583 -0
- package/src/host/hostcallWire.js +183 -0
- package/src/host/index.js +2 -0
- package/src/host/isomorphicLoader.js +44 -7
- package/src/host/nodeHost.js +227 -8
- package/src/host/sabHostcallChannel.js +206 -0
- package/src/host/timerDriver.js +203 -0
- package/src/host/wasiShim.js +41 -1
- package/src/host/wasiThreadBrowserWorker.mjs +48 -0
- package/src/host/wasiThreadHost.js +393 -0
- package/src/host/wasiThreadWorker.mjs +32 -0
- package/src/host/wasiThreadWorkerRuntime.js +93 -0
- package/src/http/index.js +339 -0
- package/src/index.d.ts +716 -10
- package/src/index.js +4 -0
- package/src/invoke/codec.js +1202 -128
- package/src/invoke/index.js +5 -1
- package/src/licensing/index.d.ts +2 -0
- package/src/licensing/index.js +2 -0
- package/src/licensing/records.js +287 -8
- package/src/manifest/codec.js +62 -14
- package/src/manifest/index.js +2 -0
- package/src/manifest/legacyToPlg.js +164 -25
- package/src/manifest/normalize.js +1 -0
- package/src/manifest/plgCodec.js +1303 -62
- package/src/manifest/typeRefs.js +162 -24
- package/src/runtime/compiledRuntimeAbi.js +47 -0
- package/src/runtime/compiledRuntimeAbi.json +33 -0
- package/src/runtime/index.d.ts +32 -0
- package/src/runtime/index.js +1 -0
- package/src/runtime-host/index.js +3 -0
- package/src/runtime-host/methodRegistry.js +55 -0
- package/src/standards/index.js +200 -56
- package/src/standards/sharedCatalog.js +16 -0
- package/src/testing/browserModuleHarness.js +604 -31
- package/src/testing/docker/wasmedge-parity.Dockerfile +39 -0
- package/src/testing/index.d.ts +151 -0
- package/src/testing/index.js +21 -0
- package/src/testing/native/wasmedge_emscripten_pthread_runner.c +25 -1
- package/src/testing/parityBrowserRunner.js +138 -0
- package/src/testing/parityHarness.js +616 -0
- package/src/testing/parityLanes.js +537 -0
- package/src/testing/processInvoke.js +29 -21
- package/src/testing/streamInvokeCodec.js +10 -175
- package/src/testing/wasmedgePin.json +6 -0
- package/src/testing/workerModuleHarness.js +242 -0
- package/src/testing/workerModuleHarnessWorker.js +176 -0
- package/src/transport/index.js +3 -0
- package/src/transport/pki.js +299 -11
- package/src/transport/records.js +16 -7
- package/src/utils/ecdsaDer.js +106 -0
- package/src/utils/wasmCrypto.js +0 -43
- package/templates/gpu-module/README.md +48 -0
- package/templates/gpu-module/include/space_data_gpu_abi.h +122 -0
- package/templates/gpu-module/manifest.json +84 -0
- package/schemas/PluginInvokeRequest.fbs +0 -18
- package/schemas/PluginInvokeResponse.fbs +0 -30
- package/schemas/spacedatastandards/PLG.fbs +0 -191
- package/src/generated/orbpro/invoke/plugin-invoke-request.d.ts +0 -51
- package/src/generated/orbpro/invoke/plugin-invoke-request.d.ts.map +0 -1
- package/src/generated/orbpro/invoke/plugin-invoke-request.js +0 -131
- package/src/generated/orbpro/invoke/plugin-invoke-request.js.map +0 -1
- package/src/generated/orbpro/invoke/plugin-invoke-request.ts +0 -173
- package/src/generated/orbpro/invoke/plugin-invoke-response.d.ts +0 -76
- package/src/generated/orbpro/invoke/plugin-invoke-response.d.ts.map +0 -1
- package/src/generated/orbpro/invoke/plugin-invoke-response.js +0 -184
- package/src/generated/orbpro/invoke/plugin-invoke-response.js.map +0 -1
- package/src/generated/orbpro/invoke/plugin-invoke-response.ts +0 -243
- package/src/generated/orbpro/invoke.d.ts +0 -3
- package/src/generated/orbpro/invoke.js +0 -5
- package/src/generated/spacedatastandards/plg/entry-function.js +0 -86
- package/src/generated/spacedatastandards/plg/entry-function.ts +0 -119
- package/src/generated/spacedatastandards/plg/index.js +0 -16
- package/src/generated/spacedatastandards/plg/index.ts +0 -11
- package/src/generated/spacedatastandards/plg/plg.js +0 -657
- package/src/generated/spacedatastandards/plg/plg.ts +0 -924
- package/src/generated/spacedatastandards/plg/plugin-capability.js +0 -66
- package/src/generated/spacedatastandards/plg/plugin-category.js +0 -15
- package/src/generated/spacedatastandards/plg/plugin-category.ts +0 -53
- package/src/generated/spacedatastandards/plg/plugin-dependency.js +0 -63
- package/src/generated/spacedatastandards/plg/plugin-dependency.ts +0 -86
- package/src/generated/spacedatastandards/plg/publication-state.js +0 -9
- package/src/generated/spacedatastandards/plg/purchase-tier.js +0 -9
- /package/src/generated/spacedatastandards/plg/{publication-state.ts → publicationState.ts} +0 -0
- /package/src/generated/spacedatastandards/plg/{purchase-tier.ts → purchaseTier.ts} +0 -0
|
@@ -21,6 +21,21 @@ import {
|
|
|
21
21
|
decodePlgManifest,
|
|
22
22
|
isPlgManifestBuffer,
|
|
23
23
|
} from "../manifest/plgCodec.js";
|
|
24
|
+
import {
|
|
25
|
+
isPayloadSchemaHashValid,
|
|
26
|
+
payloadSchemaIdentitiesEqual,
|
|
27
|
+
} from "../manifest/typeRefs.js";
|
|
28
|
+
import { isLegacyWildcardPort } from "./legacyWildcardPorts.js";
|
|
29
|
+
import { SDS_MANIFEST_SECTION_NAME } from "../bundle/constants.js";
|
|
30
|
+
import {
|
|
31
|
+
decodeUnsignedLeb128,
|
|
32
|
+
getWasmCustomSections,
|
|
33
|
+
parseWasmModuleSections,
|
|
34
|
+
} from "../bundle/wasm.js";
|
|
35
|
+
import {
|
|
36
|
+
extractPublicationRecordCollection,
|
|
37
|
+
stripPublicationRecordCollection,
|
|
38
|
+
} from "../transport/records.js";
|
|
24
39
|
|
|
25
40
|
const RecommendedCapabilitySet = new Set(RecommendedCapabilityIds);
|
|
26
41
|
const StandaloneWasiCapabilitySet = new Set(StandaloneWasiCapabilityIds);
|
|
@@ -42,7 +57,6 @@ const BrowserIncompatibleCapabilitySet = new Set([
|
|
|
42
57
|
"mqtt",
|
|
43
58
|
"tls",
|
|
44
59
|
"database",
|
|
45
|
-
"storage_adapter",
|
|
46
60
|
"storage_write",
|
|
47
61
|
"protocol_dial",
|
|
48
62
|
"protocol_handle",
|
|
@@ -97,57 +111,6 @@ function hasNonEmptyByteSequence(value) {
|
|
|
97
111
|
return false;
|
|
98
112
|
}
|
|
99
113
|
|
|
100
|
-
function normalizeTypeIdentityString(value) {
|
|
101
|
-
if (!isNonEmptyString(value)) {
|
|
102
|
-
return null;
|
|
103
|
-
}
|
|
104
|
-
return value.trim().toLowerCase();
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function normalizeTypeIdentityBytes(value) {
|
|
108
|
-
if (typeof value === "string") {
|
|
109
|
-
const trimmed = value.trim().toLowerCase();
|
|
110
|
-
return trimmed.length > 0 ? trimmed : null;
|
|
111
|
-
}
|
|
112
|
-
const bytes = ArrayBuffer.isView(value)
|
|
113
|
-
? Array.from(value)
|
|
114
|
-
: Array.isArray(value)
|
|
115
|
-
? value
|
|
116
|
-
: null;
|
|
117
|
-
if (!bytes || bytes.length === 0) {
|
|
118
|
-
return null;
|
|
119
|
-
}
|
|
120
|
-
return bytes
|
|
121
|
-
.map((entry) => Number(entry).toString(16).padStart(2, "0"))
|
|
122
|
-
.join("");
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function allowedTypesReferToSameLogicalSchema(left, right) {
|
|
126
|
-
const leftSchemaName = normalizeTypeIdentityString(left?.schemaName);
|
|
127
|
-
const rightSchemaName = normalizeTypeIdentityString(right?.schemaName);
|
|
128
|
-
if (leftSchemaName && rightSchemaName && leftSchemaName === rightSchemaName) {
|
|
129
|
-
return true;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const leftFileIdentifier = normalizeTypeIdentityString(left?.fileIdentifier);
|
|
133
|
-
const rightFileIdentifier = normalizeTypeIdentityString(right?.fileIdentifier);
|
|
134
|
-
if (
|
|
135
|
-
leftFileIdentifier &&
|
|
136
|
-
rightFileIdentifier &&
|
|
137
|
-
leftFileIdentifier === rightFileIdentifier
|
|
138
|
-
) {
|
|
139
|
-
return true;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const leftSchemaHash = normalizeTypeIdentityBytes(left?.schemaHash);
|
|
143
|
-
const rightSchemaHash = normalizeTypeIdentityBytes(right?.schemaHash);
|
|
144
|
-
if (leftSchemaHash && rightSchemaHash && leftSchemaHash === rightSchemaHash) {
|
|
145
|
-
return true;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return false;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
114
|
function normalizePayloadWireFormatName(value) {
|
|
152
115
|
if (value === undefined || value === null || value === "") {
|
|
153
116
|
return "flatbuffer";
|
|
@@ -319,6 +282,263 @@ function normalizeProtocolRole(value) {
|
|
|
319
282
|
return normalized;
|
|
320
283
|
}
|
|
321
284
|
|
|
285
|
+
/* ------------------------------------------------------------------------- *
|
|
286
|
+
* WILDCARD PORT BOUNDARY — ruled 2026-07-29 (P1 `upstream-module-sdk-1`).
|
|
287
|
+
*
|
|
288
|
+
* `acceptsAnyFlatbuffer` is a wildcard: the port declares that it does not know
|
|
289
|
+
* its payload's SDS identity. Both halves of that are real, so the boundary is
|
|
290
|
+
* mechanical, not editorial:
|
|
291
|
+
*
|
|
292
|
+
* TIER A — PERMITTED, nothing to declare. The manifest PROVES it is
|
|
293
|
+
* application-blind at the HOST boundary: it declares an `externalInterfaces`
|
|
294
|
+
* entry of kind `host-service` whose `capability` it also declares in
|
|
295
|
+
* `capabilities`. Such a port's payload is defined by a HOST OP, not by SDS
|
|
296
|
+
* (`hostcap/http-request`, `storage-ingest`, `clock`, `random`, `file`,
|
|
297
|
+
* `flatsql-query`, `p2p-discovery`, `data-source/retrieval`'s polymorphic row
|
|
298
|
+
* stream). Compiled flows inherit their dependencies' host-service interfaces,
|
|
299
|
+
* so the flow compiler's OWN synthesized wildcard ports (wildcardPortDefinition)
|
|
300
|
+
* validate here with no change to compiler output and no artifact hash churn.
|
|
301
|
+
*
|
|
302
|
+
* TIER B — PERMITTED when justified. A schema-aware module with a genuinely
|
|
303
|
+
* untyped port declares `acceptedTypeSet.wildcardJustification = {kind, detail,
|
|
304
|
+
* mediaType?}`, mirroring `sequentialJustification`: closed kind enum, each
|
|
305
|
+
* kind carrying a predicate this checker enforces, `detail` substantive, and
|
|
306
|
+
* `mediaType` (foreign/control frames) rejected outright when it is
|
|
307
|
+
* FlatBuffer/SDS-bearing — you cannot claim "no SDS identity" while carrying
|
|
308
|
+
* an SDS record.
|
|
309
|
+
*
|
|
310
|
+
* TIER C — WARNING. The (pluginId, methodId, direction, portId) is in the frozen
|
|
311
|
+
* legacy ledger (`legacyWildcardPorts.js`): shipped and hash-frozen before this
|
|
312
|
+
* rule existed. Shrink-only debt, not permission.
|
|
313
|
+
*
|
|
314
|
+
* TIER D — ERROR `wildcard-port-type`, unchanged. This is what correctly forced
|
|
315
|
+
* the CCSDS 124 codec (`capabilities: []`, `externalInterfaces: []`, not in the
|
|
316
|
+
* ledger) to declare typed `$CPS`/`$SPP` ports instead of shipping a wildcard.
|
|
317
|
+
*
|
|
318
|
+
* TWO LIMITS, STATED RATHER THAN HIDDEN:
|
|
319
|
+
*
|
|
320
|
+
* 1. Tier A is MANIFEST-scoped, not port-scoped: one matching host-service
|
|
321
|
+
* interface permits every wildcard port of every method in that manifest. So
|
|
322
|
+
* adding a host-service capability is a THIRD exit from the legacy ledger
|
|
323
|
+
* alongside "declare the type" and "declare a justification", and a product
|
|
324
|
+
* module that later acquires one stops warning about ports that do carry an
|
|
325
|
+
* SDS identity. Scoping Tier A to the methods that actually bind the
|
|
326
|
+
* interface is tracked, not done here.
|
|
327
|
+
* 2. The Tier A proof lives only in the JSON manifest. `externalInterfaces` is
|
|
328
|
+
* NOT representable in the embedded FlatBuffer manifest (see
|
|
329
|
+
* `src/manifest/normalize.js`), so a verifier holding only the compiled
|
|
330
|
+
* `.wasm` cannot reproduce this verdict — `capabilities` is embedded, the
|
|
331
|
+
* interfaces are not.
|
|
332
|
+
* ------------------------------------------------------------------------- */
|
|
333
|
+
|
|
334
|
+
export const WildcardJustificationKind = Object.freeze({
|
|
335
|
+
/** Payload is defined by a host capability op, not by SDS. */
|
|
336
|
+
HostBoundaryOpaque: "host-boundary-opaque",
|
|
337
|
+
/** Payload is an external, non-SDS wire format (CSV/TLE/vendor JSON/...). */
|
|
338
|
+
ForeignWireFormat: "foreign-wire-format",
|
|
339
|
+
/** Control frame produced and consumed inside one flow; never persisted. */
|
|
340
|
+
IntraFlowControlFrame: "intra-flow-control-frame",
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
const WildcardJustificationKindSet = new Set(
|
|
344
|
+
Object.values(WildcardJustificationKind),
|
|
345
|
+
);
|
|
346
|
+
|
|
347
|
+
const WildcardJustificationKindsRequiringMediaType = new Set([
|
|
348
|
+
WildcardJustificationKind.ForeignWireFormat,
|
|
349
|
+
WildcardJustificationKind.IntraFlowControlFrame,
|
|
350
|
+
]);
|
|
351
|
+
|
|
352
|
+
const WILDCARD_JUSTIFICATION_MIN_DETAIL_LENGTH = 24;
|
|
353
|
+
|
|
354
|
+
const MediaTypePattern =
|
|
355
|
+
/^[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]*\/[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]*(?:;[\x20-\x7e]*)?$/;
|
|
356
|
+
|
|
357
|
+
function mediaTypeCarriesSdsFlatbuffer(mediaType) {
|
|
358
|
+
const value = String(mediaType).toLowerCase();
|
|
359
|
+
return (
|
|
360
|
+
value.includes("flatbuffer") ||
|
|
361
|
+
value.startsWith("application/vnd.sds") ||
|
|
362
|
+
value.startsWith("application/vnd.spacedatastandards")
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// "I decline to name the format" is the evasion the wildcard rule exists to
|
|
367
|
+
// stop, so a justification that claims a FOREIGN wire format must name a
|
|
368
|
+
// specific one. A catch-all media type says nothing a bare wildcard did not.
|
|
369
|
+
const OpaqueMediaTypes = new Set([
|
|
370
|
+
"*/*",
|
|
371
|
+
"application/*",
|
|
372
|
+
"application/binary",
|
|
373
|
+
"application/octet-stream",
|
|
374
|
+
"application/x-binary",
|
|
375
|
+
"application/unknown",
|
|
376
|
+
"binary/octet-stream",
|
|
377
|
+
]);
|
|
378
|
+
|
|
379
|
+
function mediaTypeIsOpaque(mediaType) {
|
|
380
|
+
const value = String(mediaType).split(";")[0].trim().toLowerCase();
|
|
381
|
+
return OpaqueMediaTypes.has(value);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* TIER A predicate. True when the manifest mechanically proves that its ports
|
|
386
|
+
* face a HOST capability op rather than an SDS identity.
|
|
387
|
+
*
|
|
388
|
+
* @param {unknown} manifest
|
|
389
|
+
* @returns {boolean}
|
|
390
|
+
*/
|
|
391
|
+
export function manifestDeclaresHostBoundaryBlindness(manifest) {
|
|
392
|
+
if (!manifest || typeof manifest !== "object" || Array.isArray(manifest)) {
|
|
393
|
+
return false;
|
|
394
|
+
}
|
|
395
|
+
const interfaces = manifest.externalInterfaces;
|
|
396
|
+
if (!Array.isArray(interfaces)) {
|
|
397
|
+
return false;
|
|
398
|
+
}
|
|
399
|
+
// Capabilities are legal in BOTH forms — a bare id string, or a host
|
|
400
|
+
// capability record — so compare against the normalized id, not the raw
|
|
401
|
+
// entry. Comparing raw made a record-form manifest fail Tier A.
|
|
402
|
+
const declaredCapabilities = (
|
|
403
|
+
Array.isArray(manifest.capabilities) ? manifest.capabilities : []
|
|
404
|
+
)
|
|
405
|
+
.map((capability) =>
|
|
406
|
+
isNonEmptyString(capability)
|
|
407
|
+
? capability
|
|
408
|
+
: capability &&
|
|
409
|
+
typeof capability === "object" &&
|
|
410
|
+
!Array.isArray(capability) &&
|
|
411
|
+
isNonEmptyString(capability.capability)
|
|
412
|
+
? capability.capability
|
|
413
|
+
: null,
|
|
414
|
+
)
|
|
415
|
+
.filter((capability) => capability !== null);
|
|
416
|
+
return interfaces.some(
|
|
417
|
+
(entry) =>
|
|
418
|
+
entry &&
|
|
419
|
+
typeof entry === "object" &&
|
|
420
|
+
!Array.isArray(entry) &&
|
|
421
|
+
entry.kind === ExternalInterfaceKind.HOST_SERVICE &&
|
|
422
|
+
isNonEmptyString(entry.capability) &&
|
|
423
|
+
declaredCapabilities.includes(entry.capability),
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* TIER B. Validates `acceptedTypeSet.wildcardJustification` and enforces its
|
|
429
|
+
* kind predicate.
|
|
430
|
+
*
|
|
431
|
+
* @returns {boolean} true when the justification permits the wildcard.
|
|
432
|
+
*/
|
|
433
|
+
function validateWildcardJustification(justification, issues, location, context) {
|
|
434
|
+
const declare =
|
|
435
|
+
'Declare acceptedTypeSet.wildcardJustification = { "kind": <one of ' +
|
|
436
|
+
[...WildcardJustificationKindSet].map((kind) => `"${kind}"`).join(", ") +
|
|
437
|
+
'>, "detail": "<why this payload has no SDS identity>" } (kinds ' +
|
|
438
|
+
`"${WildcardJustificationKind.ForeignWireFormat}" and ` +
|
|
439
|
+
`"${WildcardJustificationKind.IntraFlowControlFrame}" also require "mediaType").`;
|
|
440
|
+
|
|
441
|
+
if (
|
|
442
|
+
!justification ||
|
|
443
|
+
typeof justification !== "object" ||
|
|
444
|
+
Array.isArray(justification)
|
|
445
|
+
) {
|
|
446
|
+
pushIssue(
|
|
447
|
+
issues,
|
|
448
|
+
"error",
|
|
449
|
+
"invalid-wildcard-justification",
|
|
450
|
+
`wildcardJustification must be an object, got ${
|
|
451
|
+
Array.isArray(justification) ? "an array" : typeof justification
|
|
452
|
+
}. ${declare}`,
|
|
453
|
+
`${location}.wildcardJustification`,
|
|
454
|
+
);
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
let valid = true;
|
|
459
|
+
const { kind, detail, mediaType } = justification;
|
|
460
|
+
|
|
461
|
+
if (!WildcardJustificationKindSet.has(kind)) {
|
|
462
|
+
pushIssue(
|
|
463
|
+
issues,
|
|
464
|
+
"error",
|
|
465
|
+
"invalid-wildcard-justification",
|
|
466
|
+
`wildcardJustification.kind ${JSON.stringify(kind)} is not recognised. ${declare}`,
|
|
467
|
+
`${location}.wildcardJustification.kind`,
|
|
468
|
+
);
|
|
469
|
+
valid = false;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
if (
|
|
473
|
+
!isNonEmptyString(detail) ||
|
|
474
|
+
detail.trim().length < WILDCARD_JUSTIFICATION_MIN_DETAIL_LENGTH
|
|
475
|
+
) {
|
|
476
|
+
pushIssue(
|
|
477
|
+
issues,
|
|
478
|
+
"error",
|
|
479
|
+
"invalid-wildcard-justification",
|
|
480
|
+
"wildcardJustification.detail must be a substantive explanation of at least " +
|
|
481
|
+
`${WILDCARD_JUSTIFICATION_MIN_DETAIL_LENGTH} characters naming the payload this port carries.`,
|
|
482
|
+
`${location}.wildcardJustification.detail`,
|
|
483
|
+
);
|
|
484
|
+
valid = false;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
if (WildcardJustificationKindsRequiringMediaType.has(kind)) {
|
|
488
|
+
if (!isNonEmptyString(mediaType) || !MediaTypePattern.test(mediaType)) {
|
|
489
|
+
pushIssue(
|
|
490
|
+
issues,
|
|
491
|
+
"error",
|
|
492
|
+
"invalid-wildcard-justification",
|
|
493
|
+
`wildcardJustification.kind "${kind}" requires mediaType as a "type/subtype" media type naming the non-SDS payload.`,
|
|
494
|
+
`${location}.wildcardJustification.mediaType`,
|
|
495
|
+
);
|
|
496
|
+
valid = false;
|
|
497
|
+
} else if (mediaTypeCarriesSdsFlatbuffer(mediaType)) {
|
|
498
|
+
pushIssue(
|
|
499
|
+
issues,
|
|
500
|
+
"error",
|
|
501
|
+
"unsupported-wildcard-justification",
|
|
502
|
+
`wildcardJustification.mediaType "${mediaType}" is a FlatBuffer/SDS media type: a port carrying an SDS record must declare that record's concrete identity, not a wildcard.`,
|
|
503
|
+
`${location}.wildcardJustification.mediaType`,
|
|
504
|
+
);
|
|
505
|
+
valid = false;
|
|
506
|
+
} else if (mediaTypeIsOpaque(mediaType)) {
|
|
507
|
+
pushIssue(
|
|
508
|
+
issues,
|
|
509
|
+
"error",
|
|
510
|
+
"unsupported-wildcard-justification",
|
|
511
|
+
`wildcardJustification.mediaType "${mediaType}" is a catch-all: naming the SPECIFIC non-SDS format the port carries is the entire point of this justification kind.`,
|
|
512
|
+
`${location}.wildcardJustification.mediaType`,
|
|
513
|
+
);
|
|
514
|
+
valid = false;
|
|
515
|
+
}
|
|
516
|
+
} else if (mediaType !== undefined) {
|
|
517
|
+
validateOptionalStringField(
|
|
518
|
+
issues,
|
|
519
|
+
mediaType,
|
|
520
|
+
`${location}.wildcardJustification.mediaType`,
|
|
521
|
+
"wildcardJustification mediaType",
|
|
522
|
+
);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
if (
|
|
526
|
+
kind === WildcardJustificationKind.HostBoundaryOpaque &&
|
|
527
|
+
context?.hostBoundaryBlind !== true
|
|
528
|
+
) {
|
|
529
|
+
pushIssue(
|
|
530
|
+
issues,
|
|
531
|
+
"error",
|
|
532
|
+
"unsupported-wildcard-justification",
|
|
533
|
+
`wildcardJustification.kind "${WildcardJustificationKind.HostBoundaryOpaque}" requires the manifest to declare an externalInterfaces entry of kind "${ExternalInterfaceKind.HOST_SERVICE}" whose capability is also declared in manifest.capabilities.`,
|
|
534
|
+
`${location}.wildcardJustification.kind`,
|
|
535
|
+
);
|
|
536
|
+
valid = false;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
return valid;
|
|
540
|
+
}
|
|
541
|
+
|
|
322
542
|
function validateAllowedType(type, issues, location) {
|
|
323
543
|
if (!type || typeof type !== "object" || Array.isArray(type)) {
|
|
324
544
|
pushIssue(issues, "error", "invalid-type-record", "Allowed type entries must be objects.", location);
|
|
@@ -335,6 +555,27 @@ function validateAllowedType(type, issues, location) {
|
|
|
335
555
|
);
|
|
336
556
|
return;
|
|
337
557
|
}
|
|
558
|
+
if (!isPayloadSchemaHashValid(type.schemaHash)) {
|
|
559
|
+
pushIssue(
|
|
560
|
+
issues,
|
|
561
|
+
"error",
|
|
562
|
+
"invalid-schema-hash",
|
|
563
|
+
"Allowed type schemaHash must be an even-length hexadecimal string or a byte sequence containing only integers from 0 through 255.",
|
|
564
|
+
`${location}.schemaHash`,
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
if (
|
|
568
|
+
isNonEmptyString(type.fileIdentifier) &&
|
|
569
|
+
!/^[\x20-\x7e]{4}$/.test(type.fileIdentifier)
|
|
570
|
+
) {
|
|
571
|
+
pushIssue(
|
|
572
|
+
issues,
|
|
573
|
+
"error",
|
|
574
|
+
"invalid-file-identifier",
|
|
575
|
+
"Allowed type fileIdentifier must contain exactly four printable ASCII bytes.",
|
|
576
|
+
`${location}.fileIdentifier`,
|
|
577
|
+
);
|
|
578
|
+
}
|
|
338
579
|
if (wireFormat === "aligned-binary") {
|
|
339
580
|
if (type.acceptsAnyFlatbuffer === true) {
|
|
340
581
|
pushIssue(
|
|
@@ -354,6 +595,15 @@ function validateAllowedType(type, issues, location) {
|
|
|
354
595
|
`${location}.schemaName`,
|
|
355
596
|
);
|
|
356
597
|
}
|
|
598
|
+
if (!isNonEmptyString(type.fileIdentifier)) {
|
|
599
|
+
pushIssue(
|
|
600
|
+
issues,
|
|
601
|
+
"error",
|
|
602
|
+
"missing-aligned-file-identifier",
|
|
603
|
+
"Aligned-binary allowed types must declare fileIdentifier.",
|
|
604
|
+
`${location}.fileIdentifier`,
|
|
605
|
+
);
|
|
606
|
+
}
|
|
357
607
|
if (!isNonEmptyString(type.rootTypeName)) {
|
|
358
608
|
pushIssue(
|
|
359
609
|
issues,
|
|
@@ -363,27 +613,63 @@ function validateAllowedType(type, issues, location) {
|
|
|
363
613
|
`${location}.rootTypeName`,
|
|
364
614
|
);
|
|
365
615
|
}
|
|
616
|
+
validateOptionalStringField(
|
|
617
|
+
issues,
|
|
618
|
+
type.schemaVersion,
|
|
619
|
+
`${location}.schemaVersion`,
|
|
620
|
+
"Allowed type schemaVersion",
|
|
621
|
+
);
|
|
366
622
|
validateOptionalIntegerField(
|
|
367
623
|
issues,
|
|
368
624
|
type.fixedStringLength,
|
|
369
625
|
`${location}.fixedStringLength`,
|
|
370
626
|
"Allowed type fixedStringLength",
|
|
371
|
-
{ min: 0 },
|
|
627
|
+
{ min: 0, max: 0xffff },
|
|
372
628
|
);
|
|
629
|
+
// byteLength DECLARES A FIXED RECORD STRIDE. It is optional, because
|
|
630
|
+
// "aligned-binary" carries two distinct shapes and only one of them has a
|
|
631
|
+
// stride:
|
|
632
|
+
//
|
|
633
|
+
// fixed record — byteLength = N: every frame is exactly N bytes, so the
|
|
634
|
+
// shared arena can be indexed by stride and the frame size
|
|
635
|
+
// is checked against it.
|
|
636
|
+
// aligned stream — byteLength absent: a variable-length run of bytes that
|
|
637
|
+
// must START on requiredAlignment (a size-prefixed
|
|
638
|
+
// FlatBuffer segment, a JSON control frame, an opaque byte
|
|
639
|
+
// route). There is no stride to declare and inventing one
|
|
640
|
+
// would be a false claim.
|
|
641
|
+
//
|
|
642
|
+
// Requiring it made the second shape inexpressible while 149 declarations
|
|
643
|
+
// across the shipped module fleet used exactly that shape — every flow that
|
|
644
|
+
// contained one failed `flow check` with "byteLength must be an integer".
|
|
645
|
+
// requiredAlignment stays MANDATORY: it is the property that makes the
|
|
646
|
+
// frame placeable in the arena at all.
|
|
373
647
|
validateOptionalIntegerField(
|
|
374
648
|
issues,
|
|
375
649
|
type.byteLength,
|
|
376
650
|
`${location}.byteLength`,
|
|
377
651
|
"Aligned-binary allowed type byteLength",
|
|
378
|
-
{ min: 1 },
|
|
652
|
+
{ min: 1, max: 0xffffffff },
|
|
379
653
|
);
|
|
380
|
-
validateIntegerField(
|
|
654
|
+
const alignmentValid = validateIntegerField(
|
|
381
655
|
issues,
|
|
382
656
|
type.requiredAlignment,
|
|
383
657
|
`${location}.requiredAlignment`,
|
|
384
658
|
"Aligned-binary allowed type requiredAlignment",
|
|
385
|
-
{ min: 1 },
|
|
659
|
+
{ min: 1, max: 0xffff },
|
|
386
660
|
);
|
|
661
|
+
if (
|
|
662
|
+
alignmentValid &&
|
|
663
|
+
!Number.isInteger(Math.log2(type.requiredAlignment))
|
|
664
|
+
) {
|
|
665
|
+
pushIssue(
|
|
666
|
+
issues,
|
|
667
|
+
"error",
|
|
668
|
+
"invalid-aligned-layout",
|
|
669
|
+
"Aligned-binary requiredAlignment must be a power of two.",
|
|
670
|
+
`${location}.requiredAlignment`,
|
|
671
|
+
);
|
|
672
|
+
}
|
|
387
673
|
return;
|
|
388
674
|
}
|
|
389
675
|
if (type.acceptsAnyFlatbuffer === true) {
|
|
@@ -402,30 +688,63 @@ function validateAllowedType(type, issues, location) {
|
|
|
402
688
|
location,
|
|
403
689
|
);
|
|
404
690
|
}
|
|
691
|
+
if (!isNonEmptyString(type.schemaName)) {
|
|
692
|
+
pushIssue(
|
|
693
|
+
issues,
|
|
694
|
+
"error",
|
|
695
|
+
"missing-canonical-schema-name",
|
|
696
|
+
"Canonical FlatBuffer allowed types must declare schemaName.",
|
|
697
|
+
`${location}.schemaName`,
|
|
698
|
+
);
|
|
699
|
+
}
|
|
700
|
+
if (!isNonEmptyString(type.fileIdentifier)) {
|
|
701
|
+
pushIssue(
|
|
702
|
+
issues,
|
|
703
|
+
"error",
|
|
704
|
+
"missing-canonical-file-identifier",
|
|
705
|
+
"Canonical FlatBuffer allowed types must declare fileIdentifier.",
|
|
706
|
+
`${location}.fileIdentifier`,
|
|
707
|
+
);
|
|
708
|
+
}
|
|
709
|
+
if (!isNonEmptyString(type.rootTypeName)) {
|
|
710
|
+
pushIssue(
|
|
711
|
+
issues,
|
|
712
|
+
"error",
|
|
713
|
+
"missing-canonical-root-type-name",
|
|
714
|
+
"Canonical FlatBuffer allowed types must declare rootTypeName.",
|
|
715
|
+
`${location}.rootTypeName`,
|
|
716
|
+
);
|
|
717
|
+
}
|
|
718
|
+
validateOptionalStringField(
|
|
719
|
+
issues,
|
|
720
|
+
type.schemaVersion,
|
|
721
|
+
`${location}.schemaVersion`,
|
|
722
|
+
"Allowed type schemaVersion",
|
|
723
|
+
);
|
|
405
724
|
validateOptionalIntegerField(
|
|
406
725
|
issues,
|
|
407
726
|
type.fixedStringLength,
|
|
408
727
|
`${location}.fixedStringLength`,
|
|
409
728
|
"Allowed type fixedStringLength",
|
|
410
|
-
{ min: 0 },
|
|
729
|
+
{ min: 0, max: 0xffff },
|
|
411
730
|
);
|
|
412
731
|
validateOptionalIntegerField(
|
|
413
732
|
issues,
|
|
414
733
|
type.byteLength,
|
|
415
734
|
`${location}.byteLength`,
|
|
416
735
|
"Allowed type byteLength",
|
|
417
|
-
{ min: 0 },
|
|
736
|
+
{ min: 0, max: 0xffffffff },
|
|
418
737
|
);
|
|
419
738
|
validateOptionalIntegerField(
|
|
420
739
|
issues,
|
|
421
740
|
type.requiredAlignment,
|
|
422
741
|
`${location}.requiredAlignment`,
|
|
423
742
|
"Allowed type requiredAlignment",
|
|
424
|
-
{ min: 0 },
|
|
743
|
+
{ min: 0, max: 0xffff },
|
|
425
744
|
);
|
|
426
745
|
}
|
|
427
746
|
|
|
428
|
-
function validateAcceptedTypeSet(typeSet, issues, location) {
|
|
747
|
+
function validateAcceptedTypeSet(typeSet, issues, location, context) {
|
|
429
748
|
if (!typeSet || typeof typeSet !== "object" || Array.isArray(typeSet)) {
|
|
430
749
|
pushIssue(issues, "error", "invalid-type-set", "Accepted type sets must be objects.", location);
|
|
431
750
|
return;
|
|
@@ -445,8 +764,9 @@ function validateAcceptedTypeSet(typeSet, issues, location) {
|
|
|
445
764
|
validateAllowedType(allowedType, issues, `${location}.allowedTypes[${index}]`);
|
|
446
765
|
});
|
|
447
766
|
|
|
448
|
-
const
|
|
767
|
+
const canonicalTypes = [];
|
|
449
768
|
const alignedTypes = [];
|
|
769
|
+
const wildcardTypes = [];
|
|
450
770
|
|
|
451
771
|
typeSet.allowedTypes.forEach((allowedType, index) => {
|
|
452
772
|
const wireFormat = normalizePayloadWireFormatName(allowedType?.wireFormat);
|
|
@@ -454,28 +774,167 @@ function validateAcceptedTypeSet(typeSet, issues, location) {
|
|
|
454
774
|
alignedTypes.push({ allowedType, index });
|
|
455
775
|
return;
|
|
456
776
|
}
|
|
457
|
-
if (wireFormat === "flatbuffer" && allowedType?.acceptsAnyFlatbuffer
|
|
458
|
-
|
|
777
|
+
if (wireFormat === "flatbuffer" && allowedType?.acceptsAnyFlatbuffer === true) {
|
|
778
|
+
wildcardTypes.push({ allowedType, index });
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
if (wireFormat === "flatbuffer") {
|
|
782
|
+
canonicalTypes.push({ allowedType, index });
|
|
459
783
|
}
|
|
460
784
|
});
|
|
461
785
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
786
|
+
const declaredWireFormats =
|
|
787
|
+
typeSet.allowedWireFormats ??
|
|
788
|
+
typeSet.allowed_wire_formats ??
|
|
789
|
+
typeSet.ALLOWED_WIRE_FORMATS;
|
|
790
|
+
if (declaredWireFormats !== undefined) {
|
|
791
|
+
const normalized = Array.isArray(declaredWireFormats)
|
|
792
|
+
? declaredWireFormats.map(normalizePayloadWireFormatName)
|
|
793
|
+
: [];
|
|
794
|
+
const unique = new Set(normalized);
|
|
795
|
+
if (
|
|
796
|
+
!Array.isArray(declaredWireFormats) ||
|
|
797
|
+
normalized.some((value) => value === null) ||
|
|
798
|
+
normalized.length !== 2 ||
|
|
799
|
+
unique.size !== 2 ||
|
|
800
|
+
!unique.has("flatbuffer") ||
|
|
801
|
+
!unique.has("aligned-binary")
|
|
802
|
+
) {
|
|
803
|
+
pushIssue(
|
|
804
|
+
issues,
|
|
805
|
+
"error",
|
|
806
|
+
"allowed-wire-formats-mismatch",
|
|
807
|
+
"acceptedTypeSet.allowedWireFormats, when present, must declare exactly flatbuffer and aligned-binary to match the required type pair.",
|
|
808
|
+
`${location}.allowedWireFormats`,
|
|
809
|
+
);
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
if (wildcardTypes.length > 0) {
|
|
814
|
+
// See "WILDCARD PORT BOUNDARY" above: Tier A permitted, Tier B justified,
|
|
815
|
+
// Tier C frozen legacy debt (warning), Tier D error.
|
|
816
|
+
const hostBoundaryBlind = context?.hostBoundaryBlind === true;
|
|
817
|
+
const hasJustification = typeSet.wildcardJustification !== undefined;
|
|
818
|
+
let permitted = hostBoundaryBlind;
|
|
819
|
+
|
|
820
|
+
if (hasJustification) {
|
|
821
|
+
// A declared justification is ALWAYS validated, even when Tier A would
|
|
822
|
+
// have permitted the wildcard anyway — a malformed one is an error, never
|
|
823
|
+
// a silent pass.
|
|
824
|
+
permitted =
|
|
825
|
+
validateWildcardJustification(
|
|
826
|
+
typeSet.wildcardJustification,
|
|
827
|
+
issues,
|
|
828
|
+
location,
|
|
829
|
+
context,
|
|
830
|
+
) || permitted;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
if (!permitted) {
|
|
834
|
+
const legacy =
|
|
835
|
+
context?.allowLegacyWildcards !== false &&
|
|
836
|
+
isLegacyWildcardPort(
|
|
837
|
+
context?.pluginId,
|
|
838
|
+
context?.methodId,
|
|
839
|
+
context?.direction,
|
|
840
|
+
context?.portId,
|
|
841
|
+
);
|
|
842
|
+
wildcardTypes.forEach(({ index }) => {
|
|
843
|
+
if (legacy) {
|
|
844
|
+
pushIssue(
|
|
845
|
+
issues,
|
|
846
|
+
"warning",
|
|
847
|
+
"legacy-wildcard-port-type",
|
|
848
|
+
`Port "${context?.portId}" carries a wildcard (acceptsAnyFlatbuffer) that was frozen into a shipped artifact before the wildcard-port boundary landed. It is grandfathered, not permitted: declare the concrete SDS identity, or declare acceptedTypeSet.wildcardJustification, at the next rebuild.`,
|
|
849
|
+
`${location}.allowedTypes[${index}]`,
|
|
850
|
+
);
|
|
851
|
+
return;
|
|
852
|
+
}
|
|
853
|
+
pushIssue(
|
|
854
|
+
issues,
|
|
855
|
+
"error",
|
|
856
|
+
"wildcard-port-type",
|
|
857
|
+
"PLG input and output ports must declare one concrete SDS identity with canonical and aligned-binary peers; acceptsAnyFlatbuffer is not permitted.",
|
|
858
|
+
`${location}.allowedTypes[${index}]`,
|
|
859
|
+
);
|
|
860
|
+
});
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
if (canonicalTypes.length === 0 && alignedTypes.length > 0) {
|
|
865
|
+
alignedTypes.forEach(({ index }) => {
|
|
467
866
|
pushIssue(
|
|
468
867
|
issues,
|
|
469
868
|
"error",
|
|
470
869
|
"missing-flatbuffer-fallback",
|
|
471
|
-
"Aligned-binary allowed types must be paired with a
|
|
870
|
+
"Aligned-binary allowed types must be paired with a canonical FlatBuffer peer for the same SDS identity in the same acceptedTypeSet.",
|
|
871
|
+
`${location}.allowedTypes[${index}]`,
|
|
872
|
+
);
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
// THE ALIGNED PEER IS AN OPTIMIZATION, NOT A CONFORMANCE OBLIGATION.
|
|
877
|
+
//
|
|
878
|
+
// An aligned-binary type asserts a FIXED layout, and `byteLength` is not
|
|
879
|
+
// descriptive metadata about it — it is the exact frame size the compiled
|
|
880
|
+
// router enforces (flow_runtime.cpp route_output rejects any frame where
|
|
881
|
+
// `out.length != edge.aligned_byte_length`). Most SDS records are
|
|
882
|
+
// variable-length: $OEM carries EPHEMERIS_DATA_BLOCK[], $OMM/$OCM/$OBD/$ACW
|
|
883
|
+
// are likewise unbounded. There is no honest number to write for them.
|
|
884
|
+
// Writing one anyway is a lie the runtime enforces; writing 0 produces an
|
|
885
|
+
// edge that rejects every frame it is given.
|
|
886
|
+
//
|
|
887
|
+
// Requiring an aligned peer on EVERY canonical type therefore forced every
|
|
888
|
+
// hand-written manifest to declare a layout it could not honour, and then
|
|
889
|
+
// failed it for declaring it incompletely — which is why no shipped manifest
|
|
890
|
+
// in space-data-network-modules passed. (The declarations were inert anyway:
|
|
891
|
+
// the flow compiler only sets alignedEligible when BOTH ends supply a
|
|
892
|
+
// complete layout, so every OD app edge already compiled alignedEligible
|
|
893
|
+
// false.)
|
|
894
|
+
//
|
|
895
|
+
// Ruled: a canonical-only accepted type set is LEGAL. Declaring the aligned
|
|
896
|
+
// peer is opt-in, and once declared it must be COMPLETE — byteLength and a
|
|
897
|
+
// power-of-two requiredAlignment, both still errors above. The converse
|
|
898
|
+
// stays an error too: an aligned type without a canonical fallback has no
|
|
899
|
+
// way to cross a boundary that cannot take the shared arena.
|
|
900
|
+
if (alignedTypes.length === 0 && canonicalTypes.length > 0) {
|
|
901
|
+
canonicalTypes.forEach(({ index }) => {
|
|
902
|
+
pushIssue(
|
|
903
|
+
issues,
|
|
904
|
+
"warning",
|
|
905
|
+
"no-aligned-peer",
|
|
906
|
+
"Canonical FlatBuffer allowed type declares no aligned-binary peer, so this port never takes the shared-arena zero-copy route. That is correct for a variable-length record; declare the peer (with its exact byteLength) only if the record has a FIXED aligned layout.",
|
|
472
907
|
`${location}.allowedTypes[${index}]`,
|
|
473
908
|
);
|
|
909
|
+
});
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
if (canonicalTypes.length > 1 || alignedTypes.length > 1) {
|
|
913
|
+
pushIssue(
|
|
914
|
+
issues,
|
|
915
|
+
"error",
|
|
916
|
+
"invalid-representation-pair-count",
|
|
917
|
+
"Each accepted type set must contain exactly one canonical FlatBuffer type and one aligned-binary peer.",
|
|
918
|
+
`${location}.allowedTypes`,
|
|
919
|
+
);
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
if (canonicalTypes.length === 1 && alignedTypes.length === 1) {
|
|
923
|
+
const canonicalType = canonicalTypes[0].allowedType;
|
|
924
|
+
const alignedType = alignedTypes[0].allowedType;
|
|
925
|
+
if (!payloadSchemaIdentitiesEqual(canonicalType, alignedType)) {
|
|
926
|
+
pushIssue(
|
|
927
|
+
issues,
|
|
928
|
+
"error",
|
|
929
|
+
"paired-type-identity-mismatch",
|
|
930
|
+
"Canonical FlatBuffer and aligned-binary peers must declare identical schemaName, fileIdentifier, rootTypeName, and schemaVersion/schemaHash when present.",
|
|
931
|
+
location,
|
|
932
|
+
);
|
|
474
933
|
}
|
|
475
|
-
}
|
|
934
|
+
}
|
|
476
935
|
}
|
|
477
936
|
|
|
478
|
-
function validatePort(port, issues, location, label) {
|
|
937
|
+
function validatePort(port, issues, location, label, context) {
|
|
479
938
|
if (!port || typeof port !== "object" || Array.isArray(port)) {
|
|
480
939
|
pushIssue(issues, "error", "invalid-port", `${label} entries must be objects.`, location);
|
|
481
940
|
return;
|
|
@@ -490,8 +949,22 @@ function validatePort(port, issues, location, label) {
|
|
|
490
949
|
`${location}.acceptedTypeSets`,
|
|
491
950
|
);
|
|
492
951
|
} else {
|
|
952
|
+
if (port.acceptedTypeSets.length !== 1) {
|
|
953
|
+
pushIssue(
|
|
954
|
+
issues,
|
|
955
|
+
"error",
|
|
956
|
+
"invalid-accepted-type-set-count",
|
|
957
|
+
`${label} must declare exactly one acceptedTypeSet containing its canonical and aligned-binary representation pair.`,
|
|
958
|
+
`${location}.acceptedTypeSets`,
|
|
959
|
+
);
|
|
960
|
+
}
|
|
493
961
|
port.acceptedTypeSets.forEach((typeSet, index) => {
|
|
494
|
-
validateAcceptedTypeSet(
|
|
962
|
+
validateAcceptedTypeSet(
|
|
963
|
+
typeSet,
|
|
964
|
+
issues,
|
|
965
|
+
`${location}.acceptedTypeSets[${index}]`,
|
|
966
|
+
{ ...context, portId: port.portId },
|
|
967
|
+
);
|
|
495
968
|
});
|
|
496
969
|
}
|
|
497
970
|
const minStreamsValid = validateIntegerField(
|
|
@@ -1088,8 +1561,171 @@ function validateInvokeSurfaces(invokeSurfaces, issues, sourceName) {
|
|
|
1088
1561
|
return normalized;
|
|
1089
1562
|
}
|
|
1090
1563
|
|
|
1564
|
+
function validateFlowGraph(manifest, issues, sourceName) {
|
|
1565
|
+
const arrayFields = [
|
|
1566
|
+
["flowNodes", "invalid-flow-nodes-array"],
|
|
1567
|
+
["flowEdges", "invalid-flow-edges-array"],
|
|
1568
|
+
["flowTriggers", "invalid-flow-triggers-array"],
|
|
1569
|
+
["flowTriggerBindings", "invalid-flow-trigger-bindings-array"],
|
|
1570
|
+
];
|
|
1571
|
+
for (const [field, code] of arrayFields) {
|
|
1572
|
+
if (manifest[field] !== undefined && !Array.isArray(manifest[field])) {
|
|
1573
|
+
pushIssue(
|
|
1574
|
+
issues,
|
|
1575
|
+
"error",
|
|
1576
|
+
code,
|
|
1577
|
+
`manifest.${field} must be an array when present.`,
|
|
1578
|
+
`${sourceName}.${field}`,
|
|
1579
|
+
);
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
const nodeIds = new Set();
|
|
1584
|
+
for (const [index, node] of (Array.isArray(manifest.flowNodes)
|
|
1585
|
+
? manifest.flowNodes
|
|
1586
|
+
: []).entries()) {
|
|
1587
|
+
const location = `${sourceName}.flowNodes[${index}]`;
|
|
1588
|
+
if (!node || typeof node !== "object" || Array.isArray(node)) {
|
|
1589
|
+
pushIssue(issues, "error", "invalid-flow-node", "Flow nodes must be objects.", location);
|
|
1590
|
+
continue;
|
|
1591
|
+
}
|
|
1592
|
+
if (!isNonEmptyString(node.nodeId) || !isNonEmptyString(node.pluginId)) {
|
|
1593
|
+
pushIssue(
|
|
1594
|
+
issues,
|
|
1595
|
+
"error",
|
|
1596
|
+
"invalid-flow-node",
|
|
1597
|
+
"Flow nodes must declare non-empty nodeId and pluginId fields.",
|
|
1598
|
+
location,
|
|
1599
|
+
);
|
|
1600
|
+
continue;
|
|
1601
|
+
}
|
|
1602
|
+
if (nodeIds.has(node.nodeId)) {
|
|
1603
|
+
pushIssue(
|
|
1604
|
+
issues,
|
|
1605
|
+
"error",
|
|
1606
|
+
"duplicate-flow-node-id",
|
|
1607
|
+
`Duplicate flow node id "${node.nodeId}".`,
|
|
1608
|
+
`${location}.nodeId`,
|
|
1609
|
+
);
|
|
1610
|
+
}
|
|
1611
|
+
nodeIds.add(node.nodeId);
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
for (const [index, edge] of (Array.isArray(manifest.flowEdges)
|
|
1615
|
+
? manifest.flowEdges
|
|
1616
|
+
: []).entries()) {
|
|
1617
|
+
const location = `${sourceName}.flowEdges[${index}]`;
|
|
1618
|
+
if (
|
|
1619
|
+
!edge ||
|
|
1620
|
+
typeof edge !== "object" ||
|
|
1621
|
+
Array.isArray(edge) ||
|
|
1622
|
+
!isNonEmptyString(edge.fromNodeId) ||
|
|
1623
|
+
!isNonEmptyString(edge.fromPortId) ||
|
|
1624
|
+
!isNonEmptyString(edge.toNodeId) ||
|
|
1625
|
+
!isNonEmptyString(edge.toPortId)
|
|
1626
|
+
) {
|
|
1627
|
+
pushIssue(
|
|
1628
|
+
issues,
|
|
1629
|
+
"error",
|
|
1630
|
+
"invalid-flow-edge",
|
|
1631
|
+
"Flow edges must declare non-empty fromNodeId, fromPortId, toNodeId, and toPortId fields.",
|
|
1632
|
+
location,
|
|
1633
|
+
);
|
|
1634
|
+
}
|
|
1635
|
+
for (const field of ["fromNodeId", "toNodeId"]) {
|
|
1636
|
+
if (isNonEmptyString(edge?.[field]) && !nodeIds.has(edge[field])) {
|
|
1637
|
+
pushIssue(
|
|
1638
|
+
issues,
|
|
1639
|
+
"error",
|
|
1640
|
+
"unknown-flow-node",
|
|
1641
|
+
`Flow edge references unknown node "${edge[field]}".`,
|
|
1642
|
+
`${location}.${field}`,
|
|
1643
|
+
);
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
const triggerIds = new Set();
|
|
1649
|
+
for (const [index, trigger] of (Array.isArray(manifest.flowTriggers)
|
|
1650
|
+
? manifest.flowTriggers
|
|
1651
|
+
: []).entries()) {
|
|
1652
|
+
const location = `${sourceName}.flowTriggers[${index}]`;
|
|
1653
|
+
if (
|
|
1654
|
+
!trigger ||
|
|
1655
|
+
typeof trigger !== "object" ||
|
|
1656
|
+
Array.isArray(trigger) ||
|
|
1657
|
+
!isNonEmptyString(trigger.triggerId)
|
|
1658
|
+
) {
|
|
1659
|
+
pushIssue(
|
|
1660
|
+
issues,
|
|
1661
|
+
"error",
|
|
1662
|
+
"invalid-flow-trigger",
|
|
1663
|
+
"Flow triggers must declare a non-empty triggerId.",
|
|
1664
|
+
location,
|
|
1665
|
+
);
|
|
1666
|
+
continue;
|
|
1667
|
+
}
|
|
1668
|
+
if (triggerIds.has(trigger.triggerId)) {
|
|
1669
|
+
pushIssue(
|
|
1670
|
+
issues,
|
|
1671
|
+
"error",
|
|
1672
|
+
"duplicate-flow-trigger-id",
|
|
1673
|
+
`Duplicate flow trigger id "${trigger.triggerId}".`,
|
|
1674
|
+
`${location}.triggerId`,
|
|
1675
|
+
);
|
|
1676
|
+
}
|
|
1677
|
+
triggerIds.add(trigger.triggerId);
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
for (const [index, binding] of (Array.isArray(manifest.flowTriggerBindings)
|
|
1681
|
+
? manifest.flowTriggerBindings
|
|
1682
|
+
: []).entries()) {
|
|
1683
|
+
const location = `${sourceName}.flowTriggerBindings[${index}]`;
|
|
1684
|
+
if (
|
|
1685
|
+
!binding ||
|
|
1686
|
+
typeof binding !== "object" ||
|
|
1687
|
+
Array.isArray(binding) ||
|
|
1688
|
+
!isNonEmptyString(binding.triggerId) ||
|
|
1689
|
+
!isNonEmptyString(binding.targetNodeId) ||
|
|
1690
|
+
!isNonEmptyString(binding.targetPortId)
|
|
1691
|
+
) {
|
|
1692
|
+
pushIssue(
|
|
1693
|
+
issues,
|
|
1694
|
+
"error",
|
|
1695
|
+
"invalid-flow-trigger-binding",
|
|
1696
|
+
"Flow trigger bindings must declare non-empty triggerId, targetNodeId, and targetPortId fields.",
|
|
1697
|
+
location,
|
|
1698
|
+
);
|
|
1699
|
+
}
|
|
1700
|
+
if (
|
|
1701
|
+
isNonEmptyString(binding?.triggerId) &&
|
|
1702
|
+
!triggerIds.has(binding.triggerId)
|
|
1703
|
+
) {
|
|
1704
|
+
pushIssue(
|
|
1705
|
+
issues,
|
|
1706
|
+
"error",
|
|
1707
|
+
"unknown-flow-trigger",
|
|
1708
|
+
`Flow trigger binding references unknown trigger "${binding.triggerId}".`,
|
|
1709
|
+
`${location}.triggerId`,
|
|
1710
|
+
);
|
|
1711
|
+
}
|
|
1712
|
+
if (
|
|
1713
|
+
isNonEmptyString(binding?.targetNodeId) &&
|
|
1714
|
+
!nodeIds.has(binding.targetNodeId)
|
|
1715
|
+
) {
|
|
1716
|
+
pushIssue(
|
|
1717
|
+
issues,
|
|
1718
|
+
"error",
|
|
1719
|
+
"unknown-flow-node",
|
|
1720
|
+
`Flow trigger binding references unknown node "${binding.targetNodeId}".`,
|
|
1721
|
+
`${location}.targetNodeId`,
|
|
1722
|
+
);
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1091
1727
|
export function validatePluginManifest(manifest, options = {}) {
|
|
1092
|
-
const { sourceName = "manifest" } = options;
|
|
1728
|
+
const { sourceName = "manifest", allowLegacyWildcards = true } = options;
|
|
1093
1729
|
const issues = [];
|
|
1094
1730
|
|
|
1095
1731
|
if (!manifest || typeof manifest !== "object" || Array.isArray(manifest)) {
|
|
@@ -1103,6 +1739,14 @@ export function validatePluginManifest(manifest, options = {}) {
|
|
|
1103
1739
|
});
|
|
1104
1740
|
}
|
|
1105
1741
|
|
|
1742
|
+
// Wildcard-port boundary context: resolved once per manifest, carried down to
|
|
1743
|
+
// every acceptedTypeSet. See "WILDCARD PORT BOUNDARY" above.
|
|
1744
|
+
const wildcardContext = Object.freeze({
|
|
1745
|
+
pluginId: manifest.pluginId,
|
|
1746
|
+
hostBoundaryBlind: manifestDeclaresHostBoundaryBlindness(manifest),
|
|
1747
|
+
allowLegacyWildcards: allowLegacyWildcards !== false,
|
|
1748
|
+
});
|
|
1749
|
+
|
|
1106
1750
|
validateStringField(issues, manifest.pluginId, `${sourceName}.pluginId`, "pluginId");
|
|
1107
1751
|
validateStringField(issues, manifest.name, `${sourceName}.name`, "name");
|
|
1108
1752
|
validateStringField(issues, manifest.version, `${sourceName}.version`, "version");
|
|
@@ -1215,17 +1859,23 @@ export function validatePluginManifest(manifest, options = {}) {
|
|
|
1215
1859
|
seenMethodIds.add(method.methodId);
|
|
1216
1860
|
methodLookup.set(method.methodId, method);
|
|
1217
1861
|
}
|
|
1218
|
-
if (!Array.isArray(method.inputPorts)
|
|
1862
|
+
if (!Array.isArray(method.inputPorts)) {
|
|
1219
1863
|
pushIssue(
|
|
1220
1864
|
issues,
|
|
1221
1865
|
"error",
|
|
1222
1866
|
"missing-input-ports",
|
|
1223
|
-
"Methods must declare
|
|
1867
|
+
"Methods must declare inputPorts as an array.",
|
|
1224
1868
|
`${location}.inputPorts`,
|
|
1225
1869
|
);
|
|
1226
1870
|
} else {
|
|
1227
1871
|
method.inputPorts.forEach((port, portIndex) => {
|
|
1228
|
-
validatePort(
|
|
1872
|
+
validatePort(
|
|
1873
|
+
port,
|
|
1874
|
+
issues,
|
|
1875
|
+
`${location}.inputPorts[${portIndex}]`,
|
|
1876
|
+
"Input port",
|
|
1877
|
+
{ ...wildcardContext, methodId: method.methodId, direction: "in" },
|
|
1878
|
+
);
|
|
1229
1879
|
});
|
|
1230
1880
|
}
|
|
1231
1881
|
if (!Array.isArray(method.outputPorts)) {
|
|
@@ -1238,7 +1888,13 @@ export function validatePluginManifest(manifest, options = {}) {
|
|
|
1238
1888
|
);
|
|
1239
1889
|
} else {
|
|
1240
1890
|
method.outputPorts.forEach((port, portIndex) => {
|
|
1241
|
-
validatePort(
|
|
1891
|
+
validatePort(
|
|
1892
|
+
port,
|
|
1893
|
+
issues,
|
|
1894
|
+
`${location}.outputPorts[${portIndex}]`,
|
|
1895
|
+
"Output port",
|
|
1896
|
+
{ ...wildcardContext, methodId: method.methodId, direction: "out" },
|
|
1897
|
+
);
|
|
1242
1898
|
});
|
|
1243
1899
|
}
|
|
1244
1900
|
validateIntegerField(issues, method.maxBatch, `${location}.maxBatch`, "maxBatch", {
|
|
@@ -1311,6 +1967,7 @@ export function validatePluginManifest(manifest, options = {}) {
|
|
|
1311
1967
|
issues,
|
|
1312
1968
|
sourceName,
|
|
1313
1969
|
);
|
|
1970
|
+
validateFlowGraph(manifest, issues, sourceName);
|
|
1314
1971
|
|
|
1315
1972
|
if (manifest.schemasUsed !== undefined && !Array.isArray(manifest.schemasUsed)) {
|
|
1316
1973
|
pushIssue(
|
|
@@ -1352,7 +2009,9 @@ export async function loadManifestFromFile(manifestPath) {
|
|
|
1352
2009
|
}
|
|
1353
2010
|
|
|
1354
2011
|
export function getWasmExportNames(wasmBytes) {
|
|
1355
|
-
|
|
2012
|
+
// Tolerate signed/published artifacts: strip any appended publication
|
|
2013
|
+
// record collection (signature/PNM/REC trailers) before compiling.
|
|
2014
|
+
const module = new WebAssembly.Module(stripPublicationRecordCollection(wasmBytes));
|
|
1356
2015
|
return WebAssembly.Module.exports(module).map((entry) => entry.name).sort();
|
|
1357
2016
|
}
|
|
1358
2017
|
|
|
@@ -1385,6 +2044,222 @@ function indexOfBytes(haystack, needle, startIndex = 0) {
|
|
|
1385
2044
|
return -1;
|
|
1386
2045
|
}
|
|
1387
2046
|
|
|
2047
|
+
function isPlausibleEmbeddedManifestString(value, maxLength = 512) {
|
|
2048
|
+
return (
|
|
2049
|
+
isNonEmptyString(value) &&
|
|
2050
|
+
value.length <= maxLength &&
|
|
2051
|
+
/^[\x20-\x7e]+$/.test(value)
|
|
2052
|
+
);
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
function readI32ConstExpression(bytes, offset, end) {
|
|
2056
|
+
let cursor = offset;
|
|
2057
|
+
const opcode = bytes[cursor++];
|
|
2058
|
+
if (opcode !== 0x41) {
|
|
2059
|
+
return null;
|
|
2060
|
+
}
|
|
2061
|
+
const valueInfo = decodeUnsignedLeb128(bytes, cursor);
|
|
2062
|
+
cursor = valueInfo.nextOffset;
|
|
2063
|
+
if (cursor >= end || bytes[cursor] !== 0x0b) {
|
|
2064
|
+
return null;
|
|
2065
|
+
}
|
|
2066
|
+
return { value: valueInfo.value, nextOffset: cursor + 1 };
|
|
2067
|
+
}
|
|
2068
|
+
|
|
2069
|
+
function extractWasmDataSegments(wasmBytes) {
|
|
2070
|
+
let parsed;
|
|
2071
|
+
try {
|
|
2072
|
+
parsed = parseWasmModuleSections(wasmBytes);
|
|
2073
|
+
} catch {
|
|
2074
|
+
return [];
|
|
2075
|
+
}
|
|
2076
|
+
const segments = [];
|
|
2077
|
+
for (const section of parsed.sections) {
|
|
2078
|
+
if (section.id !== 11) {
|
|
2079
|
+
continue;
|
|
2080
|
+
}
|
|
2081
|
+
const payload = parsed.bytes.subarray(section.payloadStart, section.payloadEnd);
|
|
2082
|
+
let cursor = 0;
|
|
2083
|
+
let countInfo;
|
|
2084
|
+
try {
|
|
2085
|
+
countInfo = decodeUnsignedLeb128(payload, cursor);
|
|
2086
|
+
} catch {
|
|
2087
|
+
continue;
|
|
2088
|
+
}
|
|
2089
|
+
cursor = countInfo.nextOffset;
|
|
2090
|
+
for (let index = 0; index < countInfo.value && cursor < payload.length; index += 1) {
|
|
2091
|
+
const flagsInfo = decodeUnsignedLeb128(payload, cursor);
|
|
2092
|
+
const flags = flagsInfo.value;
|
|
2093
|
+
cursor = flagsInfo.nextOffset;
|
|
2094
|
+
let memoryOffset = null;
|
|
2095
|
+
if (flags === 0) {
|
|
2096
|
+
const expression = readI32ConstExpression(payload, cursor, payload.length);
|
|
2097
|
+
if (!expression) {
|
|
2098
|
+
break;
|
|
2099
|
+
}
|
|
2100
|
+
memoryOffset = expression.value;
|
|
2101
|
+
cursor = expression.nextOffset;
|
|
2102
|
+
} else if (flags === 2) {
|
|
2103
|
+
const memoryIndexInfo = decodeUnsignedLeb128(payload, cursor);
|
|
2104
|
+
cursor = memoryIndexInfo.nextOffset;
|
|
2105
|
+
const expression = readI32ConstExpression(payload, cursor, payload.length);
|
|
2106
|
+
if (!expression) {
|
|
2107
|
+
break;
|
|
2108
|
+
}
|
|
2109
|
+
memoryOffset = expression.value;
|
|
2110
|
+
cursor = expression.nextOffset;
|
|
2111
|
+
}
|
|
2112
|
+
const sizeInfo = decodeUnsignedLeb128(payload, cursor);
|
|
2113
|
+
cursor = sizeInfo.nextOffset;
|
|
2114
|
+
const dataStart = cursor;
|
|
2115
|
+
const dataEnd = dataStart + sizeInfo.value;
|
|
2116
|
+
if (dataEnd > payload.length) {
|
|
2117
|
+
break;
|
|
2118
|
+
}
|
|
2119
|
+
segments.push({
|
|
2120
|
+
memoryOffset,
|
|
2121
|
+
bytes: payload.subarray(dataStart, dataEnd),
|
|
2122
|
+
});
|
|
2123
|
+
cursor = dataEnd;
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
2126
|
+
return segments;
|
|
2127
|
+
}
|
|
2128
|
+
|
|
2129
|
+
function concatenateWasmDataSegmentPayloads(wasmBytes) {
|
|
2130
|
+
const segments = extractWasmDataSegments(wasmBytes);
|
|
2131
|
+
if (segments.length === 0) {
|
|
2132
|
+
return null;
|
|
2133
|
+
}
|
|
2134
|
+
const totalLength = segments.reduce(
|
|
2135
|
+
(total, segment) => total + segment.bytes.length,
|
|
2136
|
+
0,
|
|
2137
|
+
);
|
|
2138
|
+
if (totalLength <= 0) {
|
|
2139
|
+
return null;
|
|
2140
|
+
}
|
|
2141
|
+
const out = new Uint8Array(totalLength);
|
|
2142
|
+
let offset = 0;
|
|
2143
|
+
for (const segment of segments) {
|
|
2144
|
+
out.set(segment.bytes, offset);
|
|
2145
|
+
offset += segment.bytes.length;
|
|
2146
|
+
}
|
|
2147
|
+
return out;
|
|
2148
|
+
}
|
|
2149
|
+
|
|
2150
|
+
function reconstructWasmDataMemoryImage(wasmBytes) {
|
|
2151
|
+
const segments = extractWasmDataSegments(wasmBytes).filter(
|
|
2152
|
+
(segment) => segment.memoryOffset !== null,
|
|
2153
|
+
);
|
|
2154
|
+
if (segments.length === 0) {
|
|
2155
|
+
return null;
|
|
2156
|
+
}
|
|
2157
|
+
const maxEnd = segments.reduce(
|
|
2158
|
+
(max, segment) => Math.max(max, segment.memoryOffset + segment.bytes.length),
|
|
2159
|
+
0,
|
|
2160
|
+
);
|
|
2161
|
+
if (!Number.isSafeInteger(maxEnd) || maxEnd <= 0) {
|
|
2162
|
+
return null;
|
|
2163
|
+
}
|
|
2164
|
+
const memory = new Uint8Array(maxEnd);
|
|
2165
|
+
for (const segment of segments) {
|
|
2166
|
+
memory.set(segment.bytes, segment.memoryOffset);
|
|
2167
|
+
}
|
|
2168
|
+
return memory;
|
|
2169
|
+
}
|
|
2170
|
+
|
|
2171
|
+
function scanForEmbeddedPlgManifest(bytes, options = {}) {
|
|
2172
|
+
const expectedPluginId =
|
|
2173
|
+
typeof options.expectedPluginId === "string" && options.expectedPluginId.length > 0
|
|
2174
|
+
? options.expectedPluginId
|
|
2175
|
+
: null;
|
|
2176
|
+
const expectedVersion =
|
|
2177
|
+
typeof options.expectedVersion === "string" && options.expectedVersion.length > 0
|
|
2178
|
+
? options.expectedVersion
|
|
2179
|
+
: null;
|
|
2180
|
+
let fallback = null;
|
|
2181
|
+
let searchStart = 0;
|
|
2182
|
+
while (searchStart < bytes.length) {
|
|
2183
|
+
const identifierOffset = indexOfBytes(
|
|
2184
|
+
bytes,
|
|
2185
|
+
PLG_IDENTIFIER_BYTES,
|
|
2186
|
+
searchStart,
|
|
2187
|
+
);
|
|
2188
|
+
if (identifierOffset === -1) {
|
|
2189
|
+
break;
|
|
2190
|
+
}
|
|
2191
|
+
searchStart = identifierOffset + PLG_IDENTIFIER_BYTES.length;
|
|
2192
|
+
if (identifierOffset < 4) {
|
|
2193
|
+
continue;
|
|
2194
|
+
}
|
|
2195
|
+
const start = identifierOffset - 4;
|
|
2196
|
+
// Upper bound on the manifest size — grab up to 64KB and let the caller
|
|
2197
|
+
// decide how much to trim. FlatBuffer decoders only read what they need.
|
|
2198
|
+
const end = Math.min(bytes.length, start + 65536);
|
|
2199
|
+
const candidate = bytes.slice(start, end);
|
|
2200
|
+
if (!isPlgManifestBuffer(candidate)) {
|
|
2201
|
+
continue;
|
|
2202
|
+
}
|
|
2203
|
+
let decoded = null;
|
|
2204
|
+
try {
|
|
2205
|
+
decoded = decodePlgManifest(candidate);
|
|
2206
|
+
} catch {
|
|
2207
|
+
continue;
|
|
2208
|
+
}
|
|
2209
|
+
if (
|
|
2210
|
+
!isPlausibleEmbeddedManifestString(decoded?.pluginId) ||
|
|
2211
|
+
!isPlausibleEmbeddedManifestString(decoded?.name) ||
|
|
2212
|
+
!isPlausibleEmbeddedManifestString(decoded?.version, 128)
|
|
2213
|
+
) {
|
|
2214
|
+
continue;
|
|
2215
|
+
}
|
|
2216
|
+
const located = { start, identifierOffset, bytes: candidate, decoded };
|
|
2217
|
+
if (
|
|
2218
|
+
(!expectedPluginId || decoded.pluginId === expectedPluginId) &&
|
|
2219
|
+
(!expectedVersion || decoded.version === expectedVersion)
|
|
2220
|
+
) {
|
|
2221
|
+
return located;
|
|
2222
|
+
}
|
|
2223
|
+
fallback ??= located;
|
|
2224
|
+
}
|
|
2225
|
+
return fallback;
|
|
2226
|
+
}
|
|
2227
|
+
|
|
2228
|
+
function decodeManifestCandidate(candidate, options = {}) {
|
|
2229
|
+
const bytes = candidate instanceof Uint8Array ? candidate.slice() : new Uint8Array(candidate);
|
|
2230
|
+
if (!isPlgManifestBuffer(bytes)) {
|
|
2231
|
+
return null;
|
|
2232
|
+
}
|
|
2233
|
+
let decoded = null;
|
|
2234
|
+
try {
|
|
2235
|
+
decoded = decodePlgManifest(bytes);
|
|
2236
|
+
} catch {
|
|
2237
|
+
return null;
|
|
2238
|
+
}
|
|
2239
|
+
if (
|
|
2240
|
+
!isPlausibleEmbeddedManifestString(decoded?.pluginId) ||
|
|
2241
|
+
!isPlausibleEmbeddedManifestString(decoded?.name) ||
|
|
2242
|
+
!isPlausibleEmbeddedManifestString(decoded?.version, 128)
|
|
2243
|
+
) {
|
|
2244
|
+
return null;
|
|
2245
|
+
}
|
|
2246
|
+
const expectedPluginId =
|
|
2247
|
+
typeof options.expectedPluginId === "string" && options.expectedPluginId.length > 0
|
|
2248
|
+
? options.expectedPluginId
|
|
2249
|
+
: null;
|
|
2250
|
+
const expectedVersion =
|
|
2251
|
+
typeof options.expectedVersion === "string" && options.expectedVersion.length > 0
|
|
2252
|
+
? options.expectedVersion
|
|
2253
|
+
: null;
|
|
2254
|
+
if (
|
|
2255
|
+
(expectedPluginId && decoded.pluginId !== expectedPluginId) ||
|
|
2256
|
+
(expectedVersion && decoded.version !== expectedVersion)
|
|
2257
|
+
) {
|
|
2258
|
+
return null;
|
|
2259
|
+
}
|
|
2260
|
+
return { start: 0, identifierOffset: 4, bytes, decoded };
|
|
2261
|
+
}
|
|
2262
|
+
|
|
1388
2263
|
/**
|
|
1389
2264
|
* Scan wasm bytes for the canonical `$PLG` FlatBuffer identifier and, when
|
|
1390
2265
|
* found, return both the raw offset and the smallest aligned candidate buffer
|
|
@@ -1393,23 +2268,49 @@ function indexOfBytes(haystack, needle, startIndex = 0) {
|
|
|
1393
2268
|
* so we walk backwards one 4-byte word and hand the caller a slice starting
|
|
1394
2269
|
* there.
|
|
1395
2270
|
*/
|
|
1396
|
-
export function locateEmbeddedPlgManifest(wasmBytes) {
|
|
1397
|
-
const
|
|
2271
|
+
export function locateEmbeddedPlgManifest(wasmBytes, options = {}) {
|
|
2272
|
+
const inputBytes = wasmBytes instanceof Uint8Array
|
|
1398
2273
|
? wasmBytes
|
|
1399
2274
|
: new Uint8Array(wasmBytes);
|
|
1400
|
-
const
|
|
1401
|
-
|
|
1402
|
-
|
|
2275
|
+
const protectedArtifact = extractPublicationRecordCollection(inputBytes);
|
|
2276
|
+
for (const entry of protectedArtifact?.mbl?.entries ?? []) {
|
|
2277
|
+
if (
|
|
2278
|
+
entry?.entryId !== "manifest" &&
|
|
2279
|
+
entry?.sectionName !== SDS_MANIFEST_SECTION_NAME
|
|
2280
|
+
) {
|
|
2281
|
+
continue;
|
|
2282
|
+
}
|
|
2283
|
+
const located = decodeManifestCandidate(
|
|
2284
|
+
new Uint8Array(entry.payload ?? []),
|
|
2285
|
+
options,
|
|
2286
|
+
);
|
|
2287
|
+
if (located) {
|
|
2288
|
+
return { ...located, source: "bundle-manifest" };
|
|
2289
|
+
}
|
|
1403
2290
|
}
|
|
1404
|
-
const
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
2291
|
+
const bytes = protectedArtifact?.payloadBytes ?? inputBytes;
|
|
2292
|
+
for (const sectionBytes of getWasmCustomSections(bytes, SDS_MANIFEST_SECTION_NAME)) {
|
|
2293
|
+
const located = decodeManifestCandidate(sectionBytes, options);
|
|
2294
|
+
if (located) {
|
|
2295
|
+
return { ...located, source: "custom-section" };
|
|
2296
|
+
}
|
|
2297
|
+
}
|
|
2298
|
+
const dataPayloads = concatenateWasmDataSegmentPayloads(bytes);
|
|
2299
|
+
if (dataPayloads) {
|
|
2300
|
+
const located = scanForEmbeddedPlgManifest(dataPayloads, options);
|
|
2301
|
+
if (located) {
|
|
2302
|
+
return { ...located, source: "data-payloads" };
|
|
2303
|
+
}
|
|
2304
|
+
}
|
|
2305
|
+
const memoryImage = reconstructWasmDataMemoryImage(bytes);
|
|
2306
|
+
if (memoryImage) {
|
|
2307
|
+
const located = scanForEmbeddedPlgManifest(memoryImage, options);
|
|
2308
|
+
if (located) {
|
|
2309
|
+
return { ...located, source: "data-memory" };
|
|
2310
|
+
}
|
|
1411
2311
|
}
|
|
1412
|
-
|
|
2312
|
+
const located = scanForEmbeddedPlgManifest(bytes, options);
|
|
2313
|
+
return located ? { ...located, source: "raw-wasm" } : null;
|
|
1413
2314
|
}
|
|
1414
2315
|
|
|
1415
2316
|
export function hasLegacyPmanManifest(wasmBytes) {
|
|
@@ -1435,7 +2336,12 @@ function validateEmbeddedManifestBytes({
|
|
|
1435
2336
|
);
|
|
1436
2337
|
}
|
|
1437
2338
|
|
|
1438
|
-
const
|
|
2339
|
+
const sourcePluginId = manifest?.pluginId ?? manifest?.plugin_id ?? null;
|
|
2340
|
+
const sourceVersion = manifest?.version ?? null;
|
|
2341
|
+
const located = locateEmbeddedPlgManifest(wasmBytes, {
|
|
2342
|
+
expectedPluginId: sourcePluginId,
|
|
2343
|
+
expectedVersion: sourceVersion,
|
|
2344
|
+
});
|
|
1439
2345
|
if (!located) {
|
|
1440
2346
|
pushIssue(
|
|
1441
2347
|
issues,
|
|
@@ -1447,9 +2353,9 @@ function validateEmbeddedManifestBytes({
|
|
|
1447
2353
|
return;
|
|
1448
2354
|
}
|
|
1449
2355
|
|
|
1450
|
-
let decoded;
|
|
2356
|
+
let decoded = located.decoded;
|
|
1451
2357
|
try {
|
|
1452
|
-
decoded
|
|
2358
|
+
decoded ??= decodePlgManifest(located.bytes);
|
|
1453
2359
|
} catch (error) {
|
|
1454
2360
|
pushIssue(
|
|
1455
2361
|
issues,
|
|
@@ -1461,7 +2367,6 @@ function validateEmbeddedManifestBytes({
|
|
|
1461
2367
|
return;
|
|
1462
2368
|
}
|
|
1463
2369
|
|
|
1464
|
-
const sourcePluginId = manifest?.pluginId ?? manifest?.plugin_id ?? null;
|
|
1465
2370
|
if (
|
|
1466
2371
|
isNonEmptyString(sourcePluginId) &&
|
|
1467
2372
|
isNonEmptyString(decoded?.pluginId) &&
|
|
@@ -1476,7 +2381,6 @@ function validateEmbeddedManifestBytes({
|
|
|
1476
2381
|
);
|
|
1477
2382
|
}
|
|
1478
2383
|
|
|
1479
|
-
const sourceVersion = manifest?.version ?? null;
|
|
1480
2384
|
if (
|
|
1481
2385
|
isNonEmptyString(sourceVersion) &&
|
|
1482
2386
|
isNonEmptyString(decoded?.version) &&
|