@xhub-short/adapters 1.0.0-beta.26 → 1.0.0-beta.27

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.
package/dist/index.d.ts CHANGED
@@ -1672,6 +1672,14 @@ declare class BrowserVideoLoader implements IVideoLoader {
1672
1672
  * Full segment preload requires hls.js which is optional
1673
1673
  */
1674
1674
  private preloadHLS;
1675
+ /**
1676
+ * Parse M3U8 manifest and pre-fetch the first N segments into the Cache API.
1677
+ * Runs concurrently for speed; tolerates individual segment fetch failures.
1678
+ *
1679
+ * Resolves relative segment paths against the manifest URL base.
1680
+ * Only runs when a cache is available - gracefully no-ops otherwise.
1681
+ */
1682
+ private preloadHLSSegments;
1675
1683
  /**
1676
1684
  * Cancel preload
1677
1685
  */
package/dist/index.js CHANGED
@@ -4196,11 +4196,42 @@ var BrowserVideoLoader = class {
4196
4196
  * Full segment preload requires hls.js which is optional
4197
4197
  */
4198
4198
  async preloadHLS(url, signal) {
4199
+ const _isDev = globalThis.process?.env?.NODE_ENV !== "production";
4200
+ const _t0 = _isDev ? performance.now() : 0;
4201
+ if (_isDev) {
4202
+ performance.mark("sv-preload:hls:start");
4203
+ console.debug(
4204
+ "%c\u{1F504} [HLS Preload] manifest fetch start",
4205
+ "color:#7c3aed;font-size:11px;",
4206
+ url.slice(url.lastIndexOf("/") + 1).slice(0, 60)
4207
+ );
4208
+ }
4199
4209
  const response = await fetch(url, { signal });
4200
4210
  if (!response.ok) {
4201
4211
  throw new Error(`HTTP error: ${response.status}`);
4202
4212
  }
4203
4213
  const text = await response.text();
4214
+ if (_isDev) {
4215
+ performance.mark("sv-preload:hls:done");
4216
+ try {
4217
+ performance.measure(
4218
+ "sv-preload:hls:manifest",
4219
+ "sv-preload:hls:start",
4220
+ "sv-preload:hls:done"
4221
+ );
4222
+ } catch {
4223
+ }
4224
+ const segCount = text.split("\n").filter(
4225
+ (l) => l.endsWith(".ts") || l.endsWith(".m4s") || l.includes(".ts?") || l.includes(".m4s?")
4226
+ ).length;
4227
+ console.debug(
4228
+ "%c\u2705 [HLS Preload] manifest done",
4229
+ "color:#059669;font-size:11px;",
4230
+ `+${(performance.now() - _t0).toFixed(0)}ms`,
4231
+ `${text.length} bytes`,
4232
+ `segments: ${segCount}`
4233
+ );
4234
+ }
4204
4235
  if (this.cache) {
4205
4236
  try {
4206
4237
  const cacheResponse = new Response(text, {
@@ -4212,8 +4243,50 @@ var BrowserVideoLoader = class {
4212
4243
  } catch {
4213
4244
  }
4214
4245
  }
4246
+ await this.preloadHLSSegments(url, text, signal);
4215
4247
  return text.length;
4216
4248
  }
4249
+ /**
4250
+ * Parse M3U8 manifest and pre-fetch the first N segments into the Cache API.
4251
+ * Runs concurrently for speed; tolerates individual segment fetch failures.
4252
+ *
4253
+ * Resolves relative segment paths against the manifest URL base.
4254
+ * Only runs when a cache is available - gracefully no-ops otherwise.
4255
+ */
4256
+ async preloadHLSSegments(manifestUrl, manifestText, signal, maxSegments = 3) {
4257
+ if (!this.cache) return;
4258
+ const baseUrl = manifestUrl.substring(0, manifestUrl.lastIndexOf("/") + 1);
4259
+ const segmentUrls = manifestText.split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#")).slice(0, maxSegments).map((l) => l.startsWith("http") ? l : `${baseUrl}${l}`);
4260
+ if (segmentUrls.length === 0) return;
4261
+ const _isDev = globalThis.process?.env?.NODE_ENV !== "production";
4262
+ if (_isDev) {
4263
+ console.debug(
4264
+ "%c\u{1F4E6} [HLS Preload] fetching first segments",
4265
+ "color:#7c3aed;font-size:11px;",
4266
+ segmentUrls.map((u) => u.slice(u.lastIndexOf("/") + 1).slice(0, 40))
4267
+ );
4268
+ }
4269
+ const cache = this.cache;
4270
+ await Promise.allSettled(
4271
+ segmentUrls.map(async (segUrl) => {
4272
+ const existing = await cache.match(segUrl);
4273
+ if (existing) return;
4274
+ const segResponse = await fetch(segUrl, { signal });
4275
+ if (segResponse.ok) {
4276
+ await cache.put(segUrl, segResponse.clone());
4277
+ if (_isDev) {
4278
+ const size = Number(segResponse.headers.get("content-length") ?? 0);
4279
+ console.debug(
4280
+ "%c \u2713 segment cached",
4281
+ "color:#059669;font-size:11px;",
4282
+ segUrl.slice(segUrl.lastIndexOf("/") + 1).slice(0, 50),
4283
+ size ? `${(size / 1024).toFixed(0)}KB` : ""
4284
+ );
4285
+ }
4286
+ }
4287
+ })
4288
+ );
4289
+ }
4217
4290
  /**
4218
4291
  * Cancel preload
4219
4292
  */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xhub-short/adapters",
3
3
  "sideEffects": false,
4
- "version": "1.0.0-beta.26",
4
+ "version": "1.0.0-beta.27",
5
5
  "type": "module",
6
6
  "publishConfig": {
7
7
  "access": "public"
@@ -20,7 +20,7 @@
20
20
  "dist"
21
21
  ],
22
22
  "dependencies": {
23
- "@xhub-short/contracts": "1.0.0-beta.26"
23
+ "@xhub-short/contracts": "1.0.0-beta.27"
24
24
  },
25
25
  "optionalDependencies": {
26
26
  "hls.js": "^1.5.0"