Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion docs/hub/code.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,38 @@ their secrets and token mappings, and the functions added on a connection
| `reveal_marketplace_integration_secrets` | `POST` | `/{version}/code/marketplace/integrations/{IntegrationViewId}/secrets/reveal` | `project` | path: `integration_view_id` |
| `set_marketplace_integration_token_mappings` | `PUT` | `/{version}/code/marketplace/integrations/{IntegrationViewId}/token-mappings` | `project` | path: `integration_view_id`; JSON body: `tokenMappings` |
| `get_marketplace_function_catalog` | `GET` | `/{version}/code/marketplace/integrations/{IntegrationViewId}/catalog` | `project` | path: `integration_view_id` |
| `get_marketplace_function_runs` | `GET` | `/{version}/code/marketplace/functions/runs` | `project` | query: exactly one of `triggerId` / `taskId`, `limit` (1–50, default 20); newest first |
| `get_marketplace_function_runs` | `GET` | `/{version}/code/marketplace/functions/runs` | `project` | query: exactly one of `functionId` / `triggerId` / `taskId`, `limit` (1–50, default 20); newest first |

```python
listings = norbix.hub.code.get_marketplace_listings(search="slack")
runs = norbix.hub.code.get_marketplace_function_runs(triggerId="trg_…", limit=5)
result = norbix.hub.code.invoke_marketplace_function("func_…", payload={"text": "Order shipped"})
```

### Marketplace function runs and their details

Each call of a marketplace function is one run row: an invoke (user, API key,
AI), a trigger run or a scheduler fire. `functionId` lists every source of one
function (up to 50 kept); `triggerId` / `taskId` list the runs one trigger or
task started (20 kept). A row carries `status` (`ok` / `failed` / `skipped`,
`None` on rows written before the field existed), `durationMs`, `source`
(`user`, `api-key`, `ai`, `trigger`, `scheduler`), `event`, `correlationId`
and `hasDetails`.

The input, steps and response of a run are written to the project log under
the row's `correlationId`, only while the environment's Norbix Logging is on —
then `hasDetails` is `True`. Read them with the logs route; its query field is
`targetCorrelationId`:

```python
runs = norbix.hub.code.get_marketplace_function_runs(functionId="func_…", limit=10)
for run in runs.get("runs", []):
if not run.get("hasDetails"):
continue # logs were off for this run
details = norbix.hub.logs.get_logs_by_correlation_id(targetCorrelationId=run["correlationId"])
# details["items"]: marketplace:run:started → marketplace:run:step … → completed | failed | skipped
```

## Cloud functions

The five routes of the gateway contract `Code.Functions.md` (§3.3, §3.4,
Expand Down
22 changes: 17 additions & 5 deletions references/hub_dtos.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
""" Options:
Date: 2026-10-12 21:43:18
Date: 2026-10-13 06:06:37
Version: 10.20
Tip: To override a DTO option, remove "#" prefix before updating
BaseUrl: http://localhost:5001
Expand Down Expand Up @@ -5965,9 +5965,14 @@ class MarketplaceFunctionRunDto:
function_id: Optional[str] = None
run_as_user_id: Optional[str] = None
succeeded: bool = False
status: Optional[str] = None
duration_ms: Optional[int] = None
error: Optional[str] = None
vendor_request_id: Optional[str] = None
correlation_id: Optional[str] = None
has_details: bool = False
trigger_id: Optional[str] = None
task_id: Optional[str] = None
input: Optional[str] = None


Expand Down Expand Up @@ -15361,17 +15366,24 @@ class GetMarketplaceFunctionCatalog(CodeMashRequestBase, IReturn[GetMarketplaceF
@dataclass_json(letter_case=LetterCase.CAMEL, undefined=Undefined.EXCLUDE)
@dataclass
class GetMarketplaceFunctionRuns(CodeMashRequestBase, IReturn[GetMarketplaceFunctionRunsResponse]):
# @ApiMember(Description="The trigger whose marketplace function runs to list (trg_…). One of triggerId / taskId.")
# @ApiMember(Description="The marketplace function whose runs to list, from every source (func_…). One of functionId / triggerId / taskId.")
function_id: Optional[str] = None
"""
The marketplace function whose runs to list, from every source (func_…). One of functionId / triggerId / taskId.
"""


# @ApiMember(Description="The trigger whose marketplace function runs to list (trg_…). One of functionId / triggerId / taskId.")
trigger_id: Optional[str] = None
"""
The trigger whose marketplace function runs to list (trg_…). One of triggerId / taskId.
The trigger whose marketplace function runs to list (trg_…). One of functionId / triggerId / taskId.
"""


# @ApiMember(Description="The scheduler task whose marketplace function runs to list (tsk_…). One of triggerId / taskId.")
# @ApiMember(Description="The scheduler task whose marketplace function runs to list (tsk_…). One of functionId / triggerId / taskId.")
task_id: Optional[str] = None
"""
The scheduler task whose marketplace function runs to list (tsk_…). One of triggerId / taskId.
The scheduler task whose marketplace function runs to list (tsk_…). One of functionId / triggerId / taskId.
"""


Expand Down
55 changes: 55 additions & 0 deletions tests/hub/test_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,3 +356,58 @@ def test_marketplace_surface_size() -> None:
client, _ = make_client()
for name, *_ in MARKETPLACE_CASES:
assert callable(getattr(client.hub.code, name)), name


RUNS_PATH = "/v3/code/marketplace/functions/runs"
RUNS_BY_FUNCTION_QUERY = {"functionId": ["func_1p4R3gTobGZpD6fXvHT4rd"], "limit": ["50"]}


def test_marketplace_function_runs_by_function_id() -> None:
"""Exactly one of functionId / triggerId / taskId (gateway item gw-runs): a function's own runs."""
client, transport = make_client()
client.hub.code.get_marketplace_function_runs(functionId="func_1p4R3gTobGZpD6fXvHT4rd", limit=50)
assert transport.last_request is not None
_assert_function_request(
"get_marketplace_function_runs(functionId)",
transport.last_request["method"],
transport.last_request["url"],
transport.last_request["body"],
"GET",
RUNS_PATH,
RUNS_BY_FUNCTION_QUERY,
None,
)


def test_async_marketplace_function_runs_by_function_id() -> None:
seen: list[httpx.Request] = []

def handler(request: httpx.Request) -> httpx.Response:
seen.append(request)
return httpx.Response(200, json={"runs": [{"functionId": "func_1p4R3gTobGZpD6fXvHT4rd", "status": "ok", "hasDetails": True}]})

async def run() -> Any:
client = AsyncNorbix(
project_id="test-project",
bearer_token="test-token",
http_client=httpx.AsyncClient(transport=httpx.MockTransport(handler)),
)
try:
return await client.hub.code.get_marketplace_function_runs(functionId="func_1p4R3gTobGZpD6fXvHT4rd", limit=50)
finally:
await client.aclose()

result = asyncio.run(run())

assert len(seen) == 1
_assert_function_request(
"async get_marketplace_function_runs(functionId)",
seen[0].method,
str(seen[0].url),
seen[0].content.decode("utf-8"),
"GET",
RUNS_PATH,
RUNS_BY_FUNCTION_QUERY,
None,
)
assert result == {"runs": [{"functionId": "func_1p4R3gTobGZpD6fXvHT4rd", "status": "ok", "hasDetails": True}]}
Loading