@develia/commons 0.4.16 → 0.4.19

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 (287) hide show
  1. package/dist/cjs/array.js +22 -2
  2. package/dist/cjs/array.js.map +1 -1
  3. package/dist/cjs/async-pool-executor.js +26 -11
  4. package/dist/cjs/async-pool-executor.js.map +1 -1
  5. package/dist/cjs/browser/form-utilities.js +35 -34
  6. package/dist/cjs/browser/form-utilities.js.map +1 -1
  7. package/dist/cjs/browser/geo-location.js +1 -1
  8. package/dist/cjs/browser/geo-location.js.map +1 -1
  9. package/dist/cjs/browser/index.js +0 -0
  10. package/dist/cjs/browser/index.js.map +0 -0
  11. package/dist/cjs/browser/native-bridge.js +3 -1
  12. package/dist/cjs/browser/native-bridge.js.map +1 -1
  13. package/dist/cjs/cancellable-promise.js +34 -13
  14. package/dist/cjs/cancellable-promise.js.map +1 -1
  15. package/dist/cjs/clean-url-search-params.js +26 -3
  16. package/dist/cjs/clean-url-search-params.js.map +1 -1
  17. package/dist/cjs/collections/cache-dictionary.js +3 -3
  18. package/dist/cjs/collections/cache-dictionary.js.map +1 -1
  19. package/dist/cjs/collections/default-map.js +0 -0
  20. package/dist/cjs/collections/default-map.js.map +1 -1
  21. package/dist/cjs/collections/default-weak-map.js +0 -0
  22. package/dist/cjs/collections/default-weak-map.js.map +1 -1
  23. package/dist/cjs/collections/from.js +3 -3
  24. package/dist/cjs/collections/from.js.map +1 -1
  25. package/dist/cjs/collections/index.js +0 -0
  26. package/dist/cjs/collections/index.js.map +1 -1
  27. package/dist/cjs/draft.js +46 -11
  28. package/dist/cjs/draft.js.map +1 -1
  29. package/dist/cjs/event-bus.js +1 -1
  30. package/dist/cjs/event-bus.js.map +1 -1
  31. package/dist/cjs/functions.js +348 -0
  32. package/dist/cjs/functions.js.map +1 -0
  33. package/dist/cjs/index.js +1 -0
  34. package/dist/cjs/index.js.map +1 -1
  35. package/dist/cjs/key-value-pair.js +0 -0
  36. package/dist/cjs/key-value-pair.js.map +1 -1
  37. package/dist/cjs/lazy.js +0 -0
  38. package/dist/cjs/lazy.js.map +1 -1
  39. package/dist/cjs/math.js +3 -0
  40. package/dist/cjs/math.js.map +1 -1
  41. package/dist/cjs/order.js +0 -0
  42. package/dist/cjs/order.js.map +1 -1
  43. package/dist/cjs/parse.js +10 -1
  44. package/dist/cjs/parse.js.map +1 -1
  45. package/dist/cjs/patch.js +0 -0
  46. package/dist/cjs/patch.js.map +1 -1
  47. package/dist/cjs/range.js +0 -0
  48. package/dist/cjs/range.js.map +0 -0
  49. package/dist/cjs/stopwatch.js +0 -0
  50. package/dist/cjs/stopwatch.js.map +1 -1
  51. package/dist/cjs/string.js +8 -5
  52. package/dist/cjs/string.js.map +1 -1
  53. package/dist/cjs/timer.js +1 -1
  54. package/dist/cjs/timer.js.map +1 -1
  55. package/dist/cjs/timespan.js +21 -8
  56. package/dist/cjs/timespan.js.map +1 -1
  57. package/dist/cjs/type-code.js +0 -0
  58. package/dist/cjs/type-code.js.map +1 -1
  59. package/dist/cjs/type.js +20 -19
  60. package/dist/cjs/type.js.map +1 -1
  61. package/dist/cjs/types.js +0 -0
  62. package/dist/cjs/types.js.map +1 -1
  63. package/dist/cjs/utilities.js +175 -39
  64. package/dist/cjs/utilities.js.map +1 -1
  65. package/dist/esm/array.js +21 -2
  66. package/dist/esm/array.js.map +1 -1
  67. package/dist/esm/async-pool-executor.js +26 -11
  68. package/dist/esm/async-pool-executor.js.map +1 -1
  69. package/dist/esm/browser/form-utilities.js +35 -34
  70. package/dist/esm/browser/form-utilities.js.map +1 -1
  71. package/dist/esm/browser/geo-location.js +1 -1
  72. package/dist/esm/browser/geo-location.js.map +1 -1
  73. package/dist/esm/browser/index.js +0 -0
  74. package/dist/esm/browser/index.js.map +0 -0
  75. package/dist/esm/browser/native-bridge.js +3 -1
  76. package/dist/esm/browser/native-bridge.js.map +1 -1
  77. package/dist/esm/cancellable-promise.js +34 -13
  78. package/dist/esm/cancellable-promise.js.map +1 -1
  79. package/dist/esm/clean-url-search-params.js +26 -3
  80. package/dist/esm/clean-url-search-params.js.map +1 -1
  81. package/dist/esm/collections/cache-dictionary.js +3 -3
  82. package/dist/esm/collections/cache-dictionary.js.map +1 -1
  83. package/dist/esm/collections/default-map.js +0 -0
  84. package/dist/esm/collections/default-map.js.map +1 -1
  85. package/dist/esm/collections/default-weak-map.js +0 -0
  86. package/dist/esm/collections/default-weak-map.js.map +1 -1
  87. package/dist/esm/collections/from.js +3 -3
  88. package/dist/esm/collections/from.js.map +1 -1
  89. package/dist/esm/collections/index.js +0 -0
  90. package/dist/esm/collections/index.js.map +1 -1
  91. package/dist/esm/draft.js +46 -11
  92. package/dist/esm/draft.js.map +1 -1
  93. package/dist/esm/event-bus.js +1 -1
  94. package/dist/esm/event-bus.js.map +1 -1
  95. package/dist/esm/functions.js +336 -0
  96. package/dist/esm/functions.js.map +1 -0
  97. package/dist/esm/index.js +1 -0
  98. package/dist/esm/index.js.map +1 -1
  99. package/dist/esm/key-value-pair.js +0 -0
  100. package/dist/esm/key-value-pair.js.map +1 -1
  101. package/dist/esm/lazy.js +0 -0
  102. package/dist/esm/lazy.js.map +1 -1
  103. package/dist/esm/math.js +3 -0
  104. package/dist/esm/math.js.map +1 -1
  105. package/dist/esm/order.js +0 -0
  106. package/dist/esm/order.js.map +1 -1
  107. package/dist/esm/parse.js +10 -1
  108. package/dist/esm/parse.js.map +1 -1
  109. package/dist/esm/patch.js +0 -0
  110. package/dist/esm/patch.js.map +1 -1
  111. package/dist/esm/range.js +0 -0
  112. package/dist/esm/range.js.map +0 -0
  113. package/dist/esm/stopwatch.js +0 -0
  114. package/dist/esm/stopwatch.js.map +1 -1
  115. package/dist/esm/string.js +8 -5
  116. package/dist/esm/string.js.map +1 -1
  117. package/dist/esm/timer.js +1 -1
  118. package/dist/esm/timer.js.map +1 -1
  119. package/dist/esm/timespan.js +21 -8
  120. package/dist/esm/timespan.js.map +1 -1
  121. package/dist/esm/type-code.js +0 -0
  122. package/dist/esm/type-code.js.map +1 -1
  123. package/dist/esm/type.js +20 -19
  124. package/dist/esm/type.js.map +1 -1
  125. package/dist/esm/types.js +0 -0
  126. package/dist/esm/types.js.map +1 -1
  127. package/dist/esm/utilities.js +174 -39
  128. package/dist/esm/utilities.js.map +1 -1
  129. package/dist/types/array.d.ts +20 -0
  130. package/dist/types/array.d.ts.map +1 -1
  131. package/dist/types/async-pool-executor.d.ts +2 -2
  132. package/dist/types/async-pool-executor.d.ts.map +1 -1
  133. package/dist/types/browser/form-utilities.d.ts +0 -0
  134. package/dist/types/browser/form-utilities.d.ts.map +1 -1
  135. package/dist/types/browser/geo-location.d.ts +0 -0
  136. package/dist/types/browser/geo-location.d.ts.map +0 -0
  137. package/dist/types/browser/index.d.ts +0 -0
  138. package/dist/types/browser/index.d.ts.map +0 -0
  139. package/dist/types/browser/native-bridge.d.ts +0 -0
  140. package/dist/types/browser/native-bridge.d.ts.map +1 -1
  141. package/dist/types/cancellable-promise.d.ts +0 -0
  142. package/dist/types/cancellable-promise.d.ts.map +1 -1
  143. package/dist/types/clean-url-search-params.d.ts +3 -1
  144. package/dist/types/clean-url-search-params.d.ts.map +1 -1
  145. package/dist/types/collections/cache-dictionary.d.ts +0 -0
  146. package/dist/types/collections/cache-dictionary.d.ts.map +0 -0
  147. package/dist/types/collections/default-map.d.ts +0 -0
  148. package/dist/types/collections/default-map.d.ts.map +0 -0
  149. package/dist/types/collections/default-weak-map.d.ts +0 -0
  150. package/dist/types/collections/default-weak-map.d.ts.map +0 -0
  151. package/dist/types/collections/from.d.ts +1 -1
  152. package/dist/types/collections/from.d.ts.map +0 -0
  153. package/dist/types/collections/index.d.ts +0 -0
  154. package/dist/types/collections/index.d.ts.map +0 -0
  155. package/dist/types/draft.d.ts +0 -0
  156. package/dist/types/draft.d.ts.map +1 -1
  157. package/dist/types/event-bus.d.ts +0 -0
  158. package/dist/types/event-bus.d.ts.map +0 -0
  159. package/dist/types/functions.d.ts +231 -0
  160. package/dist/types/functions.d.ts.map +1 -0
  161. package/dist/types/index.d.ts +1 -0
  162. package/dist/types/index.d.ts.map +1 -1
  163. package/dist/types/key-value-pair.d.ts +0 -0
  164. package/dist/types/key-value-pair.d.ts.map +0 -0
  165. package/dist/types/lazy.d.ts +0 -0
  166. package/dist/types/lazy.d.ts.map +0 -0
  167. package/dist/types/math.d.ts +0 -0
  168. package/dist/types/math.d.ts.map +1 -1
  169. package/dist/types/order.d.ts +0 -0
  170. package/dist/types/order.d.ts.map +0 -0
  171. package/dist/types/parse.d.ts +0 -0
  172. package/dist/types/parse.d.ts.map +1 -1
  173. package/dist/types/patch.d.ts +0 -0
  174. package/dist/types/patch.d.ts.map +0 -0
  175. package/dist/types/range.d.ts +0 -0
  176. package/dist/types/range.d.ts.map +0 -0
  177. package/dist/types/stopwatch.d.ts +0 -0
  178. package/dist/types/stopwatch.d.ts.map +0 -0
  179. package/dist/types/string.d.ts +0 -0
  180. package/dist/types/string.d.ts.map +1 -1
  181. package/dist/types/timer.d.ts +1 -1
  182. package/dist/types/timer.d.ts.map +0 -0
  183. package/dist/types/timespan.d.ts +0 -0
  184. package/dist/types/timespan.d.ts.map +1 -1
  185. package/dist/types/type-code.d.ts +0 -0
  186. package/dist/types/type-code.d.ts.map +0 -0
  187. package/dist/types/type.d.ts +2 -0
  188. package/dist/types/type.d.ts.map +1 -1
  189. package/dist/types/types.d.ts +1 -1
  190. package/dist/types/types.d.ts.map +1 -1
  191. package/dist/types/utilities.d.ts +21 -3
  192. package/dist/types/utilities.d.ts.map +1 -1
  193. package/dist/web/array.js +21 -2
  194. package/dist/web/array.js.map +1 -1
  195. package/dist/web/async-pool-executor.js +26 -11
  196. package/dist/web/async-pool-executor.js.map +1 -1
  197. package/dist/web/browser/form-utilities.js +35 -34
  198. package/dist/web/browser/form-utilities.js.map +1 -1
  199. package/dist/web/browser/geo-location.js +1 -1
  200. package/dist/web/browser/geo-location.js.map +1 -1
  201. package/dist/web/browser/index.js +0 -0
  202. package/dist/web/browser/index.js.map +0 -0
  203. package/dist/web/browser/native-bridge.js +3 -1
  204. package/dist/web/browser/native-bridge.js.map +1 -1
  205. package/dist/web/cancellable-promise.js +34 -13
  206. package/dist/web/cancellable-promise.js.map +1 -1
  207. package/dist/web/clean-url-search-params.js +26 -3
  208. package/dist/web/clean-url-search-params.js.map +1 -1
  209. package/dist/web/collections/cache-dictionary.js +3 -3
  210. package/dist/web/collections/cache-dictionary.js.map +1 -1
  211. package/dist/web/collections/default-map.js +0 -0
  212. package/dist/web/collections/default-map.js.map +1 -1
  213. package/dist/web/collections/default-weak-map.js +0 -0
  214. package/dist/web/collections/default-weak-map.js.map +1 -1
  215. package/dist/web/collections/from.js +3 -3
  216. package/dist/web/collections/from.js.map +1 -1
  217. package/dist/web/collections/index.js +0 -0
  218. package/dist/web/collections/index.js.map +1 -1
  219. package/dist/web/draft.js +46 -11
  220. package/dist/web/draft.js.map +1 -1
  221. package/dist/web/event-bus.js +1 -1
  222. package/dist/web/event-bus.js.map +1 -1
  223. package/dist/web/functions.js +336 -0
  224. package/dist/web/functions.js.map +1 -0
  225. package/dist/web/index.js +1 -0
  226. package/dist/web/index.js.map +1 -1
  227. package/dist/web/key-value-pair.js +0 -0
  228. package/dist/web/key-value-pair.js.map +1 -1
  229. package/dist/web/lazy.js +0 -0
  230. package/dist/web/lazy.js.map +1 -1
  231. package/dist/web/math.js +3 -0
  232. package/dist/web/math.js.map +1 -1
  233. package/dist/web/order.js +0 -0
  234. package/dist/web/order.js.map +1 -1
  235. package/dist/web/parse.js +10 -1
  236. package/dist/web/parse.js.map +1 -1
  237. package/dist/web/patch.js +0 -0
  238. package/dist/web/patch.js.map +1 -1
  239. package/dist/web/range.js +0 -0
  240. package/dist/web/range.js.map +0 -0
  241. package/dist/web/stopwatch.js +0 -0
  242. package/dist/web/stopwatch.js.map +1 -1
  243. package/dist/web/string.js +8 -5
  244. package/dist/web/string.js.map +1 -1
  245. package/dist/web/timer.js +1 -1
  246. package/dist/web/timer.js.map +1 -1
  247. package/dist/web/timespan.js +21 -8
  248. package/dist/web/timespan.js.map +1 -1
  249. package/dist/web/type-code.js +0 -0
  250. package/dist/web/type-code.js.map +1 -1
  251. package/dist/web/type.js +20 -19
  252. package/dist/web/type.js.map +1 -1
  253. package/dist/web/types.js +0 -0
  254. package/dist/web/types.js.map +1 -1
  255. package/dist/web/utilities.js +174 -39
  256. package/dist/web/utilities.js.map +1 -1
  257. package/package.json +84 -60
  258. package/src/array.ts +116 -84
  259. package/src/async-pool-executor.ts +107 -85
  260. package/src/browser/form-utilities.ts +32 -31
  261. package/src/browser/geo-location.ts +113 -113
  262. package/src/browser/native-bridge.ts +118 -116
  263. package/src/cancellable-promise.ts +102 -76
  264. package/src/clean-url-search-params.ts +36 -11
  265. package/src/collections/cache-dictionary.ts +115 -115
  266. package/src/collections/default-map.ts +48 -48
  267. package/src/collections/default-weak-map.ts +51 -51
  268. package/src/collections/from.ts +859 -859
  269. package/src/collections/index.ts +3 -3
  270. package/src/draft.ts +55 -16
  271. package/src/event-bus.ts +83 -83
  272. package/src/functions.ts +496 -0
  273. package/src/index.ts +1 -0
  274. package/src/key-value-pair.ts +24 -24
  275. package/src/lazy.ts +32 -32
  276. package/src/math.ts +33 -30
  277. package/src/order.ts +5 -5
  278. package/src/parse.ts +251 -240
  279. package/src/patch.ts +79 -79
  280. package/src/stopwatch.ts +43 -43
  281. package/src/string.ts +8 -5
  282. package/src/timer.ts +67 -67
  283. package/src/timespan.ts +412 -398
  284. package/src/type-code.ts +15 -15
  285. package/src/type.ts +372 -371
  286. package/src/types.ts +34 -30
  287. package/src/utilities.ts +653 -480
