tuain-ng-forms-lib 17.3.6 → 17.4.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.
Files changed (64) hide show
  1. package/README.md +280 -335
  2. package/esm2022/lib/classes/forms/action.mjs +3 -3
  3. package/esm2022/lib/classes/forms/element.mjs +2 -2
  4. package/esm2022/lib/classes/forms/field.mjs +4 -7
  5. package/esm2022/lib/classes/forms/form.mjs +4 -6
  6. package/esm2022/lib/classes/forms/piece-propagate.mjs +1 -1
  7. package/esm2022/lib/classes/forms/piece.mjs +2 -2
  8. package/esm2022/lib/classes/forms/section.mjs +2 -2
  9. package/esm2022/lib/classes/forms/subsection.mjs +1 -1
  10. package/esm2022/lib/classes/forms/table/action.mjs +1 -1
  11. package/esm2022/lib/classes/forms/table/column.mjs +1 -1
  12. package/esm2022/lib/classes/forms/table/row-data.mjs +3 -5
  13. package/esm2022/lib/classes/forms/table/table.mjs +2 -2
  14. package/esm2022/lib/components/elements/layout/piece.component.mjs +3 -3
  15. package/esm2022/lib/components/elements/tables/table-record-action.component.mjs +1 -1
  16. package/esm2022/lib/components/elements/tables/table-record-field.component.mjs +1 -1
  17. package/esm2022/lib/components/forms/basic-form.mjs +23 -24
  18. package/esm2022/lib/interfaces/action.interface.mjs +2 -0
  19. package/esm2022/lib/interfaces/field.interface.mjs +2 -0
  20. package/esm2022/lib/interfaces/form-config.interface.mjs +1 -1
  21. package/esm2022/lib/interfaces/form.interface.mjs +2 -0
  22. package/esm2022/lib/interfaces/index.mjs +9 -1
  23. package/esm2022/lib/interfaces/piece.interface.mjs +2 -0
  24. package/esm2022/lib/interfaces/section.interface.mjs +2 -0
  25. package/esm2022/lib/interfaces/sse-live-connection.interface.mjs +2 -0
  26. package/esm2022/lib/interfaces/table.interface.mjs +2 -0
  27. package/esm2022/lib/services/file-manager.service.mjs +5 -5
  28. package/esm2022/lib/services/form-manager.service.mjs +5 -5
  29. package/esm2022/lib/services/icon-dictionary.service.mjs +1 -1
  30. package/esm2022/lib/services/sse-live-connection.service.mjs +165 -0
  31. package/esm2022/lib/tokens/sse-live-connection.token.mjs +7 -0
  32. package/esm2022/public-api.mjs +3 -1
  33. package/fesm2022/tuain-ng-forms-lib.mjs +215 -55
  34. package/fesm2022/tuain-ng-forms-lib.mjs.map +1 -1
  35. package/lib/classes/forms/action.d.ts +3 -2
  36. package/lib/classes/forms/element.d.ts +2 -1
  37. package/lib/classes/forms/field.d.ts +5 -4
  38. package/lib/classes/forms/form.d.ts +4 -2
  39. package/lib/classes/forms/piece-propagate.d.ts +2 -1
  40. package/lib/classes/forms/piece.d.ts +4 -3
  41. package/lib/classes/forms/section.d.ts +3 -2
  42. package/lib/classes/forms/subsection.d.ts +2 -1
  43. package/lib/classes/forms/table/action.d.ts +2 -1
  44. package/lib/classes/forms/table/column.d.ts +2 -1
  45. package/lib/classes/forms/table/row-data.d.ts +3 -2
  46. package/lib/classes/forms/table/table.d.ts +3 -1
  47. package/lib/components/elements/layout/piece.component.d.ts +2 -2
  48. package/lib/components/forms/basic-form.d.ts +4 -4
  49. package/lib/interfaces/action.interface.d.ts +23 -0
  50. package/lib/interfaces/field.interface.d.ts +70 -0
  51. package/lib/interfaces/form-config.interface.d.ts +24 -16
  52. package/lib/interfaces/form.interface.d.ts +106 -0
  53. package/lib/interfaces/index.d.ts +7 -0
  54. package/lib/interfaces/piece.interface.d.ts +67 -0
  55. package/lib/interfaces/section.interface.d.ts +56 -0
  56. package/lib/interfaces/sse-live-connection.interface.d.ts +59 -0
  57. package/lib/interfaces/table.interface.d.ts +139 -0
  58. package/lib/services/file-manager.service.d.ts +4 -4
  59. package/lib/services/form-manager.service.d.ts +3 -3
  60. package/lib/services/icon-dictionary.service.d.ts +1 -1
  61. package/lib/services/sse-live-connection.service.d.ts +48 -0
  62. package/lib/tokens/sse-live-connection.token.d.ts +7 -0
  63. package/package.json +2 -1
  64. package/public-api.d.ts +2 -0
@@ -4,9 +4,16 @@ import { Subject, takeUntil, BehaviorSubject, ReplaySubject } from 'rxjs';
4
4
  import yn from 'yn';
