@stewardhq/sdk 0.2.0 → 0.5.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 (39) hide show
  1. package/README.md +123 -88
  2. package/dist/_chunks/errors.js +1 -1
  3. package/dist/_chunks/events.d.ts +315 -4
  4. package/dist/_chunks/events.js +1155 -9
  5. package/dist/_chunks/index.d.ts +3473 -90
  6. package/dist/_chunks/locale.d.ts +269 -1
  7. package/dist/_chunks/src.js +842 -24
  8. package/dist/_chunks/validators.d.ts +45 -1
  9. package/dist/_chunks/validators.js +128 -27
  10. package/dist/contract.d.ts +4 -4
  11. package/dist/contract.js +4 -4
  12. package/dist/index.d.ts +436 -22
  13. package/dist/index.js +1659 -26
  14. package/dist/server.d.ts +44 -6
  15. package/dist/server.js +29 -2
  16. package/package.json +4 -10
  17. package/dist/_chunks/steward.d.ts +0 -189
  18. package/dist/_chunks/steward.js +0 -560
  19. package/dist/testing/fixtures/events/LOCK.json +0 -27
  20. package/dist/testing/fixtures/events/account.deleted.json +0 -36
  21. package/dist/testing/fixtures/events/account.state_changed.json +0 -53
  22. package/dist/testing/fixtures/events/account.updated.json +0 -37
  23. package/dist/testing/fixtures/events/checkout.completed.json +0 -36
  24. package/dist/testing/fixtures/events/checkout.expired.json +0 -26
  25. package/dist/testing/fixtures/events/checkout.failed.json +0 -27
  26. package/dist/testing/fixtures/events/invoice.created.json +0 -37
  27. package/dist/testing/fixtures/events/invoice.issued.json +0 -38
  28. package/dist/testing/fixtures/events/invoice.voided.json +0 -39
  29. package/dist/testing/fixtures/events/subscription.activated.json +0 -40
  30. package/dist/testing/fixtures/events/subscription.cancel_scheduled.json +0 -38
  31. package/dist/testing/fixtures/events/subscription.canceled.json +0 -29
  32. package/dist/testing/fixtures/events/subscription.expired.json +0 -27
  33. package/dist/testing/fixtures/events/subscription.payment_failed.json +0 -38
  34. package/dist/testing/fixtures/events/subscription.reactivated.json +0 -36
  35. package/dist/testing/fixtures/events/subscription.renewed.json +0 -39
  36. package/dist/testing/fixtures/events/subscription.suspended.json +0 -36
  37. package/dist/testing/fixtures/events/subscription.terminated.json +0 -28
  38. package/dist/testing.d.ts +0 -626
  39. package/dist/testing.js +0 -3638
