Skip to content

Lacy

@farbenmeer/lacy wraps any Promise in a Proxy, letting you chain property access and method calls lazily. Nothing evaluates until you await the final result.

Terminal window
npm install @farbenmeer/lacy

Zero Intermediate Awaits

Build deep chains without awaiting at every step — the full chain resolves in one await.

Proxy-Based

Uses native JavaScript Proxy. No code generation, no decorators, no compilation required.

Standard Promise Protocol

LacyPromise implements .then(), .catch(), and .finally(), so it works anywhere a Promise does.

Escape Hatch

Access the raw underlying Promise at any point via the .$ property.

Without Lacy, fetching nested data requires multiple awaits:

const response = await fetch("/api/users");
const data = await response.json();
const name = data[0].name;

With Lacy, the same thing as a single lazy chain:

import { lacy } from "@farbenmeer/lacy";
const name = await lacy(fetch("/api/users")).json()[0].name;
import { lacy } from "@farbenmeer/lacy";
const users = lacy(Promise.resolve([
{ name: "Alice", age: 30 },
{ name: "Bob", age: 25 },
]));
await users[0].name; // "Alice"
await users.map((u) => u.name); // ["Alice", "Bob"]
// Deeply nested values
const data = lacy(Promise.resolve({ deeply: { nested: { value: 42 } } }));
await data.deeply.nested.value; // 42
// Raw promise escape hatch
const raw = await users.$; // [{ name: "Alice", ... }, ...]
  • Property access (obj.key) — returns a new LacyPromise resolving to the property value
  • Method calls (obj.method(args)) — invokes the method on the resolved value and wraps the result
  • await — resolves the full deferred chain
  • .$ — unwraps to the raw underlying Promise