xonecode 0.1.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 (187) hide show
  1. package/README.md +167 -0
  2. package/dist/agent/authEnDisco.js +56 -0
  3. package/dist/agent/authEnDisco.js.map +1 -0
  4. package/dist/agent/configEnDisco.js +109 -0
  5. package/dist/agent/configEnDisco.js.map +1 -0
  6. package/dist/agent/crearProyecto.js +34 -0
  7. package/dist/agent/crearProyecto.js.map +1 -0
  8. package/dist/agent/entorno.js +124 -0
  9. package/dist/agent/entorno.js.map +1 -0
  10. package/dist/agent/guionizado.js +53 -0
  11. package/dist/agent/guionizado.js.map +1 -0
  12. package/dist/agent/instantanea.js +129 -0
  13. package/dist/agent/instantanea.js.map +1 -0
  14. package/dist/agent/interrupts.js +83 -0
  15. package/dist/agent/interrupts.js.map +1 -0
  16. package/dist/agent/mensajes.js +24 -0
  17. package/dist/agent/mensajes.js.map +1 -0
  18. package/dist/agent/modelos.js +42 -0
  19. package/dist/agent/modelos.js.map +1 -0
  20. package/dist/agent/normalizar.js +20 -0
  21. package/dist/agent/normalizar.js.map +1 -0
  22. package/dist/agent/perfiles.js +103 -0
  23. package/dist/agent/perfiles.js.map +1 -0
  24. package/dist/agent/proyecto.js +107 -0
  25. package/dist/agent/proyecto.js.map +1 -0
  26. package/dist/agent/puente.js +142 -0
  27. package/dist/agent/puente.js.map +1 -0
  28. package/dist/agent/resumenDeTool.js +48 -0
  29. package/dist/agent/resumenDeTool.js.map +1 -0
  30. package/dist/agent/skills.js +65 -0
  31. package/dist/agent/skills.js.map +1 -0
  32. package/dist/agent/textoDeTool.js +113 -0
  33. package/dist/agent/textoDeTool.js.map +1 -0
  34. package/dist/agent/turnoReal.js +173 -0
  35. package/dist/agent/turnoReal.js.map +1 -0
  36. package/dist/agent/verificador.js +65 -0
  37. package/dist/agent/verificador.js.map +1 -0
  38. package/dist/agent/xoneAgent.js +106 -0
  39. package/dist/agent/xoneAgent.js.map +1 -0
  40. package/dist/bin.js +9 -0
  41. package/dist/bin.js.map +1 -0
  42. package/dist/cli/aprobar.js +82 -0
  43. package/dist/cli/aprobar.js.map +1 -0
  44. package/dist/cli/config.js +133 -0
  45. package/dist/cli/config.js.map +1 -0
  46. package/dist/cli/consola.js +346 -0
  47. package/dist/cli/consola.js.map +1 -0
  48. package/dist/cli/describe.js +53 -0
  49. package/dist/cli/describe.js.map +1 -0
  50. package/dist/cli/doctor.js +45 -0
  51. package/dist/cli/doctor.js.map +1 -0
  52. package/dist/cli/main.js +520 -0
  53. package/dist/cli/main.js.map +1 -0
  54. package/dist/cli/markdown.js +90 -0
  55. package/dist/cli/markdown.js.map +1 -0
  56. package/dist/cli/run.js +164 -0
  57. package/dist/cli/run.js.map +1 -0
  58. package/dist/cli/spinner.js +89 -0
  59. package/dist/cli/spinner.js.map +1 -0
  60. package/dist/cli/stdio.js +193 -0
  61. package/dist/cli/stdio.js.map +1 -0
  62. package/dist/cli/tema.js +40 -0
  63. package/dist/cli/tema.js.map +1 -0
  64. package/dist/cli/verify.js +62 -0
  65. package/dist/cli/verify.js.map +1 -0
  66. package/dist/core/bitacora.js +30 -0
  67. package/dist/core/bitacora.js.map +1 -0
  68. package/dist/core/config.js +236 -0
  69. package/dist/core/config.js.map +1 -0
  70. package/dist/core/contextos.js +56 -0
  71. package/dist/core/contextos.js.map +1 -0
  72. package/dist/core/deps.js +51 -0
  73. package/dist/core/deps.js.map +1 -0
  74. package/dist/core/diff.js +79 -0
  75. package/dist/core/diff.js.map +1 -0
  76. package/dist/core/esqueleto.js +366 -0
  77. package/dist/core/esqueleto.js.map +1 -0
  78. package/dist/core/events.js +2 -0
  79. package/dist/core/events.js.map +1 -0
  80. package/dist/core/modelos.js +85 -0
  81. package/dist/core/modelos.js.map +1 -0
  82. package/dist/core/notify.js +106 -0
  83. package/dist/core/notify.js.map +1 -0
  84. package/dist/core/ports.js +114 -0
  85. package/dist/core/ports.js.map +1 -0
  86. package/dist/core/turno.js +127 -0
  87. package/dist/core/turno.js.map +1 -0
  88. package/dist/vendor/hitl.js +103 -0
  89. package/dist/vendor/hitl.js.map +1 -0
  90. package/dist/vendor/skillLoaders/catalog.js +74 -0
  91. package/dist/vendor/skillLoaders/catalog.js.map +1 -0
  92. package/dist/vendor/tokenTracking.js +58 -0
  93. package/dist/vendor/tokenTracking.js.map +1 -0
  94. package/package.json +41 -0
  95. package/skills/xone-debugging/SKILL.md +52 -0
  96. package/skills/xone-debugging/references/faq.md +561 -0
  97. package/skills/xone-debugging/references/troubleshooting-y-glosario.md +429 -0
  98. package/skills/xone-development/SKILL.md +105 -0
  99. package/skills/xone-development/references/anti-patrones.md +94 -0
  100. package/skills/xone-development/references/css/atributos-por-categoria.md +509 -0
  101. package/skills/xone-development/references/css/buenas-practicas-y-parser.md +419 -0
  102. package/skills/xone-development/references/css/dinamicos-cascada-y-componentes.md +550 -0
  103. package/skills/xone-development/references/css/patrones-material-y-temas.md +1140 -0
  104. package/skills/xone-development/references/css/propiedades-y-herencia.md +885 -0
  105. package/skills/xone-development/references/css/selectores-unidades-colores.md +840 -0
  106. package/skills/xone-development/references/datos/appdata-referencia-ampliada.md +457 -0
  107. package/skills/xone-development/references/datos/appdata.md +611 -0
  108. package/skills/xone-development/references/datos/http-sqlmanager-y-crypto.md +720 -0
  109. package/skills/xone-development/references/datos/http.md +366 -0
  110. package/skills/xone-development/references/datos/oauth2-y-replica.md +156 -0
  111. package/skills/xone-development/references/device/biometria-imagedrawing-y-otros.md +544 -0
  112. package/skills/xone-development/references/device/objetos-de-dispositivo.md +583 -0
  113. package/skills/xone-development/references/device/systemsettings-referencia-ampliada.md +396 -0
  114. package/skills/xone-development/references/device/systemsettings-y-permisos.md +342 -0
  115. package/skills/xone-development/references/fundamentos/conceptos-clave.md +695 -0
  116. package/skills/xone-development/references/fundamentos/configuracion-app-xml-ini-mappings.md +668 -0
  117. package/skills/xone-development/references/fundamentos/errores-comunes.md +312 -0
  118. package/skills/xone-development/references/fundamentos/navegacion-convenciones-y-primer-proyecto.md +576 -0
  119. package/skills/xone-development/references/fundamentos/plataforma-y-anatomia-de-proyecto.md +387 -0
  120. package/skills/xone-development/references/indice-completo.md +77 -0
  121. package/skills/xone-development/references/javascript/coleccion-error-y-usuario.md +260 -0
  122. package/skills/xone-development/references/javascript/debugging-y-best-practices.md +245 -0
  123. package/skills/xone-development/references/javascript/metodos-de-los-controles.md +556 -0
  124. package/skills/xone-development/references/javascript/metodos-nativos-de-la-vista.md +114 -0
  125. package/skills/xone-development/references/javascript/motor-js-y-contexto-de-ejecucion.md +319 -0
  126. package/skills/xone-development/references/javascript/objeto-ai-llm-en-dispositivo.md +358 -0
  127. package/skills/xone-development/references/javascript/objetos-creables-a-m.md +527 -0
  128. package/skills/xone-development/references/javascript/objetos-creables-n-z.md +385 -0
  129. package/skills/xone-development/references/javascript/patrones-criticos-seguridad-y-rendimiento.md +595 -0
  130. package/skills/xone-development/references/javascript/patrones-de-navegacion-datos-y-codigo.md +751 -0
  131. package/skills/xone-development/references/javascript/patrones-de-ui-voz-integracion-y-seguridad.md +701 -0
  132. package/skills/xone-development/references/javascript/plantillas-y-funciones-utilitarias.md +647 -0
  133. package/skills/xone-development/references/javascript/self-y-dataobject.md +449 -0
  134. package/skills/xone-development/references/javascript/singletons-globales.md +361 -0
  135. package/skills/xone-development/references/javascript/ui-catalogo-de-metodos.md +464 -0
  136. package/skills/xone-development/references/javascript/ui-gps-camara-y-multimedia.md +506 -0
  137. package/skills/xone-development/references/javascript/ui-navegacion-mensajes-y-vista.md +422 -0
  138. package/skills/xone-development/references/resumen-js-datos-dispositivo.md +80 -0
  139. package/skills/xone-development/references/resumen-xml-y-css.md +74 -0
  140. package/skills/xone-development/references/tipos-de-prop.md +28 -0
  141. package/skills/xone-development/references/xml-ui/asfilter-visibilidad-eventos-y-macros.md +576 -0
  142. package/skills/xone-development/references/xml-ui/atributos-coll-group-frame.md +235 -0
  143. package/skills/xone-development/references/xml-ui/atributos-method-macro-script-event-app.md +244 -0
  144. package/skills/xone-development/references/xml-ui/atributos-prop.md +439 -0
  145. package/skills/xone-development/references/xml-ui/contents-y-macros.md +392 -0
  146. package/skills/xone-development/references/xml-ui/errores-comunes-xml.md +245 -0
  147. package/skills/xone-development/references/xml-ui/estructura-y-nodo-coll.md +326 -0
  148. package/skills/xone-development/references/xml-ui/eventos-ciclo-de-vida-e-interaccion.md +704 -0
  149. package/skills/xone-development/references/xml-ui/eventos-sistema-login-y-personalizados.md +944 -0
  150. package/skills/xone-development/references/xml-ui/layouts-herencia-y-buenas-practicas.md +618 -0
  151. package/skills/xone-development/references/xml-ui/mapas.md +685 -0
  152. package/skills/xone-development/references/xml-ui/mappings-y-colecciones-separadas.md +148 -0
  153. package/skills/xone-development/references/xml-ui/nodos-group-y-frame.md +666 -0
  154. package/skills/xone-development/references/xml-ui/patrones-de-pantalla.md +643 -0
  155. package/skills/xone-development/references/xml-ui/prop-atributos-y-condiciones.md +298 -0
  156. package/skills/xone-development/references/xml-ui/prop-tipos-basicos.md +493 -0
  157. package/skills/xone-development/references/xml-ui/prop-tipos-combos-y-controles.md +664 -0
  158. package/skills/xone-development/references/xml-ui/prop-tipos-listas-y-mapas.md +412 -0
  159. package/skills/xone-plan-builder/SKILL.md +183 -0
  160. package/skills/xone-plan-builder/agents/openai.yaml +5 -0
  161. package/skills/xone-plan-builder/references/TASKS-FORMAT.md +132 -0
  162. package/skills/xone-project-generator/SKILL.md +111 -0
  163. package/skills/xone-project-generator/references/canonical-sizes.md +292 -0
  164. package/skills/xone-project-generator/references/colecciones-base.md +16 -0
  165. package/skills/xone-project-generator/references/convenciones-de-nombres.md +16 -0
  166. package/skills/xone-project-generator/references/ejemplos-por-sector-y-prohibiciones.md +140 -0
  167. package/skills/xone-project-generator/references/fase-3-estilos-css.md +597 -0
  168. package/skills/xone-project-generator/references/fase-6-colecciones.md +762 -0
  169. package/skills/xone-project-generator/references/fase-7-asfilter-e-integraciones.md +142 -0
  170. package/skills/xone-project-generator/references/fase-7-entidades-y-estructura-de-pantalla.md +494 -0
  171. package/skills/xone-project-generator/references/fase-7-plantilla-consola.md +477 -0
  172. package/skills/xone-project-generator/references/fase-7-plantillas-de-pantalla.md +302 -0
  173. package/skills/xone-project-generator/references/fase-7-viewmodes-graficos-y-listas.md +681 -0
  174. package/skills/xone-project-generator/references/fase-7-viewmodes-mapa-y-calendario.md +479 -0
  175. package/skills/xone-project-generator/references/fases-0-2-analisis-y-modelo-de-datos.md +350 -0
  176. package/skills/xone-project-generator/references/fases-10-12-readmes-y-validacion.md +194 -0
  177. package/skills/xone-project-generator/references/fases-4-5-estructura-y-configuracion.md +587 -0
  178. package/skills/xone-project-generator/references/fases-8-9-eventos-y-javascript.md +861 -0
  179. package/skills/xone-project-generator/references/flujo-de-generacion.md +67 -0
  180. package/skills/xone-project-generator/references/plantillas-estandar.md +98 -0
  181. package/skills/xone-project-generator/references/tamanos-canonicos.md +49 -0
  182. package/skills/xone-review/SKILL.md +189 -0
  183. package/skills/xone-spec-builder/SKILL.md +235 -0
  184. package/skills/xone-spec-builder/agents/openai.yaml +5 -0
  185. package/skills/xone-spec-builder/references/ADR-FORMAT.md +55 -0
  186. package/skills/xone-spec-builder/references/CONTEXT-FORMAT.md +42 -0
  187. package/skills/xone-spec-builder/references/PLAN-FORMAT.md +120 -0
