@stewardhq/sdk 0.1.0-rc.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.
Files changed (48) hide show
  1. package/README.md +437 -0
  2. package/dist/_chunks/errors.js +73 -0
  3. package/dist/_chunks/events.d.ts +537 -0
  4. package/dist/_chunks/events.js +350 -0
  5. package/dist/_chunks/index.d.ts +6005 -0
  6. package/dist/_chunks/locale.d.ts +17 -0
  7. package/dist/_chunks/locale.js +17 -0
  8. package/dist/_chunks/src.js +1202 -0
  9. package/dist/_chunks/steward.d.ts +2588 -0
  10. package/dist/_chunks/steward.js +578 -0
  11. package/dist/_chunks/validators.d.ts +23 -0
  12. package/dist/_chunks/validators.js +106 -0
  13. package/dist/_chunks/webhook-core.d.ts +32 -0
  14. package/dist/_chunks/webhook-core.js +64 -0
  15. package/dist/_chunks/webhook.d.ts +22 -0
  16. package/dist/_chunks/webhook.js +53 -0
  17. package/dist/contract.d.ts +4 -0
  18. package/dist/contract.js +4 -0
  19. package/dist/index.d.ts +268 -0
  20. package/dist/index.js +784 -0
  21. package/dist/server.d.ts +236 -0
  22. package/dist/server.js +384 -0
  23. package/dist/testing/fixtures/events/LOCK.json +27 -0
  24. package/dist/testing/fixtures/events/account.deleted.json +36 -0
  25. package/dist/testing/fixtures/events/account.state_changed.json +53 -0
  26. package/dist/testing/fixtures/events/account.updated.json +37 -0
  27. package/dist/testing/fixtures/events/checkout.completed.json +36 -0
  28. package/dist/testing/fixtures/events/checkout.expired.json +26 -0
  29. package/dist/testing/fixtures/events/checkout.failed.json +27 -0
  30. package/dist/testing/fixtures/events/invoice.created.json +37 -0
  31. package/dist/testing/fixtures/events/invoice.issued.json +38 -0
  32. package/dist/testing/fixtures/events/invoice.voided.json +39 -0
  33. package/dist/testing/fixtures/events/subscription.activated.json +40 -0
  34. package/dist/testing/fixtures/events/subscription.cancel_scheduled.json +38 -0
  35. package/dist/testing/fixtures/events/subscription.canceled.json +29 -0
  36. package/dist/testing/fixtures/events/subscription.expired.json +27 -0
  37. package/dist/testing/fixtures/events/subscription.payment_failed.json +38 -0
  38. package/dist/testing/fixtures/events/subscription.reactivated.json +36 -0
  39. package/dist/testing/fixtures/events/subscription.renewed.json +39 -0
  40. package/dist/testing/fixtures/events/subscription.suspended.json +36 -0
  41. package/dist/testing/fixtures/events/subscription.terminated.json +28 -0
  42. package/dist/testing.d.ts +629 -0
  43. package/dist/testing.js +3759 -0
  44. package/dist/webhook/web.d.ts +17 -0
  45. package/dist/webhook/web.js +66 -0
  46. package/dist/webhook.d.ts +3 -0
  47. package/dist/webhook.js +3 -0
  48. package/package.json +70 -0
