Here's the refactored package structure with clean separation of concerns, proper type hints, and a well-defined public API.

### `queue/__init__.py`
```python
"""Job queue package providing FIFO, priority, and retry-capable job processing."""

from .core import Job, JobQueue
from .priority import PriorityQueue
from .retry import process_with_retry

__all__ = ["Job", "JobQueue", "PriorityQueue", "process_with_retry"]
```

### `queue/core.py`
```python
"""Core data model and basic FIFO queue implementation."""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any, Callable, Optional
from collections import deque
import time


@dataclass
class Job:
    """Represents a unit of work to be processed."""
    id: str
    payload: Any
    priority: int = 0
    status: str = "pending"
    created_at: float = field(default_factory=time.time)
    retries: int = 0


class JobQueue:
    """Basic FIFO job queue implementation."""

    def __init__(self) -> None:
        self._queue: deque[Job] = deque()

    def enqueue(self, job: Job) -> None:
        """Add a job to the end of the queue."""
        self._queue.append(job)

    def dequeue(self) -> Optional[Job]:
        """Remove and return the next job, or None if empty."""
        return self._queue.popleft() if self._queue else None

    def process(self, handler: Callable[[Job], None]) -> None:
        """Process the next job using the provided handler function."""
        job = self.dequeue()
        if job is None:
            return

        job.status = "processing"
        handler(job)
        job.status = "completed"

    def is_empty(self) -> bool:
        return len(self._queue) == 0

    def size(self) -> int:
        return len(self._queue)
```

### `queue/priority.py`
```python
"""Priority-based job queue implementation using a min-heap."""

from __future__ import annotations

from typing import Optional
import heapq
from .core import Job, JobQueue


class PriorityQueue(JobQueue):
    """Priority queue that processes jobs in ascending order of priority.
    
    Lower priority values are processed first. Ties are broken by insertion order.
    """

    def __init__(self) -> None:
        super().__init__()
        self._heap: list[tuple[int, int, Job]] = []
        self._counter: int = 0

    def enqueue(self, job: Job) -> None:
        """Add a job to the priority queue."""
        heapq.heappush(self._heap, (job.priority, self._counter, job))
        self._counter += 1

    def dequeue(self) -> Optional[Job]:
        """Remove and return the highest priority job, or None if empty."""
        if self._heap:
            _, _, job = heapq.heappop(self._heap)
            return job
        return None

    def is_empty(self) -> bool:
        return len(self._heap) == 0

    def size(self) -> int:
        return len(self._heap)
```

### `queue/retry.py`
```python
"""Retry logic with exponential backoff and optional jitter."""

from __future__ import annotations

import time
import random
from typing import Callable, Any, Optional
from .core import Job


def process_with_retry(
    job: Job,
    func: Callable[[Job], Any],
    max_retries: int = 3,
    base_delay: float = 1.0,
    jitter: bool = True
) -> bool:
    """Execute a job with exponential backoff retry logic.

    Args:
        job: The job instance to process.
        func: Callable that accepts the job and executes it.
        max_retries: Maximum number of retry attempts.
        base_delay: Base delay in seconds for exponential backoff.
        jitter: Whether to add random jitter to the delay.

    Returns:
        True if the job completed successfully, False if max retries exhausted.
    """
    for attempt in range(max_retries + 1):
        try:
            func(job)
            job.status = "completed"
            return True
        except Exception as e:
            job.retries += 1
            job.status = "failed"
            if attempt == max_retries:
                return False

            # Exponential backoff: base_delay * 2^attempt
            delay = base_delay * (2 ** attempt)
            if jitter:
                delay *= (0.5 + random.random())
            
            time.sleep(delay)

    return False
```

### Key Design Decisions:
1. **Single Responsibility**: 
   - `core.py` handles the data model (`Job`) and basic FIFO semantics.
   - `priority.py` isolates heap-based ordering logic.
   - `retry.py` encapsulates backoff strategy, keeping it reusable across queue types.
2. **Clean Public API**: `__init__.py` explicitly exports only what consumers need, hiding internal modules.
3. **Type Safety**: Full type hints with `from __future__ import annotations` for modern Python compatibility.
4. **Extensibility**: `JobQueue` and `PriorityQueue` share a consistent interface. `process_with_retry` is decoupled from queue internals, making it usable with any `Job` instance.
5. **Performance**: `PriorityQueue` uses `heapq` for `O(log n)` insertions/deletions instead of sorting a list on every enqueue.