@@ -0,0 +1,720 @@
1
+ # XOne — $http, SqlManager y crypto: referencia ampliada
2
+
3
+ > Fuente: `xone/v2/xone-project-generator/references/xone-javascript-patterns-c-appdata-http.md` §2.6–§2.9. Referencia de la skill; el índice está en [../../SKILL.md](../../SKILL.md).
4
+
5
+ Contenido: segunda redacción del corpus para $http, más SqlManager y la API crypto
6
+
7
+ ---
8
+
9
+ ### 2.6 API HTTP (`$http`)
10
+
11
+ #### 2.6.1 Estructura del objeto request
12
+
13
+ Todos los métodos `$http` reciben un objeto `request` con la siguiente estructura. Todos los campos son opcionales según el caso de uso:
14
+
15
+ ```javascript
16
+ let request = {
17
+ // Cabeceras HTTP
18
+ headers: {
19
+ "Content-Type" : "application/json",
20
+ "Authorization": "Bearer " + token,
21
+ "Accept-Encoding": "br" // Para Brotli
22
+ },
23
+ // Parametros de la peticion
24
+ parameters: {
25
+ connectTimeout : 120000, // ms espera conexión (recomendado: 120000)
26
+ readTimeout : 120000, // ms espera respuesta (recomendado: 120000)
27
+ allowUnsafeCertificates: false, // true = acepta certificados autofirmados
28
+ allowedRootCas : ["mi_ca.crt"], // CAs propias de confianza
29
+ enablePinning : true, // Activar certificate pinning
30
+ },
31
+ // Cuerpo / parametros de la peticion
32
+ // En GET: se añaden como query string (?clave=valor)
33
+ // En POST/PUT/PATCH/DELETE: se envian como body
34
+ // Puede ser un objeto JS (se serializa a JSON) o una cadena (XML, etc.)
35
+ data: {
36
+ campo1: "valor1",
37
+ campo2: "valor2"
38
+ },
39
+ // Certificado de cliente (mutual TLS)
40
+ privateKey : authenticationKey, // Obtenido con KeyStore
41
+ certificateChain: certificateChain, // Obtenido con KeyStore
42
+ // Ruta donde volcar la cadena de certificacion del servidor (solo depuracion)
43
+ dumpCertificateChainPath: "/sdcard/Download/"
44
+ };
45
+ ```
46
+
47
+ **Callbacks de respuesta:**
48
+
49
+ ```javascript
50
+ // Success: (sData, responseHeaders, nHttpStatusCode, fromCache, fromCacheDate)
51
+ // - sData: cuerpo de la respuesta como string
52
+ // - responseHeaders: objeto con las cabeceras de respuesta
53
+ // - nHttpStatusCode: código HTTP (200, 404, etc.)
54
+ // - fromCache: true si sData viene de la caché offline (ver más abajo); false en éxito de red
55
+ // - fromCacheDate: Date de la entrada cacheada (solo informado cuando fromCache es true)
56
+ // Error: (nError, sErrorDesc)
57
+ ```
58
+
59
+ **Caché de disco para offline (`cacheData`):** opt-in por petición. Guarda la última respuesta exitosa y, si una petición posterior **falla por error de conexión o por un 5xx**, sirve esa respuesta cacheada de forma transparente (los 4xx van por el flujo de error normal). Aplica a todos los verbos.
60
+
61
+ ```javascript
62
+ $http.post("https://api.example.com/datos", {
63
+ data : { id: 1 },
64
+ cacheData : true, // activa la caché para esta petición
65
+ cacheTTL : 3600, // opcional: segundos de validez (sin él o <=0 = no caduca)
66
+ cacheSetting: {
67
+ // Campos del body (rutas con punto) excluidos de la clave, para que dos llamadas que
68
+ // solo difieren en ellos compartan entrada. Si se pasa, REEMPLAZA por completo a los
69
+ // defaults ["transacid", "data.headers"].
70
+ ignoreBodyFields: ["transacid", "data.headers"]
71
+ }
72
+ },
73
+ function(sData, headers, statusCode, fromCache, fromCacheDate) {
74
+ if (fromCache) {
75
+ ui.showToast("Datos offline de " + fromCacheDate);
76
+ }
77
+ },
78
+ function(nError, sErrorDesc) {
79
+ // Solo si NO hay entrada válida en caché
80
+ }
81
+ );
82
+ // Solo se cachean respuestas de datos (JSON/texto); las descargas no. Sin cacheData, sin cambios.
83
+ ```
84
+
85
+ ---
86
+
87
+ #### 2.6.2 GET
88
+
89
+ ```javascript
90
+ // GET básico con parametros en query string
91
+ let request = {
92
+ parameters: {
93
+ connectTimeout: 120000,
94
+ readTimeout : 120000
95
+ },
96
+ data: {
97
+ format: "json" // Se añade como ?format=json
98
+ }
99
+ };
100
+
101
+ let miObjeto = self; // Guardar referencia a self antes del callback
102
+
103
+ $http.get("https://api.ipify.org", request,
104
+ function(sData, responseHeaders, nHttpStatusCode) {
105
+ let json = JSON.parse(sData);
106
+ miObjeto.MAP_IP = json.ip;
107
+ ui.refreshValue("MAP_IP");
108
+ },
109
+ function(nError, sErrorDesc) {
110
+ ui.showToast("Error " + nError + ": " + sErrorDesc);
111
+ }
112
+ );
113
+ ```
114
+
115
+ ```javascript
116
+ // GET con lectura de cabeceras de respuesta
117
+ $http.get("https://api.example.com/datos", request,
118
+ function(sData, responseHeaders) {
119
+ // responseHeaders es un objeto con todas las cabeceras
120
+ let fecha = new Date(responseHeaders.Date).getDate();
121
+ let contentType = responseHeaders["Content-Type"];
122
+ },
123
+ function(nError, sErrorDesc) {}
124
+ );
125
+ ```
126
+
127
+ ```javascript
128
+ // GET con compresion Brotli
129
+ let request = {
130
+ parameters: { connectTimeout: 120000, readTimeout: 120000 },
131
+ headers : { "Accept-Encoding": "br" }
132
+ };
133
+ $http.get("https://api.example.com/datos", request,
134
+ function(sData) { showData(self, sData); },
135
+ function(nError, sErrorDesc) {}
136
+ );
137
+ ```
138
+
139
+ ---
140
+
141
+ #### 2.6.3 POST
142
+
143
+ ```javascript
144
+ // POST con body JSON
145
+ let request = {
146
+ headers : { "Content-Type": "application/json" },
147
+ parameters: { connectTimeout: 120000, readTimeout: 120000 },
148
+ data : { nombre: "Juan", activo: true }
149
+ };
150
+
151
+ ui.showWaitDialog("Enviando...");
152
+ $http.post("https://api.example.com/usuarios", request,
153
+ function(sData, headers, nHttpStatusCode) {
154
+ let resultado = JSON.parse(sData);
155
+ ui.showToast("Creado con ID: " + resultado.id);
156
+ ui.hideWaitDialog();
157
+ },
158
+ function(nError, sErrorDesc) {
159
+ ui.showToast("Error: " + sErrorDesc);
160
+ ui.hideWaitDialog();
161
+ }
162
+ );
163
+ ```
164
+
165
+ ```javascript
166
+ // POST con body XML (data como string, no objeto)
167
+ let request = {
168
+ headers : { "Content-Type": "application/xml" },
169
+ parameters: { connectTimeout: 120000, readTimeout: 120000 },
170
+ data : "<note><to>Tove</to><from>Jani</from></note>"
171
+ };
172
+ $http.post("https://api.example.com/xml", request,
173
+ function(sData) {},
174
+ function(nError, sErrorDesc) {}
175
+ );
176
+ ```
177
+
178
+ ```javascript
179
+ // POST con timeout intencionadamente corto
180
+ let request = {
181
+ parameters: { connectTimeout: 3000, readTimeout: 3000 }
182
+ };
183
+ $http.post("https://api.example.com/lenta", request,
184
+ function(sData) {},
185
+ function(nError, sErrorDesc) {
186
+ // nError será de timeout si el servidor tarda mas de 3 segundos
187
+ ui.showToast("Timeout: " + sErrorDesc);
188
+ }
189
+ );
190
+ ```
191
+
192
+ ---
193
+
194
+ #### 2.6.4 PUT / DELETE / PATCH
195
+
196
+ ```javascript
197
+ let request = {
198
+ headers : { "Content-Type": "application/json" },
199
+ parameters: { connectTimeout: 120000, readTimeout: 120000 },
200
+ data : { campo: "valor" }
201
+ };
202
+
203
+ $http.put("https://api.example.com/recurso/1", request, successCb, errorCb);
204
+ $http.delete("https://api.example.com/recurso/1", request, successCb, errorCb);
205
+ $http.patch("https://api.example.com/recurso/1", request, successCb, errorCb);
206
+ ```
207
+
208
+ ---
209
+
210
+ #### 2.6.5 Descarga de fichero
211
+
212
+ ```javascript
213
+ // Descarga con GET (por defecto)
214
+ $http.download("https://example.com/documento.pdf", {},
215
+ function(sPath, headers, nHttpStatusCode) {
216
+ // sPath: ruta local donde se ha guardado el fichero descargado
217
+ ui.openFile(sPath);
218
+ },
219
+ function(nError, sMessage) {
220
+ ui.showToast("Error en descarga: " + sMessage);
221
+ }
222
+ );
223
+
224
+ // Descarga con POST (añadir method y data al request)
225
+ $http.download("https://example.com/informe", {
226
+ // method: "POST",
227
+ // data: { token: "abc", tipo: "pdf" }
228
+ },
229
+ function(sPath, headers, nHttpStatusCode) {
230
+ ui.openFile(sPath);
231
+ },
232
+ function(nError, sMessage) {
233
+ ui.showToast("Error: " + sMessage);
234
+ }
235
+ );
236
+ ```
237
+
238
+ ---
239
+
240
+ #### 2.6.6 Futures: llamadas en paralelo
241
+
242
+ Un `Future` es el objeto que devuelve cualquier método `$http`. Permite lanzar varias llamadas en paralelo y recoger los resultados cuando todas hayan terminado.
243
+
244
+ - **`future.getResult()`** — devuelve el cuerpo de la respuesta como **string**
245
+ - **`future.get()`** — devuelve el cuerpo **parseado a objeto JS** cuando es posible. **Preferible en la mayoría de casos**
246
+ - **`future.cancel()`** — cancela la peticion si aún no ha terminado
247
+
248
+ ```javascript
249
+ // Lanzar tres peticiones en paralelo (sin callbacks)
250
+ // Las tres se ejecutan simultaneamente
251
+ let future1 = $http.get("https://api.example.com/datos1", { data: { id: 1 } });
252
+ let future2 = $http.get("https://api.example.com/datos2", { data: { id: 2 } });
253
+ let future3 = $http.get("https://api.example.com/datos3", { data: { id: 3 } });
254
+
255
+ // getResult() bloquea hasta que cada peticion termina
256
+ let sValor1 = future1.getResult(); // string
257
+ let sValor2 = future2.getResult();
258
+ let sValor3 = future3.getResult();
259
+
260
+ // get() devuelve objeto JS si la respuesta es JSON parseable
261
+ let oValor1 = future1.get(); // objeto JS (preferible)
262
+ ```
263
+
264
+ ```javascript
265
+ // Futures con callbacks Y recogida de resultado
266
+ // Los callbacks se ejecutan cuando cada peticion termina
267
+ // getResult() sigue siendo util para esperar todas antes de continuar
268
+ let future1 = $http.get("https://api.example.com/datos1", { data: { text: "uno" } },
269
+ function(sData, responseHeaders) { ui.showToast("Callback OK #1"); },
270
+ function(nError, sErrorDesc) { ui.showToast("Callback error #1"); }
271
+ );
272
+ let future2 = $http.get("https://api.example.com/datos2", { data: { text: "dos" } },
273
+ function(sData, responseHeaders) { ui.showToast("Callback OK #2"); },
274
+ function(nError, sErrorDesc) { ui.showToast("Callback error #2"); }
275
+ );
276
+
277
+ // Esperar a que ambas terminen y recoger resultado
278
+ let sValor1 = future1.getResult();
279
+ let sValor2 = future2.getResult();
280
+ ```
281
+
282
+ ---
283
+
284
+ #### 2.6.7 Cancelar request
285
+
286
+ ```javascript
287
+ let future = $http.post("https://api.example.com/lenta", {},
288
+ function(sData) {},
289
+ function(nError, sErrorDesc) {
290
+ // Se llamara con error de cancelacion
291
+ }
292
+ );
293
+ // Cancelar inmediatamente (o en cualquier momento antes de que termine)
294
+ future.cancel();
295
+ ```
296
+
297
+ ---
298
+
299
+ #### 2.6.8 Seguridad SSL/TLS
300
+
301
+ ##### Certificados autofirmados (unsafe)
302
+
303
+ Solo para entornos de desarrollo/pruebas. **Nunca en produccion.**
304
+
305
+ ```javascript
306
+ let request = {
307
+ parameters: {
308
+ allowUnsafeCertificates: true,
309
+ connectTimeout: 120000,
310
+ readTimeout : 120000
311
+ }
312
+ };
313
+ $http.get("https://servidor-con-cert-autofirmado.com", request,
314
+ function(sData) {},
315
+ function(nError, sErrorDesc) {}
316
+ );
317
+ ```
318
+
319
+ ##### CA propia (certificate pinning)
320
+
321
+ Para servidores con certificado de una CA no publica. El fichero `.crt` debe estar en la carpeta de la app.
322
+
323
+ ```javascript
324
+ let request = {
325
+ parameters: {
326
+ allowedRootCas: ["mi_ca_root.crt"], // Array de ficheros .crt en la app
327
+ enablePinning : true,
328
+ connectTimeout: 120000,
329
+ readTimeout : 120000
330
+ }
331
+ };
332
+ $http.get("https://servidor-interno.example.com", request,
333
+ function(sData) {},
334
+ function(nError, sErrorDesc) {}
335
+ );
336
+ ```
337
+
338
+ ##### Certificado de cliente (mutual TLS)
339
+
340
+ Usa `KeyStore` para cargar el certificado desde un fichero `.p12`. Formatos soportados: `pkcs12`, `bks`, `jks`. Se recomienda `pkcs12` por compatibilidad.
341
+
342
+ ```javascript
343
+ ui.showWaitDialog("Abriendo keystore...");
344
+ try {
345
+ let keyStore = new KeyStore();
346
+ keyStore.open({
347
+ file : "certificado_cliente.p12",
348
+ type : "pkcs12", // pkcs12 recomendado. También: bks, jks
349
+ password: "password"
350
+ });
351
+ let privateKey = keyStore.getKey("alias");
352
+ let certificateChain = keyStore.getCertificateChain("alias");
353
+
354
+ let request = {
355
+ headers : { "Content-Type": "application/json" },
356
+ parameters : { connectTimeout: 120000, readTimeout: 120000 },
357
+ data : { campo: "valor" },
358
+ privateKey : privateKey,
359
+ certificateChain: certificateChain
360
+ };
361
+ $http.post("https://servidor-con-mutual-tls.com", request,
362
+ function(sData, headers, nHttpStatusCode) {
363
+ ui.hideWaitDialog();
364
+ },
365
+ function(nHttpStatusCode, sError) {
366
+ ui.hideWaitDialog();
367
+ }
368
+ );
369
+ } catch(ex) {
370
+ ui.hideWaitDialog();
371
+ throw ex;
372
+ }
373
+ ```
374
+
375
+ ##### Obtener la cadena de certificacion del servidor (depuracion)
376
+
377
+ Útil para obtener el `.crt` de un servidor y añadirlo como `allowedRootCas`.
378
+
379
+ ```javascript
380
+ $http.get("https://servidor.example.com", {
381
+ parameters: { connectTimeout: 120000, readTimeout: 120000 },
382
+ dumpCertificateChainPath: "/sdcard/Download/" // Carpeta donde se guardaran los .crt
383
+ }, function(sData) {
384
+ ui.showToast("Certificados guardados en /sdcard/Download/");
385
+ }, function(nError, sErrorDesc) {});
386
+ ```
387
+
388
+ ##### TLS: versión mínima
389
+
390
+ XOne negocia automáticamente la mejor versión disponible. Si el servidor requiere una versión especifica (TLS 1.0, 1.1, 1.2) se negocia sin configuración adicional — solo afecta si la versión requerida esta deshabilitada en el sistema operativo del dispositivo.
391
+
392
+ ---
393
+
394
+ #### 2.6.9 Proxy
395
+
396
+ Configura un proxy global para **toda la app**, incluido XOneLive y el replicador. Llamar con `null` para eliminar el proxy.
397
+
398
+ ```javascript
399
+ // Establecer proxy HTTP
400
+ $http.setProxy({
401
+ host: "192.168.1.100",
402
+ port: 8080,
403
+ type: "http" // "http" o "socks"
404
+ // enabledHosts: ["api.example.com"] // Solo estos hosts pasan por el proxy
405
+ // skipHosts : ["internal.example.com"] // Estos hosts NO pasan por el proxy
406
+ // NOTA: enabledHosts y skipHosts son mutuamente excluyentes
407
+ });
408
+
409
+ // Eliminar proxy
410
+ $http.setProxy(null);
411
+ ```
412
+
413
+ ---
414
+
415
+ #### 2.6.10 Verificar si HTTP (cleartext) esta permitido
416
+
417
+ En Android, por defecto solo se permiten conexiones HTTPS. Para usar HTTP se debe configurar `network_security_config.xml` en el proyecto nativo.
418
+
419
+ ```javascript
420
+ let bPermitido = systemSettings.isClearTextTrafficAllowed();
421
+ // true = HTTP sin cifrar permitido
422
+ // false = Solo HTTPS (por defecto en Android moderno)
423
+ ```
424
+
425
+ ---
426
+
427
+ #### 2.6.11 WebSocket
428
+
429
+ `WebSocket` permite comunicación bidireccional en tiempo real. Se instancia con `new WebSocket(opciones)`.
430
+
431
+ ```javascript
432
+ let ws;
433
+ let dataObject = self; // Guardar referencia antes de los callbacks
434
+
435
+ function conectarWebSocket() {
436
+ let opciones = {
437
+ url : "wss://servidor.example.com/canal",
438
+ // protocol: "mi_protocolo", // Subprotocolo opcional
439
+ // certificate: "servidor.crt", // Certificado para WSS con CA propia
440
+ // verifyWithSystemTrustManagers: true,
441
+
442
+ onOpen: function() {
443
+ ui.showToast("Conectado");
444
+ // Enviar mensaje inicial si es necesario
445
+ ws.send(JSON.stringify({ command: "login", user: "usuario" }));
446
+ },
447
+ onMessage: function(sData) {
448
+ // sData: mensaje recibido como string
449
+ dataObject.MAP_CHAT = dataObject.MAP_CHAT + sData + "\n";
450
+ ui.refreshValue("MAP_CHAT");
451
+ },
452
+ onError: function(error) {
453
+ ui.showToast("Error: " + error.message);
454
+ ws = null;
455
+ },
456
+ onClose: function() {
457
+ ui.showToast("Conexión cerrada");
458
+ ws = null;
459
+ }
460
+ };
461
+ // Cerrar conexión anterior si existe
462
+ if (ws) {
463
+ ws.close();
464
+ ws = null;
465
+ }
466
+ ws = new WebSocket(opciones);
467
+ }
468
+
469
+ function enviarMensaje(sTexto) {
470
+ if (!ws) {
471
+ throw "Conecte el WebSocket primero";
472
+ }
473
+ ws.send(JSON.stringify(sTexto));
474
+ }
475
+
476
+ function cerrarWebSocket() {
477
+ if (ws) {
478
+ ws.close();
479
+ ws = null;
480
+ }
481
+ }
482
+ ```
483
+
484
+ > **Nota:** Guardar siempre `self` en una variable local (`dataObject`) antes de definir los callbacks. Dentro de `onMessage`, `onOpen`, etc., `self` puede no estar disponible o no ser el objeto correcto.
485
+
486
+ ---
487
+
488
+ #### 2.6.12 loadFromJson / toJson
489
+
490
+ Permiten cargar datos JSON directamente en objetos y colecciones XOne, y serializar colecciones a JSON.
491
+
492
+ ```javascript
493
+ // Cargar datos en un OBJETO individual desde un string JSON
494
+ // El framework mapea las claves del JSON a los campos del objeto
495
+ let obj = new Productos();
496
+ obj.loadFromJson('{"ID": 1, "NOMBRE": "Tornillo", "PRECIO": 0.15}');
497
+ // Ahora obj.ID == 1, obj.NOMBRE == "Tornillo", obj.PRECIO == 0.15
498
+ ```
499
+
500
+ ```javascript
501
+ // Cargar datos en una COLECCION desde un array JSON
502
+ // Crea un objeto por cada elemento del array
503
+ let coll = appData.getCollection("Productos");
504
+ coll.loadFromJson('[{"ID": 1, "NOMBRE": "Tornillo"}, {"ID": 2, "NOMBRE": "Tuerca"}]');
505
+ let nTotal = coll.getCount(); // 2
506
+ let primero = coll.get(0);
507
+ // primero.ID == 1, primero.NOMBRE == "Tornillo"
508
+ ```
509
+
510
+ ```javascript
511
+ // Serializar una coleccion a array JS nativo
512
+ let coll = appData.getCollection("Usuarios");
513
+ coll.loadAll();
514
+ let jsArray = coll.toJson(); // Array de objetos JS nativos
515
+ let sJson = JSON.stringify(jsArray, null, 4); // Para enviar o mostrar
516
+
517
+ // Serializar un objeto individual
518
+ let obj = coll.get(0);
519
+ let jsObjeto = obj.toJson(); // Objeto JS nativo
520
+ let sObjJson = obj.toJsonString(); // String JSON directamente
521
+ ```
522
+
523
+ > **Caso de uso típico:** recibir datos de una API REST con `$http.get` o `$http.post`, y cargarlos directamente en una coleccion con `loadFromJson` sin necesidad de iterar campo a campo.
524
+
525
+ ---
526
+
527
+ ### 2.8 SqlManager
528
+
529
+ #### 2.8.1 Abrir Base de Datos
530
+
531
+ ```javascript
532
+ let sqlManager = new SqlManager();
533
+ let jsParams = {
534
+ databasePath : "gestion.db",
535
+ useWal : true,
536
+ readOnly : false,
537
+ useExistingConnection: true,
538
+ onDatabaseCorrupted : function() {
539
+ ui.showToast("Error: Base de datos corrupta");
540
+ }
541
+ };
542
+ sqlManager.openDatabase(jsParams);
543
+ ```
544
+
545
+ #### 2.8.2 Consultas con Parámetros
546
+
547
+ ```javascript
548
+ try {
549
+ let cursor = sqlManager.doRawQuery(
550
+ "SELECT * FROM gen_usuarios WHERE LOGIN=? AND ACTIVO=?",
551
+ "admin", 1
552
+ );
553
+ try {
554
+ let nCount = cursor.getCount();
555
+ if (nCount > 0) {
556
+ cursor.moveToFirst();
557
+ let sNombre = cursor.getString("NOMBRE");
558
+ let nId = cursor.getInteger("ID");
559
+ }
560
+ } finally {
561
+ cursor.close(); // SIEMPRE cerrar el cursor
562
+ }
563
+ } finally {
564
+ sqlManager.close(); // SIEMPRE cerrar la conexión
565
+ }
566
+ ```
567
+
568
+ #### 2.8.3 Insertar con Parámetros Seguros
569
+
570
+ ```javascript
571
+ let jsInsertParams = {
572
+ tableName: "gen_productos",
573
+ fields : {
574
+ CODIGO : "PROD001",
575
+ NOMBRE : "Producto de prueba",
576
+ PRECIO : 29.99,
577
+ ACTIVO : 1
578
+ }
579
+ };
580
+ let nIndex = sqlManager.insert(jsInsertParams);
581
+ ```
582
+
583
+ #### 2.8.4 Batch de SQLs
584
+
585
+ ```javascript
586
+ let sqls = [];
587
+ sqls.push("UPDATE gen_productos SET ACTIVO=0 WHERE STOCK=0");
588
+ sqls.push("DELETE FROM gen_log WHERE FECHA < '2024-01-01'");
589
+ sqlManager.doBatchParseSqls(sqls);
590
+ ```
591
+
592
+ #### 2.8.5 Mantenimiento de Base de Datos
593
+
594
+ ```javascript
595
+ sqlManager.doWalCheckpoint(); // Consolidar WAL
596
+ sqlManager.doVacuum(); // Compactar BD
597
+ sqlManager.dropAllIndexes(); // Eliminar indices
598
+ ```
599
+
600
+ ---
601
+
602
+ ### 2.9 API Crypto
603
+
604
+ #### 2.9.1 Hashing
605
+
606
+ ```javascript
607
+ let hash = crypto.hash({
608
+ data : "texto a hashear",
609
+ algorithm : "SHA-256", // MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512
610
+ outputFormat: "hex", // "hex" o "base64"
611
+ key : "clave_hmac" // Opcional: para HMAC
612
+ });
613
+
614
+ let md5 = crypto.md5({ data: "texto", outputFormat: "hex" });
615
+ let sha1 = crypto.sha1({ data: "texto", outputFormat: "hex" });
616
+ let sha256 = crypto.sha256({ data: "texto", outputFormat: "hex" });
617
+ let sha512 = crypto.sha512({ data: "texto", outputFormat: "hex" });
618
+ ```
619
+
620
+ #### 2.9.2 Encoding
621
+
622
+ ```javascript
623
+ let encoded = crypto.toBase64({ data: "texto plano", urlSafe: true });
624
+ let decoded = crypto.fromBase64({ data: encoded });
625
+
626
+ let b58 = crypto.toBase58({ data: "texto" });
627
+ let decoded58 = crypto.fromBase58({ data: b58 });
628
+
629
+ let b45 = crypto.toBase45({ data: "texto" });
630
+ let b32 = crypto.toBase32({ data: "texto" });
631
+ ```
632
+
633
+ #### 2.9.3 Cifrado Simetrico (AES)
634
+
635
+ ```javascript
636
+ let aesKey = crypto.generateAesKey({
637
+ alias : "mi_clave_aes",
638
+ keySize : 256,
639
+ useSecureHardware: true,
640
+ useStrongBox : true
641
+ });
642
+
643
+ let derivedKey = crypto.derivePassword({
644
+ algorithm : "PBKDF2WithHmacSHA1",
645
+ password : "miPasswordSeguro",
646
+ salt : "salt_aleatorio_unico",
647
+ iterations: 1000,
648
+ keyLength : 256
649
+ });
650
+
651
+ let encrypted = crypto.encrypt({
652
+ data : "texto secreto",
653
+ dataFormat : "string",
654
+ algorithm : "AES/GCM/NoPadding",
655
+ key : aesKey,
656
+ outputFormat: "base64"
657
+ });
658
+
659
+ let decrypted = crypto.decrypt({
660
+ data : encrypted,
661
+ dataFormat : "base64",
662
+ algorithm : "AES/GCM/NoPadding",
663
+ key : aesKey,
664
+ outputFormat: "string"
665
+ });
666
+ ```
667
+
668
+ #### 2.9.4 Cifrado de Archivos
669
+
670
+ ```javascript
671
+ crypto.encrypt({
672
+ data: "documento.pdf", dataFormat: "file",
673
+ algorithm: "AES/GCM/NoPadding", key: aesKey,
674
+ outputFormat: "file", output: "documento.pdf.crypt"
675
+ });
676
+
677
+ crypto.decrypt({
678
+ data: "documento.pdf.crypt", dataFormat: "file",
679
+ algorithm: "AES/GCM/NoPadding", key: aesKey,
680
+ outputFormat: "file", output: "documento.pdf"
681
+ });
682
+ ```
683
+
684
+ #### 2.9.5 Firma Digital
685
+
686
+ ```javascript
687
+ let keyPair = crypto.generateKeyPair({
688
+ alias: "mi_par_claves", algorithm: "EC",
689
+ keySize: 384, output: "key", outputFormat: "file",
690
+ useSecureHardware: true
691
+ });
692
+
693
+ let publicKeyPem = keyPair.getPublicKey().toPem();
694
+ let privateKeyPem = keyPair.getPrivateKey().toPem();
695
+
696
+ let signature = crypto.sign({
697
+ data: "datos a firmar", algorithm: "SHA256withECDSA",
698
+ privateKey: privateKeyPem, outputFormat: "base64"
699
+ });
700
+
701
+ let bValid = crypto.isJwtSignatureValid({
702
+ data: jwtToken, publicKey: publicKeyPem
703
+ });
704
+ ```
705
+
706
+ #### 2.9.6 Checksum
707
+
708
+ ```javascript
709
+ let crc32 = crypto.getChecksum({ type: "crc32", data: "texto" });
710
+ let crc32File = crypto.getChecksum({ type: "crc32", file: "archivo.dat" });
711
+ ```
712
+
713
+ #### 2.9.7 Listar Algoritmos Disponibles
714
+
715
+ ```javascript
716
+ let digestAlgorithms = crypto.getAvailableDigestAlgorithms();
717
+ let cipherAlgorithms = crypto.getAvailableCipherAlgorithms();
718
+ let signatureAlgorithms = crypto.getAvailableSignatureAlgorithms();
719
+ let sslProtocols = crypto.getAvailableSslProtocols();
720
+ ```