@embeddable.com/sdk-core 4.2.0 → 4.3.0-next.0
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/lib/dev.d.ts +6 -1
- package/lib/generate.d.ts +30 -1
- package/lib/index.esm.js +307 -36
- package/lib/index.esm.js.map +1 -1
- package/lib/utils/dev.utils.d.ts +26 -0
- package/package.json +1 -1
- package/src/dev.test.ts +184 -14
- package/src/dev.ts +163 -15
- package/src/generate.test.ts +187 -3
- package/src/generate.ts +148 -24
- package/src/utils/dev.utils.test.ts +126 -0
- package/src/utils/dev.utils.ts +117 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import { ServerResponse } from "http";
|
|
3
|
+
import { createReadStream } from "node:fs";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Wraps a ServerResponse object to prevent setting the Content-Length header.
|
|
7
|
+
*/
|
|
8
|
+
export function preventContentLength(res: ServerResponse) {
|
|
9
|
+
const originalSetHeader = res.setHeader.bind(res);
|
|
10
|
+
res.setHeader = function (key: string, value: any) {
|
|
11
|
+
if (key.toLowerCase() === "content-length") {
|
|
12
|
+
return this;
|
|
13
|
+
}
|
|
14
|
+
return originalSetHeader(key, value);
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function createWatcherLock() {
|
|
19
|
+
let locked = false;
|
|
20
|
+
let waiters: (() => void)[] = [];
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
lock() {
|
|
24
|
+
if (!locked) {
|
|
25
|
+
locked = true;
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
unlock() {
|
|
30
|
+
if (locked) {
|
|
31
|
+
locked = false;
|
|
32
|
+
waiters.forEach((fn) => fn());
|
|
33
|
+
waiters = [];
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
async waitUntilFree() {
|
|
38
|
+
if (!locked) return;
|
|
39
|
+
await new Promise<void>((resolve) => {
|
|
40
|
+
waiters.push(resolve);
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const delay = (ms: number) => new Promise((res) => setTimeout(res, ms));
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* This function waits until a file stabilizes, meaning its size does not change for a certain number of attempts
|
|
50
|
+
* and the content ends with a specific expected tail.
|
|
51
|
+
* It uses stream reading to check the file's content, the same wait serve-static uses.
|
|
52
|
+
* This will help to prevent when serve-static serves a file that is still being written to.
|
|
53
|
+
* One of the issues, related to this, is "Constructor for "embeddable-component#undefined" was not found", that we saw quite often in the past.
|
|
54
|
+
* @param filePath
|
|
55
|
+
* @param expectedTail
|
|
56
|
+
* @param maxAttempts
|
|
57
|
+
* @param stableCount
|
|
58
|
+
*/
|
|
59
|
+
export async function waitUntilFileStable(
|
|
60
|
+
filePath: string,
|
|
61
|
+
expectedTail: string,
|
|
62
|
+
{
|
|
63
|
+
maxAttempts = 100,
|
|
64
|
+
requiredStableCount = 2,
|
|
65
|
+
}: {
|
|
66
|
+
maxAttempts?: number;
|
|
67
|
+
requiredStableCount?: number;
|
|
68
|
+
} = {}
|
|
69
|
+
): Promise<void> {
|
|
70
|
+
let lastSize = -1;
|
|
71
|
+
let stableCounter = 0;
|
|
72
|
+
|
|
73
|
+
for (let i = 0; i < maxAttempts; i++) {
|
|
74
|
+
try {
|
|
75
|
+
const { size, tailMatches } = await checkFileTail(filePath, expectedTail);
|
|
76
|
+
|
|
77
|
+
if (size === lastSize && size > 0 && tailMatches) {
|
|
78
|
+
stableCounter++;
|
|
79
|
+
if (stableCounter >= requiredStableCount) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
stableCounter = 0;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
lastSize = size;
|
|
87
|
+
} catch {
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
await delay(50);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
throw new Error("File did not stabilize");
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function checkFileTail(
|
|
97
|
+
filePath: string,
|
|
98
|
+
expectedTail: string,
|
|
99
|
+
tailLength = 500
|
|
100
|
+
): Promise<{ size: number; tailMatches: boolean }> {
|
|
101
|
+
const stats = await fs.stat(filePath);
|
|
102
|
+
const size = stats.size;
|
|
103
|
+
const start = Math.max(0, size - tailLength);
|
|
104
|
+
|
|
105
|
+
return new Promise((resolve, reject) => {
|
|
106
|
+
let tailBuffer = "";
|
|
107
|
+
|
|
108
|
+
createReadStream(filePath, { encoding: "utf-8", start })
|
|
109
|
+
.on("data", (chunk) => {
|
|
110
|
+
tailBuffer += chunk;
|
|
111
|
+
})
|
|
112
|
+
.on("end", () => {
|
|
113
|
+
resolve({ size, tailMatches: tailBuffer.includes(expectedTail) });
|
|
114
|
+
})
|
|
115
|
+
.on("error", reject);
|
|
116
|
+
});
|
|
117
|
+
}
|