@@ -1,560 +0,0 @@
1
- import { D as API_VERSION, L as ErrorResponseSchema, O as ActorRefSchema, p as AccountDeleteResponseSchema, y as AccountStateSchema } from "./events.js";
2
- import { B as AccountDetailSchema, C as WebhookEndpointListSchema, G as HEADER_ACTOR_REF, H as CancelSubscriptionResponseSchema, I as ResyncResultSchema, J as HEADER_REQUEST_ID, K as HEADER_API_VERSION, Kt as CatalogSyncResultSchema, P as PlanSetResponseSchema, Pt as ProductSettingsSchema, Q as ManualInvoiceResponseSchema, R as errorCodeSpec, St as CheckoutSessionCreatedSchema, T as WebhookEndpointSchema, U as CheckoutSessionResponseSchema, Ut as AccountsRefreshResultSchema, V as AccountUpsertResponseSchema, W as GrantCreateResponseSchema, Wt as CatalogSchema, X as InvoiceIssueResponseSchema, Y as HEADER_SDK, Z as InvoiceVoidResponseSchema, _t as PortalSessionSchema, pt as StatsSchema, q as HEADER_IDEMPOTENCY_KEY, u as DoctorReportSchema } 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
- /**
131
- * Hesap durumu (`AccountState`). ETag = `"<version>"`; önceki yanıtın
132
- * `etag`'i verilirse ve durum değişmediyse 304 → `{notModified: true}`.
133
- */
134
- getAccountState: async (accountRef, opts = {}) => {
135
- 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);
136
- if (!("res" in sent)) return sent;
137
- const { res } = sent;
138
- const etag = res.headers.get("etag");
139
- if (res.status === 304) {
140
- const current = etag ?? opts.etag;
141
- return current === void 0 ? invalid(res) : success(res, {
142
- notModified: true,
143
- etag: current
144
- });
145
- }
146
- if (!res.ok) return failure(res);
147
- const parsed = AccountStateSchema.safeParse(await res.json().catch(() => void 0));
148
- if (!parsed.success) return invalid(res);
149
- return success(res, {
150
- notModified: false,
151
- etag,
152
- state: parsed.data
153
- });
154
- },
155
- /** Atomik plan (K6): aktif plan grant'leri → tek plan grant'i (`planCode: null` kaldırır); `strict`'te 409 `subscription_plan_higher`. */
156
- setPlan: (accountRef, input, opts) => call(PlanSetResponseSchema, "PUT", `/v1/accounts/${ref(accountRef)}/plan`, input, opts),
157
- /** Saklı durumu `account.state_changed` (`cause: "resync"`) olarak yeniden yayınlar; version değişmez (202). */
158
- resync: (accountRef, opts) => call(ResyncResultSchema, "POST", `/v1/accounts/${ref(accountRef)}/resync`, void 0, opts),
159
- /** KVKK anonimleştirme (F4e): `{ref, deletedAt}`; silinmişse 410 `account_deleted`, canlı abonelikte 409 `subscription_active`. */
160
- deleteAccount: (accountRef, opts) => call(AccountDeleteResponseSchema, "DELETE", `/v1/accounts/${ref(accountRef)}`, void 0, opts),
161
- createCheckoutSession: (accountRef, input, opts) => call(CheckoutSessionCreatedSchema, "POST", `/v1/accounts/${ref(accountRef)}/checkout-sessions`, input, opts),
162
- getCheckoutSession: (id) => call(CheckoutSessionResponseSchema, "GET", `/v1/checkout-sessions/${ref(id)}`),
163
- createPortalSession: (accountRef, input = {}, opts) => call(PortalSessionSchema, "POST", `/v1/accounts/${ref(accountRef)}/portal-sessions`, input, opts),
164
- cancelSubscription: (id, input, opts) => call(CancelSubscriptionResponseSchema, "POST", `/v1/subscriptions/${ref(id)}/cancel`, input, opts),
165
- createGrant: (accountRef, input, opts) => call(GrantCreateResponseSchema, "POST", `/v1/accounts/${ref(accountRef)}/grants`, input, opts),
166
- revokeGrant: (id, opts) => empty("DELETE", `/v1/grants/${ref(id)}`, opts),
167
- getStats: () => call(StatsSchema, "GET", "/v1/stats"),
168
- doctor: () => call(DoctorReportSchema, "GET", "/v1/doctor"),
169
- issueInvoice: (id, input, opts) => call(InvoiceIssueResponseSchema, "POST", `/v1/invoices/${ref(id)}/issue`, input, opts),
170
- /** Manuel taslak fatura (F4f): profil gerekir (422 `billing_profile_required`); `issueInvoice` ile kesilir. */
171
- createManualInvoice: (accountRef, input, opts) => call(ManualInvoiceResponseSchema, "POST", `/v1/accounts/${ref(accountRef)}/invoices`, input, opts),
172
- /** Yalnızca manuel fatura (409 `invoice_has_payment` / `invoice_not_voidable`); `invoice.voided`. */
173
- voidInvoice: (id, input, opts) => call(InvoiceVoidResponseSchema, "POST", `/v1/invoices/${ref(id)}/void`, input, opts),
174
- getInvoiceDocument: async (id) => {
175
- const sent = await send("GET", `/v1/invoices/${ref(id)}/document`, void 0, void 0);
176
- if (!("res" in sent)) return sent;
177
- const { res } = sent;
178
- if (!res.ok) return failure(res);
179
- return success(res, {
180
- contentType: res.headers.get("content-type") ?? "application/octet-stream",
181
- bytes: new Uint8Array(await res.arrayBuffer())
182
- });
183
- },
184
- getSettings: () => call(ProductSettingsSchema, "GET", "/v1/admin/settings"),
185
- updateSettings: (patch, opts) => call(ProductSettingsSchema, "PATCH", "/v1/admin/settings", patch, opts),
186
- listWebhookEndpoints: () => call(WebhookEndpointListSchema, "GET", "/v1/admin/webhook-endpoints"),
187
- createWebhookEndpoint: (input, opts) => call(WebhookEndpointSchema, "POST", "/v1/admin/webhook-endpoints", input, opts),
188
- rotateWebhookEndpointSecret: (id, input, opts) => call(WebhookEndpointSchema, "POST", `/v1/admin/webhook-endpoints/${ref(id)}/rotate`, input, opts),
189
- deactivateWebhookEndpoint: (id, opts) => call(WebhookEndpointSchema, "POST", `/v1/admin/webhook-endpoints/${ref(id)}/deactivate`, void 0, opts)
190
- };
191
- }
192
- //#endregion
193
- //#region src/retry.ts
194
- const RETRY_CLASSES = [
195
- "network",
196
- "5xx",
197
- "429"
198
- ];
199
- const BASE_DELAY_MS = 250;
200
- function retryPolicy(options = {}) {
201
- const attempts = options.attempts ?? 2;
202
- const maxDelayMs = options.maxDelayMs ?? 5e3;
203
- const on = options.on ?? RETRY_CLASSES;
204
- const problems = [];
205
- if (!Number.isInteger(attempts) || attempts < 0) problems.push(`retries.attempts negatif olmayan tam sayı olmalı: ${attempts}`);
206
- if (!Number.isFinite(maxDelayMs) || maxDelayMs < 0) problems.push(`retries.maxDelayMs negatif olmayan sayı olmalı: ${maxDelayMs}`);
207
- for (const value of on) if (!RETRY_CLASSES.includes(value)) problems.push(`retries.on bilinmeyen sınıf: ${String(value)} (${RETRY_CLASSES.join(", ")})`);
208
- if (problems.length > 0) throw new StewardConfigError({ message: `createSteward: ${problems.join("; ")}` });
209
- return {
210
- attempts,
211
- on: new Set(on),
212
- maxDelayMs,
213
- sleep: options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms))),
214
- random: options.random ?? Math.random
215
- };
216
- }
217
- /** Başarısız sonucun tekrar sınıfı; hiçbirine girmiyorsa null (4xx, sözleşme hatası). */
218
- function retryClassOf(failure) {
219
- if (failure.status === 0) return "network";
220
- if (failure.status === 429) return "429";
221
- if (failure.status >= 500) return "5xx";
222
- return null;
223
- }
224
- function shouldRetry(request, failure, policy) {
225
- if (request.method !== "GET" && request.idempotencyKey === void 0) return false;
226
- const kind = retryClassOf(failure);
227
- if (kind === null || !policy.on.has(kind)) return false;
228
- if (kind === "network") return true;
229
- return (failure.retryable ?? errorCodeSpec(failure.error)?.retryable) !== false;
230
- }
231
- /** `retry`. tekrardan (1'den başlar) önceki bekleme, ms. */
232
- function retryDelayMs(retry, failure, policy) {
233
- if (failure.retryAfterMs !== void 0) return Math.min(failure.retryAfterMs, policy.maxDelayMs);
234
- const ceiling = Math.min(policy.maxDelayMs, BASE_DELAY_MS * 2 ** (retry - 1));
235
- return Math.round(ceiling / 2 + policy.random() * ceiling / 2);
236
- }
237
- /** `send`'i politika izin verdikçe tekrarlar; son sonucu (başarılı ya da değil) döner. */
238
- async function withRetries(request, policy, send) {
239
- let result = await send();
240
- for (let retry = 1; retry <= policy.attempts && !result.ok && shouldRetry(request, result, policy); retry++) {
241
- await policy.sleep(retryDelayMs(retry, result, policy));
242
- result = await send();
243
- }
244
- return result;
245
- }
246
- //#endregion
247
- //#region src/steward.ts
248
- const SDK_HEADER = `@stewardhq/sdk/0.2.0`;
249
- const MeSchema = z.object({
250
- product: z.string(),
251
- keyName: z.string(),
252
- scope: z.enum(["product", "admin"])
253
- });
254
- const defaultEnv = () => globalThis.process?.env ?? {};
255
- function isHttpUrl(value) {
256
- try {
257
- const { protocol } = new URL(value);
258
- return protocol === "http:" || protocol === "https:";
259
- } catch {
260
- return false;
261
- }
262
- }
263
- /** Nesne ağacındaki her metodu, istek göndermeden `error(yol)` ile reddeden eşiyle değiştirir. */
264
- function rejectAll(api, error, prefix = "") {
265
- return Object.fromEntries(Object.entries(api).map(([name, value]) => {
266
- const path = `${prefix}${name}`;
267
- if (typeof value === "function") return [name, () => Promise.reject(error(path))];
268
- return [name, typeof value === "object" && value !== null ? rejectAll(value, error, `${path}.`) : value];
269
- }));
270
- }
271
- function createSteward(options = {}) {
272
- const env = options.env ?? defaultEnv();
273
- const setting = (value, name) => {
274
- const text = (value ?? env[name])?.trim();
275
- return text === void 0 || text === "" ? void 0 : text;
276
- };
277
- const baseUrl = setting(options.baseUrl, "STEWARD_URL");
278
- const apiKey = setting(options.apiKey, "STEWARD_API_KEY");
279
- const adminBaseUrl = setting(options.adminBaseUrl, "STEWARD_ADMIN_URL");
280
- const adminApiKey = setting(options.adminApiKey, "STEWARD_ADMIN_API_KEY");
281
- const timeoutMs = options.timeoutMs ?? 1e4;
282
- const adminOnly = baseUrl === void 0 && apiKey === void 0 && adminBaseUrl !== void 0 && adminApiKey !== void 0;
283
- const problems = [];
284
- if (!adminOnly) {
285
- if (baseUrl === void 0) problems.push("STEWARD_URL (baseUrl) tanımlı değil");
286
- else if (!isHttpUrl(baseUrl)) problems.push("STEWARD_URL (baseUrl) geçerli bir http(s) adresi değil");
287
- if (apiKey === void 0) problems.push("STEWARD_API_KEY (apiKey) tanımlı değil");
288
- }
289
- if (adminBaseUrl !== void 0 && !isHttpUrl(adminBaseUrl)) problems.push("STEWARD_ADMIN_URL (adminBaseUrl) geçerli bir http(s) adresi değil");
290
- if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) problems.push(`timeoutMs pozitif sayı olmalı: ${timeoutMs}`);
291
- if (options.actorRef !== void 0 && !ActorRefSchema.safeParse(options.actorRef).success) problems.push("actorRef biçimi geçersiz (tür[:kimlik], ör. system, user:42)");
292
- if (problems.length > 0) {
293
- const hint = baseUrl === void 0 && apiKey === void 0 ? " (yalnızca admin.* için STEWARD_ADMIN_URL + STEWARD_ADMIN_API_KEY yeter)" : "";
294
- throw new StewardConfigError({ message: `createSteward: ${problems.join("; ")}${hint}` });
295
- }
296
- const policy = retryPolicy(options.retries);
297
- const doFetch = options.fetch ?? fetch;
298
- const clientOptions = (target) => ({
299
- ...target,
300
- timeoutMs,
301
- sdk: SDK_HEADER,
302
- ...options.fetch !== void 0 ? { fetch: options.fetch } : {}
303
- });
304
- const adminTarget = adminBaseUrl !== void 0 && adminApiKey !== void 0 ? {
305
- baseUrl: adminBaseUrl.replace(/\/$/, ""),
306
- apiKey: adminApiKey
307
- } : null;
308
- const adminClient = adminTarget === null ? null : createBillingClient(clientOptions(adminTarget));
309
- const productTarget = baseUrl !== void 0 && apiKey !== void 0 ? {
310
- baseUrl: baseUrl.replace(/\/$/, ""),
311
- apiKey
312
- } : null;
313
- 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ı` });
314
- const raw = createBillingClient(clientOptions(productTarget ?? {
315
- baseUrl: "http://steward.invalid",
316
- apiKey: "-"
317
- }));
318
- const eitherTarget = productTarget ?? adminTarget;
319
- const eitherClient = productTarget !== null ? raw : adminClient;
320
- function requireAdmin() {
321
- if (adminClient !== null && adminTarget !== null) return {
322
- client: adminClient,
323
- target: adminTarget
324
- };
325
- const missing = [...adminBaseUrl === void 0 ? ["STEWARD_ADMIN_URL (adminBaseUrl)"] : [], ...adminApiKey === void 0 ? ["STEWARD_ADMIN_API_KEY (adminApiKey)"] : []];
326
- throw new StewardConfigError({ message: `steward.admin: ${missing.join(" ve ")} tanımlı değil` });
327
- }
328
- async function send(target, method, path, call, extraHeaders = {}) {
329
- const headers = {
330
- authorization: `Bearer ${target.apiKey}`,
331
- accept: "application/json",
332
- [HEADER_API_VERSION]: API_VERSION,
333
- [HEADER_SDK]: SDK_HEADER,
334
- ...extraHeaders
335
- };
336
- if (call.idempotencyKey !== void 0) headers[HEADER_IDEMPOTENCY_KEY] = call.idempotencyKey;
337
- if (call.actorRef !== void 0) headers[HEADER_ACTOR_REF] = call.actorRef;
338
- try {
339
- return { res: await doFetch(`${target.baseUrl}${path}`, {
340
- method,
341
- headers,
342
- signal: AbortSignal.timeout(timeoutMs)
343
- }) };
344
- } catch (error) {
345
- const name = typeof error === "object" && error !== null ? error.name : void 0;
346
- return {
347
- ok: false,
348
- status: 0,
349
- error: name === "TimeoutError" || name === "AbortError" ? "timeout" : "network_error"
350
- };
351
- }
352
- }
353
- function meta(res) {
354
- const requestId = res.headers.get(HEADER_REQUEST_ID);
355
- const retryAfterMs = res.status === 429 || res.status === 503 ? parseRetryAfter(res.headers.get("retry-after")) : null;
356
- return {
357
- ...requestId ? { requestId } : {},
358
- ...retryAfterMs !== null ? { retryAfterMs } : {}
359
- };
360
- }
361
- async function failureOf(res) {
362
- const parsed = ErrorResponseSchema.safeParse(await res.json().catch(() => null));
363
- const { requestId, retryAfterMs } = meta(res);
364
- const common = { ...retryAfterMs !== void 0 ? { retryAfterMs } : {} };
365
- if (!parsed.success) return {
366
- ok: false,
367
- status: res.status,
368
- error: `http_${res.status}`,
369
- ...requestId !== void 0 ? { requestId } : {},
370
- ...common
371
- };
372
- const { error, message, category, retryable } = parsed.data;
373
- const id = requestId ?? parsed.data.requestId;
374
- return {
375
- ok: false,
376
- status: res.status,
377
- error,
378
- ...message !== void 0 ? { message } : {},
379
- ...category !== void 0 ? { category } : {},
380
- ...retryable !== void 0 ? { retryable } : {},
381
- ...id !== void 0 ? { requestId: id } : {},
382
- ...common
383
- };
384
- }
385
- function success(res, data) {
386
- const { requestId } = meta(res);
387
- return {
388
- ok: true,
389
- status: res.status,
390
- data,
391
- ...requestId !== void 0 ? { requestId } : {}
392
- };
393
- }
394
- function invalid(res) {
395
- const { requestId } = meta(res);
396
- return {
397
- ok: false,
398
- status: res.status,
399
- error: "invalid_response",
400
- ...requestId !== void 0 ? { requestId } : {}
401
- };
402
- }
403
- async function sendParsed(target, method, path, schema, call) {
404
- const sent = await send(target, method, path, call);
405
- if (!("res" in sent)) return sent;
406
- if (!sent.res.ok) return failureOf(sent.res);
407
- const parsed = schema.safeParse(await sent.res.json().catch(() => void 0));
408
- return parsed.success ? success(sent.res, parsed.data) : invalid(sent.res);
409
- }
410
- async function readCatalog(etag) {
411
- const sent = await send(productTarget, "GET", "/v1/catalog", {}, etag !== void 0 ? { "if-none-match": etag } : {});
412
- if (!("res" in sent)) return sent;
413
- const { res } = sent;
414
- const responseEtag = res.headers.get("etag");
415
- if (res.status === 304) {
416
- const current = responseEtag ?? etag;
417
- return current === void 0 ? invalid(res) : success(res, {
418
- notModified: true,
419
- etag: current
420
- });
421
- }
422
- if (!res.ok) return failureOf(res);
423
- const parsed = CatalogSchema.safeParse(await res.json().catch(() => void 0));
424
- return parsed.success ? success(res, {
425
- notModified: false,
426
- etag: responseEtag,
427
- catalog: parsed.data
428
- }) : invalid(res);
429
- }
430
- function toError(failure) {
431
- const context = {
432
- ...failure.requestId !== void 0 ? { requestId: failure.requestId } : {},
433
- ...failure.retryAfterMs !== void 0 ? { retryAfterMs: failure.retryAfterMs } : {}
434
- };
435
- if (failure.status === 0) return new StewardNetworkError({
436
- code: failure.error === "timeout" ? "timeout" : "network_error",
437
- ...context
438
- });
439
- if (failure.error === "invalid_response") return new StewardContractError({
440
- httpStatus: failure.status,
441
- ...context
442
- });
443
- return new StewardApiError({
444
- code: failure.error,
445
- httpStatus: failure.status,
446
- ...failure.message !== void 0 ? { message: failure.message } : {},
447
- ...failure.category !== void 0 ? { category: failure.category } : {},
448
- ...failure.retryable !== void 0 ? { retryable: failure.retryable } : {},
449
- ...context
450
- });
451
- }
452
- async function run(method, call, attempt) {
453
- let effective = {};
454
- if (method !== "GET") {
455
- const actorRef = call?.actorRef ?? options.actorRef;
456
- if (actorRef === void 0) throw new StewardConfigError({
457
- code: "actor_ref_required",
458
- message: "actorRef yok: createSteward({ actorRef }) ya da çağrıda { actorRef } verin (tür[:kimlik], ör. user:42, system)"
459
- });
460
- if (!ActorRefSchema.safeParse(actorRef).success) throw new StewardConfigError({
461
- code: "invalid_actor_ref",
462
- message: "actorRef biçimi geçersiz (tür[:kimlik], ör. user:42, system)"
463
- });
464
- effective = {
465
- idempotencyKey: call?.idempotencyKey ?? globalThis.crypto.randomUUID(),
466
- actorRef
467
- };
468
- }
469
- const result = await withRetries({
470
- method,
471
- ...effective.idempotencyKey !== void 0 ? { idempotencyKey: effective.idempotencyKey } : {}
472
- }, policy, () => attempt(effective));
473
- if (result.ok) return result.data;
474
- throw toError(result);
475
- }
476
- const read = (attempt) => run("GET", void 0, attempt);
477
- const productApi = {
478
- accounts: {
479
- upsert: (ref, input, call) => run("PUT", call, (c) => raw.upsertAccount(ref, input, c)),
480
- get: (ref, opts = {}) => read(() => raw.getAccount(ref, opts.include)),
481
- state: async (ref) => {
482
- const result = await read(() => raw.getAccountState(ref));
483
- if (result.notModified) throw new StewardContractError({ httpStatus: 304 });
484
- return result.state;
485
- },
486
- readState: (ref, opts = {}) => read(() => raw.getAccountState(ref, opts.etag !== void 0 ? { etag: opts.etag } : {})),
487
- setPlan: (ref, input, call) => run("PUT", call, (c) => raw.setPlan(ref, input, c)),
488
- resync: (ref, call) => run("POST", call, (c) => raw.resync(ref, c)),
489
- delete: (ref, call) => run("DELETE", call, (c) => raw.deleteAccount(ref, c))
490
- },
491
- checkoutSessions: {
492
- create: (ref, input, call) => run("POST", call, (c) => raw.createCheckoutSession(ref, input, c)),
493
- get: (id) => read(() => raw.getCheckoutSession(id))
494
- },
495
- portalSessions: { create: (ref, input = {}, call) => run("POST", call, (c) => raw.createPortalSession(ref, input, c)) },
496
- subscriptions: { cancel: (id, input, call) => run("POST", call, (c) => raw.cancelSubscription(id, input, c)) },
497
- grants: {
498
- create: (ref, input, call) => run("POST", call, (c) => raw.createGrant(ref, input, c)),
499
- revoke: async (id, call) => {
500
- await run("DELETE", call, (c) => raw.revokeGrant(id, c));
501
- }
502
- },
503
- invoices: {
504
- issue: (id, input, call) => run("POST", call, (c) => raw.issueInvoice(id, input, c)),
505
- document: (id) => read(() => raw.getInvoiceDocument(id)),
506
- createManual: (ref, input, call) => run("POST", call, (c) => raw.createManualInvoice(ref, input, c)),
507
- void: (id, input, call) => run("POST", call, (c) => raw.voidInvoice(id, input, c))
508
- },
509
- catalog: {
510
- get: () => read(() => raw.getCatalog()),
511
- read: (opts = {}) => read(() => readCatalog(opts.etag))
512
- },
513
- stats: () => read(() => raw.getStats())
514
- };
515
- return {
516
- ...productTarget !== null ? productApi : rejectAll(productApi, missingProduct),
517
- me: () => read(() => sendParsed(eitherTarget, "GET", "/v1/me", MeSchema, {})),
518
- doctor: () => read(() => eitherClient.doctor()),
519
- admin: {
520
- catalog: { sync: async (input, call) => {
521
- const { client } = requireAdmin();
522
- return run("PUT", call, (c) => client.syncCatalog(input, c));
523
- } },
524
- accounts: { refresh: async (call) => {
525
- const { target } = requireAdmin();
526
- return run("POST", call, (c) => sendParsed(target, "POST", "/v1/admin/accounts/refresh", AccountsRefreshResultSchema, c));
527
- } },
528
- settings: {
529
- get: async () => {
530
- const { client } = requireAdmin();
531
- return read(() => client.getSettings());
532
- },
533
- update: async (patch, call) => {
534
- const { client } = requireAdmin();
535
- return run("PATCH", call, (c) => client.updateSettings(patch, c));
536
- }
537
- },
538
- endpoints: {
539
- list: async () => {
540
- const { client } = requireAdmin();
541
- return read(() => client.listWebhookEndpoints());
542
- },
543
- create: async (input, call) => {
544
- const { client } = requireAdmin();
545
- return run("POST", call, (c) => client.createWebhookEndpoint(input, c));
546
- },
547
- rotate: async (id, input, call) => {
548
- const { client } = requireAdmin();
549
- return run("POST", call, (c) => client.rotateWebhookEndpointSecret(id, input, c));
550
- },
551
- deactivate: async (id, call) => {
552
- const { client } = requireAdmin();
553
- return run("POST", call, (c) => client.deactivateWebhookEndpoint(id, c));
554
- }
555
- }
556
- }
557
- };
558
- }
559
- //#endregion
560
- export { createSteward as t };
@@ -1,27 +0,0 @@
1
- {
2
- "apiVersion": "2026-10-01",
3
- "sha256": "00b36567f8972e90997f6436efcaab7e75e1104301ace40941ba3eaaea908582",
4
- "additions": [
5
- {
6
- "since": "0.2.0",
7
- "files": [
8
- "account.state_changed.json"
9
- ],
10
- "sha256": "af2584923b587bd1d50f8aeceaca4617e76a328d092a0f08cf5b8306fe0bd2d4"
11
- },
12
- {
13
- "since": "F4f",
14
- "files": [
15
- "invoice.voided.json"
16
- ],
17
- "sha256": "26bde921ce073e6f1634612b0b8d122835972647c8feb4608f54e776559cdeaf"
18
- },
19
- {
20
- "since": "F4e",
21
- "files": [
22
- "account.deleted.json"
23
- ],
24
- "sha256": "68c3507812304c790d73ccaffa82389c7fd25c9be85a1ca405722597921c8b32"
25
- }
26
- ]
27
- }
@@ -1,36 +0,0 @@
1
- {
2
- "id": "evt_0192f1a0-0000-7000-8000-000000000030",
3
- "type": "account.deleted",
4
- "apiVersion": "2026-10-01",
5
- "createdAt": "2026-10-05T09:00:00Z",
6
- "product": "example",
7
- "accountRef": "acct_42",
8
- "data": {
9
- "account": {
10
- "ref": "acct_42",
11
- "displayName": "",
12
- "version": 9,
13
- "updatedAt": "2026-10-05T09:00:00Z",
14
- "planCode": "free",
15
- "accessState": "active",
16
- "entitlements": {
17
- "max_users": 3,
18
- "max_devices": 15,
19
- "max_networks_per_account": 1,
20
- "max_approved_routes": 0,
21
- "max_exit_nodes": 0
22
- },
23
- "catalogVersion": "3f2a9c0e7b41d8a65c09e1f4b7d2a8c3",
24
- "subscription": null,
25
- "openCheckout": null,
26
- "profile": {
27
- "present": false,
28
- "kind": null
29
- }
30
- },
31
- "detail": {
32
- "deletedAt": "2026-10-05T09:00:00Z",
33
- "actorRef": "user:7"
34
- }
35
- }
36
- }
@@ -1,53 +0,0 @@
1
- {
2
- "id": "evt_0192f1a0-0000-7000-8000-000000000020",
3
- "type": "account.state_changed",
4
- "apiVersion": "2026-10-01",
5
- "createdAt": "2026-10-01T09:00:00Z",
6
- "product": "example",
7
- "accountRef": "acct_42",
8
- "data": {
9
- "account": {
10
- "ref": "acct_42",
11
- "displayName": "Örnek A.Ş.",
12
- "version": 2,
13
- "updatedAt": "2026-10-01T09:00:00Z",
14
- "planCode": "team",
15
- "accessState": "active",
16
- "entitlements": {
17
- "max_users": null,
18
- "max_devices": 250,
19
- "max_networks_per_account": 3,
20
- "max_approved_routes": 10,
21
- "max_exit_nodes": 1
22
- },
23
- "catalogVersion": "3f2a9c0e7b41d8a65c09e1f4b7d2a8c3",
24
- "subscription": {
25
- "id": "0192f1a0-0000-7000-8000-000000000001",
26
- "status": "past_due",
27
- "planCode": "team",
28
- "interval": "month",
29
- "amountMinor": 125000,
30
- "currency": "TRY",
31
- "currentPeriodEnd": "2026-10-01T09:00:00Z",
32
- "cancelAt": null,
33
- "cancelAtPeriodEnd": false,
34
- "pastDueSince": "2026-10-01T09:00:00Z",
35
- "currentPeriodStart": "2026-09-01T09:00:00Z",
36
- "dunning": {
37
- "step": 0,
38
- "nextActionAt": "2026-10-02T09:00:00Z"
39
- },
40
- "scheduledChange": null
41
- },
42
- "openCheckout": null,
43
- "profile": {
44
- "present": true,
45
- "kind": "company"
46
- }
47
- },
48
- "detail": {
49
- "cause": "subscription.payment_failed",
50
- "causeEventId": "evt_0192f1a0-0000-7000-8000-000000000016"
51
- }
52
- }
53
- }