@stewardhq/sdk 0.1.0-rc.0 → 0.3.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 +27 -33
- package/dist/_chunks/errors.js +1 -1
- package/dist/_chunks/events.d.ts +15 -1
- package/dist/_chunks/events.js +172 -4
- package/dist/_chunks/index.d.ts +357 -3631
- package/dist/_chunks/src.js +85 -157
- package/dist/_chunks/steward.d.ts +5 -2404
- package/dist/_chunks/steward.js +12 -26
- package/dist/contract.d.ts +3 -3
- package/dist/contract.js +3 -3
- package/dist/index.d.ts +4 -66
- package/dist/index.js +4 -267
- package/dist/server.d.ts +6 -6
- package/dist/server.js +13 -2
- package/dist/testing.d.ts +60 -33
- package/dist/testing.js +70 -145
- package/package.json +4 -5
- package/dist/_chunks/locale.js +0 -17
package/dist/_chunks/src.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { $ as CurrencySchema, C as BillingProfileKindSchema, E as SubscriptionStatusSchema, F as EmailSettingsPatchSchema, I as EmailSettingsSchema, Q as CodeSchema, V as applyEmailSettingsPatch, X as ActorRefSchema, Z as AmountMinorSchema, a as EVENT_TYPES, b as AccountStateSchema, ct as IntervalSchema, et as DateTimeSchema, j as EMAIL_TEMPLATES, o as EventIdSchema, ot as ExternalRefSchema, rt as EntitlementsSchema, st as IdSchema, w as BillingProfileSchema, y as AccountSchema } from "./events.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
//#region ../contract/src/catalog.ts
|
|
4
4
|
const FeatureTypeSchema = z.enum([
|
|
@@ -175,7 +175,9 @@ const ProductSettingsSchema = z.object({
|
|
|
175
175
|
branding: BrandingSchema.default({}),
|
|
176
176
|
/** Açık checkout oturumunun ömrü (sağlayıcının form ömrü daha kısaysa o geçerli). */
|
|
177
177
|
checkoutTtlMinutes: TtlMinutesSchema.default(30),
|
|
178
|
-
portalTtlMinutes: TtlMinutesSchema.default(30)
|
|
178
|
+
portalTtlMinutes: TtlMinutesSchema.default(30),
|
|
179
|
+
/** Billing emails sent by steward (`emails.ts`). */
|
|
180
|
+
emails: EmailSettingsSchema.default({ templates: {} })
|
|
179
181
|
});
|
|
180
182
|
const BrandingPatchSchema = z.object({
|
|
181
183
|
name: BrandingNameSchema.nullable().optional(),
|
|
@@ -193,7 +195,8 @@ const ProductSettingsPatchSchema = z.object({
|
|
|
193
195
|
termsUrl: WebUrlSchema.nullable().optional(),
|
|
194
196
|
branding: BrandingPatchSchema.nullable().optional(),
|
|
195
197
|
checkoutTtlMinutes: TtlMinutesSchema.optional(),
|
|
196
|
-
portalTtlMinutes: TtlMinutesSchema.optional()
|
|
198
|
+
portalTtlMinutes: TtlMinutesSchema.optional(),
|
|
199
|
+
emails: EmailSettingsPatchSchema.nullable().optional()
|
|
197
200
|
}).strict();
|
|
198
201
|
/**
|
|
199
202
|
* Doğrulanmış yamayı ayarlara uygular (saf). Sonuç şemadan geçer; alan kuralları
|
|
@@ -210,7 +213,8 @@ function applySettingsPatch(current, patch) {
|
|
|
210
213
|
else if (fieldValue !== void 0) branding[field] = fieldValue;
|
|
211
214
|
}
|
|
212
215
|
next.branding = branding;
|
|
213
|
-
} else if (
|
|
216
|
+
} else if (key === "emails") next.emails = applyEmailSettingsPatch(current.emails, value);
|
|
217
|
+
else if (value === null) delete next[key];
|
|
214
218
|
else next[key] = value;
|
|
215
219
|
}
|
|
216
220
|
return ProductSettingsSchema.parse(next);
|
|
@@ -228,117 +232,52 @@ function isReturnUrlAllowed(settings, returnUrl) {
|
|
|
228
232
|
//#endregion
|
|
229
233
|
//#region ../contract/src/checkout.ts
|
|
230
234
|
const ReturnUrlSchema = z.url({ protocol: /^https?$/ });
|
|
231
|
-
/**
|
|
235
|
+
/** Accepted document — content lives in the product, steward keeps only the trace. */
|
|
232
236
|
const ConsentSchema = z.object({
|
|
233
237
|
document: z.string().min(1).max(100),
|
|
234
238
|
version: z.string().min(1).max(100),
|
|
235
239
|
acceptedAt: DateTimeSchema,
|
|
236
|
-
/**
|
|
240
|
+
/** Document link. */
|
|
237
241
|
url: z.string().optional()
|
|
238
242
|
});
|
|
239
|
-
/**
|
|
243
|
+
/** Document the hosted page asks the customer to accept (the page records acceptance). */
|
|
240
244
|
const CheckoutConsentInputSchema = z.object({
|
|
241
245
|
document: z.string().min(1).max(100),
|
|
242
246
|
version: z.string().min(1).max(100),
|
|
243
|
-
|
|
244
|
-
url: z.url({ protocol: /^https?$/ }).max(2e3).optional(),
|
|
245
|
-
/** Yalnızca eski gövdede (ve orada zorunlu): ürün onayı kendisi aldı. */
|
|
246
|
-
acceptedAt: DateTimeSchema.optional()
|
|
247
|
+
url: z.url({ protocol: /^https?$/ }).max(2e3)
|
|
247
248
|
});
|
|
248
|
-
/** Hosted
|
|
249
|
+
/** Hosted page prefill (not profile/identity data; K21). */
|
|
249
250
|
const CheckoutPrefillSchema = z.object({
|
|
250
251
|
email: z.email().max(200).optional(),
|
|
251
252
|
name: z.string().trim().min(1).max(200).optional(),
|
|
252
253
|
kind: BillingProfileKindSchema.optional()
|
|
253
254
|
});
|
|
254
|
-
/**
|
|
255
|
+
/** Maximum number of documents the hosted page can ask the customer to accept. */
|
|
255
256
|
const MAX_CHECKOUT_CONSENT_DOCS = 20;
|
|
256
257
|
const CheckoutSessionCreateInputSchema = z.object({
|
|
257
258
|
planCode: CodeSchema,
|
|
258
259
|
interval: IntervalSchema,
|
|
259
|
-
/**
|
|
260
|
+
/** Defaults to the product setting `defaultCurrency`. */
|
|
260
261
|
currency: CurrencySchema.optional(),
|
|
261
|
-
/**
|
|
262
|
-
locale: z.
|
|
262
|
+
/** `tr` | `en`; defaults to the product setting `defaultLocale`. */
|
|
263
|
+
locale: z.enum(SETTINGS_LOCALES).optional(),
|
|
263
264
|
/**
|
|
264
|
-
*
|
|
265
|
-
* `{
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
*
|
|
265
|
+
* The outcome returns here. Placeholders (`{CHECKOUT_ID}`, `{STATUS}`, `{ACCOUNT_REF}`,
|
|
266
|
+
* `{LOCALE}`) are filled if present; query parameters are never appended. `STATUS` is
|
|
267
|
+
* success | failed | pending (pending: provider unreachable, the session stays open and the
|
|
268
|
+
* product shows "processing"). The origin must be allowed by product settings
|
|
269
|
+
* (`appUrl` + `extraReturnOrigins`).
|
|
269
270
|
*/
|
|
270
|
-
successUrl: ReturnUrlSchema
|
|
271
|
-
/** `
|
|
272
|
-
returnUrl: ReturnUrlSchema.optional(),
|
|
273
|
-
/** Yalnızca hosted: sayfadaki "Vazgeç" hedefi (yoksa ürün ayarı `appUrl`). Origin kuralı `successUrl`le aynı. */
|
|
271
|
+
successUrl: ReturnUrlSchema,
|
|
272
|
+
/** "Cancel" target on the page (defaults to product setting `appUrl`). Same origin rule as `successUrl`. */
|
|
274
273
|
cancelUrl: ReturnUrlSchema.optional(),
|
|
275
|
-
/**
|
|
274
|
+
/** Opens the account with this name if it does not exist; never renames an existing account. */
|
|
276
275
|
displayName: z.string().min(1).max(200).optional(),
|
|
277
|
-
/** Yalnızca hosted. */
|
|
278
276
|
prefill: CheckoutPrefillSchema.optional(),
|
|
279
|
-
consents: z.array(CheckoutConsentInputSchema).optional()
|
|
280
|
-
/** Yalnızca eski gövde. */
|
|
281
|
-
profile: BillingProfileSchema.optional(),
|
|
282
|
-
/**
|
|
283
|
-
* Yalnızca eski gövde: sağlayıcının istediği kimlik numarası (ör. TCKN/VKN).
|
|
284
|
-
* Yalnızca sağlayıcıya iletilir; servis bunu SAKLAMAZ ve LOGLAMAZ.
|
|
285
|
-
*/
|
|
286
|
-
identityNumber: z.string().regex(/^\d{10,11}$/).optional()
|
|
277
|
+
consents: z.array(CheckoutConsentInputSchema).max(20).optional()
|
|
287
278
|
}).superRefine((body, ctx) => {
|
|
288
|
-
const issue = (path, message) => ctx.addIssue({
|
|
289
|
-
code: "custom",
|
|
290
|
-
path: [path],
|
|
291
|
-
message
|
|
292
|
-
});
|
|
293
|
-
if (body.successUrl !== void 0 && body.returnUrl !== void 0) issue("returnUrl", "successUrl ve returnUrl (eski ad) birlikte verilemez");
|
|
294
|
-
if (body.successUrl === void 0 && body.returnUrl === void 0) issue("successUrl", "zorunlu");
|
|
295
|
-
const hasProfile = body.profile !== void 0;
|
|
296
|
-
if (hasProfile !== (body.identityNumber !== void 0)) {
|
|
297
|
-
issue(hasProfile ? "identityNumber" : "profile", "eski gövde profile ve identityNumber'ı birlikte taşır; hosted checkout ikisini de taşımaz");
|
|
298
|
-
return;
|
|
299
|
-
}
|
|
300
|
-
if (hasProfile) {
|
|
301
|
-
if (body.currency === void 0) issue("currency", "eski gövdede zorunlu");
|
|
302
|
-
if (body.locale === void 0) issue("locale", "eski gövdede zorunlu");
|
|
303
|
-
if (body.consents === void 0) issue("consents", "eski gövdede zorunlu");
|
|
304
|
-
body.consents?.forEach((consent, i) => {
|
|
305
|
-
if (consent.acceptedAt === void 0) ctx.addIssue({
|
|
306
|
-
code: "custom",
|
|
307
|
-
path: [
|
|
308
|
-
"consents",
|
|
309
|
-
i,
|
|
310
|
-
"acceptedAt"
|
|
311
|
-
],
|
|
312
|
-
message: "eski gövdede zorunlu"
|
|
313
|
-
});
|
|
314
|
-
});
|
|
315
|
-
if (body.cancelUrl !== void 0) issue("cancelUrl", "yalnızca hosted checkout");
|
|
316
|
-
if (body.prefill !== void 0) issue("prefill", "yalnızca hosted checkout");
|
|
317
|
-
return;
|
|
318
|
-
}
|
|
319
|
-
if (body.locale !== void 0 && !SETTINGS_LOCALES.includes(body.locale)) issue("locale", `hosted checkout: ${SETTINGS_LOCALES.join(" | ")}`);
|
|
320
|
-
const consents = body.consents ?? [];
|
|
321
|
-
if (consents.length > 20) issue("consents", `en çok 20 belge`);
|
|
322
279
|
const seen = /* @__PURE__ */ new Set();
|
|
323
|
-
consents
|
|
324
|
-
if (consent.url === void 0) ctx.addIssue({
|
|
325
|
-
code: "custom",
|
|
326
|
-
path: [
|
|
327
|
-
"consents",
|
|
328
|
-
i,
|
|
329
|
-
"url"
|
|
330
|
-
],
|
|
331
|
-
message: "hosted checkout'ta zorunlu"
|
|
332
|
-
});
|
|
333
|
-
if (consent.acceptedAt !== void 0) ctx.addIssue({
|
|
334
|
-
code: "custom",
|
|
335
|
-
path: [
|
|
336
|
-
"consents",
|
|
337
|
-
i,
|
|
338
|
-
"acceptedAt"
|
|
339
|
-
],
|
|
340
|
-
message: "hosted checkout'ta onayı sayfa kaydeder"
|
|
341
|
-
});
|
|
280
|
+
body.consents?.forEach((consent, i) => {
|
|
342
281
|
if (seen.has(consent.document)) ctx.addIssue({
|
|
343
282
|
code: "custom",
|
|
344
283
|
path: [
|
|
@@ -346,18 +285,11 @@ const CheckoutSessionCreateInputSchema = z.object({
|
|
|
346
285
|
i,
|
|
347
286
|
"document"
|
|
348
287
|
],
|
|
349
|
-
message: "
|
|
288
|
+
message: "duplicate document"
|
|
350
289
|
});
|
|
351
290
|
seen.add(consent.document);
|
|
352
291
|
});
|
|
353
|
-
})
|
|
354
|
-
...rest,
|
|
355
|
-
successUrl: successUrl ?? returnUrl
|
|
356
|
-
}));
|
|
357
|
-
/** Doğrulanmış gövde eski akışı mı istiyor (K16). Hosted: false. */
|
|
358
|
-
function isLegacyCheckoutInput(input) {
|
|
359
|
-
return input.profile !== void 0 && input.identityNumber !== void 0;
|
|
360
|
-
}
|
|
292
|
+
});
|
|
361
293
|
/**
|
|
362
294
|
* `canceled` (F2b): müşteri hosted sayfada vazgeçti. Eski (0.2.0 öncesi hosted'sız)
|
|
363
295
|
* istemci bu değeri tanımaz; yalnızca hosted akışı kullanan ürün görür.
|
|
@@ -369,6 +301,7 @@ const CheckoutStatusSchema = z.enum([
|
|
|
369
301
|
"expired",
|
|
370
302
|
"canceled"
|
|
371
303
|
]);
|
|
304
|
+
/** Provider form shown on steward's hosted checkout page (never returned to the product). */
|
|
372
305
|
const ProviderPayloadSchema = z.discriminatedUnion("type", [z.object({
|
|
373
306
|
type: z.literal("html_snippet"),
|
|
374
307
|
html: z.string()
|
|
@@ -386,12 +319,10 @@ const CheckoutSessionSchema = z.object({
|
|
|
386
319
|
currency: CurrencySchema,
|
|
387
320
|
provider: z.string(),
|
|
388
321
|
locale: z.string(),
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
/**
|
|
393
|
-
cancelUrl: z.string().nullable().optional(),
|
|
394
|
-
/** Kabul edilen belgeler (hosted: sayfada onaylandıktan sonra dolar). */
|
|
322
|
+
successUrl: z.string(),
|
|
323
|
+
/** "Cancel" target (null if not given; the page falls back to product setting `appUrl`). */
|
|
324
|
+
cancelUrl: z.string().nullable(),
|
|
325
|
+
/** Accepted documents (filled once accepted on the page). */
|
|
395
326
|
consents: z.array(ConsentSchema),
|
|
396
327
|
actorRef: ActorRefSchema.nullable(),
|
|
397
328
|
failureReason: z.string().nullable(),
|
|
@@ -401,15 +332,12 @@ const CheckoutSessionSchema = z.object({
|
|
|
401
332
|
completedAt: DateTimeSchema.nullable()
|
|
402
333
|
});
|
|
403
334
|
/**
|
|
404
|
-
* `POST /v1/accounts/{ref}/checkout-sessions`
|
|
405
|
-
*
|
|
406
|
-
*
|
|
407
|
-
* - eski gövde: `url: null`, `providerPayload` sağlayıcı formu.
|
|
408
|
-
* `url` F2b öncesi steward'da yoktur (null okunur).
|
|
335
|
+
* `POST /v1/accounts/{ref}/checkout-sessions` response: `url` is steward's checkout page
|
|
336
|
+
* (`…/public/v1/checkout/{id}?k=<key>`; the key appears only here), `account` is the state
|
|
337
|
+
* after the call.
|
|
409
338
|
*/
|
|
410
339
|
const CheckoutSessionCreatedSchema = CheckoutSessionSchema.extend({
|
|
411
|
-
url: z.string()
|
|
412
|
-
providerPayload: ProviderPayloadSchema.optional(),
|
|
340
|
+
url: z.string(),
|
|
413
341
|
account: AccountStateSchema.optional()
|
|
414
342
|
});
|
|
415
343
|
const RETURN_PLACEHOLDER_RE = /\{(CHECKOUT_ID|STATUS|ACCOUNT_REF|LOCALE)\}/g;
|
|
@@ -421,28 +349,22 @@ function originOf(value) {
|
|
|
421
349
|
}
|
|
422
350
|
}
|
|
423
351
|
/**
|
|
424
|
-
*
|
|
425
|
-
*
|
|
426
|
-
*
|
|
427
|
-
*
|
|
428
|
-
*
|
|
352
|
+
* Browser redirect for a checkout outcome — the service and the fake steward share it.
|
|
353
|
+
* Placeholders in `successUrl` (`{CHECKOUT_ID}` `{STATUS}` `{ACCOUNT_REF}` `{LOCALE}`) are
|
|
354
|
+
* filled with URL-encoded values; nothing is appended, so a URL without placeholders is used
|
|
355
|
+
* as-is. An encoded value cannot change the origin; it is still checked, and if the origin
|
|
356
|
+
* would change the URL is returned unfilled.
|
|
429
357
|
*/
|
|
430
358
|
function checkoutRedirectUrl(target, status) {
|
|
431
359
|
const template = target.successUrl;
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
if (originOf(filled) !== null && originOf(filled) === originOf(template)) return filled;
|
|
441
|
-
}
|
|
442
|
-
const url = new URL(template ?? target.returnUrl);
|
|
443
|
-
url.searchParams.set("session", target.id);
|
|
444
|
-
url.searchParams.set("status", status);
|
|
445
|
-
return url.toString();
|
|
360
|
+
const values = {
|
|
361
|
+
CHECKOUT_ID: target.id,
|
|
362
|
+
STATUS: status,
|
|
363
|
+
ACCOUNT_REF: target.accountRef,
|
|
364
|
+
LOCALE: target.locale
|
|
365
|
+
};
|
|
366
|
+
const filled = template.replace(RETURN_PLACEHOLDER_RE, (_, name) => encodeURIComponent(values[name]));
|
|
367
|
+
return originOf(filled) !== null && originOf(filled) === originOf(template) ? filled : template;
|
|
446
368
|
}
|
|
447
369
|
const CHECKOUT_ERRORS = [
|
|
448
370
|
"account_not_found",
|
|
@@ -708,8 +630,6 @@ const AccountDetailSchema = AccountSchema.extend({
|
|
|
708
630
|
const withAccount = { account: AccountStateSchema.optional() };
|
|
709
631
|
/** `PUT /v1/accounts/{ref}` (201 ya da 200). */
|
|
710
632
|
const AccountUpsertResponseSchema = AccountSchema.extend(withAccount);
|
|
711
|
-
/** `PUT /v1/accounts/{ref}/billing-profile` */
|
|
712
|
-
const BillingProfileResponseSchema = BillingProfileSchema.extend(withAccount);
|
|
713
633
|
/** `POST /v1/accounts/{ref}/grants` */
|
|
714
634
|
const GrantCreateResponseSchema = GrantSchema.extend(withAccount);
|
|
715
635
|
/** `POST /v1/subscriptions/{id}/cancel` */
|
|
@@ -722,27 +642,6 @@ const ManualInvoiceResponseSchema = InvoiceSchema.extend(withAccount);
|
|
|
722
642
|
const InvoiceVoidResponseSchema = InvoiceSchema.extend(withAccount);
|
|
723
643
|
/** `GET /v1/checkout-sessions/{id}` — `account` yalnızca oturum `completed` ise. */
|
|
724
644
|
const CheckoutSessionResponseSchema = CheckoutSessionSchema.extend(withAccount);
|
|
725
|
-
const DeliverySchema = z.object({
|
|
726
|
-
endpointId: IdSchema,
|
|
727
|
-
status: z.enum([
|
|
728
|
-
"pending",
|
|
729
|
-
"delivered",
|
|
730
|
-
"dead"
|
|
731
|
-
]),
|
|
732
|
-
attempts: z.number().int().nonnegative(),
|
|
733
|
-
lastHttpStatus: z.number().int().nullable(),
|
|
734
|
-
lastError: z.string().nullable(),
|
|
735
|
-
nextAttemptAt: DateTimeSchema.nullable(),
|
|
736
|
-
deliveredAt: DateTimeSchema.nullable()
|
|
737
|
-
});
|
|
738
|
-
const EventRecordSchema = z.object({
|
|
739
|
-
event: BillingEventSchema,
|
|
740
|
-
deliveries: z.array(DeliverySchema)
|
|
741
|
-
});
|
|
742
|
-
const EventListSchema = z.object({
|
|
743
|
-
items: z.array(EventRecordSchema),
|
|
744
|
-
nextCursor: z.string().nullable()
|
|
745
|
-
});
|
|
746
645
|
/** Değişiklik yapan her istekte zorunlu başlıklar. */
|
|
747
646
|
const HEADER_IDEMPOTENCY_KEY = "idempotency-key";
|
|
748
647
|
const HEADER_ACTOR_REF = "x-actor-ref";
|
|
@@ -761,8 +660,6 @@ const ERROR_CODES = Object.freeze({
|
|
|
761
660
|
invalid_request: spec(400, "validation"),
|
|
762
661
|
invalid_account_ref: spec(400, "validation"),
|
|
763
662
|
invalid_include: spec(400, "validation"),
|
|
764
|
-
invalid_cursor: spec(400, "validation"),
|
|
765
|
-
invalid_limit: spec(400, "validation"),
|
|
766
663
|
invalid_actor_ref: spec(400, "validation"),
|
|
767
664
|
actor_ref_required: spec(400, "validation"),
|
|
768
665
|
idempotency_key_required: spec(400, "validation"),
|
|
@@ -782,7 +679,6 @@ const ERROR_CODES = Object.freeze({
|
|
|
782
679
|
grant_not_found: spec(404, "not_found"),
|
|
783
680
|
invoice_not_found: spec(404, "not_found"),
|
|
784
681
|
document_not_found: spec(404, "not_found"),
|
|
785
|
-
event_not_found: spec(404, "not_found"),
|
|
786
682
|
checkout_session_not_found: spec(404, "not_found"),
|
|
787
683
|
/** Yönetim ucu: endpoint yok ya da başka ürünün. */
|
|
788
684
|
webhook_endpoint_not_found: spec(404, "not_found"),
|
|
@@ -808,7 +704,7 @@ const ERROR_CODES = Object.freeze({
|
|
|
808
704
|
subscription_active: spec(409, "conflict"),
|
|
809
705
|
/** `DELETE /v1/accounts/:ref`: sağlayıcı formu açık checkout oturumu var; süresi dolup kapanınca tekrar dene. */
|
|
810
706
|
checkout_in_progress: spec(409, "conflict", true),
|
|
811
|
-
/** `returnUrl`
|
|
707
|
+
/** `successUrl`, `cancelUrl` or portal `returnUrl` is not in the product's allowed origins: product misconfiguration. */
|
|
812
708
|
return_url_not_allowed: spec(422, "config"),
|
|
813
709
|
/** Bu deployment'ta sağlayıcı yapılandırılmamış (503 ama beklemekle düzelmez). */
|
|
814
710
|
provider_not_configured: spec(503, "config"),
|
|
@@ -1075,6 +971,17 @@ const DoctorEndpointSchema = z.object({
|
|
|
1075
971
|
lastDelivery: WebhookLastDeliverySchema.nullable(),
|
|
1076
972
|
diagnosis: z.string()
|
|
1077
973
|
});
|
|
974
|
+
/** Billing emails (issue #15). */
|
|
975
|
+
const DoctorEmailsSchema = z.object({
|
|
976
|
+
/** The deployment has a mail transport (`STEWARD_SMTP_URL`). */
|
|
977
|
+
transportConfigured: z.boolean(),
|
|
978
|
+
/** A sender address is known (`settings.emails.from.address` or the deployment default). */
|
|
979
|
+
senderConfigured: z.boolean(),
|
|
980
|
+
/** Templates the product turned off. */
|
|
981
|
+
disabledTemplates: z.array(z.string()),
|
|
982
|
+
/** Emails are sent: transport and sender configured, at least one template on. */
|
|
983
|
+
ready: z.boolean()
|
|
984
|
+
});
|
|
1078
985
|
const DoctorReportSchema = z.object({
|
|
1079
986
|
/** `error` önemde uyarı yok. */
|
|
1080
987
|
ok: z.boolean(),
|
|
@@ -1092,8 +999,22 @@ const DoctorReportSchema = z.object({
|
|
|
1092
999
|
dunning: z.object({
|
|
1093
1000
|
/** true: dunning adımları yalnızca iz yazar (askı/sonlandırma yok). */
|
|
1094
1001
|
dryRun: z.boolean() }),
|
|
1002
|
+
/** Absent in reports of steward versions without billing emails. */
|
|
1003
|
+
emails: DoctorEmailsSchema.optional(),
|
|
1095
1004
|
warnings: z.array(DoctorWarningSchema)
|
|
1096
1005
|
});
|
|
1006
|
+
/** Email readiness from settings and the deployment's transport (pure). */
|
|
1007
|
+
function emailReadinessOf(settings, transport) {
|
|
1008
|
+
const templates = settings.emails?.templates ?? {};
|
|
1009
|
+
const disabledTemplates = EMAIL_TEMPLATES.filter((t) => templates[t]?.enabled === false);
|
|
1010
|
+
const senderConfigured = settings.emails?.from?.address !== void 0 || transport.defaultFromConfigured;
|
|
1011
|
+
return {
|
|
1012
|
+
transportConfigured: transport.configured,
|
|
1013
|
+
senderConfigured,
|
|
1014
|
+
disabledTemplates: [...disabledTemplates],
|
|
1015
|
+
ready: transport.configured && senderConfigured && disabledTemplates.length < EMAIL_TEMPLATES.length
|
|
1016
|
+
};
|
|
1017
|
+
}
|
|
1097
1018
|
/** Bekleyen en eski teslimat bundan eskiyse `endpoint_pending_backlog` (K23 alarmıyla aynı eşik). */
|
|
1098
1019
|
const DOCTOR_PENDING_BACKLOG_MS = 36e5;
|
|
1099
1020
|
/** Son denenmiş teslimattan endpoint teşhisi (saf). */
|
|
@@ -1181,6 +1102,12 @@ function buildDoctorReport(facts) {
|
|
|
1181
1102
|
if (endpoint.dead > 0) warn("warning", "endpoint_dead_deliveries", `${endpoint.dead} teslimattan vazgeçildi (dead): etkilenen hesaplar için resync`, endpoint.id);
|
|
1182
1103
|
if (endpoint.oldestPendingAt !== null && facts.checkedAt.getTime() - Date.parse(endpoint.oldestPendingAt) > 36e5) warn("warning", "endpoint_pending_backlog", `${endpoint.pending} teslimat bekliyor; en eskisi bir saatten eski`, endpoint.id);
|
|
1183
1104
|
}
|
|
1105
|
+
const emails = facts.emailTransport ? emailReadinessOf(settings, facts.emailTransport) : void 0;
|
|
1106
|
+
if (emails && emails.disabledTemplates.length < EMAIL_TEMPLATES.length) {
|
|
1107
|
+
if (!emails.transportConfigured) warn("warning", "email_not_configured", "email is not configured: steward sends no billing emails (STEWARD_SMTP_URL)");
|
|
1108
|
+
else if (!emails.senderConfigured) warn("warning", "email_sender_missing", "no email sender: set `settings.emails.from.address` or STEWARD_EMAIL_FROM");
|
|
1109
|
+
if (settings.emails?.billingPath === void 0) warn("info", "email_billing_link_missing", "`settings.emails.billingPath` is not set: email buttons open `appUrl`");
|
|
1110
|
+
}
|
|
1184
1111
|
if (dunning.dryRun) warn("info", "dunning_dry_run", "dunning dry-run: adımlar yalnızca iz yazar, askı ve sonlandırma uygulanmaz");
|
|
1185
1112
|
return {
|
|
1186
1113
|
ok: !warnings.some((w) => w.severity === "error"),
|
|
@@ -1195,8 +1122,9 @@ function buildDoctorReport(facts) {
|
|
|
1195
1122
|
hosted,
|
|
1196
1123
|
endpoints,
|
|
1197
1124
|
dunning,
|
|
1125
|
+
...emails ? { emails } : {},
|
|
1198
1126
|
warnings
|
|
1199
1127
|
};
|
|
1200
1128
|
}
|
|
1201
1129
|
//#endregion
|
|
1202
|
-
export {
|
|
1130
|
+
export { InvoiceVoidResponseSchema as $, PriceSchema as $t, WebhookSecretSchema as A, checkoutRedirectUrl as At, errorCodeSpec as B, TtlMinutesSchema as Bt, WEBHOOK_SECRET_PREFIX as C, CheckoutSessionCreateInputSchema as Ct, WebhookEndpointSchema as D, ConsentSchema as Dt, WebhookEndpointRotateInputSchema as E, CheckoutStatusSchema as Et, PlanSetModeSchema as F, ProductSettingsPatchSchema as Ft, CheckoutSessionResponseSchema as G, AccountsRefreshResultSchema as Gt, AccountDetailSchema as H, applySettingsPatch as Ht, PlanSetResponseSchema as I, ProductSettingsSchema as It, HEADER_API_VERSION as J, CatalogSyncResultSchema as Jt, GrantCreateResponseSchema as K, CatalogSchema as Kt, PlanSetWarningSchema as L, ReturnOriginSchema as Lt, webhookEndpointUrlProblem as M, BrandingSchema as Mt, PLAN_SET_MODES as N, DEFAULT_CHECKOUT_TTL_MINUTES as Nt, WebhookEndpointStatusSchema as O, MAX_CHECKOUT_CONSENT_DOCS as Ot, PlanSetInputSchema as P, DEFAULT_PORTAL_TTL_MINUTES as Pt, InvoiceIssueResponseSchema as Q, PriceDefSchema as Qt, ResyncResultSchema as R, SETTINGS_LOCALES as Rt, WEBHOOK_ENDPOINT_STATUSES as S, CheckoutPrefillSchema as St, WebhookEndpointListSchema as T, CheckoutSessionSchema as Tt, AccountUpsertResponseSchema as U, isReturnUrlAllowed as Ut, isKnownErrorCode as V, WebUrlSchema as Vt, CancelSubscriptionResponseSchema as W, returnOriginsOf as Wt, HEADER_REQUEST_ID as X, FeatureTypeSchema as Xt, HEADER_IDEMPOTENCY_KEY as Y, FeatureDefSchema as Yt, HEADER_SDK as Z, PlanDefSchema as Zt, emailReadinessOf as _, PORTAL_SESSION_ERRORS as _t, DOCTOR_SEVERITIES as a, InvoiceVoidInputSchema as at, DEFAULT_ENDPOINT_EVENT_TYPES as b, CHECKOUT_ERRORS as bt, DoctorEndpointSchema as c, ManualInvoiceLineInputSchema as ct, DoctorReportSchema as d, CancelSubscriptionInputSchema as dt, ManualInvoiceResponseSchema as et, DoctorSettingsSchema as f, GrantCreateInputSchema as ft, buildDoctorReport as g, SubscriptionSchema as gt, DoctorWarningSchema as h, StatsSchema as ht, DOCTOR_REQUIRED_LEGAL_LINKS as i, InvoiceStatusSchema as it, generateWebhookSecret as j, BrandingPatchSchema as jt, WebhookLastDeliverySchema as k, ProviderPayloadSchema as kt, DoctorHostedSchema as l, manualInvoiceTotals as lt, DoctorUnsellablePriceSchema as m, PaymentSchema as mt, DOCTOR_PROVIDER_ENVIRONMENTS as n, InvoiceLineSchema as nt, DoctorCatalogSchema as o, MANUAL_INVOICE_MAX_AMOUNT_MINOR as ot, DoctorSeveritySchema as p, GrantSchema as pt, HEADER_ACTOR_REF as q, CatalogSyncInputSchema as qt, DOCTOR_REQUIRED_BRANDING as r, InvoiceSchema as rt, DoctorEmailsSchema as s, ManualInvoiceInputSchema as st, DOCTOR_PENDING_BACKLOG_MS as t, InvoiceIssueInputSchema as tt, DoctorProviderSchema as u, splitInclusiveTax as ut, endpointDiagnosisOf as v, PortalSessionCreateInputSchema as vt, WebhookEndpointCreateInputSchema as w, CheckoutSessionCreatedSchema as wt, EventTypeSchema as x, CheckoutConsentInputSchema as xt, hostedReadinessOf as y, PortalSessionSchema as yt, ERROR_CODES as z, SettingsLocaleSchema as zt };
|