stac-fastapi-core 6.9.0__py3-none-any.whl → 6.10.0__py3-none-any.whl

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.
stac_fastapi/core/core.py CHANGED
@@ -546,18 +546,20 @@ class CoreClient(AsyncBaseCoreClient):
546
546
  return await self.all_collections(
547
547
  limit=search_request.limit if hasattr(search_request, "limit") else None,
548
548
  bbox=search_request.bbox if hasattr(search_request, "bbox") else None,
549
- datetime=search_request.datetime
550
- if hasattr(search_request, "datetime")
551
- else None,
549
+ datetime=(
550
+ search_request.datetime if hasattr(search_request, "datetime") else None
551
+ ),
552
552
  token=search_request.token if hasattr(search_request, "token") else None,
553
553
  fields=fields,
554
554
  sortby=sortby,
555
- filter_expr=search_request.filter
556
- if hasattr(search_request, "filter")
557
- else None,
558
- filter_lang=search_request.filter_lang
559
- if hasattr(search_request, "filter_lang")
560
- else None,
555
+ filter_expr=(
556
+ search_request.filter if hasattr(search_request, "filter") else None
557
+ ),
558
+ filter_lang=(
559
+ search_request.filter_lang
560
+ if hasattr(search_request, "filter_lang")
561
+ else None
562
+ ),
561
563
  query=search_request.query if hasattr(search_request, "query") else None,
562
564
  q=search_request.q if hasattr(search_request, "q") else None,
563
565
  request=request,
@@ -12,9 +12,15 @@ from starlette.responses import Response
12
12
  from typing_extensions import TypedDict
13
13
 
14
14
  from stac_fastapi.core.models import Catalog
15
- from stac_fastapi.sfeos_helpers.mappings import COLLECTIONS_INDEX
15
+ from stac_fastapi.sfeos_helpers.database import (
16
+ search_children_with_pagination_shared,
17
+ search_collections_by_parent_id_shared,
18
+ search_sub_catalogs_with_pagination_shared,
19
+ update_catalog_in_index_shared,
20
+ )
16
21
  from stac_fastapi.types import stac as stac_types
17
22
  from stac_fastapi.types.core import BaseCoreClient
23
+ from stac_fastapi.types.errors import NotFoundError
18
24
  from stac_fastapi.types.extension import ApiExtension
19
25
 
20
26
  logger = logging.getLogger(__name__)
@@ -106,6 +112,31 @@ class CatalogsExtension(ApiExtension):
106
112
  tags=["Catalogs"],
107
113
  )
108
114
 
115
+ # Add endpoint for getting sub-catalogs of a catalog
116
+ self.router.add_api_route(
117
+ path="/catalogs/{catalog_id}/catalogs",
118
+ endpoint=self.get_catalog_catalogs,
119
+ methods=["GET"],
120
+ response_model=Catalogs,
121
+ response_class=self.response_class,
122
+ summary="Get Catalog Sub-Catalogs",
123
+ description="Get sub-catalogs linked from a specific catalog.",
124
+ tags=["Catalogs"],
125
+ )
126
+
127
+ # Add endpoint for creating sub-catalogs in a catalog
128
+ self.router.add_api_route(
129
+ path="/catalogs/{catalog_id}/catalogs",
130
+ endpoint=self.create_catalog_catalog,
131
+ methods=["POST"],
132
+ response_model=Catalog,
133
+ response_class=self.response_class,
134
+ status_code=201,
135
+ summary="Create Catalog Sub-Catalog",
136
+ description="Create a new catalog and link it as a sub-catalog of a specific catalog.",
137
+ tags=["Catalogs"],
138
+ )
139
+
109
140
  # Add endpoint for creating collections in a catalog
110
141
  self.router.add_api_route(
111
142
  path="/catalogs/{catalog_id}/collections",
@@ -119,6 +150,18 @@ class CatalogsExtension(ApiExtension):
119
150
  tags=["Catalogs"],
120
151
  )
121
152
 
153
+ # Add endpoint for updating a catalog
154
+ self.router.add_api_route(
155
+ path="/catalogs/{catalog_id}",
156
+ endpoint=self.update_catalog,
157
+ methods=["PUT"],
158
+ response_model=Catalog,
159
+ response_class=self.response_class,
160
+ summary="Update Catalog",
161
+ description="Update an existing STAC catalog.",
162
+ tags=["Catalogs"],
163
+ )
164
+
122
165
  # Add endpoint for deleting a catalog
