Fetches live Singapore supermarket homepage/catalog snapshots via two separate CLIs: FairPrice (Next.js __NEXT_DATA__) and Sheng Siong (Meteor DDP). Use when the user works in clisupermarket, wants FairPrice or Sheng Siong product or homepage data, grocery CLI, ss-live, fp-live, or live supermarket scraping.
Use this skill when the task involves the clisupermarket repo, or when the user asks for live product/homepage data from NTUC FairPrice (fairprice.com.sg) or Sheng Siong (shengsiong.com.sg). These are two different systems—do not mix their CLIs or assumptions.
From the repo root:
npm install
npm run build
Requires Node 20+ (fetch for FairPrice; ws + ejson for Sheng Siong). Built entrypoints live under dist/ (not committed).
| Goal | Command | Mechanism |
|---|---|---|
| FairPrice homepage rails (banners, product swimlanes, categories, promos) | node dist/fp-live.js | HTTP GET → parse <script id="__NEXT_DATA__"> |
| Sheng Siong homepage sections + products | node dist/ss-live.js | WebSocket DDP → wss://shengsiong.com.sg/websocket |
| FairPrice cart (list / remove / clear / add / set qty) | node dist/cart.js fp … | Cookie auth → GET/DELETE/POST https://website-api.omni.fairprice.com.sg/api/cart |
| Sheng Siong cart | node dist/cart.js ss … | DDP + Cookie header → Sessions.getSessionDataByKey / Sessions.updateData / Products.getOneByIdOrSlug; optional SS_SESSION_KEY when sess-key rotates |
fp-livehttps://www.fairprice.com.sg/). Override with -u <url>.ProductCollection, CategoryCollection, PromoCollection, ImageSlideShow, VoucherSwimlane, etc.page_size × page 1). pagination.total_pages shows how many pages exist on-site; this repo does not fetch page 2+ (would need their internal browse API).--pretty (stdout JSON), -o <file>, --omit-products (counts/metadata only, smaller output).node dist/fp-live.js
node dist/fp-live.js --omit-products -o /tmp/fp.json
ss-liveHomePageSections.getAllActive + Products.getByCategoryId (~20 SKUs per category strip).--full uses Categories.getOneById + paginated Products.getByAllSlugs. The server returns cumulative product lists per page; the code slices cumulative.slice(alreadyLoaded.length)—do not “append full array” per page.{"$type":"oid","$value":"<24 hex>"} in method params—not BSON ObjectId binary in EJSON.--full, --page-size (with --full), --pause <ms> between calls, -o, --pretty.node dist/ss-live.js
node dist/ss-live.js --full --page-size 80 -o /tmp/ss.json
./dist/fairpriceNextData.js after build—fetchFairpriceLiveCatalog(url, { includeProducts }), parseNextDataScript(html)../dist/shengSiongDdp.js—ShengSiongDdpClient, fetchAllProductsForCategorySlug, meteorOid.--pause) for Sheng Siong; avoid hammering FairPrice HTML.Optional browser export JSON may live at:
secrets/fairprice-cookies.json — FairPrice (auth_token, connect.sid, …)secrets/sheng-siong-cookies.json — Sheng Siong (sess-key, Incapsula/WAF cookies, …)The secrets/ tree is gitignored (except secrets/README.md). Do not commit or paste cookie files into issues or PRs.
cart fp …)secrets/fairprice-cookies.json, or -c <path> / FAIRPRICE_COOKIES.cart fp list, cart fp remove <itemId>, cart fp clear (uses GET + DELETE with storeId + itemId query params).cart fp add and cart fp set POST the merged cart body the site uses ({ storeId, cart: { items: [{ id, q, t }, ...] } }), not { productId, quantity } alone. Exit code 2 only if the fingerprint still does not change after POST.README.md — human-oriented overview and examplessecrets/README.md — where to put fairprice-cookies.jsonsrc/fairpriceNextData.ts, src/fp-live.tssrc/fairpriceSession.ts, src/fairpriceCartApi.ts, src/cart.tssrc/shengSiongDdp.ts, src/shengSiongSession.ts, src/shengSiongCartApi.ts, src/ss-live.ts