@delopay/sdk 0.164.0 → 0.166.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/index.cjs CHANGED
@@ -63,6 +63,7 @@ __export(index_exports, {
63
63
  DEFAULT_BADGES_DARK: () => DEFAULT_BADGES_DARK,
64
64
  DEFAULT_BRANDING: () => DEFAULT_BRANDING,
65
65
  DEFAULT_BRANDING_DARK: () => DEFAULT_BRANDING_DARK,
66
+ DEFAULT_NOTICES: () => DEFAULT_NOTICES,
66
67
  Delopay: () => Delopay,
67
68
  DelopayAuthenticationError: () => DelopayAuthenticationError,
68
69
  DelopayError: () => DelopayError,
@@ -84,6 +85,12 @@ __export(index_exports, {
84
85
  NATIVE_PANE_CATEGORY_KEYS: () => NATIVE_PANE_CATEGORY_KEYS,
85
86
  NATIVE_PANE_ICON_KEYS: () => NATIVE_PANE_ICON_KEYS,
86
87
  NOMUPAY_FORM_STYLES: () => NOMUPAY_FORM_STYLES,
88
+ NOTICES_PER_SECTION: () => NOTICES_PER_SECTION,
89
+ NOTICE_ICONS: () => NOTICE_ICONS,
90
+ NOTICE_ICON_FALLBACK: () => NOTICE_ICON_FALLBACK,
91
+ NOTICE_ICON_PATHS: () => NOTICE_ICON_PATHS,
92
+ NOTICE_LABEL_MAX_LENGTH: () => NOTICE_LABEL_MAX_LENGTH,
93
+ NOTICE_SECTIONS: () => NOTICE_SECTIONS,
87
94
  OperationLimits: () => OperationLimits,
88
95
  PANES_MAX: () => PANES_MAX,
89
96
  PANE_CATEGORY_KEYS: () => PANE_CATEGORY_KEYS,
@@ -141,6 +148,7 @@ __export(index_exports, {
141
148
  cloneBranding: () => cloneBranding,
142
149
  cloneCustomField: () => cloneCustomField,
143
150
  cloneNativePane: () => cloneNativePane,
151
+ cloneNotice: () => cloneNotice,
144
152
  clonePane: () => clonePane,
145
153
  compareSections: () => compareSections,
146
154
  contrastRatio: () => contrastRatio,
@@ -156,11 +164,13 @@ __export(index_exports, {
156
164
  decodeMethodSectionLabels: () => decodeMethodSectionLabels,
157
165
  decodeMethodSectionOrder: () => decodeMethodSectionOrder,
158
166
  decodeNativePanes: () => decodeNativePanes,
167
+ decodeNotices: () => decodeNotices,
159
168
  decodePanes: () => decodePanes,
160
169
  defaultBranding: () => defaultBranding,
161
170
  defaultCustomFieldVisibility: () => defaultCustomFieldVisibility,
162
171
  defaultMethodSectionOrder: () => defaultMethodSectionOrder,
163
172
  defaultNativePane: () => defaultNativePane,
173
+ defaultNotices: () => defaultNotices,
164
174
  defaultOperatorForSource: () => defaultOperatorForSource,
165
175
  defaultPane: () => defaultPane,
166
176
  emptyPaneCatalog: () => emptyPaneCatalog,
@@ -170,6 +180,7 @@ __export(index_exports, {
170
180
  encodeMethodSectionLabels: () => encodeMethodSectionLabels,
171
181
  encodeMethodSectionOrder: () => encodeMethodSectionOrder,
172
182
  encodeNativePanes: () => encodeNativePanes,
183
+ encodeNotices: () => encodeNotices,
173
184
  encodePanes: () => encodePanes,
174
185
  evaluateCustomFieldCondition: () => evaluateCustomFieldCondition,
175
186
  evaluateCustomFieldVisibility: () => evaluateCustomFieldVisibility,
@@ -180,13 +191,17 @@ __export(index_exports, {
180
191
  inputPadValue: () => inputPadValue,
181
192
  isCheckboxChecked: () => isCheckboxChecked,
182
193
  isDarkSurface: () => isDarkSurface,
194
+ isDefaultBadgeSet: () => isDefaultBadgeSet,
183
195
  isHexColor: () => isHexColor,
196
+ isNoticeIcon: () => isNoticeIcon,
184
197
  isSubscriptionDisputeWebhook: () => isSubscriptionDisputeWebhook,
185
198
  isSubscriptionLifecycleWebhook: () => isSubscriptionLifecycleWebhook,
186
199
  knownSectionLabelKey: () => knownSectionLabelKey,
187
200
  leaf: () => leaf,
188
201
  logoDimensions: () => logoDimensions,
189
202
  nativePaneMethodInfo: () => nativePaneMethodInfo,
203
+ noticeText: () => noticeText,
204
+ noticesIn: () => noticesIn,
190
205
  offerablePaneMethods: () => offerablePaneMethods,
191
206
  paneCatalogFor: () => paneCatalogFor,
192
207
  paneDisplayDefaults: () => paneDisplayDefaults,
@@ -195,6 +210,7 @@ __export(index_exports, {
195
210
  paneViewVisibility: () => paneViewVisibility,
196
211
  parseCustomFieldsLoose: () => parseCustomFieldsLoose,
197
212
  parseImportedBranding: () => parseImportedBranding,
213
+ parseNoticesLoose: () => parseNoticesLoose,
198
214
  programToTree: () => programToTree,
199
215
  radiusValue: () => radiusValue,
200
216
  readableInkOn: () => readableInkOn,
@@ -202,12 +218,14 @@ __export(index_exports, {
202
218
  resolveAirwallexLabelStyle: () => resolveAirwallexLabelStyle,
203
219
  resolveApplePayButtonStyle: () => resolveApplePayButtonStyle,
204
220
  resolveGooglePayButtonColor: () => resolveGooglePayButtonColor,
221
+ resolveNoticesAndBadges: () => resolveNoticesAndBadges,
205
222
  resolveStripeTheme: () => resolveStripeTheme,
206
223
  ruleMatchToTree: () => ruleMatchToTree,
207
224
  sanitizeCustomCss: () => sanitizeCustomCss,
208
225
  sectionLabel: () => sectionLabel,
209
226
  sectionOrderOf: () => sectionOrderOf,
210
227
  shadowFor: () => shadowFor,
228
+ shownNotices: () => shownNotices,
211
229
  stripeSpacingValues: () => stripeSpacingValues,
212
230
  surchargeFigurePlan: () => surchargeFigurePlan,
213
231
  surchargeShowsLabel: () => surchargeShowsLabel,
@@ -1161,6 +1179,289 @@ var Customers = class {
1161
1179
  }
1162
1180
  };
1163
1181
 
1182
+ // src/recordCounter.ts
1183
+ var LF = 10;
1184
+ var CR = 13;
1185
+ var QUOTE = 34;
1186
+ var BACKSLASH = 92;
1187
+ var OPEN_BRACE = 123;
1188
+ var CLOSE_BRACE = 125;
1189
+ var OPEN_BRACKET = 91;
1190
+ var CLOSE_BRACKET = 93;
1191
+ var CsvRecordCounter = class {
1192
+ constructor() {
1193
+ this.inQuotes = false;
1194
+ this.newlines = 0;
1195
+ /** Whether anything but a line break has arrived since the last newline. */
1196
+ this.lineHasContent = false;
1197
+ }
1198
+ push(chunk) {
1199
+ let inQuotes = this.inQuotes;
1200
+ let newlines = this.newlines;
1201
+ let lineHasContent = this.lineHasContent;
1202
+ for (const byte of chunk) {
1203
+ if (byte === QUOTE) {
1204
+ inQuotes = !inQuotes;
1205
+ lineHasContent = true;
1206
+ } else if (inQuotes) {
1207
+ lineHasContent = true;
1208
+ } else if (byte === LF) {
1209
+ newlines++;
1210
+ lineHasContent = false;
1211
+ } else if (byte !== CR) {
1212
+ lineHasContent = true;
1213
+ }
1214
+ }
1215
+ this.inQuotes = inQuotes;
1216
+ this.newlines = newlines;
1217
+ this.lineHasContent = lineHasContent;
1218
+ }
1219
+ get records() {
1220
+ return Math.max(0, this.newlines - 1);
1221
+ }
1222
+ /**
1223
+ * The export writer ends every line — the header and each record — with a
1224
+ * newline, so a whole body ends on one, outside quotes. RFC 4180 lets a
1225
+ * final line break be omitted, but these bodies never omit it, and without
1226
+ * that rule a file cut part-way through its last unquoted field
1227
+ * (`pay_1,12` of `pay_1,123`) would count as one more whole record and
1228
+ * match the figure it was announced with.
1229
+ */
1230
+ get complete() {
1231
+ return this.newlines >= 1 && !this.inQuotes && !this.lineHasContent;
1232
+ }
1233
+ /**
1234
+ * The records that ended. An unterminated tail is not one of them — see
1235
+ * {@link complete}.
1236
+ */
1237
+ finish() {
1238
+ return this.records;
1239
+ }
1240
+ };
1241
+ var SEEKING = 0;
1242
+ var COUNTING = 1;
1243
+ var CLOSED = 2;
1244
+ var JsonArrayRecordCounter = class {
1245
+ constructor() {
1246
+ this.depth = 0;
1247
+ this.inString = false;
1248
+ this.escaped = false;
1249
+ this.topIsObject = false;
1250
+ this.state = SEEKING;
1251
+ this.count = 0;
1252
+ }
1253
+ push(chunk) {
1254
+ if (this.state === CLOSED) return;
1255
+ let { depth, inString, escaped, topIsObject, count } = this;
1256
+ let state = this.state;
1257
+ for (const byte of chunk) {
1258
+ if (inString) {
1259
+ if (escaped) escaped = false;
1260
+ else if (byte === BACKSLASH) escaped = true;
1261
+ else if (byte === QUOTE) inString = false;
1262
+ continue;
1263
+ }
1264
+ if (byte === QUOTE) {
1265
+ inString = true;
1266
+ } else if (byte === OPEN_BRACE || byte === OPEN_BRACKET) {
1267
+ if (depth === 0 && byte === OPEN_BRACE) topIsObject = true;
1268
+ if (byte === OPEN_BRACKET && depth === 1 && topIsObject && state === SEEKING) {
1269
+ state = COUNTING;
1270
+ }
1271
+ depth++;
1272
+ } else if (byte === CLOSE_BRACE || byte === CLOSE_BRACKET) {
1273
+ depth--;
1274
+ if (state === COUNTING) {
1275
+ if (depth === 2) count++;
1276
+ else if (depth === 1) {
1277
+ state = CLOSED;
1278
+ break;
1279
+ }
1280
+ }
1281
+ }
1282
+ }
1283
+ this.depth = depth;
1284
+ this.inString = inString;
1285
+ this.escaped = escaped;
1286
+ this.topIsObject = topIsObject;
1287
+ this.state = state;
1288
+ this.count = count;
1289
+ }
1290
+ get records() {
1291
+ return this.count;
1292
+ }
1293
+ /**
1294
+ * Whether the rows array has closed. What follows it is checked by parsing
1295
+ * the whole document, which a cut-off body fails.
1296
+ */
1297
+ get complete() {
1298
+ return this.state === CLOSED;
1299
+ }
1300
+ finish() {
1301
+ return this.count;
1302
+ }
1303
+ };
1304
+
1305
+ // src/exportDownload.ts
1306
+ var RECORD_COUNT_HEADER = "x-delopay-record-count";
1307
+ var LIST_ENVELOPE = { rows: "records", count: "record_count" };
1308
+ var WORKSPACE_ENVELOPE = { rows: "data", count: "total_count" };
1309
+ function parseRecordCount(header) {
1310
+ if (header === null) return null;
1311
+ const trimmed = header.trim();
1312
+ if (!/^\d+$/.test(trimmed)) return null;
1313
+ const value = Number(trimmed);
1314
+ return Number.isSafeInteger(value) ? value : null;
1315
+ }
1316
+ function counterFor(format) {
1317
+ if (format === "csv") return new CsvRecordCounter();
1318
+ if (format === "json") return new JsonArrayRecordCounter();
1319
+ return null;
1320
+ }
1321
+ function isRecord(value) {
1322
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1323
+ }
1324
+ function announced(expected) {
1325
+ return expected === null ? "" : ` of the ${expected} announced`;
1326
+ }
1327
+ function incomplete(message, expected, received, requestId) {
1328
+ return new DelopayError(message, {
1329
+ status: 0,
1330
+ code: "EXPORT_INCOMPLETE",
1331
+ type: "export_incomplete",
1332
+ ...requestId !== void 0 ? { requestId } : {},
1333
+ data: { expected_records: expected, received_records: received }
1334
+ });
1335
+ }
1336
+ async function downloadExport(request, call, options) {
1337
+ const { format } = call;
1338
+ const envelope = call.envelope ?? LIST_ENVELOPE;
1339
+ const onProgress = options?.onProgress;
1340
+ let latest = {
1341
+ phase: "preparing",
1342
+ receivedBytes: 0,
1343
+ totalBytes: null,
1344
+ receivedRecords: 0,
1345
+ expectedRecords: null
1346
+ };
1347
+ const seen = { attempt: -1, counter: null, expected: null, requestId: void 0, listenerError: null };
1348
+ const report = (progress) => {
1349
+ latest = progress;
1350
+ if (!onProgress) return;
1351
+ try {
1352
+ onProgress({ ...progress });
1353
+ } catch (error) {
1354
+ seen.listenerError = { error };
1355
+ throw error;
1356
+ }
1357
+ };
1358
+ report(latest);
1359
+ const onDownloadProgress = (event) => {
1360
+ if (event.attempt !== seen.attempt) {
1361
+ seen.attempt = event.attempt;
1362
+ seen.counter = counterFor(format);
1363
+ seen.expected = format === "pdf" ? null : parseRecordCount(event.headers.get(RECORD_COUNT_HEADER));
1364
+ seen.requestId = event.headers.get("x-request-id") ?? event.headers.get("x-trace-id") ?? void 0;
1365
+ }
1366
+ if (event.chunk.byteLength > 0) seen.counter?.push(event.chunk);
1367
+ report({
1368
+ phase: "receiving",
1369
+ receivedBytes: event.loaded,
1370
+ totalBytes: event.total,
1371
+ receivedRecords: seen.counter?.records ?? 0,
1372
+ expectedRecords: seen.expected
1373
+ });
1374
+ };
1375
+ let result;
1376
+ try {
1377
+ result = await request(call.method, call.path, {
1378
+ ...call.request,
1379
+ ...options?.signal !== void 0 ? { signal: options.signal } : {},
1380
+ ...options?.timeout !== void 0 ? { timeout: options.timeout } : {},
1381
+ onDownloadProgress
1382
+ });
1383
+ } catch (err) {
1384
+ if (seen.listenerError !== null && err === seen.listenerError.error) throw err;
1385
+ if (format === "json" && seen.attempt >= 0 && err instanceof SyntaxError) {
1386
+ const received2 = seen.counter?.records ?? 0;
1387
+ throw incomplete(
1388
+ seen.expected === null ? `Export incomplete: the body ended part-way through the JSON document, after ${received2} records` : `Export incomplete: the server announced ${seen.expected} records, and the body ended part-way through the JSON document after ${received2}`,
1389
+ seen.expected,
1390
+ received2,
1391
+ seen.requestId
1392
+ );
1393
+ }
1394
+ throw err;
1395
+ }
1396
+ const { expected, requestId } = seen;
1397
+ let received = 0;
1398
+ if (format === "json") {
1399
+ const rows = isRecord(result) ? result[envelope.rows] : void 0;
1400
+ if (!Array.isArray(rows)) {
1401
+ throw incomplete(
1402
+ `Export incomplete: the body is not an export envelope with a "${envelope.rows}" array, so it carries 0 records${announced(expected)}`,
1403
+ expected,
1404
+ 0,
1405
+ requestId
1406
+ );
1407
+ }
1408
+ received = rows.length;
1409
+ const declared = isRecord(result) ? result[envelope.count] : void 0;
1410
+ if (typeof declared === "number" && declared !== rows.length) {
1411
+ throw incomplete(
1412
+ `Export incomplete: the file's ${envelope.count} is ${declared}, but it carries ${rows.length} records`,
1413
+ declared,
1414
+ rows.length,
1415
+ requestId
1416
+ );
1417
+ }
1418
+ } else if (format === "csv") {
1419
+ const counter = seen.counter;
1420
+ received = counter?.finish() ?? 0;
1421
+ if (!counter?.complete) {
1422
+ throw incomplete(
1423
+ `Export incomplete: the CSV body ended part-way through a line, after ${received} complete records${announced(expected)}`,
1424
+ expected,
1425
+ received,
1426
+ requestId
1427
+ );
1428
+ }
1429
+ }
1430
+ if (expected !== null && received !== expected) {
1431
+ throw incomplete(
1432
+ `Export incomplete: the server announced ${expected} records, and the body carried ${received}`,
1433
+ expected,
1434
+ received,
1435
+ requestId
1436
+ );
1437
+ }
1438
+ report({
1439
+ phase: "done",
1440
+ receivedBytes: latest.receivedBytes,
1441
+ totalBytes: latest.totalBytes,
1442
+ receivedRecords: received,
1443
+ expectedRecords: expected
1444
+ });
1445
+ return result;
1446
+ }
1447
+ var ACCEPT = {
1448
+ csv: "text/csv",
1449
+ json: "application/json",
1450
+ pdf: "application/pdf"
1451
+ };
1452
+ function negotiated(options, format) {
1453
+ const headers = { ...options.headers, Accept: ACCEPT[format] };
1454
+ return format === "json" ? { ...options, headers } : { ...options, headers, responseType: "blob" };
1455
+ }
1456
+ function runExport(request, method, path, base, options) {
1457
+ const format = options?.format ?? "json";
1458
+ return downloadExport(
1459
+ request,
1460
+ { method, path, request: negotiated(base, format), format },
1461
+ options
1462
+ );
1463
+ }
1464
+
1164
1465
  // src/resources/disputes.ts
1165
1466
  function workspaceQuery(params) {
1166
1467
  if (!params) return void 0;
@@ -1189,9 +1490,28 @@ var Disputes = class {
1189
1490
  async workspaceAggregate(params) {
1190
1491
  return this.request("GET", "/disputes/workspace/aggregate", { query: workspaceQuery(params) });
1191
1492
  }
1192
- /** Export the complete filtered set, or throw on the server's explicit export-limit refusal. */
1193
- async workspaceExport(params) {
1194
- return this.request("GET", "/disputes/workspace/export", { query: workspaceQuery(params) });
1493
+ /**
1494
+ * Export the complete filtered set, or throw on the server's explicit
1495
+ * export-limit refusal. `GET /disputes/workspace/export`
1496
+ *
1497
+ * The body is streamed, and held to the `X-Delopay-Record-Count` the server
1498
+ * announces and to its own `total_count`: a set that arrives short rejects
1499
+ * with `EXPORT_INCOMPLETE` rather than resolving. `options` reports the
1500
+ * download's progress and takes a signal and an idle timeout — see
1501
+ * {@link ExportTransferOptions}.
1502
+ */
1503
+ async workspaceExport(params, options) {
1504
+ return downloadExport(
1505
+ this.request,
1506
+ {
1507
+ method: "GET",
1508
+ path: "/disputes/workspace/export",
1509
+ request: { query: workspaceQuery(params) },
1510
+ format: "json",
1511
+ envelope: WORKSPACE_ENVELOPE
1512
+ },
1513
+ options
1514
+ );
1195
1515
  }
1196
1516
  /**
1197
1517
  * Retrieve a dispute by its ID.
@@ -4348,77 +4668,68 @@ var Export = class {
4348
4668
  this.request = request;
4349
4669
  }
4350
4670
  async transactions(params, options) {
4351
- return this.request(
4352
- "POST",
4353
- "/export/transactions",
4354
- transactionBody(params, options)
4355
- );
4671
+ return runExport(this.request, "POST", "/export/transactions", { body: params ?? {} }, options);
4356
4672
  }
4357
4673
  async transactionsForProfile(params, options) {
4358
- return this.request(
4674
+ return runExport(
4675
+ this.request,
4359
4676
  "POST",
4360
4677
  "/export/profile/transactions",
4361
- transactionBody(params, options)
4678
+ { body: params ?? {} },
4679
+ options
4362
4680
  );
4363
4681
  }
4364
4682
  async refunds(params, options) {
4365
- return this.request("POST", "/refunds/list/export", bodied(params ?? {}, options));
4683
+ return runExport(this.request, "POST", "/refunds/list/export", { body: params ?? {} }, options);
4366
4684
  }
4367
4685
  async refundsForProfile(params, options) {
4368
- return this.request(
4686
+ return runExport(
4687
+ this.request,
4369
4688
  "POST",
4370
4689
  "/refunds/profile/list/export",
4371
- bodied(params ?? {}, options)
4690
+ { body: params ?? {} },
4691
+ options
4372
4692
  );
4373
4693
  }
4374
4694
  async disputes(params, options) {
4375
- return this.request("GET", "/disputes/list/export", queried(params, options));
4695
+ return runExport(this.request, "GET", "/disputes/list/export", queried(params), options);
4376
4696
  }
4377
4697
  async disputesForProfile(params, options) {
4378
- return this.request(
4698
+ return runExport(
4699
+ this.request,
4379
4700
  "GET",
4380
4701
  "/disputes/profile/list/export",
4381
- queried(params, options)
4702
+ queried(params),
4703
+ options
4382
4704
  );
4383
4705
  }
4384
4706
  async payouts(params, options) {
4385
- return this.request("POST", "/payouts/list/export", bodied(params, options));
4707
+ return runExport(this.request, "POST", "/payouts/list/export", { body: params }, options);
4386
4708
  }
4387
4709
  async payoutsForProfile(params, options) {
4388
- return this.request("POST", "/payouts/profile/list/export", bodied(params, options));
4710
+ return runExport(
4711
+ this.request,
4712
+ "POST",
4713
+ "/payouts/profile/list/export",
4714
+ { body: params },
4715
+ options
4716
+ );
4389
4717
  }
4390
4718
  async subscriptions(profileId, params, options) {
4391
- return this.request(
4719
+ return runExport(
4720
+ this.request,
4392
4721
  "GET",
4393
4722
  "/subscriptions/list/export",
4394
- queried(params, options, { "X-Profile-Id": profileId })
4723
+ queried(params, { "X-Profile-Id": profileId }),
4724
+ options
4395
4725
  );
4396
4726
  }
4397
4727
  async auditLog(params, options) {
4398
- return this.request("GET", "/audit/export", queried(params, options));
4728
+ return runExport(this.request, "GET", "/audit/export", queried(params), options);
4399
4729
  }
4400
4730
  };
4401
- var ACCEPT = {
4402
- csv: "text/csv",
4403
- json: "application/json",
4404
- pdf: "application/pdf"
4405
- };
4406
- function negotiated(options, format) {
4407
- const headers = { ...options.headers, Accept: ACCEPT[format] };
4408
- return format === "json" ? { ...options, headers } : { ...options, headers, responseType: "blob" };
4409
- }
4410
- function transactionBody(params, options) {
4411
- const format = options?.format ?? "json";
4412
- return negotiated({ body: { ...params, format } }, format);
4413
- }
4414
- function bodied(body, options) {
4415
- return negotiated({ body }, options?.format ?? "json");
4416
- }
4417
- function queried(params, options, headers) {
4418
- return negotiated(
4419
- { query: params ?? {}, ...headers ? { headers } : {} },
4420
- options?.format ?? "json"
4421
- );
4731
+ function queried(params, headers) {
4732
+ return { query: params ?? {}, ...headers ? { headers } : {} };
4422
4733
  }
4423
4734
 
4424
4735
  // src/resources/featureMatrix.ts
@@ -5791,6 +6102,112 @@ function findIdempotencyKey(headers) {
5791
6102
  }
5792
6103
  function noop() {
5793
6104
  }
6105
+ var ListenerFailure = class {
6106
+ constructor(cause) {
6107
+ this.cause = cause;
6108
+ }
6109
+ };
6110
+ var BodyStreamFailure = class {
6111
+ constructor(cause) {
6112
+ this.cause = cause;
6113
+ }
6114
+ };
6115
+ function abortError() {
6116
+ const error = new Error("The operation was aborted");
6117
+ error.name = "AbortError";
6118
+ return error;
6119
+ }
6120
+ function parseContentLength(header) {
6121
+ if (header === null || !/^\s*\d+\s*$/.test(header)) return null;
6122
+ const value = Number(header);
6123
+ return Number.isSafeInteger(value) ? value : null;
6124
+ }
6125
+ function readChunk(reader, signal) {
6126
+ if (signal.aborted) return Promise.reject(abortError());
6127
+ return new Promise((resolve, reject) => {
6128
+ const onAbort = () => reject(abortError());
6129
+ signal.addEventListener("abort", onAbort, { once: true });
6130
+ reader.read().then(
6131
+ (result) => {
6132
+ signal.removeEventListener("abort", onAbort);
6133
+ resolve(result);
6134
+ },
6135
+ (cause) => {
6136
+ signal.removeEventListener("abort", onAbort);
6137
+ reject(signal.aborted ? abortError() : new BodyStreamFailure(cause));
6138
+ }
6139
+ );
6140
+ });
6141
+ }
6142
+ function concatChunks(chunks, length) {
6143
+ const out = new Uint8Array(length);
6144
+ let offset = 0;
6145
+ for (const chunk of chunks) {
6146
+ out.set(chunk, offset);
6147
+ offset += chunk.byteLength;
6148
+ }
6149
+ return out.buffer;
6150
+ }
6151
+ async function receiveWithProgress(response, responseType, listener, attempt, signal, onActivity) {
6152
+ const headers = response.headers ?? new Headers();
6153
+ const total = parseContentLength(headers.get("content-length"));
6154
+ let loaded = 0;
6155
+ const notify = (chunk) => {
6156
+ try {
6157
+ listener({ loaded, total, chunk: chunk.slice(), headers, attempt });
6158
+ } catch (cause) {
6159
+ throw new ListenerFailure(cause);
6160
+ }
6161
+ };
6162
+ onActivity();
6163
+ notify(new Uint8Array(0));
6164
+ const body = response.body;
6165
+ if (!body || typeof body.getReader !== "function") {
6166
+ if (responseType === "blob") {
6167
+ const blob = await response.blob();
6168
+ const bytes3 = new Uint8Array(await blob.arrayBuffer());
6169
+ loaded = bytes3.byteLength;
6170
+ if (loaded > 0) notify(bytes3);
6171
+ return blob;
6172
+ }
6173
+ if (responseType === "arraybuffer") {
6174
+ const buffer = await response.arrayBuffer();
6175
+ loaded = buffer.byteLength;
6176
+ if (loaded > 0) notify(new Uint8Array(buffer));
6177
+ return buffer;
6178
+ }
6179
+ const text2 = await response.text();
6180
+ const bytes2 = new TextEncoder().encode(text2);
6181
+ loaded = bytes2.byteLength;
6182
+ if (loaded > 0) notify(bytes2);
6183
+ return text2 ? JSON.parse(text2) : void 0;
6184
+ }
6185
+ const reader = body.getReader();
6186
+ const chunks = [];
6187
+ try {
6188
+ for (; ; ) {
6189
+ const { done, value } = await readChunk(reader, signal);
6190
+ if (done) break;
6191
+ if (!value || value.byteLength === 0) continue;
6192
+ chunks.push(value);
6193
+ loaded += value.byteLength;
6194
+ onActivity();
6195
+ notify(value);
6196
+ }
6197
+ } catch (err) {
6198
+ reader.cancel().catch(noop);
6199
+ throw err;
6200
+ }
6201
+ const bytes = concatChunks(chunks, loaded);
6202
+ if (responseType === "blob") {
6203
+ return new Blob([bytes], { type: headers.get("content-type") ?? "" });
6204
+ }
6205
+ if (responseType === "arraybuffer") {
6206
+ return bytes;
6207
+ }
6208
+ const text = new TextDecoder().decode(bytes);
6209
+ return text ? JSON.parse(text) : void 0;
6210
+ }
5794
6211
  function combineSignals(signals) {
5795
6212
  const controller = new AbortController();
5796
6213
  const listeners = [];
@@ -6072,7 +6489,12 @@ var Delopay = class {
6072
6489
  emit("retry", { attempt, maxRetries: this.maxRetries, method, path });
6073
6490
  }
6074
6491
  const timeoutCtrl = new AbortController();
6075
- const timeoutId = setTimeout(() => timeoutCtrl.abort(), timeoutMs);
6492
+ let timeoutId = setTimeout(() => timeoutCtrl.abort(), timeoutMs);
6493
+ const restartIdleTimer = () => {
6494
+ if (timeoutCtrl.signal.aborted) return;
6495
+ clearTimeout(timeoutId);
6496
+ timeoutId = setTimeout(() => timeoutCtrl.abort(), timeoutMs);
6497
+ };
6076
6498
  const combined = combineSignals(
6077
6499
  callerSignal ? [timeoutCtrl.signal, callerSignal] : [timeoutCtrl.signal]
6078
6500
  );
@@ -6130,6 +6552,16 @@ var Delopay = class {
6130
6552
  }
6131
6553
  throw error;
6132
6554
  }
6555
+ if (options?.onDownloadProgress) {
6556
+ return await receiveWithProgress(
6557
+ response,
6558
+ options.responseType,
6559
+ options.onDownloadProgress,
6560
+ attempt,
6561
+ combined.signal,
6562
+ restartIdleTimer
6563
+ );
6564
+ }
6133
6565
  if (options?.responseType === "blob") {
6134
6566
  return await response.blob();
6135
6567
  }
@@ -6142,6 +6574,20 @@ var Delopay = class {
6142
6574
  if (err instanceof DelopayError || err instanceof DelopayAuthenticationError) {
6143
6575
  throw err;
6144
6576
  }
6577
+ if (err instanceof ListenerFailure) {
6578
+ throw err.cause;
6579
+ }
6580
+ if (err instanceof BodyStreamFailure) {
6581
+ const cause = err.cause;
6582
+ const detail = cause instanceof Error ? cause.message : String(cause ?? "body stream failed");
6583
+ lastError = new DelopayError(`Network error: ${detail}`, {
6584
+ status: 0,
6585
+ code: "NETWORK",
6586
+ type: "network_error"
6587
+ });
6588
+ if (isRetryable && attempt < this.maxRetries) continue;
6589
+ throw lastError;
6590
+ }
6145
6591
  if (err instanceof Error && err.name === "AbortError") {
6146
6592
  if (callerSignal?.aborted) {
6147
6593
  throw new DelopayError("Request aborted", {
@@ -6719,6 +7165,66 @@ function surchargeWordFor(branding, isDiscount, locale) {
6719
7165
  locale
6720
7166
  );
6721
7167
  }
7168
+ var NOTICE_SECTIONS = ["summary", "payment"];
7169
+ var NOTICES_PER_SECTION = 3;
7170
+ var NOTICE_LABEL_MAX_LENGTH = 80;
7171
+ var NOTICE_ICONS = [
7172
+ "lock",
7173
+ "shield",
7174
+ "check",
7175
+ "truck",
7176
+ "package",
7177
+ "refresh",
7178
+ "star",
7179
+ "support",
7180
+ "globe",
7181
+ "tag",
7182
+ "heart",
7183
+ "leaf",
7184
+ "clock",
7185
+ "bank"
7186
+ ];
7187
+ var NOTICE_ICON_FALLBACK = "check";
7188
+ var NOTICE_ICON_PATHS = {
7189
+ lock: [
7190
+ "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",
7191
+ "M8 10V7a4 4 0 0 1 8 0v3"
7192
+ ],
7193
+ 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"],
7194
+ check: ["M21 12a9 9 0 1 1-18 0a9 9 0 1 1 18 0z", "M8 12.5l3 3 5-6"],
7195
+ truck: [
7196
+ "M3 7.5h10v9H3z",
7197
+ "M13 11h4l3 3v2.5h-7z",
7198
+ "M8.8 18a1.8 1.8 0 1 1-3.6 0a1.8 1.8 0 1 1 3.6 0z",
7199
+ "M18.8 18a1.8 1.8 0 1 1-3.6 0a1.8 1.8 0 1 1 3.6 0z"
7200
+ ],
7201
+ package: [
7202
+ "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",
7203
+ "M12 22V12",
7204
+ "M3.29 7L12 12l8.71-5"
7205
+ ],
7206
+ refresh: ["M20 12a8 8 0 1 1-2.5-5.8", "M20 4v5h-5"],
7207
+ 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"],
7208
+ support: [
7209
+ "M5 13v-1a7 7 0 0 1 14 0v1",
7210
+ "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",
7211
+ "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",
7212
+ "M19 17.7v.8a2.5 2.5 0 0 1-2.5 2.5H13"
7213
+ ],
7214
+ globe: [
7215
+ "M21 12a9 9 0 1 1-18 0a9 9 0 1 1 18 0z",
7216
+ "M3 12h18",
7217
+ "M12 3a14 14 0 0 1 0 18a14 14 0 0 1 0-18z"
7218
+ ],
7219
+ 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"],
7220
+ 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"],
7221
+ 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"],
7222
+ clock: ["M21 12a9 9 0 1 1-18 0a9 9 0 1 1 18 0z", "M12 7v5l3 2"],
7223
+ bank: ["M3 9.5 12 4l9 5.5", "M5 10v8M9.5 10v8M14.5 10v8M19 10v8", "M3 20h18"]
7224
+ };
7225
+ function isNoticeIcon(value) {
7226
+ return typeof value === "string" && NOTICE_ICONS.includes(value);
7227
+ }
6722
7228
  var FONT_STACKS = {
6723
7229
  inter: "'Inter Variable', 'Inter', system-ui, -apple-system, sans-serif",
6724
7230
  system: "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif",
@@ -6888,6 +7394,96 @@ var DEFAULT_BADGES_DARK = [
6888
7394
  borderColor: "#1e40af"
6889
7395
  }
6890
7396
  ];
7397
+ var DEFAULT_NOTICES = [
7398
+ {
7399
+ id: "secure",
7400
+ section: "summary",
7401
+ icon: "shield",
7402
+ label: "Secure payment",
7403
+ labelTranslations: {
7404
+ de: "Sichere Zahlung",
7405
+ fr: "Paiement s\xE9curis\xE9",
7406
+ es: "Pago seguro",
7407
+ it: "Pagamento sicuro",
7408
+ nl: "Veilig betalen",
7409
+ zh: "\u5B89\u5168\u652F\u4ED8",
7410
+ "zh-Hant": "\u5B89\u5168\u4ED8\u6B3E",
7411
+ hi: "\u0938\u0941\u0930\u0915\u094D\u0937\u093F\u0924 \u092D\u0941\u0917\u0924\u093E\u0928",
7412
+ ar: "\u062F\u0641\u0639 \u0622\u0645\u0646"
7413
+ }
7414
+ },
7415
+ {
7416
+ id: "ssl",
7417
+ section: "summary",
7418
+ icon: "lock",
7419
+ label: "Encrypted \xB7 256-bit SSL",
7420
+ labelTranslations: {
7421
+ de: "Verschl\xFCsselt \xB7 256-Bit-SSL",
7422
+ fr: "Chiffr\xE9 \xB7 SSL 256 bits",
7423
+ es: "Cifrado \xB7 SSL de 256 bits",
7424
+ it: "Crittografato \xB7 SSL a 256 bit",
7425
+ nl: "Versleuteld \xB7 256-bit SSL",
7426
+ zh: "\u52A0\u5BC6 \xB7 256 \u4F4D SSL",
7427
+ "zh-Hant": "\u52A0\u5BC6 \xB7 256 \u4F4D\u5143 SSL",
7428
+ hi: "\u090F\u0928\u094D\u0915\u094D\u0930\u093F\u092A\u094D\u091F\u0947\u0921 \xB7 256-\u092C\u093F\u091F SSL",
7429
+ ar: "\u0645\u0634\u0641\u0651\u0631 \xB7 SSL \u0628\u0637\u0648\u0644 256 \u0628\u062A"
7430
+ }
7431
+ }
7432
+ ];
7433
+ function defaultNotices() {
7434
+ return DEFAULT_NOTICES.map(cloneNotice);
7435
+ }
7436
+ function cloneNotice(notice) {
7437
+ return { ...notice, labelTranslations: { ...notice.labelTranslations } };
7438
+ }
7439
+ function hexChannels(hex) {
7440
+ const raw = /^#([0-9a-f]{6})$/i.exec(hex.trim())?.[1];
7441
+ if (!raw) return null;
7442
+ return [
7443
+ parseInt(raw.slice(0, 2), 16),
7444
+ parseInt(raw.slice(2, 4), 16),
7445
+ parseInt(raw.slice(4, 6), 16)
7446
+ ];
7447
+ }
7448
+ function isThemeTintedBadgeColouring(textColor, fill, border) {
7449
+ const primary = hexChannels(textColor);
7450
+ const bg = hexChannels(fill);
7451
+ const line = hexChannels(border);
7452
+ if (!primary || !bg || !line) return false;
7453
+ const mixed = (surface, to, share) => Math.round(surface + (to - surface) * share);
7454
+ return primary.every((p, i) => {
7455
+ for (let surface = 0; surface <= 255; surface += 1) {
7456
+ if (mixed(surface, p, 0.08) === bg[i] && mixed(surface, p, 0.3) === line[i]) return true;
7457
+ }
7458
+ return false;
7459
+ });
7460
+ }
7461
+ function isDefaultBadgeSet(badges) {
7462
+ if (badges.length !== DEFAULT_BADGES.length) return false;
7463
+ const sameContent = badges.every(
7464
+ (badge, i) => badge.id === DEFAULT_BADGES[i]?.id && badge.label === DEFAULT_BADGES[i]?.label
7465
+ );
7466
+ if (!sameContent) return false;
7467
+ const colouring = (set) => set.map((b) => [b.textColor, b.backgroundColor, b.borderColor ?? ""].join("|").toLowerCase()).join("/");
7468
+ const mine = colouring(badges);
7469
+ if (mine === colouring(DEFAULT_BADGES) || mine === colouring(DEFAULT_BADGES_DARK)) return true;
7470
+ const [first] = badges;
7471
+ const border = first?.borderColor;
7472
+ if (!first || !border) return false;
7473
+ const same = (a, b) => (a ?? "").toLowerCase() === b.toLowerCase();
7474
+ return badges.every(
7475
+ (b) => same(b.textColor, first.textColor) && same(b.backgroundColor, first.backgroundColor) && same(b.borderColor, border)
7476
+ ) && isThemeTintedBadgeColouring(first.textColor, first.backgroundColor, border);
7477
+ }
7478
+ function resolveNoticesAndBadges(savedBadges, savedNotices) {
7479
+ if (savedNotices !== null) {
7480
+ return { trustBadges: savedBadges ?? [], notices: savedNotices };
7481
+ }
7482
+ if (savedBadges === null || isDefaultBadgeSet(savedBadges)) {
7483
+ return { trustBadges: [], notices: defaultNotices() };
7484
+ }
7485
+ return { trustBadges: savedBadges, notices: [] };
7486
+ }
6891
7487
  var METHOD_SECTION_ORDER_KEY = "methodSectionOrder";
6892
7488
  var METHOD_SECTION_LABELS_KEY = "methodSectionLabels";
6893
7489
  var MIN_SECTION_ORDER = 1;
@@ -7174,7 +7770,11 @@ var DEFAULT_BRANDING_BASE = {
7174
7770
  var DEFAULT_BRANDING = {
7175
7771
  ...DEFAULT_BRANDING_BASE,
7176
7772
  ...LIGHT_PALETTE,
7177
- trustBadges: DEFAULT_BADGES.map((b) => ({ ...b })),
7773
+ // No badges by default since todos#218 — notices took their place.
7774
+ // `DEFAULT_BADGES` stays exported because `isDefaultBadgeSet` still has to
7775
+ // recognise the pair on shops saved before.
7776
+ trustBadges: [],
7777
+ notices: defaultNotices(),
7178
7778
  customFields: [],
7179
7779
  methodSectionOrder: defaultMethodSectionOrder(),
7180
7780
  methodSectionLabels: {}
@@ -7197,7 +7797,8 @@ var DEFAULT_BRANDING_DARK = {
7197
7797
  // end of the ramp — 10.69 and 9.29 against the dark surface, also pinned.
7198
7798
  surchargeColor: "#fbbf24",
7199
7799
  discountColor: "#34d399",
7200
- trustBadges: DEFAULT_BADGES_DARK.map((b) => ({ ...b })),
7800
+ trustBadges: [],
7801
+ notices: defaultNotices(),
7201
7802
  customFields: [],
7202
7803
  methodSectionOrder: defaultMethodSectionOrder(),
7203
7804
  methodSectionLabels: {}
@@ -7209,6 +7810,7 @@ function cloneBranding(b) {
7209
7810
  return {
7210
7811
  ...b,
7211
7812
  trustBadges: b.trustBadges.map((badge) => ({ ...badge })),
7813
+ notices: b.notices.map(cloneNotice),
7212
7814
  customFields: b.customFields.map(cloneCustomField),
7213
7815
  methodSectionOrder: { ...b.methodSectionOrder },
7214
7816
  methodSectionLabels: Object.fromEntries(
@@ -7318,6 +7920,80 @@ function encodeBadges(badges) {
7318
7920
  }))
7319
7921
  );
7320
7922
  }
7923
+ var NOTICE_ID_MAX_LENGTH = 40;
7924
+ function capNoticeText(value) {
7925
+ return Array.from(value).slice(0, NOTICE_LABEL_MAX_LENGTH).join("");
7926
+ }
7927
+ function normalizeNotices(list) {
7928
+ const seen = /* @__PURE__ */ new Set();
7929
+ const perSection = /* @__PURE__ */ new Map();
7930
+ const out = [];
7931
+ list.forEach((raw, index) => {
7932
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
7933
+ const src = raw;
7934
+ const label = typeof src["label"] === "string" ? capNoticeText(src["label"]) : "";
7935
+ const labelTranslations = {};
7936
+ for (const [locale, text] of Object.entries(parseTranslations(src["labelTranslations"]))) {
7937
+ labelTranslations[locale] = capNoticeText(text);
7938
+ }
7939
+ if (label.trim().length === 0 && Object.keys(labelTranslations).length === 0) return;
7940
+ const section = pickEnum(src["section"], NOTICE_SECTIONS, "summary");
7941
+ const used = perSection.get(section) ?? 0;
7942
+ if (used >= NOTICES_PER_SECTION) return;
7943
+ perSection.set(section, used + 1);
7944
+ let id = typeof src["id"] === "string" ? src["id"].replace(/[^A-Za-z0-9_-]/g, "").slice(0, NOTICE_ID_MAX_LENGTH) : "";
7945
+ if (!id || seen.has(id)) id = `notice-${index + 1}`;
7946
+ while (seen.has(id)) id = `${id}x`;
7947
+ seen.add(id);
7948
+ out.push({
7949
+ id,
7950
+ section,
7951
+ icon: isNoticeIcon(src["icon"]) ? src["icon"] : NOTICE_ICON_FALLBACK,
7952
+ label,
7953
+ labelTranslations
7954
+ });
7955
+ });
7956
+ return out;
7957
+ }
7958
+ function decodeNotices(raw) {
7959
+ if (raw === void 0) return null;
7960
+ let parsed;
7961
+ try {
7962
+ parsed = JSON.parse(raw);
7963
+ } catch {
7964
+ return null;
7965
+ }
7966
+ return Array.isArray(parsed) ? normalizeNotices(parsed) : null;
7967
+ }
7968
+ function parseNoticesLoose(raw) {
7969
+ if (typeof raw === "string") return decodeNotices(raw);
7970
+ return Array.isArray(raw) ? normalizeNotices(raw) : null;
7971
+ }
7972
+ function encodeNotices(notices) {
7973
+ return JSON.stringify(
7974
+ notices.map((n) => {
7975
+ const translations = Object.entries(n.labelTranslations).filter(
7976
+ ([, text]) => text.trim().length > 0
7977
+ );
7978
+ return {
7979
+ id: n.id,
7980
+ section: n.section,
7981
+ icon: n.icon,
7982
+ label: n.label,
7983
+ ...translations.length > 0 ? { labelTranslations: Object.fromEntries(translations) } : {}
7984
+ };
7985
+ })
7986
+ );
7987
+ }
7988
+ function noticeText(notice, locale) {
7989
+ return translationFor(notice.labelTranslations, locale) ?? notice.label;
7990
+ }
7991
+ function noticesIn(notices, section) {
7992
+ return notices.filter((n) => n.section === section).slice(0, NOTICES_PER_SECTION);
7993
+ }
7994
+ function shownNotices(notices, section, locale) {
7995
+ return noticesIn(notices, section).map((notice) => ({ notice, text: noticeText(notice, locale).trim() })).filter((entry) => entry.text.length > 0);
7996
+ }
7321
7997
  var CUSTOM_FIELDS_MAX = 20;
7322
7998
  var CUSTOM_FIELD_KEY_PATTERN = /^[A-Za-z][A-Za-z0-9_-]{0,39}$/;
7323
7999
  var ALL_CUSTOM_FIELD_TYPES = [
@@ -7661,7 +8337,10 @@ function customFieldOptionLabel(option, locale) {
7661
8337
  function decodeBranding(source) {
7662
8338
  if (!source) return cloneBranding(DEFAULT_BRANDING);
7663
8339
  const extras = source.sdk_ui_rules?.[BRANDING_GROUP_KEY] ?? {};
7664
- const decodedBadges = decodeBadges(extras["trustBadges"]);
8340
+ const trustRow = resolveNoticesAndBadges(
8341
+ decodeBadges(extras["trustBadges"]),
8342
+ decodeNotices(extras["notices"])
8343
+ );
7665
8344
  const decodedCustomFields = decodeCustomFields(extras["customFields"]);
7666
8345
  const displayName = s(source.merchant_name) || s(source.seller_name);
7667
8346
  const logoUrl = s(source.merchant_logo) || s(source.logo);
@@ -7840,7 +8519,8 @@ function decodeBranding(source) {
7840
8519
  totalLabel: s(extras["totalLabel"]) || DEFAULT_BRANDING.totalLabel,
7841
8520
  showCurrencyCode: parseBool(extras["showCurrencyCode"], DEFAULT_BRANDING.showCurrencyCode),
7842
8521
  showOrderItems: parseBool(extras["showOrderItems"], DEFAULT_BRANDING.showOrderItems),
7843
- trustBadges: decodedBadges ?? DEFAULT_BRANDING.trustBadges.map((b) => ({ ...b })),
8522
+ trustBadges: trustRow.trustBadges,
8523
+ notices: trustRow.notices,
7844
8524
  customFields: decodedCustomFields ?? [],
7845
8525
  methodSectionOrder: decodeMethodSectionOrder(extras[METHOD_SECTION_ORDER_KEY]),
7846
8526
  methodSectionLabels: decodeMethodSectionLabels(extras[METHOD_SECTION_LABELS_KEY]),
@@ -8124,9 +8804,14 @@ function encodeBranding(branding, base) {
8124
8804
  nomupayApplePayButtonType: branding.nomupayApplePayButtonType,
8125
8805
  nomupayGooglePayButtonColor: branding.nomupayGooglePayButtonColor,
8126
8806
  nomupayGooglePayButtonType: branding.nomupayGooglePayButtonType,
8127
- trustBadges: encodeBadges(branding.trustBadges),
8807
+ // Always written, `[]` included — its presence is what stops a later
8808
+ // decode from migrating the shop again (`resolveNoticesAndBadges`).
8809
+ notices: encodeNotices(branding.notices),
8128
8810
  [METHOD_SECTION_ORDER_KEY]: encodeMethodSectionOrder(branding.methodSectionOrder)
8129
8811
  };
8812
+ if (branding.trustBadges.length > 0) {
8813
+ extras["trustBadges"] = encodeBadges(branding.trustBadges);
8814
+ }
8130
8815
  const sectionLabels = encodeMethodSectionLabels(branding.methodSectionLabels);
8131
8816
  if (sectionLabels) extras[METHOD_SECTION_LABELS_KEY] = sectionLabels;
8132
8817
  if (branding.customFields.length > 0) {
@@ -8192,7 +8877,10 @@ function parseImportedBranding(raw) {
8192
8877
  const dflt = DEFAULT_BRANDING;
8193
8878
  const sStr = (v, fallback) => typeof v === "string" ? v : fallback;
8194
8879
  const sHex = (v, fallback) => typeof v === "string" && isHexColor(v) ? v : fallback;
8195
- const trustBadges = parseTrustBadgesLoose(root["trustBadges"]) ?? dflt.trustBadges.map((b) => ({ ...b }));
8880
+ const { trustBadges, notices } = resolveNoticesAndBadges(
8881
+ parseTrustBadgesLoose(root["trustBadges"]),
8882
+ parseNoticesLoose(root["notices"])
8883
+ );
8196
8884
  const customFields = parseCustomFieldsLoose(root["customFields"]) ?? [];
8197
8885
  const labelStyle = (() => {
8198
8886
  const v = root["labelStyle"];
@@ -8335,6 +9023,7 @@ function parseImportedBranding(raw) {
8335
9023
  showCurrencyCode: parseBool(root["showCurrencyCode"], dflt.showCurrencyCode),
8336
9024
  showOrderItems: parseBool(root["showOrderItems"], dflt.showOrderItems),
8337
9025
  trustBadges,
9026
+ notices,
8338
9027
  customFields,
8339
9028
  // An export writes the decoded maps; a hand-written file may carry the
8340
9029
  // JSON strings the bag uses. Both are accepted, and neither is required.
@@ -9531,6 +10220,7 @@ var encodeNativePanes = encodePanes;
9531
10220
  DEFAULT_BADGES_DARK,
9532
10221
  DEFAULT_BRANDING,
9533
10222
  DEFAULT_BRANDING_DARK,
10223
+ DEFAULT_NOTICES,
9534
10224
  Delopay,
9535
10225
  DelopayAuthenticationError,
9536
10226
  DelopayError,
@@ -9552,6 +10242,12 @@ var encodeNativePanes = encodePanes;
9552
10242
  NATIVE_PANE_CATEGORY_KEYS,
9553
10243
  NATIVE_PANE_ICON_KEYS,
9554
10244
  NOMUPAY_FORM_STYLES,
10245
+ NOTICES_PER_SECTION,
10246
+ NOTICE_ICONS,
10247
+ NOTICE_ICON_FALLBACK,
10248
+ NOTICE_ICON_PATHS,
10249
+ NOTICE_LABEL_MAX_LENGTH,
10250
+ NOTICE_SECTIONS,
9555
10251
  OperationLimits,
9556
10252
  PANES_MAX,
9557
10253
  PANE_CATEGORY_KEYS,
@@ -9609,6 +10305,7 @@ var encodeNativePanes = encodePanes;
9609
10305
  cloneBranding,
9610
10306
  cloneCustomField,
9611
10307
  cloneNativePane,
10308
+ cloneNotice,
9612
10309
  clonePane,
9613
10310
  compareSections,
9614
10311
  contrastRatio,
@@ -9624,11 +10321,13 @@ var encodeNativePanes = encodePanes;
9624
10321
  decodeMethodSectionLabels,
9625
10322
  decodeMethodSectionOrder,
9626
10323
  decodeNativePanes,
10324
+ decodeNotices,
9627
10325
  decodePanes,
9628
10326
  defaultBranding,
9629
10327
  defaultCustomFieldVisibility,
9630
10328
  defaultMethodSectionOrder,
9631
10329
  defaultNativePane,
10330
+ defaultNotices,
9632
10331
  defaultOperatorForSource,
9633
10332
  defaultPane,
9634
10333
  emptyPaneCatalog,
@@ -9638,6 +10337,7 @@ var encodeNativePanes = encodePanes;
9638
10337
  encodeMethodSectionLabels,
9639
10338
  encodeMethodSectionOrder,
9640
10339
  encodeNativePanes,
10340
+ encodeNotices,
9641
10341
  encodePanes,
9642
10342
  evaluateCustomFieldCondition,
9643
10343
  evaluateCustomFieldVisibility,
@@ -9648,13 +10348,17 @@ var encodeNativePanes = encodePanes;
9648
10348
  inputPadValue,
9649
10349
  isCheckboxChecked,
9650
10350
  isDarkSurface,
10351
+ isDefaultBadgeSet,
9651
10352
  isHexColor,
10353
+ isNoticeIcon,
9652
10354
  isSubscriptionDisputeWebhook,
9653
10355
  isSubscriptionLifecycleWebhook,
9654
10356
  knownSectionLabelKey,
9655
10357
  leaf,
9656
10358
  logoDimensions,
9657
10359
  nativePaneMethodInfo,
10360
+ noticeText,
10361
+ noticesIn,
9658
10362
  offerablePaneMethods,
9659
10363
  paneCatalogFor,
9660
10364
  paneDisplayDefaults,
@@ -9663,6 +10367,7 @@ var encodeNativePanes = encodePanes;
9663
10367
  paneViewVisibility,
9664
10368
  parseCustomFieldsLoose,
9665
10369
  parseImportedBranding,
10370
+ parseNoticesLoose,
9666
10371
  programToTree,
9667
10372
  radiusValue,
9668
10373
  readableInkOn,
@@ -9670,12 +10375,14 @@ var encodeNativePanes = encodePanes;
9670
10375
  resolveAirwallexLabelStyle,
9671
10376
  resolveApplePayButtonStyle,
9672
10377
  resolveGooglePayButtonColor,
10378
+ resolveNoticesAndBadges,
9673
10379
  resolveStripeTheme,
9674
10380
  ruleMatchToTree,
9675
10381
  sanitizeCustomCss,
9676
10382
  sectionLabel,
9677
10383
  sectionOrderOf,
9678
10384
  shadowFor,
10385
+ shownNotices,
9679
10386
  stripeSpacingValues,
9680
10387
  surchargeFigurePlan,
9681
10388
  surchargeShowsLabel,