typectx v0.7: Request Suppliers and Unified Types
Version 0.7 brings a cleaner mental model to typectx by renaming "Resources" to "Request Suppliers" and unifying the Resource and Product types into a single Supply type. These breaking changes make the library's intent clearer and reduce conceptual overhead.
Let's dive in.
The Big Rename: Resources → Request Suppliers
In previous versions, we had two kinds of suppliers:
- Resource Suppliers — for simple values you pack at the entry point
- Product Suppliers — for values created by factories with dependencies
The problem? "Resource" is vague. It could mean anything—config, constants, database connections. This made it unclear when to use a Resource vs a Product.
v0.7 renames Resource Suppliers to Request Suppliers, which better communicates their primary purpose: holding data from the user's request (session, params, cookies, headers, etc.) that cannot be derived from other suppliers.
// v0.6 - The old way
const $session = market.offer("session").asResource<Session>()
// v0.7 - The new way
const $session = market.add("session").request<Session>()
This isn't just a cosmetic change—it guides better architecture. When you see request(), you immediately know this supplier is for request-scoped data that enters your system from outside.
API Changes: offer() → add()
The market API has been streamlined:
| v0.6 | v0.7 |
|---|---|
market.offer("name") | market.add("name") |
.asResource<T>() | .request<T>() |
.asProduct({ ... }) | .product({ ... }) |
The new names are shorter and more direct:
// v0.6
const $session = market.offer("session").asResource<{ userId: string }>()
const $db = market.offer("db").asProduct({
suppliers: [],
factory: () => createDbConnection()
})
// v0.7
const $session = market.add("session").request<{ userId: string }>()
const $db = market.add("db").product({
suppliers: [],
factory: () => createDbConnection()
})
Unified Types: Resource + Product → Supply
Previously, packing a Resource gave you a Resource<T>, while assembling a Product gave you a Product<T>. This distinction was mostly artificial—both are just value containers with an unpack() method.
v0.7 unifies these into a single Supply type:
// v0.6 types
type Resource<VALUE, SUPPLIER> = {
unpack(): VALUE
supplier: SUPPLIER
}
type Product<VALUE, SUPPLIER, DEPS, RESOLVED, CTX> = {
unpack(): VALUE
deps: DEPS
supplies: RESOLVED
supplier: SUPPLIER
_: { ctx: CTX; packed: boolean }
}
// v0.7 - unified
type Supply<VALUE, SUPPLIER, DEPS, RESOLVED> = {
unpack(): VALUE
deps: DEPS
supplies: RESOLVED
supplier: SUPPLIER
_: { ctx: CTX; packed: boolean }
}
Both $request.pack(value) and $product.assemble(supplies) now return a Supply. The only difference is that request supplies have empty deps and supplies objects, while product supplies have populated ones.
This simplifies generic code that works with both:
// v0.6 - needed to handle both types
function processSupply(supply: Resource | Product) {
return supply.unpack()
}
// v0.7 - just one type
function processSupply(supply: Supply) {
return supply.unpack()
}
Type Renames
If you're working with typectx's types directly, here's the mapping:
| v0.6 Type | v0.7 Type |
|---|---|
ResourceSupplier | RequestSupplier |
Resource | Supply |
Product | Supply |
Name Validation
v0.7 enforces that supplier names follow JavaScript identifier rules: they can only contain letters, digits, underscores, or $ signs, and cannot start with a digit.
// ✅ Valid names
market.add("session")
market.add("$user")
market.add("_private")
market.add("user123")
// ❌ Invalid names (will throw)
market.add("123user") // starts with digit
market.add("my-supplier") // contains hyphen
market.add("my.supplier") // contains dot
This ensures supplier names work seamlessly as object keys in deps destructuring.
@typectx/react Updates
The React adapter updates its types to match:
// Type imports
import type {
RequestSupplier, // was ResourceSupplier
Supply, // was Product | Resource
Deps,
Resolved
} from "typectx"
The hooks (useDeps, useAssembleComponent, useAssembleHook) work exactly the same—just with the updated type names internally.
Migration Guide
Step 1: Update market calls
// Before
const $session = market.offer("session").asResource<Session>()
const $db = market.offer("db").asProduct({ ... })
// After
const $session = market.add("session").request<Session>()
const $db = market.add("db").product({ ... })
Step 2: Update type imports (if using them)
// Before
import type { ResourceSupplier, Resource, Product } from "typectx"
// After
import type { RequestSupplier, Supply } from "typectx"
Step 3: Fix any invalid supplier names
If you have supplier names with hyphens, dots, or starting with digits, rename them to valid JavaScript identifiers.
Why These Changes?
- Clearer intent: "Request Supplier" immediately communicates that this is for request-scoped data
- Simpler types: One
Supplytype instead of two reduces cognitive load - Better API:
market.add().request()andmarket.add().product()are more concise - Safer names: Enforcing identifier rules prevents edge cases in
depsdestructuring
These are breaking changes, but the migration is straightforward—mostly find-and-replace.
npm install typectx@latest @typectx/react@latest