@lolyjs/core 0.3.0-alpha.4 → 0.3.0-alpha.6
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/README.md +74 -0
- package/dist/cli.cjs +672 -162
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.mjs +672 -162
- package/dist/cli.mjs.map +1 -1
- package/dist/index.cjs +867 -355
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +26 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.mjs +867 -355
- package/dist/index.mjs.map +1 -1
- package/dist/react/components.cjs +122 -5
- package/dist/react/components.cjs.map +1 -1
- package/dist/react/components.d.mts +18 -4
- package/dist/react/components.d.ts +18 -4
- package/dist/react/components.mjs +123 -6
- package/dist/react/components.mjs.map +1 -1
- package/dist/runtime.cjs +118 -116
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.mjs +118 -116
- package/dist/runtime.mjs.map +1 -1
- package/package.json +3 -1
package/dist/cli.mjs
CHANGED
|
@@ -9957,7 +9957,7 @@ var require_built3 = __commonJS({
|
|
|
9957
9957
|
});
|
|
9958
9958
|
|
|
9959
9959
|
// modules/cli/index.ts
|
|
9960
|
-
import
|
|
9960
|
+
import path36 from "path";
|
|
9961
9961
|
import process2 from "process";
|
|
9962
9962
|
|
|
9963
9963
|
// modules/build/index.ts
|
|
@@ -11746,6 +11746,7 @@ async function processRewrites(urlPath, compiledRewrites, req) {
|
|
|
11746
11746
|
const normalizedPath = urlPath.replace(/\/$/, "") || "/";
|
|
11747
11747
|
if (normalizedPath.startsWith("/static/") || // Static assets (client.js, client.css, etc.)
|
|
11748
11748
|
normalizedPath.startsWith("/__fw/") || // Framework internal routes (hot reload, etc.)
|
|
11749
|
+
normalizedPath.startsWith("/_loly/") || // Framework internal routes (image optimization, etc.)
|
|
11749
11750
|
normalizedPath === "/favicon.ico" || // Favicon
|
|
11750
11751
|
normalizedPath.startsWith("/wss/")) {
|
|
11751
11752
|
if (process.env.NODE_ENV === "development") {
|
|
@@ -12950,7 +12951,7 @@ function createDocumentTree(options) {
|
|
|
12950
12951
|
}),
|
|
12951
12952
|
...extraMetaTags,
|
|
12952
12953
|
...linkTags,
|
|
12953
|
-
...entrypointFiles.length > 0 ? entrypointFiles.
|
|
12954
|
+
...entrypointFiles.length > 0 ? entrypointFiles.map(
|
|
12954
12955
|
(file) => React.createElement("link", {
|
|
12955
12956
|
key: `preload-${file}`,
|
|
12956
12957
|
rel: "preload",
|
|
@@ -12971,6 +12972,13 @@ function createDocumentTree(options) {
|
|
|
12971
12972
|
href: faviconPath,
|
|
12972
12973
|
type: faviconType || (faviconPath.endsWith(".ico") ? "image/x-icon" : "image/png")
|
|
12973
12974
|
}),
|
|
12975
|
+
// Preload CSS para evitar bloqueo de renderizado
|
|
12976
|
+
React.createElement("link", {
|
|
12977
|
+
key: "preload-css",
|
|
12978
|
+
rel: "preload",
|
|
12979
|
+
href: clientCssPath,
|
|
12980
|
+
as: "style"
|
|
12981
|
+
}),
|
|
12974
12982
|
React.createElement("link", {
|
|
12975
12983
|
rel: "stylesheet",
|
|
12976
12984
|
href: clientCssPath
|
|
@@ -13172,12 +13180,12 @@ var DEFAULT_IGNORED_PATHS = [
|
|
|
13172
13180
|
/^\/sockjs-node/
|
|
13173
13181
|
// Hot reload websocket
|
|
13174
13182
|
];
|
|
13175
|
-
function shouldIgnorePath(
|
|
13183
|
+
function shouldIgnorePath(path37, ignoredPaths) {
|
|
13176
13184
|
return ignoredPaths.some((pattern) => {
|
|
13177
13185
|
if (typeof pattern === "string") {
|
|
13178
|
-
return
|
|
13186
|
+
return path37 === pattern || path37.startsWith(pattern);
|
|
13179
13187
|
}
|
|
13180
|
-
return pattern.test(
|
|
13188
|
+
return pattern.test(path37);
|
|
13181
13189
|
});
|
|
13182
13190
|
}
|
|
13183
13191
|
function requestLoggerMiddleware(options = {}) {
|
|
@@ -15140,7 +15148,20 @@ var DEFAULT_CONFIG2 = {
|
|
|
15140
15148
|
ssr: true,
|
|
15141
15149
|
ssg: true
|
|
15142
15150
|
},
|
|
15143
|
-
plugins: []
|
|
15151
|
+
plugins: [],
|
|
15152
|
+
images: {
|
|
15153
|
+
remotePatterns: [],
|
|
15154
|
+
domains: [],
|
|
15155
|
+
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
|
|
15156
|
+
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
|
|
15157
|
+
formats: ["image/webp", "image/avif"],
|
|
15158
|
+
quality: 75,
|
|
15159
|
+
minimumCacheTTL: 60,
|
|
15160
|
+
dangerouslyAllowSVG: false,
|
|
15161
|
+
contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;",
|
|
15162
|
+
maxWidth: 3840,
|
|
15163
|
+
maxHeight: 3840
|
|
15164
|
+
}
|
|
15144
15165
|
};
|
|
15145
15166
|
function deepMerge(target, source) {
|
|
15146
15167
|
const result = { ...target };
|
|
@@ -15257,6 +15278,53 @@ function validateConfig(config, projectRoot) {
|
|
|
15257
15278
|
if (typeof config.rendering.ssg !== "boolean") {
|
|
15258
15279
|
errors.push("config.rendering.ssg must be a boolean");
|
|
15259
15280
|
}
|
|
15281
|
+
if (config.images) {
|
|
15282
|
+
if (config.images.quality !== void 0) {
|
|
15283
|
+
if (typeof config.images.quality !== "number" || config.images.quality < 1 || config.images.quality > 100) {
|
|
15284
|
+
errors.push("config.images.quality must be a number between 1 and 100");
|
|
15285
|
+
}
|
|
15286
|
+
}
|
|
15287
|
+
if (config.images.minimumCacheTTL !== void 0) {
|
|
15288
|
+
if (typeof config.images.minimumCacheTTL !== "number" || config.images.minimumCacheTTL < 0) {
|
|
15289
|
+
errors.push("config.images.minimumCacheTTL must be a non-negative number");
|
|
15290
|
+
}
|
|
15291
|
+
}
|
|
15292
|
+
if (config.images.deviceSizes) {
|
|
15293
|
+
if (!Array.isArray(config.images.deviceSizes) || config.images.deviceSizes.some((s) => typeof s !== "number" || s <= 0)) {
|
|
15294
|
+
errors.push("config.images.deviceSizes must be an array of positive numbers");
|
|
15295
|
+
}
|
|
15296
|
+
}
|
|
15297
|
+
if (config.images.imageSizes) {
|
|
15298
|
+
if (!Array.isArray(config.images.imageSizes) || config.images.imageSizes.some((s) => typeof s !== "number" || s <= 0)) {
|
|
15299
|
+
errors.push("config.images.imageSizes must be an array of positive numbers");
|
|
15300
|
+
}
|
|
15301
|
+
}
|
|
15302
|
+
if (config.images.formats) {
|
|
15303
|
+
const validFormats = ["image/webp", "image/avif"];
|
|
15304
|
+
if (!Array.isArray(config.images.formats) || config.images.formats.some((f) => !validFormats.includes(f))) {
|
|
15305
|
+
errors.push(`config.images.formats must be an array containing only: ${validFormats.join(", ")}`);
|
|
15306
|
+
}
|
|
15307
|
+
}
|
|
15308
|
+
if (config.images.remotePatterns) {
|
|
15309
|
+
if (!Array.isArray(config.images.remotePatterns)) {
|
|
15310
|
+
errors.push("config.images.remotePatterns must be an array");
|
|
15311
|
+
} else {
|
|
15312
|
+
config.images.remotePatterns.forEach((pattern, idx) => {
|
|
15313
|
+
if (!pattern.hostname || typeof pattern.hostname !== "string") {
|
|
15314
|
+
errors.push(`config.images.remotePatterns[${idx}].hostname must be a non-empty string`);
|
|
15315
|
+
}
|
|
15316
|
+
if (pattern.protocol && !["http", "https"].includes(pattern.protocol)) {
|
|
15317
|
+
errors.push(`config.images.remotePatterns[${idx}].protocol must be 'http' or 'https'`);
|
|
15318
|
+
}
|
|
15319
|
+
});
|
|
15320
|
+
}
|
|
15321
|
+
}
|
|
15322
|
+
if (config.images.domains) {
|
|
15323
|
+
if (!Array.isArray(config.images.domains) || config.images.domains.some((d) => typeof d !== "string")) {
|
|
15324
|
+
errors.push("config.images.domains must be an array of strings");
|
|
15325
|
+
}
|
|
15326
|
+
}
|
|
15327
|
+
}
|
|
15260
15328
|
if (errors.length > 0) {
|
|
15261
15329
|
const errorMessage = [
|
|
15262
15330
|
"\u274C Configuration validation failed:",
|
|
@@ -15390,8 +15458,8 @@ async function buildApp(options = {}) {
|
|
|
15390
15458
|
}
|
|
15391
15459
|
|
|
15392
15460
|
// src/server.ts
|
|
15393
|
-
import
|
|
15394
|
-
import
|
|
15461
|
+
import fs26 from "fs";
|
|
15462
|
+
import path35 from "path";
|
|
15395
15463
|
|
|
15396
15464
|
// modules/server/setup.ts
|
|
15397
15465
|
import express from "express";
|
|
@@ -15474,7 +15542,7 @@ var ReaddirpStream = class extends Readable {
|
|
|
15474
15542
|
this._directoryFilter = normalizeFilter(opts.directoryFilter);
|
|
15475
15543
|
const statMethod = opts.lstat ? lstat : stat;
|
|
15476
15544
|
if (wantBigintFsStats) {
|
|
15477
|
-
this._stat = (
|
|
15545
|
+
this._stat = (path37) => statMethod(path37, { bigint: true });
|
|
15478
15546
|
} else {
|
|
15479
15547
|
this._stat = statMethod;
|
|
15480
15548
|
}
|
|
@@ -15499,8 +15567,8 @@ var ReaddirpStream = class extends Readable {
|
|
|
15499
15567
|
const par = this.parent;
|
|
15500
15568
|
const fil = par && par.files;
|
|
15501
15569
|
if (fil && fil.length > 0) {
|
|
15502
|
-
const { path:
|
|
15503
|
-
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent,
|
|
15570
|
+
const { path: path37, depth } = par;
|
|
15571
|
+
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path37));
|
|
15504
15572
|
const awaited = await Promise.all(slice);
|
|
15505
15573
|
for (const entry of awaited) {
|
|
15506
15574
|
if (!entry)
|
|
@@ -15540,20 +15608,20 @@ var ReaddirpStream = class extends Readable {
|
|
|
15540
15608
|
this.reading = false;
|
|
15541
15609
|
}
|
|
15542
15610
|
}
|
|
15543
|
-
async _exploreDir(
|
|
15611
|
+
async _exploreDir(path37, depth) {
|
|
15544
15612
|
let files;
|
|
15545
15613
|
try {
|
|
15546
|
-
files = await readdir(
|
|
15614
|
+
files = await readdir(path37, this._rdOptions);
|
|
15547
15615
|
} catch (error) {
|
|
15548
15616
|
this._onError(error);
|
|
15549
15617
|
}
|
|
15550
|
-
return { files, depth, path:
|
|
15618
|
+
return { files, depth, path: path37 };
|
|
15551
15619
|
}
|
|
15552
|
-
async _formatEntry(dirent,
|
|
15620
|
+
async _formatEntry(dirent, path37) {
|
|
15553
15621
|
let entry;
|
|
15554
15622
|
const basename3 = this._isDirent ? dirent.name : dirent;
|
|
15555
15623
|
try {
|
|
15556
|
-
const fullPath = presolve(pjoin(
|
|
15624
|
+
const fullPath = presolve(pjoin(path37, basename3));
|
|
15557
15625
|
entry = { path: prelative(this._root, fullPath), fullPath, basename: basename3 };
|
|
15558
15626
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
15559
15627
|
} catch (err) {
|
|
@@ -15953,16 +16021,16 @@ var delFromSet = (main, prop, item) => {
|
|
|
15953
16021
|
};
|
|
15954
16022
|
var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
|
|
15955
16023
|
var FsWatchInstances = /* @__PURE__ */ new Map();
|
|
15956
|
-
function createFsWatchInstance(
|
|
16024
|
+
function createFsWatchInstance(path37, options, listener, errHandler, emitRaw) {
|
|
15957
16025
|
const handleEvent = (rawEvent, evPath) => {
|
|
15958
|
-
listener(
|
|
15959
|
-
emitRaw(rawEvent, evPath, { watchedPath:
|
|
15960
|
-
if (evPath &&
|
|
15961
|
-
fsWatchBroadcast(sysPath.resolve(
|
|
16026
|
+
listener(path37);
|
|
16027
|
+
emitRaw(rawEvent, evPath, { watchedPath: path37 });
|
|
16028
|
+
if (evPath && path37 !== evPath) {
|
|
16029
|
+
fsWatchBroadcast(sysPath.resolve(path37, evPath), KEY_LISTENERS, sysPath.join(path37, evPath));
|
|
15962
16030
|
}
|
|
15963
16031
|
};
|
|
15964
16032
|
try {
|
|
15965
|
-
return fs_watch(
|
|
16033
|
+
return fs_watch(path37, {
|
|
15966
16034
|
persistent: options.persistent
|
|
15967
16035
|
}, handleEvent);
|
|
15968
16036
|
} catch (error) {
|
|
@@ -15978,12 +16046,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
|
|
|
15978
16046
|
listener(val1, val2, val3);
|
|
15979
16047
|
});
|
|
15980
16048
|
};
|
|
15981
|
-
var setFsWatchListener = (
|
|
16049
|
+
var setFsWatchListener = (path37, fullPath, options, handlers) => {
|
|
15982
16050
|
const { listener, errHandler, rawEmitter } = handlers;
|
|
15983
16051
|
let cont = FsWatchInstances.get(fullPath);
|
|
15984
16052
|
let watcher;
|
|
15985
16053
|
if (!options.persistent) {
|
|
15986
|
-
watcher = createFsWatchInstance(
|
|
16054
|
+
watcher = createFsWatchInstance(path37, options, listener, errHandler, rawEmitter);
|
|
15987
16055
|
if (!watcher)
|
|
15988
16056
|
return;
|
|
15989
16057
|
return watcher.close.bind(watcher);
|
|
@@ -15994,7 +16062,7 @@ var setFsWatchListener = (path34, fullPath, options, handlers) => {
|
|
|
15994
16062
|
addAndConvert(cont, KEY_RAW, rawEmitter);
|
|
15995
16063
|
} else {
|
|
15996
16064
|
watcher = createFsWatchInstance(
|
|
15997
|
-
|
|
16065
|
+
path37,
|
|
15998
16066
|
options,
|
|
15999
16067
|
fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
|
|
16000
16068
|
errHandler,
|
|
@@ -16009,7 +16077,7 @@ var setFsWatchListener = (path34, fullPath, options, handlers) => {
|
|
|
16009
16077
|
cont.watcherUnusable = true;
|
|
16010
16078
|
if (isWindows && error.code === "EPERM") {
|
|
16011
16079
|
try {
|
|
16012
|
-
const fd = await open(
|
|
16080
|
+
const fd = await open(path37, "r");
|
|
16013
16081
|
await fd.close();
|
|
16014
16082
|
broadcastErr(error);
|
|
16015
16083
|
} catch (err) {
|
|
@@ -16040,7 +16108,7 @@ var setFsWatchListener = (path34, fullPath, options, handlers) => {
|
|
|
16040
16108
|
};
|
|
16041
16109
|
};
|
|
16042
16110
|
var FsWatchFileInstances = /* @__PURE__ */ new Map();
|
|
16043
|
-
var setFsWatchFileListener = (
|
|
16111
|
+
var setFsWatchFileListener = (path37, fullPath, options, handlers) => {
|
|
16044
16112
|
const { listener, rawEmitter } = handlers;
|
|
16045
16113
|
let cont = FsWatchFileInstances.get(fullPath);
|
|
16046
16114
|
const copts = cont && cont.options;
|
|
@@ -16062,7 +16130,7 @@ var setFsWatchFileListener = (path34, fullPath, options, handlers) => {
|
|
|
16062
16130
|
});
|
|
16063
16131
|
const currmtime = curr.mtimeMs;
|
|
16064
16132
|
if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
|
|
16065
|
-
foreach(cont.listeners, (listener2) => listener2(
|
|
16133
|
+
foreach(cont.listeners, (listener2) => listener2(path37, curr));
|
|
16066
16134
|
}
|
|
16067
16135
|
})
|
|
16068
16136
|
};
|
|
@@ -16090,13 +16158,13 @@ var NodeFsHandler = class {
|
|
|
16090
16158
|
* @param listener on fs change
|
|
16091
16159
|
* @returns closer for the watcher instance
|
|
16092
16160
|
*/
|
|
16093
|
-
_watchWithNodeFs(
|
|
16161
|
+
_watchWithNodeFs(path37, listener) {
|
|
16094
16162
|
const opts = this.fsw.options;
|
|
16095
|
-
const directory = sysPath.dirname(
|
|
16096
|
-
const basename3 = sysPath.basename(
|
|
16163
|
+
const directory = sysPath.dirname(path37);
|
|
16164
|
+
const basename3 = sysPath.basename(path37);
|
|
16097
16165
|
const parent = this.fsw._getWatchedDir(directory);
|
|
16098
16166
|
parent.add(basename3);
|
|
16099
|
-
const absolutePath = sysPath.resolve(
|
|
16167
|
+
const absolutePath = sysPath.resolve(path37);
|
|
16100
16168
|
const options = {
|
|
16101
16169
|
persistent: opts.persistent
|
|
16102
16170
|
};
|
|
@@ -16106,12 +16174,12 @@ var NodeFsHandler = class {
|
|
|
16106
16174
|
if (opts.usePolling) {
|
|
16107
16175
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
16108
16176
|
options.interval = enableBin && isBinaryPath(basename3) ? opts.binaryInterval : opts.interval;
|
|
16109
|
-
closer = setFsWatchFileListener(
|
|
16177
|
+
closer = setFsWatchFileListener(path37, absolutePath, options, {
|
|
16110
16178
|
listener,
|
|
16111
16179
|
rawEmitter: this.fsw._emitRaw
|
|
16112
16180
|
});
|
|
16113
16181
|
} else {
|
|
16114
|
-
closer = setFsWatchListener(
|
|
16182
|
+
closer = setFsWatchListener(path37, absolutePath, options, {
|
|
16115
16183
|
listener,
|
|
16116
16184
|
errHandler: this._boundHandleError,
|
|
16117
16185
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -16133,7 +16201,7 @@ var NodeFsHandler = class {
|
|
|
16133
16201
|
let prevStats = stats;
|
|
16134
16202
|
if (parent.has(basename3))
|
|
16135
16203
|
return;
|
|
16136
|
-
const listener = async (
|
|
16204
|
+
const listener = async (path37, newStats) => {
|
|
16137
16205
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
|
|
16138
16206
|
return;
|
|
16139
16207
|
if (!newStats || newStats.mtimeMs === 0) {
|
|
@@ -16147,11 +16215,11 @@ var NodeFsHandler = class {
|
|
|
16147
16215
|
this.fsw._emit(EV.CHANGE, file, newStats2);
|
|
16148
16216
|
}
|
|
16149
16217
|
if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
|
|
16150
|
-
this.fsw._closeFile(
|
|
16218
|
+
this.fsw._closeFile(path37);
|
|
16151
16219
|
prevStats = newStats2;
|
|
16152
16220
|
const closer2 = this._watchWithNodeFs(file, listener);
|
|
16153
16221
|
if (closer2)
|
|
16154
|
-
this.fsw._addPathCloser(
|
|
16222
|
+
this.fsw._addPathCloser(path37, closer2);
|
|
16155
16223
|
} else {
|
|
16156
16224
|
prevStats = newStats2;
|
|
16157
16225
|
}
|
|
@@ -16183,7 +16251,7 @@ var NodeFsHandler = class {
|
|
|
16183
16251
|
* @param item basename of this item
|
|
16184
16252
|
* @returns true if no more processing is needed for this entry.
|
|
16185
16253
|
*/
|
|
16186
|
-
async _handleSymlink(entry, directory,
|
|
16254
|
+
async _handleSymlink(entry, directory, path37, item) {
|
|
16187
16255
|
if (this.fsw.closed) {
|
|
16188
16256
|
return;
|
|
16189
16257
|
}
|
|
@@ -16193,7 +16261,7 @@ var NodeFsHandler = class {
|
|
|
16193
16261
|
this.fsw._incrReadyCount();
|
|
16194
16262
|
let linkPath;
|
|
16195
16263
|
try {
|
|
16196
|
-
linkPath = await fsrealpath(
|
|
16264
|
+
linkPath = await fsrealpath(path37);
|
|
16197
16265
|
} catch (e) {
|
|
16198
16266
|
this.fsw._emitReady();
|
|
16199
16267
|
return true;
|
|
@@ -16203,12 +16271,12 @@ var NodeFsHandler = class {
|
|
|
16203
16271
|
if (dir.has(item)) {
|
|
16204
16272
|
if (this.fsw._symlinkPaths.get(full) !== linkPath) {
|
|
16205
16273
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
16206
|
-
this.fsw._emit(EV.CHANGE,
|
|
16274
|
+
this.fsw._emit(EV.CHANGE, path37, entry.stats);
|
|
16207
16275
|
}
|
|
16208
16276
|
} else {
|
|
16209
16277
|
dir.add(item);
|
|
16210
16278
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
16211
|
-
this.fsw._emit(EV.ADD,
|
|
16279
|
+
this.fsw._emit(EV.ADD, path37, entry.stats);
|
|
16212
16280
|
}
|
|
16213
16281
|
this.fsw._emitReady();
|
|
16214
16282
|
return true;
|
|
@@ -16237,9 +16305,9 @@ var NodeFsHandler = class {
|
|
|
16237
16305
|
return;
|
|
16238
16306
|
}
|
|
16239
16307
|
const item = entry.path;
|
|
16240
|
-
let
|
|
16308
|
+
let path37 = sysPath.join(directory, item);
|
|
16241
16309
|
current.add(item);
|
|
16242
|
-
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory,
|
|
16310
|
+
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path37, item)) {
|
|
16243
16311
|
return;
|
|
16244
16312
|
}
|
|
16245
16313
|
if (this.fsw.closed) {
|
|
@@ -16248,8 +16316,8 @@ var NodeFsHandler = class {
|
|
|
16248
16316
|
}
|
|
16249
16317
|
if (item === target || !target && !previous.has(item)) {
|
|
16250
16318
|
this.fsw._incrReadyCount();
|
|
16251
|
-
|
|
16252
|
-
this._addToNodeFs(
|
|
16319
|
+
path37 = sysPath.join(dir, sysPath.relative(dir, path37));
|
|
16320
|
+
this._addToNodeFs(path37, initialAdd, wh, depth + 1);
|
|
16253
16321
|
}
|
|
16254
16322
|
}).on(EV.ERROR, this._boundHandleError);
|
|
16255
16323
|
return new Promise((resolve3, reject) => {
|
|
@@ -16318,13 +16386,13 @@ var NodeFsHandler = class {
|
|
|
16318
16386
|
* @param depth Child path actually targeted for watch
|
|
16319
16387
|
* @param target Child path actually targeted for watch
|
|
16320
16388
|
*/
|
|
16321
|
-
async _addToNodeFs(
|
|
16389
|
+
async _addToNodeFs(path37, initialAdd, priorWh, depth, target) {
|
|
16322
16390
|
const ready = this.fsw._emitReady;
|
|
16323
|
-
if (this.fsw._isIgnored(
|
|
16391
|
+
if (this.fsw._isIgnored(path37) || this.fsw.closed) {
|
|
16324
16392
|
ready();
|
|
16325
16393
|
return false;
|
|
16326
16394
|
}
|
|
16327
|
-
const wh = this.fsw._getWatchHelpers(
|
|
16395
|
+
const wh = this.fsw._getWatchHelpers(path37);
|
|
16328
16396
|
if (priorWh) {
|
|
16329
16397
|
wh.filterPath = (entry) => priorWh.filterPath(entry);
|
|
16330
16398
|
wh.filterDir = (entry) => priorWh.filterDir(entry);
|
|
@@ -16340,8 +16408,8 @@ var NodeFsHandler = class {
|
|
|
16340
16408
|
const follow = this.fsw.options.followSymlinks;
|
|
16341
16409
|
let closer;
|
|
16342
16410
|
if (stats.isDirectory()) {
|
|
16343
|
-
const absPath = sysPath.resolve(
|
|
16344
|
-
const targetPath = follow ? await fsrealpath(
|
|
16411
|
+
const absPath = sysPath.resolve(path37);
|
|
16412
|
+
const targetPath = follow ? await fsrealpath(path37) : path37;
|
|
16345
16413
|
if (this.fsw.closed)
|
|
16346
16414
|
return;
|
|
16347
16415
|
closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
|
|
@@ -16351,29 +16419,29 @@ var NodeFsHandler = class {
|
|
|
16351
16419
|
this.fsw._symlinkPaths.set(absPath, targetPath);
|
|
16352
16420
|
}
|
|
16353
16421
|
} else if (stats.isSymbolicLink()) {
|
|
16354
|
-
const targetPath = follow ? await fsrealpath(
|
|
16422
|
+
const targetPath = follow ? await fsrealpath(path37) : path37;
|
|
16355
16423
|
if (this.fsw.closed)
|
|
16356
16424
|
return;
|
|
16357
16425
|
const parent = sysPath.dirname(wh.watchPath);
|
|
16358
16426
|
this.fsw._getWatchedDir(parent).add(wh.watchPath);
|
|
16359
16427
|
this.fsw._emit(EV.ADD, wh.watchPath, stats);
|
|
16360
|
-
closer = await this._handleDir(parent, stats, initialAdd, depth,
|
|
16428
|
+
closer = await this._handleDir(parent, stats, initialAdd, depth, path37, wh, targetPath);
|
|
16361
16429
|
if (this.fsw.closed)
|
|
16362
16430
|
return;
|
|
16363
16431
|
if (targetPath !== void 0) {
|
|
16364
|
-
this.fsw._symlinkPaths.set(sysPath.resolve(
|
|
16432
|
+
this.fsw._symlinkPaths.set(sysPath.resolve(path37), targetPath);
|
|
16365
16433
|
}
|
|
16366
16434
|
} else {
|
|
16367
16435
|
closer = this._handleFile(wh.watchPath, stats, initialAdd);
|
|
16368
16436
|
}
|
|
16369
16437
|
ready();
|
|
16370
16438
|
if (closer)
|
|
16371
|
-
this.fsw._addPathCloser(
|
|
16439
|
+
this.fsw._addPathCloser(path37, closer);
|
|
16372
16440
|
return false;
|
|
16373
16441
|
} catch (error) {
|
|
16374
16442
|
if (this.fsw._handleError(error)) {
|
|
16375
16443
|
ready();
|
|
16376
|
-
return
|
|
16444
|
+
return path37;
|
|
16377
16445
|
}
|
|
16378
16446
|
}
|
|
16379
16447
|
}
|
|
@@ -16416,26 +16484,26 @@ function createPattern(matcher) {
|
|
|
16416
16484
|
}
|
|
16417
16485
|
return () => false;
|
|
16418
16486
|
}
|
|
16419
|
-
function normalizePath(
|
|
16420
|
-
if (typeof
|
|
16487
|
+
function normalizePath(path37) {
|
|
16488
|
+
if (typeof path37 !== "string")
|
|
16421
16489
|
throw new Error("string expected");
|
|
16422
|
-
|
|
16423
|
-
|
|
16490
|
+
path37 = sysPath2.normalize(path37);
|
|
16491
|
+
path37 = path37.replace(/\\/g, "/");
|
|
16424
16492
|
let prepend = false;
|
|
16425
|
-
if (
|
|
16493
|
+
if (path37.startsWith("//"))
|
|
16426
16494
|
prepend = true;
|
|
16427
16495
|
const DOUBLE_SLASH_RE2 = /\/\//;
|
|
16428
|
-
while (
|
|
16429
|
-
|
|
16496
|
+
while (path37.match(DOUBLE_SLASH_RE2))
|
|
16497
|
+
path37 = path37.replace(DOUBLE_SLASH_RE2, "/");
|
|
16430
16498
|
if (prepend)
|
|
16431
|
-
|
|
16432
|
-
return
|
|
16499
|
+
path37 = "/" + path37;
|
|
16500
|
+
return path37;
|
|
16433
16501
|
}
|
|
16434
16502
|
function matchPatterns(patterns, testString, stats) {
|
|
16435
|
-
const
|
|
16503
|
+
const path37 = normalizePath(testString);
|
|
16436
16504
|
for (let index = 0; index < patterns.length; index++) {
|
|
16437
16505
|
const pattern = patterns[index];
|
|
16438
|
-
if (pattern(
|
|
16506
|
+
if (pattern(path37, stats)) {
|
|
16439
16507
|
return true;
|
|
16440
16508
|
}
|
|
16441
16509
|
}
|
|
@@ -16475,19 +16543,19 @@ var toUnix = (string) => {
|
|
|
16475
16543
|
}
|
|
16476
16544
|
return str;
|
|
16477
16545
|
};
|
|
16478
|
-
var normalizePathToUnix = (
|
|
16479
|
-
var normalizeIgnored = (cwd = "") => (
|
|
16480
|
-
if (typeof
|
|
16481
|
-
return normalizePathToUnix(sysPath2.isAbsolute(
|
|
16546
|
+
var normalizePathToUnix = (path37) => toUnix(sysPath2.normalize(toUnix(path37)));
|
|
16547
|
+
var normalizeIgnored = (cwd = "") => (path37) => {
|
|
16548
|
+
if (typeof path37 === "string") {
|
|
16549
|
+
return normalizePathToUnix(sysPath2.isAbsolute(path37) ? path37 : sysPath2.join(cwd, path37));
|
|
16482
16550
|
} else {
|
|
16483
|
-
return
|
|
16551
|
+
return path37;
|
|
16484
16552
|
}
|
|
16485
16553
|
};
|
|
16486
|
-
var getAbsolutePath = (
|
|
16487
|
-
if (sysPath2.isAbsolute(
|
|
16488
|
-
return
|
|
16554
|
+
var getAbsolutePath = (path37, cwd) => {
|
|
16555
|
+
if (sysPath2.isAbsolute(path37)) {
|
|
16556
|
+
return path37;
|
|
16489
16557
|
}
|
|
16490
|
-
return sysPath2.join(cwd,
|
|
16558
|
+
return sysPath2.join(cwd, path37);
|
|
16491
16559
|
};
|
|
16492
16560
|
var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
|
|
16493
16561
|
var DirEntry = class {
|
|
@@ -16542,10 +16610,10 @@ var DirEntry = class {
|
|
|
16542
16610
|
var STAT_METHOD_F = "stat";
|
|
16543
16611
|
var STAT_METHOD_L = "lstat";
|
|
16544
16612
|
var WatchHelper = class {
|
|
16545
|
-
constructor(
|
|
16613
|
+
constructor(path37, follow, fsw) {
|
|
16546
16614
|
this.fsw = fsw;
|
|
16547
|
-
const watchPath =
|
|
16548
|
-
this.path =
|
|
16615
|
+
const watchPath = path37;
|
|
16616
|
+
this.path = path37 = path37.replace(REPLACER_RE, "");
|
|
16549
16617
|
this.watchPath = watchPath;
|
|
16550
16618
|
this.fullWatchPath = sysPath2.resolve(watchPath);
|
|
16551
16619
|
this.dirParts = [];
|
|
@@ -16667,20 +16735,20 @@ var FSWatcher = class extends EventEmitter {
|
|
|
16667
16735
|
this._closePromise = void 0;
|
|
16668
16736
|
let paths = unifyPaths(paths_);
|
|
16669
16737
|
if (cwd) {
|
|
16670
|
-
paths = paths.map((
|
|
16671
|
-
const absPath = getAbsolutePath(
|
|
16738
|
+
paths = paths.map((path37) => {
|
|
16739
|
+
const absPath = getAbsolutePath(path37, cwd);
|
|
16672
16740
|
return absPath;
|
|
16673
16741
|
});
|
|
16674
16742
|
}
|
|
16675
|
-
paths.forEach((
|
|
16676
|
-
this._removeIgnoredPath(
|
|
16743
|
+
paths.forEach((path37) => {
|
|
16744
|
+
this._removeIgnoredPath(path37);
|
|
16677
16745
|
});
|
|
16678
16746
|
this._userIgnored = void 0;
|
|
16679
16747
|
if (!this._readyCount)
|
|
16680
16748
|
this._readyCount = 0;
|
|
16681
16749
|
this._readyCount += paths.length;
|
|
16682
|
-
Promise.all(paths.map(async (
|
|
16683
|
-
const res = await this._nodeFsHandler._addToNodeFs(
|
|
16750
|
+
Promise.all(paths.map(async (path37) => {
|
|
16751
|
+
const res = await this._nodeFsHandler._addToNodeFs(path37, !_internal, void 0, 0, _origAdd);
|
|
16684
16752
|
if (res)
|
|
16685
16753
|
this._emitReady();
|
|
16686
16754
|
return res;
|
|
@@ -16702,17 +16770,17 @@ var FSWatcher = class extends EventEmitter {
|
|
|
16702
16770
|
return this;
|
|
16703
16771
|
const paths = unifyPaths(paths_);
|
|
16704
16772
|
const { cwd } = this.options;
|
|
16705
|
-
paths.forEach((
|
|
16706
|
-
if (!sysPath2.isAbsolute(
|
|
16773
|
+
paths.forEach((path37) => {
|
|
16774
|
+
if (!sysPath2.isAbsolute(path37) && !this._closers.has(path37)) {
|
|
16707
16775
|
if (cwd)
|
|
16708
|
-
|
|
16709
|
-
|
|
16776
|
+
path37 = sysPath2.join(cwd, path37);
|
|
16777
|
+
path37 = sysPath2.resolve(path37);
|
|
16710
16778
|
}
|
|
16711
|
-
this._closePath(
|
|
16712
|
-
this._addIgnoredPath(
|
|
16713
|
-
if (this._watched.has(
|
|
16779
|
+
this._closePath(path37);
|
|
16780
|
+
this._addIgnoredPath(path37);
|
|
16781
|
+
if (this._watched.has(path37)) {
|
|
16714
16782
|
this._addIgnoredPath({
|
|
16715
|
-
path:
|
|
16783
|
+
path: path37,
|
|
16716
16784
|
recursive: true
|
|
16717
16785
|
});
|
|
16718
16786
|
}
|
|
@@ -16776,38 +16844,38 @@ var FSWatcher = class extends EventEmitter {
|
|
|
16776
16844
|
* @param stats arguments to be passed with event
|
|
16777
16845
|
* @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
|
|
16778
16846
|
*/
|
|
16779
|
-
async _emit(event,
|
|
16847
|
+
async _emit(event, path37, stats) {
|
|
16780
16848
|
if (this.closed)
|
|
16781
16849
|
return;
|
|
16782
16850
|
const opts = this.options;
|
|
16783
16851
|
if (isWindows)
|
|
16784
|
-
|
|
16852
|
+
path37 = sysPath2.normalize(path37);
|
|
16785
16853
|
if (opts.cwd)
|
|
16786
|
-
|
|
16787
|
-
const args = [
|
|
16854
|
+
path37 = sysPath2.relative(opts.cwd, path37);
|
|
16855
|
+
const args = [path37];
|
|
16788
16856
|
if (stats != null)
|
|
16789
16857
|
args.push(stats);
|
|
16790
16858
|
const awf = opts.awaitWriteFinish;
|
|
16791
16859
|
let pw;
|
|
16792
|
-
if (awf && (pw = this._pendingWrites.get(
|
|
16860
|
+
if (awf && (pw = this._pendingWrites.get(path37))) {
|
|
16793
16861
|
pw.lastChange = /* @__PURE__ */ new Date();
|
|
16794
16862
|
return this;
|
|
16795
16863
|
}
|
|
16796
16864
|
if (opts.atomic) {
|
|
16797
16865
|
if (event === EVENTS.UNLINK) {
|
|
16798
|
-
this._pendingUnlinks.set(
|
|
16866
|
+
this._pendingUnlinks.set(path37, [event, ...args]);
|
|
16799
16867
|
setTimeout(() => {
|
|
16800
|
-
this._pendingUnlinks.forEach((entry,
|
|
16868
|
+
this._pendingUnlinks.forEach((entry, path38) => {
|
|
16801
16869
|
this.emit(...entry);
|
|
16802
16870
|
this.emit(EVENTS.ALL, ...entry);
|
|
16803
|
-
this._pendingUnlinks.delete(
|
|
16871
|
+
this._pendingUnlinks.delete(path38);
|
|
16804
16872
|
});
|
|
16805
16873
|
}, typeof opts.atomic === "number" ? opts.atomic : 100);
|
|
16806
16874
|
return this;
|
|
16807
16875
|
}
|
|
16808
|
-
if (event === EVENTS.ADD && this._pendingUnlinks.has(
|
|
16876
|
+
if (event === EVENTS.ADD && this._pendingUnlinks.has(path37)) {
|
|
16809
16877
|
event = EVENTS.CHANGE;
|
|
16810
|
-
this._pendingUnlinks.delete(
|
|
16878
|
+
this._pendingUnlinks.delete(path37);
|
|
16811
16879
|
}
|
|
16812
16880
|
}
|
|
16813
16881
|
if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
|
|
@@ -16825,16 +16893,16 @@ var FSWatcher = class extends EventEmitter {
|
|
|
16825
16893
|
this.emitWithAll(event, args);
|
|
16826
16894
|
}
|
|
16827
16895
|
};
|
|
16828
|
-
this._awaitWriteFinish(
|
|
16896
|
+
this._awaitWriteFinish(path37, awf.stabilityThreshold, event, awfEmit);
|
|
16829
16897
|
return this;
|
|
16830
16898
|
}
|
|
16831
16899
|
if (event === EVENTS.CHANGE) {
|
|
16832
|
-
const isThrottled = !this._throttle(EVENTS.CHANGE,
|
|
16900
|
+
const isThrottled = !this._throttle(EVENTS.CHANGE, path37, 50);
|
|
16833
16901
|
if (isThrottled)
|
|
16834
16902
|
return this;
|
|
16835
16903
|
}
|
|
16836
16904
|
if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
|
|
16837
|
-
const fullPath = opts.cwd ? sysPath2.join(opts.cwd,
|
|
16905
|
+
const fullPath = opts.cwd ? sysPath2.join(opts.cwd, path37) : path37;
|
|
16838
16906
|
let stats2;
|
|
16839
16907
|
try {
|
|
16840
16908
|
stats2 = await stat3(fullPath);
|
|
@@ -16865,23 +16933,23 @@ var FSWatcher = class extends EventEmitter {
|
|
|
16865
16933
|
* @param timeout duration of time to suppress duplicate actions
|
|
16866
16934
|
* @returns tracking object or false if action should be suppressed
|
|
16867
16935
|
*/
|
|
16868
|
-
_throttle(actionType,
|
|
16936
|
+
_throttle(actionType, path37, timeout) {
|
|
16869
16937
|
if (!this._throttled.has(actionType)) {
|
|
16870
16938
|
this._throttled.set(actionType, /* @__PURE__ */ new Map());
|
|
16871
16939
|
}
|
|
16872
16940
|
const action = this._throttled.get(actionType);
|
|
16873
16941
|
if (!action)
|
|
16874
16942
|
throw new Error("invalid throttle");
|
|
16875
|
-
const actionPath = action.get(
|
|
16943
|
+
const actionPath = action.get(path37);
|
|
16876
16944
|
if (actionPath) {
|
|
16877
16945
|
actionPath.count++;
|
|
16878
16946
|
return false;
|
|
16879
16947
|
}
|
|
16880
16948
|
let timeoutObject;
|
|
16881
16949
|
const clear = () => {
|
|
16882
|
-
const item = action.get(
|
|
16950
|
+
const item = action.get(path37);
|
|
16883
16951
|
const count = item ? item.count : 0;
|
|
16884
|
-
action.delete(
|
|
16952
|
+
action.delete(path37);
|
|
16885
16953
|
clearTimeout(timeoutObject);
|
|
16886
16954
|
if (item)
|
|
16887
16955
|
clearTimeout(item.timeoutObject);
|
|
@@ -16889,7 +16957,7 @@ var FSWatcher = class extends EventEmitter {
|
|
|
16889
16957
|
};
|
|
16890
16958
|
timeoutObject = setTimeout(clear, timeout);
|
|
16891
16959
|
const thr = { timeoutObject, clear, count: 0 };
|
|
16892
|
-
action.set(
|
|
16960
|
+
action.set(path37, thr);
|
|
16893
16961
|
return thr;
|
|
16894
16962
|
}
|
|
16895
16963
|
_incrReadyCount() {
|
|
@@ -16903,44 +16971,44 @@ var FSWatcher = class extends EventEmitter {
|
|
|
16903
16971
|
* @param event
|
|
16904
16972
|
* @param awfEmit Callback to be called when ready for event to be emitted.
|
|
16905
16973
|
*/
|
|
16906
|
-
_awaitWriteFinish(
|
|
16974
|
+
_awaitWriteFinish(path37, threshold, event, awfEmit) {
|
|
16907
16975
|
const awf = this.options.awaitWriteFinish;
|
|
16908
16976
|
if (typeof awf !== "object")
|
|
16909
16977
|
return;
|
|
16910
16978
|
const pollInterval = awf.pollInterval;
|
|
16911
16979
|
let timeoutHandler;
|
|
16912
|
-
let fullPath =
|
|
16913
|
-
if (this.options.cwd && !sysPath2.isAbsolute(
|
|
16914
|
-
fullPath = sysPath2.join(this.options.cwd,
|
|
16980
|
+
let fullPath = path37;
|
|
16981
|
+
if (this.options.cwd && !sysPath2.isAbsolute(path37)) {
|
|
16982
|
+
fullPath = sysPath2.join(this.options.cwd, path37);
|
|
16915
16983
|
}
|
|
16916
16984
|
const now = /* @__PURE__ */ new Date();
|
|
16917
16985
|
const writes = this._pendingWrites;
|
|
16918
16986
|
function awaitWriteFinishFn(prevStat) {
|
|
16919
16987
|
statcb(fullPath, (err, curStat) => {
|
|
16920
|
-
if (err || !writes.has(
|
|
16988
|
+
if (err || !writes.has(path37)) {
|
|
16921
16989
|
if (err && err.code !== "ENOENT")
|
|
16922
16990
|
awfEmit(err);
|
|
16923
16991
|
return;
|
|
16924
16992
|
}
|
|
16925
16993
|
const now2 = Number(/* @__PURE__ */ new Date());
|
|
16926
16994
|
if (prevStat && curStat.size !== prevStat.size) {
|
|
16927
|
-
writes.get(
|
|
16995
|
+
writes.get(path37).lastChange = now2;
|
|
16928
16996
|
}
|
|
16929
|
-
const pw = writes.get(
|
|
16997
|
+
const pw = writes.get(path37);
|
|
16930
16998
|
const df = now2 - pw.lastChange;
|
|
16931
16999
|
if (df >= threshold) {
|
|
16932
|
-
writes.delete(
|
|
17000
|
+
writes.delete(path37);
|
|
16933
17001
|
awfEmit(void 0, curStat);
|
|
16934
17002
|
} else {
|
|
16935
17003
|
timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
|
|
16936
17004
|
}
|
|
16937
17005
|
});
|
|
16938
17006
|
}
|
|
16939
|
-
if (!writes.has(
|
|
16940
|
-
writes.set(
|
|
17007
|
+
if (!writes.has(path37)) {
|
|
17008
|
+
writes.set(path37, {
|
|
16941
17009
|
lastChange: now,
|
|
16942
17010
|
cancelWait: () => {
|
|
16943
|
-
writes.delete(
|
|
17011
|
+
writes.delete(path37);
|
|
16944
17012
|
clearTimeout(timeoutHandler);
|
|
16945
17013
|
return event;
|
|
16946
17014
|
}
|
|
@@ -16951,8 +17019,8 @@ var FSWatcher = class extends EventEmitter {
|
|
|
16951
17019
|
/**
|
|
16952
17020
|
* Determines whether user has asked to ignore this path.
|
|
16953
17021
|
*/
|
|
16954
|
-
_isIgnored(
|
|
16955
|
-
if (this.options.atomic && DOT_RE.test(
|
|
17022
|
+
_isIgnored(path37, stats) {
|
|
17023
|
+
if (this.options.atomic && DOT_RE.test(path37))
|
|
16956
17024
|
return true;
|
|
16957
17025
|
if (!this._userIgnored) {
|
|
16958
17026
|
const { cwd } = this.options;
|
|
@@ -16962,17 +17030,17 @@ var FSWatcher = class extends EventEmitter {
|
|
|
16962
17030
|
const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
|
|
16963
17031
|
this._userIgnored = anymatch(list, void 0);
|
|
16964
17032
|
}
|
|
16965
|
-
return this._userIgnored(
|
|
17033
|
+
return this._userIgnored(path37, stats);
|
|
16966
17034
|
}
|
|
16967
|
-
_isntIgnored(
|
|
16968
|
-
return !this._isIgnored(
|
|
17035
|
+
_isntIgnored(path37, stat4) {
|
|
17036
|
+
return !this._isIgnored(path37, stat4);
|
|
16969
17037
|
}
|
|
16970
17038
|
/**
|
|
16971
17039
|
* Provides a set of common helpers and properties relating to symlink handling.
|
|
16972
17040
|
* @param path file or directory pattern being watched
|
|
16973
17041
|
*/
|
|
16974
|
-
_getWatchHelpers(
|
|
16975
|
-
return new WatchHelper(
|
|
17042
|
+
_getWatchHelpers(path37) {
|
|
17043
|
+
return new WatchHelper(path37, this.options.followSymlinks, this);
|
|
16976
17044
|
}
|
|
16977
17045
|
// Directory helpers
|
|
16978
17046
|
// -----------------
|
|
@@ -17004,63 +17072,63 @@ var FSWatcher = class extends EventEmitter {
|
|
|
17004
17072
|
* @param item base path of item/directory
|
|
17005
17073
|
*/
|
|
17006
17074
|
_remove(directory, item, isDirectory) {
|
|
17007
|
-
const
|
|
17008
|
-
const fullPath = sysPath2.resolve(
|
|
17009
|
-
isDirectory = isDirectory != null ? isDirectory : this._watched.has(
|
|
17010
|
-
if (!this._throttle("remove",
|
|
17075
|
+
const path37 = sysPath2.join(directory, item);
|
|
17076
|
+
const fullPath = sysPath2.resolve(path37);
|
|
17077
|
+
isDirectory = isDirectory != null ? isDirectory : this._watched.has(path37) || this._watched.has(fullPath);
|
|
17078
|
+
if (!this._throttle("remove", path37, 100))
|
|
17011
17079
|
return;
|
|
17012
17080
|
if (!isDirectory && this._watched.size === 1) {
|
|
17013
17081
|
this.add(directory, item, true);
|
|
17014
17082
|
}
|
|
17015
|
-
const wp = this._getWatchedDir(
|
|
17083
|
+
const wp = this._getWatchedDir(path37);
|
|
17016
17084
|
const nestedDirectoryChildren = wp.getChildren();
|
|
17017
|
-
nestedDirectoryChildren.forEach((nested) => this._remove(
|
|
17085
|
+
nestedDirectoryChildren.forEach((nested) => this._remove(path37, nested));
|
|
17018
17086
|
const parent = this._getWatchedDir(directory);
|
|
17019
17087
|
const wasTracked = parent.has(item);
|
|
17020
17088
|
parent.remove(item);
|
|
17021
17089
|
if (this._symlinkPaths.has(fullPath)) {
|
|
17022
17090
|
this._symlinkPaths.delete(fullPath);
|
|
17023
17091
|
}
|
|
17024
|
-
let relPath =
|
|
17092
|
+
let relPath = path37;
|
|
17025
17093
|
if (this.options.cwd)
|
|
17026
|
-
relPath = sysPath2.relative(this.options.cwd,
|
|
17094
|
+
relPath = sysPath2.relative(this.options.cwd, path37);
|
|
17027
17095
|
if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
|
|
17028
17096
|
const event = this._pendingWrites.get(relPath).cancelWait();
|
|
17029
17097
|
if (event === EVENTS.ADD)
|
|
17030
17098
|
return;
|
|
17031
17099
|
}
|
|
17032
|
-
this._watched.delete(
|
|
17100
|
+
this._watched.delete(path37);
|
|
17033
17101
|
this._watched.delete(fullPath);
|
|
17034
17102
|
const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
|
|
17035
|
-
if (wasTracked && !this._isIgnored(
|
|
17036
|
-
this._emit(eventName,
|
|
17037
|
-
this._closePath(
|
|
17103
|
+
if (wasTracked && !this._isIgnored(path37))
|
|
17104
|
+
this._emit(eventName, path37);
|
|
17105
|
+
this._closePath(path37);
|
|
17038
17106
|
}
|
|
17039
17107
|
/**
|
|
17040
17108
|
* Closes all watchers for a path
|
|
17041
17109
|
*/
|
|
17042
|
-
_closePath(
|
|
17043
|
-
this._closeFile(
|
|
17044
|
-
const dir = sysPath2.dirname(
|
|
17045
|
-
this._getWatchedDir(dir).remove(sysPath2.basename(
|
|
17110
|
+
_closePath(path37) {
|
|
17111
|
+
this._closeFile(path37);
|
|
17112
|
+
const dir = sysPath2.dirname(path37);
|
|
17113
|
+
this._getWatchedDir(dir).remove(sysPath2.basename(path37));
|
|
17046
17114
|
}
|
|
17047
17115
|
/**
|
|
17048
17116
|
* Closes only file-specific watchers
|
|
17049
17117
|
*/
|
|
17050
|
-
_closeFile(
|
|
17051
|
-
const closers = this._closers.get(
|
|
17118
|
+
_closeFile(path37) {
|
|
17119
|
+
const closers = this._closers.get(path37);
|
|
17052
17120
|
if (!closers)
|
|
17053
17121
|
return;
|
|
17054
17122
|
closers.forEach((closer) => closer());
|
|
17055
|
-
this._closers.delete(
|
|
17123
|
+
this._closers.delete(path37);
|
|
17056
17124
|
}
|
|
17057
|
-
_addPathCloser(
|
|
17125
|
+
_addPathCloser(path37, closer) {
|
|
17058
17126
|
if (!closer)
|
|
17059
17127
|
return;
|
|
17060
|
-
let list = this._closers.get(
|
|
17128
|
+
let list = this._closers.get(path37);
|
|
17061
17129
|
if (!list) {
|
|
17062
17130
|
list = [];
|
|
17063
|
-
this._closers.set(
|
|
17131
|
+
this._closers.set(path37, list);
|
|
17064
17132
|
}
|
|
17065
17133
|
list.push(closer);
|
|
17066
17134
|
}
|
|
@@ -17430,11 +17498,11 @@ function createStrictRateLimiterFromConfig(config) {
|
|
|
17430
17498
|
}
|
|
17431
17499
|
|
|
17432
17500
|
// modules/server/middleware/auto-rate-limit.ts
|
|
17433
|
-
function matchesStrictPattern(
|
|
17501
|
+
function matchesStrictPattern(path37, patterns) {
|
|
17434
17502
|
for (const pattern of patterns) {
|
|
17435
17503
|
const regexPattern = pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*").replace(/\//g, "\\/");
|
|
17436
17504
|
const regex = new RegExp(`^${regexPattern}$`);
|
|
17437
|
-
if (regex.test(
|
|
17505
|
+
if (regex.test(path37)) {
|
|
17438
17506
|
return true;
|
|
17439
17507
|
}
|
|
17440
17508
|
}
|
|
@@ -17624,9 +17692,441 @@ async function handleApiRequest(options) {
|
|
|
17624
17692
|
}
|
|
17625
17693
|
}
|
|
17626
17694
|
|
|
17695
|
+
// modules/server/image-optimizer/index.ts
|
|
17696
|
+
import sharp from "sharp";
|
|
17697
|
+
import fs25 from "fs";
|
|
17698
|
+
import path33 from "path";
|
|
17699
|
+
|
|
17700
|
+
// modules/server/image-optimizer/validation.ts
|
|
17701
|
+
import path31 from "path";
|
|
17702
|
+
function isRemoteUrl(url) {
|
|
17703
|
+
return url.startsWith("http://") || url.startsWith("https://");
|
|
17704
|
+
}
|
|
17705
|
+
function sanitizeImagePath(imagePath) {
|
|
17706
|
+
const normalized = path31.normalize(imagePath).replace(/^(\.\.(\/|\\|$))+/, "");
|
|
17707
|
+
return normalized.replace(/^[/\\]+/, "");
|
|
17708
|
+
}
|
|
17709
|
+
function patternToRegex(pattern) {
|
|
17710
|
+
const parts = [];
|
|
17711
|
+
if (pattern.protocol) {
|
|
17712
|
+
parts.push(pattern.protocol === "https" ? "https" : "http");
|
|
17713
|
+
} else {
|
|
17714
|
+
parts.push("https?");
|
|
17715
|
+
}
|
|
17716
|
+
parts.push("://");
|
|
17717
|
+
let hostnamePattern = pattern.hostname.replace(/\./g, "\\.").replace(/\*\*/g, ".*").replace(/\*/g, "[^.]*");
|
|
17718
|
+
parts.push(hostnamePattern);
|
|
17719
|
+
if (pattern.port) {
|
|
17720
|
+
parts.push(`:${pattern.port}`);
|
|
17721
|
+
}
|
|
17722
|
+
if (pattern.pathname) {
|
|
17723
|
+
let pathnamePattern = pattern.pathname.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*");
|
|
17724
|
+
parts.push(pathnamePattern);
|
|
17725
|
+
} else {
|
|
17726
|
+
parts.push(".*");
|
|
17727
|
+
}
|
|
17728
|
+
const regexSource = `^${parts.join("")}`;
|
|
17729
|
+
return new RegExp(regexSource);
|
|
17730
|
+
}
|
|
17731
|
+
function validateRemoteUrl(url, config) {
|
|
17732
|
+
if (!config.remotePatterns && !config.domains) {
|
|
17733
|
+
return false;
|
|
17734
|
+
}
|
|
17735
|
+
try {
|
|
17736
|
+
const urlObj = new URL(url);
|
|
17737
|
+
const protocol = urlObj.protocol.replace(":", "");
|
|
17738
|
+
const hostname = urlObj.hostname;
|
|
17739
|
+
const port = urlObj.port || "";
|
|
17740
|
+
const pathname = urlObj.pathname;
|
|
17741
|
+
if (config.remotePatterns && config.remotePatterns.length > 0) {
|
|
17742
|
+
for (const pattern of config.remotePatterns) {
|
|
17743
|
+
const regex = patternToRegex(pattern);
|
|
17744
|
+
const testUrl = `${protocol}://${hostname}${port ? `:${port}` : ""}${pathname}`;
|
|
17745
|
+
if (regex.test(testUrl)) {
|
|
17746
|
+
if (pattern.protocol && pattern.protocol !== protocol) {
|
|
17747
|
+
continue;
|
|
17748
|
+
}
|
|
17749
|
+
if (pattern.port && pattern.port !== port) {
|
|
17750
|
+
continue;
|
|
17751
|
+
}
|
|
17752
|
+
return true;
|
|
17753
|
+
}
|
|
17754
|
+
}
|
|
17755
|
+
}
|
|
17756
|
+
if (config.domains && config.domains.length > 0) {
|
|
17757
|
+
for (const domain of config.domains) {
|
|
17758
|
+
const domainPattern = domain.replace(/\./g, "\\.").replace(/\*\*/g, ".*").replace(/\*/g, "[^.]*");
|
|
17759
|
+
const regex = new RegExp(`^${domainPattern}$`);
|
|
17760
|
+
if (regex.test(hostname)) {
|
|
17761
|
+
if (process.env.NODE_ENV === "production" && protocol !== "https") {
|
|
17762
|
+
continue;
|
|
17763
|
+
}
|
|
17764
|
+
return true;
|
|
17765
|
+
}
|
|
17766
|
+
}
|
|
17767
|
+
}
|
|
17768
|
+
return false;
|
|
17769
|
+
} catch (error) {
|
|
17770
|
+
return false;
|
|
17771
|
+
}
|
|
17772
|
+
}
|
|
17773
|
+
function validateImageDimensions(width, height, config) {
|
|
17774
|
+
const maxWidth = config.maxWidth || 3840;
|
|
17775
|
+
const maxHeight = config.maxHeight || 3840;
|
|
17776
|
+
if (width !== void 0 && (width <= 0 || width > maxWidth)) {
|
|
17777
|
+
return {
|
|
17778
|
+
valid: false,
|
|
17779
|
+
error: `Image width must be between 1 and ${maxWidth}, got ${width}`
|
|
17780
|
+
};
|
|
17781
|
+
}
|
|
17782
|
+
if (height !== void 0 && (height <= 0 || height > maxHeight)) {
|
|
17783
|
+
return {
|
|
17784
|
+
valid: false,
|
|
17785
|
+
error: `Image height must be between 1 and ${maxHeight}, got ${height}`
|
|
17786
|
+
};
|
|
17787
|
+
}
|
|
17788
|
+
return { valid: true };
|
|
17789
|
+
}
|
|
17790
|
+
function validateQuality(quality) {
|
|
17791
|
+
if (quality === void 0) {
|
|
17792
|
+
return { valid: true };
|
|
17793
|
+
}
|
|
17794
|
+
if (typeof quality !== "number" || quality < 1 || quality > 100) {
|
|
17795
|
+
return {
|
|
17796
|
+
valid: false,
|
|
17797
|
+
error: `Image quality must be between 1 and 100, got ${quality}`
|
|
17798
|
+
};
|
|
17799
|
+
}
|
|
17800
|
+
return { valid: true };
|
|
17801
|
+
}
|
|
17802
|
+
|
|
17803
|
+
// modules/server/image-optimizer/cache.ts
|
|
17804
|
+
import fs24 from "fs";
|
|
17805
|
+
import path32 from "path";
|
|
17806
|
+
import crypto from "crypto";
|
|
17807
|
+
function generateCacheKey(src, width, height, quality, format) {
|
|
17808
|
+
const data = `${src}-${width || ""}-${height || ""}-${quality || ""}-${format || ""}`;
|
|
17809
|
+
return crypto.createHash("sha256").update(data).digest("hex");
|
|
17810
|
+
}
|
|
17811
|
+
function getCacheDir(projectRoot, config) {
|
|
17812
|
+
const buildDir = getBuildDir(projectRoot, config);
|
|
17813
|
+
return path32.join(buildDir, "cache", "images");
|
|
17814
|
+
}
|
|
17815
|
+
function ensureCacheDir(cacheDir) {
|
|
17816
|
+
if (!fs24.existsSync(cacheDir)) {
|
|
17817
|
+
fs24.mkdirSync(cacheDir, { recursive: true });
|
|
17818
|
+
}
|
|
17819
|
+
}
|
|
17820
|
+
function getCachedImagePath(cacheKey, extension, cacheDir) {
|
|
17821
|
+
return path32.join(cacheDir, `${cacheKey}.${extension}`);
|
|
17822
|
+
}
|
|
17823
|
+
function hasCachedImage(cacheKey, extension, cacheDir) {
|
|
17824
|
+
const cachedPath = getCachedImagePath(cacheKey, extension, cacheDir);
|
|
17825
|
+
return fs24.existsSync(cachedPath);
|
|
17826
|
+
}
|
|
17827
|
+
function readCachedImage(cacheKey, extension, cacheDir) {
|
|
17828
|
+
const cachedPath = getCachedImagePath(cacheKey, extension, cacheDir);
|
|
17829
|
+
try {
|
|
17830
|
+
if (fs24.existsSync(cachedPath)) {
|
|
17831
|
+
return fs24.readFileSync(cachedPath);
|
|
17832
|
+
}
|
|
17833
|
+
} catch (error) {
|
|
17834
|
+
console.warn(`[image-optimizer] Failed to read cached image: ${cachedPath}`, error);
|
|
17835
|
+
}
|
|
17836
|
+
return null;
|
|
17837
|
+
}
|
|
17838
|
+
function writeCachedImage(cacheKey, extension, cacheDir, imageBuffer) {
|
|
17839
|
+
ensureCacheDir(cacheDir);
|
|
17840
|
+
const cachedPath = getCachedImagePath(cacheKey, extension, cacheDir);
|
|
17841
|
+
try {
|
|
17842
|
+
fs24.writeFileSync(cachedPath, imageBuffer);
|
|
17843
|
+
} catch (error) {
|
|
17844
|
+
console.warn(`[image-optimizer] Failed to write cached image: ${cachedPath}`, error);
|
|
17845
|
+
}
|
|
17846
|
+
}
|
|
17847
|
+
function getImageMimeType(format) {
|
|
17848
|
+
const formatMap = {
|
|
17849
|
+
webp: "image/webp",
|
|
17850
|
+
avif: "image/avif",
|
|
17851
|
+
jpeg: "image/jpeg",
|
|
17852
|
+
jpg: "image/jpeg",
|
|
17853
|
+
png: "image/png",
|
|
17854
|
+
gif: "image/gif",
|
|
17855
|
+
svg: "image/svg+xml"
|
|
17856
|
+
};
|
|
17857
|
+
const normalized = format.toLowerCase();
|
|
17858
|
+
return formatMap[normalized] || "image/jpeg";
|
|
17859
|
+
}
|
|
17860
|
+
function getImageExtension(format) {
|
|
17861
|
+
const formatMap = {
|
|
17862
|
+
"image/webp": "webp",
|
|
17863
|
+
"image/avif": "avif",
|
|
17864
|
+
"image/jpeg": "jpg",
|
|
17865
|
+
"image/png": "png",
|
|
17866
|
+
"image/gif": "gif",
|
|
17867
|
+
"image/svg+xml": "svg",
|
|
17868
|
+
webp: "webp",
|
|
17869
|
+
avif: "avif",
|
|
17870
|
+
jpeg: "jpg",
|
|
17871
|
+
jpg: "jpg",
|
|
17872
|
+
png: "png",
|
|
17873
|
+
gif: "gif",
|
|
17874
|
+
svg: "svg"
|
|
17875
|
+
};
|
|
17876
|
+
const normalized = format.toLowerCase();
|
|
17877
|
+
return formatMap[normalized] || "jpg";
|
|
17878
|
+
}
|
|
17879
|
+
|
|
17880
|
+
// modules/server/image-optimizer/index.ts
|
|
17881
|
+
async function downloadRemoteImage(url, timeout = 1e4) {
|
|
17882
|
+
let fetchFn;
|
|
17883
|
+
try {
|
|
17884
|
+
if (typeof fetch !== "undefined") {
|
|
17885
|
+
fetchFn = fetch;
|
|
17886
|
+
} else {
|
|
17887
|
+
const { fetch: undiciFetch } = await import("undici");
|
|
17888
|
+
fetchFn = undiciFetch;
|
|
17889
|
+
}
|
|
17890
|
+
} catch (error) {
|
|
17891
|
+
throw new Error("Failed to load fetch implementation. Node 18+ required or install undici.");
|
|
17892
|
+
}
|
|
17893
|
+
const controller = new AbortController();
|
|
17894
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
17895
|
+
try {
|
|
17896
|
+
const response = await fetchFn(url, {
|
|
17897
|
+
signal: controller.signal,
|
|
17898
|
+
headers: {
|
|
17899
|
+
"User-Agent": "Loly-Image-Optimizer/1.0"
|
|
17900
|
+
}
|
|
17901
|
+
});
|
|
17902
|
+
clearTimeout(timeoutId);
|
|
17903
|
+
if (!response.ok) {
|
|
17904
|
+
throw new Error(`Failed to download image: ${response.status} ${response.statusText}`);
|
|
17905
|
+
}
|
|
17906
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
17907
|
+
return Buffer.from(arrayBuffer);
|
|
17908
|
+
} catch (error) {
|
|
17909
|
+
clearTimeout(timeoutId);
|
|
17910
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
17911
|
+
throw new Error(`Image download timeout after ${timeout}ms`);
|
|
17912
|
+
}
|
|
17913
|
+
throw error;
|
|
17914
|
+
}
|
|
17915
|
+
}
|
|
17916
|
+
function readLocalImage(src, projectRoot, config) {
|
|
17917
|
+
const sanitized = sanitizeImagePath(src);
|
|
17918
|
+
const staticDir = getStaticDir(projectRoot, config);
|
|
17919
|
+
const staticPath = path33.join(staticDir, sanitized);
|
|
17920
|
+
if (fs25.existsSync(staticPath)) {
|
|
17921
|
+
return fs25.readFileSync(staticPath);
|
|
17922
|
+
}
|
|
17923
|
+
if (src.startsWith("/")) {
|
|
17924
|
+
const absolutePath = path33.join(projectRoot, sanitized);
|
|
17925
|
+
if (fs25.existsSync(absolutePath)) {
|
|
17926
|
+
return fs25.readFileSync(absolutePath);
|
|
17927
|
+
}
|
|
17928
|
+
}
|
|
17929
|
+
throw new Error(`Image not found: ${src}`);
|
|
17930
|
+
}
|
|
17931
|
+
function determineOutputFormat(sourceFormat, requestedFormat, config) {
|
|
17932
|
+
if (sourceFormat === "svg") {
|
|
17933
|
+
return "svg";
|
|
17934
|
+
}
|
|
17935
|
+
if (requestedFormat && requestedFormat !== "auto") {
|
|
17936
|
+
return requestedFormat;
|
|
17937
|
+
}
|
|
17938
|
+
const supportedFormats = config.formats || ["image/webp"];
|
|
17939
|
+
if (supportedFormats.includes("image/avif")) {
|
|
17940
|
+
return "avif";
|
|
17941
|
+
}
|
|
17942
|
+
if (supportedFormats.includes("image/webp")) {
|
|
17943
|
+
return "webp";
|
|
17944
|
+
}
|
|
17945
|
+
return sourceFormat === "svg" ? "jpeg" : sourceFormat;
|
|
17946
|
+
}
|
|
17947
|
+
async function optimizeImage(options, projectRoot, config) {
|
|
17948
|
+
const imageConfig = config.images || {};
|
|
17949
|
+
const dimValidation = validateImageDimensions(options.width, options.height, imageConfig);
|
|
17950
|
+
if (!dimValidation.valid) {
|
|
17951
|
+
throw new Error(dimValidation.error);
|
|
17952
|
+
}
|
|
17953
|
+
const qualityValidation = validateQuality(options.quality);
|
|
17954
|
+
if (!qualityValidation.valid) {
|
|
17955
|
+
throw new Error(qualityValidation.error);
|
|
17956
|
+
}
|
|
17957
|
+
if (isRemoteUrl(options.src)) {
|
|
17958
|
+
if (!validateRemoteUrl(options.src, imageConfig)) {
|
|
17959
|
+
throw new Error(`Remote image domain not allowed: ${options.src}`);
|
|
17960
|
+
}
|
|
17961
|
+
}
|
|
17962
|
+
const sourceFormat = path33.extname(options.src).slice(1).toLowerCase() || "jpeg";
|
|
17963
|
+
const outputFormat = determineOutputFormat(
|
|
17964
|
+
sourceFormat,
|
|
17965
|
+
options.format,
|
|
17966
|
+
imageConfig
|
|
17967
|
+
);
|
|
17968
|
+
const cacheKey = generateCacheKey(
|
|
17969
|
+
options.src,
|
|
17970
|
+
options.width,
|
|
17971
|
+
options.height,
|
|
17972
|
+
options.quality || imageConfig.quality || 75,
|
|
17973
|
+
outputFormat
|
|
17974
|
+
);
|
|
17975
|
+
const cacheDir = getCacheDir(projectRoot, config);
|
|
17976
|
+
const extension = getImageExtension(outputFormat);
|
|
17977
|
+
if (hasCachedImage(cacheKey, extension, cacheDir)) {
|
|
17978
|
+
const cached = readCachedImage(cacheKey, extension, cacheDir);
|
|
17979
|
+
if (cached) {
|
|
17980
|
+
const metadata2 = await sharp(cached).metadata();
|
|
17981
|
+
return {
|
|
17982
|
+
buffer: cached,
|
|
17983
|
+
format: outputFormat,
|
|
17984
|
+
mimeType: getImageMimeType(outputFormat),
|
|
17985
|
+
width: metadata2.width || options.width || 0,
|
|
17986
|
+
height: metadata2.height || options.height || 0
|
|
17987
|
+
};
|
|
17988
|
+
}
|
|
17989
|
+
}
|
|
17990
|
+
let imageBuffer;
|
|
17991
|
+
if (isRemoteUrl(options.src)) {
|
|
17992
|
+
imageBuffer = await downloadRemoteImage(options.src);
|
|
17993
|
+
} else {
|
|
17994
|
+
imageBuffer = readLocalImage(options.src, projectRoot, config);
|
|
17995
|
+
}
|
|
17996
|
+
if (outputFormat === "svg" || sourceFormat === "svg") {
|
|
17997
|
+
if (!imageConfig.dangerouslyAllowSVG) {
|
|
17998
|
+
throw new Error("SVG images are not allowed. Set images.dangerouslyAllowSVG to true to enable.");
|
|
17999
|
+
}
|
|
18000
|
+
return {
|
|
18001
|
+
buffer: imageBuffer,
|
|
18002
|
+
format: "svg",
|
|
18003
|
+
mimeType: "image/svg+xml",
|
|
18004
|
+
width: options.width || 0,
|
|
18005
|
+
height: options.height || 0
|
|
18006
|
+
};
|
|
18007
|
+
}
|
|
18008
|
+
let sharpInstance = sharp(imageBuffer);
|
|
18009
|
+
const metadata = await sharpInstance.metadata();
|
|
18010
|
+
if (options.width || options.height) {
|
|
18011
|
+
const fit = options.fit || "cover";
|
|
18012
|
+
sharpInstance = sharpInstance.resize(options.width, options.height, {
|
|
18013
|
+
fit,
|
|
18014
|
+
withoutEnlargement: true
|
|
18015
|
+
});
|
|
18016
|
+
}
|
|
18017
|
+
const quality = options.quality || imageConfig.quality || 75;
|
|
18018
|
+
switch (outputFormat) {
|
|
18019
|
+
case "webp":
|
|
18020
|
+
sharpInstance = sharpInstance.webp({ quality });
|
|
18021
|
+
break;
|
|
18022
|
+
case "avif":
|
|
18023
|
+
sharpInstance = sharpInstance.avif({ quality });
|
|
18024
|
+
break;
|
|
18025
|
+
case "jpeg":
|
|
18026
|
+
case "jpg":
|
|
18027
|
+
sharpInstance = sharpInstance.jpeg({ quality });
|
|
18028
|
+
break;
|
|
18029
|
+
case "png":
|
|
18030
|
+
sharpInstance = sharpInstance.png({ quality: Math.round(quality / 100 * 9) });
|
|
18031
|
+
break;
|
|
18032
|
+
default:
|
|
18033
|
+
sharpInstance = sharpInstance.jpeg({ quality });
|
|
18034
|
+
}
|
|
18035
|
+
const optimizedBuffer = await sharpInstance.toBuffer();
|
|
18036
|
+
const finalMetadata = await sharp(optimizedBuffer).metadata();
|
|
18037
|
+
writeCachedImage(cacheKey, extension, cacheDir, optimizedBuffer);
|
|
18038
|
+
return {
|
|
18039
|
+
buffer: optimizedBuffer,
|
|
18040
|
+
format: outputFormat,
|
|
18041
|
+
mimeType: getImageMimeType(outputFormat),
|
|
18042
|
+
width: finalMetadata.width || options.width || metadata.width || 0,
|
|
18043
|
+
height: finalMetadata.height || options.height || metadata.height || 0
|
|
18044
|
+
};
|
|
18045
|
+
}
|
|
18046
|
+
|
|
18047
|
+
// modules/server/handlers/image.ts
|
|
18048
|
+
async function handleImageRequest(options) {
|
|
18049
|
+
const { req, res, projectRoot, config } = options;
|
|
18050
|
+
try {
|
|
18051
|
+
const src = req.query.src;
|
|
18052
|
+
const width = req.query.w ? parseInt(req.query.w, 10) : void 0;
|
|
18053
|
+
const height = req.query.h ? parseInt(req.query.h, 10) : void 0;
|
|
18054
|
+
const quality = req.query.q ? parseInt(req.query.q, 10) : void 0;
|
|
18055
|
+
const format = req.query.format;
|
|
18056
|
+
const fit = req.query.fit;
|
|
18057
|
+
if (!src) {
|
|
18058
|
+
res.status(400).json({
|
|
18059
|
+
error: "Missing required parameter: src"
|
|
18060
|
+
});
|
|
18061
|
+
return;
|
|
18062
|
+
}
|
|
18063
|
+
if (typeof src !== "string") {
|
|
18064
|
+
res.status(400).json({
|
|
18065
|
+
error: "Parameter 'src' must be a string"
|
|
18066
|
+
});
|
|
18067
|
+
return;
|
|
18068
|
+
}
|
|
18069
|
+
const result = await optimizeImage(
|
|
18070
|
+
{
|
|
18071
|
+
src,
|
|
18072
|
+
width,
|
|
18073
|
+
height,
|
|
18074
|
+
quality,
|
|
18075
|
+
format,
|
|
18076
|
+
fit
|
|
18077
|
+
},
|
|
18078
|
+
projectRoot,
|
|
18079
|
+
config
|
|
18080
|
+
);
|
|
18081
|
+
const imageConfig = config.images || {};
|
|
18082
|
+
const cacheTTL = imageConfig.minimumCacheTTL || 60;
|
|
18083
|
+
res.setHeader("Content-Type", result.mimeType);
|
|
18084
|
+
res.setHeader("Content-Length", result.buffer.length);
|
|
18085
|
+
res.setHeader("Cache-Control", `public, max-age=${cacheTTL}, immutable`);
|
|
18086
|
+
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
18087
|
+
res.send(result.buffer);
|
|
18088
|
+
} catch (error) {
|
|
18089
|
+
if (error instanceof Error) {
|
|
18090
|
+
if (error.message.includes("not allowed")) {
|
|
18091
|
+
res.status(403).json({
|
|
18092
|
+
error: "Forbidden",
|
|
18093
|
+
message: error.message
|
|
18094
|
+
});
|
|
18095
|
+
return;
|
|
18096
|
+
}
|
|
18097
|
+
if (error.message.includes("not found") || error.message.includes("Image not found")) {
|
|
18098
|
+
res.status(404).json({
|
|
18099
|
+
error: "Not Found",
|
|
18100
|
+
message: error.message
|
|
18101
|
+
});
|
|
18102
|
+
return;
|
|
18103
|
+
}
|
|
18104
|
+
if (error.message.includes("must be")) {
|
|
18105
|
+
res.status(400).json({
|
|
18106
|
+
error: "Bad Request",
|
|
18107
|
+
message: error.message
|
|
18108
|
+
});
|
|
18109
|
+
return;
|
|
18110
|
+
}
|
|
18111
|
+
if (error.message.includes("timeout") || error.message.includes("download")) {
|
|
18112
|
+
res.status(504).json({
|
|
18113
|
+
error: "Gateway Timeout",
|
|
18114
|
+
message: error.message
|
|
18115
|
+
});
|
|
18116
|
+
return;
|
|
18117
|
+
}
|
|
18118
|
+
}
|
|
18119
|
+
console.error("[image-optimizer] Error processing image:", error);
|
|
18120
|
+
res.status(500).json({
|
|
18121
|
+
error: "Internal Server Error",
|
|
18122
|
+
message: "Failed to process image"
|
|
18123
|
+
});
|
|
18124
|
+
}
|
|
18125
|
+
}
|
|
18126
|
+
|
|
17627
18127
|
// modules/server/routes.ts
|
|
17628
18128
|
init_globals();
|
|
17629
|
-
import
|
|
18129
|
+
import path34 from "path";
|
|
17630
18130
|
var cachedRewriteLoader = null;
|
|
17631
18131
|
var cachedProjectRoot = null;
|
|
17632
18132
|
var cachedIsDev = null;
|
|
@@ -17654,10 +18154,20 @@ function setupRoutes(options) {
|
|
|
17654
18154
|
} = options;
|
|
17655
18155
|
const routeChunks = routeLoader.loadRouteChunks();
|
|
17656
18156
|
const rewriteLoader = getRewriteLoader(projectRoot, isDev);
|
|
17657
|
-
const ssgOutDir =
|
|
17658
|
-
config ? getBuildDir(projectRoot, config) :
|
|
18157
|
+
const ssgOutDir = path34.join(
|
|
18158
|
+
config ? getBuildDir(projectRoot, config) : path34.join(projectRoot, BUILD_FOLDER_NAME),
|
|
17659
18159
|
"ssg"
|
|
17660
18160
|
);
|
|
18161
|
+
if (config) {
|
|
18162
|
+
app.get("/_loly/image", async (req, res) => {
|
|
18163
|
+
await handleImageRequest({
|
|
18164
|
+
req,
|
|
18165
|
+
res,
|
|
18166
|
+
projectRoot,
|
|
18167
|
+
config
|
|
18168
|
+
});
|
|
18169
|
+
});
|
|
18170
|
+
}
|
|
17661
18171
|
app.all("/api/*", async (req, res) => {
|
|
17662
18172
|
const apiRoutes = isDev && getRoutes ? (await getRoutes()).apiRoutes : initialApiRoutes;
|
|
17663
18173
|
const serverConfig = await getServerConfig(projectRoot);
|
|
@@ -18704,7 +19214,7 @@ import cors from "cors";
|
|
|
18704
19214
|
import helmet from "helmet";
|
|
18705
19215
|
import cookieParser from "cookie-parser";
|
|
18706
19216
|
import compression from "compression";
|
|
18707
|
-
import
|
|
19217
|
+
import crypto2 from "crypto";
|
|
18708
19218
|
var setupApplication = async ({
|
|
18709
19219
|
projectRoot
|
|
18710
19220
|
}) => {
|
|
@@ -18813,7 +19323,7 @@ var setupApplication = async ({
|
|
|
18813
19323
|
if (process.env.NODE_ENV !== "development" && security?.contentSecurityPolicy !== false) {
|
|
18814
19324
|
app.use(
|
|
18815
19325
|
(req, res, next) => {
|
|
18816
|
-
const nonce =
|
|
19326
|
+
const nonce = crypto2.randomBytes(16).toString("base64");
|
|
18817
19327
|
res.locals.nonce = nonce;
|
|
18818
19328
|
next();
|
|
18819
19329
|
}
|
|
@@ -18884,8 +19394,8 @@ var setupApplication = async ({
|
|
|
18884
19394
|
|
|
18885
19395
|
// src/server.ts
|
|
18886
19396
|
import dotenv2 from "dotenv";
|
|
18887
|
-
var envPath =
|
|
18888
|
-
if (
|
|
19397
|
+
var envPath = path35.join(process.cwd(), ".env");
|
|
19398
|
+
if (fs26.existsSync(envPath)) {
|
|
18889
19399
|
dotenv2.config({ path: envPath });
|
|
18890
19400
|
} else {
|
|
18891
19401
|
dotenv2.config();
|
|
@@ -18906,8 +19416,8 @@ async function startServer(options = {}) {
|
|
|
18906
19416
|
}
|
|
18907
19417
|
const port = options.port ?? (process.env.PORT ? parseInt(process.env.PORT, 10) : void 0) ?? config.server.port;
|
|
18908
19418
|
const host = process.env.HOST ?? (!isDev ? "0.0.0.0" : void 0) ?? config.server.host;
|
|
18909
|
-
const appDir = options.appDir ?? (isDev ? getAppDir(projectRoot, config) :
|
|
18910
|
-
if (!isDev && !
|
|
19419
|
+
const appDir = options.appDir ?? (isDev ? getAppDir(projectRoot, config) : path35.join(getBuildDir(projectRoot, config), "server"));
|
|
19420
|
+
if (!isDev && !fs26.existsSync(appDir)) {
|
|
18911
19421
|
logger4.error("Compiled directory not found", void 0, {
|
|
18912
19422
|
buildDir: config.directories.build,
|
|
18913
19423
|
appDir,
|
|
@@ -19103,7 +19613,7 @@ async function run() {
|
|
|
19103
19613
|
}
|
|
19104
19614
|
const args = parseArgs(argv.slice(1));
|
|
19105
19615
|
const projectRoot = process2.cwd();
|
|
19106
|
-
const appDir =
|
|
19616
|
+
const appDir = path36.resolve(projectRoot, args.appDir || "app");
|
|
19107
19617
|
const port = typeof args.port === "string" && args.port.trim().length > 0 ? Number(args.port) : 3e3;
|
|
19108
19618
|
switch (command) {
|
|
19109
19619
|
case "dev": {
|