spatialdds 0.8.2__tar.gz → 0.8.3__tar.gz
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.
- {spatialdds-0.8.2 → spatialdds-0.8.3}/PKG-INFO +10 -1
- {spatialdds-0.8.2 → spatialdds-0.8.3}/README.md +7 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/pyproject.toml +9 -1
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/__init__.py +2 -2
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/openapi.html +1 -1
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/openapi.yaml +1 -1
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/client.py +69 -7
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/_participant.py +12 -10
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/codec.py +10 -8
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/errors.py +10 -0
- spatialdds-0.8.3/spatialdds/mcp_server.py +1159 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/serve.py +25 -5
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/server/gateway.py +20 -6
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/server/publish.py +13 -8
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/server/tenancy.py +3 -1
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/server/webjson.py +48 -6
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds.egg-info/PKG-INFO +10 -1
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds.egg-info/SOURCES.txt +1 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds.egg-info/entry_points.txt +1 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds.egg-info/requires.txt +3 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/setup.cfg +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/idl/anchors.idl +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/idl/argeo.idl +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/idl/common.idl +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/idl/core.idl +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/idl/discovery.idl +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/idl/events.idl +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/idl/lidar.idl +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/idl/mapping.idl +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/idl/provisional/owm.idl +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/idl/provisional/radio.idl +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/idl/provisional/rf_beam.idl +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/idl/rad.idl +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/idl/semantics.idl +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/idl/slam_frontend.idl +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/idl/types.idl +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/idl/vio.idl +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/idl/vision.idl +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/registry.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/builtin_Time.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_anchors_AnchorDelta.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_anchors_AnchorEntry.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_anchors_AnchorSet.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_anchors_AnchorSetRequest.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_anchors_AnchorSetResponse.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_argeo_NodeGeo.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_argeo_QualityRequirements.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_argeo_VpsRequest.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_argeo_VpsResponse.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_common_AssetRef.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_common_FrameRef.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_common_KV.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_common_MetaKV.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_common_Vec2.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_core_Aabb3.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_core_BlobChunk.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_core_BlobRef.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_core_ComponentRef.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_core_Edge.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_core_EntityBinding.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_core_FrameTransform.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_core_FramedPose.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_core_GeoAnchor.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_core_GeoPose.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_core_NavSatStatus.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_core_Node.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_core_PlannedTrajectory.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_core_PlannedWaypoint.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_core_PoseSE3.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_core_SnapshotRequest.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_core_SnapshotResponse.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_core_TileKey.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_core_TileMeta.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_core_TilePatch.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_disco_Announce.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_disco_Capabilities.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_disco_ContentAnnounce.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_disco_CoverageElement.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_disco_CoverageFilter.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_disco_CoverageHint.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_disco_CoverageQuery.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_disco_CoverageResponse.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_disco_Depart.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_disco_KV.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_disco_ProfileSupport.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_disco_ServiceSummary.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_disco_TopicMeta.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_disco_Transform.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_disco_ValidityWindow.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_events_CrossingLine.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_events_SpatialEvent.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_events_SpatialZone.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_events_ZoneState.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_mapping_Edge.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_mapping_MapAlignment.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_mapping_MapEvent.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_mapping_MapMeta.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_mapping_MapQuality.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_owm_Entity.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_owm_ModelCommand.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_owm_ModelPose.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_semantics_Detection2D.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_semantics_Detection2DSet.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_semantics_Detection3D.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_semantics_Detection3DSet.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_semantics_FusedTrack.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_semantics_FusedTrackSet.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_semantics_Keypoint3D.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_semantics_KeypointLink.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_common_Axis.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_common_FrameHeader.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_common_FrameQuality.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_common_Linspace.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_common_ROI.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_common_ROIReply.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_common_ROIRequest.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_common_StreamMeta.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_lidar_LidarDetection.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_lidar_LidarDetectionSet.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_lidar_LidarFrame.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_lidar_LidarMeta.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_rad_RadDetection.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_rad_RadDetectionSet.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_rad_RadSensorMeta.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_rad_RadTensorFrame.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_rad_RadTensorMeta.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_radio_RadioObservation.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_radio_RadioScan.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_radio_RadioSensorMeta.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_rf_beam_RfBeamArraySet.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_rf_beam_RfBeamFrame.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_rf_beam_RfBeamMeta.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_vision_CamIntrinsics.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_vision_Keypoint2D.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_vision_Track2D.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_vision_VisionDetections.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_vision_VisionFrame.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_sensing_vision_VisionMeta.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_slam_frontend_CameraInfo.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_slam_frontend_Feature2D.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_slam_frontend_FeatureMatch.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_slam_frontend_KeyframeFeatures.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_slam_frontend_Landmark.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_slam_frontend_MatchSet.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_slam_frontend_TrackObs.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_slam_frontend_Tracklet.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_vio_FusedState.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_vio_ImuInfo.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_vio_ImuSample.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_vio_MagnetometerSample.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/schemas/spatial_vio_SensorFusionSample.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/artifacts/serializer_tables.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/canonical.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/canonjson.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/_extra.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/blob.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/qos.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/record.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/registry.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/_field_aliases.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/builtin/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/builtin/_types.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/anchors/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/anchors/_anchors.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/argeo/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/argeo/_argeo.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/common/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/common/_types.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/core/GnssService/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/core/GnssService/_core.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/core/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/core/_core.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/disco/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/disco/_discovery.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/events/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/events/_events.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/events/enums/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/events/enums/crossing_direction_enum/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/events/enums/crossing_direction_enum/_events.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/events/enums/event_state_enum/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/events/enums/event_state_enum/_events.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/events/enums/event_type_enum/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/events/enums/event_type_enum/_events.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/events/enums/severity_enum/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/events/enums/severity_enum/_events.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/events/enums/zone_kind_enum/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/events/enums/zone_kind_enum/_events.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/mapping/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/mapping/_mapping.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/mapping/enums/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/mapping/enums/alignment_method/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/mapping/enums/alignment_method/_mapping.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/mapping/enums/edge_type/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/mapping/enums/edge_type/_mapping.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/mapping/enums/map_event_kind/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/mapping/enums/map_event_kind/_mapping.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/mapping/enums/map_kind/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/mapping/enums/map_kind/_mapping.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/mapping/enums/map_status/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/mapping/enums/map_status/_mapping.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/owm/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/owm/_owm.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/semantics/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/semantics/_semantics.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/sensing/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/sensing/common/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/sensing/common/_common.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/sensing/lidar/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/sensing/lidar/_lidar.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/sensing/rad/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/sensing/rad/_rad.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/sensing/radio/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/sensing/radio/_radio.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/sensing/rf_beam/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/sensing/rf_beam/_rf_beam.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/sensing/vision/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/sensing/vision/_vision.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/slam_frontend/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/slam_frontend/_slam_frontend.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/vio/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/dds/types/spatial/vio/_vio.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/demo/assets/duck.gltf +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/demo/assets/fountain-label.txt +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/demo/assets/fountain-marker.gltf +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/demo/fountain-anchors.mcap +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/demo/manifests/content-fountain-label.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/demo/manifests/content-fountain-marker.json +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/events.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/frames.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/journal.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/recency.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/records.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/server/__init__.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/server/bus.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/server/commands.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/server/gw_http.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/server/idlmodel.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/server/limits.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/server/mcapmeta.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/server/pin.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/server/xcdr2.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds/tokens.py +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds.egg-info/dependency_links.txt +0 -0
- {spatialdds-0.8.2 → spatialdds-0.8.3}/spatialdds.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: spatialdds
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.3
|
|
4
4
|
Summary: SpatialDDS for programs: a client for the web binding (Appendix N), a native DDS participant, and the reference registry behind one command.
|
|
5
5
|
Author: Open AR Cloud
|
|
6
6
|
License: Apache-2.0
|
|
@@ -25,6 +25,8 @@ Provides-Extra: dds
|
|
|
25
25
|
Requires-Dist: cyclonedds<12,>=11.0.1; extra == "dds"
|
|
26
26
|
Requires-Dist: mcap>=1.1; extra == "dds"
|
|
27
27
|
Requires-Dist: jsonschema>=4.0; extra == "dds"
|
|
28
|
+
Provides-Extra: mcp
|
|
29
|
+
Requires-Dist: mcp<3,>=2.3; extra == "mcp"
|
|
28
30
|
|
|
29
31
|
# spatialdds
|
|
30
32
|
|
|
@@ -488,6 +490,13 @@ what such a field digests or in what form (spatialdds-py finding 31). Where a
|
|
|
488
490
|
declared value does not parse as a SHA-256 of the asset's bytes, this library
|
|
489
491
|
raises rather than reporting a check it did not perform.
|
|
490
492
|
|
|
493
|
+
One warning, not an error: **`AdvertisedOriginWarning`** (a `UserWarning`),
|
|
494
|
+
once per endpoint, when its search results or resolver metadata advertise
|
|
495
|
+
URLs on another origin than the one you connected to. The library reads
|
|
496
|
+
through your origin either way, so it keeps working; a client that follows
|
|
497
|
+
the advertised URLs reaches the other one, which usually means the endpoint
|
|
498
|
+
was started without `--public-url`. The message names both origins.
|
|
499
|
+
|
|
491
500
|
## Integrity by default
|
|
492
501
|
|
|
493
502
|
Latched reads revalidate with the ETag the endpoint gave; `fetch_asset` checks
|
|
@@ -460,6 +460,13 @@ what such a field digests or in what form (spatialdds-py finding 31). Where a
|
|
|
460
460
|
declared value does not parse as a SHA-256 of the asset's bytes, this library
|
|
461
461
|
raises rather than reporting a check it did not perform.
|
|
462
462
|
|
|
463
|
+
One warning, not an error: **`AdvertisedOriginWarning`** (a `UserWarning`),
|
|
464
|
+
once per endpoint, when its search results or resolver metadata advertise
|
|
465
|
+
URLs on another origin than the one you connected to. The library reads
|
|
466
|
+
through your origin either way, so it keeps working; a client that follows
|
|
467
|
+
the advertised URLs reaches the other one, which usually means the endpoint
|
|
468
|
+
was started without `--public-url`. The message names both origins.
|
|
469
|
+
|
|
463
470
|
## Integrity by default
|
|
464
471
|
|
|
465
472
|
Latched reads revalidate with the ETag the endpoint gave; `fetch_asset` checks
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "spatialdds"
|
|
7
|
-
version = "0.8.
|
|
7
|
+
version = "0.8.3"
|
|
8
8
|
description = "SpatialDDS for programs: a client for the web binding (Appendix N), a native DDS participant, and the reference registry behind one command."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -40,9 +40,17 @@ server = ["aiohttp>=3.8", "mcap>=1.1", "jsonschema>=4.0"]
|
|
|
40
40
|
# Without this extra `import spatialdds` is unchanged, and `sd.participant`
|
|
41
41
|
# raises `sd.MissingExtra` naming it.
|
|
42
42
|
dds = ["cyclonedds>=11.0.1,<12", "mcap>=1.1", "jsonschema>=4.0"]
|
|
43
|
+
# Being an MCP server over the web binding: `spatialdds-mcp`. The official
|
|
44
|
+
# SDK, and nothing else: the server reads with this package's own client,
|
|
45
|
+
# so it needs no aiohttp, no mcap and no cyclonedds. 2.x because its API is
|
|
46
|
+
# the one written against (1.x's FastMCP is 2.x's MCPServer), which needs
|
|
47
|
+
# Python 3.10 or newer; without this extra the base install is unchanged and
|
|
48
|
+
# `spatialdds-mcp` exits saying which line to run.
|
|
49
|
+
mcp = ["mcp>=2.3,<3"]
|
|
43
50
|
|
|
44
51
|
[project.scripts]
|
|
45
52
|
spatialdds-serve = "spatialdds.serve:main"
|
|
53
|
+
spatialdds-mcp = "spatialdds.mcp_server:main"
|
|
46
54
|
|
|
47
55
|
[project.urls]
|
|
48
56
|
Homepage = "https://github.com/OpenArCloud/spatialdds-py"
|
|
@@ -26,7 +26,7 @@ __all__ = [
|
|
|
26
26
|
"connect", "Endpoint", "Hit", "Topic", "Resolved", "Written",
|
|
27
27
|
"Sample", "Dispose", "EndOfReplay", "Liveliness",
|
|
28
28
|
"SpatialDDSError", "Unreachable", "Problem", "Unauthorized", "SurfaceOff",
|
|
29
|
-
"IntegrityError", "UnverifiableIntegrity",
|
|
29
|
+
"IntegrityError", "UnverifiableIntegrity", "AdvertisedOriginWarning",
|
|
30
30
|
"lift", "SPEC_TAG", "SPEC_COMMIT", "APPENDIX_N", "__version__",
|
|
31
31
|
# The record builders, re-exported so that `sd.circle(...)` reads the way
|
|
32
32
|
# it does in the documentation. They live in `spatialdds.records`.
|
|
@@ -41,7 +41,7 @@ __all__ = [
|
|
|
41
41
|
"participant", "MissingExtra", "dds", "events", "frames", "Recency",
|
|
42
42
|
]
|
|
43
43
|
|
|
44
|
-
__version__ = "0.8.
|
|
44
|
+
__version__ = "0.8.3"
|
|
45
45
|
#: The SpatialDDS-spec commit whose Appendix N and generated artifacts this
|
|
46
46
|
#: package implements. Package versions and specification versions move
|
|
47
47
|
#: independently; this is the one that says what the wire looks like.
|
|
@@ -14,4 +14,4 @@ border-bottom:1px solid var(--line)}p{margin:.35rem 0}.mut,.sum .auth{color:
|
|
|
14
14
|
var(--mut)}.auth{font-size:.85rem;margin-left:.4rem}.v{display:inline-block;
|
|
15
15
|
min-width:4.2rem;font:600 12px ui-monospace,monospace;letter-spacing:.04em;
|
|
16
16
|
color:var(--acc)}.codes{font:12px ui-monospace,monospace;color:var(--mut)}
|
|
17
|
-
.s{margin-right:.5rem}.s4,.s5{color:#b5482c}a{color:var(--acc)}</style></head><body><main><h1>SpatialDDS web binding (spatialdds-py)</h1><p class=mut>Version 0.8.2 · OpenAPI 3.1.0 · generated, never hand-written · <a href='openapi'>openapi.yaml</a></p><p>Generated by <code>tools/gen_openapi.py</code> from the gateway's own tables and the published JSON Schemas; never edited by hand. Reads are open; writes take a bearer token scoped to scenes. The WebSocket streams (N.5) are described on each collection path, not modelled. A deployment's own keyed types (<code>serve --extension</code>) are publishable on their own collection paths, under the same rules as the entity lane when they carry <code>basis</code>, <code>state</code>, <code>state_reason</code> and <code>stamp</code>; a type that names an <code>asserter</code> has it stamped or verified as the bearer token's principal (<code>asserter-not-principal</code>, <code>asserter-ungrounded</code>). Their paths are not listed here, because the deployment chooses them.</p><h2>Operations</h2><section id="search"><h3><span class="v get">GET</span> <code>/.well-known/spatialdds/search</code></h3><p class="sum">Services near a geohash (§8.2.3 manifests) <span class="auth">open</span></p><p class="codes"><span class="s s2">200</span> <span class="s s4">429</span></p></section><section id="searchPost"><h3><span class="v post">POST</span> <code>/.well-known/spatialdds/search</code></h3><p class="sum">The same search, as a POST body <span class="auth">open</span></p><p class="codes"><span class="s s2">200</span> <span class="s s4">429</span> <span class="s s4">413</span> <span class="s s4">415</span></p></section><section id="listSchemas"><h3><span class="v get">GET</span> <code>/.well-known/spatialdds/schemas</code></h3><p class="sum">The published JSON Schemas, by type <span class="auth">open</span></p><p class="codes"><span class="s s2">200</span> <span class="s s4">429</span></p></section><section id="getSchema"><h3><span class="v get">GET</span> <code>/.well-known/spatialdds/schemas/{type}</code></h3><p class="sum"> <span class="auth">open</span></p><p class="codes"><span class="s s2">200</span> <span class="s s4">404</span> <span class="s s4">429</span></p></section><section id="bootstrap"><h3><span class="v get">GET</span> <code>/.well-known/spatialdds/bootstrap</code></h3><p class="sum">DDS-join material (N.2); optional <span class="auth">open</span></p><p class="codes"><span class="s s2">200</span> <span class="s s4">404</span> <span class="s s4">429</span></p></section><section id="resolverMetadata"><h3><span class="v get">GET</span> <code>/.well-known/spatialdds/resolver</code></h3><p class="sum">§7.5.2 resolver metadata <span class="auth">open</span></p><p class="codes"><span class="s s2">200</span> <span class="s s4">404</span> <span class="s s4">429</span></p></section><section id="openapi"><h3><span class="v get">GET</span> <code>/.well-known/spatialdds/openapi</code></h3><p class="sum">This document <span class="auth">open</span></p><p class="codes"><span class="s s2">200</span> <span class="s s4">429</span></p></section><section id="openapiPage"><h3><span class="v get">GET</span> <code>/.well-known/spatialdds/openapi.html</code></h3><p class="sum">This document as a static reference page <span class="auth">open</span></p><p class="codes"><span class="s s2">200</span> <span class="s s4">429</span></p></section><section id="resolve"><h3><span class="v get">GET</span> <code>/spatialdds/resolve</code></h3><p class="sum">Resolve a URI to its manifest (§7.5.2) <span class="auth">open</span></p><p class="codes"><span class="s s2">200</span> <span class="s s4">400</span> <span class="s s4">404</span> <span class="s s4">429</span></p></section><section id="putManifest"><h3><span class="v put">PUT</span> <code>/spatialdds/resolve</code></h3><p class="sum">Publish a manifest, keyed by its own <code>id</code> <span class="auth">token</span></p><p>The <code>uri</code> parameter is not used; the body's <code>id</code> is the key. Its scene segment is the lane. **Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>).</p><p class="codes"><span class="s s2">200</span> <span class="s s2">201</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">405</span> <span class="s s4">429</span> <span class="s s4">413</span> <span class="s s4">415</span> <span class="s s5">503</span></p></section><section id="withdrawManifest"><h3><span class="v delete">DELETE</span> <code>/spatialdds/resolve</code></h3><p class="sum">Withdraw a manifest; <code>resolve</code> then answers 404 <span class="auth">token</span></p><p>Owner-checked by the URI's scene segment. **Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>).</p><p class="codes"><span class="s s2">204</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">404</span> <span class="s s4">405</span> <span class="s s4">429</span> <span class="s s5">503</span></p></section><section id="getAsset"><h3><span class="v get">GET</span> <code>/assets/{name}</code></h3><p class="sum">Asset bytes this endpoint hosts (implementation-defined) <span class="auth">open</span></p><p class="codes"><span class="s s2">200</span> <span class="s s4">404</span> <span class="s s4">429</span></p></section><section id="listAnnounce"><h3><span class="v get">GET</span> <code>/{scene}/{stream}/announce/v1</code></h3><p class="sum">Every spatial.disco.Announce instance in the latched set <span class="auth">open</span></p><p>**The same URL is also a WebSocket** (N.5): connect with <code>wss://</code> and receive the latched set as <code>sample</code> events, exactly one <code>end_of_replay</code> carrying the replay count, then live <code>sample</code> and <code>dispose</code> events (<code>{event, topic, key, data | reason}</code>). Not modelled here; see [Appendix N.5](https://spatialdds.org/v1.8/appendix-n/).</p><p class="codes"><span class="s s2">200</span> <span class="s s3">304</span> <span class="s s4">404</span> <span class="s s4">429</span> <span class="s s5">503</span></p></section><section id="commandAnnounce"><h3><span class="v post">POST</span> <code>/{scene}/{stream}/announce/v1</code></h3><p class="sum">An N.6 command addressed through the announce lane <span class="auth">token</span></p><p>Accepted only on a lane whose topic advertises <code>accepts_commands</code>; otherwise <code>405</code>. **Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>). Every member of the record is required: a body is a whole record, never a patch.</p><p class="codes"><span class="s s2">202</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">405</span> <span class="s s4">409</span> <span class="s s4">429</span> <span class="s s4">413</span> <span class="s s4">415</span></p></section><section id="getAnnounce"><h3><span class="v get">GET</span> <code>/{scene}/{stream}/announce/v1/{key}</code></h3><p class="sum">One spatial.disco.Announce instance <span class="auth">open</span></p><p class="codes"><span class="s s2">200</span> <span class="s s3">304</span> <span class="s s4">404</span> <span class="s s4">429</span></p></section><section id="putAnnounce"><h3><span class="v put">PUT</span> <code>/{scene}/{stream}/announce/v1/{key}</code></h3><p class="sum">Publish or replace a spatial.disco.Announce <span class="auth">token</span></p><p>**Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>). Every member of the record is required: a body is a whole record, never a patch. The body's key must equal the URL's. <code>If-Match</code> is honoured when present.</p><p class="codes"><span class="s s2">200</span> <span class="s s2">201</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">405</span> <span class="s s4">412</span> <span class="s s4">429</span> <span class="s s4">413</span> <span class="s s4">415</span> <span class="s s5">503</span></p></section><section id="withdrawAnnounce"><h3><span class="v delete">DELETE</span> <code>/{scene}/{stream}/announce/v1/{key}</code></h3><p class="sum">Withdraw (dispose) a spatial.disco.Announce <span class="auth">token</span></p><p>**Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>). The dispose streams on the collection's WebSocket with its <code>reason</code>.</p><p class="codes"><span class="s s2">204</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">404</span> <span class="s s4">405</span> <span class="s s4">429</span> <span class="s s5">503</span></p></section><section id="listContentAnnounce"><h3><span class="v get">GET</span> <code>/{scene}/{stream}/content_announce/v1</code></h3><p class="sum">Every spatial.disco.ContentAnnounce instance in the latched set <span class="auth">open</span></p><p>**The same URL is also a WebSocket** (N.5): connect with <code>wss://</code> and receive the latched set as <code>sample</code> events, exactly one <code>end_of_replay</code> carrying the replay count, then live <code>sample</code> and <code>dispose</code> events (<code>{event, topic, key, data | reason}</code>). Not modelled here; see [Appendix N.5](https://spatialdds.org/v1.8/appendix-n/).</p><p class="codes"><span class="s s2">200</span> <span class="s s3">304</span> <span class="s s4">404</span> <span class="s s4">429</span> <span class="s s5">503</span></p></section><section id="commandContentAnnounce"><h3><span class="v post">POST</span> <code>/{scene}/{stream}/content_announce/v1</code></h3><p class="sum">An N.6 command addressed through the content_announce lane <span class="auth">token</span></p><p>Accepted only on a lane whose topic advertises <code>accepts_commands</code>; otherwise <code>405</code>. **Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>). Every member of the record is required: a body is a whole record, never a patch.</p><p class="codes"><span class="s s2">202</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">405</span> <span class="s s4">409</span> <span class="s s4">429</span> <span class="s s4">413</span> <span class="s s4">415</span></p></section><section id="getContentAnnounce"><h3><span class="v get">GET</span> <code>/{scene}/{stream}/content_announce/v1/{key}</code></h3><p class="sum">One spatial.disco.ContentAnnounce instance <span class="auth">open</span></p><p class="codes"><span class="s s2">200</span> <span class="s s3">304</span> <span class="s s4">404</span> <span class="s s4">429</span></p></section><section id="putContentAnnounce"><h3><span class="v put">PUT</span> <code>/{scene}/{stream}/content_announce/v1/{key}</code></h3><p class="sum">Publish or replace a spatial.disco.ContentAnnounce <span class="auth">token</span></p><p>**Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>). Every member of the record is required: a body is a whole record, never a patch. The body's key must equal the URL's. <code>If-Match</code> is honoured when present.</p><p class="codes"><span class="s s2">200</span> <span class="s s2">201</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">405</span> <span class="s s4">412</span> <span class="s s4">429</span> <span class="s s4">413</span> <span class="s s4">415</span> <span class="s s5">503</span></p></section><section id="withdrawContentAnnounce"><h3><span class="v delete">DELETE</span> <code>/{scene}/{stream}/content_announce/v1/{key}</code></h3><p class="sum">Withdraw (dispose) a spatial.disco.ContentAnnounce <span class="auth">token</span></p><p>**Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>). The dispose streams on the collection's WebSocket with its <code>reason</code>.</p><p class="codes"><span class="s s2">204</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">404</span> <span class="s s4">405</span> <span class="s s4">429</span> <span class="s s5">503</span></p></section><section id="listEntity"><h3><span class="v get">GET</span> <code>/{scene}/{stream}/entity/v1</code></h3><p class="sum">Every spatial.owm.Entity instance in the latched set <span class="auth">token</span></p><p>**The same URL is also a WebSocket** (N.5): connect with <code>wss://</code> and receive the latched set as <code>sample</code> events, exactly one <code>end_of_replay</code> carrying the replay count, then live <code>sample</code> and <code>dispose</code> events (<code>{event, topic, key, data | reason}</code>). Not modelled here; see [Appendix N.5](https://spatialdds.org/v1.8/appendix-n/).</p><p class="codes"><span class="s s2">200</span> <span class="s s3">304</span> <span class="s s4">404</span> <span class="s s4">429</span> <span class="s s5">503</span></p></section><section id="commandEntity"><h3><span class="v post">POST</span> <code>/{scene}/{stream}/entity/v1</code></h3><p class="sum">An N.6 command addressed through the entity lane <span class="auth">token</span></p><p>Accepted only on a lane whose topic advertises <code>accepts_commands</code>; otherwise <code>405</code>. **Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>). Every member of the record is required: a body is a whole record, never a patch.</p><p class="codes"><span class="s s2">202</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">405</span> <span class="s s4">409</span> <span class="s s4">429</span> <span class="s s4">413</span> <span class="s s4">415</span></p></section><section id="getEntity"><h3><span class="v get">GET</span> <code>/{scene}/{stream}/entity/v1/{key}</code></h3><p class="sum">One spatial.owm.Entity instance <span class="auth">token</span></p><p class="codes"><span class="s s2">200</span> <span class="s s3">304</span> <span class="s s4">404</span> <span class="s s4">429</span></p></section><section id="putEntity"><h3><span class="v put">PUT</span> <code>/{scene}/{stream}/entity/v1/{key}</code></h3><p class="sum">Publish or replace a spatial.owm.Entity <span class="auth">token</span></p><p>**Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>). Every member of the record is required: a body is a whole record, never a patch. The body's key must equal the URL's. <code>If-Match</code> is honoured when present. **Basis gates liveliness.** A DECLARED or AUTHORED body is a declaration and holds until withdrawn; it takes no <code>refresh</code>. An DERIVED or OBSERVED body must declare <code>refresh</code>, and be PUT again within it; when it lapses the gateway withdraws the instance itself, a terminal sample (RETIRED) then the dispose, both with the reason <code>refresh lapsed</code>. On a gateway with a DDS domain the instance is written there too, from the gateway's own participant.</p><p class="codes"><span class="s s2">200</span> <span class="s s2">201</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">405</span> <span class="s s4">412</span> <span class="s s5">503</span> <span class="s s4">429</span> <span class="s s4">413</span> <span class="s s4">415</span></p></section><section id="withdrawEntity"><h3><span class="v delete">DELETE</span> <code>/{scene}/{stream}/entity/v1/{key}</code></h3><p class="sum">Withdraw (dispose) a spatial.owm.Entity <span class="auth">token</span></p><p>**Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>). A terminal sample (RETIRED, with the reason) streams first, then the dispose with its <code>reason</code>, on the collection's WebSocket and, on a gateway with a DDS domain, on the bus.</p><p class="codes"><span class="s s2">204</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">404</span> <span class="s s4">405</span> <span class="s s4">429</span> <span class="s s5">503</span></p></section><section id="listGeoAnchor"><h3><span class="v get">GET</span> <code>/{scene}/{stream}/geo_anchor/v1</code></h3><p class="sum">Every spatial.core.GeoAnchor instance in the latched set <span class="auth">open</span></p><p>**The same URL is also a WebSocket** (N.5): connect with <code>wss://</code> and receive the latched set as <code>sample</code> events, exactly one <code>end_of_replay</code> carrying the replay count, then live <code>sample</code> and <code>dispose</code> events (<code>{event, topic, key, data | reason}</code>). Not modelled here; see [Appendix N.5](https://spatialdds.org/v1.8/appendix-n/).</p><p class="codes"><span class="s s2">200</span> <span class="s s3">304</span> <span class="s s4">404</span> <span class="s s4">429</span> <span class="s s5">503</span></p></section><section id="commandGeoAnchor"><h3><span class="v post">POST</span> <code>/{scene}/{stream}/geo_anchor/v1</code></h3><p class="sum">An N.6 command addressed through the geo_anchor lane <span class="auth">token</span></p><p>Accepted only on a lane whose topic advertises <code>accepts_commands</code>; otherwise <code>405</code>. **Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>). Every member of the record is required: a body is a whole record, never a patch.</p><p class="codes"><span class="s s2">202</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">405</span> <span class="s s4">409</span> <span class="s s4">429</span> <span class="s s4">413</span> <span class="s s4">415</span></p></section><section id="getGeoAnchor"><h3><span class="v get">GET</span> <code>/{scene}/{stream}/geo_anchor/v1/{key}</code></h3><p class="sum">One spatial.core.GeoAnchor instance <span class="auth">open</span></p><p class="codes"><span class="s s2">200</span> <span class="s s3">304</span> <span class="s s4">404</span> <span class="s s4">429</span></p></section><section id="putGeoAnchor"><h3><span class="v put">PUT</span> <code>/{scene}/{stream}/geo_anchor/v1/{key}</code></h3><p class="sum">Publish or replace a spatial.core.GeoAnchor <span class="auth">token</span></p><p>**Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>). Every member of the record is required: a body is a whole record, never a patch. The body's key must equal the URL's. <code>If-Match</code> is honoured when present.</p><p class="codes"><span class="s s2">200</span> <span class="s s2">201</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">405</span> <span class="s s4">412</span> <span class="s s4">429</span> <span class="s s4">413</span> <span class="s s4">415</span> <span class="s s5">503</span></p></section><section id="withdrawGeoAnchor"><h3><span class="v delete">DELETE</span> <code>/{scene}/{stream}/geo_anchor/v1/{key}</code></h3><p class="sum">Withdraw (dispose) a spatial.core.GeoAnchor <span class="auth">token</span></p><p>**Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>). The dispose streams on the collection's WebSocket with its <code>reason</code>.</p><p class="codes"><span class="s s2">204</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">404</span> <span class="s s4">405</span> <span class="s s4">429</span> <span class="s s5">503</span></p></section><section id="listInstances"><h3><span class="v get">GET</span> <code>/{scene}/{stream}/{type}/{version}</code></h3><p class="sum">Any other served topic, read-only <span class="auth">token for operator-scoped</span></p><p>Latched types answer with the latched set; streamed types with the replayed window. Public or operator-scoped per the type: <code>spatial.core.FrameTransform</code> latched public, <code>spatial.events.CrossingLine</code> latched public, <code>spatial.events.SpatialEvent</code> stream bearer, <code>spatial.events.SpatialZone</code> latched public, <code>spatial.owm.ModelPose</code> stream bearer, <code>spatial.semantics.Detection2DSet</code> stream bearer, <code>spatial.semantics.Detection3DSet</code> stream bearer, <code>spatial.semantics.FusedTrackSet</code> stream bearer. **The same URL is also a WebSocket** (N.5): connect with <code>wss://</code> and receive the latched set as <code>sample</code> events, exactly one <code>end_of_replay</code> carrying the replay count, then live <code>sample</code> and <code>dispose</code> events (<code>{event, topic, key, data | reason}</code>). Not modelled here; see [Appendix N.5](https://spatialdds.org/v1.8/appendix-n/).</p><p class="codes"><span class="s s2">200</span> <span class="s s3">304</span> <span class="s s4">401</span> <span class="s s4">404</span> <span class="s s4">429</span> <span class="s s5">503</span></p></section><section id="listWellKnownInstances"><h3><span class="v get">GET</span> <code>/.well-known/spatialdds/{stream}/{type}/{version}</code></h3><p class="sum">A four-segment topic's collection <span class="auth">token for operator-scoped</span></p><p>A four-segment topic (<code>spatialdds/<stream>/<type>/<version></code>, no scene), such as the discovery announce lane, served exactly as a scene-scoped collection is: latched set, <code>ETag</code>, <code>304</code>, the same access classes, and the N.5 stream by upgrading the same path. Read-only: a topic with no scene is in no lane. **The same URL is also a WebSocket** (N.5): connect with <code>wss://</code> and receive the latched set as <code>sample</code> events, exactly one <code>end_of_replay</code> carrying the replay count, then live <code>sample</code> and <code>dispose</code> events (<code>{event, topic, key, data | reason}</code>). Not modelled here; see [Appendix N.5](https://spatialdds.org/v1.8/appendix-n/).</p><p class="codes"><span class="s s2">200</span> <span class="s s3">304</span> <span class="s s4">401</span> <span class="s s4">404</span> <span class="s s4">429</span> <span class="s s5">503</span></p></section><section id="getWellKnownInstance"><h3><span class="v get">GET</span> <code>/.well-known/spatialdds/{stream}/{type}/{version}/{key}</code></h3><p class="sum">One instance of a four-segment topic <span class="auth">token for operator-scoped</span></p><p>A four-segment topic (<code>spatialdds/<stream>/<type>/<version></code>, no scene), such as the discovery announce lane, served exactly as a scene-scoped collection is: latched set, <code>ETag</code>, <code>304</code>, the same access classes, and the N.5 stream by upgrading the same path. Read-only: a topic with no scene is in no lane. </p><p class="codes"><span class="s s2">200</span> <span class="s s3">304</span> <span class="s s4">401</span> <span class="s s4">404</span> <span class="s s4">429</span> <span class="s s5">503</span></p></section><h2>Schemas</h2><p class=mut>115 components, from the published JSON Schemas at <code>/.well-known/spatialdds/schemas</code>.</p></main></body></html>
|
|
17
|
+
.s{margin-right:.5rem}.s4,.s5{color:#b5482c}a{color:var(--acc)}</style></head><body><main><h1>SpatialDDS web binding (spatialdds-py)</h1><p class=mut>Version 0.8.3 · OpenAPI 3.1.0 · generated, never hand-written · <a href='openapi'>openapi.yaml</a></p><p>Generated by <code>tools/gen_openapi.py</code> from the gateway's own tables and the published JSON Schemas; never edited by hand. Reads are open; writes take a bearer token scoped to scenes. The WebSocket streams (N.5) are described on each collection path, not modelled. A deployment's own keyed types (<code>serve --extension</code>) are publishable on their own collection paths, under the same rules as the entity lane when they carry <code>basis</code>, <code>state</code>, <code>state_reason</code> and <code>stamp</code>; a type that names an <code>asserter</code> has it stamped or verified as the bearer token's principal (<code>asserter-not-principal</code>, <code>asserter-ungrounded</code>). Their paths are not listed here, because the deployment chooses them.</p><h2>Operations</h2><section id="search"><h3><span class="v get">GET</span> <code>/.well-known/spatialdds/search</code></h3><p class="sum">Services near a geohash (§8.2.3 manifests) <span class="auth">open</span></p><p class="codes"><span class="s s2">200</span> <span class="s s4">429</span></p></section><section id="searchPost"><h3><span class="v post">POST</span> <code>/.well-known/spatialdds/search</code></h3><p class="sum">The same search, as a POST body <span class="auth">open</span></p><p class="codes"><span class="s s2">200</span> <span class="s s4">429</span> <span class="s s4">413</span> <span class="s s4">415</span></p></section><section id="listSchemas"><h3><span class="v get">GET</span> <code>/.well-known/spatialdds/schemas</code></h3><p class="sum">The published JSON Schemas, by type <span class="auth">open</span></p><p class="codes"><span class="s s2">200</span> <span class="s s4">429</span></p></section><section id="getSchema"><h3><span class="v get">GET</span> <code>/.well-known/spatialdds/schemas/{type}</code></h3><p class="sum"> <span class="auth">open</span></p><p class="codes"><span class="s s2">200</span> <span class="s s4">404</span> <span class="s s4">429</span></p></section><section id="bootstrap"><h3><span class="v get">GET</span> <code>/.well-known/spatialdds/bootstrap</code></h3><p class="sum">DDS-join material (N.2); optional <span class="auth">open</span></p><p class="codes"><span class="s s2">200</span> <span class="s s4">404</span> <span class="s s4">429</span></p></section><section id="resolverMetadata"><h3><span class="v get">GET</span> <code>/.well-known/spatialdds/resolver</code></h3><p class="sum">§7.5.2 resolver metadata <span class="auth">open</span></p><p class="codes"><span class="s s2">200</span> <span class="s s4">404</span> <span class="s s4">429</span></p></section><section id="openapi"><h3><span class="v get">GET</span> <code>/.well-known/spatialdds/openapi</code></h3><p class="sum">This document <span class="auth">open</span></p><p class="codes"><span class="s s2">200</span> <span class="s s4">429</span></p></section><section id="openapiPage"><h3><span class="v get">GET</span> <code>/.well-known/spatialdds/openapi.html</code></h3><p class="sum">This document as a static reference page <span class="auth">open</span></p><p class="codes"><span class="s s2">200</span> <span class="s s4">429</span></p></section><section id="resolve"><h3><span class="v get">GET</span> <code>/spatialdds/resolve</code></h3><p class="sum">Resolve a URI to its manifest (§7.5.2) <span class="auth">open</span></p><p class="codes"><span class="s s2">200</span> <span class="s s4">400</span> <span class="s s4">404</span> <span class="s s4">429</span></p></section><section id="putManifest"><h3><span class="v put">PUT</span> <code>/spatialdds/resolve</code></h3><p class="sum">Publish a manifest, keyed by its own <code>id</code> <span class="auth">token</span></p><p>The <code>uri</code> parameter is not used; the body's <code>id</code> is the key. Its scene segment is the lane. **Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>).</p><p class="codes"><span class="s s2">200</span> <span class="s s2">201</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">405</span> <span class="s s4">429</span> <span class="s s4">413</span> <span class="s s4">415</span> <span class="s s5">503</span></p></section><section id="withdrawManifest"><h3><span class="v delete">DELETE</span> <code>/spatialdds/resolve</code></h3><p class="sum">Withdraw a manifest; <code>resolve</code> then answers 404 <span class="auth">token</span></p><p>Owner-checked by the URI's scene segment. **Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>).</p><p class="codes"><span class="s s2">204</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">404</span> <span class="s s4">405</span> <span class="s s4">429</span> <span class="s s5">503</span></p></section><section id="getAsset"><h3><span class="v get">GET</span> <code>/assets/{name}</code></h3><p class="sum">Asset bytes this endpoint hosts (implementation-defined) <span class="auth">open</span></p><p class="codes"><span class="s s2">200</span> <span class="s s4">404</span> <span class="s s4">429</span></p></section><section id="listAnnounce"><h3><span class="v get">GET</span> <code>/{scene}/{stream}/announce/v1</code></h3><p class="sum">Every spatial.disco.Announce instance in the latched set <span class="auth">open</span></p><p>**The same URL is also a WebSocket** (N.5): connect with <code>wss://</code> and receive the latched set as <code>sample</code> events, exactly one <code>end_of_replay</code> carrying the replay count, then live <code>sample</code> and <code>dispose</code> events (<code>{event, topic, key, data | reason}</code>). Not modelled here; see [Appendix N.5](https://spatialdds.org/v1.8/appendix-n/).</p><p class="codes"><span class="s s2">200</span> <span class="s s3">304</span> <span class="s s4">404</span> <span class="s s4">429</span> <span class="s s5">503</span></p></section><section id="commandAnnounce"><h3><span class="v post">POST</span> <code>/{scene}/{stream}/announce/v1</code></h3><p class="sum">An N.6 command addressed through the announce lane <span class="auth">token</span></p><p>Accepted only on a lane whose topic advertises <code>accepts_commands</code>; otherwise <code>405</code>. **Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>). Every member of the record is required: a body is a whole record, never a patch.</p><p class="codes"><span class="s s2">202</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">405</span> <span class="s s4">409</span> <span class="s s4">429</span> <span class="s s4">413</span> <span class="s s4">415</span></p></section><section id="getAnnounce"><h3><span class="v get">GET</span> <code>/{scene}/{stream}/announce/v1/{key}</code></h3><p class="sum">One spatial.disco.Announce instance <span class="auth">open</span></p><p class="codes"><span class="s s2">200</span> <span class="s s3">304</span> <span class="s s4">404</span> <span class="s s4">429</span></p></section><section id="putAnnounce"><h3><span class="v put">PUT</span> <code>/{scene}/{stream}/announce/v1/{key}</code></h3><p class="sum">Publish or replace a spatial.disco.Announce <span class="auth">token</span></p><p>**Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>). Every member of the record is required: a body is a whole record, never a patch. The body's key must equal the URL's. <code>If-Match</code> is honoured when present.</p><p class="codes"><span class="s s2">200</span> <span class="s s2">201</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">405</span> <span class="s s4">412</span> <span class="s s4">429</span> <span class="s s4">413</span> <span class="s s4">415</span> <span class="s s5">503</span></p></section><section id="withdrawAnnounce"><h3><span class="v delete">DELETE</span> <code>/{scene}/{stream}/announce/v1/{key}</code></h3><p class="sum">Withdraw (dispose) a spatial.disco.Announce <span class="auth">token</span></p><p>**Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>). The dispose streams on the collection's WebSocket with its <code>reason</code>.</p><p class="codes"><span class="s s2">204</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">404</span> <span class="s s4">405</span> <span class="s s4">429</span> <span class="s s5">503</span></p></section><section id="listContentAnnounce"><h3><span class="v get">GET</span> <code>/{scene}/{stream}/content_announce/v1</code></h3><p class="sum">Every spatial.disco.ContentAnnounce instance in the latched set <span class="auth">open</span></p><p>**The same URL is also a WebSocket** (N.5): connect with <code>wss://</code> and receive the latched set as <code>sample</code> events, exactly one <code>end_of_replay</code> carrying the replay count, then live <code>sample</code> and <code>dispose</code> events (<code>{event, topic, key, data | reason}</code>). Not modelled here; see [Appendix N.5](https://spatialdds.org/v1.8/appendix-n/).</p><p class="codes"><span class="s s2">200</span> <span class="s s3">304</span> <span class="s s4">404</span> <span class="s s4">429</span> <span class="s s5">503</span></p></section><section id="commandContentAnnounce"><h3><span class="v post">POST</span> <code>/{scene}/{stream}/content_announce/v1</code></h3><p class="sum">An N.6 command addressed through the content_announce lane <span class="auth">token</span></p><p>Accepted only on a lane whose topic advertises <code>accepts_commands</code>; otherwise <code>405</code>. **Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>). Every member of the record is required: a body is a whole record, never a patch.</p><p class="codes"><span class="s s2">202</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">405</span> <span class="s s4">409</span> <span class="s s4">429</span> <span class="s s4">413</span> <span class="s s4">415</span></p></section><section id="getContentAnnounce"><h3><span class="v get">GET</span> <code>/{scene}/{stream}/content_announce/v1/{key}</code></h3><p class="sum">One spatial.disco.ContentAnnounce instance <span class="auth">open</span></p><p class="codes"><span class="s s2">200</span> <span class="s s3">304</span> <span class="s s4">404</span> <span class="s s4">429</span></p></section><section id="putContentAnnounce"><h3><span class="v put">PUT</span> <code>/{scene}/{stream}/content_announce/v1/{key}</code></h3><p class="sum">Publish or replace a spatial.disco.ContentAnnounce <span class="auth">token</span></p><p>**Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>). Every member of the record is required: a body is a whole record, never a patch. The body's key must equal the URL's. <code>If-Match</code> is honoured when present.</p><p class="codes"><span class="s s2">200</span> <span class="s s2">201</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">405</span> <span class="s s4">412</span> <span class="s s4">429</span> <span class="s s4">413</span> <span class="s s4">415</span> <span class="s s5">503</span></p></section><section id="withdrawContentAnnounce"><h3><span class="v delete">DELETE</span> <code>/{scene}/{stream}/content_announce/v1/{key}</code></h3><p class="sum">Withdraw (dispose) a spatial.disco.ContentAnnounce <span class="auth">token</span></p><p>**Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>). The dispose streams on the collection's WebSocket with its <code>reason</code>.</p><p class="codes"><span class="s s2">204</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">404</span> <span class="s s4">405</span> <span class="s s4">429</span> <span class="s s5">503</span></p></section><section id="listEntity"><h3><span class="v get">GET</span> <code>/{scene}/{stream}/entity/v1</code></h3><p class="sum">Every spatial.owm.Entity instance in the latched set <span class="auth">token</span></p><p>**The same URL is also a WebSocket** (N.5): connect with <code>wss://</code> and receive the latched set as <code>sample</code> events, exactly one <code>end_of_replay</code> carrying the replay count, then live <code>sample</code> and <code>dispose</code> events (<code>{event, topic, key, data | reason}</code>). Not modelled here; see [Appendix N.5](https://spatialdds.org/v1.8/appendix-n/).</p><p class="codes"><span class="s s2">200</span> <span class="s s3">304</span> <span class="s s4">404</span> <span class="s s4">429</span> <span class="s s5">503</span></p></section><section id="commandEntity"><h3><span class="v post">POST</span> <code>/{scene}/{stream}/entity/v1</code></h3><p class="sum">An N.6 command addressed through the entity lane <span class="auth">token</span></p><p>Accepted only on a lane whose topic advertises <code>accepts_commands</code>; otherwise <code>405</code>. **Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>). Every member of the record is required: a body is a whole record, never a patch.</p><p class="codes"><span class="s s2">202</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">405</span> <span class="s s4">409</span> <span class="s s4">429</span> <span class="s s4">413</span> <span class="s s4">415</span></p></section><section id="getEntity"><h3><span class="v get">GET</span> <code>/{scene}/{stream}/entity/v1/{key}</code></h3><p class="sum">One spatial.owm.Entity instance <span class="auth">token</span></p><p class="codes"><span class="s s2">200</span> <span class="s s3">304</span> <span class="s s4">404</span> <span class="s s4">429</span></p></section><section id="putEntity"><h3><span class="v put">PUT</span> <code>/{scene}/{stream}/entity/v1/{key}</code></h3><p class="sum">Publish or replace a spatial.owm.Entity <span class="auth">token</span></p><p>**Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>). Every member of the record is required: a body is a whole record, never a patch. The body's key must equal the URL's. <code>If-Match</code> is honoured when present. **Basis gates liveliness.** A DECLARED or AUTHORED body is a declaration and holds until withdrawn; it takes no <code>refresh</code>. An DERIVED or OBSERVED body must declare <code>refresh</code>, and be PUT again within it; when it lapses the gateway withdraws the instance itself, a terminal sample (RETIRED) then the dispose, both with the reason <code>refresh lapsed</code>. On a gateway with a DDS domain the instance is written there too, from the gateway's own participant.</p><p class="codes"><span class="s s2">200</span> <span class="s s2">201</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">405</span> <span class="s s4">412</span> <span class="s s5">503</span> <span class="s s4">429</span> <span class="s s4">413</span> <span class="s s4">415</span></p></section><section id="withdrawEntity"><h3><span class="v delete">DELETE</span> <code>/{scene}/{stream}/entity/v1/{key}</code></h3><p class="sum">Withdraw (dispose) a spatial.owm.Entity <span class="auth">token</span></p><p>**Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>). A terminal sample (RETIRED, with the reason) streams first, then the dispose with its <code>reason</code>, on the collection's WebSocket and, on a gateway with a DDS domain, on the bus.</p><p class="codes"><span class="s s2">204</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">404</span> <span class="s s4">405</span> <span class="s s4">429</span> <span class="s s5">503</span></p></section><section id="listGeoAnchor"><h3><span class="v get">GET</span> <code>/{scene}/{stream}/geo_anchor/v1</code></h3><p class="sum">Every spatial.core.GeoAnchor instance in the latched set <span class="auth">open</span></p><p>**The same URL is also a WebSocket** (N.5): connect with <code>wss://</code> and receive the latched set as <code>sample</code> events, exactly one <code>end_of_replay</code> carrying the replay count, then live <code>sample</code> and <code>dispose</code> events (<code>{event, topic, key, data | reason}</code>). Not modelled here; see [Appendix N.5](https://spatialdds.org/v1.8/appendix-n/).</p><p class="codes"><span class="s s2">200</span> <span class="s s3">304</span> <span class="s s4">404</span> <span class="s s4">429</span> <span class="s s5">503</span></p></section><section id="commandGeoAnchor"><h3><span class="v post">POST</span> <code>/{scene}/{stream}/geo_anchor/v1</code></h3><p class="sum">An N.6 command addressed through the geo_anchor lane <span class="auth">token</span></p><p>Accepted only on a lane whose topic advertises <code>accepts_commands</code>; otherwise <code>405</code>. **Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>). Every member of the record is required: a body is a whole record, never a patch.</p><p class="codes"><span class="s s2">202</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">405</span> <span class="s s4">409</span> <span class="s s4">429</span> <span class="s s4">413</span> <span class="s s4">415</span></p></section><section id="getGeoAnchor"><h3><span class="v get">GET</span> <code>/{scene}/{stream}/geo_anchor/v1/{key}</code></h3><p class="sum">One spatial.core.GeoAnchor instance <span class="auth">open</span></p><p class="codes"><span class="s s2">200</span> <span class="s s3">304</span> <span class="s s4">404</span> <span class="s s4">429</span></p></section><section id="putGeoAnchor"><h3><span class="v put">PUT</span> <code>/{scene}/{stream}/geo_anchor/v1/{key}</code></h3><p class="sum">Publish or replace a spatial.core.GeoAnchor <span class="auth">token</span></p><p>**Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>). Every member of the record is required: a body is a whole record, never a patch. The body's key must equal the URL's. <code>If-Match</code> is honoured when present.</p><p class="codes"><span class="s s2">200</span> <span class="s s2">201</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">405</span> <span class="s s4">412</span> <span class="s s4">429</span> <span class="s s4">413</span> <span class="s s4">415</span> <span class="s s5">503</span></p></section><section id="withdrawGeoAnchor"><h3><span class="v delete">DELETE</span> <code>/{scene}/{stream}/geo_anchor/v1/{key}</code></h3><p class="sum">Withdraw (dispose) a spatial.core.GeoAnchor <span class="auth">token</span></p><p>**Writes are per lane.** The path's first segment is the scene; the bearer token must be granted it (<code>tenancy.WRITE_REFUSALS</code>). The dispose streams on the collection's WebSocket with its <code>reason</code>.</p><p class="codes"><span class="s s2">204</span> <span class="s s4">400</span> <span class="s s4">401</span> <span class="s s4">403</span> <span class="s s4">404</span> <span class="s s4">405</span> <span class="s s4">429</span> <span class="s s5">503</span></p></section><section id="listInstances"><h3><span class="v get">GET</span> <code>/{scene}/{stream}/{type}/{version}</code></h3><p class="sum">Any other served topic, read-only <span class="auth">token for operator-scoped</span></p><p>Latched types answer with the latched set; streamed types with the replayed window. Public or operator-scoped per the type: <code>spatial.core.FrameTransform</code> latched public, <code>spatial.events.CrossingLine</code> latched public, <code>spatial.events.SpatialEvent</code> stream bearer, <code>spatial.events.SpatialZone</code> latched public, <code>spatial.owm.ModelPose</code> stream bearer, <code>spatial.semantics.Detection2DSet</code> stream bearer, <code>spatial.semantics.Detection3DSet</code> stream bearer, <code>spatial.semantics.FusedTrackSet</code> stream bearer. **The same URL is also a WebSocket** (N.5): connect with <code>wss://</code> and receive the latched set as <code>sample</code> events, exactly one <code>end_of_replay</code> carrying the replay count, then live <code>sample</code> and <code>dispose</code> events (<code>{event, topic, key, data | reason}</code>). Not modelled here; see [Appendix N.5](https://spatialdds.org/v1.8/appendix-n/).</p><p class="codes"><span class="s s2">200</span> <span class="s s3">304</span> <span class="s s4">401</span> <span class="s s4">404</span> <span class="s s4">429</span> <span class="s s5">503</span></p></section><section id="listWellKnownInstances"><h3><span class="v get">GET</span> <code>/.well-known/spatialdds/{stream}/{type}/{version}</code></h3><p class="sum">A four-segment topic's collection <span class="auth">token for operator-scoped</span></p><p>A four-segment topic (<code>spatialdds/<stream>/<type>/<version></code>, no scene), such as the discovery announce lane, served exactly as a scene-scoped collection is: latched set, <code>ETag</code>, <code>304</code>, the same access classes, and the N.5 stream by upgrading the same path. Read-only: a topic with no scene is in no lane. **The same URL is also a WebSocket** (N.5): connect with <code>wss://</code> and receive the latched set as <code>sample</code> events, exactly one <code>end_of_replay</code> carrying the replay count, then live <code>sample</code> and <code>dispose</code> events (<code>{event, topic, key, data | reason}</code>). Not modelled here; see [Appendix N.5](https://spatialdds.org/v1.8/appendix-n/).</p><p class="codes"><span class="s s2">200</span> <span class="s s3">304</span> <span class="s s4">401</span> <span class="s s4">404</span> <span class="s s4">429</span> <span class="s s5">503</span></p></section><section id="getWellKnownInstance"><h3><span class="v get">GET</span> <code>/.well-known/spatialdds/{stream}/{type}/{version}/{key}</code></h3><p class="sum">One instance of a four-segment topic <span class="auth">token for operator-scoped</span></p><p>A four-segment topic (<code>spatialdds/<stream>/<type>/<version></code>, no scene), such as the discovery announce lane, served exactly as a scene-scoped collection is: latched set, <code>ETag</code>, <code>304</code>, the same access classes, and the N.5 stream by upgrading the same path. Read-only: a topic with no scene is in no lane. </p><p class="codes"><span class="s s2">200</span> <span class="s s3">304</span> <span class="s s4">401</span> <span class="s s4">404</span> <span class="s s4">429</span> <span class="s s5">503</span></p></section><h2>Schemas</h2><p class=mut>115 components, from the published JSON Schemas at <code>/.well-known/spatialdds/schemas</code>.</p></main></body></html>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
openapi: 3.1.0
|
|
3
3
|
info:
|
|
4
4
|
title: SpatialDDS web binding (spatialdds-py)
|
|
5
|
-
version: 0.8.
|
|
5
|
+
version: 0.8.3
|
|
6
6
|
summary: SpatialDDS 1.8 Appendix N over HTTPS, plus this endpoint's write surface.
|
|
7
7
|
description: Generated by `tools/gen_openapi.py` from the gateway's own tables and the published JSON Schemas; never edited by hand. Reads are open; writes take a bearer token scoped to scenes. The WebSocket streams (N.5) are described on each collection path, not modelled. A deployment's own keyed types (`serve --extension`) are publishable on their own collection paths, under the same rules as the entity lane when they carry `basis`, `state`, `state_reason` and `stamp`; a type that names an `asserter` has it stamped or verified as the bearer token's principal (`asserter-not-principal`, `asserter-ungrounded`). Their paths are not listed here, because the deployment chooses them.
|
|
8
8
|
servers:
|
|
@@ -11,6 +11,7 @@ import hashlib
|
|
|
11
11
|
import json
|
|
12
12
|
import math
|
|
13
13
|
import re
|
|
14
|
+
import warnings
|
|
14
15
|
from dataclasses import dataclass
|
|
15
16
|
from typing import Any, Dict, Iterator, List, Optional
|
|
16
17
|
|
|
@@ -19,7 +20,7 @@ import requests
|
|
|
19
20
|
from . import canonical, records
|
|
20
21
|
from .errors import (IntegrityError, Problem, SpatialDDSError, Unreachable,
|
|
21
22
|
UnverifiableIntegrity, problem_for)
|
|
22
|
-
from .errors import SurfaceOff, Unauthorized
|
|
23
|
+
from .errors import AdvertisedOriginWarning, SurfaceOff, Unauthorized
|
|
23
24
|
|
|
24
25
|
#: What the package's facade resolves through this module. The two exception
|
|
25
26
|
#: subclasses are here because this is the module `spatialdds.Unauthorized`
|
|
@@ -29,11 +30,15 @@ __all__ = [
|
|
|
29
30
|
"connect", "Endpoint", "Hit", "Topic", "Resolved", "Written",
|
|
30
31
|
"Sample", "Dispose", "EndOfReplay", "Liveliness",
|
|
31
32
|
"SpatialDDSError", "Unreachable", "Problem", "Unauthorized", "SurfaceOff",
|
|
32
|
-
"IntegrityError", "UnverifiableIntegrity", "
|
|
33
|
+
"IntegrityError", "UnverifiableIntegrity", "AdvertisedOriginWarning",
|
|
34
|
+
"lift",
|
|
33
35
|
]
|
|
34
36
|
|
|
35
37
|
|
|
36
38
|
WELL_KNOWN = "/.well-known/spatialdds"
|
|
39
|
+
#: How many search pages `Endpoint.search` follows before it gives up
|
|
40
|
+
#: rather than answer with part of the list.
|
|
41
|
+
SEARCH_PAGES = 100
|
|
37
42
|
_SHA256 = re.compile(r"^(?:sha256:)?([0-9a-f]{64})$", re.I)
|
|
38
43
|
lift = canonical.lift
|
|
39
44
|
|
|
@@ -112,6 +117,7 @@ class Endpoint:
|
|
|
112
117
|
self._cache: Dict[str, Any] = {}
|
|
113
118
|
self._authority: Optional[str] = authority
|
|
114
119
|
self._s = requests.Session()
|
|
120
|
+
self._origin_warned = False
|
|
115
121
|
|
|
116
122
|
# -- plumbing --
|
|
117
123
|
def _url(self, path_or_url: str) -> str:
|
|
@@ -124,6 +130,28 @@ class Endpoint:
|
|
|
124
130
|
scheme, _, rest = url.partition("://")
|
|
125
131
|
return f"{scheme.lower()}://{rest.split('/', 1)[0].lower()}"
|
|
126
132
|
|
|
133
|
+
def _advertised(self, url: str, where: str) -> None:
|
|
134
|
+
"""Warn, once for this endpoint, if `url` is on another origin.
|
|
135
|
+
|
|
136
|
+
The URLs a service manifest or the resolver metadata advertise are
|
|
137
|
+
this endpoint's own, so their origin should be the one they were
|
|
138
|
+
read from. The library reads through `base` regardless (`_path_of`),
|
|
139
|
+
which is why a misadvertised endpoint read fine through it and
|
|
140
|
+
nowhere else (finding 83); this says so instead of hiding it.
|
|
141
|
+
"""
|
|
142
|
+
if self._origin_warned or not url.startswith(("http://", "https://")):
|
|
143
|
+
return
|
|
144
|
+
here, there = _norm_origin(self.base), _norm_origin(url)
|
|
145
|
+
if here == there:
|
|
146
|
+
return
|
|
147
|
+
self._origin_warned = True
|
|
148
|
+
warnings.warn(AdvertisedOriginWarning(
|
|
149
|
+
f"{here} advertises {there} in its {where}, not the origin it "
|
|
150
|
+
f"was read from. This client reads through {here}; a client "
|
|
151
|
+
f"that follows the advertised URL reaches {there}. The endpoint "
|
|
152
|
+
f"is likely missing --public-url (or --authority)."),
|
|
153
|
+
stacklevel=3)
|
|
154
|
+
|
|
127
155
|
def _headers(self, extra: Optional[Dict[str, str]] = None,
|
|
128
156
|
url: Optional[str] = None) -> Dict[str, str]:
|
|
129
157
|
"""Request headers; the token only for this endpoint's own origin.
|
|
@@ -245,16 +273,39 @@ class Endpoint:
|
|
|
245
273
|
|
|
246
274
|
# -- discovery --
|
|
247
275
|
def search(self, geohash: Optional[str] = None,
|
|
248
|
-
kinds: Optional[List[str]] = None
|
|
249
|
-
|
|
276
|
+
kinds: Optional[List[str]] = None,
|
|
277
|
+
max_pages: int = SEARCH_PAGES) -> List["Hit"]:
|
|
278
|
+
"""§3.3.0 search. One cell in, service manifests out.
|
|
279
|
+
|
|
280
|
+
Every page: a response carrying a `next_page_token` is followed with
|
|
281
|
+
`page_token`, the same query each time, until one carries none. 0.8.2
|
|
282
|
+
and earlier read only the first page, so a paging endpoint's later
|
|
283
|
+
services were silently missing (finding 82). An endpoint still paging
|
|
284
|
+
after `max_pages` pages raises rather than answering with part of
|
|
285
|
+
the list.
|
|
286
|
+
"""
|
|
250
287
|
params: Dict[str, Any] = {}
|
|
251
288
|
if geohash:
|
|
252
289
|
params["geohash"] = geohash
|
|
253
290
|
if kinds:
|
|
254
291
|
params["kind"] = ",".join(kinds)
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
292
|
+
hits: List["Hit"] = []
|
|
293
|
+
token = ""
|
|
294
|
+
for _ in range(max_pages):
|
|
295
|
+
page = dict(params, page_token=token) if token else params
|
|
296
|
+
doc = self.get_json(f"{WELL_KNOWN}/search", params=page or None,
|
|
297
|
+
revalidate=False)
|
|
298
|
+
for m in doc.get("results", []):
|
|
299
|
+
for t in (m.get("service") or {}).get("topics") or []:
|
|
300
|
+
if isinstance(t, dict) and t.get("url"):
|
|
301
|
+
self._advertised(str(t["url"]), "search results")
|
|
302
|
+
hits.append(Hit(self, m))
|
|
303
|
+
token = doc.get("next_page_token") or ""
|
|
304
|
+
if not token:
|
|
305
|
+
return hits
|
|
306
|
+
raise SpatialDDSError(
|
|
307
|
+
f"{self.base}: search was still paging after {max_pages} pages "
|
|
308
|
+
f"({len(hits)} services read); pass max_pages= to read further")
|
|
258
309
|
|
|
259
310
|
def near(self, lat: float, lon: float, radius_m: float) -> List["Hit"]:
|
|
260
311
|
"""Services whose declared coverage reaches a point.
|
|
@@ -287,6 +338,7 @@ class Endpoint:
|
|
|
287
338
|
raise SpatialDDSError(
|
|
288
339
|
f"{self.base} publishes no resolver metadata, so it resolves "
|
|
289
340
|
f"nothing. It is not an authority for any spatialdds:// URI.")
|
|
341
|
+
self._advertised(str(hb), "resolver metadata")
|
|
290
342
|
path = hb if hb.startswith(self.base) else self.base + _path_of(hb)
|
|
291
343
|
r = self._request("GET", path, params={"uri": uri}, raw=True)
|
|
292
344
|
return Resolved(self, uri, r.json(), r.headers.get("ETag", ""))
|
|
@@ -735,6 +787,16 @@ def _elements(cov: Any) -> List[Dict[str, Any]]:
|
|
|
735
787
|
|
|
736
788
|
# ---- small helpers --------------------------------------------------------
|
|
737
789
|
|
|
790
|
+
def _norm_origin(url: str) -> str:
|
|
791
|
+
"""scheme://host[:port], lowercased, with a scheme's default port dropped."""
|
|
792
|
+
scheme, _, rest = url.partition("://")
|
|
793
|
+
scheme, host = scheme.lower(), rest.split("/", 1)[0].lower()
|
|
794
|
+
default = {"http": ":80", "https": ":443"}.get(scheme)
|
|
795
|
+
if default and host.endswith(default):
|
|
796
|
+
host = host[:-len(default)]
|
|
797
|
+
return f"{scheme}://{host}"
|
|
798
|
+
|
|
799
|
+
|
|
738
800
|
def _path_of(url: str) -> str:
|
|
739
801
|
if url.startswith(("http://", "https://")):
|
|
740
802
|
rest = url.split("//", 1)[1]
|
|
@@ -231,10 +231,10 @@ class Writer:
|
|
|
231
231
|
"""One lane's writer. Created by `Participant.writer`, never directly."""
|
|
232
232
|
|
|
233
233
|
def __init__(self, p: "Participant", lane: _Lane, on_exit: Optional[str],
|
|
234
|
-
floor_hz: Optional[float],
|
|
234
|
+
floor_hz: Optional[float],
|
|
235
235
|
lifespan_sec: Optional[float]) -> None:
|
|
236
236
|
self._p, self._lane = p, lane
|
|
237
|
-
self.on_exit, self.floor_hz
|
|
237
|
+
self.on_exit, self.floor_hz = on_exit, floor_hz
|
|
238
238
|
self._dw = DataWriter(p._dp, p._topic(lane),
|
|
239
239
|
qos=writer_qos(lane.profile, lifespan_sec))
|
|
240
240
|
self._last: Dict[str, Any] = {}
|
|
@@ -289,13 +289,15 @@ class Writer:
|
|
|
289
289
|
def write(self, sample: Any) -> Any:
|
|
290
290
|
"""Write a typed sample, or its N.1 document. Returns the typed sample.
|
|
291
291
|
|
|
292
|
-
Validated against the published schema first
|
|
293
|
-
|
|
294
|
-
and
|
|
292
|
+
Validated against the published schema first, always: an invalid
|
|
293
|
+
sample raises `SchemaInvalid` and nothing reaches the bus. There is
|
|
294
|
+
no unvalidated mode. 0.8.2 and earlier had one, `validate=False`,
|
|
295
|
+
because validation compiled the schema per sample (finding 75); it
|
|
296
|
+
is compiled once a type now, and an unvalidated write is a hole in
|
|
297
|
+
the write contract, not a fast path.
|
|
295
298
|
"""
|
|
296
299
|
sample = self._coerce(sample)
|
|
297
|
-
|
|
298
|
-
codec.validate(sample)
|
|
300
|
+
codec.validate(sample)
|
|
299
301
|
key = codec.key_of(sample)
|
|
300
302
|
with self._lock:
|
|
301
303
|
self._dw.write(sample)
|
|
@@ -370,7 +372,7 @@ class Writer:
|
|
|
370
372
|
f"{', '.join(unknown)}")
|
|
371
373
|
terminal = self._terminal(dataclasses.replace(last, **changes),
|
|
372
374
|
reason)
|
|
373
|
-
if changes
|
|
375
|
+
if changes:
|
|
374
376
|
codec.validate(terminal)
|
|
375
377
|
del self._last[key]
|
|
376
378
|
# Immediately: nothing of this writer's may come between the
|
|
@@ -762,7 +764,7 @@ class Participant:
|
|
|
762
764
|
def writer(self, type_: Union[str, type], *, stream: Optional[str] = None,
|
|
763
765
|
qos_profile: Union[str, Profile, None] = None,
|
|
764
766
|
on_exit: Optional[str] = None,
|
|
765
|
-
floor_hz: Optional[float] = None,
|
|
767
|
+
floor_hz: Optional[float] = None,
|
|
766
768
|
version: str = "v1", type_name: Optional[str] = None,
|
|
767
769
|
lifespan_sec: Optional[float] = None,
|
|
768
770
|
topic: Optional[str] = None) -> Writer:
|
|
@@ -810,7 +812,7 @@ class Participant:
|
|
|
810
812
|
f"a writer does not offer a contract it will not meet")
|
|
811
813
|
if problems:
|
|
812
814
|
raise ParticipantRefused(problems)
|
|
813
|
-
w = Writer(self, lane, on_exit, floor_hz,
|
|
815
|
+
w = Writer(self, lane, on_exit, floor_hz, lifespan_sec)
|
|
814
816
|
self._writers.append(w)
|
|
815
817
|
for sid, svc in self._services.items():
|
|
816
818
|
if svc["spec"]["topics"] is None:
|
|
@@ -363,7 +363,7 @@ def validate(sample: Any) -> Dict[str, Any]:
|
|
|
363
363
|
check stops at the second: representable in N.1.
|
|
364
364
|
"""
|
|
365
365
|
try:
|
|
366
|
-
import jsonschema
|
|
366
|
+
import jsonschema # noqa: F401
|
|
367
367
|
except ImportError as e:
|
|
368
368
|
from ._extra import EXTRA, MissingExtra
|
|
369
369
|
raise MissingExtra(f"validation needs jsonschema: {EXTRA}") from e
|
|
@@ -371,14 +371,16 @@ def validate(sample: Any) -> Dict[str, Any]:
|
|
|
371
371
|
fqn = fqn_of(sample)
|
|
372
372
|
if fqn in _EXT_FQN:
|
|
373
373
|
return doc
|
|
374
|
-
|
|
375
|
-
|
|
374
|
+
# Compiled once a type, a process (finding 75): a validated pose write
|
|
375
|
+
# cost 5-7 ms when this compiled the schema, and read every vendored
|
|
376
|
+
# schema from disk, per sample.
|
|
377
|
+
v = webjson.vendored_validator(fqn)
|
|
378
|
+
if v is None:
|
|
376
379
|
raise SchemaInvalid(f"no published schema for {fqn}, so a sample "
|
|
377
|
-
f"cannot be validated
|
|
378
|
-
f"
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
except jsonschema.ValidationError as e:
|
|
380
|
+
f"cannot be validated, and nothing is written "
|
|
381
|
+
f"unvalidated")
|
|
382
|
+
e = webjson.first_error(v, doc)
|
|
383
|
+
if e is not None:
|
|
382
384
|
where = "/".join(str(p) for p in e.absolute_path) or "(root)"
|
|
383
385
|
raise SchemaInvalid(f"{fqn} at {where}: {e.message}") from e
|
|
384
386
|
return doc
|
|
@@ -85,3 +85,13 @@ def problem_for(status: int, doc: Dict[str, Any], url: str,
|
|
|
85
85
|
if status == 405 and slug == "publish-disabled":
|
|
86
86
|
return SurfaceOff(status, doc, url)
|
|
87
87
|
return Problem(status, doc, url)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class AdvertisedOriginWarning(UserWarning):
|
|
91
|
+
"""An endpoint advertises URLs on an origin other than the one it was
|
|
92
|
+
read from (finding 83).
|
|
93
|
+
|
|
94
|
+
The library reads through the origin it connected to, so it works either
|
|
95
|
+
way; a client that follows the advertised URL, as N.3's hypermedia
|
|
96
|
+
intends, reaches the other origin. Warned once per endpoint, naming both.
|
|
97
|
+
"""
|