@delopay/sdk 0.74.0 → 0.76.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
@@ -20,6 +20,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/internal.ts
21
21
  var internal_exports = {};
22
22
  __export(internal_exports, {
23
+ ALL_CUSTOM_FIELD_CONDITION_SOURCES: () => ALL_CUSTOM_FIELD_CONDITION_SOURCES,
24
+ ALL_CUSTOM_FIELD_OPERATORS: () => ALL_CUSTOM_FIELD_OPERATORS,
23
25
  ALL_CUSTOM_FIELD_TYPES: () => ALL_CUSTOM_FIELD_TYPES,
24
26
  Admin: () => Admin,
25
27
  AdminPortal: () => AdminPortal,
@@ -29,9 +31,14 @@ __export(internal_exports, {
29
31
  AvailabilityOverrides: () => AvailabilityOverrides,
30
32
  BRANDING_EXPORT_FORMAT: () => BRANDING_EXPORT_FORMAT,
31
33
  BRANDING_EXPORT_VERSION: () => BRANDING_EXPORT_VERSION,
34
+ CHECKBOX_CHECKED: () => CHECKBOX_CHECKED,
35
+ CHECKBOX_UNCHECKED: () => CHECKBOX_UNCHECKED,
32
36
  CUSTOM_CSS_MAX_LENGTH: () => CUSTOM_CSS_MAX_LENGTH,
33
37
  CUSTOM_FIELDS_MAX: () => CUSTOM_FIELDS_MAX,
38
+ CUSTOM_FIELD_CONDITIONS_MAX: () => CUSTOM_FIELD_CONDITIONS_MAX,
34
39
  CUSTOM_FIELD_KEY_PATTERN: () => CUSTOM_FIELD_KEY_PATTERN,
40
+ CUSTOM_FIELD_OPERATORS_BY_SOURCE: () => CUSTOM_FIELD_OPERATORS_BY_SOURCE,
41
+ CUSTOM_FIELD_VALUELESS_OPERATORS: () => CUSTOM_FIELD_VALUELESS_OPERATORS,
35
42
  Cache: () => Cache,
36
43
  CardIssuers: () => CardIssuers,
37
44
  Cards: () => Cards,
@@ -65,19 +72,27 @@ __export(internal_exports, {
65
72
  buttonPadValue: () => buttonPadValue,
66
73
  cloneBranding: () => cloneBranding,
67
74
  cloneCustomField: () => cloneCustomField,
75
+ customFieldContextFromMetadata: () => customFieldContextFromMetadata,
76
+ customFieldIsTextLike: () => customFieldIsTextLike,
77
+ customFieldOperatorTakesValue: () => customFieldOperatorTakesValue,
68
78
  customFieldOptionLabel: () => customFieldOptionLabel,
69
79
  customFieldText: () => customFieldText,
70
80
  decodeBadges: () => decodeBadges,
71
81
  decodeBranding: () => decodeBranding,
72
82
  decodeCustomFields: () => decodeCustomFields,
73
83
  defaultBranding: () => defaultBranding,
84
+ defaultCustomFieldVisibility: () => defaultCustomFieldVisibility,
85
+ defaultOperatorForSource: () => defaultOperatorForSource,
74
86
  encodeBadges: () => encodeBadges,
75
87
  encodeBranding: () => encodeBranding,
76
88
  encodeCustomFields: () => encodeCustomFields,
89
+ evaluateCustomFieldCondition: () => evaluateCustomFieldCondition,
90
+ evaluateCustomFieldVisibility: () => evaluateCustomFieldVisibility,
77
91
  feeProgram: () => feeProgram,
78
92
  fontStack: () => fontStack,
79
93
  fontWeightValue: () => fontWeightValue,
80
94
  inputPadValue: () => inputPadValue,
95
+ isCheckboxChecked: () => isCheckboxChecked,
81
96
  isDarkSurface: () => isDarkSurface,
82
97
  isHexColor: () => isHexColor,
83
98
  leaf: () => leaf,
@@ -90,7 +105,8 @@ __export(internal_exports, {
90
105
  sanitizeCustomCss: () => sanitizeCustomCss,
91
106
  shadowFor: () => shadowFor,
92
107
  surfacePadValue: () => surfacePadValue,
93
- verticalGapValue: () => verticalGapValue
108
+ verticalGapValue: () => verticalGapValue,
109
+ visibleCustomFields: () => visibleCustomFields
94
110
  });
95
111
  module.exports = __toCommonJS(internal_exports);
96
112
 
@@ -4007,7 +4023,11 @@ function cloneCustomField(f) {
4007
4023
  labelTranslations: { ...f.labelTranslations },
4008
4024
  placeholderTranslations: { ...f.placeholderTranslations },
4009
4025
  helpTextTranslations: { ...f.helpTextTranslations },
4010
- options: f.options.map((o) => ({ ...o, labelTranslations: { ...o.labelTranslations } }))
4026
+ options: f.options.map((o) => ({ ...o, labelTranslations: { ...o.labelTranslations } })),
4027
+ visibility: {
4028
+ ...f.visibility,
4029
+ conditions: f.visibility.conditions.map((c) => ({ ...c }))
4030
+ }
4011
4031
  };
4012
4032
  }
4013
4033
  var CUSTOM_CSS_MAX_LENGTH = 5e4;
@@ -4093,8 +4113,57 @@ var ALL_CUSTOM_FIELD_TYPES = [
4093
4113
  "textarea",
4094
4114
  "password",
4095
4115
  "email",
4096
- "select"
4116
+ "select",
4117
+ "checkbox"
4118
+ ];
4119
+ var CHECKBOX_CHECKED = "true";
4120
+ var CHECKBOX_UNCHECKED = "false";
4121
+ function isCheckboxChecked(value) {
4122
+ return typeof value === "string" && value.trim().toLowerCase() === CHECKBOX_CHECKED;
4123
+ }
4124
+ function customFieldIsTextLike(type) {
4125
+ return type !== "select" && type !== "checkbox";
4126
+ }
4127
+ var CUSTOM_FIELD_CONDITIONS_MAX = 10;
4128
+ var ALL_CUSTOM_FIELD_CONDITION_SOURCES = [
4129
+ "metadata",
4130
+ "currency",
4131
+ "amount"
4132
+ ];
4133
+ var ALL_CUSTOM_FIELD_OPERATORS = [
4134
+ "equals",
4135
+ "not_equals",
4136
+ "contains",
4137
+ "not_contains",
4138
+ "starts_with",
4139
+ "ends_with",
4140
+ "in",
4141
+ "not_in",
4142
+ "exists",
4143
+ "not_exists",
4144
+ "gt",
4145
+ "gte",
4146
+ "lt",
4147
+ "lte"
4097
4148
  ];
4149
+ var CUSTOM_FIELD_OPERATORS_BY_SOURCE = {
4150
+ metadata: ALL_CUSTOM_FIELD_OPERATORS,
4151
+ currency: ["equals", "not_equals", "in", "not_in"],
4152
+ amount: ["equals", "not_equals", "gt", "gte", "lt", "lte"]
4153
+ };
4154
+ var CUSTOM_FIELD_VALUELESS_OPERATORS = [
4155
+ "exists",
4156
+ "not_exists"
4157
+ ];
4158
+ function customFieldOperatorTakesValue(operator) {
4159
+ return !CUSTOM_FIELD_VALUELESS_OPERATORS.includes(operator);
4160
+ }
4161
+ function defaultOperatorForSource(source) {
4162
+ return CUSTOM_FIELD_OPERATORS_BY_SOURCE[source][0] ?? "equals";
4163
+ }
4164
+ function defaultCustomFieldVisibility() {
4165
+ return { mode: "always", match: "all", conditions: [] };
4166
+ }
4098
4167
  function parseTranslations(raw) {
4099
4168
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return {};
4100
4169
  const out = {};
@@ -4103,6 +4172,41 @@ function parseTranslations(raw) {
4103
4172
  }
4104
4173
  return out;
4105
4174
  }
4175
+ function normalizeCondition(raw, index) {
4176
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
4177
+ const c = raw;
4178
+ const source = pickEnum(
4179
+ c["source"],
4180
+ ALL_CUSTOM_FIELD_CONDITION_SOURCES,
4181
+ "metadata"
4182
+ );
4183
+ const allowed = CUSTOM_FIELD_OPERATORS_BY_SOURCE[source];
4184
+ const operator = pickEnum(
4185
+ c["operator"],
4186
+ allowed,
4187
+ defaultOperatorForSource(source)
4188
+ );
4189
+ const rawValue = c["value"];
4190
+ return {
4191
+ id: typeof c["id"] === "string" && c["id"] ? c["id"] : `cond-${index}`,
4192
+ source,
4193
+ // Only metadata conditions carry a key; drop anything else so the
4194
+ // encoded form stays canonical.
4195
+ key: source === "metadata" && typeof c["key"] === "string" ? c["key"].trim() : "",
4196
+ operator,
4197
+ value: typeof rawValue === "string" ? rawValue : typeof rawValue === "number" || typeof rawValue === "boolean" ? String(rawValue) : ""
4198
+ };
4199
+ }
4200
+ function normalizeVisibility(raw) {
4201
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return defaultCustomFieldVisibility();
4202
+ const v = raw;
4203
+ const conditions = Array.isArray(v["conditions"]) ? v["conditions"].slice(0, CUSTOM_FIELD_CONDITIONS_MAX).map(normalizeCondition).filter((c) => c !== null) : [];
4204
+ return {
4205
+ mode: pickEnum(v["mode"], ["always", "match"], "always"),
4206
+ match: pickEnum(v["match"], ["all", "any"], "all"),
4207
+ conditions
4208
+ };
4209
+ }
4106
4210
  function parseBoundedInt(raw) {
4107
4211
  const n = typeof raw === "number" ? raw : typeof raw === "string" ? Number(raw) : NaN;
4108
4212
  if (!Number.isInteger(n) || n < 0) return null;
@@ -4122,8 +4226,11 @@ function normalizeCustomField(raw, index) {
4122
4226
  labelTranslations: parseTranslations(o["labelTranslations"])
4123
4227
  };
4124
4228
  }).filter((o) => o.value.length > 0) : [];
4125
- const minLength = parseBoundedInt(f["minLength"]);
4126
- const maxLength = parseBoundedInt(f["maxLength"]);
4229
+ const textLike = customFieldIsTextLike(type);
4230
+ const minLength = textLike ? parseBoundedInt(f["minLength"]) : null;
4231
+ const maxLength = textLike ? parseBoundedInt(f["maxLength"]) : null;
4232
+ const rawDefault = typeof f["defaultValue"] === "string" ? f["defaultValue"] : "";
4233
+ const defaultValue = type === "checkbox" ? isCheckboxChecked(rawDefault) ? CHECKBOX_CHECKED : CHECKBOX_UNCHECKED : rawDefault;
4127
4234
  return {
4128
4235
  id: typeof f["id"] === "string" && f["id"] ? f["id"] : `field-${index}`,
4129
4236
  key,
@@ -4139,8 +4246,9 @@ function normalizeCustomField(raw, index) {
4139
4246
  minLength,
4140
4247
  // Guard inverted bounds at decode so consumers never see min > max.
4141
4248
  maxLength: maxLength !== null && minLength !== null && maxLength < minLength ? null : maxLength,
4142
- defaultValue: typeof f["defaultValue"] === "string" ? f["defaultValue"] : "",
4143
- options
4249
+ defaultValue,
4250
+ options,
4251
+ visibility: normalizeVisibility(f["visibility"])
4144
4252
  };
4145
4253
  }
4146
4254
  function parseCustomFieldsLoose(raw) {
@@ -4181,13 +4289,125 @@ function encodeCustomFields(fields) {
4181
4289
  ...nonEmpty(f.helpTextTranslations) ? { helpTextTranslations: nonEmpty(f.helpTextTranslations) } : {},
4182
4290
  ...f.required ? { required: true } : {},
4183
4291
  ...f.enabled ? {} : { enabled: false },
4184
- ...f.minLength !== null ? { minLength: f.minLength } : {},
4185
- ...f.maxLength !== null ? { maxLength: f.maxLength } : {},
4186
- ...f.defaultValue ? { defaultValue: f.defaultValue } : {},
4187
- ...f.type === "select" ? { options: f.options } : {}
4292
+ // Length bounds only exist for free-text types; a choice control that
4293
+ // still carries them is stale state the decoder would drop anyway.
4294
+ ...customFieldIsTextLike(f.type) && f.minLength !== null ? { minLength: f.minLength } : {},
4295
+ ...customFieldIsTextLike(f.type) && f.maxLength !== null ? { maxLength: f.maxLength } : {},
4296
+ // A checkbox persists only "starts ticked"; unticked is the decoder's
4297
+ // default, so writing 'false' would be noise on every such field.
4298
+ ...f.type === "checkbox" ? isCheckboxChecked(f.defaultValue) ? { defaultValue: CHECKBOX_CHECKED } : {} : f.defaultValue ? { defaultValue: f.defaultValue } : {},
4299
+ ...f.type === "select" ? { options: f.options } : {},
4300
+ // Omitted for unconditional fields so the stored blob (and every
4301
+ // pre-feature payload) stays byte-identical to what it was.
4302
+ ...f.visibility.mode === "match" ? { visibility: encodeVisibility(f.visibility) } : {}
4188
4303
  }))
4189
4304
  );
4190
4305
  }
4306
+ function encodeVisibility(v) {
4307
+ return {
4308
+ mode: v.mode,
4309
+ match: v.match,
4310
+ conditions: v.conditions.map((c) => ({
4311
+ id: c.id,
4312
+ source: c.source,
4313
+ ...c.source === "metadata" && c.key ? { key: c.key } : {},
4314
+ operator: c.operator,
4315
+ ...customFieldOperatorTakesValue(c.operator) && c.value ? { value: c.value } : {}
4316
+ }))
4317
+ };
4318
+ }
4319
+ function customFieldContextFromMetadata(raw) {
4320
+ const out = {};
4321
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return out;
4322
+ for (const [key, value] of Object.entries(raw)) {
4323
+ const flat = flattenMetadataValue(value);
4324
+ if (flat !== null) out[key] = flat;
4325
+ }
4326
+ return out;
4327
+ }
4328
+ function flattenMetadataValue(value) {
4329
+ if (typeof value === "string") return value;
4330
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
4331
+ if (value === null || value === void 0) return null;
4332
+ if (Array.isArray(value)) {
4333
+ return value.map((v) => flattenMetadataValue(v)).filter((v) => v !== null).join(",");
4334
+ }
4335
+ try {
4336
+ return JSON.stringify(value);
4337
+ } catch {
4338
+ return null;
4339
+ }
4340
+ }
4341
+ function norm(value) {
4342
+ return value.trim().toLowerCase();
4343
+ }
4344
+ var DECIMAL_NUMBER_PATTERN = /^[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?$/;
4345
+ function numeric(value) {
4346
+ const trimmed = value.trim();
4347
+ if (!DECIMAL_NUMBER_PATTERN.test(trimmed)) return null;
4348
+ const n = Number(trimmed);
4349
+ return Number.isFinite(n) ? n : null;
4350
+ }
4351
+ function splitList(value) {
4352
+ return value.split(",").map((part) => norm(part)).filter((part) => part.length > 0);
4353
+ }
4354
+ function operandFor(condition, ctx) {
4355
+ switch (condition.source) {
4356
+ case "currency":
4357
+ return ctx.currency;
4358
+ case "amount":
4359
+ return String(ctx.amount);
4360
+ case "metadata":
4361
+ return Object.prototype.hasOwnProperty.call(ctx.metadata, condition.key) ? ctx.metadata[condition.key] : void 0;
4362
+ }
4363
+ }
4364
+ function evaluateCustomFieldCondition(condition, ctx) {
4365
+ const raw = operandFor(condition, ctx);
4366
+ const actual = raw ?? "";
4367
+ const expected = condition.value;
4368
+ switch (condition.operator) {
4369
+ case "exists":
4370
+ return raw !== void 0 && raw.trim().length > 0;
4371
+ case "not_exists":
4372
+ return raw === void 0 || raw.trim().length === 0;
4373
+ case "equals":
4374
+ return norm(actual) === norm(expected);
4375
+ case "not_equals":
4376
+ return norm(actual) !== norm(expected);
4377
+ case "contains":
4378
+ return norm(actual).includes(norm(expected));
4379
+ case "not_contains":
4380
+ return !norm(actual).includes(norm(expected));
4381
+ case "starts_with":
4382
+ return norm(actual).startsWith(norm(expected));
4383
+ case "ends_with":
4384
+ return norm(actual).endsWith(norm(expected));
4385
+ case "in":
4386
+ return splitList(expected).includes(norm(actual));
4387
+ case "not_in":
4388
+ return !splitList(expected).includes(norm(actual));
4389
+ case "gt":
4390
+ case "gte":
4391
+ case "lt":
4392
+ case "lte": {
4393
+ const a = numeric(actual);
4394
+ const b = numeric(expected);
4395
+ if (a === null || b === null) return false;
4396
+ if (condition.operator === "gt") return a > b;
4397
+ if (condition.operator === "gte") return a >= b;
4398
+ if (condition.operator === "lt") return a < b;
4399
+ return a <= b;
4400
+ }
4401
+ }
4402
+ }
4403
+ function evaluateCustomFieldVisibility(field, ctx) {
4404
+ const { mode, match, conditions } = field.visibility;
4405
+ if (mode !== "match" || conditions.length === 0) return true;
4406
+ return match === "any" ? conditions.some((c) => evaluateCustomFieldCondition(c, ctx)) : conditions.every((c) => evaluateCustomFieldCondition(c, ctx));
4407
+ }
4408
+ function visibleCustomFields(fields, ctx) {
4409
+ return fields.filter((f) => f.enabled && evaluateCustomFieldVisibility(f, ctx));
4410
+ }
4191
4411
  function translationFor(map, locale) {
4192
4412
  if (!locale) return null;
4193
4413
  const own = (k) => {
@@ -5128,6 +5348,8 @@ var DelopayInternal = class extends Delopay {
5128
5348
  };
5129
5349
  // Annotate the CommonJS export names for ESM import in node:
5130
5350
  0 && (module.exports = {
5351
+ ALL_CUSTOM_FIELD_CONDITION_SOURCES,
5352
+ ALL_CUSTOM_FIELD_OPERATORS,
5131
5353
  ALL_CUSTOM_FIELD_TYPES,
5132
5354
  Admin,
5133
5355
  AdminPortal,
@@ -5137,9 +5359,14 @@ var DelopayInternal = class extends Delopay {
5137
5359
  AvailabilityOverrides,
5138
5360
  BRANDING_EXPORT_FORMAT,
5139
5361
  BRANDING_EXPORT_VERSION,
5362
+ CHECKBOX_CHECKED,
5363
+ CHECKBOX_UNCHECKED,
5140
5364
  CUSTOM_CSS_MAX_LENGTH,
5141
5365
  CUSTOM_FIELDS_MAX,
5366
+ CUSTOM_FIELD_CONDITIONS_MAX,
5142
5367
  CUSTOM_FIELD_KEY_PATTERN,
5368
+ CUSTOM_FIELD_OPERATORS_BY_SOURCE,
5369
+ CUSTOM_FIELD_VALUELESS_OPERATORS,
5143
5370
  Cache,
5144
5371
  CardIssuers,
5145
5372
  Cards,
@@ -5173,19 +5400,27 @@ var DelopayInternal = class extends Delopay {
5173
5400
  buttonPadValue,
5174
5401
  cloneBranding,
5175
5402
  cloneCustomField,
5403
+ customFieldContextFromMetadata,
5404
+ customFieldIsTextLike,
5405
+ customFieldOperatorTakesValue,
5176
5406
  customFieldOptionLabel,
5177
5407
  customFieldText,
5178
5408
  decodeBadges,
5179
5409
  decodeBranding,
5180
5410
  decodeCustomFields,
5181
5411
  defaultBranding,
5412
+ defaultCustomFieldVisibility,
5413
+ defaultOperatorForSource,
5182
5414
  encodeBadges,
5183
5415
  encodeBranding,
5184
5416
  encodeCustomFields,
5417
+ evaluateCustomFieldCondition,
5418
+ evaluateCustomFieldVisibility,
5185
5419
  feeProgram,
5186
5420
  fontStack,
5187
5421
  fontWeightValue,
5188
5422
  inputPadValue,
5423
+ isCheckboxChecked,
5189
5424
  isDarkSurface,
5190
5425
  isHexColor,
5191
5426
  leaf,
@@ -5198,6 +5433,7 @@ var DelopayInternal = class extends Delopay {
5198
5433
  sanitizeCustomCss,
5199
5434
  shadowFor,
5200
5435
  surfacePadValue,
5201
- verticalGapValue
5436
+ verticalGapValue,
5437
+ visibleCustomFields
5202
5438
  });
5203
5439
  //# sourceMappingURL=internal.cjs.map