@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.cjs
CHANGED
|
@@ -9953,7 +9953,7 @@ var require_built3 = __commonJS({
|
|
|
9953
9953
|
});
|
|
9954
9954
|
|
|
9955
9955
|
// modules/cli/index.ts
|
|
9956
|
-
var
|
|
9956
|
+
var import_path40 = __toESM(require("path"));
|
|
9957
9957
|
var import_process = __toESM(require("process"));
|
|
9958
9958
|
|
|
9959
9959
|
// modules/build/index.ts
|
|
@@ -11742,6 +11742,7 @@ async function processRewrites(urlPath, compiledRewrites, req) {
|
|
|
11742
11742
|
const normalizedPath = urlPath.replace(/\/$/, "") || "/";
|
|
11743
11743
|
if (normalizedPath.startsWith("/static/") || // Static assets (client.js, client.css, etc.)
|
|
11744
11744
|
normalizedPath.startsWith("/__fw/") || // Framework internal routes (hot reload, etc.)
|
|
11745
|
+
normalizedPath.startsWith("/_loly/") || // Framework internal routes (image optimization, etc.)
|
|
11745
11746
|
normalizedPath === "/favicon.ico" || // Favicon
|
|
11746
11747
|
normalizedPath.startsWith("/wss/")) {
|
|
11747
11748
|
if (process.env.NODE_ENV === "development") {
|
|
@@ -12946,7 +12947,7 @@ function createDocumentTree(options) {
|
|
|
12946
12947
|
}),
|
|
12947
12948
|
...extraMetaTags,
|
|
12948
12949
|
...linkTags,
|
|
12949
|
-
...entrypointFiles.length > 0 ? entrypointFiles.
|
|
12950
|
+
...entrypointFiles.length > 0 ? entrypointFiles.map(
|
|
12950
12951
|
(file) => import_react.default.createElement("link", {
|
|
12951
12952
|
key: `preload-${file}`,
|
|
12952
12953
|
rel: "preload",
|
|
@@ -12967,6 +12968,13 @@ function createDocumentTree(options) {
|
|
|
12967
12968
|
href: faviconPath,
|
|
12968
12969
|
type: faviconType || (faviconPath.endsWith(".ico") ? "image/x-icon" : "image/png")
|
|
12969
12970
|
}),
|
|
12971
|
+
// Preload CSS para evitar bloqueo de renderizado
|
|
12972
|
+
import_react.default.createElement("link", {
|
|
12973
|
+
key: "preload-css",
|
|
12974
|
+
rel: "preload",
|
|
12975
|
+
href: clientCssPath,
|
|
12976
|
+
as: "style"
|
|
12977
|
+
}),
|
|
12970
12978
|
import_react.default.createElement("link", {
|
|
12971
12979
|
rel: "stylesheet",
|
|
12972
12980
|
href: clientCssPath
|
|
@@ -13168,12 +13176,12 @@ var DEFAULT_IGNORED_PATHS = [
|
|
|
13168
13176
|
/^\/sockjs-node/
|
|
13169
13177
|
// Hot reload websocket
|
|
13170
13178
|
];
|
|
13171
|
-
function shouldIgnorePath(
|
|
13179
|
+
function shouldIgnorePath(path37, ignoredPaths) {
|
|
13172
13180
|
return ignoredPaths.some((pattern) => {
|
|
13173
13181
|
if (typeof pattern === "string") {
|
|
13174
|
-
return
|
|
13182
|
+
return path37 === pattern || path37.startsWith(pattern);
|
|
13175
13183
|
}
|
|
13176
|
-
return pattern.test(
|
|
13184
|
+
return pattern.test(path37);
|
|
13177
13185
|
});
|
|
13178
13186
|
}
|
|
13179
13187
|
function requestLoggerMiddleware(options = {}) {
|
|
@@ -15136,7 +15144,20 @@ var DEFAULT_CONFIG2 = {
|
|
|
15136
15144
|
ssr: true,
|
|
15137
15145
|
ssg: true
|
|
15138
15146
|
},
|
|
15139
|
-
plugins: []
|
|
15147
|
+
plugins: [],
|
|
15148
|
+
images: {
|
|
15149
|
+
remotePatterns: [],
|
|
15150
|
+
domains: [],
|
|
15151
|
+
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
|
|
15152
|
+
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
|
|
15153
|
+
formats: ["image/webp", "image/avif"],
|
|
15154
|
+
quality: 75,
|
|
15155
|
+
minimumCacheTTL: 60,
|
|
15156
|
+
dangerouslyAllowSVG: false,
|
|
15157
|
+
contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;",
|
|
15158
|
+
maxWidth: 3840,
|
|
15159
|
+
maxHeight: 3840
|
|
15160
|
+
}
|
|
15140
15161
|
};
|
|
15141
15162
|
function deepMerge(target, source) {
|
|
15142
15163
|
const result = { ...target };
|
|
@@ -15253,6 +15274,53 @@ function validateConfig(config, projectRoot) {
|
|
|
15253
15274
|
if (typeof config.rendering.ssg !== "boolean") {
|
|
15254
15275
|
errors.push("config.rendering.ssg must be a boolean");
|
|
15255
15276
|
}
|
|
15277
|
+
if (config.images) {
|
|
15278
|
+
if (config.images.quality !== void 0) {
|
|
15279
|
+
if (typeof config.images.quality !== "number" || config.images.quality < 1 || config.images.quality > 100) {
|
|
15280
|
+
errors.push("config.images.quality must be a number between 1 and 100");
|
|
15281
|
+
}
|
|
15282
|
+
}
|
|
15283
|
+
if (config.images.minimumCacheTTL !== void 0) {
|
|
15284
|
+
if (typeof config.images.minimumCacheTTL !== "number" || config.images.minimumCacheTTL < 0) {
|
|
15285
|
+
errors.push("config.images.minimumCacheTTL must be a non-negative number");
|
|
15286
|
+
}
|
|
15287
|
+
}
|
|
15288
|
+
if (config.images.deviceSizes) {
|
|
15289
|
+
if (!Array.isArray(config.images.deviceSizes) || config.images.deviceSizes.some((s) => typeof s !== "number" || s <= 0)) {
|
|
15290
|
+
errors.push("config.images.deviceSizes must be an array of positive numbers");
|
|
15291
|
+
}
|
|
15292
|
+
}
|
|
15293
|
+
if (config.images.imageSizes) {
|
|
15294
|
+
if (!Array.isArray(config.images.imageSizes) || config.images.imageSizes.some((s) => typeof s !== "number" || s <= 0)) {
|
|
15295
|
+
errors.push("config.images.imageSizes must be an array of positive numbers");
|
|
15296
|
+
}
|
|
15297
|
+
}
|
|
15298
|
+
if (config.images.formats) {
|
|
15299
|
+
const validFormats = ["image/webp", "image/avif"];
|
|
15300
|
+
if (!Array.isArray(config.images.formats) || config.images.formats.some((f) => !validFormats.includes(f))) {
|
|
15301
|
+
errors.push(`config.images.formats must be an array containing only: ${validFormats.join(", ")}`);
|
|
15302
|
+
}
|
|
15303
|
+
}
|
|
15304
|
+
if (config.images.remotePatterns) {
|
|
15305
|
+
if (!Array.isArray(config.images.remotePatterns)) {
|
|
15306
|
+
errors.push("config.images.remotePatterns must be an array");
|
|
15307
|
+
} else {
|
|
15308
|
+
config.images.remotePatterns.forEach((pattern, idx) => {
|
|
15309
|
+
if (!pattern.hostname || typeof pattern.hostname !== "string") {
|
|
15310
|
+
errors.push(`config.images.remotePatterns[${idx}].hostname must be a non-empty string`);
|
|
15311
|
+
}
|
|
15312
|
+
if (pattern.protocol && !["http", "https"].includes(pattern.protocol)) {
|
|
15313
|
+
errors.push(`config.images.remotePatterns[${idx}].protocol must be 'http' or 'https'`);
|
|
15314
|
+
}
|
|
15315
|
+
});
|
|
15316
|
+
}
|
|
15317
|
+
}
|
|
15318
|
+
if (config.images.domains) {
|
|
15319
|
+
if (!Array.isArray(config.images.domains) || config.images.domains.some((d) => typeof d !== "string")) {
|
|
15320
|
+
errors.push("config.images.domains must be an array of strings");
|
|
15321
|
+
}
|
|
15322
|
+
}
|
|
15323
|
+
}
|
|
15256
15324
|
if (errors.length > 0) {
|
|
15257
15325
|
const errorMessage = [
|
|
15258
15326
|
"\u274C Configuration validation failed:",
|
|
@@ -15386,8 +15454,8 @@ async function buildApp(options = {}) {
|
|
|
15386
15454
|
}
|
|
15387
15455
|
|
|
15388
15456
|
// src/server.ts
|
|
15389
|
-
var
|
|
15390
|
-
var
|
|
15457
|
+
var import_fs28 = __toESM(require("fs"));
|
|
15458
|
+
var import_path39 = __toESM(require("path"));
|
|
15391
15459
|
|
|
15392
15460
|
// modules/server/setup.ts
|
|
15393
15461
|
var import_express = __toESM(require("express"));
|
|
@@ -15470,7 +15538,7 @@ var ReaddirpStream = class extends import_node_stream.Readable {
|
|
|
15470
15538
|
this._directoryFilter = normalizeFilter(opts.directoryFilter);
|
|
15471
15539
|
const statMethod = opts.lstat ? import_promises.lstat : import_promises.stat;
|
|
15472
15540
|
if (wantBigintFsStats) {
|
|
15473
|
-
this._stat = (
|
|
15541
|
+
this._stat = (path37) => statMethod(path37, { bigint: true });
|
|
15474
15542
|
} else {
|
|
15475
15543
|
this._stat = statMethod;
|
|
15476
15544
|
}
|
|
@@ -15495,8 +15563,8 @@ var ReaddirpStream = class extends import_node_stream.Readable {
|
|
|
15495
15563
|
const par = this.parent;
|
|
15496
15564
|
const fil = par && par.files;
|
|
15497
15565
|
if (fil && fil.length > 0) {
|
|
15498
|
-
const { path:
|
|
15499
|
-
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent,
|
|
15566
|
+
const { path: path37, depth } = par;
|
|
15567
|
+
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path37));
|
|
15500
15568
|
const awaited = await Promise.all(slice);
|
|
15501
15569
|
for (const entry of awaited) {
|
|
15502
15570
|
if (!entry)
|
|
@@ -15536,20 +15604,20 @@ var ReaddirpStream = class extends import_node_stream.Readable {
|
|
|
15536
15604
|
this.reading = false;
|
|
15537
15605
|
}
|
|
15538
15606
|
}
|
|
15539
|
-
async _exploreDir(
|
|
15607
|
+
async _exploreDir(path37, depth) {
|
|
15540
15608
|
let files;
|
|
15541
15609
|
try {
|
|
15542
|
-
files = await (0, import_promises.readdir)(
|
|
15610
|
+
files = await (0, import_promises.readdir)(path37, this._rdOptions);
|
|
15543
15611
|
} catch (error) {
|
|
15544
15612
|
this._onError(error);
|
|
15545
15613
|
}
|
|
15546
|
-
return { files, depth, path:
|
|
15614
|
+
return { files, depth, path: path37 };
|
|
15547
15615
|
}
|
|
15548
|
-
async _formatEntry(dirent,
|
|
15616
|
+
async _formatEntry(dirent, path37) {
|
|
15549
15617
|
let entry;
|
|
15550
15618
|
const basename3 = this._isDirent ? dirent.name : dirent;
|
|
15551
15619
|
try {
|
|
15552
|
-
const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(
|
|
15620
|
+
const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(path37, basename3));
|
|
15553
15621
|
entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename: basename3 };
|
|
15554
15622
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
15555
15623
|
} catch (err) {
|
|
@@ -15949,16 +16017,16 @@ var delFromSet = (main, prop, item) => {
|
|
|
15949
16017
|
};
|
|
15950
16018
|
var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
|
|
15951
16019
|
var FsWatchInstances = /* @__PURE__ */ new Map();
|
|
15952
|
-
function createFsWatchInstance(
|
|
16020
|
+
function createFsWatchInstance(path37, options, listener, errHandler, emitRaw) {
|
|
15953
16021
|
const handleEvent = (rawEvent, evPath) => {
|
|
15954
|
-
listener(
|
|
15955
|
-
emitRaw(rawEvent, evPath, { watchedPath:
|
|
15956
|
-
if (evPath &&
|
|
15957
|
-
fsWatchBroadcast(sysPath.resolve(
|
|
16022
|
+
listener(path37);
|
|
16023
|
+
emitRaw(rawEvent, evPath, { watchedPath: path37 });
|
|
16024
|
+
if (evPath && path37 !== evPath) {
|
|
16025
|
+
fsWatchBroadcast(sysPath.resolve(path37, evPath), KEY_LISTENERS, sysPath.join(path37, evPath));
|
|
15958
16026
|
}
|
|
15959
16027
|
};
|
|
15960
16028
|
try {
|
|
15961
|
-
return (0, import_fs23.watch)(
|
|
16029
|
+
return (0, import_fs23.watch)(path37, {
|
|
15962
16030
|
persistent: options.persistent
|
|
15963
16031
|
}, handleEvent);
|
|
15964
16032
|
} catch (error) {
|
|
@@ -15974,12 +16042,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
|
|
|
15974
16042
|
listener(val1, val2, val3);
|
|
15975
16043
|
});
|
|
15976
16044
|
};
|
|
15977
|
-
var setFsWatchListener = (
|
|
16045
|
+
var setFsWatchListener = (path37, fullPath, options, handlers) => {
|
|
15978
16046
|
const { listener, errHandler, rawEmitter } = handlers;
|
|
15979
16047
|
let cont = FsWatchInstances.get(fullPath);
|
|
15980
16048
|
let watcher;
|
|
15981
16049
|
if (!options.persistent) {
|
|
15982
|
-
watcher = createFsWatchInstance(
|
|
16050
|
+
watcher = createFsWatchInstance(path37, options, listener, errHandler, rawEmitter);
|
|
15983
16051
|
if (!watcher)
|
|
15984
16052
|
return;
|
|
15985
16053
|
return watcher.close.bind(watcher);
|
|
@@ -15990,7 +16058,7 @@ var setFsWatchListener = (path34, fullPath, options, handlers) => {
|
|
|
15990
16058
|
addAndConvert(cont, KEY_RAW, rawEmitter);
|
|
15991
16059
|
} else {
|
|
15992
16060
|
watcher = createFsWatchInstance(
|
|
15993
|
-
|
|
16061
|
+
path37,
|
|
15994
16062
|
options,
|
|
15995
16063
|
fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
|
|
15996
16064
|
errHandler,
|
|
@@ -16005,7 +16073,7 @@ var setFsWatchListener = (path34, fullPath, options, handlers) => {
|
|
|
16005
16073
|
cont.watcherUnusable = true;
|
|
16006
16074
|
if (isWindows && error.code === "EPERM") {
|
|
16007
16075
|
try {
|
|
16008
|
-
const fd = await (0, import_promises2.open)(
|
|
16076
|
+
const fd = await (0, import_promises2.open)(path37, "r");
|
|
16009
16077
|
await fd.close();
|
|
16010
16078
|
broadcastErr(error);
|
|
16011
16079
|
} catch (err) {
|
|
@@ -16036,7 +16104,7 @@ var setFsWatchListener = (path34, fullPath, options, handlers) => {
|
|
|
16036
16104
|
};
|
|
16037
16105
|
};
|
|
16038
16106
|
var FsWatchFileInstances = /* @__PURE__ */ new Map();
|
|
16039
|
-
var setFsWatchFileListener = (
|
|
16107
|
+
var setFsWatchFileListener = (path37, fullPath, options, handlers) => {
|
|
16040
16108
|
const { listener, rawEmitter } = handlers;
|
|
16041
16109
|
let cont = FsWatchFileInstances.get(fullPath);
|
|
16042
16110
|
const copts = cont && cont.options;
|
|
@@ -16058,7 +16126,7 @@ var setFsWatchFileListener = (path34, fullPath, options, handlers) => {
|
|
|
16058
16126
|
});
|
|
16059
16127
|
const currmtime = curr.mtimeMs;
|
|
16060
16128
|
if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
|
|
16061
|
-
foreach(cont.listeners, (listener2) => listener2(
|
|
16129
|
+
foreach(cont.listeners, (listener2) => listener2(path37, curr));
|
|
16062
16130
|
}
|
|
16063
16131
|
})
|
|
16064
16132
|
};
|
|
@@ -16086,13 +16154,13 @@ var NodeFsHandler = class {
|
|
|
16086
16154
|
* @param listener on fs change
|
|
16087
16155
|
* @returns closer for the watcher instance
|
|
16088
16156
|
*/
|
|
16089
|
-
_watchWithNodeFs(
|
|
16157
|
+
_watchWithNodeFs(path37, listener) {
|
|
16090
16158
|
const opts = this.fsw.options;
|
|
16091
|
-
const directory = sysPath.dirname(
|
|
16092
|
-
const basename3 = sysPath.basename(
|
|
16159
|
+
const directory = sysPath.dirname(path37);
|
|
16160
|
+
const basename3 = sysPath.basename(path37);
|
|
16093
16161
|
const parent = this.fsw._getWatchedDir(directory);
|
|
16094
16162
|
parent.add(basename3);
|
|
16095
|
-
const absolutePath = sysPath.resolve(
|
|
16163
|
+
const absolutePath = sysPath.resolve(path37);
|
|
16096
16164
|
const options = {
|
|
16097
16165
|
persistent: opts.persistent
|
|
16098
16166
|
};
|
|
@@ -16102,12 +16170,12 @@ var NodeFsHandler = class {
|
|
|
16102
16170
|
if (opts.usePolling) {
|
|
16103
16171
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
16104
16172
|
options.interval = enableBin && isBinaryPath(basename3) ? opts.binaryInterval : opts.interval;
|
|
16105
|
-
closer = setFsWatchFileListener(
|
|
16173
|
+
closer = setFsWatchFileListener(path37, absolutePath, options, {
|
|
16106
16174
|
listener,
|
|
16107
16175
|
rawEmitter: this.fsw._emitRaw
|
|
16108
16176
|
});
|
|
16109
16177
|
} else {
|
|
16110
|
-
closer = setFsWatchListener(
|
|
16178
|
+
closer = setFsWatchListener(path37, absolutePath, options, {
|
|
16111
16179
|
listener,
|
|
16112
16180
|
errHandler: this._boundHandleError,
|
|
16113
16181
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -16129,7 +16197,7 @@ var NodeFsHandler = class {
|
|
|
16129
16197
|
let prevStats = stats;
|
|
16130
16198
|
if (parent.has(basename3))
|
|
16131
16199
|
return;
|
|
16132
|
-
const listener = async (
|
|
16200
|
+
const listener = async (path37, newStats) => {
|
|
16133
16201
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
|
|
16134
16202
|
return;
|
|
16135
16203
|
if (!newStats || newStats.mtimeMs === 0) {
|
|
@@ -16143,11 +16211,11 @@ var NodeFsHandler = class {
|
|
|
16143
16211
|
this.fsw._emit(EV.CHANGE, file, newStats2);
|
|
16144
16212
|
}
|
|
16145
16213
|
if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
|
|
16146
|
-
this.fsw._closeFile(
|
|
16214
|
+
this.fsw._closeFile(path37);
|
|
16147
16215
|
prevStats = newStats2;
|
|
16148
16216
|
const closer2 = this._watchWithNodeFs(file, listener);
|
|
16149
16217
|
if (closer2)
|
|
16150
|
-
this.fsw._addPathCloser(
|
|
16218
|
+
this.fsw._addPathCloser(path37, closer2);
|
|
16151
16219
|
} else {
|
|
16152
16220
|
prevStats = newStats2;
|
|
16153
16221
|
}
|
|
@@ -16179,7 +16247,7 @@ var NodeFsHandler = class {
|
|
|
16179
16247
|
* @param item basename of this item
|
|
16180
16248
|
* @returns true if no more processing is needed for this entry.
|
|
16181
16249
|
*/
|
|
16182
|
-
async _handleSymlink(entry, directory,
|
|
16250
|
+
async _handleSymlink(entry, directory, path37, item) {
|
|
16183
16251
|
if (this.fsw.closed) {
|
|
16184
16252
|
return;
|
|
16185
16253
|
}
|
|
@@ -16189,7 +16257,7 @@ var NodeFsHandler = class {
|
|
|
16189
16257
|
this.fsw._incrReadyCount();
|
|
16190
16258
|
let linkPath;
|
|
16191
16259
|
try {
|
|
16192
|
-
linkPath = await (0, import_promises2.realpath)(
|
|
16260
|
+
linkPath = await (0, import_promises2.realpath)(path37);
|
|
16193
16261
|
} catch (e) {
|
|
16194
16262
|
this.fsw._emitReady();
|
|
16195
16263
|
return true;
|
|
@@ -16199,12 +16267,12 @@ var NodeFsHandler = class {
|
|
|
16199
16267
|
if (dir.has(item)) {
|
|
16200
16268
|
if (this.fsw._symlinkPaths.get(full) !== linkPath) {
|
|
16201
16269
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
16202
|
-
this.fsw._emit(EV.CHANGE,
|
|
16270
|
+
this.fsw._emit(EV.CHANGE, path37, entry.stats);
|
|
16203
16271
|
}
|
|
16204
16272
|
} else {
|
|
16205
16273
|
dir.add(item);
|
|
16206
16274
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
16207
|
-
this.fsw._emit(EV.ADD,
|
|
16275
|
+
this.fsw._emit(EV.ADD, path37, entry.stats);
|
|
16208
16276
|
}
|
|
16209
16277
|
this.fsw._emitReady();
|
|
16210
16278
|
return true;
|
|
@@ -16233,9 +16301,9 @@ var NodeFsHandler = class {
|
|
|
16233
16301
|
return;
|
|
16234
16302
|
}
|
|
16235
16303
|
const item = entry.path;
|
|
16236
|
-
let
|
|
16304
|
+
let path37 = sysPath.join(directory, item);
|
|
16237
16305
|
current.add(item);
|
|
16238
|
-
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory,
|
|
16306
|
+
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path37, item)) {
|
|
16239
16307
|
return;
|
|
16240
16308
|
}
|
|
16241
16309
|
if (this.fsw.closed) {
|
|
@@ -16244,8 +16312,8 @@ var NodeFsHandler = class {
|
|
|
16244
16312
|
}
|
|
16245
16313
|
if (item === target || !target && !previous.has(item)) {
|
|
16246
16314
|
this.fsw._incrReadyCount();
|
|
16247
|
-
|
|
16248
|
-
this._addToNodeFs(
|
|
16315
|
+
path37 = sysPath.join(dir, sysPath.relative(dir, path37));
|
|
16316
|
+
this._addToNodeFs(path37, initialAdd, wh, depth + 1);
|
|
16249
16317
|
}
|
|
16250
16318
|
}).on(EV.ERROR, this._boundHandleError);
|
|
16251
16319
|
return new Promise((resolve3, reject) => {
|
|
@@ -16314,13 +16382,13 @@ var NodeFsHandler = class {
|
|
|
16314
16382
|
* @param depth Child path actually targeted for watch
|
|
16315
16383
|
* @param target Child path actually targeted for watch
|
|
16316
16384
|
*/
|
|
16317
|
-
async _addToNodeFs(
|
|
16385
|
+
async _addToNodeFs(path37, initialAdd, priorWh, depth, target) {
|
|
16318
16386
|
const ready = this.fsw._emitReady;
|
|
16319
|
-
if (this.fsw._isIgnored(
|
|
16387
|
+
if (this.fsw._isIgnored(path37) || this.fsw.closed) {
|
|
16320
16388
|
ready();
|
|
16321
16389
|
return false;
|
|
16322
16390
|
}
|
|
16323
|
-
const wh = this.fsw._getWatchHelpers(
|
|
16391
|
+
const wh = this.fsw._getWatchHelpers(path37);
|
|
16324
16392
|
if (priorWh) {
|
|
16325
16393
|
wh.filterPath = (entry) => priorWh.filterPath(entry);
|
|
16326
16394
|
wh.filterDir = (entry) => priorWh.filterDir(entry);
|
|
@@ -16336,8 +16404,8 @@ var NodeFsHandler = class {
|
|
|
16336
16404
|
const follow = this.fsw.options.followSymlinks;
|
|
16337
16405
|
let closer;
|
|
16338
16406
|
if (stats.isDirectory()) {
|
|
16339
|
-
const absPath = sysPath.resolve(
|
|
16340
|
-
const targetPath = follow ? await (0, import_promises2.realpath)(
|
|
16407
|
+
const absPath = sysPath.resolve(path37);
|
|
16408
|
+
const targetPath = follow ? await (0, import_promises2.realpath)(path37) : path37;
|
|
16341
16409
|
if (this.fsw.closed)
|
|
16342
16410
|
return;
|
|
16343
16411
|
closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
|
|
@@ -16347,29 +16415,29 @@ var NodeFsHandler = class {
|
|
|
16347
16415
|
this.fsw._symlinkPaths.set(absPath, targetPath);
|
|
16348
16416
|
}
|
|
16349
16417
|
} else if (stats.isSymbolicLink()) {
|
|
16350
|
-
const targetPath = follow ? await (0, import_promises2.realpath)(
|
|
16418
|
+
const targetPath = follow ? await (0, import_promises2.realpath)(path37) : path37;
|
|
16351
16419
|
if (this.fsw.closed)
|
|
16352
16420
|
return;
|
|
16353
16421
|
const parent = sysPath.dirname(wh.watchPath);
|
|
16354
16422
|
this.fsw._getWatchedDir(parent).add(wh.watchPath);
|
|
16355
16423
|
this.fsw._emit(EV.ADD, wh.watchPath, stats);
|
|
16356
|
-
closer = await this._handleDir(parent, stats, initialAdd, depth,
|
|
16424
|
+
closer = await this._handleDir(parent, stats, initialAdd, depth, path37, wh, targetPath);
|
|
16357
16425
|
if (this.fsw.closed)
|
|
16358
16426
|
return;
|
|
16359
16427
|
if (targetPath !== void 0) {
|
|
16360
|
-
this.fsw._symlinkPaths.set(sysPath.resolve(
|
|
16428
|
+
this.fsw._symlinkPaths.set(sysPath.resolve(path37), targetPath);
|
|
16361
16429
|
}
|
|
16362
16430
|
} else {
|
|
16363
16431
|
closer = this._handleFile(wh.watchPath, stats, initialAdd);
|
|
16364
16432
|
}
|
|
16365
16433
|
ready();
|
|
16366
16434
|
if (closer)
|
|
16367
|
-
this.fsw._addPathCloser(
|
|
16435
|
+
this.fsw._addPathCloser(path37, closer);
|
|
16368
16436
|
return false;
|
|
16369
16437
|
} catch (error) {
|
|
16370
16438
|
if (this.fsw._handleError(error)) {
|
|
16371
16439
|
ready();
|
|
16372
|
-
return
|
|
16440
|
+
return path37;
|
|
16373
16441
|
}
|
|
16374
16442
|
}
|
|
16375
16443
|
}
|
|
@@ -16412,26 +16480,26 @@ function createPattern(matcher) {
|
|
|
16412
16480
|
}
|
|
16413
16481
|
return () => false;
|
|
16414
16482
|
}
|
|
16415
|
-
function normalizePath(
|
|
16416
|
-
if (typeof
|
|
16483
|
+
function normalizePath(path37) {
|
|
16484
|
+
if (typeof path37 !== "string")
|
|
16417
16485
|
throw new Error("string expected");
|
|
16418
|
-
|
|
16419
|
-
|
|
16486
|
+
path37 = sysPath2.normalize(path37);
|
|
16487
|
+
path37 = path37.replace(/\\/g, "/");
|
|
16420
16488
|
let prepend = false;
|
|
16421
|
-
if (
|
|
16489
|
+
if (path37.startsWith("//"))
|
|
16422
16490
|
prepend = true;
|
|
16423
16491
|
const DOUBLE_SLASH_RE2 = /\/\//;
|
|
16424
|
-
while (
|
|
16425
|
-
|
|
16492
|
+
while (path37.match(DOUBLE_SLASH_RE2))
|
|
16493
|
+
path37 = path37.replace(DOUBLE_SLASH_RE2, "/");
|
|
16426
16494
|
if (prepend)
|
|
16427
|
-
|
|
16428
|
-
return
|
|
16495
|
+
path37 = "/" + path37;
|
|
16496
|
+
return path37;
|
|
16429
16497
|
}
|
|
16430
16498
|
function matchPatterns(patterns, testString, stats) {
|
|
16431
|
-
const
|
|
16499
|
+
const path37 = normalizePath(testString);
|
|
16432
16500
|
for (let index = 0; index < patterns.length; index++) {
|
|
16433
16501
|
const pattern = patterns[index];
|
|
16434
|
-
if (pattern(
|
|
16502
|
+
if (pattern(path37, stats)) {
|
|
16435
16503
|
return true;
|
|
16436
16504
|
}
|
|
16437
16505
|
}
|
|
@@ -16471,19 +16539,19 @@ var toUnix = (string) => {
|
|
|
16471
16539
|
}
|
|
16472
16540
|
return str;
|
|
16473
16541
|
};
|
|
16474
|
-
var normalizePathToUnix = (
|
|
16475
|
-
var normalizeIgnored = (cwd = "") => (
|
|
16476
|
-
if (typeof
|
|
16477
|
-
return normalizePathToUnix(sysPath2.isAbsolute(
|
|
16542
|
+
var normalizePathToUnix = (path37) => toUnix(sysPath2.normalize(toUnix(path37)));
|
|
16543
|
+
var normalizeIgnored = (cwd = "") => (path37) => {
|
|
16544
|
+
if (typeof path37 === "string") {
|
|
16545
|
+
return normalizePathToUnix(sysPath2.isAbsolute(path37) ? path37 : sysPath2.join(cwd, path37));
|
|
16478
16546
|
} else {
|
|
16479
|
-
return
|
|
16547
|
+
return path37;
|
|
16480
16548
|
}
|
|
16481
16549
|
};
|
|
16482
|
-
var getAbsolutePath = (
|
|
16483
|
-
if (sysPath2.isAbsolute(
|
|
16484
|
-
return
|
|
16550
|
+
var getAbsolutePath = (path37, cwd) => {
|
|
16551
|
+
if (sysPath2.isAbsolute(path37)) {
|
|
16552
|
+
return path37;
|
|
16485
16553
|
}
|
|
16486
|
-
return sysPath2.join(cwd,
|
|
16554
|
+
return sysPath2.join(cwd, path37);
|
|
16487
16555
|
};
|
|
16488
16556
|
var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
|
|
16489
16557
|
var DirEntry = class {
|
|
@@ -16538,10 +16606,10 @@ var DirEntry = class {
|
|
|
16538
16606
|
var STAT_METHOD_F = "stat";
|
|
16539
16607
|
var STAT_METHOD_L = "lstat";
|
|
16540
16608
|
var WatchHelper = class {
|
|
16541
|
-
constructor(
|
|
16609
|
+
constructor(path37, follow, fsw) {
|
|
16542
16610
|
this.fsw = fsw;
|
|
16543
|
-
const watchPath =
|
|
16544
|
-
this.path =
|
|
16611
|
+
const watchPath = path37;
|
|
16612
|
+
this.path = path37 = path37.replace(REPLACER_RE, "");
|
|
16545
16613
|
this.watchPath = watchPath;
|
|
16546
16614
|
this.fullWatchPath = sysPath2.resolve(watchPath);
|
|
16547
16615
|
this.dirParts = [];
|
|
@@ -16663,20 +16731,20 @@ var FSWatcher = class extends import_events.EventEmitter {
|
|
|
16663
16731
|
this._closePromise = void 0;
|
|
16664
16732
|
let paths = unifyPaths(paths_);
|
|
16665
16733
|
if (cwd) {
|
|
16666
|
-
paths = paths.map((
|
|
16667
|
-
const absPath = getAbsolutePath(
|
|
16734
|
+
paths = paths.map((path37) => {
|
|
16735
|
+
const absPath = getAbsolutePath(path37, cwd);
|
|
16668
16736
|
return absPath;
|
|
16669
16737
|
});
|
|
16670
16738
|
}
|
|
16671
|
-
paths.forEach((
|
|
16672
|
-
this._removeIgnoredPath(
|
|
16739
|
+
paths.forEach((path37) => {
|
|
16740
|
+
this._removeIgnoredPath(path37);
|
|
16673
16741
|
});
|
|
16674
16742
|
this._userIgnored = void 0;
|
|
16675
16743
|
if (!this._readyCount)
|
|
16676
16744
|
this._readyCount = 0;
|
|
16677
16745
|
this._readyCount += paths.length;
|
|
16678
|
-
Promise.all(paths.map(async (
|
|
16679
|
-
const res = await this._nodeFsHandler._addToNodeFs(
|
|
16746
|
+
Promise.all(paths.map(async (path37) => {
|
|
16747
|
+
const res = await this._nodeFsHandler._addToNodeFs(path37, !_internal, void 0, 0, _origAdd);
|
|
16680
16748
|
if (res)
|
|
16681
16749
|
this._emitReady();
|
|
16682
16750
|
return res;
|
|
@@ -16698,17 +16766,17 @@ var FSWatcher = class extends import_events.EventEmitter {
|
|
|
16698
16766
|
return this;
|
|
16699
16767
|
const paths = unifyPaths(paths_);
|
|
16700
16768
|
const { cwd } = this.options;
|
|
16701
|
-
paths.forEach((
|
|
16702
|
-
if (!sysPath2.isAbsolute(
|
|
16769
|
+
paths.forEach((path37) => {
|
|
16770
|
+
if (!sysPath2.isAbsolute(path37) && !this._closers.has(path37)) {
|
|
16703
16771
|
if (cwd)
|
|
16704
|
-
|
|
16705
|
-
|
|
16772
|
+
path37 = sysPath2.join(cwd, path37);
|
|
16773
|
+
path37 = sysPath2.resolve(path37);
|
|
16706
16774
|
}
|
|
16707
|
-
this._closePath(
|
|
16708
|
-
this._addIgnoredPath(
|
|
16709
|
-
if (this._watched.has(
|
|
16775
|
+
this._closePath(path37);
|
|
16776
|
+
this._addIgnoredPath(path37);
|
|
16777
|
+
if (this._watched.has(path37)) {
|
|
16710
16778
|
this._addIgnoredPath({
|
|
16711
|
-
path:
|
|
16779
|
+
path: path37,
|
|
16712
16780
|
recursive: true
|
|
16713
16781
|
});
|
|
16714
16782
|
}
|
|
@@ -16772,38 +16840,38 @@ var FSWatcher = class extends import_events.EventEmitter {
|
|
|
16772
16840
|
* @param stats arguments to be passed with event
|
|
16773
16841
|
* @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
|
|
16774
16842
|
*/
|
|
16775
|
-
async _emit(event,
|
|
16843
|
+
async _emit(event, path37, stats) {
|
|
16776
16844
|
if (this.closed)
|
|
16777
16845
|
return;
|
|
16778
16846
|
const opts = this.options;
|
|
16779
16847
|
if (isWindows)
|
|
16780
|
-
|
|
16848
|
+
path37 = sysPath2.normalize(path37);
|
|
16781
16849
|
if (opts.cwd)
|
|
16782
|
-
|
|
16783
|
-
const args = [
|
|
16850
|
+
path37 = sysPath2.relative(opts.cwd, path37);
|
|
16851
|
+
const args = [path37];
|
|
16784
16852
|
if (stats != null)
|
|
16785
16853
|
args.push(stats);
|
|
16786
16854
|
const awf = opts.awaitWriteFinish;
|
|
16787
16855
|
let pw;
|
|
16788
|
-
if (awf && (pw = this._pendingWrites.get(
|
|
16856
|
+
if (awf && (pw = this._pendingWrites.get(path37))) {
|
|
16789
16857
|
pw.lastChange = /* @__PURE__ */ new Date();
|
|
16790
16858
|
return this;
|
|
16791
16859
|
}
|
|
16792
16860
|
if (opts.atomic) {
|
|
16793
16861
|
if (event === EVENTS.UNLINK) {
|
|
16794
|
-
this._pendingUnlinks.set(
|
|
16862
|
+
this._pendingUnlinks.set(path37, [event, ...args]);
|
|
16795
16863
|
setTimeout(() => {
|
|
16796
|
-
this._pendingUnlinks.forEach((entry,
|
|
16864
|
+
this._pendingUnlinks.forEach((entry, path38) => {
|
|
16797
16865
|
this.emit(...entry);
|
|
16798
16866
|
this.emit(EVENTS.ALL, ...entry);
|
|
16799
|
-
this._pendingUnlinks.delete(
|
|
16867
|
+
this._pendingUnlinks.delete(path38);
|
|
16800
16868
|
});
|
|
16801
16869
|
}, typeof opts.atomic === "number" ? opts.atomic : 100);
|
|
16802
16870
|
return this;
|
|
16803
16871
|
}
|
|
16804
|
-
if (event === EVENTS.ADD && this._pendingUnlinks.has(
|
|
16872
|
+
if (event === EVENTS.ADD && this._pendingUnlinks.has(path37)) {
|
|
16805
16873
|
event = EVENTS.CHANGE;
|
|
16806
|
-
this._pendingUnlinks.delete(
|
|
16874
|
+
this._pendingUnlinks.delete(path37);
|
|
16807
16875
|
}
|
|
16808
16876
|
}
|
|
16809
16877
|
if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
|
|
@@ -16821,16 +16889,16 @@ var FSWatcher = class extends import_events.EventEmitter {
|
|
|
16821
16889
|
this.emitWithAll(event, args);
|
|
16822
16890
|
}
|
|
16823
16891
|
};
|
|
16824
|
-
this._awaitWriteFinish(
|
|
16892
|
+
this._awaitWriteFinish(path37, awf.stabilityThreshold, event, awfEmit);
|
|
16825
16893
|
return this;
|
|
16826
16894
|
}
|
|
16827
16895
|
if (event === EVENTS.CHANGE) {
|
|
16828
|
-
const isThrottled = !this._throttle(EVENTS.CHANGE,
|
|
16896
|
+
const isThrottled = !this._throttle(EVENTS.CHANGE, path37, 50);
|
|
16829
16897
|
if (isThrottled)
|
|
16830
16898
|
return this;
|
|
16831
16899
|
}
|
|
16832
16900
|
if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
|
|
16833
|
-
const fullPath = opts.cwd ? sysPath2.join(opts.cwd,
|
|
16901
|
+
const fullPath = opts.cwd ? sysPath2.join(opts.cwd, path37) : path37;
|
|
16834
16902
|
let stats2;
|
|
16835
16903
|
try {
|
|
16836
16904
|
stats2 = await (0, import_promises3.stat)(fullPath);
|
|
@@ -16861,23 +16929,23 @@ var FSWatcher = class extends import_events.EventEmitter {
|
|
|
16861
16929
|
* @param timeout duration of time to suppress duplicate actions
|
|
16862
16930
|
* @returns tracking object or false if action should be suppressed
|
|
16863
16931
|
*/
|
|
16864
|
-
_throttle(actionType,
|
|
16932
|
+
_throttle(actionType, path37, timeout) {
|
|
16865
16933
|
if (!this._throttled.has(actionType)) {
|
|
16866
16934
|
this._throttled.set(actionType, /* @__PURE__ */ new Map());
|
|
16867
16935
|
}
|
|
16868
16936
|
const action = this._throttled.get(actionType);
|
|
16869
16937
|
if (!action)
|
|
16870
16938
|
throw new Error("invalid throttle");
|
|
16871
|
-
const actionPath = action.get(
|
|
16939
|
+
const actionPath = action.get(path37);
|
|
16872
16940
|
if (actionPath) {
|
|
16873
16941
|
actionPath.count++;
|
|
16874
16942
|
return false;
|
|
16875
16943
|
}
|
|
16876
16944
|
let timeoutObject;
|
|
16877
16945
|
const clear = () => {
|
|
16878
|
-
const item = action.get(
|
|
16946
|
+
const item = action.get(path37);
|
|
16879
16947
|
const count = item ? item.count : 0;
|
|
16880
|
-
action.delete(
|
|
16948
|
+
action.delete(path37);
|
|
16881
16949
|
clearTimeout(timeoutObject);
|
|
16882
16950
|
if (item)
|
|
16883
16951
|
clearTimeout(item.timeoutObject);
|
|
@@ -16885,7 +16953,7 @@ var FSWatcher = class extends import_events.EventEmitter {
|
|
|
16885
16953
|
};
|
|
16886
16954
|
timeoutObject = setTimeout(clear, timeout);
|
|
16887
16955
|
const thr = { timeoutObject, clear, count: 0 };
|
|
16888
|
-
action.set(
|
|
16956
|
+
action.set(path37, thr);
|
|
16889
16957
|
return thr;
|
|
16890
16958
|
}
|
|
16891
16959
|
_incrReadyCount() {
|
|
@@ -16899,44 +16967,44 @@ var FSWatcher = class extends import_events.EventEmitter {
|
|
|
16899
16967
|
* @param event
|
|
16900
16968
|
* @param awfEmit Callback to be called when ready for event to be emitted.
|
|
16901
16969
|
*/
|
|
16902
|
-
_awaitWriteFinish(
|
|
16970
|
+
_awaitWriteFinish(path37, threshold, event, awfEmit) {
|
|
16903
16971
|
const awf = this.options.awaitWriteFinish;
|
|
16904
16972
|
if (typeof awf !== "object")
|
|
16905
16973
|
return;
|
|
16906
16974
|
const pollInterval = awf.pollInterval;
|
|
16907
16975
|
let timeoutHandler;
|
|
16908
|
-
let fullPath =
|
|
16909
|
-
if (this.options.cwd && !sysPath2.isAbsolute(
|
|
16910
|
-
fullPath = sysPath2.join(this.options.cwd,
|
|
16976
|
+
let fullPath = path37;
|
|
16977
|
+
if (this.options.cwd && !sysPath2.isAbsolute(path37)) {
|
|
16978
|
+
fullPath = sysPath2.join(this.options.cwd, path37);
|
|
16911
16979
|
}
|
|
16912
16980
|
const now = /* @__PURE__ */ new Date();
|
|
16913
16981
|
const writes = this._pendingWrites;
|
|
16914
16982
|
function awaitWriteFinishFn(prevStat) {
|
|
16915
16983
|
(0, import_fs24.stat)(fullPath, (err, curStat) => {
|
|
16916
|
-
if (err || !writes.has(
|
|
16984
|
+
if (err || !writes.has(path37)) {
|
|
16917
16985
|
if (err && err.code !== "ENOENT")
|
|
16918
16986
|
awfEmit(err);
|
|
16919
16987
|
return;
|
|
16920
16988
|
}
|
|
16921
16989
|
const now2 = Number(/* @__PURE__ */ new Date());
|
|
16922
16990
|
if (prevStat && curStat.size !== prevStat.size) {
|
|
16923
|
-
writes.get(
|
|
16991
|
+
writes.get(path37).lastChange = now2;
|
|
16924
16992
|
}
|
|
16925
|
-
const pw = writes.get(
|
|
16993
|
+
const pw = writes.get(path37);
|
|
16926
16994
|
const df = now2 - pw.lastChange;
|
|
16927
16995
|
if (df >= threshold) {
|
|
16928
|
-
writes.delete(
|
|
16996
|
+
writes.delete(path37);
|
|
16929
16997
|
awfEmit(void 0, curStat);
|
|
16930
16998
|
} else {
|
|
16931
16999
|
timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
|
|
16932
17000
|
}
|
|
16933
17001
|
});
|
|
16934
17002
|
}
|
|
16935
|
-
if (!writes.has(
|
|
16936
|
-
writes.set(
|
|
17003
|
+
if (!writes.has(path37)) {
|
|
17004
|
+
writes.set(path37, {
|
|
16937
17005
|
lastChange: now,
|
|
16938
17006
|
cancelWait: () => {
|
|
16939
|
-
writes.delete(
|
|
17007
|
+
writes.delete(path37);
|
|
16940
17008
|
clearTimeout(timeoutHandler);
|
|
16941
17009
|
return event;
|
|
16942
17010
|
}
|
|
@@ -16947,8 +17015,8 @@ var FSWatcher = class extends import_events.EventEmitter {
|
|
|
16947
17015
|
/**
|
|
16948
17016
|
* Determines whether user has asked to ignore this path.
|
|
16949
17017
|
*/
|
|
16950
|
-
_isIgnored(
|
|
16951
|
-
if (this.options.atomic && DOT_RE.test(
|
|
17018
|
+
_isIgnored(path37, stats) {
|
|
17019
|
+
if (this.options.atomic && DOT_RE.test(path37))
|
|
16952
17020
|
return true;
|
|
16953
17021
|
if (!this._userIgnored) {
|
|
16954
17022
|
const { cwd } = this.options;
|
|
@@ -16958,17 +17026,17 @@ var FSWatcher = class extends import_events.EventEmitter {
|
|
|
16958
17026
|
const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
|
|
16959
17027
|
this._userIgnored = anymatch(list, void 0);
|
|
16960
17028
|
}
|
|
16961
|
-
return this._userIgnored(
|
|
17029
|
+
return this._userIgnored(path37, stats);
|
|
16962
17030
|
}
|
|
16963
|
-
_isntIgnored(
|
|
16964
|
-
return !this._isIgnored(
|
|
17031
|
+
_isntIgnored(path37, stat4) {
|
|
17032
|
+
return !this._isIgnored(path37, stat4);
|
|
16965
17033
|
}
|
|
16966
17034
|
/**
|
|
16967
17035
|
* Provides a set of common helpers and properties relating to symlink handling.
|
|
16968
17036
|
* @param path file or directory pattern being watched
|
|
16969
17037
|
*/
|
|
16970
|
-
_getWatchHelpers(
|
|
16971
|
-
return new WatchHelper(
|
|
17038
|
+
_getWatchHelpers(path37) {
|
|
17039
|
+
return new WatchHelper(path37, this.options.followSymlinks, this);
|
|
16972
17040
|
}
|
|
16973
17041
|
// Directory helpers
|
|
16974
17042
|
// -----------------
|
|
@@ -17000,63 +17068,63 @@ var FSWatcher = class extends import_events.EventEmitter {
|
|
|
17000
17068
|
* @param item base path of item/directory
|
|
17001
17069
|
*/
|
|
17002
17070
|
_remove(directory, item, isDirectory) {
|
|
17003
|
-
const
|
|
17004
|
-
const fullPath = sysPath2.resolve(
|
|
17005
|
-
isDirectory = isDirectory != null ? isDirectory : this._watched.has(
|
|
17006
|
-
if (!this._throttle("remove",
|
|
17071
|
+
const path37 = sysPath2.join(directory, item);
|
|
17072
|
+
const fullPath = sysPath2.resolve(path37);
|
|
17073
|
+
isDirectory = isDirectory != null ? isDirectory : this._watched.has(path37) || this._watched.has(fullPath);
|
|
17074
|
+
if (!this._throttle("remove", path37, 100))
|
|
17007
17075
|
return;
|
|
17008
17076
|
if (!isDirectory && this._watched.size === 1) {
|
|
17009
17077
|
this.add(directory, item, true);
|
|
17010
17078
|
}
|
|
17011
|
-
const wp = this._getWatchedDir(
|
|
17079
|
+
const wp = this._getWatchedDir(path37);
|
|
17012
17080
|
const nestedDirectoryChildren = wp.getChildren();
|
|
17013
|
-
nestedDirectoryChildren.forEach((nested) => this._remove(
|
|
17081
|
+
nestedDirectoryChildren.forEach((nested) => this._remove(path37, nested));
|
|
17014
17082
|
const parent = this._getWatchedDir(directory);
|
|
17015
17083
|
const wasTracked = parent.has(item);
|
|
17016
17084
|
parent.remove(item);
|
|
17017
17085
|
if (this._symlinkPaths.has(fullPath)) {
|
|
17018
17086
|
this._symlinkPaths.delete(fullPath);
|
|
17019
17087
|
}
|
|
17020
|
-
let relPath =
|
|
17088
|
+
let relPath = path37;
|
|
17021
17089
|
if (this.options.cwd)
|
|
17022
|
-
relPath = sysPath2.relative(this.options.cwd,
|
|
17090
|
+
relPath = sysPath2.relative(this.options.cwd, path37);
|
|
17023
17091
|
if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
|
|
17024
17092
|
const event = this._pendingWrites.get(relPath).cancelWait();
|
|
17025
17093
|
if (event === EVENTS.ADD)
|
|
17026
17094
|
return;
|
|
17027
17095
|
}
|
|
17028
|
-
this._watched.delete(
|
|
17096
|
+
this._watched.delete(path37);
|
|
17029
17097
|
this._watched.delete(fullPath);
|
|
17030
17098
|
const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
|
|
17031
|
-
if (wasTracked && !this._isIgnored(
|
|
17032
|
-
this._emit(eventName,
|
|
17033
|
-
this._closePath(
|
|
17099
|
+
if (wasTracked && !this._isIgnored(path37))
|
|
17100
|
+
this._emit(eventName, path37);
|
|
17101
|
+
this._closePath(path37);
|
|
17034
17102
|
}
|
|
17035
17103
|
/**
|
|
17036
17104
|
* Closes all watchers for a path
|
|
17037
17105
|
*/
|
|
17038
|
-
_closePath(
|
|
17039
|
-
this._closeFile(
|
|
17040
|
-
const dir = sysPath2.dirname(
|
|
17041
|
-
this._getWatchedDir(dir).remove(sysPath2.basename(
|
|
17106
|
+
_closePath(path37) {
|
|
17107
|
+
this._closeFile(path37);
|
|
17108
|
+
const dir = sysPath2.dirname(path37);
|
|
17109
|
+
this._getWatchedDir(dir).remove(sysPath2.basename(path37));
|
|
17042
17110
|
}
|
|
17043
17111
|
/**
|
|
17044
17112
|
* Closes only file-specific watchers
|
|
17045
17113
|
*/
|
|
17046
|
-
_closeFile(
|
|
17047
|
-
const closers = this._closers.get(
|
|
17114
|
+
_closeFile(path37) {
|
|
17115
|
+
const closers = this._closers.get(path37);
|
|
17048
17116
|
if (!closers)
|
|
17049
17117
|
return;
|
|
17050
17118
|
closers.forEach((closer) => closer());
|
|
17051
|
-
this._closers.delete(
|
|
17119
|
+
this._closers.delete(path37);
|
|
17052
17120
|
}
|
|
17053
|
-
_addPathCloser(
|
|
17121
|
+
_addPathCloser(path37, closer) {
|
|
17054
17122
|
if (!closer)
|
|
17055
17123
|
return;
|
|
17056
|
-
let list = this._closers.get(
|
|
17124
|
+
let list = this._closers.get(path37);
|
|
17057
17125
|
if (!list) {
|
|
17058
17126
|
list = [];
|
|
17059
|
-
this._closers.set(
|
|
17127
|
+
this._closers.set(path37, list);
|
|
17060
17128
|
}
|
|
17061
17129
|
list.push(closer);
|
|
17062
17130
|
}
|
|
@@ -17426,11 +17494,11 @@ function createStrictRateLimiterFromConfig(config) {
|
|
|
17426
17494
|
}
|
|
17427
17495
|
|
|
17428
17496
|
// modules/server/middleware/auto-rate-limit.ts
|
|
17429
|
-
function matchesStrictPattern(
|
|
17497
|
+
function matchesStrictPattern(path37, patterns) {
|
|
17430
17498
|
for (const pattern of patterns) {
|
|
17431
17499
|
const regexPattern = pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*").replace(/\//g, "\\/");
|
|
17432
17500
|
const regex = new RegExp(`^${regexPattern}$`);
|
|
17433
|
-
if (regex.test(
|
|
17501
|
+
if (regex.test(path37)) {
|
|
17434
17502
|
return true;
|
|
17435
17503
|
}
|
|
17436
17504
|
}
|
|
@@ -17620,9 +17688,441 @@ async function handleApiRequest(options) {
|
|
|
17620
17688
|
}
|
|
17621
17689
|
}
|
|
17622
17690
|
|
|
17691
|
+
// modules/server/image-optimizer/index.ts
|
|
17692
|
+
var import_sharp = __toESM(require("sharp"));
|
|
17693
|
+
var import_fs27 = __toESM(require("fs"));
|
|
17694
|
+
var import_path37 = __toESM(require("path"));
|
|
17695
|
+
|
|
17696
|
+
// modules/server/image-optimizer/validation.ts
|
|
17697
|
+
var import_path35 = __toESM(require("path"));
|
|
17698
|
+
function isRemoteUrl(url) {
|
|
17699
|
+
return url.startsWith("http://") || url.startsWith("https://");
|
|
17700
|
+
}
|
|
17701
|
+
function sanitizeImagePath(imagePath) {
|
|
17702
|
+
const normalized = import_path35.default.normalize(imagePath).replace(/^(\.\.(\/|\\|$))+/, "");
|
|
17703
|
+
return normalized.replace(/^[/\\]+/, "");
|
|
17704
|
+
}
|
|
17705
|
+
function patternToRegex(pattern) {
|
|
17706
|
+
const parts = [];
|
|
17707
|
+
if (pattern.protocol) {
|
|
17708
|
+
parts.push(pattern.protocol === "https" ? "https" : "http");
|
|
17709
|
+
} else {
|
|
17710
|
+
parts.push("https?");
|
|
17711
|
+
}
|
|
17712
|
+
parts.push("://");
|
|
17713
|
+
let hostnamePattern = pattern.hostname.replace(/\./g, "\\.").replace(/\*\*/g, ".*").replace(/\*/g, "[^.]*");
|
|
17714
|
+
parts.push(hostnamePattern);
|
|
17715
|
+
if (pattern.port) {
|
|
17716
|
+
parts.push(`:${pattern.port}`);
|
|
17717
|
+
}
|
|
17718
|
+
if (pattern.pathname) {
|
|
17719
|
+
let pathnamePattern = pattern.pathname.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*");
|
|
17720
|
+
parts.push(pathnamePattern);
|
|
17721
|
+
} else {
|
|
17722
|
+
parts.push(".*");
|
|
17723
|
+
}
|
|
17724
|
+
const regexSource = `^${parts.join("")}`;
|
|
17725
|
+
return new RegExp(regexSource);
|
|
17726
|
+
}
|
|
17727
|
+
function validateRemoteUrl(url, config) {
|
|
17728
|
+
if (!config.remotePatterns && !config.domains) {
|
|
17729
|
+
return false;
|
|
17730
|
+
}
|
|
17731
|
+
try {
|
|
17732
|
+
const urlObj = new URL(url);
|
|
17733
|
+
const protocol = urlObj.protocol.replace(":", "");
|
|
17734
|
+
const hostname = urlObj.hostname;
|
|
17735
|
+
const port = urlObj.port || "";
|
|
17736
|
+
const pathname = urlObj.pathname;
|
|
17737
|
+
if (config.remotePatterns && config.remotePatterns.length > 0) {
|
|
17738
|
+
for (const pattern of config.remotePatterns) {
|
|
17739
|
+
const regex = patternToRegex(pattern);
|
|
17740
|
+
const testUrl = `${protocol}://${hostname}${port ? `:${port}` : ""}${pathname}`;
|
|
17741
|
+
if (regex.test(testUrl)) {
|
|
17742
|
+
if (pattern.protocol && pattern.protocol !== protocol) {
|
|
17743
|
+
continue;
|
|
17744
|
+
}
|
|
17745
|
+
if (pattern.port && pattern.port !== port) {
|
|
17746
|
+
continue;
|
|
17747
|
+
}
|
|
17748
|
+
return true;
|
|
17749
|
+
}
|
|
17750
|
+
}
|
|
17751
|
+
}
|
|
17752
|
+
if (config.domains && config.domains.length > 0) {
|
|
17753
|
+
for (const domain of config.domains) {
|
|
17754
|
+
const domainPattern = domain.replace(/\./g, "\\.").replace(/\*\*/g, ".*").replace(/\*/g, "[^.]*");
|
|
17755
|
+
const regex = new RegExp(`^${domainPattern}$`);
|
|
17756
|
+
if (regex.test(hostname)) {
|
|
17757
|
+
if (process.env.NODE_ENV === "production" && protocol !== "https") {
|
|
17758
|
+
continue;
|
|
17759
|
+
}
|
|
17760
|
+
return true;
|
|
17761
|
+
}
|
|
17762
|
+
}
|
|
17763
|
+
}
|
|
17764
|
+
return false;
|
|
17765
|
+
} catch (error) {
|
|
17766
|
+
return false;
|
|
17767
|
+
}
|
|
17768
|
+
}
|
|
17769
|
+
function validateImageDimensions(width, height, config) {
|
|
17770
|
+
const maxWidth = config.maxWidth || 3840;
|
|
17771
|
+
const maxHeight = config.maxHeight || 3840;
|
|
17772
|
+
if (width !== void 0 && (width <= 0 || width > maxWidth)) {
|
|
17773
|
+
return {
|
|
17774
|
+
valid: false,
|
|
17775
|
+
error: `Image width must be between 1 and ${maxWidth}, got ${width}`
|
|
17776
|
+
};
|
|
17777
|
+
}
|
|
17778
|
+
if (height !== void 0 && (height <= 0 || height > maxHeight)) {
|
|
17779
|
+
return {
|
|
17780
|
+
valid: false,
|
|
17781
|
+
error: `Image height must be between 1 and ${maxHeight}, got ${height}`
|
|
17782
|
+
};
|
|
17783
|
+
}
|
|
17784
|
+
return { valid: true };
|
|
17785
|
+
}
|
|
17786
|
+
function validateQuality(quality) {
|
|
17787
|
+
if (quality === void 0) {
|
|
17788
|
+
return { valid: true };
|
|
17789
|
+
}
|
|
17790
|
+
if (typeof quality !== "number" || quality < 1 || quality > 100) {
|
|
17791
|
+
return {
|
|
17792
|
+
valid: false,
|
|
17793
|
+
error: `Image quality must be between 1 and 100, got ${quality}`
|
|
17794
|
+
};
|
|
17795
|
+
}
|
|
17796
|
+
return { valid: true };
|
|
17797
|
+
}
|
|
17798
|
+
|
|
17799
|
+
// modules/server/image-optimizer/cache.ts
|
|
17800
|
+
var import_fs26 = __toESM(require("fs"));
|
|
17801
|
+
var import_path36 = __toESM(require("path"));
|
|
17802
|
+
var import_crypto = __toESM(require("crypto"));
|
|
17803
|
+
function generateCacheKey(src, width, height, quality, format) {
|
|
17804
|
+
const data = `${src}-${width || ""}-${height || ""}-${quality || ""}-${format || ""}`;
|
|
17805
|
+
return import_crypto.default.createHash("sha256").update(data).digest("hex");
|
|
17806
|
+
}
|
|
17807
|
+
function getCacheDir(projectRoot, config) {
|
|
17808
|
+
const buildDir = getBuildDir(projectRoot, config);
|
|
17809
|
+
return import_path36.default.join(buildDir, "cache", "images");
|
|
17810
|
+
}
|
|
17811
|
+
function ensureCacheDir(cacheDir) {
|
|
17812
|
+
if (!import_fs26.default.existsSync(cacheDir)) {
|
|
17813
|
+
import_fs26.default.mkdirSync(cacheDir, { recursive: true });
|
|
17814
|
+
}
|
|
17815
|
+
}
|
|
17816
|
+
function getCachedImagePath(cacheKey, extension, cacheDir) {
|
|
17817
|
+
return import_path36.default.join(cacheDir, `${cacheKey}.${extension}`);
|
|
17818
|
+
}
|
|
17819
|
+
function hasCachedImage(cacheKey, extension, cacheDir) {
|
|
17820
|
+
const cachedPath = getCachedImagePath(cacheKey, extension, cacheDir);
|
|
17821
|
+
return import_fs26.default.existsSync(cachedPath);
|
|
17822
|
+
}
|
|
17823
|
+
function readCachedImage(cacheKey, extension, cacheDir) {
|
|
17824
|
+
const cachedPath = getCachedImagePath(cacheKey, extension, cacheDir);
|
|
17825
|
+
try {
|
|
17826
|
+
if (import_fs26.default.existsSync(cachedPath)) {
|
|
17827
|
+
return import_fs26.default.readFileSync(cachedPath);
|
|
17828
|
+
}
|
|
17829
|
+
} catch (error) {
|
|
17830
|
+
console.warn(`[image-optimizer] Failed to read cached image: ${cachedPath}`, error);
|
|
17831
|
+
}
|
|
17832
|
+
return null;
|
|
17833
|
+
}
|
|
17834
|
+
function writeCachedImage(cacheKey, extension, cacheDir, imageBuffer) {
|
|
17835
|
+
ensureCacheDir(cacheDir);
|
|
17836
|
+
const cachedPath = getCachedImagePath(cacheKey, extension, cacheDir);
|
|
17837
|
+
try {
|
|
17838
|
+
import_fs26.default.writeFileSync(cachedPath, imageBuffer);
|
|
17839
|
+
} catch (error) {
|
|
17840
|
+
console.warn(`[image-optimizer] Failed to write cached image: ${cachedPath}`, error);
|
|
17841
|
+
}
|
|
17842
|
+
}
|
|
17843
|
+
function getImageMimeType(format) {
|
|
17844
|
+
const formatMap = {
|
|
17845
|
+
webp: "image/webp",
|
|
17846
|
+
avif: "image/avif",
|
|
17847
|
+
jpeg: "image/jpeg",
|
|
17848
|
+
jpg: "image/jpeg",
|
|
17849
|
+
png: "image/png",
|
|
17850
|
+
gif: "image/gif",
|
|
17851
|
+
svg: "image/svg+xml"
|
|
17852
|
+
};
|
|
17853
|
+
const normalized = format.toLowerCase();
|
|
17854
|
+
return formatMap[normalized] || "image/jpeg";
|
|
17855
|
+
}
|
|
17856
|
+
function getImageExtension(format) {
|
|
17857
|
+
const formatMap = {
|
|
17858
|
+
"image/webp": "webp",
|
|
17859
|
+
"image/avif": "avif",
|
|
17860
|
+
"image/jpeg": "jpg",
|
|
17861
|
+
"image/png": "png",
|
|
17862
|
+
"image/gif": "gif",
|
|
17863
|
+
"image/svg+xml": "svg",
|
|
17864
|
+
webp: "webp",
|
|
17865
|
+
avif: "avif",
|
|
17866
|
+
jpeg: "jpg",
|
|
17867
|
+
jpg: "jpg",
|
|
17868
|
+
png: "png",
|
|
17869
|
+
gif: "gif",
|
|
17870
|
+
svg: "svg"
|
|
17871
|
+
};
|
|
17872
|
+
const normalized = format.toLowerCase();
|
|
17873
|
+
return formatMap[normalized] || "jpg";
|
|
17874
|
+
}
|
|
17875
|
+
|
|
17876
|
+
// modules/server/image-optimizer/index.ts
|
|
17877
|
+
async function downloadRemoteImage(url, timeout = 1e4) {
|
|
17878
|
+
let fetchFn;
|
|
17879
|
+
try {
|
|
17880
|
+
if (typeof fetch !== "undefined") {
|
|
17881
|
+
fetchFn = fetch;
|
|
17882
|
+
} else {
|
|
17883
|
+
const { fetch: undiciFetch } = await import("undici");
|
|
17884
|
+
fetchFn = undiciFetch;
|
|
17885
|
+
}
|
|
17886
|
+
} catch (error) {
|
|
17887
|
+
throw new Error("Failed to load fetch implementation. Node 18+ required or install undici.");
|
|
17888
|
+
}
|
|
17889
|
+
const controller = new AbortController();
|
|
17890
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
17891
|
+
try {
|
|
17892
|
+
const response = await fetchFn(url, {
|
|
17893
|
+
signal: controller.signal,
|
|
17894
|
+
headers: {
|
|
17895
|
+
"User-Agent": "Loly-Image-Optimizer/1.0"
|
|
17896
|
+
}
|
|
17897
|
+
});
|
|
17898
|
+
clearTimeout(timeoutId);
|
|
17899
|
+
if (!response.ok) {
|
|
17900
|
+
throw new Error(`Failed to download image: ${response.status} ${response.statusText}`);
|
|
17901
|
+
}
|
|
17902
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
17903
|
+
return Buffer.from(arrayBuffer);
|
|
17904
|
+
} catch (error) {
|
|
17905
|
+
clearTimeout(timeoutId);
|
|
17906
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
17907
|
+
throw new Error(`Image download timeout after ${timeout}ms`);
|
|
17908
|
+
}
|
|
17909
|
+
throw error;
|
|
17910
|
+
}
|
|
17911
|
+
}
|
|
17912
|
+
function readLocalImage(src, projectRoot, config) {
|
|
17913
|
+
const sanitized = sanitizeImagePath(src);
|
|
17914
|
+
const staticDir = getStaticDir(projectRoot, config);
|
|
17915
|
+
const staticPath = import_path37.default.join(staticDir, sanitized);
|
|
17916
|
+
if (import_fs27.default.existsSync(staticPath)) {
|
|
17917
|
+
return import_fs27.default.readFileSync(staticPath);
|
|
17918
|
+
}
|
|
17919
|
+
if (src.startsWith("/")) {
|
|
17920
|
+
const absolutePath = import_path37.default.join(projectRoot, sanitized);
|
|
17921
|
+
if (import_fs27.default.existsSync(absolutePath)) {
|
|
17922
|
+
return import_fs27.default.readFileSync(absolutePath);
|
|
17923
|
+
}
|
|
17924
|
+
}
|
|
17925
|
+
throw new Error(`Image not found: ${src}`);
|
|
17926
|
+
}
|
|
17927
|
+
function determineOutputFormat(sourceFormat, requestedFormat, config) {
|
|
17928
|
+
if (sourceFormat === "svg") {
|
|
17929
|
+
return "svg";
|
|
17930
|
+
}
|
|
17931
|
+
if (requestedFormat && requestedFormat !== "auto") {
|
|
17932
|
+
return requestedFormat;
|
|
17933
|
+
}
|
|
17934
|
+
const supportedFormats = config.formats || ["image/webp"];
|
|
17935
|
+
if (supportedFormats.includes("image/avif")) {
|
|
17936
|
+
return "avif";
|
|
17937
|
+
}
|
|
17938
|
+
if (supportedFormats.includes("image/webp")) {
|
|
17939
|
+
return "webp";
|
|
17940
|
+
}
|
|
17941
|
+
return sourceFormat === "svg" ? "jpeg" : sourceFormat;
|
|
17942
|
+
}
|
|
17943
|
+
async function optimizeImage(options, projectRoot, config) {
|
|
17944
|
+
const imageConfig = config.images || {};
|
|
17945
|
+
const dimValidation = validateImageDimensions(options.width, options.height, imageConfig);
|
|
17946
|
+
if (!dimValidation.valid) {
|
|
17947
|
+
throw new Error(dimValidation.error);
|
|
17948
|
+
}
|
|
17949
|
+
const qualityValidation = validateQuality(options.quality);
|
|
17950
|
+
if (!qualityValidation.valid) {
|
|
17951
|
+
throw new Error(qualityValidation.error);
|
|
17952
|
+
}
|
|
17953
|
+
if (isRemoteUrl(options.src)) {
|
|
17954
|
+
if (!validateRemoteUrl(options.src, imageConfig)) {
|
|
17955
|
+
throw new Error(`Remote image domain not allowed: ${options.src}`);
|
|
17956
|
+
}
|
|
17957
|
+
}
|
|
17958
|
+
const sourceFormat = import_path37.default.extname(options.src).slice(1).toLowerCase() || "jpeg";
|
|
17959
|
+
const outputFormat = determineOutputFormat(
|
|
17960
|
+
sourceFormat,
|
|
17961
|
+
options.format,
|
|
17962
|
+
imageConfig
|
|
17963
|
+
);
|
|
17964
|
+
const cacheKey = generateCacheKey(
|
|
17965
|
+
options.src,
|
|
17966
|
+
options.width,
|
|
17967
|
+
options.height,
|
|
17968
|
+
options.quality || imageConfig.quality || 75,
|
|
17969
|
+
outputFormat
|
|
17970
|
+
);
|
|
17971
|
+
const cacheDir = getCacheDir(projectRoot, config);
|
|
17972
|
+
const extension = getImageExtension(outputFormat);
|
|
17973
|
+
if (hasCachedImage(cacheKey, extension, cacheDir)) {
|
|
17974
|
+
const cached = readCachedImage(cacheKey, extension, cacheDir);
|
|
17975
|
+
if (cached) {
|
|
17976
|
+
const metadata2 = await (0, import_sharp.default)(cached).metadata();
|
|
17977
|
+
return {
|
|
17978
|
+
buffer: cached,
|
|
17979
|
+
format: outputFormat,
|
|
17980
|
+
mimeType: getImageMimeType(outputFormat),
|
|
17981
|
+
width: metadata2.width || options.width || 0,
|
|
17982
|
+
height: metadata2.height || options.height || 0
|
|
17983
|
+
};
|
|
17984
|
+
}
|
|
17985
|
+
}
|
|
17986
|
+
let imageBuffer;
|
|
17987
|
+
if (isRemoteUrl(options.src)) {
|
|
17988
|
+
imageBuffer = await downloadRemoteImage(options.src);
|
|
17989
|
+
} else {
|
|
17990
|
+
imageBuffer = readLocalImage(options.src, projectRoot, config);
|
|
17991
|
+
}
|
|
17992
|
+
if (outputFormat === "svg" || sourceFormat === "svg") {
|
|
17993
|
+
if (!imageConfig.dangerouslyAllowSVG) {
|
|
17994
|
+
throw new Error("SVG images are not allowed. Set images.dangerouslyAllowSVG to true to enable.");
|
|
17995
|
+
}
|
|
17996
|
+
return {
|
|
17997
|
+
buffer: imageBuffer,
|
|
17998
|
+
format: "svg",
|
|
17999
|
+
mimeType: "image/svg+xml",
|
|
18000
|
+
width: options.width || 0,
|
|
18001
|
+
height: options.height || 0
|
|
18002
|
+
};
|
|
18003
|
+
}
|
|
18004
|
+
let sharpInstance = (0, import_sharp.default)(imageBuffer);
|
|
18005
|
+
const metadata = await sharpInstance.metadata();
|
|
18006
|
+
if (options.width || options.height) {
|
|
18007
|
+
const fit = options.fit || "cover";
|
|
18008
|
+
sharpInstance = sharpInstance.resize(options.width, options.height, {
|
|
18009
|
+
fit,
|
|
18010
|
+
withoutEnlargement: true
|
|
18011
|
+
});
|
|
18012
|
+
}
|
|
18013
|
+
const quality = options.quality || imageConfig.quality || 75;
|
|
18014
|
+
switch (outputFormat) {
|
|
18015
|
+
case "webp":
|
|
18016
|
+
sharpInstance = sharpInstance.webp({ quality });
|
|
18017
|
+
break;
|
|
18018
|
+
case "avif":
|
|
18019
|
+
sharpInstance = sharpInstance.avif({ quality });
|
|
18020
|
+
break;
|
|
18021
|
+
case "jpeg":
|
|
18022
|
+
case "jpg":
|
|
18023
|
+
sharpInstance = sharpInstance.jpeg({ quality });
|
|
18024
|
+
break;
|
|
18025
|
+
case "png":
|
|
18026
|
+
sharpInstance = sharpInstance.png({ quality: Math.round(quality / 100 * 9) });
|
|
18027
|
+
break;
|
|
18028
|
+
default:
|
|
18029
|
+
sharpInstance = sharpInstance.jpeg({ quality });
|
|
18030
|
+
}
|
|
18031
|
+
const optimizedBuffer = await sharpInstance.toBuffer();
|
|
18032
|
+
const finalMetadata = await (0, import_sharp.default)(optimizedBuffer).metadata();
|
|
18033
|
+
writeCachedImage(cacheKey, extension, cacheDir, optimizedBuffer);
|
|
18034
|
+
return {
|
|
18035
|
+
buffer: optimizedBuffer,
|
|
18036
|
+
format: outputFormat,
|
|
18037
|
+
mimeType: getImageMimeType(outputFormat),
|
|
18038
|
+
width: finalMetadata.width || options.width || metadata.width || 0,
|
|
18039
|
+
height: finalMetadata.height || options.height || metadata.height || 0
|
|
18040
|
+
};
|
|
18041
|
+
}
|
|
18042
|
+
|
|
18043
|
+
// modules/server/handlers/image.ts
|
|
18044
|
+
async function handleImageRequest(options) {
|
|
18045
|
+
const { req, res, projectRoot, config } = options;
|
|
18046
|
+
try {
|
|
18047
|
+
const src = req.query.src;
|
|
18048
|
+
const width = req.query.w ? parseInt(req.query.w, 10) : void 0;
|
|
18049
|
+
const height = req.query.h ? parseInt(req.query.h, 10) : void 0;
|
|
18050
|
+
const quality = req.query.q ? parseInt(req.query.q, 10) : void 0;
|
|
18051
|
+
const format = req.query.format;
|
|
18052
|
+
const fit = req.query.fit;
|
|
18053
|
+
if (!src) {
|
|
18054
|
+
res.status(400).json({
|
|
18055
|
+
error: "Missing required parameter: src"
|
|
18056
|
+
});
|
|
18057
|
+
return;
|
|
18058
|
+
}
|
|
18059
|
+
if (typeof src !== "string") {
|
|
18060
|
+
res.status(400).json({
|
|
18061
|
+
error: "Parameter 'src' must be a string"
|
|
18062
|
+
});
|
|
18063
|
+
return;
|
|
18064
|
+
}
|
|
18065
|
+
const result = await optimizeImage(
|
|
18066
|
+
{
|
|
18067
|
+
src,
|
|
18068
|
+
width,
|
|
18069
|
+
height,
|
|
18070
|
+
quality,
|
|
18071
|
+
format,
|
|
18072
|
+
fit
|
|
18073
|
+
},
|
|
18074
|
+
projectRoot,
|
|
18075
|
+
config
|
|
18076
|
+
);
|
|
18077
|
+
const imageConfig = config.images || {};
|
|
18078
|
+
const cacheTTL = imageConfig.minimumCacheTTL || 60;
|
|
18079
|
+
res.setHeader("Content-Type", result.mimeType);
|
|
18080
|
+
res.setHeader("Content-Length", result.buffer.length);
|
|
18081
|
+
res.setHeader("Cache-Control", `public, max-age=${cacheTTL}, immutable`);
|
|
18082
|
+
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
18083
|
+
res.send(result.buffer);
|
|
18084
|
+
} catch (error) {
|
|
18085
|
+
if (error instanceof Error) {
|
|
18086
|
+
if (error.message.includes("not allowed")) {
|
|
18087
|
+
res.status(403).json({
|
|
18088
|
+
error: "Forbidden",
|
|
18089
|
+
message: error.message
|
|
18090
|
+
});
|
|
18091
|
+
return;
|
|
18092
|
+
}
|
|
18093
|
+
if (error.message.includes("not found") || error.message.includes("Image not found")) {
|
|
18094
|
+
res.status(404).json({
|
|
18095
|
+
error: "Not Found",
|
|
18096
|
+
message: error.message
|
|
18097
|
+
});
|
|
18098
|
+
return;
|
|
18099
|
+
}
|
|
18100
|
+
if (error.message.includes("must be")) {
|
|
18101
|
+
res.status(400).json({
|
|
18102
|
+
error: "Bad Request",
|
|
18103
|
+
message: error.message
|
|
18104
|
+
});
|
|
18105
|
+
return;
|
|
18106
|
+
}
|
|
18107
|
+
if (error.message.includes("timeout") || error.message.includes("download")) {
|
|
18108
|
+
res.status(504).json({
|
|
18109
|
+
error: "Gateway Timeout",
|
|
18110
|
+
message: error.message
|
|
18111
|
+
});
|
|
18112
|
+
return;
|
|
18113
|
+
}
|
|
18114
|
+
}
|
|
18115
|
+
console.error("[image-optimizer] Error processing image:", error);
|
|
18116
|
+
res.status(500).json({
|
|
18117
|
+
error: "Internal Server Error",
|
|
18118
|
+
message: "Failed to process image"
|
|
18119
|
+
});
|
|
18120
|
+
}
|
|
18121
|
+
}
|
|
18122
|
+
|
|
17623
18123
|
// modules/server/routes.ts
|
|
17624
18124
|
init_globals();
|
|
17625
|
-
var
|
|
18125
|
+
var import_path38 = __toESM(require("path"));
|
|
17626
18126
|
var cachedRewriteLoader = null;
|
|
17627
18127
|
var cachedProjectRoot = null;
|
|
17628
18128
|
var cachedIsDev = null;
|
|
@@ -17650,10 +18150,20 @@ function setupRoutes(options) {
|
|
|
17650
18150
|
} = options;
|
|
17651
18151
|
const routeChunks = routeLoader.loadRouteChunks();
|
|
17652
18152
|
const rewriteLoader = getRewriteLoader(projectRoot, isDev);
|
|
17653
|
-
const ssgOutDir =
|
|
17654
|
-
config ? getBuildDir(projectRoot, config) :
|
|
18153
|
+
const ssgOutDir = import_path38.default.join(
|
|
18154
|
+
config ? getBuildDir(projectRoot, config) : import_path38.default.join(projectRoot, BUILD_FOLDER_NAME),
|
|
17655
18155
|
"ssg"
|
|
17656
18156
|
);
|
|
18157
|
+
if (config) {
|
|
18158
|
+
app.get("/_loly/image", async (req, res) => {
|
|
18159
|
+
await handleImageRequest({
|
|
18160
|
+
req,
|
|
18161
|
+
res,
|
|
18162
|
+
projectRoot,
|
|
18163
|
+
config
|
|
18164
|
+
});
|
|
18165
|
+
});
|
|
18166
|
+
}
|
|
17657
18167
|
app.all("/api/*", async (req, res) => {
|
|
17658
18168
|
const apiRoutes = isDev && getRoutes ? (await getRoutes()).apiRoutes : initialApiRoutes;
|
|
17659
18169
|
const serverConfig = await getServerConfig(projectRoot);
|
|
@@ -18700,7 +19210,7 @@ var import_cors = __toESM(require("cors"));
|
|
|
18700
19210
|
var import_helmet = __toESM(require("helmet"));
|
|
18701
19211
|
var import_cookie_parser = __toESM(require("cookie-parser"));
|
|
18702
19212
|
var import_compression = __toESM(require("compression"));
|
|
18703
|
-
var
|
|
19213
|
+
var import_crypto2 = __toESM(require("crypto"));
|
|
18704
19214
|
var setupApplication = async ({
|
|
18705
19215
|
projectRoot
|
|
18706
19216
|
}) => {
|
|
@@ -18809,7 +19319,7 @@ var setupApplication = async ({
|
|
|
18809
19319
|
if (process.env.NODE_ENV !== "development" && security?.contentSecurityPolicy !== false) {
|
|
18810
19320
|
app.use(
|
|
18811
19321
|
(req, res, next) => {
|
|
18812
|
-
const nonce =
|
|
19322
|
+
const nonce = import_crypto2.default.randomBytes(16).toString("base64");
|
|
18813
19323
|
res.locals.nonce = nonce;
|
|
18814
19324
|
next();
|
|
18815
19325
|
}
|
|
@@ -18880,8 +19390,8 @@ var setupApplication = async ({
|
|
|
18880
19390
|
|
|
18881
19391
|
// src/server.ts
|
|
18882
19392
|
var import_dotenv2 = __toESM(require("dotenv"));
|
|
18883
|
-
var envPath =
|
|
18884
|
-
if (
|
|
19393
|
+
var envPath = import_path39.default.join(process.cwd(), ".env");
|
|
19394
|
+
if (import_fs28.default.existsSync(envPath)) {
|
|
18885
19395
|
import_dotenv2.default.config({ path: envPath });
|
|
18886
19396
|
} else {
|
|
18887
19397
|
import_dotenv2.default.config();
|
|
@@ -18902,8 +19412,8 @@ async function startServer(options = {}) {
|
|
|
18902
19412
|
}
|
|
18903
19413
|
const port = options.port ?? (process.env.PORT ? parseInt(process.env.PORT, 10) : void 0) ?? config.server.port;
|
|
18904
19414
|
const host = process.env.HOST ?? (!isDev ? "0.0.0.0" : void 0) ?? config.server.host;
|
|
18905
|
-
const appDir = options.appDir ?? (isDev ? getAppDir(projectRoot, config) :
|
|
18906
|
-
if (!isDev && !
|
|
19415
|
+
const appDir = options.appDir ?? (isDev ? getAppDir(projectRoot, config) : import_path39.default.join(getBuildDir(projectRoot, config), "server"));
|
|
19416
|
+
if (!isDev && !import_fs28.default.existsSync(appDir)) {
|
|
18907
19417
|
logger4.error("Compiled directory not found", void 0, {
|
|
18908
19418
|
buildDir: config.directories.build,
|
|
18909
19419
|
appDir,
|
|
@@ -19099,7 +19609,7 @@ async function run() {
|
|
|
19099
19609
|
}
|
|
19100
19610
|
const args = parseArgs(argv.slice(1));
|
|
19101
19611
|
const projectRoot = import_process.default.cwd();
|
|
19102
|
-
const appDir =
|
|
19612
|
+
const appDir = import_path40.default.resolve(projectRoot, args.appDir || "app");
|
|
19103
19613
|
const port = typeof args.port === "string" && args.port.trim().length > 0 ? Number(args.port) : 3e3;
|
|
19104
19614
|
switch (command) {
|
|
19105
19615
|
case "dev": {
|