Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83738bfebf | ||
|
|
5089a2ae6b | ||
|
|
b83c8b6546 | ||
|
|
0e4189f693 | ||
|
|
1cf010e9fb | ||
|
|
7e58858353 | ||
|
|
9ed55d57dd |
No files matched your search
@@ -163,3 +163,65 @@ jobs:
|
|||||||
run: cp .env.example .env
|
run: cp .env.example .env
|
||||||
- name: Build
|
- name: Build
|
||||||
run: pnpm turbo build --affected
|
run: pnpm turbo build --affected
|
||||||
|
|
||||||
|
memory-regression:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 15
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v4
|
||||||
|
- name: Build Docker image
|
||||||
|
uses: docker/build-push-action@v7
|
||||||
|
with:
|
||||||
|
platforms: linux/amd64
|
||||||
|
context: .
|
||||||
|
push: false
|
||||||
|
load: true
|
||||||
|
tags: homarr-memory-test
|
||||||
|
network: host
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
|
env:
|
||||||
|
SKIP_ENV_VALIDATION: true
|
||||||
|
- name: Start container and measure memory
|
||||||
|
run: |
|
||||||
|
docker run -d --name homarr-mem-test -p 17575:7575 homarr-memory-test
|
||||||
|
# Wait for container to be healthy (up to 60s)
|
||||||
|
healthy=false
|
||||||
|
for i in $(seq 1 30); do
|
||||||
|
if curl -sf http://localhost:17575/api/health 2>/dev/null; then
|
||||||
|
echo "Container healthy after $((i * 2))s"
|
||||||
|
healthy=true
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
if [ "$healthy" != "true" ]; then
|
||||||
|
echo "ERROR: Container never became healthy"
|
||||||
|
docker logs homarr-mem-test --tail 50
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# Warm up: hit the dashboard page a few times
|
||||||
|
for i in $(seq 1 5); do
|
||||||
|
curl -sf http://localhost:17575/ > /dev/null 2>&1 || true
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
# Measure RSS after warmup
|
||||||
|
MEM_KB=$(docker stats --no-stream --format '{{.MemUsage}}' homarr-mem-test | sed 's| /.*||')
|
||||||
|
echo "Raw memory: $MEM_KB"
|
||||||
|
# Convert to numeric MB (handles GiB and MiB suffixes)
|
||||||
|
MEM_NUM=$(echo "$MEM_KB" | awk '{
|
||||||
|
if ($0 ~ /GiB/) { gsub(/GiB/,""); print $1 * 1024 }
|
||||||
|
else if ($0 ~ /MiB/) { gsub(/MiB/,""); print $1 }
|
||||||
|
else if ($0 ~ /KiB/) { gsub(/KiB/,""); print $1 / 1024 }
|
||||||
|
else { print $1 / 1048576 }
|
||||||
|
}')
|
||||||
|
echo "Memory usage: ${MEM_NUM} MB"
|
||||||
|
MAX_MB=700
|
||||||
|
if awk "BEGIN {exit !($MEM_NUM > $MAX_MB)}"; then
|
||||||
|
echo "ERROR: Memory usage ${MEM_NUM} MB exceeds ${MAX_MB} MB threshold"
|
||||||
|
docker logs homarr-mem-test --tail 50
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Memory check passed: ${MEM_NUM} MB <= ${MAX_MB} MB"
|
||||||
@@ -66,7 +66,7 @@ jobs:
|
|||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v6
|
||||||
if: env.SKIP_RELEASE == 'false'
|
if: env.SKIP_RELEASE == 'false'
|
||||||
with:
|
with:
|
||||||
node-version: 24.17.0
|
node-version: 24.18.0
|
||||||
package-manager-cache: false
|
package-manager-cache: false
|
||||||
- run: npm i -g pnpm
|
- run: npm i -g pnpm
|
||||||
if: env.SKIP_RELEASE == 'false'
|
if: env.SKIP_RELEASE == 'false'
|
||||||
|
|||||||
+1
-1
@@ -1,2 +1,2 @@
|
|||||||
[tools]
|
[tools]
|
||||||
node = "24.17.0"
|
node = "24.18.0"
|
||||||
@@ -1,3 +1,10 @@
|
|||||||
|
## [1.68.1](https://github.com/homarr-labs/homarr/compare/v1.68.0...v1.68.1) (2026-06-30)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* make source maps opt-in to restore v1.67.0 memory baseline ([57ef0af](https://github.com/homarr-labs/homarr/commit/57ef0af4a252ea39727caeba7e13587dabc6254e)), closes [#6123](https://github.com/homarr-labs/homarr/issues/6123)
|
||||||
|
* revert production source maps to restore v1.67.0 memory baseline ([60a69e3](https://github.com/homarr-labs/homarr/commit/60a69e31efc7168b8f4309daf75954d7730d883b)), closes [#6123](https://github.com/homarr-labs/homarr/issues/6123)
|
||||||
|
|
||||||
## [1.68.0](https://github.com/homarr-labs/homarr/compare/v1.67.0...v1.68.0) (2026-06-26)
|
## [1.68.0](https://github.com/homarr-labs/homarr/compare/v1.67.0...v1.68.0) (2026-06-26)
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|||||||
+1
-15
@@ -1,4 +1,4 @@
|
|||||||
FROM node:24.17.0-alpine AS base
|
FROM node:24.18.0-alpine AS base
|
||||||
|
|
||||||
FROM base AS builder
|
FROM base AS builder
|
||||||
RUN apk add --no-cache libc6-compat
|
RUN apk add --no-cache libc6-compat
|
||||||
@@ -20,17 +20,6 @@ ARG DISABLE_REDIS_LOGS='true'
|
|||||||
|
|
||||||
RUN corepack enable pnpm && pnpm build
|
RUN corepack enable pnpm && pnpm build
|
||||||
|
|
||||||
# The standalone output tracing omits server chunk source maps (.next/server/**/*.map), which is
|
|
||||||
# where production Node stack frames point. Copy the .map files into the standalone tree (preserving
|
|
||||||
# directory structure) so the existing standalone COPY ships them, keeping traces readable.
|
|
||||||
# See https://github.com/homarr-labs/homarr/issues/5891
|
|
||||||
RUN cd apps/nextjs/.next/server && \
|
|
||||||
find . -name '*.map' | while IFS= read -r map; do \
|
|
||||||
dest="../standalone/apps/nextjs/.next/server/$map"; \
|
|
||||||
mkdir -p "$(dirname "$dest")"; \
|
|
||||||
cp "$map" "$dest"; \
|
|
||||||
done
|
|
||||||
|
|
||||||
FROM base AS runner
|
FROM base AS runner
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
@@ -75,9 +64,6 @@ ENV DB_DRIVER='better-sqlite3'
|
|||||||
ENV AUTH_PROVIDERS='credentials'
|
ENV AUTH_PROVIDERS='credentials'
|
||||||
ENV REDIS_IS_EXTERNAL='false'
|
ENV REDIS_IS_EXTERNAL='false'
|
||||||
ENV NODE_ENV='production'
|
ENV NODE_ENV='production'
|
||||||
# Tell Node to symbolicate stack traces using the shipped .map files so production logs
|
|
||||||
# show original source locations instead of minified frames, see https://github.com/homarr-labs/homarr/issues/5891
|
|
||||||
ENV NODE_OPTIONS='--enable-source-maps'
|
|
||||||
|
|
||||||
ENTRYPOINT [ "/app/entrypoint.sh" ]
|
ENTRYPOINT [ "/app/entrypoint.sh" ]
|
||||||
CMD ["sh", "run.sh"]
|
CMD ["sh", "run.sh"]
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
---
|
||||||
|
title: 'FileFlows'
|
||||||
|
description: "FileFlows is a distributed media processing system that allows you to encode, compress and process your media files across multiple nodes."
|
||||||
|
hide_title: true
|
||||||
|
---
|
||||||
|
|
||||||
|
import { IntegrationHeader } from '@site/src/components/integrations/header';
|
||||||
|
import { IntegrationCapabilites } from '@site/src/components/integrations/widgets';
|
||||||
|
import { AddingIntegration } from '@site/src/components/integrations/adding';
|
||||||
|
import {IntegrationSecrets} from '@site/src/components/integrations/secrets';
|
||||||
|
import { IconTransform } from "@tabler/icons-react";
|
||||||
|
import { fileFlowsIntegration } from '.';
|
||||||
|
import { mediaTranscodingWidget } from '@site/docs/widgets/media-transcoding';
|
||||||
|
|
||||||
|
|
||||||
|
<IntegrationHeader
|
||||||
|
integration={fileFlowsIntegration}
|
||||||
|
categories={['Media Transcoding']}
|
||||||
|
/>
|
||||||
|
|
||||||
|
### Widgets & Capabilities
|
||||||
|
<IntegrationCapabilites
|
||||||
|
items={[{ widget: mediaTranscodingWidget }]}
|
||||||
|
/>
|
||||||
|
|
||||||
|
### Adding the integration
|
||||||
|
<AddingIntegration />
|
||||||
|
|
||||||
|
### Secrets
|
||||||
|
<IntegrationSecrets secrets={[{
|
||||||
|
credentials: ['apiKey'],
|
||||||
|
steps: []
|
||||||
|
}, {
|
||||||
|
credentials: [],
|
||||||
|
steps: []
|
||||||
|
}]} />
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { IntegrationDefinition } from "@site/src/types";
|
||||||
|
export const fileFlowsIntegration: IntegrationDefinition = {
|
||||||
|
name: "FileFlows",
|
||||||
|
description:
|
||||||
|
"FileFlows is a distributed media processing system that allows you to encode, compress and process your media files across multiple nodes.",
|
||||||
|
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/fileflows.png",
|
||||||
|
path: "../../integrations/fileflows",
|
||||||
|
};
|
||||||
@@ -31,8 +31,6 @@ const nextConfig: NextConfig = {
|
|||||||
},
|
},
|
||||||
output: "standalone",
|
output: "standalone",
|
||||||
reactStrictMode: true,
|
reactStrictMode: true,
|
||||||
// Ship browser source maps so production client stack traces are readable, see https://github.com/homarr-labs/homarr/issues/5891
|
|
||||||
productionBrowserSourceMaps: true,
|
|
||||||
// react compiler breaks mantine-react-table, so disabled for now
|
// react compiler breaks mantine-react-table, so disabled for now
|
||||||
//reactCompiler: true,
|
//reactCompiler: true,
|
||||||
/** We already do typechecking as separate tasks in CI */
|
/** We already do typechecking as separate tasks in CI */
|
||||||
@@ -43,8 +41,6 @@ const nextConfig: NextConfig = {
|
|||||||
*/
|
*/
|
||||||
serverExternalPackages: ["dockerode", "isomorphic-dompurify", "jsdom", "better-sqlite3"],
|
serverExternalPackages: ["dockerode", "isomorphic-dompurify", "jsdom", "better-sqlite3"],
|
||||||
experimental: {
|
experimental: {
|
||||||
// Ship server source maps so production Node stack traces in logs reference original source, see https://github.com/homarr-labs/homarr/issues/5891
|
|
||||||
serverSourceMaps: true,
|
|
||||||
optimizePackageImports: ["@mantine/core", "@mantine/hooks", "@tabler/icons-react"],
|
optimizePackageImports: ["@mantine/core", "@mantine/hooks", "@tabler/icons-react"],
|
||||||
turbopackFileSystemCacheForDev: true,
|
turbopackFileSystemCacheForDev: true,
|
||||||
preloadEntriesOnStart: false,
|
preloadEntriesOnStart: false,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM node:24.17.0-trixie AS base
|
FROM node:24.18.0-trixie AS base
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY package.json .
|
COPY package.json .
|
||||||
COPY pnpm-lock.yaml .
|
COPY pnpm-lock.yaml .
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
"better-sqlite3": "^12.10.0"
|
"better-sqlite3": "^12.10.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=24.17.0",
|
"node": ">=24.18.0",
|
||||||
"pnpm": ">=11.9.0"
|
"pnpm": ">=11.9.0"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@11.9.0"
|
"packageManager": "pnpm@11.9.0"
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "homarr",
|
"name": "homarr",
|
||||||
"version": "1.68.0",
|
"version": "1.68.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "cross-env CI=true turbo build",
|
"build": "cross-env CI=true turbo build",
|
||||||
@@ -61,7 +61,7 @@
|
|||||||
"vitest": "catalog:"
|
"vitest": "catalog:"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=24.17.0",
|
"node": ">=24.18.0",
|
||||||
"pnpm": ">=11.9.0"
|
"pnpm": ">=11.9.0"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@11.9.0",
|
"packageManager": "pnpm@11.9.0",
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ const integrationAliases: Partial<Record<IntegrationKind, readonly string[]>> =
|
|||||||
linuxServerIO: ["linuxserver"],
|
linuxServerIO: ["linuxserver"],
|
||||||
coolify: ["coolify"],
|
coolify: ["coolify"],
|
||||||
truenas: ["truenas"],
|
truenas: ["truenas"],
|
||||||
|
fileFlows: ["fileflows"],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const matchIntegrationKind = (search: string): IntegrationKind | null => {
|
export const matchIntegrationKind = (search: string): IntegrationKind | null => {
|
||||||
|
|||||||
@@ -312,6 +312,7 @@ export type HomarrDocumentationPath =
|
|||||||
| "/docs/integrations/dash-dot"
|
| "/docs/integrations/dash-dot"
|
||||||
| "/docs/integrations/glances"
|
| "/docs/integrations/glances"
|
||||||
| "/docs/integrations/tdarr"
|
| "/docs/integrations/tdarr"
|
||||||
|
| "/docs/integrations/fileflows"
|
||||||
| "/docs/integrations/proxmox"
|
| "/docs/integrations/proxmox"
|
||||||
| "/docs/integrations/nextcloud"
|
| "/docs/integrations/nextcloud"
|
||||||
| "/docs/integrations/unifi-controller"
|
| "/docs/integrations/unifi-controller"
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ export const integrationDocSlugs: Record<IntegrationKind, string | null> = {
|
|||||||
dashDot: "dash-dot",
|
dashDot: "dash-dot",
|
||||||
glances: "glances",
|
glances: "glances",
|
||||||
tdarr: "tdarr",
|
tdarr: "tdarr",
|
||||||
|
fileFlows: "fileflows",
|
||||||
proxmox: "proxmox",
|
proxmox: "proxmox",
|
||||||
nextcloud: "nextcloud",
|
nextcloud: "nextcloud",
|
||||||
unifiController: "unifi-controller",
|
unifiController: "unifi-controller",
|
||||||
|
|||||||
@@ -251,6 +251,14 @@ export const integrationDefs = {
|
|||||||
documentationUrl: createDocumentationLink("/docs/integrations/tdarr"),
|
documentationUrl: createDocumentationLink("/docs/integrations/tdarr"),
|
||||||
defaultPort: 8265,
|
defaultPort: 8265,
|
||||||
},
|
},
|
||||||
|
fileFlows: {
|
||||||
|
name: "FileFlows",
|
||||||
|
secretKinds: [[], ["apiKey"]],
|
||||||
|
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/fileflows.png",
|
||||||
|
category: ["mediaTranscoding"],
|
||||||
|
documentationUrl: createDocumentationLink("/docs/integrations/fileflows"),
|
||||||
|
defaultPort: 5000,
|
||||||
|
},
|
||||||
proxmox: {
|
proxmox: {
|
||||||
name: "Proxmox",
|
name: "Proxmox",
|
||||||
secretKinds: [["username", "tokenId", "apiKey", "realm"]],
|
secretKinds: [["username", "tokenId", "apiKey", "realm"]],
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import { RadarrIntegration } from "../media-organizer/radarr/radarr-integration"
|
|||||||
import { ReadarrIntegration } from "../media-organizer/readarr/readarr-integration";
|
import { ReadarrIntegration } from "../media-organizer/readarr/readarr-integration";
|
||||||
import { SonarrIntegration } from "../media-organizer/sonarr/sonarr-integration";
|
import { SonarrIntegration } from "../media-organizer/sonarr/sonarr-integration";
|
||||||
import { TdarrIntegration } from "../media-transcoding/tdarr-integration";
|
import { TdarrIntegration } from "../media-transcoding/tdarr-integration";
|
||||||
|
import { FileFlowsIntegration } from "../media-transcoding/fileflows-integration";
|
||||||
import { MockIntegration } from "../mock/mock-integration";
|
import { MockIntegration } from "../mock/mock-integration";
|
||||||
import { NavidromeIntegration } from "../navidrome/navidrome-integration";
|
import { NavidromeIntegration } from "../navidrome/navidrome-integration";
|
||||||
import { NextcloudIntegration } from "../nextcloud/nextcloud.integration";
|
import { NextcloudIntegration } from "../nextcloud/nextcloud.integration";
|
||||||
@@ -109,6 +110,7 @@ export const integrationCreators = {
|
|||||||
readarr: ReadarrIntegration,
|
readarr: ReadarrIntegration,
|
||||||
dashDot: DashDotIntegration,
|
dashDot: DashDotIntegration,
|
||||||
tdarr: TdarrIntegration,
|
tdarr: TdarrIntegration,
|
||||||
|
fileFlows: FileFlowsIntegration,
|
||||||
proxmox: ProxmoxIntegration,
|
proxmox: ProxmoxIntegration,
|
||||||
emby: EmbyIntegration,
|
emby: EmbyIntegration,
|
||||||
nextcloud: NextcloudIntegration,
|
nextcloud: NextcloudIntegration,
|
||||||
|
|||||||
@@ -0,0 +1,200 @@
|
|||||||
|
import { fetchWithTrustedCertificatesAsync } from "@homarr/core/infrastructure/http";
|
||||||
|
|
||||||
|
import type { IntegrationTestingInput } from "../base/integration";
|
||||||
|
import { Integration } from "../base/integration";
|
||||||
|
import { TestConnectionError } from "../base/test-connection/test-connection-error";
|
||||||
|
import type { TestingResult } from "../base/test-connection/test-connection-service";
|
||||||
|
import type { IMediaTranscodingIntegration } from "../interfaces/media-transcoding/media-transcoding-integration";
|
||||||
|
import type { TdarrQueue, TdarrStatistics, TdarrWorker } from "../interfaces/media-transcoding/media-transcoding-types";
|
||||||
|
import {
|
||||||
|
libraryStatusSchema,
|
||||||
|
recentlyFinishedSchema,
|
||||||
|
shrinkageGroupsSchema,
|
||||||
|
statusResponseSchema,
|
||||||
|
upcomingFilesSchema,
|
||||||
|
workersResponseSchema,
|
||||||
|
} from "./fileflows-validation-schemas";
|
||||||
|
|
||||||
|
export class FileFlowsIntegration extends Integration implements IMediaTranscodingIntegration {
|
||||||
|
protected async testingAsync(input: IntegrationTestingInput): Promise<TestingResult> {
|
||||||
|
const response = await input.fetchAsync(this.url("/api/system/version"), {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
accept: "application/json",
|
||||||
|
...(super.hasSecretValue("apiKey") ? { "X-Api-Key": super.getSecretValue("apiKey") } : {}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) return TestConnectionError.StatusResult(response);
|
||||||
|
|
||||||
|
return { success: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getStatisticsAsync(): Promise<TdarrStatistics> {
|
||||||
|
const headerParams = {
|
||||||
|
accept: "application/json",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
...(super.hasSecretValue("apiKey") ? { "X-Api-Key": super.getSecretValue("apiKey") } : {}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const [statusData, libraryStatusData, shrinkageData] = await Promise.all([
|
||||||
|
this.fetchStatusAsync(headerParams),
|
||||||
|
this.fetchLibraryStatusAsync(headerParams),
|
||||||
|
this.fetchShrinkageAsync(headerParams),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const failedCount = libraryStatusData
|
||||||
|
.filter((item) => item.Status === 4)
|
||||||
|
.reduce((sum, item) => sum + item.Count, 0);
|
||||||
|
const processedCount = libraryStatusData
|
||||||
|
.filter((item) => item.Status === 3)
|
||||||
|
.reduce((sum, item) => sum + item.Count, 0);
|
||||||
|
const queuedCount = libraryStatusData
|
||||||
|
.filter((item) => item.Status === 1 || item.Status === 5)
|
||||||
|
.reduce((sum, item) => sum + item.Count, 0);
|
||||||
|
|
||||||
|
const totalSavedSpace = Object.values(shrinkageData).reduce(
|
||||||
|
(sum, group) => sum + Math.max(0, group.OriginalSize - group.FinalSize),
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
|
||||||
|
const transcodeStatus = [
|
||||||
|
{ name: "Processed", value: statusData.processed },
|
||||||
|
{ name: "Queued", value: statusData.queue },
|
||||||
|
{ name: "Processing", value: statusData.processing },
|
||||||
|
{ name: "Failed", value: failedCount },
|
||||||
|
];
|
||||||
|
|
||||||
|
return {
|
||||||
|
libraryName: "All",
|
||||||
|
totalFileCount: processedCount + queuedCount + statusData.processing + failedCount,
|
||||||
|
totalTranscodeCount: statusData.processed,
|
||||||
|
totalHealthCheckCount: 0,
|
||||||
|
failedTranscodeCount: failedCount,
|
||||||
|
failedHealthCheckCount: 0,
|
||||||
|
stagedTranscodeCount: statusData.queue,
|
||||||
|
stagedHealthCheckCount: 0,
|
||||||
|
totalSavedSpace,
|
||||||
|
transcodeStatus,
|
||||||
|
healthCheckStatus: [],
|
||||||
|
videoCodecs: [],
|
||||||
|
videoContainers: [],
|
||||||
|
videoResolutions: [],
|
||||||
|
audioCodecs: [],
|
||||||
|
audioContainers: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getWorkersAsync(): Promise<TdarrWorker[]> {
|
||||||
|
const headerParams = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
...(super.hasSecretValue("apiKey") ? { "X-Api-Key": super.getSecretValue("apiKey") } : {}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const url = this.url("/api/worker");
|
||||||
|
const response = await fetchWithTrustedCertificatesAsync(url, {
|
||||||
|
method: "GET",
|
||||||
|
headers: headerParams,
|
||||||
|
});
|
||||||
|
|
||||||
|
const workersData = await workersResponseSchema.parseAsync(await response.json());
|
||||||
|
|
||||||
|
return workersData.map((worker) => ({
|
||||||
|
id: worker.Uid,
|
||||||
|
filePath: worker.RelativeFile ?? "",
|
||||||
|
fps: 0,
|
||||||
|
percentage: worker.CurrentPartPercent,
|
||||||
|
ETA: worker.ProcessingTime?.TotalSeconds ? `${Math.round(worker.ProcessingTime.TotalSeconds)}s` : "",
|
||||||
|
jobType: worker.CurrentPartName ?? "Processing",
|
||||||
|
status: "Processing",
|
||||||
|
step: worker.CurrentPartName ?? "",
|
||||||
|
originalSize: worker.LibraryFile?.OriginalSize ?? 0,
|
||||||
|
estimatedSize: null,
|
||||||
|
outputSize: null,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getQueueAsync(firstItemIndex: number, pageSize: number): Promise<TdarrQueue> {
|
||||||
|
const headerParams = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
...(super.hasSecretValue("apiKey") ? { "X-Api-Key": super.getSecretValue("apiKey") } : {}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const [upcomingItems, recentlyFinishedItems] = await Promise.all([
|
||||||
|
this.fetchUpcomingAsync(headerParams),
|
||||||
|
this.fetchRecentlyFinishedAsync(headerParams),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const queueArray = [
|
||||||
|
...upcomingItems.map((item) => ({
|
||||||
|
id: item.Uid,
|
||||||
|
healthCheck: "",
|
||||||
|
transcode: item.Flow ?? "Default",
|
||||||
|
filePath: item.RelativePath ?? item.Name ?? "",
|
||||||
|
fileSize: item.OriginalSize ?? 0,
|
||||||
|
container: "",
|
||||||
|
codec: "",
|
||||||
|
resolution: "",
|
||||||
|
type: "transcode" as const,
|
||||||
|
})),
|
||||||
|
...recentlyFinishedItems.map((item) => ({
|
||||||
|
id: item.Uid,
|
||||||
|
healthCheck: "",
|
||||||
|
transcode: item.Flow ?? "Default",
|
||||||
|
filePath: item.RelativePath ?? item.Name ?? "",
|
||||||
|
fileSize: item.FinalSize ?? item.OriginalSize ?? 0,
|
||||||
|
container: "",
|
||||||
|
codec: "",
|
||||||
|
resolution: "",
|
||||||
|
type: "health-check" as const,
|
||||||
|
})),
|
||||||
|
].slice(0, pageSize);
|
||||||
|
|
||||||
|
return {
|
||||||
|
array: queueArray,
|
||||||
|
totalCount: upcomingItems.length + recentlyFinishedItems.length,
|
||||||
|
startIndex: firstItemIndex,
|
||||||
|
endIndex: firstItemIndex + queueArray.length - 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async fetchStatusAsync(headerParams: Record<string, string>) {
|
||||||
|
const response = await fetchWithTrustedCertificatesAsync(this.url("/api/status"), {
|
||||||
|
method: "GET",
|
||||||
|
headers: headerParams,
|
||||||
|
});
|
||||||
|
return statusResponseSchema.parseAsync(await response.json());
|
||||||
|
}
|
||||||
|
|
||||||
|
private async fetchLibraryStatusAsync(headerParams: Record<string, string>) {
|
||||||
|
const response = await fetchWithTrustedCertificatesAsync(this.url("/api/library-file/status"), {
|
||||||
|
method: "GET",
|
||||||
|
headers: headerParams,
|
||||||
|
});
|
||||||
|
return libraryStatusSchema.parseAsync(await response.json());
|
||||||
|
}
|
||||||
|
|
||||||
|
private async fetchShrinkageAsync(headerParams: Record<string, string>) {
|
||||||
|
const response = await fetchWithTrustedCertificatesAsync(this.url("/api/library-file/shrinkage-groups"), {
|
||||||
|
method: "GET",
|
||||||
|
headers: headerParams,
|
||||||
|
});
|
||||||
|
return shrinkageGroupsSchema.parseAsync(await response.json());
|
||||||
|
}
|
||||||
|
|
||||||
|
private async fetchUpcomingAsync(headerParams: Record<string, string>) {
|
||||||
|
const response = await fetchWithTrustedCertificatesAsync(this.url("/api/library-file/upcoming"), {
|
||||||
|
method: "GET",
|
||||||
|
headers: headerParams,
|
||||||
|
});
|
||||||
|
return upcomingFilesSchema.parseAsync(await response.json());
|
||||||
|
}
|
||||||
|
|
||||||
|
private async fetchRecentlyFinishedAsync(headerParams: Record<string, string>) {
|
||||||
|
const response = await fetchWithTrustedCertificatesAsync(this.url("/api/library-file/recently-finished"), {
|
||||||
|
method: "GET",
|
||||||
|
headers: headerParams,
|
||||||
|
});
|
||||||
|
return recentlyFinishedSchema.parseAsync(await response.json());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
|
export const statusResponseSchema = z.object({
|
||||||
|
queue: z.number(),
|
||||||
|
processing: z.number(),
|
||||||
|
processed: z.number(),
|
||||||
|
processingFiles: z
|
||||||
|
.array(
|
||||||
|
z.object({
|
||||||
|
name: z.string().nullable(),
|
||||||
|
relativePath: z.string().nullable(),
|
||||||
|
library: z.string().nullable(),
|
||||||
|
step: z.string().nullable(),
|
||||||
|
stepPercent: z.number(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.optional()
|
||||||
|
.transform((arr) => arr ?? []),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const libraryStatusSchema = z.array(
|
||||||
|
z.object({
|
||||||
|
Name: z.string().nullable(),
|
||||||
|
Status: z.number(),
|
||||||
|
Count: z.number(),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
export const shrinkageGroupsSchema = z.record(
|
||||||
|
z.string(),
|
||||||
|
z.object({
|
||||||
|
Library: z.string().nullable(),
|
||||||
|
OriginalSize: z.number(),
|
||||||
|
FinalSize: z.number(),
|
||||||
|
Items: z.number(),
|
||||||
|
Difference: z.number().optional(),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
export const workersResponseSchema = z.array(
|
||||||
|
z.object({
|
||||||
|
Uid: z.string(),
|
||||||
|
NodeName: z.string().nullable(),
|
||||||
|
RelativeFile: z.string().nullable(),
|
||||||
|
CurrentPart: z.number(),
|
||||||
|
CurrentPartName: z.string().nullable(),
|
||||||
|
CurrentPartPercent: z.number(),
|
||||||
|
StartedAt: z.string(),
|
||||||
|
LastUpdate: z.string(),
|
||||||
|
ProcessingTime: z
|
||||||
|
.object({
|
||||||
|
TotalSeconds: z.number().optional(),
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
|
LibraryFile: z
|
||||||
|
.object({
|
||||||
|
OriginalSize: z.number(),
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
|
Library: z
|
||||||
|
.object({
|
||||||
|
Name: z.string().nullable(),
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
export const upcomingFilesSchema = z.array(
|
||||||
|
z.object({
|
||||||
|
Uid: z.string(),
|
||||||
|
Name: z.string().nullable(),
|
||||||
|
RelativePath: z.string().nullable(),
|
||||||
|
OriginalSize: z.number().nullable(),
|
||||||
|
FinalSize: z.number().nullable(),
|
||||||
|
Status: z.number(),
|
||||||
|
Library: z.string().nullable(),
|
||||||
|
Flow: z.string().nullable(),
|
||||||
|
Node: z.string().nullable(),
|
||||||
|
ProcessingTime: z
|
||||||
|
.object({
|
||||||
|
TotalSeconds: z.number().optional(),
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
export const recentlyFinishedSchema = z.array(
|
||||||
|
z.object({
|
||||||
|
Uid: z.string(),
|
||||||
|
Name: z.string().nullable(),
|
||||||
|
RelativePath: z.string().nullable(),
|
||||||
|
OriginalSize: z.number().nullable(),
|
||||||
|
FinalSize: z.number().nullable(),
|
||||||
|
Status: z.number(),
|
||||||
|
Library: z.string().nullable(),
|
||||||
|
Flow: z.string().nullable(),
|
||||||
|
}),
|
||||||
|
);
|
||||||
Generated
+29
-14
@@ -337,8 +337,8 @@ catalogs:
|
|||||||
specifier: ^0.2.9
|
specifier: ^0.2.9
|
||||||
version: 0.2.9
|
version: 0.2.9
|
||||||
dockerode:
|
dockerode:
|
||||||
specifier: ^5.0.0
|
specifier: ^5.0.1
|
||||||
version: 5.0.0
|
version: 5.0.1
|
||||||
dotenv:
|
dotenv:
|
||||||
specifier: ^17.4.2
|
specifier: ^17.4.2
|
||||||
version: 17.4.2
|
version: 17.4.2
|
||||||
@@ -445,8 +445,8 @@ catalogs:
|
|||||||
specifier: ^1.18.0
|
specifier: ^1.18.0
|
||||||
version: 1.18.0
|
version: 1.18.0
|
||||||
posthog-js:
|
posthog-js:
|
||||||
specifier: ^1.393.4
|
specifier: ^1.393.5
|
||||||
version: 1.393.4
|
version: 1.395.0
|
||||||
posthog-node:
|
posthog-node:
|
||||||
specifier: ^4.18.0
|
specifier: ^4.18.0
|
||||||
version: 4.18.0
|
version: 4.18.0
|
||||||
@@ -1012,7 +1012,7 @@ importers:
|
|||||||
version: 1.18.0(postcss@8.5.15)
|
version: 1.18.0(postcss@8.5.15)
|
||||||
posthog-js:
|
posthog-js:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 1.393.4
|
version: 1.395.0
|
||||||
prismjs:
|
prismjs:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 1.30.0
|
version: 1.30.0
|
||||||
@@ -1771,7 +1771,7 @@ importers:
|
|||||||
version: link:../core
|
version: link:../core
|
||||||
dockerode:
|
dockerode:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 5.0.0
|
version: 5.0.1
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@homarr/tsconfig':
|
'@homarr/tsconfig':
|
||||||
specifier: workspace:^0.1.0
|
specifier: workspace:^0.1.0
|
||||||
@@ -6418,8 +6418,8 @@ packages:
|
|||||||
'@polka/url@1.0.0-next.25':
|
'@polka/url@1.0.0-next.25':
|
||||||
resolution: {integrity: sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==}
|
resolution: {integrity: sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==}
|
||||||
|
|
||||||
'@posthog/core@1.37.3':
|
'@posthog/core@1.38.0':
|
||||||
resolution: {integrity: sha512-Dvw4CTlRVH4K5ag/B8YIHgG4E27w43MCUsXpn1iKQHIggIMN3Shq9whG4Omm3OvXPF+VikBTmpyMKUjckPxw+g==}
|
resolution: {integrity: sha512-QLrJh0hMVpEJXHNyiJR9YhvIO5tzLDedw4UHdvB+ub4fXHMtHCA8H44qgl11HWR3ajpjxtJ8hs3HyOGVF3Zc1w==}
|
||||||
|
|
||||||
'@posthog/types@1.391.1':
|
'@posthog/types@1.391.1':
|
||||||
resolution: {integrity: sha512-ASwd7Nf4pViqdYRYaNRyPYRVKWa1CcHUAUWR0XeQJLGdNnsWACBwe0sSieb/cHnKsRXjRwO/23KIY83lm/Ccpw==}
|
resolution: {integrity: sha512-ASwd7Nf4pViqdYRYaNRyPYRVKWa1CcHUAUWR0XeQJLGdNnsWACBwe0sSieb/cHnKsRXjRwO/23KIY83lm/Ccpw==}
|
||||||
@@ -9678,6 +9678,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-C52mvJ+7lcyhWNfrzVfFsbTrBfy/ezE9FGEYLpu17FUeBcCkxERk9nN7uDl/478ynDiQ4U+5DbQC2vENHkVEtQ==}
|
resolution: {integrity: sha512-C52mvJ+7lcyhWNfrzVfFsbTrBfy/ezE9FGEYLpu17FUeBcCkxERk9nN7uDl/478ynDiQ4U+5DbQC2vENHkVEtQ==}
|
||||||
engines: {node: '>= 14.17'}
|
engines: {node: '>= 14.17'}
|
||||||
|
|
||||||
|
dockerode@5.0.1:
|
||||||
|
resolution: {integrity: sha512-avsq/xk4YPIrn0CgleX5bjT9Y8IT1p9PxrNQ++RBQ2WEyFfHCTDsT9kmyxz+H/axnjAwg8wJWEIuPGOUuNupiA==}
|
||||||
|
engines: {node: '>= 14.17'}
|
||||||
|
|
||||||
docusaurus-plugin-image-zoom@3.0.1:
|
docusaurus-plugin-image-zoom@3.0.1:
|
||||||
resolution: {integrity: sha512-mQrqA99VpoMQJNbi02qkWAMVNC4+kwc6zLLMNzraHAJlwn+HrlUmZSEDcTwgn+H4herYNxHKxveE2WsYy73eGw==}
|
resolution: {integrity: sha512-mQrqA99VpoMQJNbi02qkWAMVNC4+kwc6zLLMNzraHAJlwn+HrlUmZSEDcTwgn+H4herYNxHKxveE2WsYy73eGw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -13116,8 +13120,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-Ray65LYEJrMMqDtsBUBXunEVP/g4wtATvq/xz9rchUoLy/9mSkkFgUko/8DVtGxgiP3vivpFMgfb9HpCuDrBHg==}
|
resolution: {integrity: sha512-Ray65LYEJrMMqDtsBUBXunEVP/g4wtATvq/xz9rchUoLy/9mSkkFgUko/8DVtGxgiP3vivpFMgfb9HpCuDrBHg==}
|
||||||
engines: {node: '>=10.15.1'}
|
engines: {node: '>=10.15.1'}
|
||||||
|
|
||||||
posthog-js@1.393.4:
|
posthog-js@1.395.0:
|
||||||
resolution: {integrity: sha512-mOBSVQczEfyLnW3aFRbLXZEuE0Rfbmhqm9UCnuLeMFUUz0uYTkbnyhl5+Uc+BLSGfyiXHLf3nm2BqxYC+G/PXA==}
|
resolution: {integrity: sha512-5iTb00CGt2eQUUiBQysQiX89RAbCN6wK2sDNzvs9zv0alaY8mJ0ZySrUD3LQ+XyLhgM5pCpacBuUwChqiYDLDw==}
|
||||||
|
|
||||||
posthog-node@4.18.0:
|
posthog-node@4.18.0:
|
||||||
resolution: {integrity: sha512-XROs1h+DNatgKh/AlIlCtDxWzwrKdYDb2mOs58n4yN8BkGN9ewqeQwG5ApS4/IzwCb7HPttUkOVulkYatd2PIw==}
|
resolution: {integrity: sha512-XROs1h+DNatgKh/AlIlCtDxWzwrKdYDb2mOs58n4yN8BkGN9ewqeQwG5ApS4/IzwCb7HPttUkOVulkYatd2PIw==}
|
||||||
@@ -17951,7 +17955,7 @@ snapshots:
|
|||||||
|
|
||||||
'@esbuild-kit/core-utils@3.3.2':
|
'@esbuild-kit/core-utils@3.3.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.28.0
|
esbuild: 0.28.1
|
||||||
source-map-support: 0.5.21
|
source-map-support: 0.5.21
|
||||||
|
|
||||||
'@esbuild-kit/esm-loader@2.6.5':
|
'@esbuild-kit/esm-loader@2.6.5':
|
||||||
@@ -19897,7 +19901,7 @@ snapshots:
|
|||||||
|
|
||||||
'@polka/url@1.0.0-next.25': {}
|
'@polka/url@1.0.0-next.25': {}
|
||||||
|
|
||||||
'@posthog/core@1.37.3':
|
'@posthog/core@1.38.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@posthog/types': 1.391.1
|
'@posthog/types': 1.391.1
|
||||||
|
|
||||||
@@ -23479,6 +23483,17 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
dockerode@5.0.1:
|
||||||
|
dependencies:
|
||||||
|
'@balena/dockerignore': 1.0.2
|
||||||
|
'@grpc/grpc-js': 1.12.5
|
||||||
|
'@grpc/proto-loader': 0.7.13
|
||||||
|
docker-modem: 5.0.7
|
||||||
|
protobufjs: 7.4.0
|
||||||
|
tar-fs: 2.1.4
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
docusaurus-plugin-image-zoom@3.0.1(@docusaurus/theme-classic@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.3(@swc/helpers@0.5.15))(esbuild@0.28.1)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@swc/helpers@0.5.15)(esbuild@0.28.1)(postcss@8.5.15))(@rspack/core@1.7.11(@swc/helpers@0.5.15))(@swc/core@1.15.3(@swc/helpers@0.5.15))(@types/react@19.2.17)(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@6.0.3)):
|
docusaurus-plugin-image-zoom@3.0.1(@docusaurus/theme-classic@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.3(@swc/helpers@0.5.15))(esbuild@0.28.1)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@swc/helpers@0.5.15)(esbuild@0.28.1)(postcss@8.5.15))(@rspack/core@1.7.11(@swc/helpers@0.5.15))(@swc/core@1.15.3(@swc/helpers@0.5.15))(@types/react@19.2.17)(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@6.0.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@docusaurus/theme-classic': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.3(@swc/helpers@0.5.15))(esbuild@0.28.1)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@swc/helpers@0.5.15)(esbuild@0.28.1)(postcss@8.5.15))(@rspack/core@1.7.11(@swc/helpers@0.5.15))(@swc/core@1.15.3(@swc/helpers@0.5.15))(@types/react@19.2.17)(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@6.0.3)
|
'@docusaurus/theme-classic': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.3(@swc/helpers@0.5.15))(esbuild@0.28.1)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@swc/helpers@0.5.15)(esbuild@0.28.1)(postcss@8.5.15))(@rspack/core@1.7.11(@swc/helpers@0.5.15))(@swc/core@1.15.3(@swc/helpers@0.5.15))(@types/react@19.2.17)(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@6.0.3)
|
||||||
@@ -27405,9 +27420,9 @@ snapshots:
|
|||||||
|
|
||||||
posthog-docusaurus@2.0.5: {}
|
posthog-docusaurus@2.0.5: {}
|
||||||
|
|
||||||
posthog-js@1.393.4:
|
posthog-js@1.395.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@posthog/core': 1.37.3
|
'@posthog/core': 1.38.0
|
||||||
'@posthog/types': 1.391.1
|
'@posthog/types': 1.391.1
|
||||||
core-js: 3.49.0
|
core-js: 3.49.0
|
||||||
dompurify: 3.4.11
|
dompurify: 3.4.11
|
||||||
|
|||||||
+2
-2
@@ -92,7 +92,7 @@ catalog:
|
|||||||
"@types/video.js": ^7.3.58
|
"@types/video.js": ^7.3.58
|
||||||
"@types/ws": ^8.18.1
|
"@types/ws": ^8.18.1
|
||||||
"@types/xml2js": ^0.4.14
|
"@types/xml2js": ^0.4.14
|
||||||
posthog-js: ^1.393.4
|
posthog-js: ^1.393.5
|
||||||
posthog-node: ^4.18.0
|
posthog-node: ^4.18.0
|
||||||
"@vitejs/plugin-react": ^6.0.3
|
"@vitejs/plugin-react": ^6.0.3
|
||||||
"@vitest/coverage-v8": ^4.1.9
|
"@vitest/coverage-v8": ^4.1.9
|
||||||
@@ -118,7 +118,7 @@ catalog:
|
|||||||
dayjs: ^1.11.21
|
dayjs: ^1.11.21
|
||||||
deepmerge: 4.3.1
|
deepmerge: 4.3.1
|
||||||
dns-caching: ^0.2.9
|
dns-caching: ^0.2.9
|
||||||
dockerode: ^5.0.0
|
dockerode: ^5.0.1
|
||||||
dotenv: ^17.4.2
|
dotenv: ^17.4.2
|
||||||
dotenv-cli: ^11.0.0
|
dotenv-cli: ^11.0.0
|
||||||
drizzle-kit: ^0.31.10
|
drizzle-kit: ^0.31.10
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ runs:
|
|||||||
- uses: pnpm/action-setup@v6
|
- uses: pnpm/action-setup@v6
|
||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: 24.17.0
|
node-version: 24.18.0
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
|
|
||||||
- shell: bash
|
- shell: bash
|
||||||
|
|||||||
Reference in new issue
Block a user