@@ -0,0 +1,578 @@
1
+ import { D as API_VERSION, L as ErrorResponseSchema, O as ActorRefSchema, p as AccountDeleteResponseSchema, w as EntitlementSnapshotSchema, y as AccountStateSchema } from "./events.js";
2
+ import { $ as HEADER_SDK, B as AccountDetailSchema, C as WebhookEndpointListSchema, Et as CheckoutSessionCreatedSchema, H as BillingProfileResponseSchema, I as ResyncResultSchema, J as GrantCreateResponseSchema, Jt as AccountsRefreshResultSchema, K as EventListSchema, P as PlanSetResponseSchema, Q as HEADER_REQUEST_ID, R as errorCodeSpec, T as WebhookEndpointSchema, U as CancelSubscriptionResponseSchema, V as AccountUpsertResponseSchema, W as CheckoutSessionResponseSchema, X as HEADER_API_VERSION, Y as HEADER_ACTOR_REF, Yt as CatalogSchema, Z as HEADER_IDEMPOTENCY_KEY, Zt as CatalogSyncResultSchema, _t as StatsSchema, et as InvoiceIssueResponseSchema, nt as ManualInvoiceResponseSchema, q as EventRecordSchema, tt as InvoiceVoidResponseSchema, u as DoctorReportSchema, xt as PortalSessionSchema, zt as ProductSettingsSchema } from "./src.js";
3
+ import { a as StewardNetworkError, n as StewardConfigError, r as StewardContractError, t as StewardApiError } from "./errors.js";
4
+ import { z } from "zod";
5
+ //#region ../contract/src/client.ts
6
+ /**
7
+ * `Retry-After` başlığını milisaniyeye çevirir: saniye (tam sayı) ya da HTTP
8
+ * tarihi. Geçmiş tarih 0; okunamayan değer null.
9
+ */
10
+ function parseRetryAfter(value, now = Date.now()) {
11
+ if (value === null || value === void 0) return null;
12
+ const trimmed = value.trim();
13
+ if (/^\d+$/.test(trimmed)) return Number(trimmed) * 1e3;
14
+ if (!/^[A-Za-z]/.test(trimmed)) return null;
15
+ const at = Date.parse(trimmed);
16
+ return Number.isNaN(at) ? null : Math.max(0, at - now);
17
+ }
18
+ const SDK_HEADER_VALUE = /^[\x21-\x7e][\x20-\x7e]{0,199}$/;
19
+ function createBillingClient(options) {
20
+ const baseUrl = options.baseUrl.replace(/\/$/, "");
21
+ const doFetch = options.fetch ?? fetch;
22
+ const timeoutMs = options.timeoutMs ?? 1e4;
23
+ if (options.sdk !== void 0 && !SDK_HEADER_VALUE.test(options.sdk)) throw new Error("sdk: yazdırılabilir ASCII, en çok 200 karakter");
24
+ function meta(res) {
25
+ const out = {};
26
+ const requestId = res.headers.get(HEADER_REQUEST_ID);
27
+ if (requestId) out.requestId = requestId;
28
+ if (res.status === 429 || res.status === 503) {
29
+ const retryAfterMs = parseRetryAfter(res.headers.get("retry-after"));
30
+ if (retryAfterMs !== null) out.retryAfterMs = retryAfterMs;
31
+ }
32
+ return out;
33
+ }
34
+ async function send(method, path, body, call, extraHeaders) {
35
+ const headers = {
36
+ authorization: `Bearer ${options.apiKey}`,
37
+ accept: "application/json",
38
+ [HEADER_API_VERSION]: API_VERSION,
39
+ ...extraHeaders
40
+ };
41
+ if (options.sdk !== void 0) headers[HEADER_SDK] = options.sdk;
42
+ if (method !== "GET") headers[HEADER_IDEMPOTENCY_KEY] = call?.idempotencyKey ?? globalThis.crypto.randomUUID();
43
+ if (call?.actorRef) headers[HEADER_ACTOR_REF] = call.actorRef;
44
+ if (body !== void 0) headers["content-type"] = "application/json";
45
+ try {
46
+ return { res: await doFetch(`${baseUrl}${path}`, {
47
+ method,
48
+ headers,
49
+ ...body !== void 0 ? { body: JSON.stringify(body) } : {},
50
+ signal: AbortSignal.timeout(timeoutMs)
51
+ }) };
52
+ } catch (error) {
53
+ return {
54
+ ok: false,
55
+ status: 0,
56
+ error: error instanceof Error && (error.name === "TimeoutError" || error.name === "AbortError") ? "timeout" : "network_error"
57
+ };
58
+ }
59
+ }
60
+ async function failure(res) {
61
+ const json = await res.json().catch(() => null);
62
+ const parsed = ErrorResponseSchema.safeParse(json);
63
+ const { requestId, retryAfterMs } = meta(res);
64
+ const common = {
65
+ ...requestId !== void 0 ? { requestId } : {},
66
+ ...retryAfterMs !== void 0 ? { retryAfterMs } : {}
67
+ };
68
+ if (parsed.success) {
69
+ const { error, message, category, retryable } = parsed.data;
70
+ const bodyRequestId = requestId === void 0 ? parsed.data.requestId : void 0;
71
+ return {
72
+ ok: false,
73
+ status: res.status,
74
+ error,
75
+ ...message !== void 0 ? { message } : {},
76
+ ...category !== void 0 ? { category } : {},
77
+ ...retryable !== void 0 ? { retryable } : {},
78
+ ...bodyRequestId !== void 0 ? { requestId: bodyRequestId } : {},
79
+ ...common
80
+ };
81
+ }
82
+ return {
83
+ ok: false,
84
+ status: res.status,
85
+ error: `http_${res.status}`,
86
+ ...common
87
+ };
88
+ }
89
+ function success(res, data) {
90
+ const { requestId } = meta(res);
91
+ return {
92
+ ok: true,
93
+ status: res.status,
94
+ data,
95
+ ...requestId !== void 0 ? { requestId } : {}
96
+ };
97
+ }
98
+ function invalid(res) {
99
+ const { requestId } = meta(res);
100
+ return {
101
+ ok: false,
102
+ status: res.status,
103
+ error: "invalid_response",
104
+ ...requestId !== void 0 ? { requestId } : {}
105
+ };
106
+ }
107
+ async function call(schema, method, path, body, opts) {
108
+ const sent = await send(method, path, body, opts);
109
+ if (!("res" in sent)) return sent;
110
+ const { res } = sent;
111
+ if (!res.ok) return failure(res);
112
+ const json = await res.json().catch(() => void 0);
113
+ const parsed = schema.safeParse(json);
114
+ if (!parsed.success) return invalid(res);
115
+ return success(res, parsed.data);
116
+ }
117
+ async function empty(method, path, opts) {
118
+ const sent = await send(method, path, void 0, opts);
119
+ if (!("res" in sent)) return sent;
120
+ const { res } = sent;
121
+ if (!res.ok) return failure(res);
122
+ return success(res, null);
123
+ }
124
+ const ref = (value) => encodeURIComponent(value);
125
+ return {
126
+ getCatalog: () => call(CatalogSchema, "GET", "/v1/catalog"),
127
+ syncCatalog: (input, opts) => call(CatalogSyncResultSchema, "PUT", "/v1/admin/catalog", input, opts),
128
+ upsertAccount: (accountRef, input, opts) => call(AccountUpsertResponseSchema, "PUT", `/v1/accounts/${ref(accountRef)}`, input, opts),
129
+ getAccount: (accountRef, include = []) => call(AccountDetailSchema, "GET", `/v1/accounts/${ref(accountRef)}${include.length ? `?include=${include.join(",")}` : ""}`),
130
+ getEntitlements: (accountRef) => call(EntitlementSnapshotSchema, "GET", `/v1/accounts/${ref(accountRef)}/entitlements`),
131
+ /**
132
+ * Hesap durumu (`AccountState`). ETag = `"<version>"`; önceki yanıtın
133
+ * `etag`'i verilirse ve durum değişmediyse 304 → `{notModified: true}`.
134
+ */
135
+ getAccountState: async (accountRef, opts = {}) => {
136
+ const sent = await send("GET", `/v1/accounts/${ref(accountRef)}/state`, void 0, void 0, opts.etag !== void 0 ? { "if-none-match": opts.etag } : void 0);
137
+ if (!("res" in sent)) return sent;
138
+ const { res } = sent;
139
+ const etag = res.headers.get("etag");
140
+ if (res.status === 304) {
141
+ const current = etag ?? opts.etag;
142
+ return current === void 0 ? invalid(res) : success(res, {
143
+ notModified: true,
144
+ etag: current
145
+ });
146
+ }
147
+ if (!res.ok) return failure(res);
148
+ const parsed = AccountStateSchema.safeParse(await res.json().catch(() => void 0));
149
+ if (!parsed.success) return invalid(res);
150
+ return success(res, {
151
+ notModified: false,
152
+ etag,
153
+ state: parsed.data
154
+ });
155
+ },
156
+ putBillingProfile: (accountRef, profile, opts) => call(BillingProfileResponseSchema, "PUT", `/v1/accounts/${ref(accountRef)}/billing-profile`, profile, opts),
157
+ /** Atomik plan (K6): aktif plan grant'leri → tek plan grant'i (`planCode: null` kaldırır); `strict`'te 409 `subscription_plan_higher`. */
158
+ setPlan: (accountRef, input, opts) => call(PlanSetResponseSchema, "PUT", `/v1/accounts/${ref(accountRef)}/plan`, input, opts),
159
+ /** Saklı durumu `account.state_changed` (`cause: "resync"`) olarak yeniden yayınlar; version değişmez (202). */
160
+ resync: (accountRef, opts) => call(ResyncResultSchema, "POST", `/v1/accounts/${ref(accountRef)}/resync`, void 0, opts),
161
+ /** KVKK anonimleştirme (F4e): `{ref, deletedAt}`; silinmişse 410 `account_deleted`, canlı abonelikte 409 `subscription_active`. */
162
+ deleteAccount: (accountRef, opts) => call(AccountDeleteResponseSchema, "DELETE", `/v1/accounts/${ref(accountRef)}`, void 0, opts),
163
+ createCheckoutSession: (accountRef, input, opts) => call(CheckoutSessionCreatedSchema, "POST", `/v1/accounts/${ref(accountRef)}/checkout-sessions`, input, opts),
164
+ getCheckoutSession: (id) => call(CheckoutSessionResponseSchema, "GET", `/v1/checkout-sessions/${ref(id)}`),
165
+ createPortalSession: (accountRef, input = {}, opts) => call(PortalSessionSchema, "POST", `/v1/accounts/${ref(accountRef)}/portal-sessions`, input, opts),
166
+ cancelSubscription: (id, input, opts) => call(CancelSubscriptionResponseSchema, "POST", `/v1/subscriptions/${ref(id)}/cancel`, input, opts),
167
+ createGrant: (accountRef, input, opts) => call(GrantCreateResponseSchema, "POST", `/v1/accounts/${ref(accountRef)}/grants`, input, opts),
168
+ revokeGrant: (id, opts) => empty("DELETE", `/v1/grants/${ref(id)}`, opts),
169
+ getStats: () => call(StatsSchema, "GET", "/v1/stats"),
170
+ doctor: () => call(DoctorReportSchema, "GET", "/v1/doctor"),
171
+ issueInvoice: (id, input, opts) => call(InvoiceIssueResponseSchema, "POST", `/v1/invoices/${ref(id)}/issue`, input, opts),
172
+ /** Manuel taslak fatura (F4f): profil gerekir (422 `billing_profile_required`); `issueInvoice` ile kesilir. */
173
+ createManualInvoice: (accountRef, input, opts) => call(ManualInvoiceResponseSchema, "POST", `/v1/accounts/${ref(accountRef)}/invoices`, input, opts),
174
+ /** Yalnızca manuel fatura (409 `invoice_has_payment` / `invoice_not_voidable`); `invoice.voided`. */
175
+ voidInvoice: (id, input, opts) => call(InvoiceVoidResponseSchema, "POST", `/v1/invoices/${ref(id)}/void`, input, opts),
176
+ getInvoiceDocument: async (id) => {
177
+ const sent = await send("GET", `/v1/invoices/${ref(id)}/document`, void 0, void 0);
178
+ if (!("res" in sent)) return sent;
179
+ const { res } = sent;
180
+ if (!res.ok) return failure(res);
181
+ return success(res, {
182
+ contentType: res.headers.get("content-type") ?? "application/octet-stream",
183
+ bytes: new Uint8Array(await res.arrayBuffer())
184
+ });
185
+ },
186
+ listEvents: (query = {}) => {
187
+ const params = new URLSearchParams();
188
+ if (query.accountRef) params.set("account", query.accountRef);
189
+ if (query.cursor) params.set("cursor", query.cursor);
190
+ if (query.limit) params.set("limit", String(query.limit));
191
+ const qs = params.toString();
192
+ return call(EventListSchema, "GET", `/v1/events${qs ? `?${qs}` : ""}`);
193
+ },
194
+ redeliverEvent: (id, opts) => call(EventRecordSchema, "POST", `/v1/events/${ref(id)}/redeliver`, void 0, opts),
195
+ getSettings: () => call(ProductSettingsSchema, "GET", "/v1/admin/settings"),
196
+ updateSettings: (patch, opts) => call(ProductSettingsSchema, "PATCH", "/v1/admin/settings", patch, opts),
197
+ listWebhookEndpoints: () => call(WebhookEndpointListSchema, "GET", "/v1/admin/webhook-endpoints"),
198
+ createWebhookEndpoint: (input, opts) => call(WebhookEndpointSchema, "POST", "/v1/admin/webhook-endpoints", input, opts),
199
+ rotateWebhookEndpointSecret: (id, input, opts) => call(WebhookEndpointSchema, "POST", `/v1/admin/webhook-endpoints/${ref(id)}/rotate`, input, opts),
200
+ deactivateWebhookEndpoint: (id, opts) => call(WebhookEndpointSchema, "POST", `/v1/admin/webhook-endpoints/${ref(id)}/deactivate`, void 0, opts)
201
+ };
202
+ }
203
+ //#endregion
204
+ //#region src/retry.ts
205
+ const RETRY_CLASSES = [
206
+ "network",
207
+ "5xx",
208
+ "429"
209
+ ];
210
+ const BASE_DELAY_MS = 250;
211
+ function retryPolicy(options = {}) {
212
+ const attempts = options.attempts ?? 2;
213
+ const maxDelayMs = options.maxDelayMs ?? 5e3;
214
+ const on = options.on ?? RETRY_CLASSES;
215
+ const problems = [];
216
+ if (!Number.isInteger(attempts) || attempts < 0) problems.push(`retries.attempts negatif olmayan tam sayı olmalı: ${attempts}`);
217
+ if (!Number.isFinite(maxDelayMs) || maxDelayMs < 0) problems.push(`retries.maxDelayMs negatif olmayan sayı olmalı: ${maxDelayMs}`);
218
+ for (const value of on) if (!RETRY_CLASSES.includes(value)) problems.push(`retries.on bilinmeyen sınıf: ${String(value)} (${RETRY_CLASSES.join(", ")})`);
219
+ if (problems.length > 0) throw new StewardConfigError({ message: `createSteward: ${problems.join("; ")}` });
220
+ return {
221
+ attempts,
222
+ on: new Set(on),
223
+ maxDelayMs,
224
+ sleep: options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms))),
225
+ random: options.random ?? Math.random
226
+ };
227
+ }
228
+ /** Başarısız sonucun tekrar sınıfı; hiçbirine girmiyorsa null (4xx, sözleşme hatası). */
229
+ function retryClassOf(failure) {
230
+ if (failure.status === 0) return "network";
231
+ if (failure.status === 429) return "429";
232
+ if (failure.status >= 500) return "5xx";
233
+ return null;
234
+ }
235
+ function shouldRetry(request, failure, policy) {
236
+ if (request.method !== "GET" && request.idempotencyKey === void 0) return false;
237
+ const kind = retryClassOf(failure);
238
+ if (kind === null || !policy.on.has(kind)) return false;
239
+ if (kind === "network") return true;
240
+ return (failure.retryable ?? errorCodeSpec(failure.error)?.retryable) !== false;
241
+ }
242
+ /** `retry`. tekrardan (1'den başlar) önceki bekleme, ms. */
243
+ function retryDelayMs(retry, failure, policy) {
244
+ if (failure.retryAfterMs !== void 0) return Math.min(failure.retryAfterMs, policy.maxDelayMs);
245
+ const ceiling = Math.min(policy.maxDelayMs, BASE_DELAY_MS * 2 ** (retry - 1));
246
+ return Math.round(ceiling / 2 + policy.random() * ceiling / 2);
247
+ }
248
+ /** `send`'i politika izin verdikçe tekrarlar; son sonucu (başarılı ya da değil) döner. */
249
+ async function withRetries(request, policy, send) {
250
+ let result = await send();
251
+ for (let retry = 1; retry <= policy.attempts && !result.ok && shouldRetry(request, result, policy); retry++) {
252
+ await policy.sleep(retryDelayMs(retry, result, policy));
253
+ result = await send();
254
+ }
255
+ return result;
256
+ }
257
+ //#endregion
258
+ //#region src/steward.ts
259
+ const SDK_HEADER = `@stewardhq/sdk/0.1.0-rc.0`;
260
+ const MeSchema = z.object({
261
+ product: z.string(),
262
+ keyName: z.string(),
263
+ scope: z.enum(["product", "admin"])
264
+ });
265
+ const defaultEnv = () => globalThis.process?.env ?? {};
266
+ function isHttpUrl(value) {
267
+ try {
268
+ const { protocol } = new URL(value);
269
+ return protocol === "http:" || protocol === "https:";
270
+ } catch {
271
+ return false;
272
+ }
273
+ }
274
+ /** Nesne ağacındaki her metodu, istek göndermeden `error(yol)` ile reddeden eşiyle değiştirir. */
275
+ function rejectAll(api, error, prefix = "") {
276
+ return Object.fromEntries(Object.entries(api).map(([name, value]) => {
277
+ const path = `${prefix}${name}`;
278
+ if (typeof value === "function") return [name, () => Promise.reject(error(path))];
279
+ return [name, typeof value === "object" && value !== null ? rejectAll(value, error, `${path}.`) : value];
280
+ }));
281
+ }
282
+ function createSteward(options = {}) {
283
+ const env = options.env ?? defaultEnv();
284
+ const setting = (value, name) => {
285
+ const text = (value ?? env[name])?.trim();
286
+ return text === void 0 || text === "" ? void 0 : text;
287
+ };
288
+ const baseUrl = setting(options.baseUrl, "STEWARD_URL");
289
+ const apiKey = setting(options.apiKey, "STEWARD_API_KEY");
290
+ const adminBaseUrl = setting(options.adminBaseUrl, "STEWARD_ADMIN_URL");
291
+ const adminApiKey = setting(options.adminApiKey, "STEWARD_ADMIN_API_KEY");
292
+ const timeoutMs = options.timeoutMs ?? 1e4;
293
+ const adminOnly = baseUrl === void 0 && apiKey === void 0 && adminBaseUrl !== void 0 && adminApiKey !== void 0;
294
+ const problems = [];
295
+ if (!adminOnly) {
296
+ if (baseUrl === void 0) problems.push("STEWARD_URL (baseUrl) tanımlı değil");
297
+ else if (!isHttpUrl(baseUrl)) problems.push("STEWARD_URL (baseUrl) geçerli bir http(s) adresi değil");
298
+ if (apiKey === void 0) problems.push("STEWARD_API_KEY (apiKey) tanımlı değil");
299
+ }
300
+ if (adminBaseUrl !== void 0 && !isHttpUrl(adminBaseUrl)) problems.push("STEWARD_ADMIN_URL (adminBaseUrl) geçerli bir http(s) adresi değil");
301
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) problems.push(`timeoutMs pozitif sayı olmalı: ${timeoutMs}`);
302
+ if (options.actorRef !== void 0 && !ActorRefSchema.safeParse(options.actorRef).success) problems.push("actorRef biçimi geçersiz (tür[:kimlik], ör. system, user:42)");
303
+ if (problems.length > 0) {
304
+ const hint = baseUrl === void 0 && apiKey === void 0 ? " (yalnızca admin.* için STEWARD_ADMIN_URL + STEWARD_ADMIN_API_KEY yeter)" : "";
305
+ throw new StewardConfigError({ message: `createSteward: ${problems.join("; ")}${hint}` });
306
+ }
307
+ const policy = retryPolicy(options.retries);
308
+ const doFetch = options.fetch ?? fetch;
309
+ const clientOptions = (target) => ({
310
+ ...target,
311
+ timeoutMs,
312
+ sdk: SDK_HEADER,
313
+ ...options.fetch !== void 0 ? { fetch: options.fetch } : {}
314
+ });
315
+ const adminTarget = adminBaseUrl !== void 0 && adminApiKey !== void 0 ? {
316
+ baseUrl: adminBaseUrl.replace(/\/$/, ""),
317
+ apiKey: adminApiKey
318
+ } : null;
319
+ const adminClient = adminTarget === null ? null : createBillingClient(clientOptions(adminTarget));
320
+ const productTarget = baseUrl !== void 0 && apiKey !== void 0 ? {
321
+ baseUrl: baseUrl.replace(/\/$/, ""),
322
+ apiKey
323
+ } : null;
324
+ const missingProduct = (name) => new StewardConfigError({ message: `steward.${name}: STEWARD_URL (baseUrl) ve STEWARD_API_KEY (apiKey) tanımlı değil; istemci yalnızca admin.* için yapılandırıldı` });
325
+ const raw = productTarget !== null ? createBillingClient(clientOptions(productTarget)) : rejectAll(createBillingClient(clientOptions({
326
+ baseUrl: "http://steward.invalid",
327
+ apiKey: "-"
328
+ })), (name) => missingProduct(`raw.${name}`));
329
+ const eitherTarget = productTarget ?? adminTarget;
330
+ const eitherClient = productTarget !== null ? raw : adminClient;
331
+ function requireAdmin() {
332
+ if (adminClient !== null && adminTarget !== null) return {
333
+ client: adminClient,
334
+ target: adminTarget
335
+ };
336
+ const missing = [...adminBaseUrl === void 0 ? ["STEWARD_ADMIN_URL (adminBaseUrl)"] : [], ...adminApiKey === void 0 ? ["STEWARD_ADMIN_API_KEY (adminApiKey)"] : []];
337
+ throw new StewardConfigError({ message: `steward.admin: ${missing.join(" ve ")} tanımlı değil` });
338
+ }
339
+ async function send(target, method, path, call, extraHeaders = {}) {
340
+ const headers = {
341
+ authorization: `Bearer ${target.apiKey}`,
342
+ accept: "application/json",
343
+ [HEADER_API_VERSION]: API_VERSION,
344
+ [HEADER_SDK]: SDK_HEADER,
345
+ ...extraHeaders
346
+ };
347
+ if (call.idempotencyKey !== void 0) headers[HEADER_IDEMPOTENCY_KEY] = call.idempotencyKey;
348
+ if (call.actorRef !== void 0) headers[HEADER_ACTOR_REF] = call.actorRef;
349
+ try {
350
+ return { res: await doFetch(`${target.baseUrl}${path}`, {
351
+ method,
352
+ headers,
353
+ signal: AbortSignal.timeout(timeoutMs)
354
+ }) };
355
+ } catch (error) {
356
+ const name = typeof error === "object" && error !== null ? error.name : void 0;
357
+ return {
358
+ ok: false,
359
+ status: 0,
360
+ error: name === "TimeoutError" || name === "AbortError" ? "timeout" : "network_error"
361
+ };
362
+ }
363
+ }
364
+ function meta(res) {
365
+ const requestId = res.headers.get(HEADER_REQUEST_ID);
366
+ const retryAfterMs = res.status === 429 || res.status === 503 ? parseRetryAfter(res.headers.get("retry-after")) : null;
367
+ return {
368
+ ...requestId ? { requestId } : {},
369
+ ...retryAfterMs !== null ? { retryAfterMs } : {}
370
+ };
371
+ }
372
+ async function failureOf(res) {
373
+ const parsed = ErrorResponseSchema.safeParse(await res.json().catch(() => null));
374
+ const { requestId, retryAfterMs } = meta(res);
375
+ const common = { ...retryAfterMs !== void 0 ? { retryAfterMs } : {} };
376
+ if (!parsed.success) return {
377
+ ok: false,
378
+ status: res.status,
379
+ error: `http_${res.status}`,
380
+ ...requestId !== void 0 ? { requestId } : {},
381
+ ...common
382
+ };
383
+ const { error, message, category, retryable } = parsed.data;
384
+ const id = requestId ?? parsed.data.requestId;
385
+ return {
386
+ ok: false,
387
+ status: res.status,
388
+ error,
389
+ ...message !== void 0 ? { message } : {},
390
+ ...category !== void 0 ? { category } : {},
391
+ ...retryable !== void 0 ? { retryable } : {},
392
+ ...id !== void 0 ? { requestId: id } : {},
393
+ ...common
394
+ };
395
+ }
396
+ function success(res, data) {
397
+ const { requestId } = meta(res);
398
+ return {
399
+ ok: true,
400
+ status: res.status,
401
+ data,
402
+ ...requestId !== void 0 ? { requestId } : {}
403
+ };
404
+ }
405
+ function invalid(res) {
406
+ const { requestId } = meta(res);
407
+ return {
408
+ ok: false,
409
+ status: res.status,
410
+ error: "invalid_response",
411
+ ...requestId !== void 0 ? { requestId } : {}
412
+ };
413
+ }
414
+ async function sendParsed(target, method, path, schema, call) {
415
+ const sent = await send(target, method, path, call);
416
+ if (!("res" in sent)) return sent;
417
+ if (!sent.res.ok) return failureOf(sent.res);
418
+ const parsed = schema.safeParse(await sent.res.json().catch(() => void 0));
419
+ return parsed.success ? success(sent.res, parsed.data) : invalid(sent.res);
420
+ }
421
+ async function readCatalog(etag) {
422
+ const sent = await send(productTarget, "GET", "/v1/catalog", {}, etag !== void 0 ? { "if-none-match": etag } : {});
423
+ if (!("res" in sent)) return sent;
424
+ const { res } = sent;
425
+ const responseEtag = res.headers.get("etag");
426
+ if (res.status === 304) {
427
+ const current = responseEtag ?? etag;
428
+ return current === void 0 ? invalid(res) : success(res, {
429
+ notModified: true,
430
+ etag: current
431
+ });
432
+ }
433
+ if (!res.ok) return failureOf(res);
434
+ const parsed = CatalogSchema.safeParse(await res.json().catch(() => void 0));
435
+ return parsed.success ? success(res, {
436
+ notModified: false,
437
+ etag: responseEtag,
438
+ catalog: parsed.data
439
+ }) : invalid(res);
440
+ }
441
+ function toError(failure) {
442
+ const context = {
443
+ ...failure.requestId !== void 0 ? { requestId: failure.requestId } : {},
444
+ ...failure.retryAfterMs !== void 0 ? { retryAfterMs: failure.retryAfterMs } : {}
445
+ };
446
+ if (failure.status === 0) return new StewardNetworkError({
447
+ code: failure.error === "timeout" ? "timeout" : "network_error",
448
+ ...context
449
+ });
450
+ if (failure.error === "invalid_response") return new StewardContractError({
451
+ httpStatus: failure.status,
452
+ ...context
453
+ });
454
+ return new StewardApiError({
455
+ code: failure.error,
456
+ httpStatus: failure.status,
457
+ ...failure.message !== void 0 ? { message: failure.message } : {},
458
+ ...failure.category !== void 0 ? { category: failure.category } : {},
459
+ ...failure.retryable !== void 0 ? { retryable: failure.retryable } : {},
460
+ ...context
461
+ });
462
+ }
463
+ async function run(method, call, attempt) {
464
+ let effective = {};
465
+ if (method !== "GET") {
466
+ const actorRef = call?.actorRef ?? options.actorRef;
467
+ if (actorRef === void 0) throw new StewardConfigError({
468
+ code: "actor_ref_required",
469
+ message: "actorRef yok: createSteward({ actorRef }) ya da çağrıda { actorRef } verin (tür[:kimlik], ör. user:42, system)"
470
+ });
471
+ if (!ActorRefSchema.safeParse(actorRef).success) throw new StewardConfigError({
472
+ code: "invalid_actor_ref",
473
+ message: "actorRef biçimi geçersiz (tür[:kimlik], ör. user:42, system)"
474
+ });
475
+ effective = {
476
+ idempotencyKey: call?.idempotencyKey ?? globalThis.crypto.randomUUID(),
477
+ actorRef
478
+ };
479
+ }
480
+ const result = await withRetries({
481
+ method,
482
+ ...effective.idempotencyKey !== void 0 ? { idempotencyKey: effective.idempotencyKey } : {}
483
+ }, policy, () => attempt(effective));
484
+ if (result.ok) return result.data;
485
+ throw toError(result);
486
+ }
487
+ const read = (attempt) => run("GET", void 0, attempt);
488
+ const productApi = {
489
+ accounts: {
490
+ upsert: (ref, input, call) => run("PUT", call, (c) => raw.upsertAccount(ref, input, c)),
491
+ get: (ref, opts = {}) => read(() => raw.getAccount(ref, opts.include)),
492
+ state: async (ref) => {
493
+ const result = await read(() => raw.getAccountState(ref));
494
+ if (result.notModified) throw new StewardContractError({ httpStatus: 304 });
495
+ return result.state;
496
+ },
497
+ readState: (ref, opts = {}) => read(() => raw.getAccountState(ref, opts.etag !== void 0 ? { etag: opts.etag } : {})),
498
+ entitlements: (ref) => read(() => raw.getEntitlements(ref)),
499
+ putBillingProfile: (ref, profile, call) => run("PUT", call, (c) => raw.putBillingProfile(ref, profile, c)),
500
+ setPlan: (ref, input, call) => run("PUT", call, (c) => raw.setPlan(ref, input, c)),
501
+ resync: (ref, call) => run("POST", call, (c) => raw.resync(ref, c)),
502
+ delete: (ref, call) => run("DELETE", call, (c) => raw.deleteAccount(ref, c))
503
+ },
504
+ checkoutSessions: {
505
+ create: (ref, input, call) => run("POST", call, (c) => raw.createCheckoutSession(ref, input, c)),
506
+ get: (id) => read(() => raw.getCheckoutSession(id))
507
+ },
508
+ portalSessions: { create: (ref, input = {}, call) => run("POST", call, (c) => raw.createPortalSession(ref, input, c)) },
509
+ subscriptions: { cancel: (id, input, call) => run("POST", call, (c) => raw.cancelSubscription(id, input, c)) },
510
+ grants: {
511
+ create: (ref, input, call) => run("POST", call, (c) => raw.createGrant(ref, input, c)),
512
+ revoke: async (id, call) => {
513
+ await run("DELETE", call, (c) => raw.revokeGrant(id, c));
514
+ }
515
+ },
516
+ invoices: {
517
+ issue: (id, input, call) => run("POST", call, (c) => raw.issueInvoice(id, input, c)),
518
+ document: (id) => read(() => raw.getInvoiceDocument(id)),
519
+ createManual: (ref, input, call) => run("POST", call, (c) => raw.createManualInvoice(ref, input, c)),
520
+ void: (id, input, call) => run("POST", call, (c) => raw.voidInvoice(id, input, c))
521
+ },
522
+ catalog: {
523
+ get: () => read(() => raw.getCatalog()),
524
+ read: (opts = {}) => read(() => readCatalog(opts.etag))
525
+ },
526
+ events: {
527
+ list: (query = {}) => read(() => raw.listEvents(query)),
528
+ redeliver: (id, call) => run("POST", call, (c) => raw.redeliverEvent(id, c))
529
+ },
530
+ stats: () => read(() => raw.getStats())
531
+ };
532
+ return {
533
+ ...productTarget !== null ? productApi : rejectAll(productApi, missingProduct),
534
+ me: () => read(() => sendParsed(eitherTarget, "GET", "/v1/me", MeSchema, {})),
535
+ doctor: () => read(() => eitherClient.doctor()),
536
+ admin: {
537
+ catalog: { sync: async (input, call) => {
538
+ const { client } = requireAdmin();
539
+ return run("PUT", call, (c) => client.syncCatalog(input, c));
540
+ } },
541
+ accounts: { refresh: async (call) => {
542
+ const { target } = requireAdmin();
543
+ return run("POST", call, (c) => sendParsed(target, "POST", "/v1/admin/accounts/refresh", AccountsRefreshResultSchema, c));
544
+ } },
545
+ settings: {
546
+ get: async () => {
547
+ const { client } = requireAdmin();
548
+ return read(() => client.getSettings());
549
+ },
550
+ update: async (patch, call) => {
551
+ const { client } = requireAdmin();
552
+ return run("PATCH", call, (c) => client.updateSettings(patch, c));
553
+ }
554
+ },
555
+ endpoints: {
556
+ list: async () => {
557
+ const { client } = requireAdmin();
558
+ return read(() => client.listWebhookEndpoints());
559
+ },
560
+ create: async (input, call) => {
561
+ const { client } = requireAdmin();
562
+ return run("POST", call, (c) => client.createWebhookEndpoint(input, c));
563
+ },
564
+ rotate: async (id, input, call) => {
565
+ const { client } = requireAdmin();
566
+ return run("POST", call, (c) => client.rotateWebhookEndpointSecret(id, input, c));
567
+ },
568
+ deactivate: async (id, call) => {
569
+ const { client } = requireAdmin();
570
+ return run("POST", call, (c) => client.deactivateWebhookEndpoint(id, c));
571
+ }
572
+ }
573
+ },
574
+ raw
575
+ };
576
+ }
577
+ //#endregion
578
+ export { createBillingClient as n, parseRetryAfter as r, createSteward as t };
@@ -0,0 +1,23 @@
1
+ //#region ../contract/src/validators.d.ts
2
+ /**
3
+ * T.C. kimlik numarası: 11 hane, ilk hane 0 değil;
4
+ * 10. hane = ((1.+3.+5.+7.+9.) × 7 − (2.+4.+6.+8.)) mod 10,
5
+ * 11. hane = (ilk 10 hanenin toplamı) mod 10.
6
+ */
7
+ declare function isValidTckn(value: unknown): boolean;
8
+ /**
9
+ * Vergi kimlik numarası (GİB): 10 hane; i = 0…8 için
10
+ * t = (hane + 9 − i) mod 10, p = t × 2^(9 − i) mod 9 (t ≠ 0 ve p = 0 ise 9),
11
+ * son hane = (10 − Σp mod 10) mod 10.
12
+ */
13
+ declare function isValidVkn(value: unknown): boolean;
14
+ /**
15
+ * E.164 telefon: `+`, sıfırla başlamayan ülke kodu, toplam 8–15 hane
16
+ * (steward fatura profili şemasıyla aynı). `{country: "TR"}`: `+90` ve 10 hane
17
+ * (iyzico'nun istediği biçim).
18
+ */
19
+ declare function isE164(value: unknown, options?: {
20
+ country?: "TR";
21
+ }): boolean;
22
+ //#endregion
23
+ export { isValidTckn as n, isValidVkn as r, isE164 as t };