A small Node.js sidecar microservice that provides two Hebcal APIs which are
not available natively in the Go port of Hebcal web APIs,
hebcal-api-go. The Go service handles
date conversion, zmanim, geolocation and Shabbat times with high throughput, but
it has no leyning (Torah reading) data and cannot compute every daily-learning
series on its own. This service fills those two gaps by wrapping the mature
Node.js @hebcal packages and exposing them over a
local Unix-domain socket.
The two APIs are:
- Daily Learning (
/learning) — the 20 daily-learning series from@hebcal/learning, used by the PDF calendar feature. Six of them cannot be generated in-process by hebcal-go — Sefer HaMitzvot, Kitzur Shulchan Arukh, Arukh HaShulchan, Amud HaYomi (Dirshu), Chofetz Chaim and Shemirat HaLashon — which is the main reason this service exists. - Leyning (
/leyning) — Torah readings for Shabbat and holidays, including the triennial cycle, from@hebcal/leyningand@hebcal/triennial. This backs the/shabbat?cfg=jsonhandler in hebcal-api-go.
Responses use Hebcal's "classic API" JSON shape, produced by
@hebcal/rest-api, so they drop in where
hebcal-api-go previously called out to hebcal-web over HTTP.
The server listens on a Unix-domain socket rather than a TCP port:
/run/hebcal/readings-svc.sock
Override the path with --socket (or -s, or the SOCKET_PATH environment
variable) — useful on macOS, which has no /run, and where the whole path has
to stay under the ~104-byte sun_path limit:
node index.js --socket /tmp/readings-svc.sockOn startup a stale socket file is removed, and the socket is chmod 0666 so the
web app's user can connect to it. The socket is cleaned up on SIGINT,
SIGTERM and normal exit. All responses are application/json; errors are
returned as { "error": "..." } with HTTP status 400 (bad request, e.g. a
missing or malformed date) or 404 (unknown path).
Liveness probe. Returns 200 {"status":"ok"}.
Daily-learning readings for a date range. Each series is toggled on with its
query code set to on or 1.
Query parameters
| Parameter | Required | Description |
|---|---|---|
start |
yes | Start date, YYYY-MM-DD |
end |
yes | End date, YYYY-MM-DD |
lg |
no | Locale (default en) |
i |
no | i=on for the Israel schedule |
Series toggles (<code>=on)
| Code | Series |
|---|---|
F |
Daf Yomi |
myomi |
Mishna Yomi |
dpy |
Perek Yomi |
nyomi |
Nach Yomi |
dty |
Tanakh Yomi |
dps |
Psalms (Tehillim) |
d929 |
929 |
dr1 |
Rambam (1 chapter/day) |
dr3 |
Rambam (3 chapters/day) |
dsm |
Sefer HaMitzvot |
yyomi |
Yerushalmi (Vilna) |
yys |
Yerushalmi (Schottenstein) |
dcc |
Chofetz Chaim |
dshl |
Shemirat HaLashon |
ayd |
Amud HaYomi (Dirshu) |
dw |
Daf-a-Week |
dpa |
Pirkei Avot (summer) |
ahsy |
Arukh HaShulchan Yomi |
dksa |
Kitzur Shulchan Arukh |
Example
GET /learning?start=2026-08-14&end=2026-08-14&dsm=on&dksa=on
Torah readings for Shabbat and holidays that fall within a date range. Only
events that have leyning are returned. Parsha HaShavua events (from 5745 onward)
also include the triennial cycle reading.
Query parameters
| Parameter | Required | Description |
|---|---|---|
start |
yes | Start date, YYYY-MM-DD |
end |
yes | End date, YYYY-MM-DD |
i |
no | i=on for the Israel schedule |
Example
GET /leyning?start=2026-08-14&end=2026-08-22
Each returned item carries a leyning object with the aliyot, torah summary,
haftarah (and the haftarah_sephardic / haftarah_chabad variants where they
differ), maftir, and, for a parsha, the triennial aliyot.
English only, deliberately — this endpoint takes no lg. The readings are
locale-invariant (book names, verse references and the | Shabbat Shekalim
reasons come out of @hebcal/leyning in English whatever the locale), so a
locale would only change each item's title, which no caller reads: hebcal-api-go
matches items to its own events by the untranslated event description
(title_orig, or title when the two are the same). /learning does take lg,
because its titles are the content.
Requires Node.js (ESM; the package is "type": "module").
npm install # install dependencies
node index.js # start the server on the Unix socket
npm run lint # lint the *.js source files with oxlintTo exercise the service without a Unix-socket HTTP client, use curl --unix-socket:
curl --unix-socket /run/hebcal/readings-svc.sock \
'http://unix/leyning?start=2026-08-14&end=2026-08-22'| File | Responsibility |
|---|---|
index.js |
HTTP server, Unix-socket lifecycle, routing |
learning.js |
/learning handler and query-code → series mapping |
leyning.js |
/leyning handler, including triennial readings |
date.js |
start/end date parsing and validation |
systemd/hebcal-readings.service runs it as a DynamicUser unit with
RuntimeDirectory=hebcal, which is what creates and cleans up /run/hebcal.
BSD-2-Clause. See package.json.