123
166
  self.router.add_api_route(
124
167
  path="/catalogs/{catalog_id}",
@@ -281,6 +324,55 @@ class CatalogsExtension(ApiExtension):
281
324
  # Return the created catalog
282
325
  return catalog
283
326
 
327
+ async def update_catalog(
328
+ self, catalog_id: str, catalog: Catalog, request: Request
329
+ ) -> Catalog:
330
+ """Update an existing catalog.
331
+
332
+ Args:
333
+ catalog_id: The ID of the catalog to update.
334
+ catalog: The updated catalog data.
335
+ request: Request object.
336
+
337
+ Returns:
338
+ The updated catalog.
339
+
340
+ Raises:
341
+ HTTPException: If the catalog is not found.
342
+ """
343
+ try:
344
+ # Verify the catalog exists
345
+ existing_catalog_db = await self.client.database.find_catalog(catalog_id)
346
+
347
+ # Convert STAC catalog to database format
348
+ db_catalog = self.client.catalog_serializer.stac_to_db(catalog, request)
349
+ db_catalog_dict = db_catalog.model_dump()
350
+ db_catalog_dict["type"] = "Catalog"
351
+
352
+ # Preserve parent_ids and other internal fields from the existing catalog
353
+ if "parent_ids" in existing_catalog_db:
354
+ db_catalog_dict["parent_ids"] = existing_catalog_db["parent_ids"]
355
+
356
+ # Update the catalog in the database (upsert via create_catalog)
357
+ await self.client.database.create_catalog(db_catalog_dict, refresh=True)
358
+
359
+ # Return the updated catalog
360
+ return catalog
361
+
362
+ except HTTPException:
363
+ raise
364
+ except Exception as e:
365
+ error_msg = str(e)
366
+ if "not found" in error_msg.lower():
367
+ raise HTTPException(
368
+ status_code=404, detail=f"Catalog {catalog_id} not found"
369
+ )
370
+ logger.error(f"Error updating catalog {catalog_id}: {e}")
371
+ raise HTTPException(
372
+ status_code=500,
373
+ detail=f"Failed to update catalog: {str(e)}",
374
+ )
375
+
284
376
  async def get_catalog(self, catalog_id: str, request: Request) -> Catalog:
285
377
  """Get a specific catalog by ID.
286
378
 
@@ -365,11 +457,9 @@ class CatalogsExtension(ApiExtension):
365
457
  await self.client.database.find_catalog(catalog_id)
366
458
 
367
459
  # Find all collections with this catalog in parent_ids
368
- query_body = {"query": {"term": {"parent_ids": catalog_id}}, "size": 10000}
369
- search_result = await self.client.database.client.search(
370
- index=COLLECTIONS_INDEX, body=query_body
460
+ children = await search_collections_by_parent_id_shared(
461
+ self.client.database.client, catalog_id
371
462
  )
372
- children = [hit["_source"] for hit in search_result["hits"]["hits"]]
373
463
 
374
464
  # Safe Unlink: Remove catalog from all children's parent_ids
375
465
  # If a child becomes an orphan, adopt it to root
@@ -440,27 +530,15 @@ class CatalogsExtension(ApiExtension):
440
530
  # Verify the catalog exists
441
531
  await self.client.database.find_catalog(catalog_id)
442
532
 
443
- # Query collections by parent_ids field using Elasticsearch directly
533
+ # Query collections by parent_ids field
444
534
  # This uses the parent_ids field in the collection mapping to find all
445
535
  # collections that have this catalog as a parent
446
- query_body = {"query": {"term": {"parent_ids": catalog_id}}}
447
-
448
- # Execute the search to get collection IDs
449
- try:
450
- search_result = await self.client.database.client.search(
451
- index=COLLECTIONS_INDEX, body=query_body
452
- )
453
- except Exception as e:
454
- logger.error(
455
- f"Error searching for collections with parent {catalog_id}: {e}"
456
- )
457
- search_result = {"hits": {"hits": []}}
536
+ collections_data = await search_collections_by_parent_id_shared(
537
+ self.client.database.client, catalog_id
538
+ )
458
539
 
459
- # Extract collection IDs from search results
460
- collection_ids = []
461
- hits = search_result.get("hits", {}).get("hits", [])
462
- for hit in hits:
463
- collection_ids.append(hit.get("_id"))
540
+ # Extract collection IDs from results
541
+ collection_ids = [coll.get("id") for coll in collections_data]
464
542
 
465
543
  # Fetch the collections
466
544
  collections = []
@@ -524,6 +602,194 @@ class CatalogsExtension(ApiExtension):
524
602
  status_code=404, detail=f"Catalog {catalog_id} not found"
525
603
  )
526
604
 
605
+ async def get_catalog_catalogs(
606
+ self,
607
+ catalog_id: str,
608
+ request: Request,
609
+ limit: int = Query(10, ge=1, le=100),
610
+ token: Optional[str] = Query(None),
611
+ ) -> Catalogs:
612
+ """Get all sub-catalogs of a specific catalog with pagination.
613
+
614
+ Args:
615
+ catalog_id: The ID of the parent catalog.
616
+ request: Request object.
617
+ limit: Maximum number of results to return (default: 10, max: 100).
618
+ token: Pagination token for cursor-based pagination.
619
+
620
+ Returns:
621
+ A Catalogs response containing sub-catalogs with pagination links.
622
+
623
+ Raises:
624
+ HTTPException: If the catalog is not found.
625
+ """
626
+ try:
627
+ # Verify the catalog exists
628
+ await self.client.database.find_catalog(catalog_id)
629
+
630
+ # Search for sub-catalogs with pagination
631
+ (
632
+ catalogs_data,
633
+ total_hits,
634
+ next_token,
635
+ ) = await search_sub_catalogs_with_pagination_shared(
636
+ self.client.database.client, catalog_id, limit, token
637
+ )
638
+
639
+ # Serialize to STAC format
640
+ catalogs = []
641
+ for catalog_data in catalogs_data:
642
+ try:
643
+ catalog = self.client.catalog_serializer.db_to_stac(
644
+ catalog_data,
645
+ request,
646
+ extensions=[
647
+ type(ext).__name__
648
+ for ext in self.client.database.extensions
649
+ ],
650
+ )
651
+ catalogs.append(catalog)
652
+ except Exception as e:
653
+ logger.error(
654
+ f"Error serializing catalog {catalog_data.get('id')}: {e}"
655
+ )
656
+ continue
657
+
658
+ # Generate pagination links
659
+ base_url = str(request.base_url)
660
+ links = [
661
+ {"rel": "root", "type": "application/json", "href": base_url},
662
+ {
663
+ "rel": "parent",
664
+ "type": "application/json",
665
+ "href": f"{base_url}catalogs/{catalog_id}",
666
+ },
667
+ {
668
+ "rel": "self",
669
+ "type": "application/json",
670
+ "href": str(request.url),
671
+ },
672
+ ]
673
+
674
+ # Add next link if more results exist
675
+ if next_token:
676
+ query_params = {"limit": limit, "token": next_token}
677
+ links.append(
678
+ {
679
+ "rel": "next",
680
+ "href": f"{base_url}catalogs/{catalog_id}/catalogs?{urlencode(query_params)}",
681
+ "type": "application/json",
682
+ "title": "Next page",
683
+ }
684
+ )
685
+
686
+ return {
687
+ "catalogs": catalogs,
688
+ "links": links,
689
+ "numberReturned": len(catalogs),
690
+ "numberMatched": total_hits,
691
+ }
692
+
693
+ except HTTPException:
694
+ # Re-raise HTTP exceptions as-is
695
+ raise
696
+ except Exception as e:
697
+ logger.error(
698
+ f"Error retrieving catalogs for catalog {catalog_id}: {e}",
699
+ exc_info=True,
700
+ )
701
+ raise HTTPException(
702
+ status_code=404, detail=f"Catalog {catalog_id} not found"
703
+ )
704
+
705
+ async def create_catalog_catalog(
706
+ self, catalog_id: str, catalog: Catalog, request: Request
707
+ ) -> Catalog:
708
+ """Create a new catalog or link an existing catalog as a sub-catalog.
709
+
710
+ Logic:
711
+ 1. Verifies the parent catalog exists.
712
+ 2. If the sub-catalog already exists: Appends the parent ID to its parent_ids
713
+ (enabling poly-hierarchy - a catalog can have multiple parents).
714
+ 3. If the sub-catalog is new: Creates it with parent_ids initialized to [catalog_id].
715
+
716
+ Args:
717
+ catalog_id: The ID of the parent catalog.
718
+ catalog: The catalog to create or link.
719
+ request: Request object.
720
+
721
+ Returns:
722
+ The created or linked catalog.
723
+
724
+ Raises:
725
+ HTTPException: If the parent catalog is not found or operation fails.
726
+ """
727
+ try:
728
+ # 1. Verify the parent catalog exists
729
+ await self.client.database.find_catalog(catalog_id)
730
+
731
+ # 2. Check if the sub-catalog already exists
732
+ try:
733
+ existing_catalog = await self.client.database.find_catalog(catalog.id)
734
+
735
+ # --- UPDATE PATH (Existing Catalog) ---
736
+ # We are linking an existing catalog to a new parent (poly-hierarchy)
737
+
738
+ # Ensure parent_ids list exists
739
+ if "parent_ids" not in existing_catalog:
740
+ existing_catalog["parent_ids"] = []
741
+
742
+ # Append if not already present
743
+ if catalog_id not in existing_catalog["parent_ids"]:
744
+ existing_catalog["parent_ids"].append(catalog_id)
745
+
746
+ # Persist the update
747
+ await update_catalog_in_index_shared(
748
+ self.client.database.client, catalog.id, existing_catalog
749
+ )
750
+ logger.info(
751
+ f"Linked existing catalog {catalog.id} to parent {catalog_id}"
752
+ )
753
+
754
+ # Return the STAC object
755
+ return self.client.catalog_serializer.db_to_stac(
756
+ existing_catalog, request
757
+ )
758
+
759
+ except NotFoundError:
760
+ # --- CREATE PATH (New Catalog) ---
761
+ # Catalog does not exist, so we create it
762
+
763
+ # Convert STAC catalog to database format
764
+ db_catalog = self.client.catalog_serializer.stac_to_db(catalog, request)
765
+
766
+ # Convert to dict
767
+ db_catalog_dict = db_catalog.model_dump()
768
+ db_catalog_dict["type"] = "Catalog"
769
+
770
+ # Initialize parent_ids
771
+ db_catalog_dict["parent_ids"] = [catalog_id]
772
+
773
+ # Create in DB
774
+ await self.client.database.create_catalog(db_catalog_dict, refresh=True)
775
+ logger.info(
776
+ f"Created new catalog {catalog.id} with parent {catalog_id}"
777
+ )
778
+
779
+ return catalog
780
+
781
+ except HTTPException:
782
+ raise
783
+ except Exception as e:
784
+ logger.error(
785
+ f"Error processing sub-catalog {catalog.id} in parent {catalog_id}: {e}",
786
+ exc_info=True,
787
+ )
788
+ raise HTTPException(
789
+ status_code=500,
790
+ detail=f"Failed to process sub-catalog: {str(e)}",
791
+ )
792
+
527
793
  async def create_catalog_collection(
528
794
  self, catalog_id: str, collection: Collection, request: Request
529
795
  ) -> stac_types.Collection:
@@ -792,57 +1058,14 @@ class CatalogsExtension(ApiExtension):
792
1058
  # 1. Verify the parent catalog exists
793
1059
  await self.client.database.find_catalog(catalog_id)
794
1060
 
795
- # 2. Build the Search Query
796
- # We search the COLLECTIONS_INDEX because it holds both Catalogs and Collections
797
-
798
- # Base filter: Parent match
799
- # This finds anything where 'parent_ids' contains this catalog_id
800
- filter_queries = [{"term": {"parent_ids": catalog_id}}]
801
-
802
- # Optional filter: Type
803
- if type:
804
- # If user asks for ?type=Catalog, we only return Catalogs
805
- filter_queries.append({"term": {"type": type}})
806
-
807
- # 3. Calculate Pagination (Search After)
808
- body = {
809
- "query": {"bool": {"filter": filter_queries}},
810
- "sort": [{"id": {"order": "asc"}}], # Stable sort for pagination
811
- "size": limit,
812
- }
813
-
814
- # Handle search_after token - split by '|' to get all sort values
815
- search_after: Optional[List[str]] = None
816
- if token:
817
- try:
818
- # The token should be a pipe-separated string of sort values
819
- # e.g., "collection-1"
820
- from typing import cast
821
-
822
- search_after_parts = cast(List[str], token.split("|"))
823
- # If the number of sort fields doesn't match token parts, ignore the token
824
- if len(search_after_parts) != len(body["sort"]): # type: ignore
825
- search_after = None
826
- else:
827
- search_after = search_after_parts
828
- except Exception:
829
- search_after = None
830
-
831
- if search_after is not None:
832
- body["search_after"] = search_after
833
-
834
- # 4. Execute Search
835
- search_result = await self.client.database.client.search(
836
- index=COLLECTIONS_INDEX, body=body
1061
+ # 2. Search for children with pagination
1062
+ children_data, total, next_token = await search_children_with_pagination_shared(
1063
+ self.client.database.client, catalog_id, limit, token, type
837
1064
  )
838
1065
 
839
- # 5. Process Results
840
- hits = search_result.get("hits", {}).get("hits", [])
841
- total = search_result.get("hits", {}).get("total", {}).get("value", 0)
842
-
1066
+ # 3. Serialize children based on type
843
1067
  children = []
844
- for hit in hits:
845
- doc = hit["_source"]
1068
+ for doc in children_data:
846
1069
  resource_type = doc.get(
847
1070
  "type", "Collection"
848
1071
  ) # Default to Collection if missing
@@ -856,7 +1079,7 @@ class CatalogsExtension(ApiExtension):
856
1079
 
857
1080
  children.append(child)
858
1081
 
859
- # 6. Format Response
1082
+ # 4. Format Response
860
1083
  # The Children extension uses a specific response format
861
1084
  response = {
862
1085
  "children": children,
@@ -877,14 +1100,7 @@ class CatalogsExtension(ApiExtension):
877
1100
  "numberMatched": total,
878
1101
  }
879
1102
 
880
- # 7. Generate Next Link
881
- next_token = None
882
- if len(hits) == limit:
883
- next_token_values = hits[-1].get("sort")
884
- if next_token_values:
885
- # Join all sort values with '|' to create the token
886
- next_token = "|".join(str(val) for val in next_token_values)
887
-
1103
+ # 5. Generate Next Link
888
1104
  if next_token:
889
1105
  # Get existing query params
890
1106
  parsed_url = urlparse(str(request.url))
@@ -355,6 +355,9 @@ class CatalogSerializer(Serializer):
355
355
  # Avoid modifying the input dict in-place
356
356
  catalog = deepcopy(catalog)
357
357
 
358
+ # Remove internal fields (not part of STAC spec)
359
+ catalog.pop("parent_ids", None)
360
+
358
361
  # Set defaults
359
362
  catalog.setdefault("type", "Catalog")
360
363
  catalog.setdefault("stac_extensions", [])
@@ -1,2 +1,2 @@
1
1
  """library version."""
2
- __version__ = "6.9.0"
2
+ __version__ = "6.10.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stac_fastapi_core
3
- Version: 6.9.0
3
+ Version: 6.10.0
4
4
  Summary: Core library for the Elasticsearch and Opensearch stac-fastapi backends.
5
5
  Project-URL: Homepage, https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch
6
6
  License: MIT
@@ -2,19 +2,19 @@ stac_fastapi/core/__init__.py,sha256=8izV3IWRGdXmDOK1hIPQAanbWs9EI04PJCGgqG1ZGIs
2
2
  stac_fastapi/core/base_database_logic.py,sha256=JL7DRcDdqeaLbSPPGcIUMs7q6I3Gm_E5XCOwFG458Io,6053
3
3
  stac_fastapi/core/base_settings.py,sha256=R3_Sx7n5XpGMs3zAwFJD7y008WvGU_uI2xkaabm82Kg,239
4
4
  stac_fastapi/core/basic_auth.py,sha256=RhFv3RVSHF6OaqnaaU2DO4ncJ_S5nB1q8UNpnVJJsrk,2155
5
- stac_fastapi/core/core.py,sha256=LTUF1253Bq-E9G9oaK3cPgou7Mk4iemHkS7hDVgwSow,52244
5
+ stac_fastapi/core/core.py,sha256=OKgezb8kEaB10aeNpov4xxHabM7_5ABl3wD6VaVdChE,52300
6
6
  stac_fastapi/core/datetime_utils.py,sha256=QygF2mJFfI_zqCwmSIec3HYqrsVsn3nUcaRQx3CD7Zw,4683
7
7
  stac_fastapi/core/queryables.py,sha256=0gKdxlmCVaIj3ODpmyIfzLChEB1nNKXPZhA3K9ApfL0,3755
8
8
  stac_fastapi/core/rate_limit.py,sha256=Gu8dAaJReGsj1L91U6m2tflU6RahpXDRs2-AYSKoybA,1318
9
9
  stac_fastapi/core/redis_utils.py,sha256=xqZfXwrZ0Wei6EDereOygW_Aq6DBDykhQYD86Ws9P28,9706
10
10
  stac_fastapi/core/route_dependencies.py,sha256=hdtuMkv-zY1vg0YxiCz1aKP0SbBcORqDGEKDGgEazW8,5482
11
- stac_fastapi/core/serializers.py,sha256=l5EWZvlGjlfsZ3S4wHjWKD8sJBf83zd2dkursu18fV4,13345
11
+ stac_fastapi/core/serializers.py,sha256=r9BhjoAWH5Kg6ypEugPZcJ7tPaFx8vWaMJkfoPW5Fdw,13443
12
12
  stac_fastapi/core/session.py,sha256=aXqu4LXfVbAAsChMVXd9gAhczA2bZPne6HqPeklAwMY,474
13
13
  stac_fastapi/core/utilities.py,sha256=B-tLc_H_v92q8ZNpzk-9nKQMKe-bVHUk64HpybGqYX0,10398
14
- stac_fastapi/core/version.py,sha256=Zec8murh7xqMR7l6fB74XJcq2QdyNqRgOdhLMwBYPAI,45
14
+ stac_fastapi/core/version.py,sha256=bQiD_D-FuZl4YJZxrz9LK-THtzxnF7e-QdjJAiGBoSY,46
15
15
  stac_fastapi/core/extensions/__init__.py,sha256=oaK-UJDQSEISdQ8VtM0ESxpsv7Hx1HbAdmMnh6MTFD4,356
16
16
  stac_fastapi/core/extensions/aggregation.py,sha256=v1hUHqlYuMqfQ554g3cTp16pUyRYucQxPERbHPAFtf8,1878
17
- stac_fastapi/core/extensions/catalogs.py,sha256=iOMmPdY0vhGx9QkIMEaLbEaCLvGY2iyg6U07Gdpjejc,38000
17
+ stac_fastapi/core/extensions/catalogs.py,sha256=JR9ireabml5zCcWVM1FPIWZjb87Ffnk81MQm8cnUi6I,45668
18
18
  stac_fastapi/core/extensions/collections_search.py,sha256=ZxCRQ5jyhrg6zDs037qLDzCz0T3tq3a9_lXfYQ9GweQ,14546
19
19
  stac_fastapi/core/extensions/fields.py,sha256=NCT5XHvfaf297eDPNaIFsIzvJnbbUTpScqF0otdx0NA,1066
20
20
  stac_fastapi/core/extensions/filter.py,sha256=-NQGME7rR_ereuDx-LAa1M5JhEXFaKiTtkH2asraYHE,2998
@@ -22,6 +22,6 @@ stac_fastapi/core/extensions/query.py,sha256=Xmo8pfZEZKPudZEjjozv3R0wLOP0ayjC9E6
22
22
  stac_fastapi/core/models/__init__.py,sha256=sUsEB7umGZVYXjT4EHqLwm8p2wevtRBdig2Ioj2ZdVQ,631
23
23
  stac_fastapi/core/models/links.py,sha256=5KEZKisFN34U4UuOzSQnDy0QdsUOT2VRuuY36vs-FGw,7074
24
24
  stac_fastapi/core/models/search.py,sha256=7SgAUyzHGXBXSqB4G6cwq9FMwoAS00momb7jvBkjyow,27
25
- stac_fastapi_core-6.9.0.dist-info/METADATA,sha256=4ot6ylGlLz67tpQZ5VPxAbw2kOC1O_VCAzGXZ2dQ39U,3480
26
- stac_fastapi_core-6.9.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
27
- stac_fastapi_core-6.9.0.dist-info/RECORD,,
25
+ stac_fastapi_core-6.10.0.dist-info/METADATA,sha256=DQkAL0txwG2gljAhY5jwcijSO-PIFXprbmD_SkwIVLU,3481
26
+ stac_fastapi_core-6.10.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
27
+ stac_fastapi_core-6.10.0.dist-info/RECORD,,