@86d-app/core
v0.0.4
Published
Core package for 86d dynamic commerce platform
Readme
[!WARNING] This project is under active development and is not ready for production use. Please proceed with caution. Use at your own risk.
@86d-app/core
Core types and utilities for building modules in the 86d module system. This package provides everything module authors need to create publishable, type-safe modules.
Installation
npm install @86d-app/core
# or
pnpm add @86d-app/coreFeatures
- Type-safe module definition - Full TypeScript support for modules, endpoints, and controllers
- Endpoint utilities - Re-exports from
better-callandzodfor defining HTTP endpoints - Client API - Auto-generated React Query hooks for consuming module endpoints
- Module dependencies - Declare required modules with the
requiresfield
Creating a Module
A module is a self-contained unit that provides endpoints, controllers, and optionally a database schema.
import {
createEndpoint,
z,
type Module,
type ModuleContext,
type ModuleService,
} from "@86d-app/core";
// Define your service interface
interface MyService extends ModuleService {
id: "my-module";
version: "1.0.0";
getData(): Promise<string>;
}
// Create endpoints
const getItems = createEndpoint(
"/items",
{ method: "GET" },
async (ctx) => {
const context = ctx.context as ModuleContext;
return { items: [] };
}
);
const createItem = createEndpoint(
"/items",
{
method: "POST",
body: z.object({
name: z.string(),
price: z.number().positive(),
}),
},
async (ctx) => {
const { body } = ctx;
const context = ctx.context as ModuleContext;
// Create item logic...
return { id: "123", ...body };
}
);
// Export module factory
export default function myModule(): Module {
return {
id: "my-module",
// Declare dependencies (optional)
requires: ["auth"],
// Initialize module and register service
init: async (ctx: ModuleContext) => {
const service: MyService = {
id: "my-module",
version: "1.0.0",
async getData() {
return "Hello from my module!";
},
};
return { service };
},
// Define endpoints
endpoints: {
store: {
"/items": createItem,
"/items/list": getItems,
},
admin: {
// Admin endpoints here
},
},
};
}Module Dependencies
Use the requires field to declare dependencies on other modules:
export default function checkout(): Module {
return {
id: "checkout",
requires: ["cart", "products"], // Must be initialized before this module
init: async (ctx: ModuleContext) => {
// Safe to access - runtime guarantees these exist
const cartService = ctx.services.cart as CartService;
const productsService = ctx.services.products as ProductsService;
// No null checks needed!
const cart = await cartService.getCart({ customerId: "..." });
},
};
}The runtime will:
- Validate required modules are initialized before your module
- Throw a clear error if dependencies are missing
- Guarantee services from required modules exist
Client API
The client package provides React Query integration for consuming module endpoints.
Setup
import { ModuleClientProvider } from "@86d-app/core/client";
import cart from "@my-org/cart";
import products from "@my-org/products";
function App({ children }) {
return (
<ModuleClientProvider
baseURL="/api"
modules={[cart(), products()]}
headers={() => ({
Authorization: `Bearer ${getToken()}`,
})}
>
{children}
</ModuleClientProvider>
);
}Using Hooks
import { useModuleClient } from "@86d-app/core/client";
function ProductList() {
const client = useModuleClient();
// GET endpoints become queries
const { data, isLoading } = client
.module("products")
.store["/products"]
.useQuery({ category: "electronics" });
// POST/PUT/DELETE endpoints become mutations
const addToCart = client.module("cart").store["/cart"].useMutation({
onSuccess: () => {
// Invalidate related queries
client.module("cart").store["/cart/get"].invalidate();
},
});
if (isLoading) return <div>Loading...</div>;
return (
<ul>
{data?.products.map((product) => (
<li key={product.id}>
{product.name}
<button
onClick={() =>
addToCart.mutate({
productId: product.id,
quantity: 1,
price: product.price,
})
}
>
Add to Cart
</button>
</li>
))}
</ul>
);
}Non-React Usage
import { createModuleClient } from "@86d-app/core/client";
import cart from "@my-org/cart";
const client = createModuleClient([cart()], {
baseURL: "https://api.example.com",
});
// Direct fetch (no React hooks)
const cartData = await client.module("cart").store["/cart/get"].fetch();API Reference
Types
| Export | Description |
|--------|-------------|
| Module | Main module definition interface |
| ModuleContext | Runtime context passed to endpoints and init |
| ModuleService | Base interface for services exposed to other modules |
| ModuleSchema | Database schema definition type |
| ModuleDataService | Interface for scoped data access |
| BaseAdapter | Base interface for module adapters |
Endpoint Utilities (re-exported from better-call)
| Export | Description |
|--------|-------------|
| createEndpoint | Create an HTTP endpoint |
| createRouter | Create a router from endpoints |
| z | Zod schema builder |
| Endpoint | Endpoint type |
| EndpointContext | Context passed to endpoint handlers |
Client API
| Export | Description |
|--------|-------------|
| ModuleClientProvider | React provider component |
| useModuleClient | Hook to access the client |
| createModuleClient | Factory for non-React usage |
| createQueryClient | Create a QueryClient instance |
| getQueryClient | Get/create singleton QueryClient |
Module Context
The ModuleContext provides access to:
interface ModuleContext {
storeId: string; // Tenant ID
data: ModuleDataService; // Scoped data access
adapter: Record<string, any>; // Module adapters
services: Record<string, ModuleService>; // Other modules' services
options: Record<string, any>; // Module configuration
modules: string[]; // Enabled module IDs
session?: {
customerId?: string;
guestId?: string;
isAdmin?: boolean;
};
}Best Practices
- Export service types - Let other modules import your service interface
- Use
requires- Declare dependencies explicitly for better error messages - Scope data access - Always use
ctx.datainstead of direct DB access - Version your services - Include a version string for compatibility checks
- Keep modules focused - Each module should have a single responsibility
