@forgeco/ext-feed
v0.3.4
Published
Forge extension (FEED): projects a store's published assortment as a Google Shopping XML feed. Regenerated from outbox events (the app's event-script declares history: 'skip') with a daily scheduler backstop; served by the storefront at a stable public UR
Readme
@forgeco/ext-feed
The published half of a Forge app: the Google Shopping XML generator.
A Forge app has two halves. Its manifest, its event-script, its scheduled job and its ficha action run inside the kernel, which already ships them; what a storefront needs is the piece that turns a catalog page into a feed document, and that is all this package contains.
⚠️ It ships no React and no CSS. Unlike the block packages next to it, this half is a pure function: products in, one XML document out — no I/O, no clock, no environment. That is deliberate. The route that serves the feed belongs to the storefront (the kernel is not reachable from outside, so a crawler could never fetch it from the port); what belongs to the app is the document itself, and a pure function is the shape that a test can hold still and a customer can replace.
Install
The Forge packages are published as tarballs on the GitHub Release, so install them together — they resolve each other from the sibling files, not from a registry:
npm i ./forgeco-ext-feed-<version>.tgzUse it
import { buildGoogleFeed } from '@forgeco/ext-feed/google-xml';
const { xml, included, skipped } = buildGoogleFeed(products, {
storeTitle: 'Minha Loja',
storeLink: 'https://minhaloja.com.br',
linkFor: (product) => `https://minhaloja.com.br${canonicalProductPath(product)}`,
brandOf: (product) => brands[product.brand_id ?? '']?.name,
});products is what the read port serves (GET /v1/read/products?store=…) — the published assortment, already
filtered by the kernel. The generator builds no URL of its own: the product link and the brand name are
resolved by the caller, because both already have exactly one source, and re-deriving either here would be a
second one.
skipped is not decoration. An item with no resolvable image, no link or an unusable price is left OUT and
COUNTED — a feed that shrank has to be able to say what it dropped, because "the catalog is empty" and "the
generator is broken" produce the same empty document.
Wire it into Next
// next.config.mjs
export default {
transpilePackages: ['@forgeco/ext-feed'],
};Without it the build fails loudly (Module parse failed: Unexpected token on the first export type) — it
never degrades into an app that half works. This package ships TypeScript source, on purpose: your bundler
compiles it with your settings, and its types ARE the source.
Money
Prices arrive from the kernel as integer cents and become Google's decimal here, on the way out, by integer arithmetic. No float ever touches the value. If you fork this file, keep that property: it is the one thing in here that fails silently and only in somebody else's feed.
