@rewloy/node 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,49 @@ https://rewloy.com/gelistiriciler/degisiklikler
5
5
 
6
6
  This library's releases. The API's own changes are listed at the link above.
7
7
 
8
+ ## 0.2.0 (2026-10-05)
9
+
10
+ Rewloy API 1.0.5'e göre yeniden üretildi: 255 işlem (0.1.0'da 237). Kasa için
11
+ `recordSale` ve `reverseSale`; README'de yeni bir kasa örneği, test modu ve
12
+ `baseUrl`.
13
+
14
+ Regenerated from Rewloy API 1.0.5: 255 operations (237 in 0.1.0).
15
+
16
+ - **New operations (18).**
17
+ - *Till:* `recordSale` (`POST /v1/passes/{serial}/sale`: write a completed
18
+ sale to a card; the card type decides what is written) and `reverseSale`
19
+ (`POST /v1/passes/{serial}/sale/reverse`: take a refunded sale back).
20
+ - *Checkout codes and shop connections:* `quoteCheckoutCode`,
21
+ `holdCheckoutCode`, `captureCheckoutOrder`, `releaseCheckoutOrder`,
22
+ `refundCheckoutOrder`, `listOrderRedemptions`, `listShopRedemptions`,
23
+ `releaseShopRedemption`, `refundShopRedemption`, `setShopSettings`,
24
+ `setShopCeiling`, `setShopPluginAbilities`, and for the card holder
25
+ `holderCheckoutCodes`, `mintHolderCheckoutCode`, `cancelHolderCheckoutCode`.
26
+ - `getMeta` (`GET /v1/meta`): the API's version.
27
+ - **`getPass`** now also returns `programName`, `currency`, `stamps`
28
+ (`count`, `max`), `points`, `money` (`amountMinor`, `currency`), `customer`
29
+ (with `customers.read`), `actions` and `sale`.
30
+ - **Webhooks.** `webhooks.manage` API keys manage webhooks (`createWebhook`,
31
+ `listWebhooks`, `getWebhook`, `setWebhookStatus`, `testWebhook`,
32
+ `listWebhookDeliveries`, `webhookEvents`); a webhook reports `createdByKey`.
33
+ - **Other fields.** `issuePass` returns `created`; business lists and `me`
34
+ carry `currency`; programs carry `sale`; batches `onlineValue`; shops
35
+ `accepts`, `settings`, `shopName`, `unbacked` and the plugin key's
36
+ `abilities`.
37
+ - **Generator.** A doc comment holding an unbalanced bracket no longer
38
+ breaks an object union such as the answer of `me`.
39
+ - **README.**
40
+ - A till example with `recordSale`, the structured fields of `getPass` and
41
+ a refund with `reverseSale`.
42
+ - `Idempotency-Key`: a key is unique for good per credential. The
43
+ receipt number alone is not a key (fiscal receipt numbers restart after
44
+ the Z report): use register + Z number + receipt number, or a UUID
45
+ stored with the sale. The receipt number goes in `reference`.
46
+ - Test mode exists: `rwk_test_` keys and a test business. The "being
47
+ prepared" wording is gone.
48
+ - How to set a custom base URL (staging), and a link to the developer
49
+ docs, https://rewloy.com/gelistiriciler.
50
+
8
51
  ## 0.1.0 (2026-10-04)
9
52
 
10
53
 
package/README.md CHANGED
@@ -13,15 +13,16 @@ kartı, kupon ve indirimdir:
13
13
 
14
14
  Kasada QR okutulur; bakiye, ödül ve kampanyalar kartın kendisinde güncellenir.
