```ts
export function createLruCache(capacity: number): { get: (key: string) => number | undefined; put: (key: string, value: number) => void; size: () => number } {
    if (!Number.isInteger(capacity) || capacity <= 0) {
        throw new Error("capacity must be a positive integer");
    }

    const cache = new Map<string, number>();
    const lruOrder: string[] = [];

    function get(key: string): number | undefined {
        if (cache.has(key)) {
            // Move key to end of lruOrder (most recently used)
            const index = lruOrder.indexOf(key);
            if (index > -1) {
                lruOrder.splice(index, 1);
                lruOrder.push(key);
            }
            return cache.get(key);
        }
        return undefined;
    }

    function put(key: string, value: number): void {
        if (cache.has(key)) {
            // Update existing key
            cache.set(key, value);
            // Move to most recently used
            const index = lruOrder.indexOf(key);
            if (index > -1) {
                lruOrder.splice(index, 1);
                lruOrder.push(key);
            }
        } else {
            // New key
            if (cache.size >= capacity) {
                // Evict least recently used
                const lruKey = lruOrder.shift();
                if (lruKey !== undefined) {
                    cache.delete(lruKey);
                }
            }
            cache.set(key, value);
            lruOrder.push(key);
        }
    }

    function size(): number {
        return cache.size;
    }

    return { get, put, size };
}
```