Metadata-Version: 2.4
Name: platform-ext-utils
Version: 0.1.0
Summary: Shared utility library for Cloudscaile extension features, providing Kafka integration and utilities
Author: Cloudscaile Engineering
License: Apache-2.0
Keywords: cloudscaile,kafka,extensions,utilities
Classifier: Development Status :: 3 - Alpha
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: confluent-kafka>=2.4
Requires-Dist: pydantic>=2.0
Requires-Dist: pydantic-settings>=2.0
Requires-Dist: httpx>=0.25
Dynamic: license-file

# platform-ext-utils

Shared utility library for Cloudscaile extension features, providing Kafka integration, environment configuration management, and external connectivity utilities.

## Features

- **Kafka Service**: Simplified Kafka producer and consumer interface with Sasl support
- **Environment Management**: Centralized configuration via environment variables
- **Logger**: Pre-configured logging for consistent application logs
- **External Connectivity**: Internal HTTP client instances for inter-service communication
- **Audit**: Best-effort `record_audit_event` for platform `/internal/v1/audit-events`

## Installation

```bash
pip install platform-ext-utils
```

## Requirements

- Python >= 3.9
- confluent-kafka >= 2.4
- pydantic >= 2.0
- pydantic-settings >= 2.0
- httpx >= 0.25

## Configuration

All configuration is done via environment variables:

```bash
# Identity (required)
TENANT_NAME=
EXTENSION_NAME=
MODULE_NAME=
PLATFORM_URL=

# Optional: internal platform base for /internal/v1 (no path suffix)
PLATFORM_INTERNAL_URL=

# Kafka Configuration
KAFKA_REQUIRED=
KAFKA_CLIENT_ID=
KAFKA_BROKERS=
KAFKA_GROUP_ID=
KAFKA_CONSUMER_TOPIC=
KAFKA_PRODUCER_TOPIC=

# Optional: Kafka SASL Authentication
KAFKA_SASL=
KAFKA_SASL_USERNAME=
KAFKA_SASL_PASSWORD=

# Required for restart_extension() — Vault-issued secret minted automatically
# at extension-creation time, not something an extension author sets.
EXTENSION_RESTART_TOKEN=
```

## Usage

### Producing Messages

```python
from py_utils import produce_message

produce_message(
    {"event": "user_created", "userId": "123"},
    topic="user-events"
)
```

### Consuming Messages

```python
from py_utils import kafka_service

def handle_message(event):
    print("Received:", event)

if kafka_service:
    kafka_service.consume(callback=handle_message)
```

The callback receives:

```python
{
  "queueName": "<topic>",
  "partition": 0,
  "offset": 42,
  "message": "<decoded string>",
  "timestamp": (<type>, <value>)
}
```

### Using Logger

```python
from py_utils.utils.logger import logger

logger.info("Application started")
logger.error("An error occurred")
```

### External Connectivity

```python
from py_utils import internal_axios_instances

# Use pre-configured HTTP clients for inter-service communication
```

### Audit events

```python
from py_utils import record_audit_event
import os

record_audit_event(
    action="MY_EXT_ACTION",
    result="SUCCESS",  # SUCCESS | FAILURE | DENIED
    tenant_name=os.environ["TENANT_NAME"],
    metadata={"extensionName": os.environ["EXTENSION_NAME"]},
)
```

Requires `PLATFORM_INTERNAL_URL` (cluster/svc base URL, **no** path suffix). Soft-fails (logs, does not raise). Auth is not sent in V1.

### Calling another extension's module

```python
from py_utils import call_extension

# `source` must be a real inbound request (or headers dict) carrying the
# caller's own Authorization header. Request-scoped only — not usable from a
# background job, Kafka consumer, or cron task with no end-user token to forward.
result = call_extension(request, "other-extension", "py", "/some/path")
```

### Restarting this extension

```python
from py_utils import restart_extension

# Dispatches a restart of this extension's own "py" module via the platform.
# Resolving means the restart was dispatched, NOT that the pod(s) have
# actually restarted — there is no confirmation step.
result = restart_extension()
```

## License

Apache License 2.0

## Author

Cloudscaile Engineering
