```typescript
import { Map } from "std/collections/map";

export function topologicalSort(nodes: readonly string[], edges: readonly (readonly [string, string])[]): string[] {
  if (!nodes.length || nodes.some(node => !edges.includes([node, node]))) {
    throw new Error("Invalid input");
  }

  const inDegree = new Map<string, number>();
  const graph: Map<string, Set<string>> = new Map();

  nodes.forEach(node => {
    inDegree.set(node, 0);
    graph.set(node, new Set());
  });

  edges.forEach(([from, to]) => {
    if (!graph.has(from)) {
      graph.set(from, new Set());
    }
    if (!graph.has(to)) {
      graph.set(to, new Set());
    }

    inDegree.set(to, (inDegree.get(to) || 0) + 1);
    graph.get(from)?.add(to);
  });

  const freeNodes = nodes.filter(node => inDegree.get(node)! === 0);

  if (!freeNodes.length) {
    throw new Error("No valid ordering exists");
  }

  const sorted: string[] = [];
  while (freeNodes.length > 0) {
    const node = freeNodes.shift()!;
    sorted.push(node);
    graph.forEach((neighbors, current) => {
      neighbors.delete(node);
      if (!neighbors.size && !inDegree.has(current)) {
        freeNodes.push(current);
      }
    });
  }

  return sorted;
}
```