@xhub-short/adapters 1.0.0-beta.25 → 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 +12 -0
- package/dist/index.js +88 -0
- package/package.json +4 -4
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
|
*/
|
|
@@ -2109,6 +2117,10 @@ declare class HttpClient {
|
|
|
2109
2117
|
* Get base URL (for sendBeacon which needs full URL)
|
|
2110
2118
|
*/
|
|
2111
2119
|
getBaseUrl(): string;
|
|
2120
|
+
/**
|
|
2121
|
+
* Check if access token is available
|
|
2122
|
+
*/
|
|
2123
|
+
hasAccessToken(): Promise<boolean>;
|
|
2112
2124
|
private isRefreshing;
|
|
2113
2125
|
private refreshPromise;
|
|
2114
2126
|
constructor(config: HttpClientConfig);
|
package/dist/index.js
CHANGED
|
@@ -2164,6 +2164,10 @@ var RESTAnalyticsAdapter = class {
|
|
|
2164
2164
|
const events = [...this.queue];
|
|
2165
2165
|
this.queue = [];
|
|
2166
2166
|
try {
|
|
2167
|
+
const hasToken = await this.httpClient.hasAccessToken();
|
|
2168
|
+
if (!hasToken) {
|
|
2169
|
+
return;
|
|
2170
|
+
}
|
|
2167
2171
|
const requestBody = await this.buildRequestBody(events);
|
|
2168
2172
|
if (this.trySendBeacon(requestBody)) {
|
|
2169
2173
|
return;
|
|
@@ -3351,6 +3355,17 @@ var HttpClient = class {
|
|
|
3351
3355
|
getBaseUrl() {
|
|
3352
3356
|
return this.config.baseUrl;
|
|
3353
3357
|
}
|
|
3358
|
+
/**
|
|
3359
|
+
* Check if access token is available
|
|
3360
|
+
*/
|
|
3361
|
+
async hasAccessToken() {
|
|
3362
|
+
try {
|
|
3363
|
+
const token = await this.config.auth.getAccessToken();
|
|
3364
|
+
return !!token;
|
|
3365
|
+
} catch {
|
|
3366
|
+
return false;
|
|
3367
|
+
}
|
|
3368
|
+
}
|
|
3354
3369
|
/**
|
|
3355
3370
|
* Make HTTP request with auth and retry
|
|
3356
3371
|
*/
|
|
@@ -4181,11 +4196,42 @@ var BrowserVideoLoader = class {
|
|
|
4181
4196
|
* Full segment preload requires hls.js which is optional
|
|
4182
4197
|
*/
|
|
4183
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
|
+
}
|
|
4184
4209
|
const response = await fetch(url, { signal });
|
|
4185
4210
|
if (!response.ok) {
|
|
4186
4211
|
throw new Error(`HTTP error: ${response.status}`);
|
|
4187
4212
|
}
|
|
4188
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
|
+
}
|
|
4189
4235
|
if (this.cache) {
|
|
4190
4236
|
try {
|
|
4191
4237
|
const cacheResponse = new Response(text, {
|
|
@@ -4197,8 +4243,50 @@ var BrowserVideoLoader = class {
|
|
|
4197
4243
|
} catch {
|
|
4198
4244
|
}
|
|
4199
4245
|
}
|
|
4246
|
+
await this.preloadHLSSegments(url, text, signal);
|
|
4200
4247
|
return text.length;
|
|
4201
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
|
+
}
|
|
4202
4290
|
/**
|
|
4203
4291
|
* Cancel preload
|
|
4204
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.
|
|
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.
|
|
23
|
+
"@xhub-short/contracts": "1.0.0-beta.27"
|
|
24
24
|
},
|
|
25
25
|
"optionalDependencies": {
|
|
26
26
|
"hls.js": "^1.5.0"
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"tsup": "^8.3.0",
|
|
30
30
|
"typescript": "^5.7.0",
|
|
31
31
|
"vitest": "^2.1.0",
|
|
32
|
-
"@xhub-short/tsconfig": "0.1
|
|
33
|
-
"@xhub-short/vitest-config": "0.1.0-beta.
|
|
32
|
+
"@xhub-short/tsconfig": "0.0.1-beta.2",
|
|
33
|
+
"@xhub-short/vitest-config": "0.1.0-beta.13"
|
|
34
34
|
},
|
|
35
35
|
"scripts": {
|
|
36
36
|
"build": "tsup",
|