jsfe 1.10.7 → 1.10.9

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.
@@ -61,6 +61,8 @@ export function validateFlowContracts(flows: any, tools?: any[], { externalFlows
61
61
  question_es: string;
62
62
  retry: string;
63
63
  retry_es: string;
64
+ retry_text: string;
65
+ retry_text_es: string;
64
66
  };
65
67
  email: {
66
68
  label: string;
@@ -89,6 +91,8 @@ export function validateFlowContracts(flows: any, tools?: any[], { externalFlows
89
91
  question_es: string;
90
92
  retry: string;
91
93
  retry_es: string;
94
+ retry_text: string;
95
+ retry_text_es: string;
92
96
  };
93
97
  account_number: {
94
98
  label: string;
@@ -105,6 +109,8 @@ export function validateFlowContracts(flows: any, tools?: any[], { externalFlows
105
109
  question_es: string;
106
110
  retry: string;
107
111
  retry_es: string;
112
+ retry_text: string;
113
+ retry_text_es: string;
108
114
  };
109
115
  ssn_last4: {
110
116
  label: string;
@@ -183,8 +189,12 @@ export function validateFlowContracts(flows: any, tools?: any[], { externalFlows
183
189
  validator: string;
184
190
  question: string;
185
191
  question_es: string;
192
+ question_text: string;
193
+ question_text_es: string;
186
194
  retry: string;
187
195
  retry_es: string;
196
+ retry_text: string;
197
+ retry_text_es: string;
188
198
  };
189
199
  card_expiration: {
190
200
  label: string;
@@ -202,6 +212,8 @@ export function validateFlowContracts(flows: any, tools?: any[], { externalFlows
202
212
  question_es: string;
203
213
  retry: string;
204
214
  retry_es: string;
215
+ retry_text: string;
216
+ retry_text_es: string;
205
217
  };
206
218
  card_cvv: {
207
219
  label: string;
@@ -1 +1 @@
1
- {"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../../src/forms/contracts.js"],"names":[],"mappings":"AAgBA;;;IAGC;AACD;;;;;EAGC;AACD,qGAAqG;AACrG;;QAwCC;AAqBD;;;QAEC;AAgBD;;;;;;;;;QASC;AACD;;;;QAGC;AACD;;;;;;;;QA8BC;AAED,mHAAmH;AACnH,kDAgBC;AAED,+GAA+G;AAC/G;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2EC"}
1
+ {"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../../src/forms/contracts.js"],"names":[],"mappings":"AAgBA;;;IAGC;AACD;;;;;EAGC;AACD,qGAAqG;AACrG;;QAwCC;AAqBD;;;QAEC;AAgBD;;;;;;;;;QASC;AACD;;;;QAGC;AACD;;;;;;;;QA8BC;AAED,mHAAmH;AACnH,kDAgBC;AAED,+GAA+G;AAC/G;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2EC"}
@@ -84,6 +84,8 @@ export namespace FIELD_PRESETS {
84
84
  let question_es: string;
85
85
  let retry: string;
86
86
  let retry_es: string;
87
+ let retry_text: string;
88
+ let retry_text_es: string;
87
89
  }
88
90
  namespace email {
89
91
  let label_1: string;
@@ -133,6 +135,10 @@ export namespace FIELD_PRESETS {
133
135
  export { retry_2 as retry };
134
136
  let retry_es_2: string;
135
137
  export { retry_es_2 as retry_es };
138
+ let retry_text_1: string;
139
+ export { retry_text_1 as retry_text };
140
+ let retry_text_es_1: string;
141
+ export { retry_text_es_1 as retry_text_es };
136
142
  }
137
143
  namespace account_number {
138
144
  let label_3: string;
@@ -160,6 +166,10 @@ export namespace FIELD_PRESETS {
160
166
  export { retry_3 as retry };
161
167
  let retry_es_3: string;
162
168
  export { retry_es_3 as retry_es };
169
+ let retry_text_2: string;
170
+ export { retry_text_2 as retry_text };
171
+ let retry_text_es_2: string;
172
+ export { retry_text_es_2 as retry_text_es };
163
173
  }
164
174
  namespace ssn_last4 {
165
175
  let label_4: string;
@@ -287,10 +297,16 @@ export namespace FIELD_PRESETS {
287
297
  export { question_9 as question };
288
298
  let question_es_9: string;
289
299
  export { question_es_9 as question_es };
300
+ export let question_text: string;
301
+ export let question_text_es: string;
290
302
  let retry_4: string;
291
303
  export { retry_4 as retry };
292
304
  let retry_es_4: string;
293
305
  export { retry_es_4 as retry_es };
306
+ let retry_text_3: string;
307
+ export { retry_text_3 as retry_text };
308
+ let retry_text_es_3: string;
309
+ export { retry_text_es_3 as retry_text_es };
294
310
  }
295
311
  namespace card_expiration {
296
312
  let label_10: string;
@@ -321,6 +337,10 @@ export namespace FIELD_PRESETS {
321
337
  export { retry_5 as retry };
322
338
  let retry_es_5: string;
323
339
  export { retry_es_5 as retry_es };
340
+ let retry_text_4: string;
341
+ export { retry_text_4 as retry_text };
342
+ let retry_text_es_4: string;
343
+ export { retry_text_es_4 as retry_text_es };
324
344
  }
325
345
  namespace card_cvv {
326
346
  let label_11: string;
@@ -1 +1 @@
1
- {"version":3,"file":"flows.d.ts","sourceRoot":"","sources":["../../src/forms/flows.js"],"names":[],"mappings":"AAsHA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4DC;AACD;;;GAGG;AACH;;;;;;EAGC;AAgZD,wHAAwH;AACxH,wEAaC;AACD,4FAA4F;AAC5F;;;EAYC;AACD,sGAAsG;AACtG;;;EAOC;AArkBM,6CAAuG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4vB9G;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAOG"}
1
+ {"version":3,"file":"flows.d.ts","sourceRoot":"","sources":["../../src/forms/flows.js"],"names":[],"mappings":"AA4HA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4DC;AACD;;;GAGG;AACH;;;;;;EAGC;AAgZD,wHAAwH;AACxH,wEAaC;AACD,4FAA4F;AAC5F;;;EAYC;AACD,sGAAsG;AACtG;;;EAOC;AA3kBM,6CAAuG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkwB9G;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAOG"}
@@ -45,16 +45,19 @@ const KEYS_JS = "(function (n) { var k = []; for (var i = 1; k.length < n && i <
45
45
  export const FIELD_PRESETS = {
46
46
  phone: { label: 'phone number', label_es: 'número de teléfono', profile: { kind: 'phone' }, digits: { min: 10, max: 11 },
47
47
  question: 'What is your phone number?', question_es: '¿Cuál es su número de teléfono?',
48
- retry: 'Please say or enter your 10-digit phone number.', retry_es: 'Por favor diga o ingrese su número de teléfono de 10 dígitos.' },
48
+ retry: 'Please say or enter your 10-digit phone number.', retry_es: 'Por favor diga o ingrese su número de teléfono de 10 dígitos.',
49
+ retry_text: 'Please type your 10-digit phone number.', retry_text_es: 'Por favor escriba su número de teléfono de 10 dígitos.' },
49
50
  email: { label: 'email address', label_es: 'correo electrónico', profile: { kind: 'email' },
50
51
  question: 'What is your email address?', question_es: '¿Cuál es su correo electrónico?',
51
52
  retry: 'Please say your email address, for example juan at gmail dot com.', retry_es: 'Por favor diga su correo electrónico, por ejemplo juan arroba gmail punto com.' },
52
53
  zip: { label: 'ZIP code', label_es: 'código postal', profile: { kind: 'digits', min: 5, max: 5 }, digits: { min: 5, max: 5 },
53
54
  question: 'What is your ZIP code?', question_es: '¿Cuál es su código postal?',
54
- retry: 'Please say or enter your 5-digit ZIP code.', retry_es: 'Por favor diga o ingrese su código postal de 5 dígitos.' },
55
+ retry: 'Please say or enter your 5-digit ZIP code.', retry_es: 'Por favor diga o ingrese su código postal de 5 dígitos.',
56
+ retry_text: 'Please type your 5-digit ZIP code.', retry_text_es: 'Por favor escriba su código postal de 5 dígitos.' },
55
57
  account_number: { label: 'account number', label_es: 'número de cuenta', profile: { kind: 'identifier', pattern: '^\\d{6,12}$' }, digits: { min: 6, max: 12 },
56
58
  question: 'What is your account number?', question_es: '¿Cuál es su número de cuenta?',
57
- retry: 'Please say or enter your account number.', retry_es: 'Por favor diga o ingrese su número de cuenta.' },
59
+ retry: 'Please say or enter your account number.', retry_es: 'Por favor diga o ingrese su número de cuenta.',
60
+ retry_text: 'Please type your account number.', retry_text_es: 'Por favor escriba su número de cuenta.' },
58
61
  ssn_last4: { label: 'last four digits of your Social Security number', label_es: 'últimos cuatro dígitos de su Seguro Social',
59
62
  profile: { kind: 'digits', min: 4, max: 4 }, digits: { min: 4, max: 4 }, pii: true,
60
63
  question: 'What are the last four digits of your Social Security number?', question_es: '¿Cuáles son los últimos cuatro dígitos de su Seguro Social?' },
@@ -68,13 +71,16 @@ export const FIELD_PRESETS = {
68
71
  card_number: { label: 'card number', label_es: 'número de tarjeta', accumulate: true, accumulate_first: '^[2-6]', profile: { kind: 'digits', min: 13, max: 19 }, digits: { min: 13, max: 19, complete: [{ first: '4', lengths: [16, 19] }, { first: '25', lengths: [16] }, { first: '3', lengths: [15] }, { first: '6', lengths: [16, 19] }] },
69
72
  pii: true, validator: 'validate-card-number',
70
73
  question: 'Please say or enter your card number.', question_es: 'Por favor diga o ingrese el número de su tarjeta.',
71
- retry: 'Please say or enter the full card number.', retry_es: 'Por favor diga o ingrese el número completo de su tarjeta.' },
74
+ question_text: 'Please type your card number.', question_text_es: 'Por favor escriba el número de su tarjeta.',
75
+ retry: 'Please say or enter the full card number.', retry_es: 'Por favor diga o ingrese el número completo de su tarjeta.',
76
+ retry_text: 'Please type the full card number.', retry_text_es: 'Por favor escriba el número completo de su tarjeta.' },
72
77
  card_expiration: { label: 'expiration date', label_es: 'fecha de vencimiento',
73
78
  // MM0YY: a zero said between month and year ("020 28", prod 2026-10-25 14:10, was taken for the billing ZIP)
74
79
  profile: { kind: 'pattern', regex: '\\b(0?[1-9]|1[0-2])\\s*(?:/|-|\\s|de)?\\s*(?:20)?(\\d{2})\\b|\\b0[1-9]0\\s+(?:20)?\\d{2}\\b' }, digits: { min: 3, max: 6 },
75
80
  validator: 'validate-card-expiration',
76
81
  question: 'What is the expiration date, month and year?', question_es: '¿Cuál es la fecha de vencimiento, mes y año?',
77
- retry: 'Please say or enter the expiration as four digits, month then year, like 0 9 2 8.', retry_es: 'Por favor diga o ingrese el vencimiento en cuatro dígitos, mes y año, por ejemplo 0 9 2 8.' },
82
+ retry: 'Please say or enter the expiration as four digits, month then year, like 0 9 2 8.', retry_es: 'Por favor diga o ingrese el vencimiento en cuatro dígitos, mes y año, por ejemplo 0 9 2 8.',
83
+ retry_text: 'Please type the expiration as four digits, month then year, like 0928.', retry_text_es: 'Por favor escriba el vencimiento en cuatro dígitos, mes y año, por ejemplo 0928.' },
78
84
  card_cvv: { label: 'security code', label_es: 'código de seguridad', profile: { kind: 'digits', min: 3, max: 4 }, digits: { min: 3, max: 4 }, pii: true,
79
85
  question: 'What is the security code on the back of the card?', question_es: '¿Cuál es el código de seguridad al reverso de la tarjeta?' },
80
86
  card_zip: { label: 'billing ZIP code', label_es: 'código postal de facturación', profile: { kind: 'digits', min: 5, max: 5 }, digits: { min: 5, max: 5 },
@@ -1 +1 @@
1
- {"version":3,"file":"answer.d.ts","sourceRoot":"","sources":["../../src/helpers/answer.js"],"names":[],"mappings":"AA4MA;;;GAGG;AACH,wEAkBC;AAED,+HAA+H;AAC/H,oDAIC;AAcD,2GAA2G;AAC3G,uDAGC;AAOD;;;;;GAKG;AACH,+DAUC;AAKD;;;;GAIG;AACH,oDAEC;AAiBD;;;;;;GAMG;AACH,mDAAmF;AAEnF,kGAAkG;AAClG;;;EAmCC;AAUD;;;;;;;;;GASG;AACH,6EA4GC;;;;;;;;AA/aD,qCAKiD"}
1
+ {"version":3,"file":"answer.d.ts","sourceRoot":"","sources":["../../src/helpers/answer.js"],"names":[],"mappings":"AA6MA;;;GAGG;AACH,wEAkBC;AAED,+HAA+H;AAC/H,oDAIC;AAcD,2GAA2G;AAC3G,uDAGC;AAOD;;;;;GAKG;AACH,+DAUC;AAKD;;;;GAIG;AACH,oDAEC;AAiBD;;;;;;GAMG;AACH,mDAAmF;AAEnF,kGAAkG;AAClG;;;EAmCC;AAUD;;;;;;;;;GASG;AACH,6EA4GC;;;;;;;;AA/aD,qCAKwE"}
@@ -39,14 +39,15 @@ export const ANSWER_WORDS = {
39
39
  // The ONLY words that confirm a choice that charges or cancels (`exact`), besides the choice's own words and keys; courtesy
40
40
  // around them is allowed (owner decision 2026-10-15: "clear charge confirmation exclusively"). Left out on purpose:
41
41
  // acknowledgements ("ok", "está bien", "fine", "sounds good", "perfecto": "I heard you", not "charge me"), "bueno" (the
42
- // Mexican phone "hello?"), courtesy alone ("please", "por favor"), words that are questions once ASR drops the "?"
43
- // ("right", "seguro", "exactly", "así es"), and agreeing to continue ("continue", "continuar").
42
+ // Mexican phone "hello?"), words that are questions once ASR drops the "?" ("right", "seguro", "exactly", "así es"), and
43
+ // agreeing to continue ("continue", "continuar"). "please" / "por favor" alone confirm (owner rule 2026-10-26: prod
44
+ // 21:47, "por favor" to "presione 1 o diga SÍ" at a payment offer was not taken and the payment was lost).
44
45
  export const CONFIRM_WORDS = ['yes', 'yeah', 'yep', 'yup', 'sure', 'of course', 'absolutely', 'definitely', 'confirm', 'i confirm',
45
46
  'confirmed', 'approve', 'i approve', 'approved', 'agree', 'i agree', 'agreed', 'proceed', 'go ahead', 'go ahead please', 'do it',
46
47
  'correct', "that's correct", 'that is correct', "that's right", 'that is right', 'yes i do',
47
48
  'si', 'sí', 'claro', 'claro que sí', 'claro que si', 'por supuesto', 'confirmo', 'confirmado', 'apruebo', 'aprobado', 'adelante',
48
49
  'dale', 'hazlo', 'procede', 'proceda', 'proceder', 'procedo', 'sí proceda', 'si proceda', 'correcto', 'de acuerdo',
49
- 'estoy de acuerdo', 'sí quiero', 'si quiero'];
50
+ 'estoy de acuerdo', 'sí quiero', 'si quiero', 'please', 'por favor'];
50
51
  // Acknowledgements: never a confirmation of an `exact` choice on their own, but said beside one ("Sí, está bien", "Yes,
51
52
  // okay") they change nothing, like courtesy. Beside an exact choice's own words, a CONFIRM word is the same ("Yes, the
52
53
  // full balance").
@@ -10,8 +10,13 @@
10
10
  export function readEmail(text: any, { literal }?: {
11
11
  literal?: boolean | undefined;
12
12
  }): string;
13
- /** The 10-digit North American number in the answer (a leading 1 dropped), or ''. */
14
- export function readPhone(text: any): string;
13
+ /**
14
+ * The 10-digit North American number in the answer (a leading 1 dropped), or ''. A caller who restates the number
15
+ * ("Area code 21. 213 555 0147.", "Area code, 213 555. Area code 213-555-0147.") is read by the last complete number
16
+ * after a sentence break or an "area code": prod 2026-10-26 07:28, the first read as a Mexican number, the second as
17
+ * nothing. An answer with an international prefix (+, plus, más, 00) is never split, so it stays international.
18
+ */
19
+ export function readPhone(text: any): any;
15
20
  /**
16
21
  * A phone number from outside the US / Canada in the answer, as its digits with the country code, or ''. With an
17
22
  * explicit prefix ("+", "plus", "más", "00") 8-15 digits; without one 11-13 digits not starting with 1 (a card or an
@@ -28,7 +33,7 @@ export function callerIsInternational(cargo: any): boolean;
28
33
  */
29
34
  export function readIdentifier(text: any, accountPattern?: string): {
30
35
  kind: string;
31
- value: string;
36
+ value: any;
32
37
  } | null;
33
38
  /**
34
39
  * The last four characters of a number (card, account, phone, tracking) as said to the customer: spaced one by one on a
@@ -1 +1 @@
1
- {"version":3,"file":"contact.d.ts","sourceRoot":"","sources":["../../src/helpers/contact.js"],"names":[],"mappings":"AAiBA;;;;;;;;GAQG;AACH;;WA8BC;AAED,qFAAqF;AACrF,6CASC;AAED;;;;;GAKG;AACH,0DAgBC;AAED,qHAAqH;AACrH,2DAIC;AAED;;;;GAIG;AACH;;;SAmBC;AAED;;;GAGG;AACH,sDAOC;AAED;;;;;GAKG;AACH,yEAUC;AAQD;;;;;GAKG;AACH,qDAIC;AAED,mHAAmH;AACnH,oDAIC"}
1
+ {"version":3,"file":"contact.d.ts","sourceRoot":"","sources":["../../src/helpers/contact.js"],"names":[],"mappings":"AAiBA;;;;;;;;GAQG;AACH;;WA8BC;AAID;;;;;GAKG;AACH,0CAWC;AAED;;;;;GAKG;AACH,0DAgBC;AAED,qHAAqH;AACrH,2DAIC;AAED;;;;GAIG;AACH;;;SAmBC;AAED;;;GAGG;AACH,sDAOC;AAED;;;;;GAKG;AACH,yEAUC;AAQD;;;;;GAKG;AACH,qDAIC;AAED,mHAAmH;AACnH,oDAIC"}
@@ -56,17 +56,25 @@ export function readEmail(text, { literal = false } = {}) {
56
56
  return /^[a-z0-9][a-z0-9._%+-]*@[a-z0-9.-]+\.[a-z]{2,}$/.test(email) ? email : '';
57
57
  }
58
58
  }
59
- /** The 10-digit North American number in the answer (a leading 1 dropped), or ''. */
59
+ const northAmerican = (digits) => digits.length === 11 && digits.startsWith('1') ? digits.slice(1) : digits.length === 10 ? digits : '';
60
+ /**
61
+ * The 10-digit North American number in the answer (a leading 1 dropped), or ''. A caller who restates the number
62
+ * ("Area code 21. 213 555 0147.", "Area code, 213 555. Area code 213-555-0147.") is read by the last complete number
63
+ * after a sentence break or an "area code": prod 2026-10-26 07:28, the first read as a Mexican number, the second as
64
+ * nothing. An answer with an international prefix (+, plus, más, 00) is never split, so it stays international.
65
+ */
60
66
  export function readPhone(text) {
61
- const digits = String(text ?? '').replace(/[^0-9]/g, '');
62
- if (digits.length === 11 && digits.startsWith('1')) {
63
- return digits.slice(1);
67
+ const t = String(text ?? '');
68
+ const whole = northAmerican(t.replace(/[^0-9]/g, ''));
69
+ if (whole) {
70
+ return whole;
64
71
  }
65
- else if (digits.length === 10) {
66
- return digits;
72
+ else if (/(^|[\s(])(\+|00|plus\b|m[aá]s\b)\s*\d/i.test(t)) {
73
+ return '';
67
74
  }
68
75
  else {
69
- return '';
76
+ const restated = t.split(/[.!?;](?:\s+|$)|\barea\s+code\b|\bc[oó]digo\s+de\s+[aá]rea\b/i).map((part) => northAmerican(part.replace(/[^0-9]/g, ''))).filter(Boolean);
77
+ return restated.length ? restated[restated.length - 1] : '';
70
78
  }
71
79
  }
72
80
  /**
@@ -4,7 +4,10 @@ export function missFormInput(cargo: any, id: any, input: any): any;
4
4
  * turn away on an unreadable answer: it says it did not catch that and asks again. Its exits stay explicit (the form's
5
5
  * stop words, max_attempts and on_exhausted, and whatever the host intercepts before the engine). */
6
6
  export function formMustComplete(cargo: any, id: any, input: any): boolean;
7
- /** Explicit retry wins. Otherwise acknowledge only an actual unrecognized answer, once per re-ask. */
7
+ /**
8
+ * Explicit retry wins. Otherwise acknowledge only an actual unrecognized answer, once per re-ask.
9
+ * question_text / retry_text (and _es): the written-channel wording, used only when the conversation is not a call.
10
+ */
8
11
  export function formInputPrompt(cargo: any, id: any, input: any, spec: any, data?: {}, language?: string): any;
9
12
  export function consumeFormFeedback(cargo: any, id: any, input: any): boolean;
10
13
  /** Recovery refers to the actual owning root, and never permits a fresh attempt at an unknown action. */
@@ -1 +1 @@
1
- {"version":3,"file":"form-conversation.d.ts","sourceRoot":"","sources":["../../src/helpers/form-conversation.js"],"names":[],"mappings":"AAGA,0EAGC;AACD,oEAGC;AACD;;qGAEqG;AACrG,2EAWC;AACD,sGAAsG;AACtG,+GAOC;AACD,8EAAwI;AAExI,yGAAyG;AACzG;;;;;;;;;;;;;;;;;;;;EAUC;AAED,sGAAsG;AACtG;;;;;;;;;;;;;;;;;;;;EAeC"}
1
+ {"version":3,"file":"form-conversation.d.ts","sourceRoot":"","sources":["../../src/helpers/form-conversation.js"],"names":[],"mappings":"AAGA,0EAGC;AACD,oEAGC;AACD;;qGAEqG;AACrG,2EAWC;AACD;;;GAGG;AACH,+GAQC;AACD,8EAAwI;AAExI,yGAAyG;AACzG;;;;;;;;;;;;;;;;;;;;EAUC;AAED,sGAAsG;AACtG;;;;;;;;;;;;;;;;;;;;EAeC"}
@@ -41,11 +41,15 @@ export function formMustComplete(cargo, id, input) {
41
41
  }
42
42
  return false;
43
43
  }
44
- /** Explicit retry wins. Otherwise acknowledge only an actual unrecognized answer, once per re-ask. */
44
+ /**
45
+ * Explicit retry wins. Otherwise acknowledge only an actual unrecognized answer, once per re-ask.
46
+ * question_text / retry_text (and _es): the written-channel wording, used only when the conversation is not a call.
47
+ */
45
48
  export function formInputPrompt(cargo, id, input, spec, data = {}, language = 'en') {
46
- const es = language === 'es', feedback = cargo.forms?.[id]?.feedback?.[input];
47
- const question = spec.question_from && (es ? (data[spec.question_from + '_es'] || data[spec.question_from]) : data[spec.question_from]) || (es ? (spec.question_es || spec.question) : spec.question) || '';
48
- const retry = es ? spec.retry_es : spec.retry;
49
+ const es = language === 'es', feedback = cargo.forms?.[id]?.feedback?.[input], text = !cargo?.voice;
50
+ const written = (key) => text ? (es ? (spec[key + '_text_es'] || spec[key + '_text']) : spec[key + '_text']) : undefined;
51
+ const question = spec.question_from && (es ? (data[spec.question_from + '_es'] || data[spec.question_from]) : data[spec.question_from]) || written('question') || (es ? (spec.question_es || spec.question) : spec.question) || '';
52
+ const retry = written('retry') || (es ? spec.retry_es : spec.retry);
49
53
  if (feedback === 'partial')
50
54
  return es ? 'Continúe.' : 'Go on.';
51
55
  if (feedback && retry)
@@ -1 +1 @@
1
- export const JSFE_RUNTIME_FINGERPRINT = "sha256:7d7eed4421d54620c8003db7ad362a4ecfb2689e8fcaf050e43fd93912f6e914";
1
+ export const JSFE_RUNTIME_FINGERPRINT = "sha256:747832e9ef9aa989fff3e0af1692ca56be68abc6c591ea3112e86ea1d1e99bec";
@@ -160,6 +160,7 @@ Field options:
160
160
  | Fields | Meaning |
161
161
  | --- | --- |
162
162
  | `label`, `label_es`; `question`, `question_es`; `retry`, `retry_es` | Names, first prompt and explicit retry wording. Contextual question templates compile to workers automatically. |
163
+ | `question_text`, `question_text_es`; `retry_text`, `retry_text_es` | Optional written-channel wording, used instead when the conversation is not a call (`cargo.voice` false). |
163
164
  | `description` | Public extraction guidance; `response.description`, when used, describes an open answer. |
164
165
  | `when` | Map paths to desired scalar values or arrays; siblings use field names, session paths use `cargo.*`, owner data uses `form.*`. Values prefixed `!` exclude that value. |
165
166
  | `unless` | Paths whose populated, non-false value makes the field inapplicable. |
@@ -1,3 +1,18 @@
1
+ ## 1.10.9: written wording for a written channel
2
+
3
+ An input may carry `question_text` / `retry_text` (and `_es`): the wording used when the conversation is not a call
4
+ (`cargo.voice` false). Absent, `question` / `retry` are used on every channel, as before. The phone, ZIP, account number
5
+ and card presets carry them, so a chat no longer reads "Por favor diga o ingrese el número de su tarjeta" (prod 2026-10-26,
6
+ web D365 and WhatsApp).
7
+
8
+ **A restated phone number is read.** `readPhone` (and so `readIdentifier`) reads the last complete North American number after a sentence break or an "area code" when the whole answer is not one number: "Area code 21. 213 555 0147." was read as a Mexican number and "Area code, 213 555. Area code 213-555-0147." as nothing (prod 2026-10-26). An answer with an international prefix is never split.
9
+
10
+ ## 1.10.8: "por favor" confirms
11
+
12
+ "please" / "por favor" alone are a firm YES (`CONFIRM_WORDS`; owner rule 2026-10-26: prod 21:47, "por favor" to "presione 1 o
13
+ diga SÍ" at a payment offer was not taken and the payment was lost). "No, por favor", "espere por favor" and "un enlace
14
+ por favor" are still not a YES.
15
+
1
16
  ## 1.10.7: a firm question's key in minimal context
2
17
 
3
18
  At a firm question (a yes choice that charges or cancels), its key confirms only alone or beside please/thanks or a CONFIRM
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jsfe",
3
- "version": "1.10.7",
3
+ "version": "1.10.9",
4
4
  "description": "TypeScript workflow engine for conversational/automation apps: multi-flow orchestration, interrupt/resume, stack-based control, robust errors, and flexible tool/REST integration.",
5
5
  "license": "MIT",
6
6
  "author": "Ron Pinkas",