Electron app loading improvements + Windows paths fix (#429)
- Electron no longer allows Windows paths in URLs (https://www.electronjs.org/docs/latest/breaking-changes#behavior-changed-custom-protocol-url-handling-on-windows), fixes with help of wabac.js to replace `C:\path\to\file` with `C//path/to/file` - Electron app cleanup: replace deprecated protocol handlers with new protocol.handle() method, update types - Electron app: ensure just filename is displayed on index page, consistent with other platforms - Update to wabac.js 2.23.2 - Update to Electron 36.3.2 - Fixes #427 - bump to 2.3.12
This commit is contained in:
@@ -2,13 +2,22 @@
|
|||||||
|
|
||||||
## CHANGES
|
## CHANGES
|
||||||
|
|
||||||
|
v2.3.12
|
||||||
|
|
||||||
|
- App: Cleanup Electron app code and add typing
|
||||||
|
- App: fix loading files from disk on Windows, existing files should continue to load
|
||||||
|
- Fidelity: Fix meta refresh rewriting (via wabac.js 2.23.2)
|
||||||
|
|
||||||
v2.3.11
|
v2.3.11
|
||||||
|
|
||||||
- Fidelity: Fix to importmaps (via wabac.js 2.23.1)
|
- Fidelity: Fix to importmaps (via wabac.js 2.23.1)
|
||||||
|
|
||||||
v2.3.10
|
v2.3.10
|
||||||
|
|
||||||
- Dependencies: Update Electron dependencies
|
- Dependencies: Update Electron dependencies
|
||||||
|
|
||||||
v2.3.9
|
v2.3.9
|
||||||
|
|
||||||
- Loading: Avoid unnecessary reloads of multiWACZ JSON, prune expired (via wabac.js 2.23.0)
|
- Loading: Avoid unnecessary reloads of multiWACZ JSON, prune expired (via wabac.js 2.23.0)
|
||||||
- Fidelity: Fix CSP issue with iframes in Firefox (via wabac.js 2.23.0)
|
- Fidelity: Fix CSP issue with iframes in Firefox (via wabac.js 2.23.0)
|
||||||
- Testing: Add testing for CSP handling and embeds in Firefox and Webkit
|
- Testing: Add testing for CSP handling and embeds in Firefox and Webkit
|
||||||
|
|||||||
+8
-6
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "replaywebpage",
|
"name": "replaywebpage",
|
||||||
"productName": "ReplayWeb.page",
|
"productName": "ReplayWeb.page",
|
||||||
"version": "2.3.11",
|
"version": "2.3.12",
|
||||||
"description": "Serverless Web Archive Replay",
|
"description": "Serverless Web Archive Replay",
|
||||||
"repository": "https://github.com/webrecorder/replayweb.page",
|
"repository": "https://github.com/webrecorder/replayweb.page",
|
||||||
"homepage": "https://replayweb.page/",
|
"homepage": "https://replayweb.page/",
|
||||||
@@ -22,10 +22,10 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-free": "^5.15.4",
|
"@fortawesome/fontawesome-free": "^5.15.4",
|
||||||
"@shoelace-style/shoelace": "~2.15.1",
|
"@shoelace-style/shoelace": "~2.15.1",
|
||||||
"@webrecorder/wabac": "^2.23.1",
|
"@webrecorder/wabac": "^2.23.2",
|
||||||
"bulma": "^0.9.3",
|
"bulma": "^0.9.3",
|
||||||
"electron-log": "^4.4.1",
|
"electron-log": "^4.4.1",
|
||||||
"electron-updater": "^6.3.9",
|
"electron-updater": "^6.6.2",
|
||||||
"fetch-ndjson": "^1.1.6",
|
"fetch-ndjson": "^1.1.6",
|
||||||
"flexsearch": "^0.7.31",
|
"flexsearch": "^0.7.31",
|
||||||
"keyword-mark-element": "^0.2.0",
|
"keyword-mark-element": "^0.2.0",
|
||||||
@@ -33,9 +33,8 @@
|
|||||||
"marked": "^4.0.10",
|
"marked": "^4.0.10",
|
||||||
"micromark": "^4.0.1",
|
"micromark": "^4.0.1",
|
||||||
"micromark-extension-gfm-strikethrough": "^2.1.0",
|
"micromark-extension-gfm-strikethrough": "^2.1.0",
|
||||||
"mime-types": "^2.1.32",
|
"mime-types": "^3.0.1",
|
||||||
"minimist": "^1.2.5",
|
"minimist": "^1.2.5",
|
||||||
"node-fetch": "^3.3.0",
|
|
||||||
"pretty-bytes": "^5.6.0",
|
"pretty-bytes": "^5.6.0",
|
||||||
"process": "^0.11.10",
|
"process": "^0.11.10",
|
||||||
"register-service-worker": "^1.7.2",
|
"register-service-worker": "^1.7.2",
|
||||||
@@ -47,11 +46,14 @@
|
|||||||
"@playwright/test": "^1.52.0",
|
"@playwright/test": "^1.52.0",
|
||||||
"@types/flexsearch": "^0.7.3",
|
"@types/flexsearch": "^0.7.3",
|
||||||
"@types/lodash": "^4.17.5",
|
"@types/lodash": "^4.17.5",
|
||||||
|
"@types/mime-types": "^2.1.4",
|
||||||
|
"@types/minimist": "^1.2.5",
|
||||||
|
"@types/node": "^22.15.18",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.12.0",
|
"@typescript-eslint/eslint-plugin": "^6.12.0",
|
||||||
"@typescript-eslint/parser": "^6.12.0",
|
"@typescript-eslint/parser": "^6.12.0",
|
||||||
"copy-webpack-plugin": "^9.0.1",
|
"copy-webpack-plugin": "^9.0.1",
|
||||||
"css-loader": "^6.2.0",
|
"css-loader": "^6.2.0",
|
||||||
"electron": "^36.2.1",
|
"electron": "^36.3.2",
|
||||||
"electron-builder": "^26.0.12",
|
"electron-builder": "^26.0.12",
|
||||||
"electron-notarize": "^1.2.2",
|
"electron-notarize": "^1.2.2",
|
||||||
"eslint": "^8.56.0",
|
"eslint": "^8.56.0",
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ export default defineConfig({
|
|||||||
projects: [
|
projects: [
|
||||||
{
|
{
|
||||||
name: "chrome",
|
name: "chrome",
|
||||||
use: { ...devices['Desktop Chrome'], channel: "chrome" },
|
use: { ...devices["Desktop Chrome"], channel: "chrome" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'firefox',
|
name: "firefox",
|
||||||
use: { ...devices['Desktop Firefox'] },
|
use: { ...devices["Desktop Firefox"] },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'webkit',
|
name: "webkit",
|
||||||
use: { ...devices['Desktop Safari'] },
|
use: { ...devices["Desktop Safari"] },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
webServer: [
|
webServer: [
|
||||||
|
|||||||
@@ -639,13 +639,6 @@ export class ReplayWebApp extends LitElement {
|
|||||||
if (this.pageParams.get("swName")) {
|
if (this.pageParams.get("swName")) {
|
||||||
this.swName = this.pageParams.get("swName") || undefined;
|
this.swName = this.pageParams.get("swName") || undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_APP && this.sourceUrl.startsWith("file://")) {
|
|
||||||
this.loadInfo = {
|
|
||||||
sourceUrl: this.sourceUrl,
|
|
||||||
loadUrl: this.sourceUrl.replace("file://", "file2://"),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7006 - Parameter 'event' implicitly has an 'any' type.
|
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7006 - Parameter 'event' implicitly has an 'any' type.
|
||||||
|
|||||||
+17
-9
@@ -5,12 +5,15 @@ import fasUpload from "@fortawesome/fontawesome-free/svgs/solid/upload.svg";
|
|||||||
import { customElement, property } from "lit/decorators.js";
|
import { customElement, property } from "lit/decorators.js";
|
||||||
|
|
||||||
export interface FileWithPath extends File {
|
export interface FileWithPath extends File {
|
||||||
path: string;
|
path?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare let window: Window & {
|
declare let window: Window & {
|
||||||
electron?: {
|
electron?: {
|
||||||
getPath: (file: File) => string;
|
getPaths: (file: File) => {
|
||||||
|
loadUrl: string;
|
||||||
|
sourceUrl: string;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -94,12 +97,13 @@ export class Chooser extends LitElement {
|
|||||||
|
|
||||||
setFile(file: FileWithPath) {
|
setFile(file: FileWithPath) {
|
||||||
this.file = file;
|
this.file = file;
|
||||||
// file.path only available in electron app
|
if (IS_APP && window.electron?.getPaths) {
|
||||||
if (IS_APP && window.electron?.getPath) {
|
const { loadUrl, sourceUrl } = window.electron.getPaths(this.file);
|
||||||
this.file.path = window.electron.getPath(this.file);
|
this.file.path = loadUrl;
|
||||||
|
this.fileDisplayName = sourceUrl;
|
||||||
|
} else {
|
||||||
|
this.fileDisplayName = "file://" + file.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.fileDisplayName = "file://" + (file.path || file.name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async onChooseNativeFile() {
|
async onChooseNativeFile() {
|
||||||
@@ -149,9 +153,11 @@ export class Chooser extends LitElement {
|
|||||||
|
|
||||||
if (this.file) {
|
if (this.file) {
|
||||||
loadInfo.isFile = true;
|
loadInfo.isFile = true;
|
||||||
// file.path only available in electron app
|
// should only be set in Electron app
|
||||||
if (this.file.path) {
|
if (this.file.path) {
|
||||||
loadInfo.loadUrl = "file2://" + this.file.path;
|
loadInfo.loadUrl = this.file.path;
|
||||||
|
loadInfo.sourceUrl = this.fileDisplayName;
|
||||||
|
loadInfo.name = this.file.name;
|
||||||
loadInfo.noCache = true;
|
loadInfo.noCache = true;
|
||||||
} else if (this.fileHandle) {
|
} else if (this.fileHandle) {
|
||||||
loadInfo.loadUrl = this.fileDisplayName;
|
loadInfo.loadUrl = this.fileDisplayName;
|
||||||
@@ -163,8 +169,10 @@ export class Chooser extends LitElement {
|
|||||||
loadInfo.noCache = false;
|
loadInfo.noCache = false;
|
||||||
}
|
}
|
||||||
loadInfo.size = this.file.size;
|
loadInfo.size = this.file.size;
|
||||||
|
if (!loadInfo.name) {
|
||||||
loadInfo.name = this.fileDisplayName;
|
loadInfo.name = this.fileDisplayName;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CustomEvent("load-start", {
|
new CustomEvent("load-start", {
|
||||||
|
|||||||
+25
-3
@@ -3,12 +3,34 @@
|
|||||||
import { CollectionLoader } from "@webrecorder/wabac/swlib";
|
import { CollectionLoader } from "@webrecorder/wabac/swlib";
|
||||||
import { type IpcRendererEvent } from "electron";
|
import { type IpcRendererEvent } from "electron";
|
||||||
|
|
||||||
const { ipcRenderer, contextBridge, webUtils } = require("electron");
|
import { sep as pathSep } from "node:path";
|
||||||
|
|
||||||
|
import { ipcRenderer, contextBridge, webUtils } from "electron";
|
||||||
|
|
||||||
|
const FILE_SCHEME = "file://";
|
||||||
|
const CUSTOM_FILE_SCHEME = "file2://";
|
||||||
|
|
||||||
|
function rewriteLoadUrl(loadUrl: string) {
|
||||||
|
if (pathSep !== "/") {
|
||||||
|
// for windows, will replace such that C:\path\to\file becomes C//path/to/file
|
||||||
|
loadUrl = loadUrl.replaceAll(pathSep, "/").replace(":", "/");
|
||||||
|
}
|
||||||
|
return CUSTOM_FILE_SCHEME + loadUrl;
|
||||||
|
}
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld("electron", {
|
contextBridge.exposeInMainWorld("electron", {
|
||||||
IS_APP: true,
|
IS_APP: true,
|
||||||
getPath(file: File) {
|
getPaths(file: File) {
|
||||||
return webUtils.getPathForFile(file);
|
const url = webUtils.getPathForFile(file);
|
||||||
|
const sourceUrl = FILE_SCHEME + url;
|
||||||
|
const loadUrl = rewriteLoadUrl(url);
|
||||||
|
return { loadUrl, sourceUrl };
|
||||||
|
},
|
||||||
|
getFileLoadUrl(sourceUrl: string) {
|
||||||
|
if (!sourceUrl.startsWith(FILE_SCHEME)) {
|
||||||
|
return sourceUrl;
|
||||||
|
}
|
||||||
|
return rewriteLoadUrl(sourceUrl.slice(FILE_SCHEME.length));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+113
-182
@@ -1,8 +1,5 @@
|
|||||||
/* eslint-env node */
|
/* eslint-env node */
|
||||||
|
|
||||||
import fetch from "node-fetch";
|
|
||||||
import { Headers } from "node-fetch";
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
app,
|
app,
|
||||||
session,
|
session,
|
||||||
@@ -16,21 +13,20 @@ import {
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
|
|
||||||
import { ArchiveResponse, Rewriter } from "@webrecorder/wabac";
|
import { ArchiveRequest, ArchiveResponse, Rewriter } from "@webrecorder/wabac";
|
||||||
|
|
||||||
import { PassThrough, Readable } from "stream";
|
import { Readable } from "stream";
|
||||||
|
|
||||||
import { autoUpdater } from "electron-updater";
|
import { autoUpdater } from "electron-updater";
|
||||||
import log from "electron-log";
|
import log from "electron-log";
|
||||||
|
|
||||||
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7016 - Could not find a declaration file for module 'mime-types'. 'node_modules/mime-types/index.js' implicitly has an 'any' type.
|
|
||||||
import mime from "mime-types";
|
import mime from "mime-types";
|
||||||
import url from "url";
|
import url from "url";
|
||||||
|
|
||||||
// @ts-expect-error - TS2322 - Type 'typeof Headers' is not assignable to type '{ new (init?: HeadersInit | undefined): Headers; prototype: Headers; }'.
|
import minimist from "minimist";
|
||||||
global.Headers = Headers;
|
|
||||||
// @ts-expect-error - TS2322 - Type '(url: RequestInfo, init?: RequestInit | undefined) => Promise<Response>' is not assignable to type '(input: RequestInfo, init?: RequestInit | undefined) => Promise<Response>'.
|
//global.Headers = Headers;
|
||||||
global.fetch = fetch;
|
//global.fetch = fetch;
|
||||||
|
|
||||||
const STATIC_PREFIX = "http://localhost:5471/";
|
const STATIC_PREFIX = "http://localhost:5471/";
|
||||||
|
|
||||||
@@ -95,7 +91,7 @@ class ElectronReplayApp {
|
|||||||
);
|
);
|
||||||
app.quit();
|
app.quit();
|
||||||
} else {
|
} else {
|
||||||
app.on("second-instance", (event, commandLine /*, workingDir*/) => {
|
app.on("second-instance", (_, commandLine) => {
|
||||||
// Just create a new window in case of second instance request
|
// Just create a new window in case of second instance request
|
||||||
this.createMainWindow(commandLine);
|
this.createMainWindow(commandLine);
|
||||||
});
|
});
|
||||||
@@ -147,9 +143,7 @@ class ElectronReplayApp {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: Fix this the next time the file is edited.
|
void app.whenReady().then(() => this.onAppReady());
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
||||||
app.whenReady().then(() => this.onAppReady());
|
|
||||||
|
|
||||||
// Quit when all windows are closed.
|
// Quit when all windows are closed.
|
||||||
app.on("window-all-closed", function () {
|
app.on("window-all-closed", function () {
|
||||||
@@ -164,9 +158,7 @@ class ElectronReplayApp {
|
|||||||
autoUpdater.logger = log;
|
autoUpdater.logger = log;
|
||||||
// @ts-expect-error - TS2339 - Property 'transports' does not exist on type 'Logger'.
|
// @ts-expect-error - TS2339 - Property 'transports' does not exist on type 'Logger'.
|
||||||
autoUpdater.logger.transports.file.level = "info";
|
autoUpdater.logger.transports.file.level = "info";
|
||||||
// TODO: Fix this the next time the file is edited.
|
void autoUpdater.checkForUpdatesAndNotify();
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
||||||
autoUpdater.checkForUpdatesAndNotify();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onAppReady() {
|
onAppReady() {
|
||||||
@@ -178,17 +170,13 @@ class ElectronReplayApp {
|
|||||||
contents.setWindowOpenHandler(({ url }) => {
|
contents.setWindowOpenHandler(({ url }) => {
|
||||||
// load docs in native browser for now
|
// load docs in native browser for now
|
||||||
if (url === STATIC_PREFIX + "docs") {
|
if (url === STATIC_PREFIX + "docs") {
|
||||||
// TODO: Fix this the next time the file is edited.
|
void shell.openExternal("https://replayweb.page/docs/");
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
||||||
shell.openExternal("https://replayweb.page/docs/");
|
|
||||||
return { action: "deny" };
|
return { action: "deny" };
|
||||||
}
|
}
|
||||||
|
|
||||||
// load external URLs in native browser
|
// load external URLs in native browser
|
||||||
if (!url.startsWith(STATIC_PREFIX)) {
|
if (!url.startsWith(STATIC_PREFIX)) {
|
||||||
// TODO: Fix this the next time the file is edited.
|
void shell.openExternal(url);
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
||||||
shell.openExternal(url);
|
|
||||||
return { action: "deny" };
|
return { action: "deny" };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,16 +186,12 @@ class ElectronReplayApp {
|
|||||||
|
|
||||||
const sesh = session.defaultSession;
|
const sesh = session.defaultSession;
|
||||||
|
|
||||||
// TODO: Fix this the next time the file is edited.
|
sesh.protocol.handle("http", async (request: Request) =>
|
||||||
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
this.doIntercept(request),
|
||||||
sesh.protocol.interceptStreamProtocol("http", (request, callback) =>
|
|
||||||
this.doIntercept(request, callback),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: Fix this the next time the file is edited.
|
protocol.handle(FILE_PROTO, async (request: Request) =>
|
||||||
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
this.doHandleFile(request),
|
||||||
protocol.registerStreamProtocol(FILE_PROTO, (request, callback) =>
|
|
||||||
this.doHandleFile(request, callback),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
this.origUA = sesh.getUserAgent();
|
this.origUA = sesh.getUserAgent();
|
||||||
@@ -215,69 +199,49 @@ class ElectronReplayApp {
|
|||||||
this.mainWindow = this.createMainWindow(process.argv);
|
this.mainWindow = this.createMainWindow(process.argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7006 - Parameter 'request' implicitly has an 'any' type. | TS7006 - Parameter 'callback' implicitly has an 'any' type.
|
async doHandleFile(request: Request): Promise<Response> {
|
||||||
async doHandleFile(request, callback) {
|
|
||||||
//const parsedUrl = new URL(request.url);
|
//const parsedUrl = new URL(request.url);
|
||||||
//const filename = parsedUrl.searchParams.get("filename");
|
//const filename = parsedUrl.searchParams.get("filename");
|
||||||
|
|
||||||
if (request.url === FILE_PROTO + "://localhost") {
|
if (request.url === FILE_PROTO + "://localhost") {
|
||||||
callback({ statusCode: 200, data: null });
|
return new Response("", { status: 200 });
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Fix this the next time the file is edited.
|
let urlStr = request.url.replace(FILE_PROTO, "file");
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
if (path.sep !== "/") {
|
||||||
const filename = url.fileURLToPath(request.url.replace(FILE_PROTO, "file"));
|
urlStr = urlStr.replace(/(\/\/\w)(\/\/)/, "$1:/");
|
||||||
|
urlStr = urlStr.replaceAll("/", path.sep);
|
||||||
|
}
|
||||||
|
|
||||||
const headers = { "Content-Type": "application/octet-stream" };
|
const filename = url.fileURLToPath(urlStr);
|
||||||
// TODO: Fix this the next time the file is edited.
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
const headers = new Headers({ "Content-Type": "application/octet-stream" });
|
||||||
const reqHeaders = new Headers(request.headers);
|
const reqHeaders = new Headers(request.headers);
|
||||||
|
|
||||||
if (filename) {
|
if (filename) {
|
||||||
const stat = await fs.promises.lstat(filename);
|
const stat = await fs.promises.lstat(filename);
|
||||||
|
|
||||||
if (!stat.isFile()) {
|
if (!stat.isFile()) {
|
||||||
return this.notFound(filename, callback);
|
return this.notFound(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
const size = stat.size;
|
const size = stat.size;
|
||||||
|
|
||||||
const { statusCode, start, end } = this.parseRange(
|
const { status, start, end } = this.parseRange(reqHeaders, headers, size);
|
||||||
reqHeaders,
|
|
||||||
headers,
|
|
||||||
size,
|
|
||||||
);
|
|
||||||
|
|
||||||
const data =
|
const data =
|
||||||
request.method === "HEAD"
|
request.method === "HEAD"
|
||||||
? null
|
? null
|
||||||
: fs.createReadStream(filename, { start, end });
|
: Readable.toWeb(fs.createReadStream(filename, { start, end }));
|
||||||
|
|
||||||
callback({ statusCode, headers, data });
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
|
||||||
return;
|
return new Response(data as any, { status, headers });
|
||||||
} else {
|
} else {
|
||||||
return this.notFound("No Resource Specified", callback);
|
return this.notFound("No Resource Specified");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7006 - Parameter 'data' implicitly has an 'any' type.
|
async doIntercept(request: Request): Promise<Response> {
|
||||||
_bufferToStream(data) {
|
|
||||||
const rv = new PassThrough();
|
|
||||||
rv.push(data);
|
|
||||||
rv.push(null);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
async doIntercept(
|
|
||||||
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7006 - Parameter 'request' implicitly has an 'any' type.
|
|
||||||
request,
|
|
||||||
callback: (response: {
|
|
||||||
statusCode: number;
|
|
||||||
headers: Record<string, string>;
|
|
||||||
data: fs.ReadStream;
|
|
||||||
}) => void,
|
|
||||||
) {
|
|
||||||
console.log(`${request.method} ${request.url} from ${request.referrer}`);
|
console.log(`${request.method} ${request.url} from ${request.referrer}`);
|
||||||
|
|
||||||
// if local server
|
// if local server
|
||||||
@@ -289,8 +253,8 @@ class ElectronReplayApp {
|
|||||||
this.proxyColl = m[1];
|
this.proxyColl = m[1];
|
||||||
this.proxyTS = m[2];
|
this.proxyTS = m[2];
|
||||||
|
|
||||||
request.url = m[3];
|
//request.url = m[3];
|
||||||
return await this.resolveArchiveResponse(request, callback);
|
return await this.resolveArchiveResponse(request, m[3]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// try serve static file from app dir
|
// try serve static file from app dir
|
||||||
@@ -303,8 +267,6 @@ class ElectronReplayApp {
|
|||||||
filename = "docs/index.html";
|
filename = "docs/index.html";
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Fix this the next time the file is edited.
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
||||||
let ext = path.extname(filename);
|
let ext = path.extname(filename);
|
||||||
if (!ext) {
|
if (!ext) {
|
||||||
ext = ".html";
|
ext = ".html";
|
||||||
@@ -314,103 +276,92 @@ class ElectronReplayApp {
|
|||||||
const mimeType = mime.contentType(ext);
|
const mimeType = mime.contentType(ext);
|
||||||
|
|
||||||
if (mimeType) {
|
if (mimeType) {
|
||||||
// TODO: Fix this the next time the file is edited.
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
||||||
const fullPath = path.join(this.staticContentPath, filename);
|
const fullPath = path.join(this.staticContentPath, filename);
|
||||||
|
|
||||||
console.log("fullPath: " + fullPath);
|
console.log("fullPath: " + fullPath);
|
||||||
|
|
||||||
const data = fs.createReadStream(fullPath);
|
const data = fs.createReadStream(fullPath);
|
||||||
|
|
||||||
return callback({
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
|
||||||
statusCode: 200,
|
return new Response(Readable.toWeb(data) as any, {
|
||||||
headers: { "content-type": mimeType },
|
headers: { "content-type": mimeType },
|
||||||
data,
|
status: 200,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.notFound(request.url, callback);
|
return this.notFound(request.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
// possible 'live leak' attempt, return archived version, if any
|
// possible 'live leak' attempt, return archived version, if any
|
||||||
if (request.referrer?.startsWith(REPLAY_PREFIX)) {
|
if (request.referrer.startsWith(REPLAY_PREFIX)) {
|
||||||
return await this.resolveArchiveResponse(request, callback);
|
return await this.resolveArchiveResponse(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.proxyLive(request, callback);
|
return await this.proxyLive(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7006 - Parameter 'request' implicitly has an 'any' type. | TS7006 - Parameter 'callback' implicitly has an 'any' type.
|
async proxyLive(request: Request): Promise<Response> {
|
||||||
async proxyLive(request, callback) {
|
|
||||||
let headers = request.headers;
|
let headers = request.headers;
|
||||||
const { method, url, uploadData } = request;
|
const { method, url, body } = request;
|
||||||
|
|
||||||
const body = uploadData
|
// const body = uploadData
|
||||||
? Readable.from(readBody(uploadData, session.defaultSession))
|
// ? Readable.from(readBody(uploadData, session.defaultSession))
|
||||||
: null;
|
// : null;
|
||||||
|
|
||||||
if (this.origUA) {
|
if (this.origUA) {
|
||||||
// pass UA if origUA is set
|
headers = new Headers(headers);
|
||||||
headers["User-Agent"] = this.origUA;
|
headers.set("User-Agent", this.origUA);
|
||||||
}
|
}
|
||||||
|
|
||||||
let response;
|
let response;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// TODO: Fix this the next time the file is edited.
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
||||||
response = await fetch(url, { method, headers, body });
|
response = await fetch(url, { method, headers, body });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn("fetch failed for: " + url);
|
console.warn("fetch failed for: " + url);
|
||||||
callback({ statusCode: 502, headers: {}, data: null });
|
return new Response("", { status: 502 });
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
const data = method === "HEAD" ? null : response.body;
|
const data = method === "HEAD" ? null : response.body;
|
||||||
const statusCode = response.status;
|
const status = response.status;
|
||||||
|
|
||||||
headers = Object.fromEntries(response.headers.entries());
|
return new Response(data, { status, headers: response.headers });
|
||||||
callback({ statusCode, headers, data });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
notFound(url: string) {
|
||||||
*
|
|
||||||
* @param {string} url
|
|
||||||
* @param {(props: {
|
|
||||||
* statusCode: number;
|
|
||||||
* headers: Record<string, string>;
|
|
||||||
* data: unknown;
|
|
||||||
* }) => void} callback
|
|
||||||
*/
|
|
||||||
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7006 - Parameter 'url' implicitly has an 'any' type. | TS7006 - Parameter 'callback' implicitly has an 'any' type.
|
|
||||||
notFound(url, callback) {
|
|
||||||
console.log("not found: " + url);
|
console.log("not found: " + url);
|
||||||
const data = this._bufferToStream(
|
const headers = { "Content-Type": 'text/html; charset="utf-8"' };
|
||||||
|
return new Response(
|
||||||
`Sorry, the url <b>${url}</b> could not be found in this archive.`,
|
`Sorry, the url <b>${url}</b> could not be found in this archive.`,
|
||||||
|
{ status: 404, headers },
|
||||||
);
|
);
|
||||||
callback({
|
|
||||||
statusCode: 404,
|
|
||||||
headers: { "Content-Type": 'text/html; charset="utf-8"' },
|
|
||||||
data,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7006 - Parameter 'request' implicitly has an 'any' type. | TS7006 - Parameter 'callback' implicitly has an 'any' type.
|
async resolveArchiveResponse(
|
||||||
async resolveArchiveResponse(request, callback) {
|
request: Request,
|
||||||
const channel = `req:${new Date().getTime()}:${request.url}`;
|
urlOverride?: string,
|
||||||
|
): Promise<Response> {
|
||||||
|
const url = urlOverride || request.url;
|
||||||
|
const channel = `req:${new Date().getTime()}:${url}`;
|
||||||
|
|
||||||
ipcMain.once(channel, async (event, status, headers, payload) => {
|
let resolve: (r: Response) => void;
|
||||||
const url = request.url;
|
|
||||||
|
|
||||||
|
const p = new Promise<Response>((r) => (resolve = r));
|
||||||
|
ipcMain.once(
|
||||||
|
channel,
|
||||||
|
async (
|
||||||
|
event,
|
||||||
|
status: number,
|
||||||
|
reqHeaders: Record<string, string>,
|
||||||
|
payload,
|
||||||
|
) => {
|
||||||
if (status === 404 && !payload) {
|
if (status === 404 && !payload) {
|
||||||
return this.notFound(url, callback);
|
return this.notFound(url);
|
||||||
} else {
|
} else {
|
||||||
console.log("got response for: " + url);
|
console.log("got response for: " + url);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Fix this the next time the file is edited.
|
let headers = new Headers(reqHeaders);
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
||||||
headers = new Headers(headers);
|
|
||||||
const date = new Date();
|
const date = new Date();
|
||||||
|
|
||||||
let response: ArchiveResponse = new ArchiveResponse({
|
let response: ArchiveResponse = new ArchiveResponse({
|
||||||
@@ -430,16 +381,12 @@ class ElectronReplayApp {
|
|||||||
useBaseRules: true,
|
useBaseRules: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: Fix this the next time the file is edited.
|
const arRequest = new ArchiveRequest(url, request);
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
||||||
request.headers = new Headers(request.headers);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response = await rewriter.rewrite(response, request);
|
response = await rewriter.rewrite(response, arRequest);
|
||||||
|
|
||||||
// TODO: Fix this the next time the file is edited.
|
headers = response.headers;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
||||||
headers = Object.fromEntries(response.headers.entries());
|
|
||||||
|
|
||||||
let data = await response.getBuffer();
|
let data = await response.getBuffer();
|
||||||
if (!data) {
|
if (!data) {
|
||||||
@@ -447,24 +394,21 @@ class ElectronReplayApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (status === 206 || status === 200) {
|
if (status === 206 || status === 200) {
|
||||||
const { statusCode, start, end } = this.parseRange(
|
headers = new Headers(response.headers);
|
||||||
request.headers,
|
const res = this.parseRange(request.headers, headers, data.length);
|
||||||
headers,
|
const { start, end } = res;
|
||||||
data.length,
|
status = res.status;
|
||||||
);
|
|
||||||
if (start !== undefined) {
|
if (start !== undefined) {
|
||||||
data = data.slice(start, end);
|
data = data.slice(start, end);
|
||||||
}
|
}
|
||||||
status = statusCode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = this._bufferToStream(data);
|
resolve(new Response(data, { status, headers }));
|
||||||
|
|
||||||
callback({ statusCode: status, headers, data: result });
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn(e);
|
console.warn(e);
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
if (this.mainWindow) {
|
if (this.mainWindow) {
|
||||||
this.mainWindow.webContents.send(
|
this.mainWindow.webContents.send(
|
||||||
@@ -475,45 +419,39 @@ class ElectronReplayApp {
|
|||||||
channel,
|
channel,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7006 - Parameter 'reqHeaders' implicitly has an 'any' type. | TS7006 - Parameter 'headers' implicitly has an 'any' type. | TS7006 - Parameter 'size' implicitly has an 'any' type.
|
parseRange(reqHeaders: Headers, headers: Headers, size: number) {
|
||||||
parseRange(reqHeaders, headers, size) {
|
let status = 200;
|
||||||
let statusCode = 200;
|
|
||||||
const range = reqHeaders.get("range");
|
const range = reqHeaders.get("range");
|
||||||
|
|
||||||
if (!range) {
|
if (!range) {
|
||||||
if (headers) {
|
headers.set("content-length", "" + size);
|
||||||
headers["Content-Length"] = "" + size;
|
return { status };
|
||||||
}
|
|
||||||
return { statusCode };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const m = range.match(/bytes=([\d]+)-([\d]*)/);
|
const m = range.match(/bytes=([\d]+)-([\d]*)/);
|
||||||
if (!m) {
|
if (!m) {
|
||||||
return { statusCode };
|
return { status };
|
||||||
}
|
}
|
||||||
|
|
||||||
const start = Number(m[1]);
|
const start = Number(m[1]);
|
||||||
const end = m[2] ? Number(m[2]) : size - 1;
|
const end = m[2] ? Number(m[2]) : size - 1;
|
||||||
statusCode = 206;
|
status = 206;
|
||||||
if (headers) {
|
headers.set("content-range", `bytes ${start}-${end}/${size}`);
|
||||||
headers["Content-Range"] = `bytes ${start}-${end}/${size}`;
|
headers.set("content-length", `${end - start + 1}`);
|
||||||
headers["Content-Length"] = `${end - start + 1}`;
|
return { status, start, end };
|
||||||
}
|
|
||||||
return { statusCode, start, end };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7006 - Parameter 'argv' implicitly has an 'any' type.
|
createMainWindow(argv: string[]) {
|
||||||
createMainWindow(argv) {
|
|
||||||
const sourceString = this.getOpenUrl(argv);
|
const sourceString = this.getOpenUrl(argv);
|
||||||
|
|
||||||
// Create the browser window.
|
// Create the browser window.
|
||||||
const theWindow = new BrowserWindow({
|
const theWindow = new BrowserWindow({
|
||||||
width: this.screenSize.width,
|
width: this.screenSize.width,
|
||||||
height: this.screenSize.height,
|
height: this.screenSize.height,
|
||||||
// @ts-expect-error - TS2345 - Argument of type '{ width: any; height: any; isMaximized: boolean; show: false; webPreferences: { plugins: boolean; preload: string; nativeWindowOpen: boolean; contextIsolation: boolean; enableRemoteModule: boolean; sandbox: boolean; nodeIntegration: boolean; }; }' is not assignable to parameter of type 'BrowserWindowConstructorOptions'.
|
|
||||||
isMaximized: true,
|
|
||||||
show: false,
|
show: false,
|
||||||
webPreferences: this.mainWindowWebPreferences,
|
webPreferences: this.mainWindowWebPreferences,
|
||||||
}).once("ready-to-show", () => {
|
}).once("ready-to-show", () => {
|
||||||
@@ -521,9 +459,7 @@ class ElectronReplayApp {
|
|||||||
theWindow.maximize();
|
theWindow.maximize();
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: Fix this the next time the file is edited.
|
void theWindow.loadURL(STATIC_PREFIX + this.mainWindowUrl + sourceString);
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
||||||
theWindow.loadURL(STATIC_PREFIX + this.mainWindowUrl + sourceString);
|
|
||||||
if (process.env.NODE_ENV === "development") {
|
if (process.env.NODE_ENV === "development") {
|
||||||
theWindow.webContents.openDevTools();
|
theWindow.webContents.openDevTools();
|
||||||
}
|
}
|
||||||
@@ -531,15 +467,15 @@ class ElectronReplayApp {
|
|||||||
return theWindow;
|
return theWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7006 - Parameter 'argv' implicitly has an 'any' type.
|
getOpenUrl(argv: string[]) {
|
||||||
getOpenUrl(argv) {
|
const parsed = minimist(argv.slice(process.defaultApp ? 2 : 1));
|
||||||
argv = require("minimist")(argv.slice(process.defaultApp ? 2 : 1));
|
|
||||||
|
|
||||||
const filename =
|
const filename =
|
||||||
this.openNextFile ||
|
this.openNextFile ||
|
||||||
argv.filename ||
|
parsed.filename ||
|
||||||
argv.f ||
|
parsed.f ||
|
||||||
(argv._.length && argv._[0]);
|
(parsed._.length && parsed._[0]);
|
||||||
|
|
||||||
this.openNextFile = null;
|
this.openNextFile = null;
|
||||||
|
|
||||||
let sourceString = "";
|
let sourceString = "";
|
||||||
@@ -551,19 +487,15 @@ class ElectronReplayApp {
|
|||||||
|
|
||||||
const urlParams = new URLSearchParams();
|
const urlParams = new URLSearchParams();
|
||||||
|
|
||||||
const openUrl = argv.url;
|
const openUrl = parsed.url as string | undefined;
|
||||||
|
|
||||||
const openTS = argv.ts || argv.timestamp;
|
const openTS = (parsed.ts || parsed.timestamp) as string | undefined;
|
||||||
|
|
||||||
if (openUrl) {
|
if (openUrl) {
|
||||||
// TODO: Fix this the next time the file is edited.
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
||||||
urlParams.set("url", openUrl);
|
urlParams.set("url", openUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (openTS) {
|
if (openTS) {
|
||||||
// TODO: Fix this the next time the file is edited.
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
||||||
urlParams.set("ts", openTS);
|
urlParams.set("ts", openTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -576,15 +508,14 @@ class ElectronReplayApp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7006 - Parameter 'body' implicitly has an 'any' type. | TS7006 - Parameter 'session' implicitly has an 'any' type.
|
// async function* readBody(body, session) {
|
||||||
async function* readBody(body, session) {
|
// for (const chunk of body) {
|
||||||
for (const chunk of body) {
|
// if (chunk.bytes) {
|
||||||
if (chunk.bytes) {
|
// yield await Promise.resolve(chunk.bytes);
|
||||||
yield await Promise.resolve(chunk.bytes);
|
// } else if (chunk.blobUUID) {
|
||||||
} else if (chunk.blobUUID) {
|
// yield await session.getBlobData(chunk.blobUUID);
|
||||||
yield await session.getBlobData(chunk.blobUUID);
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
export { ElectronReplayApp, STATIC_PREFIX };
|
export { ElectronReplayApp, STATIC_PREFIX };
|
||||||
|
|||||||
+24
-5
@@ -1,11 +1,10 @@
|
|||||||
import { LitElement, html, css, type PropertyValues, nothing } from "lit";
|
import { LitElement, html, css, type PropertyValues, nothing } from "lit";
|
||||||
import { wrapCss } from "./misc";
|
import { IS_APP, wrapCss } from "./misc";
|
||||||
import rwpLogo from "~assets/brand/replaywebpage-icon-color.svg";
|
import rwpLogo from "~assets/brand/replaywebpage-icon-color.svg";
|
||||||
import rwpLogoAnimated from "~assets/brand/replaywebpage-icon-color-animated.svg";
|
import rwpLogoAnimated from "~assets/brand/replaywebpage-icon-color-animated.svg";
|
||||||
|
|
||||||
import prettyBytes from "pretty-bytes";
|
import prettyBytes from "pretty-bytes";
|
||||||
|
|
||||||
import { parseURLSchemeHostPath } from "./pageutils";
|
|
||||||
import { property } from "lit/decorators.js";
|
import { property } from "lit/decorators.js";
|
||||||
import type { LoadInfo } from "./item";
|
import type { LoadInfo } from "./item";
|
||||||
import { ifDefined } from "lit/directives/if-defined.js";
|
import { ifDefined } from "lit/directives/if-defined.js";
|
||||||
@@ -28,6 +27,12 @@ const NO_ANIM_STATES: LoadingState[] = [
|
|||||||
"permission_needed",
|
"permission_needed",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
declare let window: Window & {
|
||||||
|
electron?: {
|
||||||
|
getFileLoadUrl: (sourceUrl: string) => string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
class Loader extends LitElement {
|
class Loader extends LitElement {
|
||||||
@property({ type: String }) sourceUrl?: string;
|
@property({ type: String }) sourceUrl?: string;
|
||||||
@property({ type: Object }) loadInfo: LoadInfo | null = null;
|
@property({ type: Object }) loadInfo: LoadInfo | null = null;
|
||||||
@@ -46,7 +51,7 @@ class Loader extends LitElement {
|
|||||||
@property({ type: String }) extraMsg?: string;
|
@property({ type: String }) extraMsg?: string;
|
||||||
@property({ type: String }) swName?: string;
|
@property({ type: String }) swName?: string;
|
||||||
|
|
||||||
pingInterval: number | NodeJS.Timer = 0;
|
pingInterval: number | NodeJS.Timeout = 0;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- requestPermission() type mismatch
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- requestPermission() type mismatch
|
||||||
fileHandle: any = null;
|
fileHandle: any = null;
|
||||||
noWebWorker = false;
|
noWebWorker = false;
|
||||||
@@ -161,7 +166,8 @@ class Loader extends LitElement {
|
|||||||
|
|
||||||
// custom protocol handlers here...
|
// custom protocol handlers here...
|
||||||
try {
|
try {
|
||||||
const { scheme, host, path } = parseURLSchemeHostPath(sourceUrl!);
|
const url = new URL(sourceUrl!);
|
||||||
|
const scheme = url.protocol.slice(0, -1);
|
||||||
|
|
||||||
switch (scheme) {
|
switch (scheme) {
|
||||||
case "googledrive":
|
case "googledrive":
|
||||||
@@ -174,12 +180,24 @@ class Loader extends LitElement {
|
|||||||
case "s3":
|
case "s3":
|
||||||
source = {
|
source = {
|
||||||
sourceUrl,
|
sourceUrl,
|
||||||
loadUrl: `https://${host}.s3.amazonaws.com${path}`,
|
loadUrl: `https://${url.hostname}.s3.amazonaws.com${url.href.slice(
|
||||||
|
url.origin.length,
|
||||||
|
)}`,
|
||||||
name: this.sourceUrl,
|
name: this.sourceUrl,
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "file":
|
case "file":
|
||||||
|
if (!this.loadInfo && sourceUrl && IS_APP && window.electron) {
|
||||||
|
const loadUrl = window.electron.getFileLoadUrl(sourceUrl);
|
||||||
|
const name = loadUrl.slice(loadUrl.lastIndexOf("/") + 1);
|
||||||
|
source = {
|
||||||
|
sourceUrl,
|
||||||
|
loadUrl,
|
||||||
|
name,
|
||||||
|
noCache: true,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
if (!this.loadInfo && !this.tryFileHandle) {
|
if (!this.loadInfo && !this.tryFileHandle) {
|
||||||
this.state = "errored";
|
this.state = "errored";
|
||||||
this.error = `\
|
this.error = `\
|
||||||
@@ -190,6 +208,7 @@ You can select a file to upload from the main page by clicking the 'Choose File.
|
|||||||
}
|
}
|
||||||
|
|
||||||
source = this.loadInfo;
|
source = this.loadInfo;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "proxy":
|
case "proxy":
|
||||||
|
|||||||
+4
-5
@@ -103,7 +103,7 @@ async function sourceToId(url: string) {
|
|||||||
// simple parse of scheme, host, rest of path
|
// simple parse of scheme, host, rest of path
|
||||||
// not using URL due to different browser behavior
|
// not using URL due to different browser behavior
|
||||||
function parseURLSchemeHostPath(url: string) {
|
function parseURLSchemeHostPath(url: string) {
|
||||||
let inx = url.indexOf("://");
|
let inx = url.indexOf(":");
|
||||||
let hostInx = 0;
|
let hostInx = 0;
|
||||||
let scheme = "";
|
let scheme = "";
|
||||||
let host = "";
|
let host = "";
|
||||||
@@ -111,13 +111,12 @@ function parseURLSchemeHostPath(url: string) {
|
|||||||
|
|
||||||
if (inx >= 0) {
|
if (inx >= 0) {
|
||||||
scheme = url.slice(0, inx);
|
scheme = url.slice(0, inx);
|
||||||
inx += 3;
|
url = url.slice(inx + 1);
|
||||||
} else {
|
inx += 1;
|
||||||
inx++;
|
}
|
||||||
if (url.startsWith("//")) {
|
if (url.startsWith("//")) {
|
||||||
inx += 2;
|
inx += 2;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
hostInx = url.indexOf("/", inx);
|
hostInx = url.indexOf("/", inx);
|
||||||
if (hostInx > 0) {
|
if (hostInx > 0) {
|
||||||
|
|||||||
@@ -57,7 +57,6 @@ test("same-domain iframe embed is loading", async ({ page }) => {
|
|||||||
const inside = res.frameLocator("iframe").locator("body");
|
const inside = res.frameLocator("iframe").locator("body");
|
||||||
|
|
||||||
await expect(inside).toContainText("Inside iframe");
|
await expect(inside).toContainText("Inside iframe");
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("cross-domain iframe embed is loading", async ({ page }) => {
|
test("cross-domain iframe embed is loading", async ({ page }) => {
|
||||||
@@ -75,7 +74,6 @@ test("cross-domain iframe embed is loading", async ({ page }) => {
|
|||||||
const inside = res.frameLocator("iframe").locator("body");
|
const inside = res.frameLocator("iframe").locator("body");
|
||||||
|
|
||||||
await expect(inside).toContainText("Inside iframe");
|
await expect(inside).toContainText("Inside iframe");
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("sandbox + cross-domain embed is loading", async ({ page }) => {
|
test("sandbox + cross-domain embed is loading", async ({ page }) => {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "./dist/",
|
"outDir": "./dist/",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
|
"lib": ["esnext", "dom", "dom.iterable"],
|
||||||
"target": "es6",
|
"target": "es6",
|
||||||
"moduleResolution": "Bundler",
|
"moduleResolution": "Bundler",
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
|
|||||||
@@ -726,6 +726,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.5.tgz#e6c29b58e66995d57cd170ce3e2a61926d55ee04"
|
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.5.tgz#e6c29b58e66995d57cd170ce3e2a61926d55ee04"
|
||||||
integrity sha512-MBIOHVZqVqgfro1euRDWX7OO0fBVUUMrN6Pwm8LQsz8cWhEpihlvR70ENj3f40j58TNxZaWv2ndSkInykNBBJw==
|
integrity sha512-MBIOHVZqVqgfro1euRDWX7OO0fBVUUMrN6Pwm8LQsz8cWhEpihlvR70ENj3f40j58TNxZaWv2ndSkInykNBBJw==
|
||||||
|
|
||||||
|
"@types/mime-types@^2.1.4":
|
||||||
|
version "2.1.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/mime-types/-/mime-types-2.1.4.tgz#93a1933e24fed4fb9e4adc5963a63efcbb3317a2"
|
||||||
|
integrity sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==
|
||||||
|
|
||||||
"@types/mime@*":
|
"@types/mime@*":
|
||||||
version "3.0.1"
|
version "3.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10"
|
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10"
|
||||||
@@ -736,6 +741,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690"
|
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690"
|
||||||
integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==
|
integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==
|
||||||
|
|
||||||
|
"@types/minimist@^1.2.5":
|
||||||
|
version "1.2.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.5.tgz#ec10755e871497bcd83efe927e43ec46e8c0747e"
|
||||||
|
integrity sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==
|
||||||
|
|
||||||
"@types/ms@*":
|
"@types/ms@*":
|
||||||
version "0.7.31"
|
version "0.7.31"
|
||||||
resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197"
|
resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197"
|
||||||
@@ -753,7 +763,7 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.38.tgz#f8bb07c371ccb1903f3752872c89f44006132947"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.38.tgz#f8bb07c371ccb1903f3752872c89f44006132947"
|
||||||
integrity sha512-5jY9RhV7c0Z4Jy09G+NIDTsCZ5G0L5n+Z+p+Y7t5VJHM30bgwzSjVtlcBxqAj+6L/swIlvtOSzr8rBk/aNyV2g==
|
integrity sha512-5jY9RhV7c0Z4Jy09G+NIDTsCZ5G0L5n+Z+p+Y7t5VJHM30bgwzSjVtlcBxqAj+6L/swIlvtOSzr8rBk/aNyV2g==
|
||||||
|
|
||||||
"@types/node@^22.7.7":
|
"@types/node@^22.15.18", "@types/node@^22.7.7":
|
||||||
version "22.15.18"
|
version "22.15.18"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.15.18.tgz#2f8240f7e932f571c2d45f555ba0b6c3f7a75963"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.15.18.tgz#2f8240f7e932f571c2d45f555ba0b6c3f7a75963"
|
||||||
integrity sha512-v1DKRfUdyW+jJhZNEI1PYy29S2YRxMV5AOO/x/SjKmW0acCIOqmbj6Haf9eHAhsPmrhlHSxEhv/1WszcLWV4cg==
|
integrity sha512-v1DKRfUdyW+jJhZNEI1PYy29S2YRxMV5AOO/x/SjKmW0acCIOqmbj6Haf9eHAhsPmrhlHSxEhv/1WszcLWV4cg==
|
||||||
@@ -1102,10 +1112,10 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-2.0.5.tgz#325db42395cd49fe6c14057f9a900e427df8810e"
|
resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-2.0.5.tgz#325db42395cd49fe6c14057f9a900e427df8810e"
|
||||||
integrity sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==
|
integrity sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==
|
||||||
|
|
||||||
"@webrecorder/wabac@^2.23.1":
|
"@webrecorder/wabac@^2.23.2":
|
||||||
version "2.23.1"
|
version "2.23.2"
|
||||||
resolved "https://registry.yarnpkg.com/@webrecorder/wabac/-/wabac-2.23.1.tgz#bf51615c82954a09db19b30443b9d386ba1af5ae"
|
resolved "https://registry.yarnpkg.com/@webrecorder/wabac/-/wabac-2.23.2.tgz#be6447bffe90d45d4a7fbee894f7a544a4a281e9"
|
||||||
integrity sha512-9qNjelK5TvLa8adMdOPAsUC29TTRA/6vHmjhRmsi4PSKhCN/1F0YpZYL6H0LJHr2+WpE/coXMxB0nqhJKOhLLw==
|
integrity sha512-hYtr62PvHqE9FHhzPFwi9prA6bqnbX/SXYB4IcKrCvENgB1EqB71/bEBUqZ4GbMnX2pI4YNJfpA7tXF+n1Azgw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@peculiar/asn1-ecc" "^2.3.4"
|
"@peculiar/asn1-ecc" "^2.3.4"
|
||||||
"@peculiar/asn1-schema" "^2.3.3"
|
"@peculiar/asn1-schema" "^2.3.3"
|
||||||
@@ -1587,14 +1597,6 @@ buffer@^6.0.3:
|
|||||||
base64-js "^1.3.1"
|
base64-js "^1.3.1"
|
||||||
ieee754 "^1.2.1"
|
ieee754 "^1.2.1"
|
||||||
|
|
||||||
builder-util-runtime@9.2.10:
|
|
||||||
version "9.2.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-9.2.10.tgz#a0f7d9e214158402e78b74a745c8d9f870c604bc"
|
|
||||||
integrity sha512-6p/gfG1RJSQeIbz8TK5aPNkoztgY1q5TgmGFMAXcY8itsGW6Y2ld1ALsZ5UJn8rog7hKF3zHx5iQbNQ8uLcRlw==
|
|
||||||
dependencies:
|
|
||||||
debug "^4.3.4"
|
|
||||||
sax "^1.2.4"
|
|
||||||
|
|
||||||
builder-util-runtime@9.3.1:
|
builder-util-runtime@9.3.1:
|
||||||
version "9.3.1"
|
version "9.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-9.3.1.tgz#0daedde0f6d381f2a00a50a407b166fe7dca1a67"
|
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-9.3.1.tgz#0daedde0f6d381f2a00a50a407b166fe7dca1a67"
|
||||||
@@ -2065,11 +2067,6 @@ cssesc@^3.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
|
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
|
||||||
integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
|
integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
|
||||||
|
|
||||||
data-uri-to-buffer@^4.0.0:
|
|
||||||
version "4.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz#b5db46aea50f6176428ac05b73be39a57701a64b"
|
|
||||||
integrity sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==
|
|
||||||
|
|
||||||
debug@2.6.9:
|
debug@2.6.9:
|
||||||
version "2.6.9"
|
version "2.6.9"
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||||
@@ -2360,12 +2357,12 @@ electron-to-chromium@^1.4.668:
|
|||||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.733.tgz#708d51ce01a7ed3b401d5ced85e9f5d504fd4217"
|
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.733.tgz#708d51ce01a7ed3b401d5ced85e9f5d504fd4217"
|
||||||
integrity sha512-gUI9nhI2iBGF0OaYYLKOaOtliFMl+Bt1rY7VmEjwxOxqoYLub/D9xmduPEhbw2imE6gYkJKhIE5it+KE2ulVxQ==
|
integrity sha512-gUI9nhI2iBGF0OaYYLKOaOtliFMl+Bt1rY7VmEjwxOxqoYLub/D9xmduPEhbw2imE6gYkJKhIE5it+KE2ulVxQ==
|
||||||
|
|
||||||
electron-updater@^6.3.9:
|
electron-updater@^6.6.2:
|
||||||
version "6.3.9"
|
version "6.6.2"
|
||||||
resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-6.3.9.tgz#e1e7f155624c58e6f3760f376c3a584028165ec4"
|
resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-6.6.2.tgz#3e65e044f1a99b00d61e200e24de8e709c69ce99"
|
||||||
integrity sha512-2PJNONi+iBidkoC5D1nzT9XqsE8Q1X28Fn6xRQhO3YX8qRRyJ3mkV4F1aQsuRnYPqq6Hw+E51y27W75WgDoofw==
|
integrity sha512-Cr4GDOkbAUqRHP5/oeOmH/L2Bn6+FQPxVLZtPbcmKZC63a1F3uu5EefYOssgZXG3u/zBlubbJ5PJdITdMVggbw==
|
||||||
dependencies:
|
dependencies:
|
||||||
builder-util-runtime "9.2.10"
|
builder-util-runtime "9.3.1"
|
||||||
fs-extra "^10.1.0"
|
fs-extra "^10.1.0"
|
||||||
js-yaml "^4.1.0"
|
js-yaml "^4.1.0"
|
||||||
lazy-val "^1.0.5"
|
lazy-val "^1.0.5"
|
||||||
@@ -2374,10 +2371,10 @@ electron-updater@^6.3.9:
|
|||||||
semver "^7.6.3"
|
semver "^7.6.3"
|
||||||
tiny-typed-emitter "^2.1.0"
|
tiny-typed-emitter "^2.1.0"
|
||||||
|
|
||||||
electron@^36.2.1:
|
electron@^36.3.2:
|
||||||
version "36.2.1"
|
version "36.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/electron/-/electron-36.2.1.tgz#7c9d7c6c7076a3ddb7b1c326a851cb92c775b0b1"
|
resolved "https://registry.yarnpkg.com/electron/-/electron-36.3.2.tgz#4a60f95e8d3858d01570c03b58dc2fb2f17ee8b6"
|
||||||
integrity sha512-mm1Y+Ms46xcOTA69h8hpqfX392HfV4lga9aEkYkd/Syx1JBStvcACOIouCgGrnZpxNZPVS1jM8NTcMkNjuK6BQ==
|
integrity sha512-v0/j7n22CL3OYv9BIhq6JJz2+e1HmY9H4bjTk8/WzVT9JwVX/T/21YNdR7xuQ6XDSEo9gP5JnqmjOamE+CUY8Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@electron/get" "^2.0.0"
|
"@electron/get" "^2.0.0"
|
||||||
"@types/node" "^22.7.7"
|
"@types/node" "^22.7.7"
|
||||||
@@ -2807,14 +2804,6 @@ fd-slicer@~1.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
pend "~1.2.0"
|
pend "~1.2.0"
|
||||||
|
|
||||||
fetch-blob@^3.1.2, fetch-blob@^3.1.4:
|
|
||||||
version "3.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.2.0.tgz#f09b8d4bbd45adc6f0c20b7e787e793e309dcce9"
|
|
||||||
integrity sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==
|
|
||||||
dependencies:
|
|
||||||
node-domexception "^1.0.0"
|
|
||||||
web-streams-polyfill "^3.0.3"
|
|
||||||
|
|
||||||
fetch-ndjson@^1.1.6:
|
fetch-ndjson@^1.1.6:
|
||||||
version "1.1.6"
|
version "1.1.6"
|
||||||
resolved "https://registry.yarnpkg.com/fetch-ndjson/-/fetch-ndjson-1.1.6.tgz#541eb930a48cf5311093b8aa71bece0ed9713e7f"
|
resolved "https://registry.yarnpkg.com/fetch-ndjson/-/fetch-ndjson-1.1.6.tgz#541eb930a48cf5311093b8aa71bece0ed9713e7f"
|
||||||
@@ -2915,13 +2904,6 @@ form-data@^4.0.0:
|
|||||||
combined-stream "^1.0.8"
|
combined-stream "^1.0.8"
|
||||||
mime-types "^2.1.12"
|
mime-types "^2.1.12"
|
||||||
|
|
||||||
formdata-polyfill@^4.0.10:
|
|
||||||
version "4.0.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423"
|
|
||||||
integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==
|
|
||||||
dependencies:
|
|
||||||
fetch-blob "^3.1.2"
|
|
||||||
|
|
||||||
forwarded@0.2.0:
|
forwarded@0.2.0:
|
||||||
version "0.2.0"
|
version "0.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
|
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
|
||||||
@@ -4306,13 +4288,25 @@ mime-db@1.52.0:
|
|||||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.49.0.tgz#f3dfde60c99e9cf3bc9701d687778f537001cbed"
|
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.49.0.tgz#f3dfde60c99e9cf3bc9701d687778f537001cbed"
|
||||||
integrity sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==
|
integrity sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==
|
||||||
|
|
||||||
mime-types@^2.1.12, mime-types@^2.1.27, mime-types@^2.1.31, mime-types@^2.1.32, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34:
|
mime-db@^1.54.0:
|
||||||
|
version "1.54.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.54.0.tgz#cddb3ee4f9c64530dff640236661d42cb6a314f5"
|
||||||
|
integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==
|
||||||
|
|
||||||
|
mime-types@^2.1.12, mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34:
|
||||||
version "2.1.35"
|
version "2.1.35"
|
||||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
|
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
|
||||||
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
|
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
|
||||||
dependencies:
|
dependencies:
|
||||||
mime-db "1.52.0"
|
mime-db "1.52.0"
|
||||||
|
|
||||||
|
mime-types@^3.0.1:
|
||||||
|
version "3.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-3.0.1.tgz#b1d94d6997a9b32fd69ebaed0db73de8acb519ce"
|
||||||
|
integrity sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==
|
||||||
|
dependencies:
|
||||||
|
mime-db "^1.54.0"
|
||||||
|
|
||||||
mime@1.6.0, mime@^1.6.0:
|
mime@1.6.0, mime@^1.6.0:
|
||||||
version "1.6.0"
|
version "1.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
|
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
|
||||||
@@ -4560,20 +4554,6 @@ node-api-version@^0.2.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
semver "^7.3.5"
|
semver "^7.3.5"
|
||||||
|
|
||||||
node-domexception@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5"
|
|
||||||
integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==
|
|
||||||
|
|
||||||
node-fetch@^3.3.0:
|
|
||||||
version "3.3.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.3.0.tgz#37e71db4ecc257057af828d523a7243d651d91e4"
|
|
||||||
integrity sha512-BKwRP/O0UvoMKp7GNdwPlObhYGB5DQqwhEDQlNKuoqwVYSxkSZCSbHjnFFmUEtwSKRPU4kNK8PbDYYitwaE3QA==
|
|
||||||
dependencies:
|
|
||||||
data-uri-to-buffer "^4.0.0"
|
|
||||||
fetch-blob "^3.1.4"
|
|
||||||
formdata-polyfill "^4.0.10"
|
|
||||||
|
|
||||||
node-forge@^1:
|
node-forge@^1:
|
||||||
version "1.3.1"
|
version "1.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3"
|
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3"
|
||||||
@@ -6460,11 +6440,6 @@ web-component-analyzer@^2.0.0, web-component-analyzer@^2.0.0-next.5:
|
|||||||
typescript "~5.2.0"
|
typescript "~5.2.0"
|
||||||
yargs "^17.7.2"
|
yargs "^17.7.2"
|
||||||
|
|
||||||
web-streams-polyfill@^3.0.3:
|
|
||||||
version "3.2.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6"
|
|
||||||
integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==
|
|
||||||
|
|
||||||
webpack-cli@^5.1.4:
|
webpack-cli@^5.1.4:
|
||||||
version "5.1.4"
|
version "5.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-5.1.4.tgz#c8e046ba7eaae4911d7e71e2b25b776fcc35759b"
|
resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-5.1.4.tgz#c8e046ba7eaae4911d7e71e2b25b776fcc35759b"
|
||||||
|
|||||||
Reference in New Issue
Block a user