@autobusal/providers 1.44.0 → 1.44.2

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.
@@ -42,13 +42,46 @@ const analytics = (container: string | null | undefined): void => {
42
42
  window.dataLayer = window.dataLayer || [];
43
43
  window.dataLayer.push({ 'gtm.start': Date.now(), event: 'gtm.js' });
44
44
 
45
- const script = document.createElement('script');
45
+ /*
46
+ * LOADED IN THE FIRST QUIET MOMENT, not while the page races for the
47
+ * network.
48
+ *
49
+ * Edited: Claude - Date: 2026-09-16
50
+ *
51
+ * Measured with Lighthouse against production on a throttled phone: the
52
+ * container and the GA tag it pulls are 287 KB of script - more than this
53
+ * app's own entry chunk - fetched in the same window as the bundle, the
54
+ * translations and the images, on a connection modelled at 1.6 Mbps. The
55
+ * page is no more usable for having them early, and every byte they take
56
+ * is one the content is waiting for.
57
+ *
58
+ * The dataLayer is filled FIRST, above, and GTM reads whatever is already
59
+ * in it when it boots - so a page view or a commerce event announced in
60
+ * the meantime still arrives. That is the only thing that could have made
61
+ * deferring this wrong.
62
+ *
63
+ * Safari has no requestIdleCallback, so setTimeout is the fallback rather
64
+ * than a polyfill: "soon, after the load" is the whole requirement.
65
+ */
66
+ const load = (): void => {
67
+ if (document.getElementById(CONTAINER_ID)) {
68
+ return;
69
+ }
46
70
 
47
- script.id = CONTAINER_ID;
48
- script.async = true;
49
- script.src = `https://www.googletagmanager.com/gtm.js?id=${ encodeURIComponent(container) }`;
71
+ const script = document.createElement('script');
50
72
 
51
- document.head.appendChild(script);
73
+ script.id = CONTAINER_ID;
74
+ script.async = true;
75
+ script.src = `https://www.googletagmanager.com/gtm.js?id=${ encodeURIComponent(container) }`;
76
+
77
+ document.head.appendChild(script);
78
+ };
79
+
80
+ if (typeof window.requestIdleCallback === 'function') {
81
+ window.requestIdleCallback(load, { timeout: 2000 });
82
+ } else {
83
+ window.setTimeout(load, 1200);
84
+ }
52
85
  };
53
86
 
54
87
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autobusal/providers",
3
- "version": "1.44.0",
3
+ "version": "1.44.2",
4
4
  "author": "Ferjolt Ozuni",
5
5
  "type": "module",
6
6
  "main": "index.ts",
package/types/routes.ts CHANGED
@@ -148,6 +148,24 @@ export interface FoundData extends Omit<RouteData, 'locations' | 'id'> {
148
148
  // must read "missing" as unknown, never as direct.
149
149
  stops_count?: number
150
150
 
151
+ /**
152
+ * How many seats are still on sale on this departure.
153
+ *
154
+ * Edited: Claude - Date: 2026-09-16
155
+ *
156
+ * NOT `trip.available_seats`, which is the coach's CAPACITY - the search
157
+ * subtracts what every brand has sold and what the operator holds back
158
+ * before deciding whether to offer the departure at all, and this is that
159
+ * answer (Routes\Search\Buses::removeOccupied). Reading the capacity
160
+ * instead announced 49 free seats on a coach with 49 sold, which is the
161
+ * one number on a result card nobody would think to doubt.
162
+ *
163
+ * Optional: an external-provider offer has no seat count of ours, and an
164
+ * older API does not send this at all - in both cases the card shows
165
+ * nothing rather than guessing.
166
+ */
167
+ seats_left?: number
168
+
151
169
  /**
152
170
  * Claude - 2026-08-29 (audit A3-02h)
153
171
  *