@delopay/sdk 0.163.0 → 0.165.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/dist/internal.cjs CHANGED
@@ -71,6 +71,7 @@ __export(internal_exports, {
71
71
  DEFAULT_BADGES_DARK: () => DEFAULT_BADGES_DARK,
72
72
  DEFAULT_BRANDING: () => DEFAULT_BRANDING,
73
73
  DEFAULT_BRANDING_DARK: () => DEFAULT_BRANDING_DARK,
74
+ DEFAULT_NOTICES: () => DEFAULT_NOTICES,
74
75
  Delopay: () => Delopay,
75
76
  DelopayAuthenticationError: () => DelopayAuthenticationError,
76
77
  DelopayError: () => DelopayError,
@@ -95,6 +96,12 @@ __export(internal_exports, {
95
96
  NATIVE_PANE_CATEGORY_KEYS: () => NATIVE_PANE_CATEGORY_KEYS,
96
97
  NATIVE_PANE_ICON_KEYS: () => NATIVE_PANE_ICON_KEYS,
97
98
  NOMUPAY_FORM_STYLES: () => NOMUPAY_FORM_STYLES,
99
+ NOTICES_PER_SECTION: () => NOTICES_PER_SECTION,
100
+ NOTICE_ICONS: () => NOTICE_ICONS,
101
+ NOTICE_ICON_FALLBACK: () => NOTICE_ICON_FALLBACK,
102
+ NOTICE_ICON_PATHS: () => NOTICE_ICON_PATHS,
103
+ NOTICE_LABEL_MAX_LENGTH: () => NOTICE_LABEL_MAX_LENGTH,
104
+ NOTICE_SECTIONS: () => NOTICE_SECTIONS,
98
105
  OperationLimits: () => OperationLimits,
99
106
  PANES_MAX: () => PANES_MAX,
100
107
  PANE_CATEGORY_KEYS: () => PANE_CATEGORY_KEYS,
@@ -154,6 +161,7 @@ __export(internal_exports, {
154
161
  cloneBranding: () => cloneBranding,
155
162
  cloneCustomField: () => cloneCustomField,
156
163
  cloneNativePane: () => cloneNativePane,
164
+ cloneNotice: () => cloneNotice,
157
165
  clonePane: () => clonePane,
158
166
  compareSections: () => compareSections,
159
167
  contrastRatio: () => contrastRatio,
@@ -169,11 +177,13 @@ __export(internal_exports, {
169
177
  decodeMethodSectionLabels: () => decodeMethodSectionLabels,
170
178
  decodeMethodSectionOrder: () => decodeMethodSectionOrder,
171
179
  decodeNativePanes: () => decodeNativePanes,
180
+ decodeNotices: () => decodeNotices,
172
181
  decodePanes: () => decodePanes,
173
182
  defaultBranding: () => defaultBranding,
174
183
  defaultCustomFieldVisibility: () => defaultCustomFieldVisibility,
175
184
  defaultMethodSectionOrder: () => defaultMethodSectionOrder,
176
185
  defaultNativePane: () => defaultNativePane,
186
+ defaultNotices: () => defaultNotices,
177
187
  defaultOperatorForSource: () => defaultOperatorForSource,
178
188
  defaultPane: () => defaultPane,
179
189
  emptyPaneCatalog: () => emptyPaneCatalog,
@@ -183,6 +193,7 @@ __export(internal_exports, {
183
193
  encodeMethodSectionLabels: () => encodeMethodSectionLabels,
184
194
  encodeMethodSectionOrder: () => encodeMethodSectionOrder,
185
195
  encodeNativePanes: () => encodeNativePanes,
196
+ encodeNotices: () => encodeNotices,
186
197
  encodePanes: () => encodePanes,
187
198
  evaluateCustomFieldCondition: () => evaluateCustomFieldCondition,
188
199
  evaluateCustomFieldVisibility: () => evaluateCustomFieldVisibility,
@@ -193,13 +204,17 @@ __export(internal_exports, {
193
204
  inputPadValue: () => inputPadValue,
194
205
  isCheckboxChecked: () => isCheckboxChecked,
195
206
  isDarkSurface: () => isDarkSurface,
207
+ isDefaultBadgeSet: () => isDefaultBadgeSet,
196
208
  isHexColor: () => isHexColor,
209
+ isNoticeIcon: () => isNoticeIcon,
197
210
  isSubscriptionDisputeWebhook: () => isSubscriptionDisputeWebhook,
198
211
  isSubscriptionLifecycleWebhook: () => isSubscriptionLifecycleWebhook,
199
212
  knownSectionLabelKey: () => knownSectionLabelKey,
200
213
  leaf: () => leaf,
201
214
  logoDimensions: () => logoDimensions,
202
215
  nativePaneMethodInfo: () => nativePaneMethodInfo,
216
+ noticeText: () => noticeText,
217
+ noticesIn: () => noticesIn,
203
218
  offerablePaneMethods: () => offerablePaneMethods,
204
219
  paneCatalogFor: () => paneCatalogFor,
205
220
  paneDisplayDefaults: () => paneDisplayDefaults,
@@ -208,6 +223,7 @@ __export(internal_exports, {
208
223
  paneViewVisibility: () => paneViewVisibility,
209
224
  parseCustomFieldsLoose: () => parseCustomFieldsLoose,
210
225
  parseImportedBranding: () => parseImportedBranding,
226
+ parseNoticesLoose: () => parseNoticesLoose,
211
227
  programToTree: () => programToTree,
212
228
  radiusValue: () => radiusValue,
213
229
  readableInkOn: () => readableInkOn,
@@ -215,12 +231,14 @@ __export(internal_exports, {
215
231
  resolveAirwallexLabelStyle: () => resolveAirwallexLabelStyle,
216
232
  resolveApplePayButtonStyle: () => resolveApplePayButtonStyle,
217
233
  resolveGooglePayButtonColor: () => resolveGooglePayButtonColor,
234
+ resolveNoticesAndBadges: () => resolveNoticesAndBadges,
218
235
  resolveStripeTheme: () => resolveStripeTheme,
219
236
  ruleMatchToTree: () => ruleMatchToTree,
220
237
  sanitizeCustomCss: () => sanitizeCustomCss,
221
238
  sectionLabel: () => sectionLabel,
222
239
  sectionOrderOf: () => sectionOrderOf,
223
240
  shadowFor: () => shadowFor,
241
+ shownNotices: () => shownNotices,
224
242
  stripeSpacingValues: () => stripeSpacingValues,
225
243
  surchargeFigurePlan: () => surchargeFigurePlan,
226
244
  surchargeShowsLabel: () => surchargeShowsLabel,
@@ -1999,6 +2017,16 @@ var Payments = class {
1999
2017
  * Not the hosted-shop settlement API under `settlement.*`, which is host →
2000
2018
  * shop owner and manual; this is acquirer → merchant bank, per payment.
2001
2019
  *
2020
+ * Each attempt also carries what the rail itself took for it —
2021
+ * `processor_cost_amount` with its own `processor_cost_currency` and
2022
+ * `processor_cost_exponent`, the `processor_cost_source` that says how the
2023
+ * figure was obtained, the `processor_cost_basis` behind an estimate, and
2024
+ * the `connector_method_code` it was priced under. Recorded for **every**
2025
+ * merchant, not only those that host shops. Never present an `estimated`
2026
+ * cost as an observation, and read an absent `processor_cost_source` as
2027
+ * "nothing was ever written", which is not the `unavailable` the rail
2028
+ * answers with.
2029
+ *
2002
2030
  * `GET /payments/{paymentId}/settlement`
2003
2031
  *
2004
2032
  * @param paymentId - The payment intent ID.
@@ -2017,6 +2045,9 @@ var Payments = class {
2017
2045
  * if (attempt.status === 'paid_out') {
2018
2046
  * console.log(attempt.paid_out_at, attempt.payout_reference);
2019
2047
  * }
2048
+ * if (attempt.processor_cost_source === 'estimated') {
2049
+ * // Label it an estimate — it was derived from a cost schedule.
2050
+ * }
2020
2051
  * }
2021
2052
  * ```
2022
2053
  */
@@ -5252,6 +5283,65 @@ var Settlement = class {
5252
5283
  ...options
5253
5284
  });
5254
5285
  }
5286
+ /**
5287
+ * What a period's payments cost at the rails, grouped by shop, connector
5288
+ * and payment method. Answers for **every** merchant, including one that
5289
+ * hosts nobody — it reads the per-attempt settlement record rather than the
5290
+ * settlement lines, which exist only where hosting fees are configured.
5291
+ *
5292
+ * A sibling of {@link Settlement.cost} rather than a widening of it. That
5293
+ * endpoint is a profit statement whose revenue term is hosting income, and
5294
+ * a merchant who hosts nobody has none. This publishes cost and never
5295
+ * margin.
5296
+ *
5297
+ * Send `year` and `month` together to report one UTC calendar month, or
5298
+ * neither for the running month so far.
5299
+ *
5300
+ * **The response carries no period total, and a caller must not compute
5301
+ * one here.** Every figure keeps the unit the rail reported it in, and the
5302
+ * unit is part of each bucket's key, so adding two buckets is not addition.
5303
+ * Convert caller-side if you need one number, and say which rates you used.
5304
+ * The counts are totalled, because a count has no unit.
5305
+ *
5306
+ * Two distinctions not to flatten when rendering a bucket:
5307
+ * `cost_amount` covers `reported_count + estimated_count` attempts out of
5308
+ * `attempt_count` and is a lower bound whenever those disagree; and
5309
+ * `unavailable_count` (the rail says it has no figure) means something
5310
+ * different from `unwritten_count` (a gap in our own recording).
5311
+ *
5312
+ * **Merchant scope.** A token scoped to a single shop, a role narrowed to
5313
+ * specific connector accounts, or a role without the settlement-read
5314
+ * permission group is refused `403`: what a rail charged is the merchant's
5315
+ * own cost base, and here it is the whole response, so there is nothing
5316
+ * coherent to redact down to. Gate the surface on the caller's scope rather
5317
+ * than calling it and handling the failure.
5318
+ *
5319
+ * `GET /settlement/processor-cost`
5320
+ *
5321
+ * @example
5322
+ * ```typescript
5323
+ * const period = await delopay.settlement.processorCost({
5324
+ * test_mode: false,
5325
+ * year: 2026,
5326
+ * month: 7,
5327
+ * });
5328
+ * for (const bucket of period.buckets) {
5329
+ * // Each bucket is its own unit — render per bucket, never a sum.
5330
+ * console.log(bucket.connector, bucket.cost_amount, bucket.cost_currency);
5331
+ * }
5332
+ * ```
5333
+ */
5334
+ async processorCost(params, options) {
5335
+ return this.request("GET", "/settlement/processor-cost", {
5336
+ query: {
5337
+ profile_id: params?.profile_id,
5338
+ test_mode: params?.test_mode,
5339
+ year: params?.year,
5340
+ month: params?.month
5341
+ },
5342
+ ...options
5343
+ });
5344
+ }
5255
5345
  /**
5256
5346
  * List generated settlement statements, newest first.
5257
5347
  *
@@ -6660,6 +6750,66 @@ function surchargeWordFor(branding, isDiscount, locale) {
6660
6750
  locale
6661
6751
  );
6662
6752
  }
6753
+ var NOTICE_SECTIONS = ["summary", "payment"];
6754
+ var NOTICES_PER_SECTION = 3;
6755
+ var NOTICE_LABEL_MAX_LENGTH = 80;
6756
+ var NOTICE_ICONS = [
6757
+ "lock",
6758
+ "shield",
6759
+ "check",
6760
+ "truck",
6761
+ "package",
6762
+ "refresh",
6763
+ "star",
6764
+ "support",
6765
+ "globe",
6766
+ "tag",
6767
+ "heart",
6768
+ "leaf",
6769
+ "clock",
6770
+ "bank"
6771
+ ];
6772
+ var NOTICE_ICON_FALLBACK = "check";
6773
+ var NOTICE_ICON_PATHS = {
6774
+ lock: [
6775
+ "M6 10h12a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2z",
6776
+ "M8 10V7a4 4 0 0 1 8 0v3"
6777
+ ],
6778
+ shield: ["M12 3l7 3v6c0 4.2-2.9 7.6-7 9-4.1-1.4-7-4.8-7-9V6z", "M9 12l2.5 2.5 4-4.5"],
6779
+ check: ["M21 12a9 9 0 1 1-18 0a9 9 0 1 1 18 0z", "M8 12.5l3 3 5-6"],
6780
+ truck: [
6781
+ "M3 7.5h10v9H3z",
6782
+ "M13 11h4l3 3v2.5h-7z",
6783
+ "M8.8 18a1.8 1.8 0 1 1-3.6 0a1.8 1.8 0 1 1 3.6 0z",
6784
+ "M18.8 18a1.8 1.8 0 1 1-3.6 0a1.8 1.8 0 1 1 3.6 0z"
6785
+ ],
6786
+ package: [
6787
+ "M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z",
6788
+ "M12 22V12",
6789
+ "M3.29 7L12 12l8.71-5"
6790
+ ],
6791
+ refresh: ["M20 12a8 8 0 1 1-2.5-5.8", "M20 4v5h-5"],
6792
+ star: ["m12 3.6 2.6 5.3 5.9.9-4.3 4.1 1 5.8-5.2-2.7-5.2 2.7 1-5.8-4.3-4.1 5.9-.9z"],
6793
+ support: [
6794
+ "M5 13v-1a7 7 0 0 1 14 0v1",
6795
+ "M3.5 14.5a1.8 1.8 0 0 1 1.8-1.8H7v5H5.3a1.8 1.8 0 0 1-1.8-1.8z",
6796
+ "M20.5 14.5a1.8 1.8 0 0 0-1.8-1.8H17v5h1.7a1.8 1.8 0 0 0 1.8-1.8z",
6797
+ "M19 17.7v.8a2.5 2.5 0 0 1-2.5 2.5H13"
6798
+ ],
6799
+ globe: [
6800
+ "M21 12a9 9 0 1 1-18 0a9 9 0 1 1 18 0z",
6801
+ "M3 12h18",
6802
+ "M12 3a14 14 0 0 1 0 18a14 14 0 0 1 0-18z"
6803
+ ],
6804
+ tag: ["M11 3H4v7l10 10 7-7z", "M9.1 7a1.3 1.3 0 1 1-2.6 0a1.3 1.3 0 1 1 2.6 0z"],
6805
+ heart: ["M12 20s-7-4.4-7-9.3A3.9 3.9 0 0 1 12 8a3.9 3.9 0 0 1 7 2.7c0 4.9-7 9.3-7 9.3z"],
6806
+ leaf: ["M20 4c0 9-5.4 13-9.5 13A4.5 4.5 0 0 1 6 12.5C6 7 12 4 20 4z", "M4 20c2-4.5 5-7.5 9-9.5"],
6807
+ clock: ["M21 12a9 9 0 1 1-18 0a9 9 0 1 1 18 0z", "M12 7v5l3 2"],
6808
+ bank: ["M3 9.5 12 4l9 5.5", "M5 10v8M9.5 10v8M14.5 10v8M19 10v8", "M3 20h18"]
6809
+ };
6810
+ function isNoticeIcon(value) {
6811
+ return typeof value === "string" && NOTICE_ICONS.includes(value);
6812
+ }
6663
6813
  var FONT_STACKS = {
6664
6814
  inter: "'Inter Variable', 'Inter', system-ui, -apple-system, sans-serif",
6665
6815
  system: "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif",
@@ -6829,6 +6979,96 @@ var DEFAULT_BADGES_DARK = [
6829
6979
  borderColor: "#1e40af"
6830
6980
  }
6831
6981
  ];
6982
+ var DEFAULT_NOTICES = [
6983
+ {
6984
+ id: "secure",
6985
+ section: "summary",
6986
+ icon: "shield",
6987
+ label: "Secure payment",
6988
+ labelTranslations: {
6989
+ de: "Sichere Zahlung",
6990
+ fr: "Paiement s\xE9curis\xE9",
6991
+ es: "Pago seguro",
6992
+ it: "Pagamento sicuro",
6993
+ nl: "Veilig betalen",
6994
+ zh: "\u5B89\u5168\u652F\u4ED8",
6995
+ "zh-Hant": "\u5B89\u5168\u4ED8\u6B3E",
6996
+ hi: "\u0938\u0941\u0930\u0915\u094D\u0937\u093F\u0924 \u092D\u0941\u0917\u0924\u093E\u0928",
6997
+ ar: "\u062F\u0641\u0639 \u0622\u0645\u0646"
6998
+ }
6999
+ },
7000
+ {
7001
+ id: "ssl",
7002
+ section: "summary",
7003
+ icon: "lock",
7004
+ label: "Encrypted \xB7 256-bit SSL",
7005
+ labelTranslations: {
7006
+ de: "Verschl\xFCsselt \xB7 256-Bit-SSL",
7007
+ fr: "Chiffr\xE9 \xB7 SSL 256 bits",
7008
+ es: "Cifrado \xB7 SSL de 256 bits",
7009
+ it: "Crittografato \xB7 SSL a 256 bit",
7010
+ nl: "Versleuteld \xB7 256-bit SSL",
7011
+ zh: "\u52A0\u5BC6 \xB7 256 \u4F4D SSL",
7012
+ "zh-Hant": "\u52A0\u5BC6 \xB7 256 \u4F4D\u5143 SSL",
7013
+ hi: "\u090F\u0928\u094D\u0915\u094D\u0930\u093F\u092A\u094D\u091F\u0947\u0921 \xB7 256-\u092C\u093F\u091F SSL",
7014
+ ar: "\u0645\u0634\u0641\u0651\u0631 \xB7 SSL \u0628\u0637\u0648\u0644 256 \u0628\u062A"
7015
+ }
7016
+ }
7017
+ ];
7018
+ function defaultNotices() {
7019
+ return DEFAULT_NOTICES.map(cloneNotice);
7020
+ }
7021
+ function cloneNotice(notice) {
7022
+ return { ...notice, labelTranslations: { ...notice.labelTranslations } };
7023
+ }
7024
+ function hexChannels(hex) {
7025
+ const raw = /^#([0-9a-f]{6})$/i.exec(hex.trim())?.[1];
7026
+ if (!raw) return null;
7027
+ return [
7028
+ parseInt(raw.slice(0, 2), 16),
7029
+ parseInt(raw.slice(2, 4), 16),
7030
+ parseInt(raw.slice(4, 6), 16)
7031
+ ];
7032
+ }
7033
+ function isThemeTintedBadgeColouring(textColor, fill, border) {
7034
+ const primary = hexChannels(textColor);
7035
+ const bg = hexChannels(fill);
7036
+ const line = hexChannels(border);
7037
+ if (!primary || !bg || !line) return false;
7038
+ const mixed = (surface, to, share) => Math.round(surface + (to - surface) * share);
7039
+ return primary.every((p, i) => {
7040
+ for (let surface = 0; surface <= 255; surface += 1) {
7041
+ if (mixed(surface, p, 0.08) === bg[i] && mixed(surface, p, 0.3) === line[i]) return true;
7042
+ }
7043
+ return false;
7044
+ });
7045
+ }
7046
+ function isDefaultBadgeSet(badges) {
7047
+ if (badges.length !== DEFAULT_BADGES.length) return false;
7048
+ const sameContent = badges.every(
7049
+ (badge, i) => badge.id === DEFAULT_BADGES[i]?.id && badge.label === DEFAULT_BADGES[i]?.label
7050
+ );
7051
+ if (!sameContent) return false;
7052
+ const colouring = (set) => set.map((b) => [b.textColor, b.backgroundColor, b.borderColor ?? ""].join("|").toLowerCase()).join("/");
7053
+ const mine = colouring(badges);
7054
+ if (mine === colouring(DEFAULT_BADGES) || mine === colouring(DEFAULT_BADGES_DARK)) return true;
7055
+ const [first] = badges;
7056
+ const border = first?.borderColor;
7057
+ if (!first || !border) return false;
7058
+ const same = (a, b) => (a ?? "").toLowerCase() === b.toLowerCase();
7059
+ return badges.every(
7060
+ (b) => same(b.textColor, first.textColor) && same(b.backgroundColor, first.backgroundColor) && same(b.borderColor, border)
7061
+ ) && isThemeTintedBadgeColouring(first.textColor, first.backgroundColor, border);
7062
+ }
7063
+ function resolveNoticesAndBadges(savedBadges, savedNotices) {
7064
+ if (savedNotices !== null) {
7065
+ return { trustBadges: savedBadges ?? [], notices: savedNotices };
7066
+ }
7067
+ if (savedBadges === null || isDefaultBadgeSet(savedBadges)) {
7068
+ return { trustBadges: [], notices: defaultNotices() };
7069
+ }
7070
+ return { trustBadges: savedBadges, notices: [] };
7071
+ }
6832
7072
  var METHOD_SECTION_ORDER_KEY = "methodSectionOrder";
6833
7073
  var METHOD_SECTION_LABELS_KEY = "methodSectionLabels";
6834
7074
  var MIN_SECTION_ORDER = 1;
@@ -7115,7 +7355,11 @@ var DEFAULT_BRANDING_BASE = {
7115
7355
  var DEFAULT_BRANDING = {
7116
7356
  ...DEFAULT_BRANDING_BASE,
7117
7357
  ...LIGHT_PALETTE,
7118
- trustBadges: DEFAULT_BADGES.map((b) => ({ ...b })),
7358
+ // No badges by default since todos#218 — notices took their place.
7359
+ // `DEFAULT_BADGES` stays exported because `isDefaultBadgeSet` still has to
7360
+ // recognise the pair on shops saved before.
7361
+ trustBadges: [],
7362
+ notices: defaultNotices(),
7119
7363
  customFields: [],
7120
7364
  methodSectionOrder: defaultMethodSectionOrder(),
7121
7365
  methodSectionLabels: {}
@@ -7138,7 +7382,8 @@ var DEFAULT_BRANDING_DARK = {
7138
7382
  // end of the ramp — 10.69 and 9.29 against the dark surface, also pinned.
7139
7383
  surchargeColor: "#fbbf24",
7140
7384
  discountColor: "#34d399",
7141
- trustBadges: DEFAULT_BADGES_DARK.map((b) => ({ ...b })),
7385
+ trustBadges: [],
7386
+ notices: defaultNotices(),
7142
7387
  customFields: [],
7143
7388
  methodSectionOrder: defaultMethodSectionOrder(),
7144
7389
  methodSectionLabels: {}
@@ -7150,6 +7395,7 @@ function cloneBranding(b) {
7150
7395
  return {
7151
7396
  ...b,
7152
7397
  trustBadges: b.trustBadges.map((badge) => ({ ...badge })),
7398
+ notices: b.notices.map(cloneNotice),
7153
7399
  customFields: b.customFields.map(cloneCustomField),
7154
7400
  methodSectionOrder: { ...b.methodSectionOrder },
7155
7401
  methodSectionLabels: Object.fromEntries(
@@ -7259,6 +7505,80 @@ function encodeBadges(badges) {
7259
7505
  }))
7260
7506
  );
7261
7507
  }
7508
+ var NOTICE_ID_MAX_LENGTH = 40;
7509
+ function capNoticeText(value) {
7510
+ return Array.from(value).slice(0, NOTICE_LABEL_MAX_LENGTH).join("");
7511
+ }
7512
+ function normalizeNotices(list) {
7513
+ const seen = /* @__PURE__ */ new Set();
7514
+ const perSection = /* @__PURE__ */ new Map();
7515
+ const out = [];
7516
+ list.forEach((raw, index) => {
7517
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
7518
+ const src = raw;
7519
+ const label = typeof src["label"] === "string" ? capNoticeText(src["label"]) : "";
7520
+ const labelTranslations = {};
7521
+ for (const [locale, text] of Object.entries(parseTranslations(src["labelTranslations"]))) {
7522
+ labelTranslations[locale] = capNoticeText(text);
7523
+ }
7524
+ if (label.trim().length === 0 && Object.keys(labelTranslations).length === 0) return;
7525
+ const section = pickEnum(src["section"], NOTICE_SECTIONS, "summary");
7526
+ const used = perSection.get(section) ?? 0;
7527
+ if (used >= NOTICES_PER_SECTION) return;
7528
+ perSection.set(section, used + 1);
7529
+ let id = typeof src["id"] === "string" ? src["id"].replace(/[^A-Za-z0-9_-]/g, "").slice(0, NOTICE_ID_MAX_LENGTH) : "";
7530
+ if (!id || seen.has(id)) id = `notice-${index + 1}`;
7531
+ while (seen.has(id)) id = `${id}x`;
7532
+ seen.add(id);
7533
+ out.push({
7534
+ id,
7535
+ section,
7536
+ icon: isNoticeIcon(src["icon"]) ? src["icon"] : NOTICE_ICON_FALLBACK,
7537
+ label,
7538
+ labelTranslations
7539
+ });
7540
+ });
7541
+ return out;
7542
+ }
7543
+ function decodeNotices(raw) {
7544
+ if (raw === void 0) return null;
7545
+ let parsed;
7546
+ try {
7547
+ parsed = JSON.parse(raw);
7548
+ } catch {
7549
+ return null;
7550
+ }
7551
+ return Array.isArray(parsed) ? normalizeNotices(parsed) : null;
7552
+ }
7553
+ function parseNoticesLoose(raw) {
7554
+ if (typeof raw === "string") return decodeNotices(raw);
7555
+ return Array.isArray(raw) ? normalizeNotices(raw) : null;
7556
+ }
7557
+ function encodeNotices(notices) {
7558
+ return JSON.stringify(
7559
+ notices.map((n) => {
7560
+ const translations = Object.entries(n.labelTranslations).filter(
7561
+ ([, text]) => text.trim().length > 0
7562
+ );
7563
+ return {
7564
+ id: n.id,
7565
+ section: n.section,
7566
+ icon: n.icon,
7567
+ label: n.label,
7568
+ ...translations.length > 0 ? { labelTranslations: Object.fromEntries(translations) } : {}
7569
+ };
7570
+ })
7571
+ );
7572
+ }
7573
+ function noticeText(notice, locale) {
7574
+ return translationFor(notice.labelTranslations, locale) ?? notice.label;
7575
+ }
7576
+ function noticesIn(notices, section) {
7577
+ return notices.filter((n) => n.section === section).slice(0, NOTICES_PER_SECTION);
7578
+ }
7579
+ function shownNotices(notices, section, locale) {
7580
+ return noticesIn(notices, section).map((notice) => ({ notice, text: noticeText(notice, locale).trim() })).filter((entry) => entry.text.length > 0);
7581
+ }
7262
7582
  var CUSTOM_FIELDS_MAX = 20;
7263
7583
  var CUSTOM_FIELD_KEY_PATTERN = /^[A-Za-z][A-Za-z0-9_-]{0,39}$/;
7264
7584
  var ALL_CUSTOM_FIELD_TYPES = [
@@ -7602,7 +7922,10 @@ function customFieldOptionLabel(option, locale) {
7602
7922
  function decodeBranding(source) {
7603
7923
  if (!source) return cloneBranding(DEFAULT_BRANDING);
7604
7924
  const extras = source.sdk_ui_rules?.[BRANDING_GROUP_KEY] ?? {};
7605
- const decodedBadges = decodeBadges(extras["trustBadges"]);
7925
+ const trustRow = resolveNoticesAndBadges(
7926
+ decodeBadges(extras["trustBadges"]),
7927
+ decodeNotices(extras["notices"])
7928
+ );
7606
7929
  const decodedCustomFields = decodeCustomFields(extras["customFields"]);
7607
7930
  const displayName = s(source.merchant_name) || s(source.seller_name);
7608
7931
  const logoUrl = s(source.merchant_logo) || s(source.logo);
@@ -7781,7 +8104,8 @@ function decodeBranding(source) {
7781
8104
  totalLabel: s(extras["totalLabel"]) || DEFAULT_BRANDING.totalLabel,
7782
8105
  showCurrencyCode: parseBool(extras["showCurrencyCode"], DEFAULT_BRANDING.showCurrencyCode),
7783
8106
  showOrderItems: parseBool(extras["showOrderItems"], DEFAULT_BRANDING.showOrderItems),
7784
- trustBadges: decodedBadges ?? DEFAULT_BRANDING.trustBadges.map((b) => ({ ...b })),
8107
+ trustBadges: trustRow.trustBadges,
8108
+ notices: trustRow.notices,
7785
8109
  customFields: decodedCustomFields ?? [],
7786
8110
  methodSectionOrder: decodeMethodSectionOrder(extras[METHOD_SECTION_ORDER_KEY]),
7787
8111
  methodSectionLabels: decodeMethodSectionLabels(extras[METHOD_SECTION_LABELS_KEY]),
@@ -8065,9 +8389,14 @@ function encodeBranding(branding, base) {
8065
8389
  nomupayApplePayButtonType: branding.nomupayApplePayButtonType,
8066
8390
  nomupayGooglePayButtonColor: branding.nomupayGooglePayButtonColor,
8067
8391
  nomupayGooglePayButtonType: branding.nomupayGooglePayButtonType,
8068
- trustBadges: encodeBadges(branding.trustBadges),
8392
+ // Always written, `[]` included — its presence is what stops a later
8393
+ // decode from migrating the shop again (`resolveNoticesAndBadges`).
8394
+ notices: encodeNotices(branding.notices),
8069
8395
  [METHOD_SECTION_ORDER_KEY]: encodeMethodSectionOrder(branding.methodSectionOrder)
8070
8396
  };
8397
+ if (branding.trustBadges.length > 0) {
8398
+ extras["trustBadges"] = encodeBadges(branding.trustBadges);
8399
+ }
8071
8400
  const sectionLabels = encodeMethodSectionLabels(branding.methodSectionLabels);
8072
8401
  if (sectionLabels) extras[METHOD_SECTION_LABELS_KEY] = sectionLabels;
8073
8402
  if (branding.customFields.length > 0) {
@@ -8133,7 +8462,10 @@ function parseImportedBranding(raw) {
8133
8462
  const dflt = DEFAULT_BRANDING;
8134
8463
  const sStr = (v, fallback) => typeof v === "string" ? v : fallback;
8135
8464
  const sHex = (v, fallback) => typeof v === "string" && isHexColor(v) ? v : fallback;
8136
- const trustBadges = parseTrustBadgesLoose(root["trustBadges"]) ?? dflt.trustBadges.map((b) => ({ ...b }));
8465
+ const { trustBadges, notices } = resolveNoticesAndBadges(
8466
+ parseTrustBadgesLoose(root["trustBadges"]),
8467
+ parseNoticesLoose(root["notices"])
8468
+ );
8137
8469
  const customFields = parseCustomFieldsLoose(root["customFields"]) ?? [];
8138
8470
  const labelStyle = (() => {
8139
8471
  const v = root["labelStyle"];
@@ -8276,6 +8608,7 @@ function parseImportedBranding(raw) {
8276
8608
  showCurrencyCode: parseBool(root["showCurrencyCode"], dflt.showCurrencyCode),
8277
8609
  showOrderItems: parseBool(root["showOrderItems"], dflt.showOrderItems),
8278
8610
  trustBadges,
8611
+ notices,
8279
8612
  customFields,
8280
8613
  // An export writes the decoded maps; a hand-written file may carry the
8281
8614
  // JSON strings the bag uses. Both are accepted, and neither is required.
@@ -10884,6 +11217,7 @@ var DelopayInternal = class extends Delopay {
10884
11217
  DEFAULT_BADGES_DARK,
10885
11218
  DEFAULT_BRANDING,
10886
11219
  DEFAULT_BRANDING_DARK,
11220
+ DEFAULT_NOTICES,
10887
11221
  Delopay,
10888
11222
  DelopayAuthenticationError,
10889
11223
  DelopayError,
@@ -10908,6 +11242,12 @@ var DelopayInternal = class extends Delopay {
10908
11242
  NATIVE_PANE_CATEGORY_KEYS,
10909
11243
  NATIVE_PANE_ICON_KEYS,
10910
11244
  NOMUPAY_FORM_STYLES,
11245
+ NOTICES_PER_SECTION,
11246
+ NOTICE_ICONS,
11247
+ NOTICE_ICON_FALLBACK,
11248
+ NOTICE_ICON_PATHS,
11249
+ NOTICE_LABEL_MAX_LENGTH,
11250
+ NOTICE_SECTIONS,
10911
11251
  OperationLimits,
10912
11252
  PANES_MAX,
10913
11253
  PANE_CATEGORY_KEYS,
@@ -10967,6 +11307,7 @@ var DelopayInternal = class extends Delopay {
10967
11307
  cloneBranding,
10968
11308
  cloneCustomField,
10969
11309
  cloneNativePane,
11310
+ cloneNotice,
10970
11311
  clonePane,
10971
11312
  compareSections,
10972
11313
  contrastRatio,
@@ -10982,11 +11323,13 @@ var DelopayInternal = class extends Delopay {
10982
11323
  decodeMethodSectionLabels,
10983
11324
  decodeMethodSectionOrder,
10984
11325
  decodeNativePanes,
11326
+ decodeNotices,
10985
11327
  decodePanes,
10986
11328
  defaultBranding,
10987
11329
  defaultCustomFieldVisibility,
10988
11330
  defaultMethodSectionOrder,
10989
11331
  defaultNativePane,
11332
+ defaultNotices,
10990
11333
  defaultOperatorForSource,
10991
11334
  defaultPane,
10992
11335
  emptyPaneCatalog,
@@ -10996,6 +11339,7 @@ var DelopayInternal = class extends Delopay {
10996
11339
  encodeMethodSectionLabels,
10997
11340
  encodeMethodSectionOrder,
10998
11341
  encodeNativePanes,
11342
+ encodeNotices,
10999
11343
  encodePanes,
11000
11344
  evaluateCustomFieldCondition,
11001
11345
  evaluateCustomFieldVisibility,
@@ -11006,13 +11350,17 @@ var DelopayInternal = class extends Delopay {
11006
11350
  inputPadValue,
11007
11351
  isCheckboxChecked,
11008
11352
  isDarkSurface,
11353
+ isDefaultBadgeSet,
11009
11354
  isHexColor,
11355
+ isNoticeIcon,
11010
11356
  isSubscriptionDisputeWebhook,
11011
11357
  isSubscriptionLifecycleWebhook,
11012
11358
  knownSectionLabelKey,
11013
11359
  leaf,
11014
11360
  logoDimensions,
11015
11361
  nativePaneMethodInfo,
11362
+ noticeText,
11363
+ noticesIn,
11016
11364
  offerablePaneMethods,
11017
11365
  paneCatalogFor,
11018
11366
  paneDisplayDefaults,
@@ -11021,6 +11369,7 @@ var DelopayInternal = class extends Delopay {
11021
11369
  paneViewVisibility,
11022
11370
  parseCustomFieldsLoose,
11023
11371
  parseImportedBranding,
11372
+ parseNoticesLoose,
11024
11373
  programToTree,
11025
11374
  radiusValue,
11026
11375
  readableInkOn,
@@ -11028,12 +11377,14 @@ var DelopayInternal = class extends Delopay {
11028
11377
  resolveAirwallexLabelStyle,
11029
11378
  resolveApplePayButtonStyle,
11030
11379
  resolveGooglePayButtonColor,
11380
+ resolveNoticesAndBadges,
11031
11381
  resolveStripeTheme,
11032
11382
  ruleMatchToTree,
11033
11383
  sanitizeCustomCss,
11034
11384
  sectionLabel,
11035
11385
  sectionOrderOf,
11036
11386
  shadowFor,
11387
+ shownNotices,
11037
11388
  stripeSpacingValues,
11038
11389
  surchargeFigurePlan,
11039
11390
  surchargeShowsLabel,