@samsara-dev/appwright 0.9.17 → 0.9.20
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/CHANGELOG.md +18 -0
- package/dist/gptDriver/index.d.ts +6 -0
- package/dist/gptDriver/index.d.ts.map +1 -1
- package/dist/gptDriver/index.js +19 -2
- package/dist/providers/browserstack/index.d.ts.map +1 -1
- package/dist/providers/browserstack/index.js +9 -2
- package/dist/reporter.d.ts.map +1 -1
- package/dist/reporter.js +3 -34
- package/dist/types/index.d.ts +24 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/validateMp4.d.ts +7 -0
- package/dist/validateMp4.d.ts.map +1 -0
- package/dist/validateMp4.js +47 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# appwright
|
|
2
2
|
|
|
3
|
+
## 0.9.20
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 88706fe: Fix node engine constraint from >=24.12.0 to >=20.19.6. The previous constraint blocked installation on Node 20. Add Node 20.19.6 to CI build and test matrix.
|
|
8
|
+
|
|
9
|
+
## 0.9.19
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 17f5350: Add `testIdFormat` option to `GptDriverConfig` for human-readable GPT Driver session IDs. When configured, replaces Playwright's hash-based testId with a custom format (e.g. "Form Submission - submit form with all field types") in every MobileBoost API call. Backward-compatible: omitting the option preserves existing behavior.
|
|
14
|
+
|
|
15
|
+
## 0.9.18
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- f7d62b6: Validate MP4 moov atom after BrowserStack video download to prevent corrupt video attachments. BrowserStack can return HTTP 200 with a video still being finalized (missing moov atom). The download retry loop now re-downloads until the file has a valid moov atom, capped at 5 retries.
|
|
20
|
+
|
|
3
21
|
## 0.9.17
|
|
4
22
|
|
|
5
23
|
### Patch Changes
|
|
@@ -34,6 +34,12 @@ export declare class GptDriverProvider implements GptDriverApi {
|
|
|
34
34
|
private driver;
|
|
35
35
|
private testIdWarned;
|
|
36
36
|
constructor(webDriverClient: WebDriverClient, options?: GptDriverConfig | undefined);
|
|
37
|
+
/**
|
|
38
|
+
* Resolve the testId for the current test context.
|
|
39
|
+
* Uses the custom testIdFormat callback if configured, otherwise falls back
|
|
40
|
+
* to Playwright's hash-based testId.
|
|
41
|
+
*/
|
|
42
|
+
private resolveTestId;
|
|
37
43
|
private getAppiumUrl;
|
|
38
44
|
private getDriver;
|
|
39
45
|
private requireDriver;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/gptDriver/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,IAAI,eAAe,EAAE,MAAM,WAAW,CAAC;AAG3D,OAAO,KAAK,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/gptDriver/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,IAAI,eAAe,EAAE,MAAM,WAAW,CAAC;AAG3D,OAAO,KAAK,EAAE,eAAe,EAAc,MAAM,UAAU,CAAC;AAI5D;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1E,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAClE,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;CAC9D;AAED;;;;;;;;;GASG;AACH,qBAAa,iBAAkB,YAAW,YAAY;IAKlD,OAAO,CAAC,eAAe;IACvB,OAAO,CAAC,OAAO,CAAC;IALlB,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,YAAY,CAAS;gBAGnB,eAAe,EAAE,eAAe,EAChC,OAAO,CAAC,EAAE,eAAe,YAAA;IAGnC;;;;OAIG;IACH,OAAO,CAAC,aAAa;IAgBrB,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,SAAS;IA0BjB,OAAO,CAAC,aAAa;IA8BrB,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,kBAAkB;IAS1B,OAAO,CAAC,aAAa;IAMf,SAAS,CACb,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,IAAI,CAAC;IAkBV,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAaxC,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAa/C,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAajE,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAWnE"}
|
package/dist/gptDriver/index.js
CHANGED
|
@@ -82,6 +82,23 @@ let GptDriverProvider = (() => {
|
|
|
82
82
|
this.webDriverClient = webDriverClient;
|
|
83
83
|
this.options = options;
|
|
84
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Resolve the testId for the current test context.
|
|
87
|
+
* Uses the custom testIdFormat callback if configured, otherwise falls back
|
|
88
|
+
* to Playwright's hash-based testId.
|
|
89
|
+
*/
|
|
90
|
+
resolveTestId(testInfo) {
|
|
91
|
+
if (!testInfo)
|
|
92
|
+
return undefined;
|
|
93
|
+
if (this.options?.testIdFormat) {
|
|
94
|
+
const info = {
|
|
95
|
+
title: testInfo.title,
|
|
96
|
+
titlePath: testInfo.titlePath,
|
|
97
|
+
};
|
|
98
|
+
return this.options.testIdFormat(info);
|
|
99
|
+
}
|
|
100
|
+
return testInfo.testId;
|
|
101
|
+
}
|
|
85
102
|
getAppiumUrl() {
|
|
86
103
|
const { protocol, hostname, port, path, user, key } = this.webDriverClient.options;
|
|
87
104
|
// Include basic auth for cloud providers (BrowserStack, LambdaTest)
|
|
@@ -102,7 +119,7 @@ let GptDriverProvider = (() => {
|
|
|
102
119
|
driver: this.webDriverClient,
|
|
103
120
|
serverConfig: { url: this.getAppiumUrl() },
|
|
104
121
|
cachingMode: "INTERACTION_REGION",
|
|
105
|
-
testId: test_1.default.info()
|
|
122
|
+
testId: this.resolveTestId(test_1.default.info()) ?? `test-${Date.now()}`,
|
|
106
123
|
...(this.options?.additionalUserContext != null && {
|
|
107
124
|
additionalUserContext: this.options.additionalUserContext,
|
|
108
125
|
}),
|
|
@@ -121,7 +138,7 @@ let GptDriverProvider = (() => {
|
|
|
121
138
|
// gpt-driver-node declares testId as private in TS but it's a plain
|
|
122
139
|
// JS property at runtime — safe to mutate directly.
|
|
123
140
|
// TODO: Replace with public setTestId() if gpt-driver-node exposes one.
|
|
124
|
-
const currentTestId = test_1.default.info()
|
|
141
|
+
const currentTestId = this.resolveTestId(test_1.default.info());
|
|
125
142
|
if (currentTestId && "testId" in driver) {
|
|
126
143
|
driver.testId = currentTestId;
|
|
127
144
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/browserstack/index.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,eAAe,EACf,cAAc,EAGf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/browserstack/index.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,eAAe,EACf,cAAc,EAGf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AA2DtC,qBAAa,0BAA2B,YAAW,cAAc;IAC/D,OAAO,CAAC,cAAc,CAAC,CAA6B;IACpD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,OAAO,CAA+B;gBAG5C,OAAO,EAAE,WAAW,CAAC,eAAe,CAAC,EACrC,WAAW,EAAE,MAAM,GAAG,SAAS;IAU3B,WAAW;IA0EX,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;IAMlC,OAAO,CAAC,cAAc;YASR,YAAY;YAoCZ,iBAAiB;YAKjB,yBAAyB;WAK1B,aAAa,CACxB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IA2GlD,eAAe,CAAC,OAAO,EAAE;QAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf;IA2BD,OAAO,CAAC,YAAY;CAuLrB"}
|
|
@@ -13,6 +13,7 @@ const device_1 = require("../../device");
|
|
|
13
13
|
const logger_1 = require("../../logger");
|
|
14
14
|
const s3_1 = require("./s3");
|
|
15
15
|
const appiumSettings_1 = require("../appiumSettings");
|
|
16
|
+
const validateMp4_1 = require("../../validateMp4");
|
|
16
17
|
const API_BASE_URL = "https://api-cloud.browserstack.com/app-automate";
|
|
17
18
|
const envVarKeyForBuild = (projectName) => `BROWSERSTACK_APP_URL_${projectName.toUpperCase()}`;
|
|
18
19
|
function getAuthHeader() {
|
|
@@ -213,13 +214,19 @@ class BrowserStackDeviceProvider {
|
|
|
213
214
|
fileStream.destroy();
|
|
214
215
|
throw err;
|
|
215
216
|
}
|
|
217
|
+
// BrowserStack can return HTTP 200 with a video whose moov
|
|
218
|
+
// atom hasn't been written yet (still encoding). Throwing
|
|
219
|
+
// here lets async-retry re-download until the file is valid.
|
|
220
|
+
if (!(0, validateMp4_1.validateMp4)(tempPathForWriting)) {
|
|
221
|
+
throw new Error("Downloaded video is incomplete (missing moov atom)");
|
|
222
|
+
}
|
|
216
223
|
}, {
|
|
217
|
-
retries:
|
|
224
|
+
retries: 5,
|
|
218
225
|
minTimeout: 3_000,
|
|
219
226
|
maxTimeout: 60_000,
|
|
220
227
|
onRetry: (err, i) => {
|
|
221
228
|
const message = err instanceof Error ? err.message : String(err);
|
|
222
|
-
logger_1.logger.warn(`[${new Date().toISOString()}] Video download retry ${i}/
|
|
229
|
+
logger_1.logger.warn(`[${new Date().toISOString()}] Video download retry ${i}/5 failed: ${message}`);
|
|
223
230
|
},
|
|
224
231
|
});
|
|
225
232
|
fs_1.default.renameSync(tempPathForWriting, pathToTestVideo);
|
package/dist/reporter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAWhF,cAAM,eAAgB,YAAW,QAAQ;IACvC,OAAO,CAAC,gBAAgB,CAAsB;IAK9C,OAAO,CAAC,oBAAoB,CAA6C;IAEzE,OAAO;IAQP,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU;IAU9C,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU;IAgItC,KAAK;YAKG,kCAAkC;IA6ChD;;;;;;;OAOG;YACW,2BAA2B;IAqBzC,OAAO,CAAC,4BAA4B;IAyBpC,OAAO,CAAC,qBAAqB;CAU9B;AAuGD,eAAe,eAAe,CAAC"}
|
package/dist/reporter.js
CHANGED
|
@@ -10,6 +10,7 @@ const fluent_ffmpeg_1 = __importDefault(require("fluent-ffmpeg"));
|
|
|
10
10
|
const ffmpeg_1 = __importDefault(require("@ffmpeg-installer/ffmpeg"));
|
|
11
11
|
const logger_1 = require("./logger");
|
|
12
12
|
const utils_1 = require("./utils");
|
|
13
|
+
const validateMp4_1 = require("./validateMp4");
|
|
13
14
|
const workerInfo_1 = require("./fixture/workerInfo");
|
|
14
15
|
class VideoDownloader {
|
|
15
16
|
downloadPromises = [];
|
|
@@ -230,7 +231,7 @@ class VideoDownloader {
|
|
|
230
231
|
async function waitForFileOrEndTime(filePath, workerIndex, timeout = 5 * 60 * 1000) {
|
|
231
232
|
const deadline = Date.now() + timeout;
|
|
232
233
|
while (Date.now() < deadline) {
|
|
233
|
-
if (fs_1.default.existsSync(filePath) && validateMp4(filePath)) {
|
|
234
|
+
if (fs_1.default.existsSync(filePath) && (0, validateMp4_1.validateMp4)(filePath)) {
|
|
234
235
|
return "file";
|
|
235
236
|
}
|
|
236
237
|
try {
|
|
@@ -246,41 +247,9 @@ async function waitForFileOrEndTime(filePath, workerIndex, timeout = 5 * 60 * 10
|
|
|
246
247
|
}
|
|
247
248
|
throw new Error(`Timed out waiting for video file or worker ${workerIndex} endTime`);
|
|
248
249
|
}
|
|
249
|
-
/**
|
|
250
|
-
* Validate that an MP4 file has a valid moov atom (metadata header).
|
|
251
|
-
* BrowserStack videos can be incomplete if downloaded before finalization,
|
|
252
|
-
* resulting in a missing moov atom that causes ffmpeg to fail.
|
|
253
|
-
*/
|
|
254
|
-
function validateMp4(filePath) {
|
|
255
|
-
try {
|
|
256
|
-
const fd = fs_1.default.openSync(filePath, "r");
|
|
257
|
-
const stat = fs_1.default.fstatSync(fd);
|
|
258
|
-
const moovMarker = Buffer.from("moov");
|
|
259
|
-
const chunkSize = Math.min(stat.size, 128 * 1024);
|
|
260
|
-
// Check the beginning (fast-start MP4s place moov before mdat)
|
|
261
|
-
const head = Buffer.alloc(chunkSize);
|
|
262
|
-
fs_1.default.readSync(fd, head, 0, chunkSize, 0);
|
|
263
|
-
if (head.includes(moovMarker)) {
|
|
264
|
-
fs_1.default.closeSync(fd);
|
|
265
|
-
return true;
|
|
266
|
-
}
|
|
267
|
-
// Check the end (standard MP4s place moov after mdat)
|
|
268
|
-
if (stat.size > chunkSize) {
|
|
269
|
-
const tail = Buffer.alloc(chunkSize);
|
|
270
|
-
fs_1.default.readSync(fd, tail, 0, chunkSize, stat.size - chunkSize);
|
|
271
|
-
fs_1.default.closeSync(fd);
|
|
272
|
-
return tail.includes(moovMarker);
|
|
273
|
-
}
|
|
274
|
-
fs_1.default.closeSync(fd);
|
|
275
|
-
return false;
|
|
276
|
-
}
|
|
277
|
-
catch {
|
|
278
|
-
return false;
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
250
|
function trimVideo({ originalVideoPath, startSecs, durationSecs, outputPath, }) {
|
|
282
251
|
logger_1.logger.log(`Attemping to trim video: ${originalVideoPath} at start: ${startSecs} and duration: ${durationSecs} to ${outputPath}`);
|
|
283
|
-
if (!validateMp4(originalVideoPath)) {
|
|
252
|
+
if (!(0, validateMp4_1.validateMp4)(originalVideoPath)) {
|
|
284
253
|
throw new Error(`Video file is incomplete or corrupt (missing moov atom): ${originalVideoPath}`);
|
|
285
254
|
}
|
|
286
255
|
const copyName = `draft-for-${outputPath}`;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -48,6 +48,16 @@ export type AppwrightConfig = {
|
|
|
48
48
|
*/
|
|
49
49
|
gptDriver?: GptDriverConfig;
|
|
50
50
|
};
|
|
51
|
+
/**
|
|
52
|
+
* Minimal test metadata exposed to the testIdFormat callback.
|
|
53
|
+
* Deliberately narrow to avoid coupling consumer code to Playwright internals.
|
|
54
|
+
*/
|
|
55
|
+
export type TestIdInfo = {
|
|
56
|
+
/** The test's own title (e.g. "submit form with all field types"). */
|
|
57
|
+
title: string;
|
|
58
|
+
/** Full title path from outermost describe to the test (e.g. ["Form Submission", "submit form…"]). */
|
|
59
|
+
titlePath: string[];
|
|
60
|
+
};
|
|
51
61
|
/**
|
|
52
62
|
* Configuration for GPT Driver passed through to the gpt-driver-node SDK.
|
|
53
63
|
*/
|
|
@@ -58,6 +68,20 @@ export type GptDriverConfig = {
|
|
|
58
68
|
* that helps the AI understand your app's UI and behavior.
|
|
59
69
|
*/
|
|
60
70
|
additionalUserContext?: string;
|
|
71
|
+
/**
|
|
72
|
+
* Custom formatter for the testId sent to GPT Driver / MobileBoost.
|
|
73
|
+
* When provided, the return value replaces Playwright's hash-based testId
|
|
74
|
+
* in every GPT Driver API call, making sessions easier to identify in the
|
|
75
|
+
* MobileBoost dashboard.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* testIdFormat: (info) =>
|
|
80
|
+
* info.titlePath.slice(0, -1).join(" > ") + " - " + info.title
|
|
81
|
+
* // Produces: "Form Submission - submit form with all field types"
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
testIdFormat?: (info: TestIdInfo) => string;
|
|
61
85
|
};
|
|
62
86
|
/**
|
|
63
87
|
* Configuration for Visual Trace screenshot capture
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACnC,OAAO,KAAK,EAAE,sCAAsC,EAAE,MAAM,6BAA6B,CAAC;AAC1F,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;AAEtE,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B;;OAEG;IACH,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,WAAW,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9B;;OAEG;IACH,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAE7B;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE;QAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACrB;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IAEpB,aAAa,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;CAC7B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate that an MP4 file has a valid moov atom (metadata header).
|
|
3
|
+
* BrowserStack videos can be incomplete if downloaded before finalization,
|
|
4
|
+
* resulting in a missing moov atom that causes ffmpeg to fail.
|
|
5
|
+
*/
|
|
6
|
+
export declare function validateMp4(filePath: string): boolean;
|
|
7
|
+
//# sourceMappingURL=validateMp4.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validateMp4.d.ts","sourceRoot":"","sources":["../src/validateMp4.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAkCrD"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.validateMp4 = validateMp4;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
/**
|
|
9
|
+
* Validate that an MP4 file has a valid moov atom (metadata header).
|
|
10
|
+
* BrowserStack videos can be incomplete if downloaded before finalization,
|
|
11
|
+
* resulting in a missing moov atom that causes ffmpeg to fail.
|
|
12
|
+
*/
|
|
13
|
+
function validateMp4(filePath) {
|
|
14
|
+
let fd;
|
|
15
|
+
try {
|
|
16
|
+
fd = fs_1.default.openSync(filePath, "r");
|
|
17
|
+
const stat = fs_1.default.fstatSync(fd);
|
|
18
|
+
const moovMarker = Buffer.from("moov");
|
|
19
|
+
const chunkSize = Math.min(stat.size, 128 * 1024);
|
|
20
|
+
// Check the beginning (fast-start MP4s place moov before mdat)
|
|
21
|
+
const head = Buffer.alloc(chunkSize);
|
|
22
|
+
fs_1.default.readSync(fd, head, 0, chunkSize, 0);
|
|
23
|
+
if (head.includes(moovMarker)) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
// Check the end (standard MP4s place moov after mdat)
|
|
27
|
+
if (stat.size > chunkSize) {
|
|
28
|
+
const tail = Buffer.alloc(chunkSize);
|
|
29
|
+
fs_1.default.readSync(fd, tail, 0, chunkSize, stat.size - chunkSize);
|
|
30
|
+
return tail.includes(moovMarker);
|
|
31
|
+
}
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
if (fd !== undefined) {
|
|
39
|
+
try {
|
|
40
|
+
fs_1.default.closeSync(fd);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// already failing
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@samsara-dev/appwright",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.20",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"registry": "https://registry.npmjs.org/",
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
8
8
|
"main": "dist/index.js",
|
|
9
9
|
"engines": {
|
|
10
|
-
"node": ">=
|
|
10
|
+
"node": ">=20.19.6"
|
|
11
11
|
},
|
|
12
12
|
"bin": {
|
|
13
13
|
"appwright": "dist/bin/index.js"
|