Один файл без залежностей. Працює в Node 18+ і сучасних браузерах (вбудовані fetch, FormData, Web Crypto). Версія - 1.7.2 (константа SDK_VERSION у файлі). Для кожної операції API у клієнті є метод.
Встановлення
Завантажити grem.ts і покласти в проєкт. Пакета в npm немає.
Швидкий старт
import { GremClient } from './grem';
const grem = new GremClient({ apiKey: process.env.GREM_API_KEY });
const { estimate } = await grem.valuation.express({
propertyCategory: 'apartment',
addressText: 'Torstraße 12, Berlin',
totalArea: 64,
});
console.log(estimate.pricePoint, estimate.currency);
Базова адреса за замовчуванням - https://developers.grem.capital/api/v1 (параметр baseUrl). Ключ створюється в кабінеті: API → Ключі.
Завдання
Кожна відповідь завдання містить jobId (API 1.6.0+). jobs.wait опитує статус (безкоштовно), поки state не стане completed, partial, failed або action_required. Невдалий запит статусу (мережа, 5xx, 429) його не зупиняє: опитування триває, до 5 збоїв поспіль:
const job = await grem.text.generate({ city: 'Berlin', totalArea: 64, language: 'en' });
const done = await grem.jobs.wait('text/generate', job.jobId);
if (done.state === 'failed') throw new Error('generation failed');
Перевірка звіту чекає на підтвердження:
const form = new FormData();
form.append('file', pdfBlob, 'report.pdf');
const review = await grem.valuation.review(form);
await grem.valuation.confirmReview(review.jobId);
const result = await grem.jobs.wait('valuation/review', review.jobId);
Що є в клієнті
| Група | Методи |
|---|---|
| ключ | ping(), me() |
| оцінка | valuation.express, valuation.report, valuation.rent, valuation.review, valuation.confirmReview |
| контент | content.generate, text.generate, video.create, video.music, video.endings, avatar.video, avatar.list |
| матеріали | site.create, pdf.create, flyer.create, draft.extract, photo.enhance, floorplan.create |
| довідники | voices(), toolsStatus(), works(), dictionaries() |
| завдання і файли | jobs.get, jobs.wait, artifact(path, { range, signal }), uploads.images |
| об'єкти | objects.list, get, create, update, delete, setAgency, setAssignee |
| ліди | leads.list, get, create, update, delete, matches, claim, returnToPool |
| Swipe Match | match.list, get, events, sendEvent |
| вебхуки | webhooks.list, create, update, delete, test, deliveries, resend |
| чат | chat.createSession, listSessions, updateSession, deleteSession, sendMessage, history, stream |
Інструменти з файлами приймають FormData - як заповнювати поля, описано на сторінці кожного інструмента.
Пісочниця
З тестовим ключем опція simulate задає результат кожного імітованого виклику (Пісочниця):
const grem = new GremClient({ apiKey: process.env.GREM_TEST_KEY, simulate: 'failed' });
З бойовим ключем опція simulate викидає помилку під час створення клієнта: виклик виконався б насправді.
За замовчуванням запит чекає до 5 хвилин (timeoutMs): запуск інструмента може тривати понад хвилину, а обрив не зупиняє ні роботу, ні її оплату.
Клієнт повторює відхилений виклик після Retry-After, до maxRetries разів (за замовчуванням 3, не більше 10; 0 вимикає повтори): 429 - завжди, виклик із перевищенням ліміту не оброблено; 503 - для читання, а для запису лише з Idempotency-Key: 503 може прийти вже після побічного ефекту. Retry-After понад 30 секунд клієнт не чекає: помилка викидається одразу. Ваш AbortSignal перериває і паузу. Передайте цей signal у request(). Без Retry-After паузи - 1, 2, 4 ... секунди. Завантаження (uploads.images) після 503 не повторюється (після 429 повторюється: завантаження не оброблено). Переданий signal замінює тайм-аут запиту (timeoutMs).
Помилки
Відповідь 4xx чи 5xx кидає GremError з полями status, title, detail, code, errors, requestId і retryAfter (для 429 і 503):
import { GremError } from './grem';
try {
await grem.text.generate({});
} catch (e) {
if (e instanceof GremError) console.error(e.status, e.title, e.code, e.detail);
}
Безпечні повтори
Останній аргумент методів, що запускають інструмент чи створюють запис, - Idempotency-Key:
await grem.pdf.create({ pdfName: 'Presentation', objectId, language: 'ENG' }, crypto.randomUUID());
uploads.images теж приймає ключ, але API його ігнорує: повторне завантаження зберігає файли ще раз.
Вебхуки
import { verifyWebhookSignature } from './grem';
app.post('/grem-hook', express.raw({ type: 'application/json' }), async (req, res) => {
const raw = req.body.toString('utf8');
const ok = await verifyWebhookSignature(process.env.GREM_WEBHOOK_SECRET, req.get('x-grem-signature'), raw);
if (!ok) return res.status(400).send('invalid signature');
const event = JSON.parse(raw);
res.sendStatus(200);
});
Чат
const session = await grem.chat.createSession();
const stop = new AbortController();
const streaming = grem.chat
.stream(session.sessionId, (data) => console.log(data), stop.signal)
.catch((e) => { if (e.name !== 'AbortError') throw e; }); // stop.abort() rejects with AbortError
await grem.chat.sendMessage(session.sessionId, 'Привіт!');
stop.abort(); // when you no longer need the stream
await streaming;
Без третього аргументу sendMessage надсилає випадковий clientMessageId (і в Node 18). Щоб безпечно повторити повідомлення, передайте свій id і використовуйте його повторно: на один id відповідають і списують один раз.