diff --git a/README.md b/README.md index 15ffd80..17849d7 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ if (error) { case 'outOfStock': console.log(error.resource.message); // Follow-up links on errors can be navigated as well (with full type safety) - let restocked = await navigate(error.resource.restock); + const restocked = await navigate(error.resource.restock); console.log(`Notify user that ${restocked.name} needs to be restocked`); return; // Default branch handles unexpected errors (network, error status, parse errors) diff --git a/docs/hateoas-bff-example.md b/docs/hateoas-bff-example.md index 5747b71..0a4c275 100644 --- a/docs/hateoas-bff-example.md +++ b/docs/hateoas-bff-example.md @@ -41,7 +41,7 @@ Everything runs in one Fastify process for ease of running. The logical separati ## 1b. Link conventions by backend Each backend uses a different link representation to demonstrate that `typesafe-hypermedia` -is format-agnostic (see AGENTS.md Core Concept #5 and `docs/how-it-works.md §9`): +is format-agnostic (see AGENTS.md Core Concept #5 and `docs/how-it-works.md §8`): | Backend | Link pattern | Example | Why | |---------|-------------|---------|-----| @@ -121,14 +121,14 @@ The client's job is to render whichever `view.*` sub-object is populated. Becaus | View | Triggered by | Composes from | |----------------------|-------------------------------------------|---------------| -| **Home** | `view=home` (or no `view`) | PIM (featured by tag) + ERP (quotes) | -| **Category** | `view=category&category=` | PIM + ERP | -| **Product detail** | `view=product&sku=` | PIM (product, reviews, related) + ERP (quote, stock) + DAM (images, optional) | -| **Cart** | `view=cart` | PIM (names) + ERP (quotes) + CRM (offers for promo) — plus recommendations via PIM `relatedProductsUrl` | -| **Wishlist** | `view=wishlist` | PIM + ERP | -| **Search results** | `view=search&search=` | PIM + ERP (when results) | -| **Orders list** | `view=orders` | ERP | -| **Order confirmation** | `view=order-confirmation&orderId=` | ERP (falls back to orders list + danger toast if id not found) | +| **Home** | `GET /bff/home` | PIM (featured by tag) + ERP (quotes) | +| **Category** | `GET /bff/category?category=` | PIM + ERP | +| **Product detail** | `GET /bff/product?sku=` | PIM (product, reviews, related) + ERP (quote, stock) + DAM (images, optional) | +| **Cart** | `GET /bff/cart` | PIM (names) + ERP (quotes) + CRM (offers for promo) — plus recommendations via PIM `relatedProductsUrl` | +| **Wishlist** | `GET /bff/wishlist` | PIM + ERP | +| **Search results** | `GET /bff/search?search=` | PIM + ERP (when results) | +| **Orders list** | `GET /bff/orders` | ERP | +| **Order confirmation** | `GET /bff/order-confirmation?orderId=` | ERP (falls back to orders list + danger toast if id not found) | Every view builder threads a `used: Set` and calls `used.add('pim'|'erp'|'crm'|'dam')` as it fetches. `buildDataSources(used)` turns the set into the `dataSources` field at the end. This gives the UI an automatic, honest attribution bar at the bottom of every page. diff --git a/docs/how-it-works.md b/docs/how-it-works.md index 7116117..3b7fb4e 100644 --- a/docs/how-it-works.md +++ b/docs/how-it-works.md @@ -335,7 +335,7 @@ A key insight: error resources are not special. They are regular resources that This design keeps the API definition simple and consistent. -## 9. Design Decisions (The "Why") +## 8. Design Decisions (The "Why") ### Why Support Both Link Objects and String Properties? @@ -377,7 +377,7 @@ The library doesn't pick winners - it provides the tools and lets developers cho ### Why Simple Initialization? * **Ease of Use**: `linkTo()` provides a simple starting point - validates config and returns the root link. -* **Type Safety**: Explicit `apiRoot` parameter ensures correct return type. +* **Type Safety**: Explicit `resource` parameter ensures correct return type. * **Separation of Concerns**: Initialization separated from navigation (use `navigate()` to navigate). * **Trade-off**: Resources must stay in memory for navigation (metadata stored in module-level `WeakMap`s keyed by object identity). @@ -389,7 +389,7 @@ The library doesn't pick winners - it provides the tools and lets developers cho * **Type Safety**: TypeScript enforces handling through the tuple pattern. You cannot accidentally ignore errors once `expect` is declared. * **Trade-off**: More verbose than try/catch, but explicit and type-safe. Forces thinking about error cases upfront. -## 10. Known Gaps & Roadmap +## 9. Known Gaps & Roadmap **Phase 1: Core Completeness** @@ -397,8 +397,8 @@ The library doesn't pick winners - it provides the tools and lets developers cho **Phase 2: Robustness** * ✅ **Performance (RESOLVED)**: Link extraction uses compiled path accessors cached per ResourceDefinition. First fetch compiles optimized traversal functions, subsequent fetches reuse them. No repeated traversals for similar paths (e.g., `items[].author` and `items[].category` share traversal). Performance optimized for production use. -* **Reattachment after serialization**: Need a utility to reattach runtime metadata to objects that have been serialized/deserialized (Note: This is generally an anti-pattern in HATEOAS - see Section 7.3 for best practices). +* **Reattachment after serialization**: Need a utility to reattach runtime metadata to objects that have been serialized/deserialized (Note: Caching hrefs like this is an anti-pattern in HATEOAS — you lose the server's ability to evolve URLs. Prefer re-fetching from the root navigable when the link might have changed.). -## 11. Lessons Learned +## 10. Lessons Learned * *Placeholder: Document failed refactoring attempts here to avoid repeating mistakes.* diff --git a/docs/roadmap.md b/docs/roadmap.md index 751f691..79c1629 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -18,7 +18,7 @@ Debugging "Link metadata not found" errors currently requires developers to ment ### Approach -Export a `debugNavigable(obj)` function that queries the global `navigableOwner` map and the owning client's `MetadataStore`, returning a structured snapshot: +Export a `debugNavigable(obj)` function that queries the `apiClientByNavigable` and `linksByNavigable` WeakMaps in `src/runtime-metadata.ts`, returning a structured snapshot: ```typescript debugNavigable(shop)