@@ -227,6 +227,12 @@ class DeployParam(BaseModel):
227227 namespace_uuid : Optional [UUID ] = None
228228 """Static UUIDv5 namespace for stable Software entity UUIDs.
229229 If None, a default namespace is used."""
230+ public_url : Optional [str ] = None
231+ """Public Prefect API URL stored in the PrefectFlow entity.
232+ Use this when the PREFECT_API_URL used by the worker differs from the
233+ URL clients (e.g. prefect.js) should use to reach the API.
234+ Example: PREFECT_API_URL='http://localhost:4200/api' but clients need
235+ 'https://example.com/w/rest.php/apigateway'."""
230236
231237 class Config :
232238 arbitrary_types_allowed = True
@@ -240,6 +246,7 @@ async def register_flow(
240246 osw_instance : OSW ,
241247 flow : Flow ,
242248 namespace_uuid : Optional [UUID ] = None ,
249+ public_url : Optional [str ] = None ,
243250) -> None :
244251 """Register a Prefect flow as Software + PrefectFlow entities on OSW.
245252
@@ -256,6 +263,9 @@ async def register_flow(
256263 namespace_uuid
257264 UUIDv5 namespace for generating the Software entity UUID.
258265 If None, uses a default namespace.
266+ public_url
267+ Public Prefect API URL to store in the PrefectFlow entity.
268+ If None, PREFECT_API_URL env var is used.
259269 """
260270 if namespace_uuid is None :
261271 namespace_uuid = _DEFAULT_NAMESPACE_UUID
@@ -285,15 +295,36 @@ async def register_flow(
285295 )
286296
287297 # create PrefectFlow entity
288- prefect_api_url = environ .get ("PREFECT_API_URL" , "" )
289- prefect_domain = prefect_api_url .split ("//" )[- 1 ].split ("/" )[0 ]
298+ # use public_url if provided, otherwise fall back to PREFECT_API_URL
299+ from urllib .parse import urlparse
300+
301+ entity_url = public_url or environ .get ("PREFECT_API_URL" , "" )
302+ parsed = urlparse (entity_url )
303+ prefect_domain = parsed .hostname or ""
304+ prefect_schema = parsed .scheme or "https"
305+ prefect_port = [parsed .port ] if parsed .port else None
306+ prefect_path = parsed .path or None
307+ # reconstruct full URL preserving query params and fragment
308+ prefect_url = (
309+ f"{ prefect_schema } ://{ prefect_domain } "
310+ + (f":{ parsed .port } " if parsed .port else "" )
311+ + (prefect_path or "" )
312+ )
313+ if parsed .query :
314+ prefect_url += f"?{ parsed .query } "
315+ if parsed .fragment :
316+ prefect_url += f"#{ parsed .fragment } "
290317 this_flow = model .PrefectFlow (
291318 uuid = flow_uuid ,
292319 label = [model .Label (text = flow .name + " Prefect Flow" )],
293320 description = [model .Description (text = flow .description or "" )],
294321 flow_id = str (flow_uuid ),
295322 hosted_software = [get_full_title (this_tool )],
296323 domain = prefect_domain ,
324+ schema_ = prefect_schema ,
325+ network_port = prefect_port ,
326+ url_path = prefect_path ,
327+ url = prefect_url ,
297328 )
298329
299330 # delete stale PrefectFlow entities that reference the same Software
@@ -318,7 +349,9 @@ async def register_flow(
318349 comment = "Replaced by updated PrefectFlow deployment" ,
319350 )
320351
321- osw_instance .store_entity (OSW .StoreEntityParam (entities = [this_tool , this_flow ]))
352+ osw_instance .store_entity (
353+ OSW .StoreEntityParam (entities = [this_tool , this_flow ], overwrite = True )
354+ )
322355
323356 # build parameters template from flow function signature
324357 # includes all fields so users can see and customize them
@@ -414,6 +447,7 @@ async def _deploy(param: DeployParam):
414447 osw_instance = param .osw ,
415448 flow = flow ,
416449 namespace_uuid = param .namespace_uuid ,
450+ public_url = param .public_url ,
417451 )
418452
419453 if version ("prefect" ) in SpecifierSet (">=3.0" ):
0 commit comments