UK

Тема

Колір акценту

Тема й колір збережуться на satelit.md і в застосунку.

Панель Обрати тариф

Законодавчий дайджест

Щоранку: що опубліковано в Monitorul Oficial за темами й видавцями, які вас цікавлять. HTML-файл, готовий до надсилання електронною поштою.

Як це працює

  1. Дізнається, які дні мають дайджест, з /v1/law/digests.
  2. Бере дайджест найновішого дня.
  3. Фільтрує акти за вашими темами й видавцями. Важливі акти йдуть першими.
  4. Пише digest-YYYY-MM-DD.html з посиланнями на офіційну сторінку кожного акта.

Скільки коштує: 2 кредити за список, 2 за дайджест: 4 кредити на день, 120 на місяць. Вміщується в тариф Start. З тарифу Creator можна отримувати подію law.digest замість опитування.

Як запустити

bash
export SATELIT_KEY=sat_live_...
TOPICS=business,justice ISSUERS=guvernul node law_digest.mjs

Що виводить

stdout
digest-2026-10-31.html: 6 of 20 acts, 4 credits

Повний скрипт

law_digest.mjs
#!/usr/bin/env node
// Law digest: what Monitorul Oficial published, on your topics and issuers, as an HTML file ready to e-mail.
//   SATELIT_KEY=sat_live_... TOPICS=taxes,business ISSUERS=guvernul node law_digest.mjs
// No dependencies, Node 18 or newer. Put it in cron: 0 8 * * 1-6 node /path/law_digest.mjs
import { writeFileSync } from "node:fs";

const BASE = process.env.SATELIT_BASE ?? "https://api.satelit.md/v1";
const KEY = process.env.SATELIT_KEY;
const LANG = process.env.DIGEST_LANG ?? "ro";
const TOPICS = (process.env.TOPICS ?? "").split(",").filter(Boolean);
const ISSUERS = (process.env.ISSUERS ?? "").split(",").filter(Boolean);
if (!KEY) throw new Error("Set SATELIT_KEY");

async function api(path, params = {}) {
  const url = new URL(BASE + path);
  for (const [k, v] of Object.entries({ lang: LANG, ...params })) url.searchParams.set(k, v);
  const res = await fetch(url, { headers: { Authorization: `Bearer ${KEY}` } });
  const body = await res.json();
  if (!res.ok) throw new Error(`${path}: ${body.error.code}: ${body.error.message}`);
  return body;
}

const esc = (s = "") => String(s).replace(/[&<>"]/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" })[c]);

const days = await api("/law/digests", { days: 7 });
if (!days.data.length) {
  console.log("No digest in the last 7 days");
  process.exit(0);
}
const { date } = days.data[0];
const digest = await api(`/law/digests/${date}`);

const wanted = (act) =>
  (!TOPICS.length || TOPICS.includes(act.topic)) && (!ISSUERS.length || ISSUERS.includes(act.issuer_key));
const acts = digest.data.items.filter(wanted).sort((a, b) => Number(b.important) - Number(a.important));

const rows = acts.map((a) =>
  `<li${a.important ? ' style="font-weight:600"' : ""}><a href="${esc(a.url)}">${esc(a.heading)}</a><br><small>${esc(a.issuer_name)}, ${esc(a.mo_ref)}</small></li>`,
);
const html = `<!doctype html><html lang="${LANG}"><meta charset="utf-8"><title>${esc(digest.data.title)}</title>
<h1>${esc(digest.data.title)}</h1><p>${esc(digest.data.intro ?? "")}</p>
<ul>${rows.join("\n") || "<li>0</li>"}</ul>
<p><small>${esc(digest.meta.attribution ?? "")}</small></p></html>\n`;

const file = `digest-${date}.html`;
writeFileSync(file, html);
console.log(`${file}: ${acts.length} of ${digest.data.items.length} acts, ${days.meta.credits + digest.meta.credits} credits`);