@stewardhq/sdk 0.1.0-rc.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/README.md CHANGED
@@ -17,7 +17,7 @@ ESM, Node ≥ 22. Tek çalışma zamanı bağımlılığı zod.
17
17
 
18
18
  | Import | İçerik |
19
19
  | --- | --- |
20
- | `@stewardhq/sdk` | Tüm şema/tipler + istemciler (`createSteward`, `createCatalogCache`, `stateCache`, fırlatmayan `createBillingClient`) + yardımcılar: hata sınıfları, `httpStatusFor`, `errorMessages`/`messageFor`, `defineCatalog`, `formatPrice`/`taxBreakdown`, `isValidTckn`/`isValidVkn`/`isE164` |
20
+ | `@stewardhq/sdk` | Tüm şema/tipler + fırlatan istemci `createSteward`, hesap durumu önbelleği `stateCache`, `defineCatalog`, hata sınıfları + `httpStatusFor`, `isValidTckn`/`isValidVkn`/`isE164` |
21
21
  | `@stewardhq/sdk/contract` | Yalnızca şemalar ve tipler |
22
22
  | `@stewardhq/sdk/webhook` | `signWebhook` / `verifyWebhook` / `verifyWebhookRaw` (Node HMAC, senkron) |
23
23
  | `@stewardhq/sdk/webhook/web` | Aynı API WebCrypto ile (async; edge/workerd/tarayıcı) |