@@ -1,114 +1,114 @@
1
- // ─── Tipos ───────────────────────────────────────────────
2
-
3
- export interface GeoLocation {
4
- latitude: number;
5
- longitude: number;
6
- accuracy: number;
7
- altitude: number | null;
8
- altitudeAccuracy: number | null;
9
- heading: number | null;
10
- speed: number | null;
11
- timestamp: number;
12
- }
13
-
14
- export interface GeoLocationOptions {
15
- enableHighAccuracy?: boolean;
16
- timeout?: number;
17
- maximumAge?: number;
18
- }
19
-
20
- // ─── Helpers ─────────────────────────────────────────────
21
-
22
- function positionToGeoLocation(position: GeolocationPosition): GeoLocation {
23
- const {coords, timestamp} = position;
24
- return {
25
- latitude: coords.latitude,
26
- longitude: coords.longitude,
27
- accuracy: coords.accuracy,
28
- altitude: coords.altitude,
29
- altitudeAccuracy: coords.altitudeAccuracy,
30
- heading: coords.heading,
31
- speed: coords.speed,
32
- timestamp,
33
- };
34
- }
35
-
36
- function geolocationError(error: GeolocationPositionError): Error {
37
- switch (error.code) {
38
- case error.PERMISSION_DENIED:
39
- return new Error('Has denegado el permiso de ubicación.');
40
- case error.POSITION_UNAVAILABLE:
41
- return new Error('No se pudo determinar tu ubicación.');
42
- case error.TIMEOUT:
43
- return new Error('Tiempo de espera agotado al obtener la ubicación.');
44
- default:
45
- return new Error('Error desconocido al obtener la ubicación.');
46
- }
47
- }
48
-
49
- function requestPosition(options: PositionOptions): Promise<GeoLocation> {
50
- return new Promise((resolve, reject) => {
51
- navigator.geolocation.getCurrentPosition(
52
- (position) => resolve(positionToGeoLocation(position)),
53
- (error) => reject(geolocationError(error)),
54
- options,
55
- );
56
- });
57
- }
58
-
59
- async function ensurePermission(): Promise<void> {
60
- if (!navigator.permissions) return;
61
-
62
- const permission = await navigator.permissions.query({name: 'geolocation'});
63
-
64
- if (permission.state === 'denied') {
65
- throw new Error(
66
- 'Permiso de ubicación denegado. Actívalo en la configuración del navegador.',
67
- );
68
- }
69
-
70
- if (permission.state === 'prompt') {
71
- await new Promise<void>((resolve, reject) => {
72
- // Escuchar cambio de estado del permiso
73
- permission.onchange = () => {
74
- permission.onchange = null;
75
- if (permission.state === 'granted') {
76
- resolve();
77
- } else {
78
- reject(new Error('Has denegado el permiso de ubicación.'));
79
- }
80
- };
81
-
82
- // Forzar el diálogo nativo del navegador
83
- navigator.geolocation.getCurrentPosition(
84
- () => {
85
- permission.onchange = null;
86
- resolve();
87
- },
88
- (error) => {
89
- permission.onchange = null;
90
- reject(geolocationError(error));
91
- },
92
- {timeout: 30000},
93
- );
94
- });
95
- }
96
- }
97
-
98
- // ─── Función principal ──────────────────────────────────
99
-
100
- export default async function getGeoLocation(
101
- options: GeoLocationOptions = {},
102
- ): Promise<GeoLocation> {
103
- if (!navigator.geolocation) {
104
- throw new Error('Tu navegador no soporta geolocalización.');
105
- }
106
-
107
- await ensurePermission();
108
-
109
- return requestPosition({
110
- enableHighAccuracy: options.enableHighAccuracy ?? true,
111
- timeout: options.timeout ?? 10000,
112
- maximumAge: options.maximumAge ?? 0,
113
- });
1
+ // ─── Tipos ───────────────────────────────────────────────
2
+
3
+ export interface GeoLocation {
4
+ latitude: number;
5
+ longitude: number;
6
+ accuracy: number;
7
+ altitude: number | null;
8
+ altitudeAccuracy: number | null;
9
+ heading: number | null;
10
+ speed: number | null;
11
+ timestamp: number;
12
+ }
13
+
14
+ export interface GeoLocationOptions {
15
+ enableHighAccuracy?: boolean;
16
+ timeout?: number;
17
+ maximumAge?: number;
18
+ }
19
+
20
+ // ─── Helpers ─────────────────────────────────────────────
21
+
22
+ function positionToGeoLocation(position: GeolocationPosition): GeoLocation {
23
+ const {coords, timestamp} = position;
24
+ return {
25
+ latitude: coords.latitude,
26
+ longitude: coords.longitude,
27
+ accuracy: coords.accuracy,
28
+ altitude: coords.altitude,
29
+ altitudeAccuracy: coords.altitudeAccuracy,
30
+ heading: coords.heading,
31
+ speed: coords.speed,
32
+ timestamp,
33
+ };
34
+ }
35
+
36
+ function geolocationError(error: GeolocationPositionError): Error {
37
+ switch (error.code) {
38
+ case error.PERMISSION_DENIED:
39
+ return new Error('Has denegado el permiso de ubicación.');
40
+ case error.POSITION_UNAVAILABLE:
41
+ return new Error('No se pudo determinar tu ubicación.');
42
+ case error.TIMEOUT:
43
+ return new Error('Tiempo de espera agotado al obtener la ubicación.');
44
+ default:
45
+ return new Error('Error desconocido al obtener la ubicación.');
46
+ }
47
+ }
48
+
49
+ function requestPosition(options: PositionOptions): Promise<GeoLocation> {
50
+ return new Promise((resolve, reject) => {
51
+ navigator.geolocation.getCurrentPosition(
52
+ (position) => resolve(positionToGeoLocation(position)),
53
+ (error) => reject(geolocationError(error)),
54
+ options,
55
+ );
56
+ });
57
+ }
58
+
59
+ async function ensurePermission(): Promise<void> {
60
+ if (!navigator.permissions) return;
61
+
62
+ const permission = await navigator.permissions.query({name: 'geolocation'});
63
+
64
+ if (permission.state === 'denied') {
65
+ throw new Error(
66
+ 'Permiso de ubicación denegado. Actívalo en la configuración del navegador.',
67
+ );
68
+ }
69
+
70
+ if (permission.state === 'prompt') {
71
+ await new Promise<void>((resolve, reject) => {
72
+ // Escuchar cambio de estado del permiso
73
+ permission.onchange = () => {
74
+ permission.onchange = null;
75
+ if (permission.state === 'granted') {
76
+ resolve();
77
+ } else {
78
+ reject(new Error('Has denegado el permiso de ubicación.'));
79
+ }
80
+ };
81
+
82
+ // Forzar el diálogo nativo del navegador
83
+ navigator.geolocation.getCurrentPosition(
84
+ () => {
85
+ permission.onchange = null;
86
+ resolve();
87
+ },
88
+ (error) => {
89
+ permission.onchange = null;
90
+ reject(geolocationError(error));
91
+ },
92
+ {timeout: 30000},
93
+ );
94
+ });
95
+ }
96
+ }
97
+
98
+ // ─── Función principal ──────────────────────────────────
99
+
100
+ export default async function getGeoLocation(
101
+ options: GeoLocationOptions = {},
102
+ ): Promise<GeoLocation> {
103
+ if (typeof navigator === 'undefined' || !navigator.geolocation) {
104
+ throw new Error('Tu navegador no soporta geolocalización.');
105
+ }
106
+
107
+ await ensurePermission();
108
+
109
+ return requestPosition({
110
+ enableHighAccuracy: options.enableHighAccuracy ?? true,
111
+ timeout: options.timeout ?? 10000,
112
+ maximumAge: options.maximumAge ?? 0,
113
+ });
114
114
  }
@@ -1,117 +1,119 @@
1
- // ─── Tipos ───────────────────────────────────────────────
2
- interface BridgeOptions {
3
- channel: Channel;
4
- timeout?: number | null;
5
- callbackName?: string; // ← nuevo
6
- }
7
- interface PendingCall {
8
- resolve: (value: unknown) => void;
9
- reject: (reason: Error) => void;
10
- timer: ReturnType<typeof setTimeout> | null;
11
- }
12
-
13
- interface Channel {
14
- postMessage: (message: string) => void;
15
- }
16
-
17
-
18
-
19
- // ─── Clase ──────────────────────────────────────────────
20
-
21
- export default class NativeBridge {
22
- private _pending = new Map<number, PendingCall>();
23
- private _callId = 0;
24
- private readonly _defaultTimeout: number | null;
25
- private readonly _channel: Channel;
26
-
27
-
28
- constructor({ channel, timeout = 3000, callbackName = '__nativeResponseHandler' }: BridgeOptions) {
29
- this._defaultTimeout = timeout;
30
- this._channel = channel;
31
-
32
- if (!this._channel) {
33
- throw new Error('Channel not found');
34
- }
35
-
36
- (window as any)[callbackName] = this._callback;
37
-
38
- // Proxy: cualquier propiedad no existente se convierte en call()
39
- return new Proxy(this, {
40
- get(target: NativeBridge, prop: string | symbol) {
41
- if (prop in target) {
42
- return (target as any)[prop];
43
- }
44
- return (data?: unknown, timeout?: number | null) => target.call(String(prop), data, timeout);
45
- },
46
- }) as unknown as NativeBridge;
47
- }
48
-
49
-
50
- private _callback(id: number, error: any, result: any) {
51
-
52
- const pending = this._pending.get(id);
53
- if (!pending) {
54
- return;
55
- }
56
-
57
- if (pending.timer !== null) {
58
- clearTimeout(pending.timer);
59
- }
60
-
61
- this._pending.delete(id);
62
-
63
- if (error) {
64
- pending.reject(error instanceof Error? error : new Error(String(error)));
65
- } else {
66
- pending.resolve(result);
67
- }
68
- }
69
-
70
- call(method: string, data: unknown = null, timeout?: number | null): Promise<unknown> {
71
-
72
-
73
- const effectiveTimeout = timeout !== undefined ? timeout : this._defaultTimeout;
74
-
75
- return new Promise<unknown>((resolve, reject) => {
76
- const id = this._callId++;
77
-
78
- let timer: ReturnType<typeof setTimeout> | null = null;
79
-
80
- // Solo crear timer si hay timeout
81
- if (effectiveTimeout !== null && effectiveTimeout > 0) {
82
- timer = setTimeout(() => {
83
- this._pending.delete(id);
84
- reject(new Error(`Timeout (${effectiveTimeout}ms): ${method}`));
85
- }, effectiveTimeout);
86
- }
87
-
88
- this._pending.set(id, { resolve, reject, timer });
89
- this._channel!.postMessage(JSON.stringify({ id, method, data }));
90
- });
91
- }
92
-
93
-
94
- send(method: string, data: unknown = null): void {
95
- this._channel!.postMessage(JSON.stringify({ method, data }));
96
- }
97
-
98
- /**
99
- * Número de llamadas pendientes
100
- */
101
- get pendingCount(): number {
102
- return this._pending.size;
103
- }
104
-
105
- /**
106
- * Cancela todas las llamadas pendientes
107
- */
108
- cancelAll(): void {
109
- for (const [, { reject, timer }] of this._pending) {
110
- if (timer !== null) {
111
- clearTimeout(timer);
112
- }
113
- reject(new Error('Cancelled'));
114
- }
115
- this._pending.clear();
116
- }
1
+ // ─── Tipos ───────────────────────────────────────────────
2
+ interface BridgeOptions {
3
+ channel: Channel;
4
+ timeout?: number | null;
5
+ callbackName?: string; // ← nuevo
6
+ }
7
+ interface PendingCall {
8
+ resolve: (value: unknown) => void;
9
+ reject: (reason: Error) => void;
10
+ timer: ReturnType<typeof setTimeout> | null;
11
+ }
12
+
13
+ interface Channel {
14
+ postMessage: (message: string) => void;
15
+ }
16
+
17
+
18
+
19
+ // ─── Clase ──────────────────────────────────────────────
20
+
21
+ export default class NativeBridge {
22
+ private _pending = new Map<number, PendingCall>();
23
+ private _callId = 0;
24
+ private readonly _defaultTimeout: number | null;
25
+ private readonly _channel: Channel;
26
+
27
+
28
+ constructor({ channel, timeout = 3000, callbackName = '__nativeResponseHandler' }: BridgeOptions) {
29
+ this._defaultTimeout = timeout;
30
+ this._channel = channel;
31
+
32
+ if (!this._channel) {
33
+ throw new Error('Channel not found');
34
+ }
35
+
36
+ (window as any)[callbackName] = (id: number, error: any, result: any) => {
37
+ this._callback(id, error, result);
38
+ };
39
+
40
+ // Proxy: cualquier propiedad no existente se convierte en call()
41
+ return new Proxy(this, {
42
+ get(target: NativeBridge, prop: string | symbol) {
43
+ if (prop in target) {
44
+ return (target as any)[prop];
45
+ }
46
+ return (data?: unknown, timeout?: number | null) => target.call(String(prop), data, timeout);
47
+ },
48
+ }) as unknown as NativeBridge;
49
+ }
50
+
51
+
52
+ private _callback(id: number, error: any, result: any) {
53
+
54
+ const pending = this._pending.get(id);
55
+ if (!pending) {
56
+ return;
57
+ }
58
+
59
+ if (pending.timer !== null) {
60
+ clearTimeout(pending.timer);
61
+ }
62
+
63
+ this._pending.delete(id);
64
+
65
+ if (error) {
66
+ pending.reject(error instanceof Error? error : new Error(String(error)));
67
+ } else {
68
+ pending.resolve(result);
69
+ }
70
+ }
71
+
72
+ call(method: string, data: unknown = null, timeout?: number | null): Promise<unknown> {
73
+
74
+
75
+ const effectiveTimeout = timeout !== undefined ? timeout : this._defaultTimeout;
76
+
77
+ return new Promise<unknown>((resolve, reject) => {
78
+ const id = this._callId++;
79
+
80
+ let timer: ReturnType<typeof setTimeout> | null = null;
81
+
82
+ // Solo crear timer si hay timeout
83
+ if (effectiveTimeout !== null && effectiveTimeout > 0) {
84
+ timer = setTimeout(() => {
85
+ this._pending.delete(id);
86
+ reject(new Error(`Timeout (${effectiveTimeout}ms): ${method}`));
87
+ }, effectiveTimeout);
88
+ }
89
+
90
+ this._pending.set(id, { resolve, reject, timer });
91
+ this._channel!.postMessage(JSON.stringify({ id, method, data }));
92
+ });
93
+ }
94
+
95
+
96
+ send(method: string, data: unknown = null): void {
97
+ this._channel!.postMessage(JSON.stringify({ method, data }));
98
+ }
99
+
100
+ /**
101
+ * Número de llamadas pendientes
102
+ */
103
+ get pendingCount(): number {
104
+ return this._pending.size;
105
+ }
106
+
107
+ /**
108
+ * Cancela todas las llamadas pendientes
109
+ */
110
+ cancelAll(): void {
111
+ for (const [, { reject, timer }] of this._pending) {
112
+ if (timer !== null) {
113
+ clearTimeout(timer);
114
+ }
115
+ reject(new Error('Cancelled'));
116
+ }
117
+ this._pending.clear();
118
+ }
117
119
  }
@@ -1,77 +1,103 @@
1
- type CancellablePromiseExecutor<T> = (
2
- resolve: (value: T | PromiseLike<T>) => void,
3
- reject: (reason?: unknown) => void,
4
- signal: AbortSignal
5
- ) => void;
6
-
7
- export default class CancellablePromise<T> extends Promise<T> {
8
-
9
- private _controller: AbortController;
10
-
11
- static get [Symbol.species]() {
12
- return Promise;
13
- }
14
-
15
- constructor(executor: CancellablePromiseExecutor<T>) {
16
- const controller = new AbortController();
17
-
18
- super((resolve, reject) => {
19
- controller.signal.addEventListener("abort", () => {
20
- reject(controller.signal.reason);
21
- });
22
-
23
- executor(resolve, reject, controller.signal);
24
- });
25
-
26
- this._controller = controller;
27
- }
28
-
29
- get cancelled(): boolean {
30
- return this._controller.signal.aborted;
31
- }
32
-
33
- cancel(reason: unknown = new Error("Promesa cancelada")): void {
34
- if (!this.cancelled) {
35
- this._controller.abort(reason);
36
- }
37
- }
38
-
39
- static async compete<T>(promises: CancellablePromise<T>[]): Promise<T> {
40
- return await Promise.race(promises).then(
41
- (resultado) => {
42
- for (const p of promises) {
43
- p.cancel();
44
- }
45
- return resultado;
46
- },
47
- (error) => {
48
- for (const p of promises) {
49
- p.cancel();
50
- }
51
- throw error;
52
- }
53
- );
54
- }
55
-
56
- static async cooperate<T>(promises: CancellablePromise<T>[]): Promise<T[]> {
57
- try {
58
- return await Promise.all(promises);
59
- } catch (error) {
60
- for (const p of promises) {
61
- p.cancel();
62
- }
63
- throw error;
64
- }
65
- }
66
-
67
- static withTimeout<T>(executor: CancellablePromiseExecutor<T>, ms: number): CancellablePromise<T> {
68
- return new CancellablePromise<T>((resolve, reject, signal) => {
69
- const timer = setTimeout(() => {
70
- reject(new Error(`Timeout: ${ms}ms`));
71
- }, ms);
72
-
73
- signal.addEventListener("abort", () => clearTimeout(timer));
74
- executor(resolve, reject, signal);
75
- });
76
- }
1
+ type CancellablePromiseExecutor<T> = (
2
+ resolve: (value: T | PromiseLike<T>) => void,
3
+ reject: (reason?: unknown) => void,
4
+ signal: AbortSignal
5
+ ) => void;
6
+
7
+ export default class CancellablePromise<T> extends Promise<T> {
8
+
9
+ private _controller: AbortController;
10
+
11
+ static get [Symbol.species]() {
12
+ return Promise;
13
+ }
14
+
15
+ constructor(executor: CancellablePromiseExecutor<T>) {
16
+ const controller = new AbortController();
17
+
18
+ super((resolve, reject) => {
19
+ controller.signal.addEventListener("abort", () => {
20
+ reject(controller.signal.reason);
21
+ });
22
+
23
+ executor(resolve, reject, controller.signal);
24
+ });
25
+
26
+ this._controller = controller;
27
+ }
28
+
29
+ get cancelled(): boolean {
30
+ return this._controller.signal.aborted;
31
+ }
32
+
33
+ cancel(reason: unknown = new Error("Promesa cancelada")): void {
34
+ if (!this.cancelled) {
35
+ this._controller.abort(reason);
36
+ }
37
+ }
38
+
39
+ static async compete<T>(promises: CancellablePromise<T>[]): Promise<T> {
40
+ if (promises.length === 0) {
41
+ throw new Error("No promises to compete.");
42
+ }
43
+
44
+ const result = await Promise.race(
45
+ promises.map((promise, index) => promise.then(
46
+ value => ({index, value, rejected: false as const}),
47
+ reason => ({index, reason, rejected: true as const}),
48
+ ))
49
+ );
50
+
51
+ for (let i = 0; i < promises.length; i++) {
52
+ if (i !== result.index) {
53
+ promises[i].cancel();
54
+ }
55
+ }
56
+
57
+ if (result.rejected) {
58
+ throw result.reason;
59
+ }
60
+
61
+ return result.value;
62
+ }
63
+
64
+ static async cooperate<T>(promises: CancellablePromise<T>[]): Promise<T[]> {
65
+ try {
66
+ return await Promise.all(promises);
67
+ } catch (error) {
68
+ for (const p of promises) {
69
+ p.cancel();
70
+ }
71
+ throw error;
72
+ }
73
+ }
74
+
75
+ static withTimeout<T>(executor: CancellablePromiseExecutor<T>, ms: number): CancellablePromise<T> {
76
+ return new CancellablePromise<T>((resolve, reject, signal) => {
77
+ let settled = false;
78
+ const timer = setTimeout(() => {
79
+ safeReject(new Error(`Timeout: ${ms}ms`));
80
+ }, ms);
81
+
82
+ const cleanup = () => clearTimeout(timer);
83
+ const safeResolve = (value: T | PromiseLike<T>) => {
84
+ if (settled) return;
85
+ settled = true;
86
+ cleanup();
87
+ resolve(value);
88
+ };
89
+ const safeReject = (reason?: unknown) => {
90
+ if (settled) return;
91
+ settled = true;
92
+ cleanup();
93
+ reject(reason);
94
+ };
95
+
96
+ signal.addEventListener("abort", () => {
97
+ settled = true;
98
+ cleanup();
99
+ }, {once: true});
100
+ executor(safeResolve, safeReject, signal);
101
+ });
102
+ }
77
103
  }