5
5
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
6
6
  import { nanoid } from 'nanoid';
7
+ import { fetchEventSource } from '@microsoft/fetch-event-source';
7
8
 
8
9
  const ICON_RESOLVER = new InjectionToken('ICON_RESOLVER');
9
10
 
11
+ /**
12
+ * Token con el que cada app provee su configuración del stream SSE.
13
+ * Sigue el mismo patrón que `ICON_RESOLVER`.
14
+ */
15
+ const SSE_LIVE_CONNECTION_CONFIG = new InjectionToken('SSE_LIVE_CONNECTION_CONFIG');
16
+
10
17
  class FormPiece {
11
18
  destroy$ = new Subject();
12
19
  _formState = '';
@@ -117,7 +124,7 @@ class FormPiece {
117
124
  set disabled(disabled) { this.enabled = !disabled; }
118
125
  enable() { this.enabled = true; }
119
126
  disable() { this.enabled = false; }
120
- formStateChangeCustomSubscribe(form, formChangeSubject) { }
127
+ formStateChangeCustomSubscribe(_form, _formChangeSubject) { }
121
128
  formStateChange(state) {
122
129
  if (state) {
123
130
  this._formState = state;
@@ -249,7 +256,7 @@ class FormElement extends FormPiecePropagate {
249
256
  }
250
257
  }
251
258
  catch (e) {
252
- console.log(`Atributo ${attrName} no presente o valor ${value} inconsistente. ${e}`);
259
+ console.error(`Atributo ${attrName} no presente o valor ${value} inconsistente. ${e}`);
253
260
  }
254
261
  }
255
262
  isField() { return this.elementType === ElementType.Field; }
@@ -566,7 +573,7 @@ class FieldDescriptor extends FormElement {
566
573
  /**
567
574
  * @deprecated Since v17. Use options instead. Will be removed in v19.
568
575
  */
569
- setFieldOptions(newOptions) { return this.options = newOptions; }
576
+ setFieldOptions(newOptions) { this.options = newOptions; }
570
577
  /**
571
578
  * @deprecated Since v17. Use intrinsicErrorMessage instead. Will be removed in v19.
572
579
  */
@@ -592,7 +599,6 @@ class FieldDescriptor extends FormElement {
592
599
  && Array.isArray(fieldCurrentValue) && fieldCurrentValue.length === 0) {
593
600
  return true;
594
601
  }
595
- ;
596
602
  if (this._fieldType === this._formConfig.fieldTypes.phone) {
597
603
  if (!Array.isArray(fieldCurrentValue)) {
598
604
  return true;
@@ -602,7 +608,6 @@ class FieldDescriptor extends FormElement {
602
608
  }
603
609
  return false;
604
610
  }
605
- ;
606
611
  const arrayFieldTypes = this._formConfig.arrayFieldTypes ?? null;
607
612
  if (arrayFieldTypes && Object.keys(arrayFieldTypes).includes(this._fieldType)) {
608
613
  let arraySize = arrayFieldTypes[this._fieldType];
@@ -612,7 +617,6 @@ class FieldDescriptor extends FormElement {
612
617
  }
613
618
  return (Array.isArray(fieldCurrentValue) && fieldCurrentValue.length < arraySize);
614
619
  }
615
- ;
616
620
  return fieldCurrentValue === '';
617
621
  }
618
622
  notifyEditionPartial() {
@@ -646,14 +650,14 @@ class FieldDescriptor extends FormElement {
646
650
  if (intrinsicValidation && fieldValue && this._minValue && fieldValue < this._minValue) {
647
651
  intrinsicValidation = false;
648
652
  const formatedMinValue = !isNaN(+this._minValue)
649
- ? this._minValue.toLocaleString('es-CO')
653
+ ? Number(this._minValue).toLocaleString('es-CO')
650
654
  : this._minValue;
651
655
  this.setError('99', `El valor de ${this.title} no puede ser inferior a ${formatedMinValue}`);
652
656
  }
653
657
  if (intrinsicValidation && fieldValue && this._maxValue && fieldValue > this._maxValue) {
654
658
  intrinsicValidation = false;
655
659
  const formatedMaxValue = !isNaN(+this._maxValue)
656
- ? this._maxValue.toLocaleString('es-CO')
660
+ ? Number(this._maxValue).toLocaleString('es-CO')
657
661
  : this._maxValue;
658
662
  this.setError('99', `El valor de ${this.title} no puede ser superior a ${formatedMaxValue}`);
659
663
  }
@@ -812,7 +816,7 @@ class FormAction extends FormElement {
812
816
  }
813
817
  }
814
818
  }
815
- updateRestrictedVisibility(event) {
819
+ updateRestrictedVisibility(_event) {
816
820
  const newVisible = this._absoluteVisible && this.viewOnState(this._formState);
817
821
  (this._visible !== newVisible) && this.setVisibility(newVisible);
818
822
  }
@@ -839,7 +843,7 @@ class FormAction extends FormElement {
839
843
  this[propertyName] = receivedAction[propertyName];
840
844
  }
841
845
  catch (e) {
842
- console.log(`Error actualizando la propiedad ${propertyName} de la acción ${this.actionCode}. ${e}`);
846
+ console.error(`Error actualizando la propiedad ${propertyName} de la acción ${this.actionCode}. ${e}`);
843
847
  }
844
848
  }
845
849
  }
@@ -1008,7 +1012,7 @@ class RecordFormSection extends FormPiecePropagate {
1008
1012
  }
1009
1013
  get title() { return this._sectionTitle; }
1010
1014
  set title(title) { this._sectionTitle = title; }
1011
- getVisibleSubsections(state) {
1015
+ getVisibleSubsections(_state) {
1012
1016
  return this._subSections.filter(subSection => subSection.visible);
1013
1017
  }
1014
1018
  getSubsection(subSectionCode) {
@@ -1223,7 +1227,6 @@ class TableRecordData {
1223
1227
  const rawRecordData = recordData.filter(fieldData => fieldData.fieldCode && fieldNames.includes(fieldData.fieldCode));
1224
1228
  rawRecordData.forEach(fieldData => {
1225
1229
  const { fieldCode, fieldValue } = fieldData;
1226
- const fieldDef = recordDefinition.find(column => column.fieldCode === fieldCode);
1227
1230
  this.recordData[fieldCode] = fieldValue ?? '';
1228
1231
  if (fieldCode === selectionFieldName) {
1229
1232
  this.selected = fieldValue;
@@ -1234,7 +1237,6 @@ class TableRecordData {
1234
1237
  const fields = Object.keys(recordData);
1235
1238
  fields.forEach(fieldCode => {
1236
1239
  const fieldValue = recordData[fieldCode];
1237
- const fieldDef = recordDefinition.find(column => column.fieldCode === fieldCode);
1238
1240
  this.recordData[fieldCode] = fieldValue ?? '';
1239
1241
  });
1240
1242
  }
@@ -1257,7 +1259,7 @@ class TableRecordData {
1257
1259
  let wordIsPresent = false;
1258
1260
  for (const fieldCode in this.recordData) {
1259
1261
  const columnDef = columnObj?.[fieldCode];
1260
- if (columnDef?.searchable && this.recordData.hasOwnProperty(fieldCode)) {
1262
+ if (columnDef?.searchable && Object.prototype.hasOwnProperty.call(this.recordData, fieldCode)) {
1261
1263
  const term = word.toUpperCase();
1262
1264
  let fieldValue;
1263
1265
  if (columnDef.fieldType.toUpperCase().includes('DATE')) {
@@ -1284,7 +1286,7 @@ class TableRecordData {
1284
1286
  }
1285
1287
  for (const condition of columnFilters) {
1286
1288
  const { fieldCode, operator, values } = condition;
1287
- if (this.recordData.hasOwnProperty(fieldCode)) {
1289
+ if (Object.prototype.hasOwnProperty.call(this.recordData, fieldCode)) {
1288
1290
  const fieldValue = this.recordData[fieldCode];
1289
1291
  const stringValue = fieldValue.toString().toUpperCase();
1290
1292
  if (operator === ComparisonOperator.G && fieldValue <= values[0]) {
@@ -1465,6 +1467,7 @@ class RecordTable extends FormElement {
1465
1467
  get selectionField() { return this._selectionField; }
1466
1468
  get allSelected() { return this._allSelected; }
1467
1469
  get tableCode() { return this._tableCode; }
1470
+ get code() { return this._tableCode; }
1468
1471
  get tableTitle() { return this._tableTitle; }
1469
1472
  get currentPage() { return this._currentPage; }
1470
1473
  get totalPages() { return this._totalPages; }
@@ -1715,7 +1718,6 @@ class RecordTable extends FormElement {
1715
1718
  this.updateVisibleRecords();
1716
1719
  }
1717
1720
  getTableRecord(recordId) {
1718
- const recordIdKey = (typeof recordId === 'object') ? JSON.stringify(recordId) : recordId;
1719
1721
  return (this._tableRecordObj && recordId && this._tableRecordObj[recordId])
1720
1722
  ? this._tableRecordObj[recordId] : null;
1721
1723
  }
@@ -1860,9 +1862,7 @@ const HIDE = 'hide';
1860
1862
  const ENABLE = 'enable';
1861
1863
  const DISABLE = 'disable';
1862
1864
  const CLEAN = 'clean';
1863
- const alwaysVisible = 'ALWAYS';
1864
1865
  const neverVisible = 'NONE';
1865
- const onStatesVisible = 'ONSTATES';
1866
1866
  class FormStructureAndData {
1867
1867
  _stateChange = new Subject();
1868
1868
  _immutableData = {};
@@ -2091,7 +2091,7 @@ class FormStructureAndData {
2091
2091
  field && (field.required = required);
2092
2092
  }
2093
2093
  catch (e) {
2094
- console.log(`Error modificando campo ${code}: ${e}`);
2094
+ console.error(`Error modificando campo ${code}: ${e}`);
2095
2095
  }
2096
2096
  }
2097
2097
  }
@@ -2159,7 +2159,7 @@ class FormStructureAndData {
2159
2159
  processedFields += 1;
2160
2160
  }
2161
2161
  catch (e) {
2162
- console.log(`Error procesando funcion en campo ${field}: ${e}`);
2162
+ console.error(`Error procesando funcion en campo ${field}: ${e}`);
2163
2163
  }
2164
2164
  }
2165
2165
  }
@@ -2222,7 +2222,7 @@ class FormStructureAndData {
2222
2222
  for (let index = 0; index < codes.length; index++) {
2223
2223
  const code = codes[index];
2224
2224
  if (code) {
2225
- resultObject[code] = this.fields?.[code]?.getValue() ?? null;
2225
+ resultObject[code] = this.fields?.[code]?.value ?? null;
2226
2226
  }
2227
2227
  }
2228
2228
  return resultObject;
@@ -2445,7 +2445,7 @@ class PieceComponent {
2445
2445
  enabled = computed(() => !this.disabled());
2446
2446
  customAttributes = signal({});
2447
2447
  setForm(form) { this.form = form; }
2448
- propagatedAttributeChange(attribute, value) { }
2448
+ propagatedAttributeChange(_attribute, _value) { }
2449
2449
  updatePieceAttribute(signaledAttributes, signaledAttribute, value) {
2450
2450
  if (!signaledAttributes.includes(signaledAttribute)) {
2451
2451
  return;
@@ -2468,7 +2468,7 @@ class PieceComponent {
2468
2468
  }
2469
2469
  }
2470
2470
  }
2471
- customAttributeChange(subAttribute, value) { }
2471
+ customAttributeChange(_subAttribute, _value) { }
2472
2472
  updateCustomAttribute(attrName, attrValue) {
2473
2473
  this.customAttributes.update(old => ({ ...old, [attrName]: attrValue }));
2474
2474
  this.customAttributeChange(attrName, attrValue);
@@ -3048,9 +3048,9 @@ class LibFormManagerService {
3048
3048
  this.cleanStack();
3049
3049
  }
3050
3050
  // Métodos virtuales para las aplicaciones
3051
- getFormDefinition(formCode) { }
3052
- execServerAction(actionDetail) { }
3053
- goToForm(formCode, token, subject) { }
3051
+ getFormDefinition(_formCode) { }
3052
+ execServerAction(_actionDetail) { }
3053
+ goToForm(_formCode, _token, _subject) { }
3054
3054
  async loadStack() { }
3055
3055
  saveStack() { }
3056
3056
  cleanStack() { this.pageStack = []; }
@@ -3089,7 +3089,7 @@ class LibFormManagerService {
3089
3089
  return token;
3090
3090
  }
3091
3091
  unstack(token = null) {
3092
- let index = (token) ? this.findFormInStack(token).index : this.pageStack.length - 2;
3092
+ const index = (token) ? this.findFormInStack(token).index : this.pageStack.length - 2;
3093
3093
  let formInfo = null;
3094
3094
  if (index >= 0) {
3095
3095
  formInfo = this.pageStack[index];
@@ -3182,10 +3182,10 @@ class LibEventManagerService {
3182
3182
  }
3183
3183
 
3184
3184
  class LibFileManagementService {
3185
- openFile(fileBase64Data, fileName, fileType) { }
3186
- saveFileFromURL(fileUrl, fileName = null, fileType = null) { }
3187
- saveFile(fileBase64Data, fileName, fileType) { }
3188
- printPdfFile(pdfBufferData) { }
3185
+ openFile(_fileBase64Data, _fileName, _fileType) { }
3186
+ saveFileFromURL(_fileUrl, _fileName = null, _fileType = null) { }
3187
+ saveFile(_fileBase64Data, _fileName, _fileType) { }
3188
+ printPdfFile(_pdfBufferData) { }
3189
3189
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LibFileManagementService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
3190
3190
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LibFileManagementService });
3191
3191
  }
@@ -3194,7 +3194,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
3194
3194
  }] });
3195
3195
 
3196
3196
  const PAYLOAD_VERSION = 'TUAINEXCHANGE_1.0';
3197
- const INLINE_ACTION = 'INLINE';
3198
3197
  const GLOBAL_ACTION = 'GLOBAL';
3199
3198
  const GET_DATA_ACTION = 'GETDATA';
3200
3199
  const SUBJECT = 'subject';
@@ -3314,9 +3313,9 @@ class BasicFormComponent extends FormStructureAndData {
3314
3313
  displayActionServerError() { }
3315
3314
  displayValidationServerError() { }
3316
3315
  displayTableServerError() { }
3317
- showFieldInfo(code, detail) { }
3318
- showModalDialog(title, body, options, callback, params) { }
3319
- openUploadDialog(title, body, options, callback, params) { }
3316
+ showFieldInfo(_code, _detail) { }
3317
+ showModalDialog(_title, _body, _options, _callback, _params) { }
3318
+ openUploadDialog(_title, _body, _options, _callback, _params) { }
3320
3319
  subscribeAppEvent(eventName, callback) {
3321
3320
  this._eventEmiter.subscribe(eventName, callback);
3322
3321
  }
@@ -3666,7 +3665,7 @@ class BasicFormComponent extends FormStructureAndData {
3666
3665
  const clientSectionMethods = this._formSectionsCanDeactivate[code];
3667
3666
  if (clientSectionMethods) {
3668
3667
  for (const clientSectionMethod of clientSectionMethods) {
3669
- const { callback, properties } = clientSectionMethod;
3668
+ const { callback } = clientSectionMethod;
3670
3669
  const canActivate = callback(sectionObject);
3671
3670
  if (canActivate === false) {
3672
3671
  return false;
@@ -3684,7 +3683,7 @@ class BasicFormComponent extends FormStructureAndData {
3684
3683
  const clientSectionMethods = this._formSectionsActivate[code];
3685
3684
  if (clientSectionMethods) {
3686
3685
  for (const clientSectionMethod of clientSectionMethods) {
3687
- const { callback, properties } = clientSectionMethod;
3686
+ const { callback } = clientSectionMethod;
3688
3687
  callback(sectionObject);
3689
3688
  }
3690
3689
  }
@@ -3698,7 +3697,7 @@ class BasicFormComponent extends FormStructureAndData {
3698
3697
  const clientSectionMethods = this._formSectionsInactivate[code];
3699
3698
  if (clientSectionMethods) {
3700
3699
  for (const clientSectionMethod of clientSectionMethods) {
3701
- const { callback, properties } = clientSectionMethod;
3700
+ const { callback } = clientSectionMethod;
3702
3701
  callback(sectionObject);
3703
3702
  }
3704
3703
  }
@@ -3711,7 +3710,7 @@ class BasicFormComponent extends FormStructureAndData {
3711
3710
  }
3712
3711
  if (this._actionsInProgress[code]) {
3713
3712
  const { sent } = this._actionsInProgress[code];
3714
- console.log(`Reingreso sobre acción ${code} con ejecución previa ${sent}`);
3713
+ console.error(`Reingreso sobre acción ${code} con ejecución previa ${sent}`);
3715
3714
  return;
3716
3715
  }
3717
3716
  this._actionsInProgress[code] = { sent: new Date() };
@@ -3721,7 +3720,7 @@ class BasicFormComponent extends FormStructureAndData {
3721
3720
  if (clientActionMethods) {
3722
3721
  const clientActionPromises = [];
3723
3722
  for (const clientActionMethod of clientActionMethods) {
3724
- const { callback, properties } = clientActionMethod;
3723
+ const { callback } = clientActionMethod;
3725
3724
  const continueActionPromise = callback(actionObject);
3726
3725
  clientActionPromises.push(continueActionPromise);
3727
3726
  }
@@ -3750,7 +3749,7 @@ class BasicFormComponent extends FormStructureAndData {
3750
3749
  if (backend) {
3751
3750
  if (this._serverActionsInProgress[code]) {
3752
3751
  const { sent } = this._serverActionsInProgress[code];
3753
- console.log(`Reingreso server en acción ${code} con ejecución previa ${sent}`);
3752
+ console.error(`Reingreso server en acción ${code} con ejecución previa ${sent}`);
3754
3753
  return;
3755
3754
  }
3756
3755
  this._serverActionsInProgress[code] = { sent: new Date() };
@@ -3764,7 +3763,7 @@ class BasicFormComponent extends FormStructureAndData {
3764
3763
  }
3765
3764
  else {
3766
3765
  for (let index = 0; index < this._actionServerError.length; index++) {
3767
- const { callback, properties } = this._actionServerError[index];
3766
+ const { callback } = this._actionServerError[index];
3768
3767
  callback(action);
3769
3768
  }
3770
3769
  }
@@ -3822,7 +3821,7 @@ class BasicFormComponent extends FormStructureAndData {
3822
3821
  this.removeEventHandler(this._fieldValidationsStart, codes);
3823
3822
  this.removeEventHandler(this._fieldValidationsFinish, codes);
3824
3823
  }
3825
- async startFieldInputValidation(code, intrinsicValidation = true) {
3824
+ async startFieldInputValidation(code, _intrinsicValidation = true) {
3826
3825
  this.notifyFormActivity();
3827
3826
  const fieldToValidate = this.getField(code);
3828
3827
  if (!fieldToValidate) {
@@ -3832,7 +3831,7 @@ class BasicFormComponent extends FormStructureAndData {
3832
3831
  if (validationCallbacks) {
3833
3832
  const clientValidationPromises = [];
3834
3833
  for (const validationMethod of validationCallbacks) {
3835
- const { callback, properties } = validationMethod;
3834
+ const { callback } = validationMethod;
3836
3835
  const continueValidationPromise = callback(fieldToValidate);
3837
3836
  clientValidationPromises.push(continueValidationPromise);
3838
3837
  }
@@ -3850,7 +3849,7 @@ class BasicFormComponent extends FormStructureAndData {
3850
3849
  if (eventHandlerCallbacks) {
3851
3850
  const clientEventPromises = [];
3852
3851
  for (const eventHandlerMethod of eventHandlerCallbacks) {
3853
- const { callback, properties } = eventHandlerMethod;
3852
+ const { callback } = eventHandlerMethod;
3854
3853
  const clientEventPromise = callback(eventName, eventData, fieldToTrigger);
3855
3854
  clientEventPromises.push(clientEventPromise);
3856
3855
  }
@@ -3866,7 +3865,7 @@ class BasicFormComponent extends FormStructureAndData {
3866
3865
  if (validationCallbacks) {
3867
3866
  const clientValidationPromises = [];
3868
3867
  for (const validationMethod of validationCallbacks) {
3869
- const { callback, properties } = validationMethod;
3868
+ const { callback } = validationMethod;
3870
3869
  const clientValidationPromise = callback(fieldToValidate);
3871
3870
  clientValidationPromises.push(clientValidationPromise);
3872
3871
  }
@@ -3898,7 +3897,7 @@ class BasicFormComponent extends FormStructureAndData {
3898
3897
  fieldObj?.setErrorCode(this.errorCode);
3899
3898
  fieldObj?.setErrorMessage(this.errorMessage);
3900
3899
  for (let index = 0; index < this._fieldServerError.length; index++) {
3901
- const { callback, properties } = this._fieldServerError[index];
3900
+ const { callback } = this._fieldServerError[index];
3902
3901
  callback(fieldObj);
3903
3902
  }
3904
3903
  }
@@ -4052,7 +4051,7 @@ class BasicFormComponent extends FormStructureAndData {
4052
4051
  if (tableActionMethods) {
4053
4052
  const clientActionPromises = [];
4054
4053
  for (const tableActionMethod of tableActionMethods) {
4055
- const { callback, properties } = tableActionMethod;
4054
+ const { callback } = tableActionMethod;
4056
4055
  const clientActionPromise = callback(tableActionDetail);
4057
4056
  clientActionPromises.push(clientActionPromise);
4058
4057
  }
@@ -4088,7 +4087,7 @@ class BasicFormComponent extends FormStructureAndData {
4088
4087
  }
4089
4088
  else {
4090
4089
  for (let index = 0; index < this._tableServerError.length; index++) {
4091
- const { callback, properties } = this._tableServerError[index];
4090
+ const { callback } = this._tableServerError[index];
4092
4091
  callback(tableObject);
4093
4092
  }
4094
4093
  }
@@ -4136,7 +4135,7 @@ class BasicFormComponent extends FormStructureAndData {
4136
4135
  if (tableActionMethods) {
4137
4136
  const clientActionPromises = [];
4138
4137
  for (const tableActionMethod of tableActionMethods) {
4139
- const { callback, properties } = tableActionMethod;
4138
+ const { callback } = tableActionMethod;
4140
4139
  const clientActionPromise = callback(tableActionDetail);
4141
4140
  clientActionPromises.push(clientActionPromise);
4142
4141
  }
@@ -4215,7 +4214,7 @@ class BasicFormComponent extends FormStructureAndData {
4215
4214
  if (tableEventHandlers) {
4216
4215
  const clientActionPromises = [];
4217
4216
  for (const tableSelectionMethod of tableEventHandlers) {
4218
- const { callback, properties } = tableSelectionMethod;
4217
+ const { callback } = tableSelectionMethod;
4219
4218
  const clientActionPromise = callback(tableSelectionDetail);
4220
4219
  clientActionPromises.push(clientActionPromise);
4221
4220
  }
@@ -4293,7 +4292,7 @@ class BasicFormComponent extends FormStructureAndData {
4293
4292
  if (tableActionMethods) {
4294
4293
  const clientActionPromises = [];
4295
4294
  for (const tableActionMethod of tableActionMethods) {
4296
- const { callback, properties } = tableActionMethod;
4295
+ const { callback } = tableActionMethod;
4297
4296
  const clientActionPromise = callback(tableActionDetail);
4298
4297
  clientActionPromises.push(clientActionPromise);
4299
4298
  }
@@ -4362,7 +4361,7 @@ class BasicFormComponent extends FormStructureAndData {
4362
4361
  if (tableEventHandlers) {
4363
4362
  const clientActionPromises = [];
4364
4363
  for (const tableActionMethod of tableEventHandlers) {
4365
- const { callback, properties } = tableActionMethod;
4364
+ const { callback } = tableActionMethod;
4366
4365
  const clientActionPromise = callback(tableActionDetail);
4367
4366
  clientActionPromises.push(clientActionPromise);
4368
4367
  }
@@ -4463,7 +4462,7 @@ class BasicFormComponent extends FormStructureAndData {
4463
4462
  }
4464
4463
  notifyFormActivity() {
4465
4464
  if (this._notifyFormActivity) {
4466
- this._eventEmiter.next('formActivity', { code: this.formCode });
4465
+ this._eventEmiter.next('formActivity', { code: this.name });
4467
4466
  }
4468
4467
  }
4469
4468
  /**
@@ -4793,6 +4792,167 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
4793
4792
  type: Injectable
4794
4793
  }] });
4795
4794
 
4795
+ const DEFAULT_STREAM_PATH = '/liveconnect/stream';
4796
+ const DEFAULT_SESSION_ENDED_EVENT = 'sessionEnded';
4797
+ const SESSION_EVENT_CLASS = 'session';
4798
+ const SESSION_REPLACED_EVENT_TYPE = 'sessionReplaced';
4799
+ /** Error que detiene los reintentos de `fetchEventSource` (handshake rechazado). */
4800
+ class FatalSseError extends Error {
4801
+ }
4802
+ /**
4803
+ * Canal de eventos servidor→cliente sobre Server-Sent Events (SSE).
4804
+ *
4805
+ * Reemplaza al `LiveConnectionService` basado en Socket.IO que vivía duplicado
4806
+ * en cada app. El uso siempre fue unidireccional (un único handshake y luego
4807
+ * solo recepción), así que SSE encaja sin perder funcionalidad y además gana
4808
+ * reconexión automática nativa.
4809
+ *
4810
+ * El servicio es agnóstico de la app: toda la integración (URL, token de auth,
4811
+ * allow-list, re-emisión al bus, logger) llega por `SSE_LIVE_CONNECTION_CONFIG`.
4812
+ * El ciclo de vida (cuándo abrir/cerrar) lo controla cada app llamando
4813
+ * `open()`/`close()` — típicamente atado a `sessionEstablished`/`sessionEnded`,
4814
+ * y en móvil además al `appStateChange` de Capacitor.
4815
+ */
4816
+ class SseLiveConnectionService {
4817
+ _config = inject(SSE_LIVE_CONNECTION_CONFIG);
4818
+ _abort = null;
4819
+ _currentSessionId = null;
4820
+ _connected = false;
4821
+ isConnected() {
4822
+ return this._connected;
4823
+ }
4824
+ /**
4825
+ * Abre el stream SSE para la sesión dada (cierra cualquier stream anterior).
4826
+ * El handshake viaja en el header `Authorization`, no en la URL.
4827
+ */
4828
+ async open(sessionData) {
4829
+ this.close();
4830
+ if (!sessionData) {
4831
+ return;
4832
+ }
4833
+ this._currentSessionId = sessionData?.sessionId ?? null;
4834
+ const logger = this._config.logger;
4835
+ const allowed = this._allowedSet();
4836
+ const token = await this._config.getAuthToken(sessionData);
4837
+ const scheme = this._config.authScheme ?? 'Bearer';
4838
+ const authorization = scheme ? `${scheme} ${token}` : token;
4839
+ const abort = new AbortController();
4840
+ this._abort = abort;
4841
+ this.openEventSource(this._buildStreamUrl(), {
4842
+ signal: abort.signal,
4843
+ openWhenHidden: this._config.keepOpenWhenHidden ?? true,
4844
+ headers: { Authorization: authorization },
4845
+ onopen: async (response) => {
4846
+ const contentType = response.headers.get('content-type') ?? '';
4847
+ if (response.ok && contentType.includes('text/event-stream')) {
4848
+ this._connected = true;
4849
+ return;
4850
+ }
4851
+ // 4xx (p. ej. 401) => fatal, no reintentar. 5xx/otros => reintentar.
4852
+ if (response.status >= 400 && response.status < 500) {
4853
+ throw new FatalSseError(`handshake rechazado: ${response.status}`);
4854
+ }
4855
+ throw new Error(`handshake inesperado: ${response.status}`);
4856
+ },
4857
+ onmessage: msg => {
4858
+ if (!msg.data) {
4859
+ return; // comentarios/heartbeats no traen `data`
4860
+ }
4861
+ let eventData;
4862
+ try {
4863
+ eventData = JSON.parse(msg.data);
4864
+ }
4865
+ catch {
4866
+ logger?.warn?.('[SseLiveConnection] Payload no-JSON descartado');
4867
+ return;
4868
+ }
4869
+ logger?.debug?.(`[SseLiveConnection] Evento recibido: ${msg.data}`);
4870
+ if (this._handleSessionReplaced(eventData)) {
4871
+ return;
4872
+ }
4873
+ const eventClass = eventData?.eventClass;
4874
+ if (typeof eventClass !== 'string' || !allowed.has(eventClass)) {
4875
+ logger?.warn?.('[SseLiveConnection] Evento no permitido rechazado:', eventClass);
4876
+ return;
4877
+ }
4878
+ this._config.emit(eventClass, eventData);
4879
+ },
4880
+ onerror: err => {
4881
+ this._connected = false;
4882
+ if (err instanceof FatalSseError) {
4883
+ logger?.warn?.('[SseLiveConnection]', err.message);
4884
+ throw err; // detiene los reintentos
4885
+ }
4886
+ logger?.warn?.('[SseLiveConnection] error de stream, reintentando', err?.message ?? err);
4887
+ // devolver undefined => fetch-event-source reintenta con backoff propio
4888
+ },
4889
+ }).catch(err => {
4890
+ this._connected = false;
4891
+ if (!(err instanceof FatalSseError) && err?.name !== 'AbortError') {
4892
+ logger?.warn?.('[SseLiveConnection] stream finalizado', err?.message ?? err);
4893
+ }
4894
+ });
4895
+ }
4896
+ /**
4897
+ * Punto de indirección (seam) sobre `fetchEventSource`: permite sustituirlo en
4898
+ * tests (`fetchEventSource` es un binding ESM de solo lectura, no espiable).
4899
+ * En producción delega directamente en la librería.
4900
+ */
4901
+ openEventSource(url, options) {
4902
+ return fetchEventSource(url, options);
4903
+ }
4904
+ /** Cierra el stream actual (idempotente). */
4905
+ close() {
4906
+ if (this._abort) {
4907
+ this._abort.abort();
4908
+ this._abort = null;
4909
+ }
4910
+ this._connected = false;
4911
+ }
4912
+ _buildStreamUrl() {
4913
+ const base = (this._config.buildUrl() ?? '').replace(/\/+$/, '');
4914
+ const path = this._config.streamPath ?? DEFAULT_STREAM_PATH;
4915
+ return `${base}${path.startsWith('/') ? path : '/' + path}`;
4916
+ }
4917
+ _allowedSet() {
4918
+ const allowed = this._config.allowedEvents;
4919
+ return allowed instanceof Set ? allowed : new Set(allowed);
4920
+ }
4921
+ /**
4922
+ * Maneja el evento de lifecycle `sessionReplaced` (otra apertura de sesión
4923
+ * para el mismo usuario). Si el `newSessionId` difiere de la sesión local,
4924
+ * emite el evento de fin de sesión para forzar logout. Se ejecuta antes del
4925
+ * filtro de allow-list porque no se re-emite al bus genérico.
4926
+ * Devuelve `true` cuando consume el evento.
4927
+ */
4928
+ _handleSessionReplaced(eventData) {
4929
+ if ((this._config.handleSessionReplaced ?? true) === false) {
4930
+ return false;
4931
+ }
4932
+ if (eventData?.eventClass !== SESSION_EVENT_CLASS ||
4933
+ eventData?.eventType !== SESSION_REPLACED_EVENT_TYPE) {
4934
+ return false;
4935
+ }
4936
+ const newSessionId = eventData?.eventDetail?.newSessionId ?? null;
4937
+ if (!this._currentSessionId) {
4938
+ return true; // no hay sesión local que cerrar
4939
+ }
4940
+ if (newSessionId && newSessionId === this._currentSessionId) {
4941
+ return true; // corresponde a la propia sesión recién abierta
4942
+ }
4943
+ this._config.logger?.warn?.('[SseLiveConnection] Sesión reemplazada por otra apertura para el mismo usuario', { currentSessionId: this._currentSessionId, newSessionId });
4944
+ const sessionEndedName = this._config.sessionEndedEventName ?? DEFAULT_SESSION_ENDED_EVENT;
4945
+ this._config.emit(sessionEndedName, null);
4946
+ return true;
4947
+ }
4948
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SseLiveConnectionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
4949
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SseLiveConnectionService, providedIn: 'root' });
4950
+ }
4951
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SseLiveConnectionService, decorators: [{
4952
+ type: Injectable,
4953
+ args: [{ providedIn: 'root' }]
4954
+ }] });
4955
+
4796
4956
  const COMPONENTS = [
4797
4957
  ActionComponent,
4798
4958
  FieldComponent,
@@ -4845,5 +5005,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
4845
5005
  * Generated bundle index. Do not edit.
4846
5006
  */
4847
5007
 
4848
- export { ActionComponent, BaseIconResolverService, BasicFormComponent, ComparisonOperator, ElementComponent, ElementType, FieldComponent, FieldDescriptor, FormAction, FormActionType, FormElement, FormErrorComponent, FormHeaderComponent, FormPiece, FormPiecePropagate, FormStructureAndData, HEADER, ICON_RESOLVER, IconDictionaryService, LibEventManagerService, LibFileManagementService, LibFormManagerService, LibTableComponent, LibTableRecordActionComponent, LibTableRecordFieldComponent, NO_ERROR, PieceComponent, RecordFormSection, RecordFormSubSection, RecordTable, RecordTableColumn, SectionComponent, SubSectionComponent, TableAction, TableRecordData, TuainNgFormsLibModule, elementTypes, formActions, iconDictionary, operators };
5008
+ export { ActionComponent, BaseIconResolverService, BasicFormComponent, ComparisonOperator, ElementComponent, ElementType, FieldComponent, FieldDescriptor, FormAction, FormActionType, FormElement, FormErrorComponent, FormHeaderComponent, FormPiece, FormPiecePropagate, FormStructureAndData, HEADER, ICON_RESOLVER, IconDictionaryService, LibEventManagerService, LibFileManagementService, LibFormManagerService, LibTableComponent, LibTableRecordActionComponent, LibTableRecordFieldComponent, NO_ERROR, PieceComponent, RecordFormSection, RecordFormSubSection, RecordTable, RecordTableColumn, SSE_LIVE_CONNECTION_CONFIG, SectionComponent, SseLiveConnectionService, SubSectionComponent, TableAction, TableRecordData, TuainNgFormsLibModule, elementTypes, formActions, iconDictionary, operators };
4849
5009
  //# sourceMappingURL=tuain-ng-forms-lib.mjs.map