fix: migrate from node-cron to croner (#5407)
This commit is contained in:
1 parent
ed6680ba6a
commit
e8edc203b6
10 files changed
+72
-116
No files matched your search
@@ -37,6 +37,7 @@
|
||||
"@homarr/server-settings": "workspace:^0.1.0",
|
||||
"@homarr/validation": "workspace:^0.1.0",
|
||||
"@homarr/widgets": "workspace:^0.1.0",
|
||||
"croner": "catalog:",
|
||||
"dayjs": "catalog:",
|
||||
"dotenv": "catalog:",
|
||||
"fastify": "catalog:",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { schedule, validate as validateCron } from "node-cron";
|
||||
import { Cron } from "croner";
|
||||
|
||||
import { createLogger } from "@homarr/core/infrastructure/logs";
|
||||
import type { IJobManager } from "@homarr/cron-job-api";
|
||||
@@ -21,28 +21,31 @@ export class JobManager implements IJobManager {
|
||||
public async triggerAsync(name: JobGroupKeys): Promise<void> {
|
||||
await this.jobGroup.runManuallyAsync(name);
|
||||
}
|
||||
public async stopAsync(name: JobGroupKeys): Promise<void> {
|
||||
await this.jobGroup.stopAsync(name);
|
||||
public stop(name: JobGroupKeys): void {
|
||||
this.jobGroup.stop(name);
|
||||
}
|
||||
public async updateIntervalAsync(name: JobGroupKeys, cron: string): Promise<void> {
|
||||
logger.info("Updating cron job interval", { name, expression: cron });
|
||||
const job = this.jobGroup.getJobRegistry().get(name);
|
||||
if (!job) throw new Error(`Job ${name} not found`);
|
||||
if (!validateCron(cron)) {
|
||||
throw new Error(`Invalid cron expression: ${cron}`);
|
||||
}
|
||||
if (job.preventCustomInterval && cron !== job.cronExpression) {
|
||||
throw new Error(`Custom cron expressions are not allowed for job ${name}`);
|
||||
}
|
||||
|
||||
await this.updateConfigurationAsync(name, { cronExpression: cron });
|
||||
await this.jobGroup.getTask(name)?.destroy();
|
||||
const updatedConfig = await this.updateConfigurationAsync(name, { cronExpression: cron });
|
||||
this.jobGroup.getTask(name)?.stop();
|
||||
|
||||
this.jobGroup.setTask(
|
||||
name,
|
||||
schedule(cron, () => void job.executeAsync(), {
|
||||
name,
|
||||
}),
|
||||
new Cron(
|
||||
cron,
|
||||
{
|
||||
name,
|
||||
timezone: job.timezone,
|
||||
paused: !updatedConfig.isEnabled,
|
||||
},
|
||||
() => void job.executeAsync(),
|
||||
),
|
||||
);
|
||||
logger.info("Cron job interval updated", { name, expression: cron });
|
||||
}
|
||||
@@ -52,7 +55,7 @@ export class JobManager implements IJobManager {
|
||||
if (!job) throw new Error(`Job ${name} not found`);
|
||||
|
||||
await this.updateConfigurationAsync(name, { isEnabled: false });
|
||||
await this.jobGroup.stopAsync(name);
|
||||
this.jobGroup.stop(name);
|
||||
logger.info("Cron job disabled", { name });
|
||||
}
|
||||
public async enableAsync(name: JobGroupKeys): Promise<void> {
|
||||
@@ -86,21 +89,27 @@ export class JobManager implements IJobManager {
|
||||
name,
|
||||
configuration: JSON.stringify(configuration),
|
||||
});
|
||||
return;
|
||||
return {
|
||||
name,
|
||||
cronExpression: configuration.cronExpression ?? existingConfig.cronExpression,
|
||||
isEnabled: configuration.isEnabled ?? existingConfig.isEnabled,
|
||||
};
|
||||
}
|
||||
|
||||
const job = this.jobGroup.getJobRegistry().get(name);
|
||||
if (!job) throw new Error(`Job ${name} not found`);
|
||||
|
||||
await this.db.insert(cronJobConfigurations).values({
|
||||
const updatedConfig = {
|
||||
name,
|
||||
cronExpression: configuration.cronExpression ?? job.cronExpression,
|
||||
isEnabled: configuration.isEnabled ?? true,
|
||||
});
|
||||
};
|
||||
await this.db.insert(cronJobConfigurations).values(updatedConfig);
|
||||
logger.debug("Cron job configuration updated", {
|
||||
name,
|
||||
configuration: JSON.stringify(configuration),
|
||||
});
|
||||
return updatedConfig;
|
||||
}
|
||||
|
||||
public async getAllAsync(): Promise<
|
||||
|
||||
@@ -2,7 +2,7 @@ import { observable } from "@trpc/server/observable";
|
||||
import z from "zod/v4";
|
||||
|
||||
import { createLogger } from "@homarr/core/infrastructure/logs";
|
||||
import { cronExpressionSchema, jobGroupKeys, jobNameSchema } from "@homarr/cron-job-api";
|
||||
import { jobGroupKeys, jobNameSchema } from "@homarr/cron-job-api";
|
||||
import { cronJobApi } from "@homarr/cron-job-api/client";
|
||||
import type { TaskStatus } from "@homarr/cron-job-status";
|
||||
import { createCronJobStatusChannel } from "@homarr/cron-job-status";
|
||||
@@ -35,7 +35,7 @@ export const cronJobsRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
name: jobNameSchema,
|
||||
cron: cronExpressionSchema,
|
||||
cron: z.string(),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ input }) => {
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
"@trpc/client": "catalog:",
|
||||
"@trpc/server": "catalog:",
|
||||
"@trpc/tanstack-react-query": "catalog:",
|
||||
"node-cron": "catalog:",
|
||||
"react": "catalog:",
|
||||
"zod": "catalog:"
|
||||
},
|
||||
@@ -40,7 +39,6 @@
|
||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||
"@homarr/prettier-config": "workspace:^0.1.0",
|
||||
"@homarr/tsconfig": "workspace:^0.1.0",
|
||||
"@types/node-cron": "catalog:",
|
||||
"@types/react": "catalog:",
|
||||
"eslint": "catalog:",
|
||||
"typescript": "catalog:"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { initTRPC, TRPCError } from "@trpc/server";
|
||||
import { validate } from "node-cron";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import type { JobGroupKeys } from "@homarr/cron-jobs";
|
||||
@@ -13,7 +12,7 @@ export const jobNameSchema = z.enum(jobGroup.getKeys());
|
||||
export interface IJobManager {
|
||||
startAsync(name: JobGroupKeys): Promise<void>;
|
||||
triggerAsync(name: JobGroupKeys): Promise<void>;
|
||||
stopAsync(name: JobGroupKeys): Promise<void>;
|
||||
stop(name: JobGroupKeys): void;
|
||||
updateIntervalAsync(name: JobGroupKeys, cron: string): Promise<void>;
|
||||
disableAsync(name: JobGroupKeys): Promise<void>;
|
||||
enableAsync(name: JobGroupKeys): Promise<void>;
|
||||
@@ -52,10 +51,6 @@ const apiKeyProcedure = t.procedure.use(({ ctx, next }) => {
|
||||
});
|
||||
});
|
||||
|
||||
export const cronExpressionSchema = z.string().refine((expression) => validate(expression), {
|
||||
error: "Invalid cron expression",
|
||||
});
|
||||
|
||||
export const jobRouter = createTrpcRouter({
|
||||
start: apiKeyProcedure.input(jobNameSchema).mutation(async ({ input, ctx }) => {
|
||||
await ctx.manager.startAsync(input);
|
||||
@@ -63,14 +58,14 @@ export const jobRouter = createTrpcRouter({
|
||||
trigger: apiKeyProcedure.input(jobNameSchema).mutation(async ({ input, ctx }) => {
|
||||
await ctx.manager.triggerAsync(input);
|
||||
}),
|
||||
stop: apiKeyProcedure.input(jobNameSchema).mutation(async ({ input, ctx }) => {
|
||||
await ctx.manager.stopAsync(input);
|
||||
stop: apiKeyProcedure.input(jobNameSchema).mutation(({ input, ctx }) => {
|
||||
ctx.manager.stop(input);
|
||||
}),
|
||||
updateInterval: apiKeyProcedure
|
||||
.input(
|
||||
z.object({
|
||||
name: jobNameSchema,
|
||||
cron: cronExpressionSchema,
|
||||
cron: z.string(),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
|
||||
@@ -27,13 +27,12 @@
|
||||
"@homarr/common": "workspace:^0.1.0",
|
||||
"@homarr/core": "workspace:^",
|
||||
"@homarr/db": "workspace:^0.1.0",
|
||||
"node-cron": "catalog:"
|
||||
"croner": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||
"@homarr/prettier-config": "workspace:^0.1.0",
|
||||
"@homarr/tsconfig": "workspace:^0.1.0",
|
||||
"@types/node-cron": "catalog:",
|
||||
"eslint": "catalog:",
|
||||
"typescript": "catalog:"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createTask, validate } from "node-cron";
|
||||
import { Cron } from "croner";
|
||||
|
||||
import { Stopwatch } from "@homarr/common";
|
||||
import type { MaybePromise } from "@homarr/common/types";
|
||||
@@ -83,10 +83,15 @@ const createCallback = <TAllowedNames extends string, TName extends TAllowedName
|
||||
? defaultCronExpression
|
||||
: (configuration?.cronExpression ?? defaultCronExpression);
|
||||
|
||||
const scheduledTask = createTask(cronExpression, () => void catchingCallbackAsync(), {
|
||||
name,
|
||||
timezone: creatorOptions.timezone,
|
||||
});
|
||||
const scheduledTask = new Cron(
|
||||
cronExpression,
|
||||
{
|
||||
name,
|
||||
timezone: creatorOptions.timezone,
|
||||
paused: true,
|
||||
},
|
||||
() => void catchingCallbackAsync(),
|
||||
);
|
||||
creatorOptions.logger.logDebug("The scheduled task for cron job was created", {
|
||||
name,
|
||||
cronExpression: defaultCronExpression,
|
||||
@@ -116,6 +121,7 @@ const createCallback = <TAllowedNames extends string, TName extends TAllowedName
|
||||
},
|
||||
preventManualExecution: options.preventManualExecution ?? false,
|
||||
preventCustomInterval: options.preventCustomInterval ?? false,
|
||||
timezone: creatorOptions.timezone,
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -132,13 +138,6 @@ export const createCronJobCreator = <TAllowedNames extends string = string>(
|
||||
defaultCronExpression: TExpression,
|
||||
options: CreateCronJobOptions = { runOnStart: false },
|
||||
) => {
|
||||
creatorOptions.logger.logDebug("Validating cron expression for cron job", {
|
||||
name,
|
||||
cronExpression: defaultCronExpression,
|
||||
});
|
||||
if (!validate(defaultCronExpression)) {
|
||||
throw new Error(`Invalid cron expression '${defaultCronExpression}' for job '${name}'`);
|
||||
}
|
||||
creatorOptions.logger.logDebug("Cron job expression for cron job is valid", {
|
||||
name,
|
||||
cronExpression: defaultCronExpression,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { ScheduledTask } from "node-cron";
|
||||
import type { Cron } from "croner";
|
||||
|
||||
import { objectEntries, objectKeys } from "@homarr/common";
|
||||
import { db } from "@homarr/db";
|
||||
@@ -34,7 +34,7 @@ export const createJobGroupCreator = <TAllowedNames extends string = string>(
|
||||
});
|
||||
}
|
||||
|
||||
const tasks = new Map<string, ScheduledTask>();
|
||||
const tasks = new Map<string, Cron>();
|
||||
|
||||
return {
|
||||
initializeAsync: async () => {
|
||||
@@ -62,7 +62,7 @@ export const createJobGroupCreator = <TAllowedNames extends string = string>(
|
||||
name: job.name,
|
||||
});
|
||||
await job.onStartAsync();
|
||||
await tasks.get(name as string)?.start();
|
||||
tasks.get(name as string)?.resume();
|
||||
},
|
||||
startAllAsync: async () => {
|
||||
for (const job of jobRegistry.values()) {
|
||||
@@ -74,7 +74,7 @@ export const createJobGroupCreator = <TAllowedNames extends string = string>(
|
||||
name: job.name,
|
||||
});
|
||||
await job.onStartAsync();
|
||||
await tasks.get(job.name)?.start();
|
||||
tasks.get(job.name)?.resume();
|
||||
}
|
||||
},
|
||||
runManuallyAsync: async (name: keyof TJobs) => {
|
||||
@@ -87,23 +87,23 @@ export const createJobGroupCreator = <TAllowedNames extends string = string>(
|
||||
options.logger.logInfo("Running schedule cron job manually.", {
|
||||
name: job.name,
|
||||
});
|
||||
await tasks.get(name as string)?.execute();
|
||||
await tasks.get(name as string)?.trigger();
|
||||
},
|
||||
stopAsync: async (name: keyof TJobs) => {
|
||||
stop: (name: keyof TJobs) => {
|
||||
const job = jobRegistry.get(name as string);
|
||||
if (!job) return;
|
||||
|
||||
options.logger.logInfo("Stopping schedule of cron job.", {
|
||||
name: job.name,
|
||||
});
|
||||
await tasks.get(name as string)?.stop();
|
||||
tasks.get(name as string)?.pause();
|
||||
},
|
||||
stopAllAsync: async () => {
|
||||
stopAll: () => {
|
||||
for (const job of jobRegistry.values()) {
|
||||
options.logger.logInfo("Stopping schedule of cron job.", {
|
||||
name: job.name,
|
||||
});
|
||||
await tasks.get(job.name)?.stop();
|
||||
tasks.get(job.name)?.pause();
|
||||
}
|
||||
},
|
||||
getJobRegistry() {
|
||||
@@ -112,8 +112,8 @@ export const createJobGroupCreator = <TAllowedNames extends string = string>(
|
||||
getTask(name: keyof TJobs) {
|
||||
return tasks.get(name as string) ?? null;
|
||||
},
|
||||
setTask(name: keyof TJobs, task: ScheduledTask) {
|
||||
tasks.set(name as string, task);
|
||||
setTask(name: keyof TJobs, cron: Cron) {
|
||||
tasks.set(name as string, cron);
|
||||
},
|
||||
getKeys() {
|
||||
return objectKeys(jobs);
|
||||
|
||||
Generated
+17
-61
@@ -240,9 +240,6 @@ catalogs:
|
||||
'@types/node':
|
||||
specifier: ^24.12.2
|
||||
version: 24.12.2
|
||||
'@types/node-cron':
|
||||
specifier: ^3.0.11
|
||||
version: 3.0.11
|
||||
'@types/node-unifi':
|
||||
specifier: ^2.5.1
|
||||
version: 2.5.1
|
||||
@@ -321,6 +318,9 @@ catalogs:
|
||||
cookies:
|
||||
specifier: ^0.9.1
|
||||
version: 0.9.1
|
||||
croner:
|
||||
specifier: 10.0.1
|
||||
version: 10.0.1
|
||||
cross-env:
|
||||
specifier: ^10.1.0
|
||||
version: 10.1.0
|
||||
@@ -435,9 +435,6 @@ catalogs:
|
||||
next-intl:
|
||||
specifier: 4.9.1
|
||||
version: 4.9.1
|
||||
node-cron:
|
||||
specifier: ^4.2.1
|
||||
version: 4.2.1
|
||||
node-loader:
|
||||
specifier: ^2.1.0
|
||||
version: 2.1.0
|
||||
@@ -986,6 +983,9 @@ importers:
|
||||
'@homarr/widgets':
|
||||
specifier: workspace:^0.1.0
|
||||
version: link:../../packages/widgets
|
||||
croner:
|
||||
specifier: 'catalog:'
|
||||
version: 10.0.1
|
||||
dayjs:
|
||||
specifier: 'catalog:'
|
||||
version: 1.11.20
|
||||
@@ -1526,9 +1526,6 @@ importers:
|
||||
'@trpc/tanstack-react-query':
|
||||
specifier: 'catalog:'
|
||||
version: 11.16.0(@tanstack/react-query@5.100.5(react@19.2.5))(@trpc/client@11.16.0(@trpc/server@11.16.0(typescript@5.9.3))(typescript@5.9.3))(@trpc/server@11.16.0(typescript@5.9.3))(react@19.2.5)(typescript@5.9.3)
|
||||
node-cron:
|
||||
specifier: 'catalog:'
|
||||
version: 4.2.1
|
||||
react:
|
||||
specifier: 'catalog:'
|
||||
version: 19.2.5
|
||||
@@ -1545,9 +1542,6 @@ importers:
|
||||
'@homarr/tsconfig':
|
||||
specifier: workspace:^0.1.0
|
||||
version: link:../../tooling/typescript
|
||||
'@types/node-cron':
|
||||
specifier: 'catalog:'
|
||||
version: 3.0.11
|
||||
'@types/react':
|
||||
specifier: 'catalog:'
|
||||
version: 19.2.14
|
||||
@@ -1661,9 +1655,9 @@ importers:
|
||||
'@homarr/db':
|
||||
specifier: workspace:^0.1.0
|
||||
version: link:../db
|
||||
node-cron:
|
||||
croner:
|
||||
specifier: 'catalog:'
|
||||
version: 4.2.1
|
||||
version: 10.0.1
|
||||
devDependencies:
|
||||
'@homarr/eslint-config':
|
||||
specifier: workspace:^0.2.0
|
||||
@@ -1674,9 +1668,6 @@ importers:
|
||||
'@homarr/tsconfig':
|
||||
specifier: workspace:^0.1.0
|
||||
version: link:../../tooling/typescript
|
||||
'@types/node-cron':
|
||||
specifier: 'catalog:'
|
||||
version: 3.0.11
|
||||
eslint:
|
||||
specifier: 'catalog:'
|
||||
version: 9.39.4
|
||||
@@ -4383,7 +4374,6 @@ packages:
|
||||
|
||||
'@million/lint@1.0.14':
|
||||
resolution: {integrity: sha512-u6/kglVwZRu5+GMmtkNlGLqJVkgTl0TtM+hLa9rBg7pldx+5NG5bk45NvL37uZmAr2Xfa1C6qHb7GrFwfP372g==}
|
||||
deprecated: This package is no longer maintained
|
||||
hasBin: true
|
||||
|
||||
'@ndaidong/bellajs@12.0.1':
|
||||
@@ -5688,9 +5678,6 @@ packages:
|
||||
'@types/ms@2.1.0':
|
||||
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
|
||||
|
||||
'@types/node-cron@3.0.11':
|
||||
resolution: {integrity: sha512-0ikrnug3/IyneSHqCBeslAhlK2aBfYek1fGo4bP4QnZPmiqSGRK+Oy7ZMisLWkesffJvQ1cqAcBnJC+8+nxIAg==}
|
||||
|
||||
'@types/node-fetch@2.6.13':
|
||||
resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==}
|
||||
|
||||
@@ -6635,6 +6622,10 @@ packages:
|
||||
resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==}
|
||||
engines: {node: '>= 14'}
|
||||
|
||||
croner@10.0.1:
|
||||
resolution: {integrity: sha512-ixNtAJndqh173VQ4KodSdJEI6nuioBWI0V1ITNKhZZsO0pEMoDxz539T4FTTbSZ/xIOSuDnzxLVRqBVSvPNE2g==}
|
||||
engines: {node: '>=18.0'}
|
||||
|
||||
cross-env@10.1.0:
|
||||
resolution: {integrity: sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==}
|
||||
engines: {node: '>=20'}
|
||||
@@ -6886,9 +6877,6 @@ packages:
|
||||
dom-walk@0.1.2:
|
||||
resolution: {integrity: sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==}
|
||||
|
||||
dompurify@3.3.3:
|
||||
resolution: {integrity: sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA==}
|
||||
|
||||
dompurify@3.4.1:
|
||||
resolution: {integrity: sha512-JahakDAIg1gyOm7dlgWSDjV4n7Ip2PKR55NIT6jrMfIgLFgWo81vdr1/QGqWtFNRqXP9UV71oVePtjqS2ebnPw==}
|
||||
|
||||
@@ -7403,10 +7391,6 @@ packages:
|
||||
fast-xml-builder@1.1.5:
|
||||
resolution: {integrity: sha512-4TJn/8FKLeslLAH3dnohXqE3QSoxkhvaMzepOIZytwJXZO69Bfz0HBdDHzOTOon6G59Zrk6VQ2bEiv1t61rfkA==}
|
||||
|
||||
fast-xml-parser@5.7.1:
|
||||
resolution: {integrity: sha512-8Cc3f8GUGUULg34pBch/KGyPLglS+OFs05deyOlY7fL2MTagYPKrVQNmR1fLF/yJ9PH5ZSTd3YDF6pnmeZU+zA==}
|
||||
hasBin: true
|
||||
|
||||
fast-xml-parser@5.7.2:
|
||||
resolution: {integrity: sha512-P7oW7tLbYnhOLQk/Gv7cZgzgMPP/XN03K02/Jy6Y/NHzyIAIpxuZIM/YqAkfiXFPxA2CTm7NtCijK9EDu09u2w==}
|
||||
hasBin: true
|
||||
@@ -7503,15 +7487,6 @@ packages:
|
||||
fn.name@1.1.0:
|
||||
resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==}
|
||||
|
||||
follow-redirects@1.15.9:
|
||||
resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
|
||||
engines: {node: '>=4.0'}
|
||||
peerDependencies:
|
||||
debug: '*'
|
||||
peerDependenciesMeta:
|
||||
debug:
|
||||
optional: true
|
||||
|
||||
follow-redirects@1.16.0:
|
||||
resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==}
|
||||
engines: {node: '>=4.0'}
|
||||
@@ -8793,10 +8768,6 @@ packages:
|
||||
resolution: {integrity: sha512-lytcDEdxKjGJPTLEfW4mYMigRezMlyJY8W4wxJK8zE533Jlb8L8dRuObJFWg2P+AuOIxoCgKF+2Oq4d4Zd0OUA==}
|
||||
engines: {node: ^18 || ^20 || >= 21}
|
||||
|
||||
node-cron@4.2.1:
|
||||
resolution: {integrity: sha512-lgimEHPE/QDgFlywTd8yTR61ptugX3Qer29efeyWw2rv259HtGBNn1vZVmp8lB9uo9wC0t/AT4iGqXxia+CJFg==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
|
||||
node-domexception@1.0.0:
|
||||
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
|
||||
engines: {node: '>=10.5.0'}
|
||||
@@ -11867,7 +11838,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@ndaidong/bellajs': 12.0.1
|
||||
cross-fetch: 4.1.0
|
||||
fast-xml-parser: 5.7.1
|
||||
fast-xml-parser: 5.7.2
|
||||
html-entities: 2.6.0
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
@@ -14021,8 +13992,6 @@ snapshots:
|
||||
|
||||
'@types/ms@2.1.0': {}
|
||||
|
||||
'@types/node-cron@3.0.11': {}
|
||||
|
||||
'@types/node-fetch@2.6.13':
|
||||
dependencies:
|
||||
'@types/node': 24.12.2
|
||||
@@ -14675,7 +14644,7 @@ snapshots:
|
||||
|
||||
axios@1.9.0:
|
||||
dependencies:
|
||||
follow-redirects: 1.15.9
|
||||
follow-redirects: 1.16.0
|
||||
form-data: 4.0.5
|
||||
proxy-from-env: 1.1.0
|
||||
transitivePeerDependencies:
|
||||
@@ -15103,6 +15072,8 @@ snapshots:
|
||||
crc-32: 1.2.2
|
||||
readable-stream: 4.5.2
|
||||
|
||||
croner@10.0.1: {}
|
||||
|
||||
cross-env@10.1.0:
|
||||
dependencies:
|
||||
'@epic-web/invariant': 1.0.0
|
||||
@@ -15340,10 +15311,6 @@ snapshots:
|
||||
|
||||
dom-walk@0.1.2: {}
|
||||
|
||||
dompurify@3.3.3:
|
||||
optionalDependencies:
|
||||
'@types/trusted-types': 2.0.7
|
||||
|
||||
dompurify@3.4.1:
|
||||
optionalDependencies:
|
||||
'@types/trusted-types': 2.0.7
|
||||
@@ -15991,13 +15958,6 @@ snapshots:
|
||||
dependencies:
|
||||
path-expression-matcher: 1.5.0
|
||||
|
||||
fast-xml-parser@5.7.1:
|
||||
dependencies:
|
||||
'@nodable/entities': 2.1.0
|
||||
fast-xml-builder: 1.1.5
|
||||
path-expression-matcher: 1.5.0
|
||||
strnum: 2.2.3
|
||||
|
||||
fast-xml-parser@5.7.2:
|
||||
dependencies:
|
||||
'@nodable/entities': 2.1.0
|
||||
@@ -16102,8 +16062,6 @@ snapshots:
|
||||
|
||||
fn.name@1.1.0: {}
|
||||
|
||||
follow-redirects@1.15.9: {}
|
||||
|
||||
follow-redirects@1.16.0: {}
|
||||
|
||||
for-each@0.3.5:
|
||||
@@ -17512,8 +17470,6 @@ snapshots:
|
||||
|
||||
node-addon-api@8.3.1: {}
|
||||
|
||||
node-cron@4.2.1: {}
|
||||
|
||||
node-domexception@1.0.0: {}
|
||||
|
||||
node-emoji@2.2.0:
|
||||
@@ -19220,7 +19176,7 @@ snapshots:
|
||||
classnames: 2.5.1
|
||||
css.escape: 1.5.1
|
||||
deep-extend: 0.6.0
|
||||
dompurify: 3.3.3
|
||||
dompurify: 3.4.1
|
||||
ieee754: 1.2.1
|
||||
immutable: 3.8.2
|
||||
js-file-download: 0.4.12
|
||||
|
||||
+1
-2
@@ -86,7 +86,6 @@ catalog:
|
||||
"@types/css-modules": ^1.0.5
|
||||
"@types/dockerode": ^4.0.1
|
||||
"@types/node": ^24.12.2
|
||||
"@types/node-cron": ^3.0.11
|
||||
"@types/node-unifi": ^2.5.1
|
||||
"@types/pg": ^8.20.0
|
||||
"@types/prismjs": ^1.26.6
|
||||
@@ -113,6 +112,7 @@ catalog:
|
||||
conventional-changelog-conventionalcommits: ^9.3.1
|
||||
cookie: 1.1.1
|
||||
cookies: ^0.9.1
|
||||
croner: 10.0.1
|
||||
cross-env: ^10.1.0
|
||||
crypto-js: ^4.2.0
|
||||
dayjs: ^1.11.20
|
||||
@@ -151,7 +151,6 @@ catalog:
|
||||
next: 16.2.4
|
||||
next-auth: 5.0.0-beta.31
|
||||
next-intl: 4.9.1
|
||||
node-cron: ^4.2.1
|
||||
node-loader: ^2.1.0
|
||||
octokit: ^5.0.5
|
||||
pg: ^8.20.0
|
||||
|
||||
Reference in new issue
Block a user