@logto/tunnel 0.2.0 → 0.2.2
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.
|
@@ -25,4 +25,4 @@ export declare const checkExperienceInput: (url?: string, staticPath?: string) =
|
|
|
25
25
|
* @example isLogtoRequestPath('/consent') // true
|
|
26
26
|
*/
|
|
27
27
|
export declare const isLogtoRequestPath: (requestPath?: string) => boolean;
|
|
28
|
-
export declare const
|
|
28
|
+
export declare const getMimeType: (requestPath: string) => string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import fs from 'node:fs/promises';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
-
import { isValidUrl } from '@logto/core-kit';
|
|
4
|
+
import { isFileAssetPath, isValidUrl, parseRange } from '@logto/core-kit';
|
|
5
5
|
import { conditional, trySafe } from '@silverhand/essentials';
|
|
6
6
|
import chalk from 'chalk';
|
|
7
7
|
import { createProxyMiddleware, responseInterceptor } from 'http-proxy-middleware';
|
|
@@ -35,18 +35,42 @@ export const createStaticFileProxy = (staticPath) => async (request, response) =
|
|
|
35
35
|
if (request.method === 'HEAD' || request.method === 'GET') {
|
|
36
36
|
const fallBackToIndex = !isFileAssetPath(request.url);
|
|
37
37
|
const requestPath = path.join(staticPath, fallBackToIndex ? index : request.url);
|
|
38
|
+
const { range = '' } = request.headers;
|
|
39
|
+
const readFile = async (requestPath, start, end) => {
|
|
40
|
+
const fileHandle = await fs.open(requestPath, 'r');
|
|
41
|
+
const { size } = await fileHandle.stat();
|
|
42
|
+
const readStart = start ?? 0;
|
|
43
|
+
const readEnd = end ?? Math.max(size - 1, 0);
|
|
44
|
+
const buffer = Buffer.alloc(readEnd - readStart + 1);
|
|
45
|
+
await fileHandle.read(buffer, 0, buffer.length, readStart);
|
|
46
|
+
await fileHandle.close();
|
|
47
|
+
return { buffer, totalFileSize: size };
|
|
48
|
+
};
|
|
49
|
+
const setRangeHeaders = (response, range, totalFileSize) => {
|
|
50
|
+
if (range) {
|
|
51
|
+
const { start, end } = parseRange(range);
|
|
52
|
+
const readStart = start ?? 0;
|
|
53
|
+
const readEnd = end ?? totalFileSize - 1;
|
|
54
|
+
response.setHeader('Accept-Ranges', 'bytes');
|
|
55
|
+
response.setHeader('Content-Range', `bytes ${readStart}-${readEnd}/${totalFileSize}`);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
38
58
|
try {
|
|
39
|
-
const
|
|
59
|
+
const { start, end } = parseRange(range);
|
|
60
|
+
const { buffer, totalFileSize } = await readFile(requestPath, start, end);
|
|
40
61
|
response.setHeader('cache-control', fallBackToIndex ? noCache : maxAgeSevenDays);
|
|
41
62
|
response.setHeader('content-type', getMimeType(request.url));
|
|
42
|
-
response
|
|
43
|
-
response.
|
|
63
|
+
setRangeHeaders(response, range, totalFileSize);
|
|
64
|
+
response.setHeader('content-length', String(buffer.length));
|
|
65
|
+
response.writeHead(range ? 206 : 200);
|
|
66
|
+
response.end(buffer);
|
|
44
67
|
}
|
|
45
68
|
catch (error) {
|
|
46
69
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
47
70
|
consoleLog.error(chalk.red(errorMessage));
|
|
48
71
|
response.setHeader('content-type', getMimeType(request.url));
|
|
49
|
-
|
|
72
|
+
const statusCode = errorMessage === 'Range not satisfiable.' ? 416 : existsSync(request.url) ? 500 : 404;
|
|
73
|
+
response.writeHead(statusCode);
|
|
50
74
|
response.end();
|
|
51
75
|
}
|
|
52
76
|
}
|
|
@@ -116,12 +140,7 @@ Specify --help for available options`);
|
|
|
116
140
|
* @example isLogtoRequestPath('/consent') // true
|
|
117
141
|
*/
|
|
118
142
|
export const isLogtoRequestPath = (requestPath) => ['/oidc/', '/api/'].some((path) => requestPath?.startsWith(path)) || requestPath === '/consent';
|
|
119
|
-
export const
|
|
120
|
-
// Check if the request URL contains query params. If yes, ignore the params and check the request path
|
|
121
|
-
const pathWithoutQuery = url.split('?')[0];
|
|
122
|
-
return Boolean(pathWithoutQuery?.split('/').at(-1)?.includes('.'));
|
|
123
|
-
};
|
|
124
|
-
const getMimeType = (requestPath) => {
|
|
143
|
+
export const getMimeType = (requestPath) => {
|
|
125
144
|
const fallBackToIndex = !isFileAssetPath(requestPath);
|
|
126
145
|
if (fallBackToIndex) {
|
|
127
146
|
return indexContentType;
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import { expect, describe, it } from 'vitest';
|
|
2
|
-
import {
|
|
2
|
+
import { getMimeType } from './utils.js';
|
|
3
3
|
describe('Tunnel utils', () => {
|
|
4
|
-
it('should be able to
|
|
5
|
-
expect(
|
|
6
|
-
expect(
|
|
7
|
-
expect(
|
|
8
|
-
expect(
|
|
9
|
-
expect(
|
|
10
|
-
expect(isFileAssetPath('/api/interaction/submit')).toBe(false);
|
|
11
|
-
expect(isFileAssetPath('/consent')).toBe(false);
|
|
12
|
-
expect(isFileAssetPath('/callback/45doq0d004awrjyvdbp92?state=PxsR_Iqtkxw&code=4/0AcvDMrCOMTFXWlKzTcUO24xDify5tQbIMYvaYDS0sj82NzzYlrG4BWXJB4-OxjBI1RPL8g&scope=email%20profile%20openid%20https:/www.googleapis.com/auth/userinfo.profile%20https:/www.googleapis.com/auth/userinfo.email&authuser=0&hd=silverhand.io&prompt=consent')).toBe(false);
|
|
4
|
+
it('should be able to get mime type according to request path', () => {
|
|
5
|
+
expect(getMimeType('/scripts.js')).toEqual('text/javascript');
|
|
6
|
+
expect(getMimeType('/image.png')).toEqual('image/png');
|
|
7
|
+
expect(getMimeType('/style.css')).toEqual('text/css');
|
|
8
|
+
expect(getMimeType('/index.html')).toEqual('text/html');
|
|
9
|
+
expect(getMimeType('/')).toEqual('text/html; charset=utf-8');
|
|
13
10
|
});
|
|
14
11
|
});
|
package/lib/package-json.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export const packageJson = {
|
|
2
2
|
"name": "@logto/tunnel",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "A CLI tool that creates tunnel service to Logto Cloud for local development.",
|
|
5
5
|
"author": "Silverhand Inc. <contact@silverhand.io>",
|
|
6
6
|
"homepage": "https://github.com/logto-io/logto#readme",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@logto/tunnel",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "A CLI tool that creates tunnel service to Logto Cloud for local development.",
|
|
5
5
|
"author": "Silverhand Inc. <contact@silverhand.io>",
|
|
6
6
|
"homepage": "https://github.com/logto-io/logto#readme",
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
"ora": "^8.0.1",
|
|
39
39
|
"yargs": "^17.6.0",
|
|
40
40
|
"zod": "^3.23.8",
|
|
41
|
-
"@logto/
|
|
42
|
-
"@logto/
|
|
41
|
+
"@logto/shared": "^3.1.2",
|
|
42
|
+
"@logto/core-kit": "^2.5.1"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@silverhand/eslint-config": "6.0.1",
|