@@ -127,7 +127,7 @@ import { Checkout } from "@stewardhq/sdk/server";
127
127
  const checkout = Checkout({
128
128
  steward, cache: state,
129
129
  // mutlak; origin steward ayarında izinli (appUrl + extraReturnOrigins). Yer tutucular varsa
130
- // steward yalnızca onları doldurur, yoksa ?session=&status= ekler.
130
+ // steward yalnızca onları doldurur; yoksa adres aynen kullanılır (parametre eklenmez).
131
131
  successUrl: `${process.env.APP_URL}/{LOCALE}/app/orgs/{ACCOUNT_REF}/billing?checkout={CHECKOUT_ID}`,
132
132
  consents: (locale) => legalDocs(locale), // [{document, version, url}] ya da dizi; sayfada onaylatılır
133
133
  // cancelUrl (yoksa ayar appUrl), locale ve currency (yoksa ürün ayarı)
@@ -155,9 +155,8 @@ app.get("/v1/orgs/:orgId/billing/checkout/:id", async (c) => // dönü
155
155
  | Yanıtta `url` yok (F2b öncesi steward) | `StewardContractError` |
156
156
 
157
157
  Kullanıcı sayfayı kapatırsa oturum süresi dolunca (`checkoutTtlMinutes`) steward kapatır;
158
- ürün sonucu `account.state_changed` ile öğrenir. `profile` + `identityNumber` taşıyan eski gövde
159
- (`steward.checkoutSessions.create`) açılışta sağlayıcı formu döndürmeye devam eder (N3 + 1
160
- release sonra kaldırılır).
158
+ ürün sonucu `account.state_changed` ile öğrenir. `steward.checkoutSessions.create` de yalnızca
159
+ hosted gövdeyi kabul eder; fatura profili yalnızca hosted checkout ve portal sayfalarında yazılır.
161
160
 
162
161
  Hosted müşteri portalı (`/server`) — abonelik durumu, dönem sonunda iptal, ödemeyi yeniden dene,
163
162
  fatura listesi/PDF ve kurumsal fatura profili steward'ın sayfasında; ürün yalnızca yetkiyi
@@ -211,22 +210,20 @@ await steward.grants.create(accountRef, { planCode: "team", reason: "kurumsal s
211
210
 
212
211
  | Kaynak | Metotlar |
213
212
  | --- | --- |
214
- | `accounts` | `upsert(ref, input)`, `get(ref, {include?})`, `state(ref)`, `readState(ref, {etag?})` (304 → `{notModified: true}`), `entitlements(ref)`, `putBillingProfile(ref, profile)`, `setPlan(ref, {planCode \| null, reason, mode?, endsAt?, overrides?})` → `{grant, account, warnings}` (canlı abonelik planı hedefi geçiyorsa `mode: "ensure"` uyarı, `"strict"` `subscription_plan_higher`), `resync(ref)` → `{queued, eventId}` (saklı durum `account.state_changed`, `cause: "resync"`), `delete(ref)` → `{ref, deletedAt}` (KVKK anonimleştirme; faturalar kalır; önce canlı abonelik `immediate` iptal — yoksa `subscription_active`, formu açık checkout'ta `checkout_in_progress`; sonra hesabın her ucu `account_deleted` 410) |
213
+ | `accounts` | `upsert(ref, input)`, `get(ref, {include?})`, `state(ref)`, `readState(ref, {etag?})` (304 → `{notModified: true}`), `setPlan(ref, {planCode \| null, reason, mode?, endsAt?, overrides?})` → `{grant, account, warnings}` (canlı abonelik planı hedefi geçiyorsa `mode: "ensure"` uyarı, `"strict"` `subscription_plan_higher`), `resync(ref)` → `{queued, eventId}` (saklı durum `account.state_changed`, `cause: "resync"`), `delete(ref)` → `{ref, deletedAt}` (KVKK anonimleştirme; faturalar kalır; önce canlı abonelik `immediate` iptal — yoksa `subscription_active`, formu açık checkout'ta `checkout_in_progress`; sonra hesabın her ucu `account_deleted` 410) |
215
214
  | `checkoutSessions` | `create(ref, input)`, `get(id)` |
216
215
  | `portalSessions` | `create(ref, {locale?, returnUrl?})` → `{id, url, expiresAt}` (hosted müşteri portalı; `CustomerPortal()` bunu sarar) |
217
216
  | `subscriptions` | `cancel(id, input)` |
218
217
  | `grants` | `create(ref, input)`, `revoke(id)` |
219
218
  | `invoices` | `issue(id, input)`, `document(id)` → `{contentType, bytes}`, `createManual(ref, {lines, currency, taxRateBps, taxInclusive?, dueAt?, note?})` (manuel taslak; profil gerekir, `issue` ile kesilir), `void(id, {reason})` (yalnızca manuel fatura; `invoice.voided` yalnızca filtresinde isteyen endpoint'e) |
220
219
  | `catalog` | `get()`, `read({etag?})` |
221
- | `events` | `list({accountRef?, cursor?, limit?})`, `redeliver(id)` |
222
220
  | — | `stats()`, `me()`, `doctor()` → kurulum teşhisi (`GET /v1/doctor`; aşağıda) |
223
221
  | `admin` | `catalog.sync(input)`, `accounts.refresh()`, `settings.{get(), update(patch)}`, `endpoints.{list(), create(input), rotate(id, {secret}), deactivate(id)}` — `STEWARD_ADMIN_URL` + `STEWARD_ADMIN_API_KEY` (ya da `adminBaseUrl`/`adminApiKey`) ister; yoksa çağrıda `StewardConfigError` |
224
- | `raw` | Fırlatmayan, tekrar denemeyen sözleşme istemcisi (`createBillingClient`; `{ ok, data }` / `{ ok: false, status, error }`) |
225
222
 
226
223
  - **Mutasyonlar** son argümanda `{ idempotencyKey?, actorRef? }` alır. Anahtar
227
224
  verilmezse çağrı başına üretilir; `actorRef` verilmezse `createSteward`'daki varsayılan gider.
228
225
  İkisi de yoksa ya da biçimi geçersizse (`tür[:kimlik]`) istek **gitmez**: `StewardConfigError`
229
- (`code` servisinkiyle aynı: `actor_ref_required` / `invalid_actor_ref`). `raw` bu denetimi yapmaz.
226
+ (`code` servisinkiyle aynı: `actor_ref_required` / `invalid_actor_ref`).
230
227
  - **Yalnızca yönetim:** `STEWARD_URL` ve `STEWARD_API_KEY` ikisi de yoksa ve `STEWARD_ADMIN_URL` +
231
228
  `STEWARD_ADMIN_API_KEY` (ya da `adminBaseUrl`/`adminApiKey`) verilmişse istemci kurulur (CLI, katalog
232
229
  senkronu): `admin.*` çalışır, iki kapsama açık `doctor()` ve `me()` admin anahtarıyla gider, ürün uçları
@@ -279,16 +276,6 @@ const report = await steward.doctor();
279
276
  Kodlar ve teşhisler açık kümedir (bilinmeyeni yalnızca gösterin). `provider.healthy` ve
280
277
  `lastError` yanıtı veren steward pod'unun gözlemidir.
281
278
 
282
- Katalog önbelleği — TTL içinde bellekten, sonra `If-None-Match` (304 gövdeyi korur);
283
- eşzamanlı çağrılar tek istek; başarılı okumadan sonraki hatada bayat değer + `logger.warn`:
284
-
285
- ```ts
286
- import { createCatalogCache } from "@stewardhq/sdk";
287
-
288
- const catalogCache = createCatalogCache(steward, { ttlMs: 60_000, logger });
289
- const { plans, prices } = await catalogCache.get();
290
- ```
291
-
292
279
  Katalog — kodda tipli tanım; eksik/fazla hak, yanlış tip (`limit` → tam sayı ya da
293
280
  `null` = sınırsız, `flag` → boolean, `text` → string) ve tanımsız plana fiyat derleme
294
281
  hatasıdır, tipler atlatılırsa tanım anında `StewardConfigError` fırlatır (TypeScript ≥ 5.4):
@@ -317,25 +304,24 @@ const placeholder = catalog.stateOf("org_1", "team", { accessState: "active", di
317
304
  katalogda yoksa varsayılan plandan) alır, asla "sınırsız" üretmez; `onFallback`
318
305
  ile alarm verilebilir. Snapshot yoksa varsayılan planın hakları.
319
306
 
320
- Hatalar ve metinler — ürün API'sinin durum kodu ve kullanıcı metni:
307
+ Hatalar — ürün API'sinin durum kodu:
321
308
 
322
309
  ```ts
323
- import { httpStatusFor, messageFor, StewardError } from "@stewardhq/sdk";
310
+ import { httpStatusFor, StewardError } from "@stewardhq/sdk";
324
311
 
325
312
  if (error instanceof StewardError) {
326
313
  const { status, headers } = httpStatusFor(error, { logger }); // already_subscribed 409, rate_limited 503 + Retry-After…
327
- return Response.json({ error: error.code, message: messageFor(error.code, locale) }, { status, headers });
314
+ return Response.json({ error: error.code }, { status, headers });
328
315
  }
329
316
  ```
330
317
 
331
318
  Tabloda olmayan kod `category`'ye göre eşlenir (`not_found` 404, `conflict` 409,
332
319
  `provider` 502, `unavailable` 503; `validation`/`config` 500 + ERROR log).
333
- `errorMessages.{tr,en}` sözleşmenin `ERROR_CODES` kaydındaki her kodu ve istemci
334
- kodlarını (`network_error`, `timeout`, `invalid_response`, `config_error`) kapsar.
320
+ Kullanıcıya gösterilen metin ürünündür (`error.code` → kendi i18n'iniz); `error.message`
321
+ log içindir (steward'ın mesajı, yoksa kod). Fiyat gösterimi hosted checkout/portal
322
+ sayfalarındadır; SDK para biçimlendirme yardımcısı taşımaz.
335
323
 
336
- Para ve doğrulayıcılar: `formatPrice(price, "tr")` → `₺1.250,00 · KDV dahil`;
337
- `taxBreakdown(price)` servisin faturadaki matrah/KDV ayrıştırmasıyla kuruşu kuruşuna
338
- aynıdır. `isValidTckn`, `isValidVkn` (sağlama hanesi), `isE164(value, {country: "TR"}?)`
324
+ Doğrulayıcılar: `isValidTckn`, `isValidVkn` (sağlama hanesi), `isE164(value, {country: "TR"}?)`
339
325
  değeri olduğu gibi denetler (boşluk kırpmaz).
340
326
 
341
327
  Testler (`/testing`, Node) — sahte steward sunucu açmaz, `fetch` verir; başlıkları
@@ -378,6 +364,7 @@ await fake.simulate.renewal("org_1", { fail: true }); // saat dönem sonuna; pa
378
364
  await fake.simulate.advance({ days: 7 }); // zamanlanmış işler kendi anında (dunning, dönem sonu iptali, checkout süresi, grant penceresi, portal oturumu silme)
379
365
  fake.simulate.outage(true, { mode: "503" }); // ya da "network": fetch reddeder
380
366
  await fake.simulate.deliver("account.state_changed", { ref: "org_1", duplicate: true, outOfOrder: true });
367
+ fake.simulate.redeliver(eventId); // operatörün pod CLI `redeliver-event`'i: aynı event sonraki flush'ta yeniden
381
368
 
382
369
  const { request } = signedEvent("subscription.renewed", { accountRef: "org_1" }, { secret });
383
370
  await webhooks.handle(request());
@@ -390,7 +377,7 @@ Alıcı bağlanmadan `flush`/`deliver` fırlatır (event'ler outbox'ta bekler);
390
377
  Sahtenin bilerek farklı olduğu yerler: teslimat asenkron değil (`flush()`), `dead`
391
378
  olmaz ve geri çekilme beklenmez; sağlayıcı hata vermez; dönüş origin'i (`settings.appUrl`,
392
379
  `settings.extraReturnOrigins` ya da kısayolu `returnOrigins`) hiç ayarlanmazsa her
393
- `returnUrl` kabul; `admin.endpoints` ile açılan endpoint yalnızca kayıttır (teslimat
380
+ `successUrl`/`cancelUrl`/`returnUrl` kabul; `admin.endpoints` ile açılan endpoint yalnızca kayıttır (teslimat
394
381
  `webhook` seçeneğinin alıcısına gider, `lastDelivery` hep null; `doctor()`'da teşhisi
395
382
  `no_deliveries`, sağlayıcı `fake` ve sağlıklı); dunning'de yeniden deneme
396
383
  sonucu `renewal` ile gelir; her yanıt `X-Request-Id` (hata gövdesinde `requestId`) taşır;
@@ -419,14 +406,16 @@ sonuçlandırmaz: servisteki gibi sonuç sonradan gelir — `simulate.renewal(re
419
406
  siparişi başarılı sayar (`subscription.reactivated`), `{fail: true}` yine başarısız.
420
407
  `simulate.portalCancel/portalRetryPayment` bilinmeyen ya da süresi geçmiş oturumda fırlatır.
421
408
 
422
- ## `@z9cloud/steward-contract`'tan geçiş
409
+ ## `@steward/contract`'tan geçiş
423
410
 
424
411
  | Eski | Yeni |
425
412
  | --- | --- |
426
413
  | `@z9cloud/steward-contract` | `@stewardhq/sdk` (ya da yalnız şema için `@stewardhq/sdk/contract`) |
427
- | `@z9cloud/steward-contract/client` | `@stewardhq/sdk` (`createBillingClient` aynen; fırlatan istemci `createSteward`) |
414
+ | `@z9cloud/steward-contract/client` | `@stewardhq/sdk` `createSteward` (fırlatan; fırlatmayan `createBillingClient` dışa açılmaz) |
428
415
  | `@z9cloud/steward-contract/webhook` | `@stewardhq/sdk/webhook` |
429
416
  | `@z9cloud/steward-contract/fixtures/events/*.json` | `@stewardhq/sdk/testing/fixtures/events/*.json` |
417
+ | `getEntitlements(ref)` / `accounts.entitlements(ref)` | `accounts.state(ref)` ya da `stateCache` (tek okuma modeli `AccountState`; uç 2026-09-16'da kaldırıldı) |
418
+ | `listEvents` / `redeliverEvent` / `events.*` | Yok (2026-09-16): kaçırılan durum için `accounts.resync(ref)`; dead teslimatı operatör pod CLI `redeliver-event` ile yeniden gönderir (testte `fake.simulate.redeliver`) |
430
419
 
431
420
  GitHub Packages `.npmrc` satırı ve Docker `--secret` bağlaması artık gerekmez.
432
421
 
@@ -2,7 +2,7 @@ import { z } from "zod";
2
2
  //#region ../contract/src/common.ts
3
3
  const API_VERSION = "2026-10-01";
4
4
  const CodeSchema = z.string().regex(/^[a-z][a-z0-9_]{0,62}$/, "küçük harf, rakam ve _ (harfle başlar)");
5
- /** Ürün tarafındaki değişmez kimlik (ör. nixscale'de ağın shortId'si). */
5
+ /** Immutable product-side identity (e.g. the id of an org in the product). */
6
6
  const ExternalRefSchema = z.string().min(1).max(200).regex(/^[A-Za-z0-9_.:-]+$/, "yalnızca harf, rakam ve _ . : -");
7
7
  const IdSchema = z.uuid();
8
8
  const CurrencySchema = z.string().regex(/^[A-Z]{3}$/, "ISO-4217 kodu");