15
15
  Panelde yapılabilen her şey [Rewloy API v1](https://rewloy.com/gelistiriciler)
16
- ile de yapılabilir; bu kütüphane onu Node.js'ten kullanır:
16
+ ile de yapılabilir; bu kütüphane onu Node.js'ten kullanır. Geliştirici
17
+ belgeleri: **https://rewloy.com/gelistiriciler**.
17
18
 
18
19
  - **Tam tipli.** API'nin her işlemi, `operationId` adıyla bir metottur.
19
20
  Parametreler, gövdeler ve yanıtlar OpenAPI belgesinden
20
21
  ([`openapi.json`](https://app.rewloy.com/v1/openapi.json)) üretilen
21
22
  tiplerle gelir. CI belgeyi her gün okur ve değişince yeniden üretir.
22
23
  - **Bağımlılıksız.** Node 22 ve üstü; yerleşik `fetch` ve `node:crypto`.
23
- - **Güvenli tekrar.** Geçici hatalarda ölçülü yeniden deneme; kasa işleminde
24
- ve kampanyada `Idempotency-Key`.
24
+ - **Güvenli tekrar.** Geçici hatalarda ölçülü yeniden deneme; satışta, kasa
25
+ işleminde ve kampanyada `Idempotency-Key`.
25
26
  - **Ötesi:** sayfalama, canlı akış (SSE), webhook imzası doğrulama,
26
27
  kullanımdan kalkma uyarıları.
27
28
 
@@ -51,7 +52,7 @@ işlemin gerektirdikleriyle:
51
52
  - `query`: sorgu parametreleri;
52
53
  - `body`: JSON gövde;
53
54
  - `merchant`: `Rewloy-Merchant` başlığı;
54
- - `idempotencyKey`: `Idempotency-Key` başlığı (kasa işlemi ve kampanya);
55
+ - `idempotencyKey`: `Idempotency-Key` başlığı (satış, kasa işlemi ve kampanya);
55
56
  - `signal`, `timeoutMs`, `maxRetries`.
56
57
 
57
58
  Metot yanıttaki `data`yı döndürür. Sayfalı listelerde `{ data, meta }`,
@@ -85,12 +86,27 @@ Bir işlem istemcinin kimlik türünü kabul etmiyor ama kimliksiz de çalışı
85
86
  bir kimliği reddeder (`CREDENTIAL_NOT_ALLOWED`).
86
87
 
87
88
  Diğer seçenekler:
88
- - `baseUrl` (varsayılan `https://app.rewloy.com`);
89
+ - `baseUrl` (varsayılan `https://app.rewloy.com`; `/v1` olmadan, kütüphane ekler);
89
90
  - `timeoutMs` (60000);
90
91
  - `maxRetries` (2);
91
92
  - `fetch`: kendi `fetch`iniz;
92
93
  - `userAgent`: gönderilen `User-Agent`a eklenir, örneğin `"KasaPOS/4.2"`.
93
94
 
95
+ ### Başka bir adres (staging)
96
+
97
+ API'nin başka bir kopyasına (kendi staging ortamınız ya da bir vekil sunucu)
98
+ `baseUrl` ile bağlanılır:
99
+
100
+ ```ts
101
+ const rewloy = new Rewloy({
102
+ apiKey: process.env.REWLOY_API_KEY!,
103
+ baseUrl: 'https://rewloy-staging.ornek.com', // /v1 olmadan
104
+ });
105
+ ```
106
+
107
+ Gerçek müşterilere dokunmadan denemek için adres değiştirmeniz gerekmez:
108
+ [test modu](#test-modu) aynı adreste, ayrı bir test ortamıyla çalışır.
109
+
94
110
  ## Kart vermek ve kasada işlem
95
111
 
96
112
  ```ts
@@ -101,16 +117,79 @@ const { serial, cardUrl } = await rewloy.issuePass({
101
117
  const sonuc = await rewloy.passAction({
102
118
  params: { serial },
103
119
  body: { action: 'earn-stamps', locationId, count: 1 },
104
- idempotencyKey: `fis-${fisNo}`,
120
+ idempotencyKey: `kasa3-z0187-fis${fisNo}`, // aşağıya bakın
105
121
  });
106
- if (sonuc.duplicate) console.log('Bu fiş zaten işlenmiş');
122
+ if (sonuc.duplicate) console.log('Bu işlem zaten yazılmış');
107
123
  ```
108
124
 
109
- `passAction` ve `sendCampaign` bir `Idempotency-Key` ister. Verilmezse
110
- kütüphane bir UUID üretir ve aynı çağrının her denemesinde aynısını gönderir.
111
- Kasada fiş numarası gibi kendi anahtarınızı vermek daha iyidir: uygulama
112
- çöküp yeniden başlasa bile aynı fiş ikinci kez işlenmez, aynı anahtarla tekrar
113
- ilk sonucu `duplicate: true` ile döndürür.
125
+ ### Satış: `recordSale`
126
+
127
+ Kasa ya da kendi yazılımınız için en kolay yol `recordSale`dir: "bu satış
128
+ oldu, sen yaz". Ödenen toplamı (kartın para biriminde, kuruş) gönderirsiniz;
129
+ ne yazılacağına kartın türü ve programın kendi kuralı karar verir. Kartın
130
+ türünü bilmeniz gerekmez.
131
+
132
+ ```ts
133
+ const kart = await rewloy.getPass({ params: { serial } });
134
+ // Kartın türüne özgü alanlar; `balance` yerine bunları okuyun.
135
+ if (kart.stamps) console.log(`${kart.stamps.count} / ${kart.stamps.max} damga`);
136
+ if (kart.points !== undefined) console.log(`${kart.points} puan`);
137
+ if (kart.money) console.log(`${kart.money.amountMinor / 100} ${kart.money.currency}`);
138
+ console.log(kart.programName, kart.customer?.name); // customer: yalnız customers.read yetkisiyle
139
+
140
+ // Fiş numarası anahtar olamaz: kasa + Z no + fiş no, ya da satışla saklanan bir UUID.
141
+ const anahtar = `kasa3-z0187-fis${fisNo}`;
142
+ const satis = await rewloy.recordSale({
143
+ params: { serial },
144
+ body: {
145
+ locationId,
146
+ amountMinor: 4550, // 45,50: kartın para biriminde (`kart.currency`), kuruş
147
+ currency: kart.currency, // isteğe bağlı güvence: uyuşmazsa 422 CURRENCY_MISMATCH
148
+ reference: `fis-${fisNo}`, // fiş numarası buraya yazılır
149
+ },
150
+ idempotencyKey: anahtar,
151
+ });
152
+ if (satis.applied === 'none') console.log('Yazılan bir şey yok:', satis.reason);
153
+ else console.log(`${satis.credited} ${satis.applied} yazıldı, bakiye ${satis.balance}`);
154
+ if (satis.rewardReady) console.log('Ödül hazır');
155
+ ```
156
+
157
+ `GET /v1/passes/{serial}` ayrıca `actions` (kartın aldığı kasa işlemleri ve
158
+ şimdi yapılıp yapılamayacakları) ve `sale` (bir satışın bu kartta ne
159
+ yazacağı) alanlarını verir.
160
+
161
+ **İade.** `reverseSale` bir satışın karta yazdığını geri alır; satışı
162
+ yazarken gönderdiğiniz anahtarla (`saleKey`) ya da `reference`la bulur:
163
+
164
+ ```ts
165
+ const geri = await rewloy.reverseSale({
166
+ params: { serial },
167
+ body: { saleKey: anahtar, locationId },
168
+ });
169
+ console.log(geri.reversed, geri.applied, geri.balance, geri.duplicate);
170
+ ```
171
+
172
+ Bir satış bir kez geri alınır (tekrar `duplicate: true` döner). Kazanılan
173
+ kullanılmışsa (ödüle ya da harcamaya gitmişse) `409 SALE_ALREADY_SPENT` gelir ve
174
+ hiçbir şey yazılmaz.
175
+
176
+ ### `Idempotency-Key`
177
+
178
+ `recordSale`, `passAction` ve `sendCampaign` bir `Idempotency-Key` ister.
179
+ Verilmezse kütüphane bir UUID üretir ve aynı çağrının her denemesinde aynısını
180
+ gönderir; ama uygulama çöküp yeniden başlarsa yeni bir anahtar üretilir ve
181
+ satış ikinci kez yazılabilir. Kasada anahtarı kendiniz üretip satışla birlikte
182
+ saklayın:
183
+ - **Anahtar bir kimlik için kalıcı olarak tekildir** (8–64 karakter; defterden
184
+ hiç silinmez). Aynı anahtarla aynı isteğin tekrarı ikinci kez yazmaz ve
185
+ ilk sonucu `duplicate: true` ile döndürür. Aynı anahtar başka bir gövdeyle
186
+ `422 IDEMPOTENCY_KEY_REUSED` alır.
187
+ - **Fiş numarası tek başına anahtar olamaz:** yazarkasa fiş numaraları Z
188
+ raporundan sonra yeniden başlar. Kasa + Z no + fiş no birleşimi
189
+ (`kasa3-z0187-fis0042`) ya da satışla birlikte saklanıp tekrarda yeniden
190
+ gönderilen bir UUID kullanın.
191
+ - **Fiş numarası `reference` alanına** yazılır; müşterinin geçmişinde ve işlem
192
+ dökümünde görünür.
114
193
 
115
194
  ## Sayfalama
116
195
 
@@ -164,6 +243,22 @@ gösterilen sırla (`whsec_…`) doğrular:
164
243
  - `t` şimdiden 300 saniyeden (`toleranceSeconds`) uzaksa reddeder;
165
244
  - gövdeyi ayrıştırılmış olarak döndürür.
166
245
 
246
+ Webhook'u panelden ya da API'den ekleyebilirsiniz. `webhooks.manage` yetkili
247
+ bir API anahtarı `createWebhook`, `listWebhooks`, `getWebhook`,
248
+ `setWebhookStatus`, `testWebhook` ve `listWebhookDeliveries`yi çağırabilir;
249
+ `webhookEvents` abone olunabilecek olayları söyler. Sır (`secret`) yalnız
250
+ `createWebhook` yanıtında gelir, saklayın:
251
+
252
+ ```ts
253
+ const { webhook, secret } = await rewloy.createWebhook({
254
+ body: { url: 'https://ornek.com/rewloy/webhook', events: ['pass.activity', 'pass.voided'] },
255
+ });
256
+ await rewloy.testWebhook({ params: { id: webhook.id } }); // webhook.test olayı gönderir
257
+ ```
258
+
259
+ Adres herkese açık bir `https` adresi olmalıdır (test ortamında da);
260
+ yerelde bir tünel kullanın.
261
+
167
262
  Tutmazsa `WebhookSignatureError` atar: 400 ile yanıtlayın ve hiçbir işlem
168
263
  yapmayın. Gövde mutlaka ham olmalıdır. JSON olarak ayrıştırılıp yeniden yazılan
169
264
  bir gövde imzayı tutturmaz.
@@ -238,7 +333,7 @@ try {
238
333
  await rewloy.passAction({
239
334
  params: { serial },
240
335
  body: { action: 'spend', locationId, amountMinor: 5000 },
241
- idempotencyKey: `fis-${fisNo}`,
336
+ idempotencyKey: `kasa3-z0187-fis${fisNo}`,
242
337
  });
243
338
  } catch (err) {
244
339
  if (err instanceof RateLimitError) console.log(`${err.retryAfter} saniye sonra yeniden deneyin`);
@@ -309,14 +404,35 @@ yanit.data; // kampanya
309
404
  `data`, sayfalı listede `meta`, `status`, `headers`, `requestId`, `mode` ve
310
405
  `replayed`.
311
406
 
312
- `mode`, yanıtın `Rewloy-Mode` başlığıdır. Platformda test modu hazırlanıyor:
313
- gerçek mesaj göndermeyen, gerçek kart vermeyen test anahtarları. Geldiğinde
314
- test yanıtları bunu bu başlıkla söyleyecek. Başlık yoksa `null`. Canlı akışta
315
- aynı bilgi `akis.mode`dadır.
407
+ `mode`, yanıtın `Rewloy-Mode` başlığıdır: `live` ya da `test`. Başlık yoksa
408
+ `null`. Canlı akışta aynı bilgi `akis.mode`dadır.
316
409
 
317
410
  İşlem tablosu da dışa açıktır: `OPERATIONS.passAction` →
318
411
  `{ method, path, auth, merchant, idempotency, paged, stream, deprecated, … }`.
319
412
 
413
+ ## Test modu
414
+
415
+ Gerçek müşterilere dokunmadan denemek için işletmenizin bir **test ortamı**
416
+ vardır: ona bağlı ayrı bir işletme (adı "· Test" ile biter); kendi
417
+ programları, müşterileri, kartları, anahtarları ve webhook'ları. Panel →
418
+ Geliştirici → "Test ortamını aç" ya da `POST /v1/test/environment`. Orada
419
+ oluşturulan anahtar `rwk_test_` ile başlar ve aynı adreste, aynı yollarla
420
+ çalışır:
421
+
422
+ ```ts
423
+ const rewloy = new Rewloy({ apiKey: process.env.REWLOY_TEST_KEY! }); // rwk_test_…
424
+ const yanit = await rewloy.request('getPass', { params: { serial } });
425
+ yanit.mode; // 'test'
426
+ ```
427
+
428
+ - Test ortamı hiçbir şey göndermez (e-posta, bildirim, SMS); kartlar
429
+ cüzdanlara eklenmez. Gönderilmeyenler `GET /v1/test/messages` ile okunur.
430
+ - Webhook'lar teslim edilir ve `Rewloy-Test: 1` başlığıyla `"test": true`
431
+ taşır.
432
+ - Gerçek müşteri verisini test ortamına girmeyin.
433
+
434
+ Ayrıntı: https://rewloy.com/gelistiriciler#test-ortamı
435
+
320
436
  ## Geliştirme
321
437
 
322
438
  ```sh
@@ -369,7 +485,8 @@ Bir güvenlik açığı bulursanız [SECURITY.md](SECURITY.md) dosyasındaki yol
369
485
  > **Status: preview (0.x), published on npm. The API is stable; the
370
486
  > library's interface may change until 1.0.**
371
487
 
372
- The documentation of the API itself is in Turkish (links above). In short:
488
+ The documentation of the API itself is in Turkish. Developer docs:
489
+ **https://rewloy.com/gelistiriciler**. In short:
373
490
 
374
491
  - Every operation of the API is a method named by its `operationId`, typed
375
492
  from the OpenAPI document, which CI reads daily and regenerates from.
@@ -393,21 +510,37 @@ import { Rewloy } from '@rewloy/node';
393
510
  const rewloy = new Rewloy({ apiKey: process.env.REWLOY_API_KEY! }); // or { staffSession, merchant } or { holderSession }
394
511
 
395
512
  const { serial } = await rewloy.issuePass({ body: { programId, email, kvkkConsent: true } });
396
- const result = await rewloy.passAction({
513
+ const sale = await rewloy.recordSale({
397
514
  params: { serial },
398
- body: { action: 'earn-stamps', locationId },
399
- idempotencyKey: `receipt-${receiptNo}`, // generated when omitted, reused across retries
515
+ body: { locationId, amountMinor: 4550, reference: `receipt-${receiptNo}` }, // amount in the card's currency, minor units
516
+ idempotencyKey: `till3-z0187-r${receiptNo}`,
400
517
  });
401
518
  ```
402
519
 
520
+ - **Till.** `recordSale` writes a completed sale to a card (the card type and
521
+ the programme's own rule decide what is written); `getPass` returns the
522
+ card's structured fields (`programName`, `currency`, `stamps`, `points`,
523
+ `money`, `customer`); `reverseSale` takes a refunded sale back:
524
+ `rewloy.reverseSale({ params: { serial }, body: { saleKey: key } })`.
525
+ - **Idempotency keys.** `recordSale`, `passAction` and `sendCampaign` need an
526
+ `Idempotency-Key`. A key is unique **for good per credential**: do not use the
527
+ receipt number alone (fiscal receipt numbers restart after the Z report) but
528
+ register + Z number + receipt number, or a UUID stored with the sale. The
529
+ receipt number goes in `reference`. A generated key only covers the retries
530
+ of one call, not a restart of your app.
531
+ - **Base URL.** `new Rewloy({ apiKey, baseUrl: 'https://staging.example.com' })`
532
+ (the origin, without `/v1`). Default `https://app.rewloy.com`.
533
+ - **Test mode.** Open the test environment (panel → Developer, or
534
+ `POST /v1/test/environment`) and use its `rwk_test_` key at the same address:
535
+ a separate test business that sends nothing and never reaches real
536
+ customers. Webhooks are delivered with `Rewloy-Test: 1`.
403
537
  - **Arguments.** Each method takes one object: `params`, `query` and `body` as
404
538
  the operation needs, plus `merchant`, `idempotencyKey`, `signal`, `timeoutMs`
405
539
  and `maxRetries`.
406
540
  - **Results.** It resolves to the answer's `data`: `{ data, meta }` for paged
407
541
  lists, `undefined` for 204, a `Blob` for files.
408
542
  - **The whole answer.** `rewloy.request(id, args)` returns `status`,
409
- `headers`, `requestId`, `mode` (the `Rewloy-Mode` header, for the coming
410
- test mode) and `replayed` (`Idempotent-Replayed`).
543
+ `headers`, `requestId`, `mode` (the `Rewloy-Mode` header: `live` or `test`) and `replayed` (`Idempotent-Replayed`).
411
544
  - **Pagination.** `rewloy.paginate('listCustomers', args)` iterates the items
412
545
  of every page.
413
546
  - **Streams.** `rewloy.liveFeed({ signal })` (or `rewloy.stream('liveFeed',
@@ -451,3 +584,9 @@ const event = verifyWebhook({ payload: req.body, header: req.get('Rewloy-Signatu
451
584
 
452
585
  Report vulnerabilities privately, as [SECURITY.md](SECURITY.md) says.
453
586
  [MIT](LICENSE) licensed.
587
+
588
+ ## Yeni sürüm yayımlamak / Releasing
589
+
590
+ `package.json`'daki sürümü ve CHANGELOG'u güncelleyin, commit'leyin, `v<sürüm>` etiketini gönderin (`git tag v0.2.0 && git push origin v0.2.0`). `release.yml` npm'e güvenilir yayıncı (trusted publishing) yoluyla, jetonsuz ve kaynak kanıtıyla (provenance) yayımlar.
591
+
592
+ Bump the version in `package.json` and the changelog, commit, and push a `v<version>` tag. `release.yml` publishes to npm through trusted publishing: no token, with provenance.