@lvce-editor/shared-process 0.99.20 → 0.99.22
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/package.json +2 -2
- package/src/parts/BuiltinExtensionsPath/BuiltinExtensionsPath.js +1 -1
- package/src/parts/GetByteRange/GetByteRange.js +43 -0
- package/src/parts/GetContentResponse/GetContentResponse.js +2 -2
- package/src/parts/GetElectronFileResponse/GetElectronFileResponse.js +19 -0
- package/src/parts/GetElectronFileResponseContent/GetElectronFileResponseContent.js +18 -2
- package/src/parts/GetHeaders/GetHeaders.js +3 -0
- package/src/parts/HttpHeader/HttpHeader.js +3 -0
- package/src/parts/HttpStatusCode/HttpStatusCode.js +2 -0
- package/src/parts/Platform/Platform.js +3 -3
- package/src/parts/PreloadUrl/PreloadUrl.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lvce-editor/shared-process",
|
|
3
|
-
"version": "0.99.
|
|
3
|
+
"version": "0.99.22",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@lvce-editor/assert": "1.9.0",
|
|
21
|
-
"@lvce-editor/extension-host-helper-process": "0.99.
|
|
21
|
+
"@lvce-editor/extension-host-helper-process": "0.99.22",
|
|
22
22
|
"@lvce-editor/ipc": "16.10.0",
|
|
23
23
|
"@lvce-editor/json-rpc": "8.6.0",
|
|
24
24
|
"@lvce-editor/jsonc-parser": "1.5.0",
|
|
@@ -3,6 +3,6 @@ import { fileURLToPath } from 'url'
|
|
|
3
3
|
|
|
4
4
|
export const getBuiltinExtensionsPath = () => {
|
|
5
5
|
const staticServerPath = fileURLToPath(import.meta.resolve('@lvce-editor/static-server'))
|
|
6
|
-
const builtinExtensionsPath = join(staticServerPath, '..', '..', 'static', '
|
|
6
|
+
const builtinExtensionsPath = join(staticServerPath, '..', '..', 'static', '7d43ec7', 'extensions')
|
|
7
7
|
return builtinExtensionsPath
|
|
8
8
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
const byteRangeRegex = /^bytes=(\d*)-(\d*)$/
|
|
7
|
+
|
|
8
|
+
const isValidInteger = (value) => {
|
|
9
|
+
return Number.isSafeInteger(value) && value >= 0
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const getByteRange = (rangeHeader, size) => {
|
|
13
|
+
const match = byteRangeRegex.exec(rangeHeader)
|
|
14
|
+
if (!match || size <= 0) {
|
|
15
|
+
return undefined
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const [, startText, endText] = match
|
|
19
|
+
if (!startText && !endText) {
|
|
20
|
+
return undefined
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (!startText) {
|
|
24
|
+
const suffixLength = Number(endText)
|
|
25
|
+
if (!isValidInteger(suffixLength) || suffixLength === 0) {
|
|
26
|
+
return undefined
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
end: size - 1,
|
|
30
|
+
start: Math.max(0, size - suffixLength),
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const start = Number(startText)
|
|
35
|
+
const requestedEnd = endText ? Number(endText) : size - 1
|
|
36
|
+
if (!isValidInteger(start) || !isValidInteger(requestedEnd) || start >= size || start > requestedEnd) {
|
|
37
|
+
return undefined
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
end: Math.min(requestedEnd, size - 1),
|
|
41
|
+
start,
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as HttpStatusCode from '../HttpStatusCode/HttpStatusCode.js'
|
|
2
2
|
|
|
3
|
-
export const getContentResponse = async (content, headers = {}) => {
|
|
3
|
+
export const getContentResponse = async (content, headers = {}, status = HttpStatusCode.Ok) => {
|
|
4
4
|
return {
|
|
5
5
|
body: content,
|
|
6
6
|
init: {
|
|
7
7
|
headers,
|
|
8
|
-
status
|
|
8
|
+
status,
|
|
9
9
|
},
|
|
10
10
|
}
|
|
11
11
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { pathToFileURL } from 'node:url'
|
|
2
|
+
import * as GetByteRange from '../GetByteRange/GetByteRange.js'
|
|
2
3
|
import * as GetContentResponse from '../GetContentResponse/GetContentResponse.js'
|
|
3
4
|
import * as GetElectronFileResponseAbsolutePath from '../GetElectronFileResponseAbsolutePath/GetElectronFileResponseAbsolutePath.js'
|
|
4
5
|
import * as GetElectronFileResponseContent from '../GetElectronFileResponseContent/GetElectronFileResponseContent.js'
|
|
@@ -10,6 +11,7 @@ import * as GetPathEtag from '../GetPathEtag/GetPathEtag.js'
|
|
|
10
11
|
import * as GetServerErrorResponse from '../GetServerErrorResponse/GetServerErrorResponse.js'
|
|
11
12
|
import * as GetTypeScriptSyntaxErrorResponse from '../GetTypeScriptSyntaxErrorResponse/GetTypeScriptSyntaxErrorResponse.js'
|
|
12
13
|
import * as HttpHeader from '../HttpHeader/HttpHeader.js'
|
|
14
|
+
import * as HttpStatusCode from '../HttpStatusCode/HttpStatusCode.js'
|
|
13
15
|
import * as IsEnoentError from '../IsEnoentError/IsEnoentError.js'
|
|
14
16
|
import * as IsTypeScriptSyntaxError from '../IsTypeScriptSyntaxError/IsTypeScriptSyntaxError.js'
|
|
15
17
|
import * as Logger from '../Logger/Logger.js'
|
|
@@ -29,12 +31,14 @@ export const getElectronFileResponse = async (url, request) => {
|
|
|
29
31
|
let etag
|
|
30
32
|
let preparedContent
|
|
31
33
|
let stats
|
|
34
|
+
let totalSize
|
|
32
35
|
// TODO when is there no request?
|
|
33
36
|
if (request) {
|
|
34
37
|
const info = await GetPathEtag.getPathEtag(absolutePath)
|
|
35
38
|
etag = info.etag
|
|
36
39
|
stats = info.stats
|
|
37
40
|
let size = stats.size
|
|
41
|
+
totalSize = size
|
|
38
42
|
if (absolutePath.endsWith('.html')) {
|
|
39
43
|
// TODO since dynamic data is injected to the stat size is not accurate
|
|
40
44
|
// which is why this workaround is needed
|
|
@@ -47,6 +51,21 @@ export const getElectronFileResponse = async (url, request) => {
|
|
|
47
51
|
return GetNotModifiedResponse.getNotModifiedResponse(headers)
|
|
48
52
|
}
|
|
49
53
|
}
|
|
54
|
+
const rangeHeader = request?.headers?.[HttpHeader.Range]
|
|
55
|
+
if (rangeHeader && pathName.startsWith('/remote') && typeof totalSize === 'number') {
|
|
56
|
+
const range = GetByteRange.getByteRange(rangeHeader, totalSize)
|
|
57
|
+
if (!range) {
|
|
58
|
+
const headers = await GetHeaders.getHeaders(absolutePath, pathName, etag, url, 0)
|
|
59
|
+
headers[HttpHeader.CacheControl] = 'public, max-age=0, must-revalidate'
|
|
60
|
+
headers[HttpHeader.ContentRange] = `bytes */${totalSize}`
|
|
61
|
+
return GetContentResponse.getContentResponse(Buffer.alloc(0), headers, HttpStatusCode.RangeNotSatisfiable)
|
|
62
|
+
}
|
|
63
|
+
const content = await GetElectronFileResponseContent.getElectronFileResponseContent(request, absolutePath, url, range)
|
|
64
|
+
const headers = await GetHeaders.getHeaders(absolutePath, pathName, etag, url, content.byteLength)
|
|
65
|
+
headers[HttpHeader.CacheControl] = 'public, max-age=0, must-revalidate'
|
|
66
|
+
headers[HttpHeader.ContentRange] = `bytes ${range.start}-${range.end}/${totalSize}`
|
|
67
|
+
return GetContentResponse.getContentResponse(content, headers, HttpStatusCode.PartialContent)
|
|
68
|
+
}
|
|
50
69
|
const content = preparedContent || (await GetElectronFileResponseContent.getElectronFileResponseContent(request, absolutePath, url))
|
|
51
70
|
const size = content.byteLength
|
|
52
71
|
const headers = await GetHeaders.getHeaders(absolutePath, pathName, etag, url, size)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { readFile } from 'node:fs/promises'
|
|
1
|
+
import { open, readFile } from 'node:fs/promises'
|
|
2
|
+
|
|
2
3
|
import * as AddCustomPathsToIndexHtml from '../AddCustomPathsToIndexHtml/AddCustomPathsToIndexHtml.js'
|
|
3
4
|
import * as Platform from '../Platform/Platform.js'
|
|
4
5
|
import * as ShouldTranspileTypescript from '../ShouldTranspileTypescript/ShouldTranspileTypescript.js'
|
|
@@ -6,7 +7,22 @@ import * as TranspileTypeScript from '../TranspileTypeScript/TranspileTypeScript
|
|
|
6
7
|
|
|
7
8
|
const useCache = false // TODO enable this
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
const readRange = async (absolutePath, range) => {
|
|
11
|
+
const length = range.end - range.start + 1
|
|
12
|
+
const buffer = Buffer.allocUnsafe(length)
|
|
13
|
+
const file = await open(absolutePath, 'r')
|
|
14
|
+
try {
|
|
15
|
+
const { bytesRead } = await file.read(buffer, 0, length, range.start)
|
|
16
|
+
return buffer.subarray(0, bytesRead)
|
|
17
|
+
} finally {
|
|
18
|
+
await file.close()
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const getElectronFileResponseContent = async (request, absolutePath, url, range) => {
|
|
23
|
+
if (range) {
|
|
24
|
+
return readRange(absolutePath, range)
|
|
25
|
+
}
|
|
10
26
|
if (ShouldTranspileTypescript.shouldTranspileTypescript(request, url)) {
|
|
11
27
|
const content = await readFile(absolutePath)
|
|
12
28
|
const newContent = await TranspileTypeScript.transpileTypeScript(content.toString(), useCache)
|
|
@@ -15,6 +15,9 @@ export const getHeaders = async (absolutePath, pathName, etag, url, size) => {
|
|
|
15
15
|
[HttpHeader.CrossOriginEmbedderPolicy]: CrossOriginEmbedderPolicy.value,
|
|
16
16
|
[HttpHeader.CrossOriginResourcePolicy]: CrossOriginResourcePolicy.value,
|
|
17
17
|
}
|
|
18
|
+
if (pathName.startsWith('/remote')) {
|
|
19
|
+
headers[HttpHeader.AcceptRanges] = 'bytes'
|
|
20
|
+
}
|
|
18
21
|
const extraHeaders = await GetExtraHeaders.getExtraHeaders({
|
|
19
22
|
absolutePath,
|
|
20
23
|
etag,
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
export const AcceptRanges = 'Accept-Ranges'
|
|
1
2
|
export const CacheControl = 'Cache-Control'
|
|
3
|
+
export const ContentRange = 'Content-Range'
|
|
2
4
|
export const ContentType = 'Content-Type'
|
|
3
5
|
export const ContentLength = 'Content-Length'
|
|
4
6
|
export const ContentSecurityPolicy = 'Content-Security-Policy'
|
|
@@ -7,3 +9,4 @@ export const CrossOriginOpenerPolicy = 'Cross-Origin-Opener-Policy'
|
|
|
7
9
|
export const CrossOriginResourcePolicy = 'Cross-Origin-Resource-Policy'
|
|
8
10
|
export const Etag = 'Etag'
|
|
9
11
|
export const IfNotMatch = 'if-none-match'
|
|
12
|
+
export const Range = 'range'
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export const NotFound = 404
|
|
2
2
|
export const Ok = 200
|
|
3
|
+
export const PartialContent = 206
|
|
3
4
|
export const Forbidden = 403
|
|
4
5
|
export const UnprocessableContent = 422
|
|
5
6
|
export const ServerError = 500
|
|
6
7
|
export const NotModifed = 304
|
|
7
8
|
export const MultipleChoices = 300
|
|
9
|
+
export const RangeNotSatisfiable = 416
|
|
@@ -61,11 +61,11 @@ export const getSetupName = () => {
|
|
|
61
61
|
return 'Lvce-Setup'
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
export const version = '0.99.
|
|
64
|
+
export const version = '0.99.22'
|
|
65
65
|
|
|
66
|
-
export const commit = '
|
|
66
|
+
export const commit = '7d43ec7'
|
|
67
67
|
|
|
68
|
-
export const date = '2026-08-
|
|
68
|
+
export const date = '2026-08-08T21:51:37.000Z'
|
|
69
69
|
|
|
70
70
|
export const getVersion = () => {
|
|
71
71
|
return version
|
|
@@ -2,5 +2,5 @@ import { join } from 'node:path'
|
|
|
2
2
|
import * as Root from '../Root/Root.js'
|
|
3
3
|
|
|
4
4
|
export const getPreloadUrl = () => {
|
|
5
|
-
return join(Root.root, 'static', '
|
|
5
|
+
return join(Root.root, 'static', '7d43ec7', 'packages', 'preload', 'dist', 'index.js')
|
|
6
6
|
}
|