spatialdds 0.5.1__tar.gz → 0.5.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.5.1 → spatialdds-0.5.3}/PKG-INFO +36 -2
- {spatialdds-0.5.1 → spatialdds-0.5.3}/README.md +35 -1
- {spatialdds-0.5.1 → spatialdds-0.5.3}/pyproject.toml +1 -1
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/__init__.py +1 -1
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/server/gw_http.py +182 -25
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds.egg-info/PKG-INFO +36 -2
- {spatialdds-0.5.1 → spatialdds-0.5.3}/setup.cfg +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/idl/core.idl +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/idl/discovery.idl +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/idl/types.idl +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/builtin_Time.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_anchors_AnchorDelta.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_anchors_AnchorEntry.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_anchors_AnchorSet.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_anchors_AnchorSetRequest.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_anchors_AnchorSetResponse.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_argeo_NodeGeo.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_argeo_QualityRequirements.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_argeo_VpsRequest.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_argeo_VpsResponse.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_common_AssetRef.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_common_FrameRef.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_common_KV.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_common_MetaKV.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_common_Vec2.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_Aabb3.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_BlobChunk.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_BlobRef.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_ComponentRef.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_Edge.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_EntityBinding.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_FrameTransform.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_FramedPose.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_GeoAnchor.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_GeoPose.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_NavSatStatus.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_Node.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_PlannedTrajectory.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_PlannedWaypoint.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_PoseSE3.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_SnapshotRequest.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_SnapshotResponse.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_TileKey.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_TileMeta.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_TilePatch.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_disco_Announce.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_disco_Capabilities.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_disco_ContentAnnounce.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_disco_CoverageElement.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_disco_CoverageFilter.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_disco_CoverageHint.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_disco_CoverageQuery.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_disco_CoverageResponse.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_disco_Depart.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_disco_KV.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_disco_ProfileSupport.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_disco_ServiceSummary.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_disco_TopicMeta.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_disco_Transform.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_disco_ValidityWindow.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_events_CrossingLine.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_events_SpatialEvent.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_events_SpatialZone.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_events_ZoneState.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_mapping_Edge.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_mapping_MapAlignment.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_mapping_MapEvent.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_mapping_MapMeta.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_mapping_MapQuality.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_owm_Entity.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_owm_ModelCommand.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_owm_ModelPose.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_semantics_Detection2D.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_semantics_Detection2DSet.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_semantics_Detection3D.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_semantics_Detection3DSet.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_semantics_FusedTrack.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_semantics_FusedTrackSet.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_semantics_Keypoint3D.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_semantics_KeypointLink.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_common_Axis.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_common_FrameHeader.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_common_FrameQuality.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_common_Linspace.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_common_ROI.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_common_ROIReply.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_common_ROIRequest.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_common_StreamMeta.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_lidar_LidarDetection.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_lidar_LidarDetectionSet.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_lidar_LidarFrame.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_lidar_LidarMeta.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_rad_RadDetection.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_rad_RadDetectionSet.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_rad_RadSensorMeta.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_rad_RadTensorFrame.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_rad_RadTensorMeta.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_radio_RadioObservation.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_radio_RadioScan.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_radio_RadioSensorMeta.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_rf_beam_RfBeamArraySet.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_rf_beam_RfBeamFrame.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_rf_beam_RfBeamMeta.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_vision_CamIntrinsics.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_vision_Keypoint2D.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_vision_Track2D.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_vision_VisionDetections.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_vision_VisionFrame.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_vision_VisionMeta.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_slam_frontend_CameraInfo.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_slam_frontend_Feature2D.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_slam_frontend_FeatureMatch.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_slam_frontend_KeyframeFeatures.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_slam_frontend_Landmark.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_slam_frontend_MatchSet.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_slam_frontend_TrackObs.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_slam_frontend_Tracklet.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_vio_FusedState.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_vio_ImuInfo.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_vio_ImuSample.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_vio_MagnetometerSample.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_vio_SensorFusionSample.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/serializer_tables.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/canonical.py +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/canonjson.py +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/client.py +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/demo/assets/duck.gltf +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/demo/assets/fountain-label.txt +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/demo/assets/fountain-marker.gltf +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/demo/fountain-anchors.mcap +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/demo/manifests/content-fountain-label.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/demo/manifests/content-fountain-marker.json +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/errors.py +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/records.py +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/serve.py +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/server/__init__.py +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/server/commands.py +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/server/gateway.py +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/server/idlmodel.py +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/server/pin.py +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/server/publish.py +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/server/webjson.py +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/server/xcdr2.py +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds.egg-info/SOURCES.txt +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds.egg-info/dependency_links.txt +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds.egg-info/entry_points.txt +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds.egg-info/requires.txt +0 -0
- {spatialdds-0.5.1 → spatialdds-0.5.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.5.
|
|
3
|
+
Version: 0.5.3
|
|
4
4
|
Summary: SpatialDDS over plain HTTPS and a WebSocket: a client for the web binding (Appendix N), and the reference registry behind one command.
|
|
5
5
|
Author: Open AR Cloud
|
|
6
6
|
License: Apache-2.0
|
|
@@ -419,7 +419,41 @@ an object the app had already discarded. If you called `register()` before
|
|
|
419
419
|
`make_app()`, 0.4.0 and 0.5.0 worked; if you called it after, the command lane
|
|
420
420
|
advertised nothing and refused every POST.
|
|
421
421
|
|
|
422
|
-
|
|
422
|
+
0.5.2 made `notify` safe from the thread its own docstring invited. It put
|
|
423
|
+
onto the subscriber queue directly, and `asyncio.Queue.put_nowait` from a
|
|
424
|
+
foreign thread enqueues without waking the loop — so a backend reading a bus
|
|
425
|
+
in a thread fed a parked subscriber nothing until the loop woke for some other
|
|
426
|
+
reason. Busy endpoint, invisible; idle endpoint, silent. Measured: a bridge
|
|
427
|
+
pumping 202 samples into two registered subscriber queues delivered 0 live
|
|
428
|
+
events. If you call `notify` only from the serving loop, 0.5.0 and 0.5.1 were
|
|
429
|
+
correct for you.
|
|
430
|
+
|
|
431
|
+
0.5.3 lets a browser reach this gateway at all. `Authorization` is not a
|
|
432
|
+
CORS-safelisted request header, so a cross-origin request carrying one is
|
|
433
|
+
preceded by an `OPTIONS` preflight — and no `OPTIONS` was routed, so aiohttp
|
|
434
|
+
answered `405 Allow: GET,HEAD,POST` and the browser stopped there without
|
|
435
|
+
making the request. Two consequences, both found from outside by a real page
|
|
436
|
+
rather than by a gate here: **N.6 was unreachable from a browser for every
|
|
437
|
+
access class**, because a command always carries a credential and so always
|
|
438
|
+
preflights, which no reclassification can change; and a `public-cacheable`
|
|
439
|
+
`GET` that answers `200` with `Access-Control-Allow-Origin: *` failed outright
|
|
440
|
+
if the client volunteered a credential it did not need.
|
|
441
|
+
|
|
442
|
+
An authorized operator-scoped response now also carries the asking origin,
|
|
443
|
+
echoed, with `Vary: Origin, Authorization`. The previous reasoning was that a
|
|
444
|
+
gated resource should never be CORS-open because its credential "must not be
|
|
445
|
+
invited to attach ambiently" — right about the risk and wrong about the
|
|
446
|
+
mechanism. `Access-Control-Allow-Credentials` is what issues that invitation,
|
|
447
|
+
this package sets it nowhere, and a `Bearer` token the page holds and chooses
|
|
448
|
+
to attach is the opposite of ambient. Refusing the origin never kept a
|
|
449
|
+
credential out; it made an authorized `200` unreadable by the client that had
|
|
450
|
+
authorized itself. The body is still `no-store`, the credential is still
|
|
451
|
+
required, and nothing is newly reachable without one.
|
|
452
|
+
|
|
453
|
+
If your clients are not browsers, 0.5.0 through 0.5.2 were correct for you:
|
|
454
|
+
nothing else changes, and no response loses a header it had.
|
|
455
|
+
|
|
456
|
+
## Not in 0.5.3
|
|
423
457
|
|
|
424
458
|
Stated so nobody waits for them: no async API, no caching beyond ETag
|
|
425
459
|
revalidation, no retry policy, no MCAP tooling beyond the journal the server
|
|
@@ -395,7 +395,41 @@ an object the app had already discarded. If you called `register()` before
|
|
|
395
395
|
`make_app()`, 0.4.0 and 0.5.0 worked; if you called it after, the command lane
|
|
396
396
|
advertised nothing and refused every POST.
|
|
397
397
|
|
|
398
|
-
|
|
398
|
+
0.5.2 made `notify` safe from the thread its own docstring invited. It put
|
|
399
|
+
onto the subscriber queue directly, and `asyncio.Queue.put_nowait` from a
|
|
400
|
+
foreign thread enqueues without waking the loop — so a backend reading a bus
|
|
401
|
+
in a thread fed a parked subscriber nothing until the loop woke for some other
|
|
402
|
+
reason. Busy endpoint, invisible; idle endpoint, silent. Measured: a bridge
|
|
403
|
+
pumping 202 samples into two registered subscriber queues delivered 0 live
|
|
404
|
+
events. If you call `notify` only from the serving loop, 0.5.0 and 0.5.1 were
|
|
405
|
+
correct for you.
|
|
406
|
+
|
|
407
|
+
0.5.3 lets a browser reach this gateway at all. `Authorization` is not a
|
|
408
|
+
CORS-safelisted request header, so a cross-origin request carrying one is
|
|
409
|
+
preceded by an `OPTIONS` preflight — and no `OPTIONS` was routed, so aiohttp
|
|
410
|
+
answered `405 Allow: GET,HEAD,POST` and the browser stopped there without
|
|
411
|
+
making the request. Two consequences, both found from outside by a real page
|
|
412
|
+
rather than by a gate here: **N.6 was unreachable from a browser for every
|
|
413
|
+
access class**, because a command always carries a credential and so always
|
|
414
|
+
preflights, which no reclassification can change; and a `public-cacheable`
|
|
415
|
+
`GET` that answers `200` with `Access-Control-Allow-Origin: *` failed outright
|
|
416
|
+
if the client volunteered a credential it did not need.
|
|
417
|
+
|
|
418
|
+
An authorized operator-scoped response now also carries the asking origin,
|
|
419
|
+
echoed, with `Vary: Origin, Authorization`. The previous reasoning was that a
|
|
420
|
+
gated resource should never be CORS-open because its credential "must not be
|
|
421
|
+
invited to attach ambiently" — right about the risk and wrong about the
|
|
422
|
+
mechanism. `Access-Control-Allow-Credentials` is what issues that invitation,
|
|
423
|
+
this package sets it nowhere, and a `Bearer` token the page holds and chooses
|
|
424
|
+
to attach is the opposite of ambient. Refusing the origin never kept a
|
|
425
|
+
credential out; it made an authorized `200` unreadable by the client that had
|
|
426
|
+
authorized itself. The body is still `no-store`, the credential is still
|
|
427
|
+
required, and nothing is newly reachable without one.
|
|
428
|
+
|
|
429
|
+
If your clients are not browsers, 0.5.0 through 0.5.2 were correct for you:
|
|
430
|
+
nothing else changes, and no response loses a header it had.
|
|
431
|
+
|
|
432
|
+
## Not in 0.5.3
|
|
399
433
|
|
|
400
434
|
Stated so nobody waits for them: no async API, no caching beyond ETag
|
|
401
435
|
revalidation, no retry policy, no MCAP tooling beyond the journal the server
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "spatialdds"
|
|
7
|
-
version = "0.5.
|
|
7
|
+
version = "0.5.3"
|
|
8
8
|
description = "SpatialDDS over plain HTTPS and a WebSocket: a client for the web binding (Appendix N), and the reference registry behind one command."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -37,7 +37,7 @@ __all__ = [
|
|
|
37
37
|
"content_manifest", "geo_anchor", "service_uri", "content_uri",
|
|
38
38
|
]
|
|
39
39
|
|
|
40
|
-
__version__ = "0.5.
|
|
40
|
+
__version__ = "0.5.3"
|
|
41
41
|
#: The SpatialDDS-spec commit whose Appendix N and generated artifacts this
|
|
42
42
|
#: package implements. Package versions and specification versions move
|
|
43
43
|
#: independently; this is the one that says what the wire looks like.
|
|
@@ -91,20 +91,55 @@ def _problem(status: int, slug: str, title: str, detail: str,
|
|
|
91
91
|
headers={"Cache-Control": "no-store"})
|
|
92
92
|
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
#: What a cross-origin reader may see beyond the body. Without it the ETag and
|
|
95
|
+
#: the access class are served and unreadable, which is the instrument failing
|
|
96
|
+
#: to report what it measures.
|
|
97
|
+
EXPOSE_HEADERS = ("ETag, X-SpatialDDS-Topic, X-SpatialDDS-Type, "
|
|
98
|
+
"X-SpatialDDS-Access")
|
|
99
|
+
|
|
100
|
+
#: Request headers a browser may send to this gateway. `Authorization` is the
|
|
101
|
+
#: one that matters and the one that is not CORS-safelisted, so a request
|
|
102
|
+
#: carrying it preflights; `Content-Type` is needed for any JSON body, and
|
|
103
|
+
#: `If-None-Match` for conditional GETs.
|
|
104
|
+
ALLOW_HEADERS = "Authorization, Content-Type, If-None-Match"
|
|
105
|
+
|
|
106
|
+
#: Methods this gateway serves. Stated once so the preflight answer and the
|
|
107
|
+
#: `Allow` header on a refusal cannot drift apart.
|
|
108
|
+
ALLOW_METHODS = "GET, HEAD, POST, PUT, DELETE, OPTIONS"
|
|
109
|
+
|
|
110
|
+
#: How long a browser may cache a preflight. Ten minutes: long enough that a
|
|
111
|
+
#: page does not preflight every command, short enough that changing the
|
|
112
|
+
#: policy takes effect inside a session.
|
|
113
|
+
PREFLIGHT_MAX_AGE = 600
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _cache_headers(access: str, doc_ttl: int | None = None,
|
|
117
|
+
origin: str | None = None) -> dict[str, str]:
|
|
95
118
|
"""Cacheability, reach, and auth decided together or not at all.
|
|
96
119
|
|
|
97
120
|
The CORS header lives in this branch rather than in a middleware for the
|
|
98
121
|
same reason the cache header does: a public-cacheable resource is one a
|
|
99
122
|
client may read without presenting anything, so there is no origin that
|
|
100
|
-
should be refused it
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
123
|
+
should be refused it. Putting the two in one function makes the pairing
|
|
124
|
+
impossible to drift apart.
|
|
125
|
+
|
|
126
|
+
**An operator-scoped response now carries an echoed origin too, and the
|
|
127
|
+
reasoning that said otherwise was close to right.** It read: gated by "a
|
|
128
|
+
credential a browser must not be invited to attach ambiently". The
|
|
129
|
+
invitation is real and `Access-Control-Allow-Origin` is not how it is
|
|
130
|
+
issued --- `Access-Control-Allow-Credentials` is. Cookies and HTTP auth
|
|
131
|
+
ride along only when that header says so and the client asks for
|
|
132
|
+
`credentials: 'include'`; this gateway sets it nowhere and never will, so
|
|
133
|
+
nothing here is ambient. A `Bearer` token in an `Authorization` header is
|
|
134
|
+
the opposite of ambient: the page had to hold it and choose to attach it.
|
|
135
|
+
|
|
136
|
+
Refusing the origin did not keep that credential out. It made an
|
|
137
|
+
authorized response unreadable by the client that authorized itself ---
|
|
138
|
+
measured from `SpatialDDS-demo`'s browser lane, where a page holding a
|
|
139
|
+
valid token could not read a word of a 200 it had earned. So the origin is
|
|
140
|
+
echoed rather than `*`, with `Vary: Origin`, which keeps a shared cache
|
|
141
|
+
from serving one origin's answer to another; the body stays `no-store`
|
|
142
|
+
regardless, and the credential is still required. No gate is weakened.
|
|
108
143
|
"""
|
|
109
144
|
if access == gateway.PUBLIC:
|
|
110
145
|
# N.4: where a public-cacheable resource is a manifest carrying its own
|
|
@@ -113,15 +148,73 @@ def _cache_headers(access: str, doc_ttl: int | None = None) -> dict[str, str]:
|
|
|
113
148
|
age = gateway.PUBLIC_MAX_AGE if doc_ttl is None else doc_ttl
|
|
114
149
|
return {"Cache-Control": f"public, max-age={age}",
|
|
115
150
|
"Access-Control-Allow-Origin": "*",
|
|
116
|
-
"Access-Control-Expose-Headers":
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
#
|
|
120
|
-
#
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
151
|
+
"Access-Control-Expose-Headers": EXPOSE_HEADERS}
|
|
152
|
+
# Operator-scoped. Never cacheable, by the same decision that gated it.
|
|
153
|
+
# `doc_ttl` is ignored here deliberately: N.4 grants no lifetime to a gated
|
|
154
|
+
# resource whatever `ttl_sec` it carries, because the cache that would
|
|
155
|
+
# honour it is the shared one the gate exists to keep the body out of.
|
|
156
|
+
headers = {"Cache-Control": "no-store", "Vary": "Authorization"}
|
|
157
|
+
if origin:
|
|
158
|
+
# Echoed, not `*`: a wildcard on a response that varies by credential
|
|
159
|
+
# is the combination a shared cache can get wrong, and there is no
|
|
160
|
+
# reason to name an origin this request did not come from.
|
|
161
|
+
headers["Access-Control-Allow-Origin"] = origin
|
|
162
|
+
headers["Vary"] = "Origin, Authorization"
|
|
163
|
+
headers["Access-Control-Expose-Headers"] = EXPOSE_HEADERS
|
|
164
|
+
return headers
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
async def preflight(request: web.Request) -> web.Response:
|
|
168
|
+
"""Answer the `OPTIONS` a browser sends before a credentialed request.
|
|
169
|
+
|
|
170
|
+
**Why this route has to exist, and why nothing in the specification said
|
|
171
|
+
so.** `Authorization` is not a CORS-safelisted request header, so a
|
|
172
|
+
cross-origin request carrying one is preceded by a preflight. This gateway
|
|
173
|
+
routed no `OPTIONS` at all, so aiohttp answered `405` with
|
|
174
|
+
`Allow: GET,HEAD,POST` --- and the browser stopped there, never making the
|
|
175
|
+
request. Two consequences, both measured against 0.5.2 from a page on
|
|
176
|
+
another origin:
|
|
177
|
+
|
|
178
|
+
* N.6 was unreachable from a browser for **every** access class, because a
|
|
179
|
+
command always carries a credential. Reclassifying a lane cannot help:
|
|
180
|
+
the preflight is triggered by the request, not by what the resource is.
|
|
181
|
+
* A `public-cacheable` GET that answers `200` with
|
|
182
|
+
`Access-Control-Allow-Origin: *` failed outright if the client
|
|
183
|
+
volunteered a credential it did not need.
|
|
184
|
+
|
|
185
|
+
Both are fixed here rather than in Appendix N, because nothing in N
|
|
186
|
+
forbade any of it --- a conforming endpoint could simply omit it, which is
|
|
187
|
+
the separate gap filed for the specification: a binding whose flagship
|
|
188
|
+
client is a browser should have to *state* its preflight behaviour.
|
|
189
|
+
|
|
190
|
+
`Allow-Credentials` is deliberately absent. It is the header that would
|
|
191
|
+
invite cookies and HTTP auth to ride along ambiently, and this gateway
|
|
192
|
+
wants the opposite: a credential the page holds and chooses to attach.
|
|
193
|
+
|
|
194
|
+
A bare `OPTIONS` with no `Origin` is not a preflight; it gets the same
|
|
195
|
+
`Allow` list as a courtesy, which also keeps `ALLOW_METHODS` the single
|
|
196
|
+
place that answer is written.
|
|
197
|
+
"""
|
|
198
|
+
origin = request.headers.get("Origin")
|
|
199
|
+
headers = {"Allow": ALLOW_METHODS}
|
|
200
|
+
if origin:
|
|
201
|
+
headers.update({
|
|
202
|
+
"Access-Control-Allow-Origin": origin,
|
|
203
|
+
"Access-Control-Allow-Methods": ALLOW_METHODS,
|
|
204
|
+
# Echo what was asked for when it was asked, so a header this
|
|
205
|
+
# gateway has not thought of is refused rather than blanket-allowed,
|
|
206
|
+
# and fall back to the list above for a preflight that names none.
|
|
207
|
+
"Access-Control-Allow-Headers":
|
|
208
|
+
request.headers.get("Access-Control-Request-Headers")
|
|
209
|
+
or ALLOW_HEADERS,
|
|
210
|
+
"Access-Control-Max-Age": str(PREFLIGHT_MAX_AGE),
|
|
211
|
+
"Access-Control-Expose-Headers": EXPOSE_HEADERS,
|
|
212
|
+
# The answer depends on all three, so a cache must not reuse it
|
|
213
|
+
# across different ones.
|
|
214
|
+
"Vary": "Origin, Access-Control-Request-Method, "
|
|
215
|
+
"Access-Control-Request-Headers",
|
|
216
|
+
})
|
|
217
|
+
return web.Response(status=204, headers=headers)
|
|
125
218
|
|
|
126
219
|
|
|
127
220
|
def _authorized(request: web.Request, token: str | None) -> bool:
|
|
@@ -145,7 +238,9 @@ def _json_response(request: web.Request, doc: Any, access: str,
|
|
|
145
238
|
doc_ttl: int | None = None) -> web.Response:
|
|
146
239
|
"""One JSON resource, with its ETag, its cache class, and 304 handling."""
|
|
147
240
|
etag = _etag(doc)
|
|
148
|
-
headers = {"ETag": etag,
|
|
241
|
+
headers = {"ETag": etag,
|
|
242
|
+
**_cache_headers(access, doc_ttl,
|
|
243
|
+
request.headers.get("Origin")),
|
|
149
244
|
**(extra or {})}
|
|
150
245
|
if request.headers.get("If-None-Match", "") == etag:
|
|
151
246
|
return web.Response(status=304, headers=headers)
|
|
@@ -473,7 +568,27 @@ def _written(request: web.Request, doc: Any, created: bool,
|
|
|
473
568
|
if not created else web.Response(
|
|
474
569
|
body=_body(doc), status=201, content_type="application/json",
|
|
475
570
|
headers={"ETag": _etag(doc),
|
|
476
|
-
**_cache_headers(gateway.OPERATOR
|
|
571
|
+
**_cache_headers(gateway.OPERATOR, None,
|
|
572
|
+
request.headers.get("Origin")),
|
|
573
|
+
**extra})
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
def _running_loop():
|
|
577
|
+
"""The loop running in *this* thread, or None. Never raises."""
|
|
578
|
+
try:
|
|
579
|
+
return asyncio.get_running_loop()
|
|
580
|
+
except RuntimeError:
|
|
581
|
+
return None
|
|
582
|
+
|
|
583
|
+
|
|
584
|
+
async def _remember_loop(app: web.Application) -> None:
|
|
585
|
+
"""Record the serving loop, so `notify` can reach it from a thread.
|
|
586
|
+
|
|
587
|
+
An `on_startup` signal rather than `make_app`, because `make_app` is
|
|
588
|
+
ordinarily called before there is a loop to record -- an embedder builds
|
|
589
|
+
the app, then hands it to `run_app`.
|
|
590
|
+
"""
|
|
591
|
+
app["loop"] = asyncio.get_running_loop()
|
|
477
592
|
|
|
478
593
|
|
|
479
594
|
def notify(app: web.Application, topic: str, event: dict) -> None:
|
|
@@ -500,16 +615,38 @@ def notify(app: web.Application, topic: str, event: dict) -> None:
|
|
|
500
615
|
"topic": topic,
|
|
501
616
|
"key": key, "data": data})
|
|
502
617
|
|
|
503
|
-
Synchronous on purpose:
|
|
504
|
-
|
|
505
|
-
it
|
|
618
|
+
Synchronous on purpose: there is nothing to await, so a backend reading a
|
|
619
|
+
DDS bus from a thread can call it without arranging a loop. **That use is
|
|
620
|
+
now actually safe**, which it was not in 0.5.0 and 0.5.1: this put onto
|
|
621
|
+
the queue directly, and `asyncio.Queue.put_nowait` from a foreign thread
|
|
622
|
+
enqueues without waking the selector, so a parked subscriber resumed only
|
|
623
|
+
when the loop happened to wake for some other reason. On a busy endpoint
|
|
624
|
+
that is immediate and the bug invisible; on an idle one the events sat
|
|
625
|
+
unseen. The docstring promised the thread case before the code delivered
|
|
626
|
+
it, which is the worse half of the defect.
|
|
506
627
|
|
|
507
628
|
Subscriptions only stay open to be woken when `live_subscriptions` is on
|
|
508
629
|
--- see `make_app`. Calling this against an endpoint serving a finished
|
|
509
630
|
recording is harmless and reaches nobody.
|
|
510
631
|
"""
|
|
632
|
+
loop = app.get("loop")
|
|
511
633
|
for q in list(app["subs"].get(topic, ())):
|
|
512
|
-
|
|
634
|
+
if loop is None or loop is _running_loop():
|
|
635
|
+
q.put_nowait(event)
|
|
636
|
+
else:
|
|
637
|
+
# `asyncio.Queue.put_nowait` is not thread-safe, and the part
|
|
638
|
+
# that bites is not the enqueue -- it is the wakeup. It resolves
|
|
639
|
+
# the parked getter's future directly, and resolving a future
|
|
640
|
+
# from a foreign thread schedules the callback without waking
|
|
641
|
+
# the selector, so the subscriber's `await q.get()` resumes only
|
|
642
|
+
# when the loop next happens to wake for some other reason. On a
|
|
643
|
+
# busy endpoint that is immediate and the bug is invisible; on an
|
|
644
|
+
# idle one the events sit in the queue.
|
|
645
|
+
#
|
|
646
|
+
# Measured on 2026-10-17: a bridge pumping 202 samples into two
|
|
647
|
+
# registered subscriber queues delivered 0 live events, while the
|
|
648
|
+
# same call from the loop thread delivered every one.
|
|
649
|
+
loop.call_soon_threadsafe(q.put_nowait, event)
|
|
513
650
|
|
|
514
651
|
|
|
515
652
|
async def _broadcast(request: web.Request, topic: str, event: dict) -> None:
|
|
@@ -701,7 +838,9 @@ async def delete_instance(request: web.Request) -> web.Response:
|
|
|
701
838
|
{"event": "dispose", "topic": topic, "key": key,
|
|
702
839
|
"reason": reason})
|
|
703
840
|
return web.Response(status=204,
|
|
704
|
-
headers=_cache_headers(
|
|
841
|
+
headers=_cache_headers(
|
|
842
|
+
gateway.OPERATOR, None,
|
|
843
|
+
request.headers.get("Origin")))
|
|
705
844
|
|
|
706
845
|
|
|
707
846
|
async def put_manifest(request: web.Request) -> web.Response:
|
|
@@ -888,6 +1027,11 @@ def make_app(state: gateway.State, base: str, token: str | None,
|
|
|
888
1027
|
else commands.Registry())
|
|
889
1028
|
app["journal"] = journal
|
|
890
1029
|
app["subs"] = {}
|
|
1030
|
+
#: The serving loop, filled in at startup. `notify` needs it to hand an
|
|
1031
|
+
#: event across a thread boundary safely; None until then, which is
|
|
1032
|
+
#: correct -- nothing can be subscribed before the app is running.
|
|
1033
|
+
app["loop"] = None
|
|
1034
|
+
app.on_startup.append(_remember_loop)
|
|
891
1035
|
app["assets"] = assets
|
|
892
1036
|
app.add_routes([
|
|
893
1037
|
web.get("/", root),
|
|
@@ -914,5 +1058,18 @@ def make_app(state: gateway.State, base: str, token: str | None,
|
|
|
914
1058
|
web.delete("/{scene}/{stream}/{type}/{version}/{key}",
|
|
915
1059
|
delete_instance),
|
|
916
1060
|
web.put(gateway.RESOLVE_PATH, put_manifest),
|
|
1061
|
+
# The preflight, on every path that can be asked for cross-origin
|
|
1062
|
+
# with a credential or a JSON body. Mirrors the routes above rather
|
|
1063
|
+
# than using a catch-all, so a path this gateway does not serve still
|
|
1064
|
+
# 404s on OPTIONS instead of promising a method nobody implements.
|
|
1065
|
+
web.options(f"{WELL_KNOWN}/schemas", preflight),
|
|
1066
|
+
web.options(f"{WELL_KNOWN}/schemas/{{type}}", preflight),
|
|
1067
|
+
web.options(f"{WELL_KNOWN}/search", preflight),
|
|
1068
|
+
web.options(f"{WELL_KNOWN}/bootstrap", preflight),
|
|
1069
|
+
web.options(f"{WELL_KNOWN}/resolver", preflight),
|
|
1070
|
+
web.options(gateway.RESOLVE_PATH, preflight),
|
|
1071
|
+
web.options(f"{ASSET_PATH}/{{name}}", preflight),
|
|
1072
|
+
web.options("/{scene}/{stream}/{type}/{version}", preflight),
|
|
1073
|
+
web.options("/{scene}/{stream}/{type}/{version}/{key}", preflight),
|
|
917
1074
|
])
|
|
918
1075
|
return app
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: spatialdds
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.3
|
|
4
4
|
Summary: SpatialDDS over plain HTTPS and a WebSocket: a client for the web binding (Appendix N), and the reference registry behind one command.
|
|
5
5
|
Author: Open AR Cloud
|
|
6
6
|
License: Apache-2.0
|
|
@@ -419,7 +419,41 @@ an object the app had already discarded. If you called `register()` before
|
|
|
419
419
|
`make_app()`, 0.4.0 and 0.5.0 worked; if you called it after, the command lane
|
|
420
420
|
advertised nothing and refused every POST.
|
|
421
421
|
|
|
422
|
-
|
|
422
|
+
0.5.2 made `notify` safe from the thread its own docstring invited. It put
|
|
423
|
+
onto the subscriber queue directly, and `asyncio.Queue.put_nowait` from a
|
|
424
|
+
foreign thread enqueues without waking the loop — so a backend reading a bus
|
|
425
|
+
in a thread fed a parked subscriber nothing until the loop woke for some other
|
|
426
|
+
reason. Busy endpoint, invisible; idle endpoint, silent. Measured: a bridge
|
|
427
|
+
pumping 202 samples into two registered subscriber queues delivered 0 live
|
|
428
|
+
events. If you call `notify` only from the serving loop, 0.5.0 and 0.5.1 were
|
|
429
|
+
correct for you.
|
|
430
|
+
|
|
431
|
+
0.5.3 lets a browser reach this gateway at all. `Authorization` is not a
|
|
432
|
+
CORS-safelisted request header, so a cross-origin request carrying one is
|
|
433
|
+
preceded by an `OPTIONS` preflight — and no `OPTIONS` was routed, so aiohttp
|
|
434
|
+
answered `405 Allow: GET,HEAD,POST` and the browser stopped there without
|
|
435
|
+
making the request. Two consequences, both found from outside by a real page
|
|
436
|
+
rather than by a gate here: **N.6 was unreachable from a browser for every
|
|
437
|
+
access class**, because a command always carries a credential and so always
|
|
438
|
+
preflights, which no reclassification can change; and a `public-cacheable`
|
|
439
|
+
`GET` that answers `200` with `Access-Control-Allow-Origin: *` failed outright
|
|
440
|
+
if the client volunteered a credential it did not need.
|
|
441
|
+
|
|
442
|
+
An authorized operator-scoped response now also carries the asking origin,
|
|
443
|
+
echoed, with `Vary: Origin, Authorization`. The previous reasoning was that a
|
|
444
|
+
gated resource should never be CORS-open because its credential "must not be
|
|
445
|
+
invited to attach ambiently" — right about the risk and wrong about the
|
|
446
|
+
mechanism. `Access-Control-Allow-Credentials` is what issues that invitation,
|
|
447
|
+
this package sets it nowhere, and a `Bearer` token the page holds and chooses
|
|
448
|
+
to attach is the opposite of ambient. Refusing the origin never kept a
|
|
449
|
+
credential out; it made an authorized `200` unreadable by the client that had
|
|
450
|
+
authorized itself. The body is still `no-store`, the credential is still
|
|
451
|
+
required, and nothing is newly reachable without one.
|
|
452
|
+
|
|
453
|
+
If your clients are not browsers, 0.5.0 through 0.5.2 were correct for you:
|
|
454
|
+
nothing else changes, and no response loses a header it had.
|
|
455
|
+
|
|
456
|
+
## Not in 0.5.3
|
|
423
457
|
|
|
424
458
|
Stated so nobody waits for them: no async API, no caching beyond ETag
|
|
425
459
|
revalidation, no retry policy, no MCAP tooling beyond the journal the server
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_anchors_AnchorDelta.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_anchors_AnchorEntry.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_anchors_AnchorSet.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_argeo_NodeGeo.json
RENAMED
|
File without changes
|
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_argeo_VpsRequest.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_argeo_VpsResponse.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_common_AssetRef.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_common_FrameRef.json
RENAMED
|
File without changes
|
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_common_MetaKV.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_BlobChunk.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_BlobRef.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_ComponentRef.json
RENAMED
|
File without changes
|
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_EntityBinding.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_FrameTransform.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_FramedPose.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_GeoAnchor.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_GeoPose.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_NavSatStatus.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_PlannedWaypoint.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_PoseSE3.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_SnapshotRequest.json
RENAMED
|
File without changes
|
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_TileKey.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_TileMeta.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_core_TilePatch.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_disco_Announce.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_disco_Capabilities.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_disco_CoverageFilter.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_disco_CoverageHint.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_disco_CoverageQuery.json
RENAMED
|
File without changes
|
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_disco_Depart.json
RENAMED
|
File without changes
|
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_disco_ProfileSupport.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_disco_ServiceSummary.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_disco_TopicMeta.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_disco_Transform.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_disco_ValidityWindow.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_events_CrossingLine.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_events_SpatialEvent.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_events_SpatialZone.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_events_ZoneState.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_mapping_Edge.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_mapping_MapAlignment.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_mapping_MapEvent.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_mapping_MapMeta.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_mapping_MapQuality.json
RENAMED
|
File without changes
|
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_owm_ModelCommand.json
RENAMED
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_owm_ModelPose.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_semantics_FusedTrack.json
RENAMED
|
File without changes
|
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_semantics_Keypoint3D.json
RENAMED
|
File without changes
|
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_common_Axis.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_sensing_common_ROI.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_vio_FusedState.json
RENAMED
|
File without changes
|
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/artifacts/schemas/spatial_vio_ImuSample.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{spatialdds-0.5.1 → spatialdds-0.5.3}/spatialdds/demo/manifests/content-fountain-marker.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|