mirror of
https://github.com/PreMiD/PreMiD.git
synced 2026-04-06 04:41:58 +02:00
Compare commits
11 Commits
api-worker
...
api-master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
255f840275 | ||
|
|
12089fe773 | ||
|
|
4b43e03ff0 | ||
|
|
d16ec114b0 | ||
|
|
8ea8904752 | ||
|
|
7fabdb8fe4 | ||
|
|
2554b20b34 | ||
|
|
9e72d2cc7f | ||
|
|
4af1ff22f1 | ||
|
|
f339035463 | ||
|
|
b67226dcdd |
11
apps/api-master/environment.d.ts
vendored
11
apps/api-master/environment.d.ts
vendored
@@ -1,14 +1,3 @@
|
||||
declare module "ip-location-api" {
|
||||
export function lookup(ip: string): Promise<{
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
country: string;
|
||||
} | null>;
|
||||
|
||||
export function updateDb(options: { fields?: string[]; dataDir?: string; tmpDataDir?: string; smallMemory?: boolean; autoUpdate?: string }): Promise<void>;
|
||||
export function reload(options: { fields?: string[]; dataDir?: string; tmpDataDir?: string; smallMemory?: boolean; autoUpdate?: string }): Promise<void>;
|
||||
}
|
||||
|
||||
declare namespace NodeJS {
|
||||
export interface ProcessEnv {
|
||||
METRICS_DATABASE_URL?: string;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@premid/api-master",
|
||||
"type": "module",
|
||||
"version": "0.0.37",
|
||||
"version": "0.0.39",
|
||||
"private": true,
|
||||
"description": "PreMiD's api master",
|
||||
"license": "MPL-2.0",
|
||||
@@ -24,7 +24,6 @@
|
||||
"debug": "^4.3.6",
|
||||
"drizzle-orm": "^0.33.0",
|
||||
"ioredis": "^5.3.2",
|
||||
"ip-location-api": "^2.0.1",
|
||||
"ky": "^1.7.2",
|
||||
"p-limit": "^6.1.0",
|
||||
"postgres": "^3.4.4",
|
||||
|
||||
@@ -1,46 +1,3 @@
|
||||
import { join } from "node:path";
|
||||
import process from "node:process";
|
||||
import { lookup, reload } from "ip-location-api";
|
||||
import { mainLog } from "../index.js";
|
||||
|
||||
const fields = ["latitude", "longitude", "country"];
|
||||
|
||||
const dataDir = join(process.cwd(), "data");
|
||||
const tmpDataDir = join(process.cwd(), "tmp");
|
||||
const smallMemory = true;
|
||||
|
||||
let initialized = false;
|
||||
|
||||
export async function lookupIp(ip: string): Promise<{ latitude: number; longitude: number; country: string } | undefined> {
|
||||
if (!initialized) {
|
||||
reloadIpLocationApi();
|
||||
return undefined;
|
||||
}
|
||||
try {
|
||||
return await lookup(ip) ?? undefined;
|
||||
}
|
||||
catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
let reloading: Promise<void> | undefined;
|
||||
let log: debug.Debugger | undefined;
|
||||
|
||||
export async function reloadIpLocationApi() {
|
||||
log ??= mainLog.extend("IP-Location-API");
|
||||
|
||||
if (reloading)
|
||||
return reloading;
|
||||
|
||||
reloading = new Promise((resolve, reject) => {
|
||||
log?.("Reloading IP location API");
|
||||
reload({ fields, dataDir, tmpDataDir, smallMemory, autoUpdate: "0 9 * * *" }).then(() => {
|
||||
log?.("IP location API reloaded");
|
||||
initialized = true;
|
||||
reloading = undefined;
|
||||
resolve();
|
||||
}).catch(reject);
|
||||
});
|
||||
return reloading;
|
||||
export async function lookupIp(_ip: string): Promise<{ latitude: number; longitude: number; country: string } | undefined> {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
54
apps/api-master/src/functions/updateVersionGauge.ts
Normal file
54
apps/api-master/src/functions/updateVersionGauge.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import process from "node:process";
|
||||
import pLimit from "p-limit";
|
||||
import type { Gauge } from "prom-client";
|
||||
import { mainLog, redis } from "../index.js";
|
||||
|
||||
export const updateExtensionVersionGaugeLimit = pLimit(1);
|
||||
let log: debug.Debugger | undefined;
|
||||
|
||||
const scanCount = Number.parseInt(process.env.SCAN_COUNT || "1000", 10);
|
||||
|
||||
export async function updateExtensionVersionGauge(gauge: Gauge) {
|
||||
await updateExtensionVersionGaugeLimit(async () => {
|
||||
log ??= mainLog.extend("Extension-Version-Updates");
|
||||
log?.("Starting extension version gauge update");
|
||||
|
||||
const pattern = "pmd-api.heartbeatUpdates.*";
|
||||
let cursor: string = "0";
|
||||
const versionCounts = new Map<string, number>();
|
||||
|
||||
do {
|
||||
const [newCursor, keys] = await redis.scan(cursor, "MATCH", pattern, "COUNT", scanCount);
|
||||
cursor = newCursor;
|
||||
|
||||
//* Use pipelining for batch Redis operations
|
||||
const pipeline = redis.pipeline();
|
||||
keys.forEach(key => pipeline.hmget(key, "extension_version"));
|
||||
const hashes = await pipeline.exec();
|
||||
|
||||
if (!hashes) {
|
||||
log?.("No hashes found");
|
||||
return;
|
||||
}
|
||||
|
||||
hashes.forEach(([err, hash]) => {
|
||||
if (err || !Array.isArray(hash))
|
||||
return;
|
||||
|
||||
const [version] = hash;
|
||||
if (version && typeof version === "string")
|
||||
versionCounts.set(version, (versionCounts.get(version) || 0) + 1);
|
||||
});
|
||||
} while (cursor !== "0");
|
||||
|
||||
log?.("Updating extension version gauge");
|
||||
|
||||
//* Batch update the gauge
|
||||
gauge.reset();
|
||||
for (const [version, count] of versionCounts) {
|
||||
gauge.set({ version }, count);
|
||||
}
|
||||
|
||||
log?.("Extension version gauge update completed");
|
||||
});
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import debug from "debug";
|
||||
import { clearOldSessions } from "./functions/clearOldSessions.js";
|
||||
import createRedis from "./functions/createRedis.js";
|
||||
import "./tracing.js";
|
||||
import { reloadIpLocationApi } from "./functions/lookupIp.js";
|
||||
import { cleanupOldUserData } from "./functions/cleanupOldUserData.js";
|
||||
import { setupServer } from "./functions/setupServer.js";
|
||||
|
||||
@@ -16,8 +15,6 @@ export const mainLog = debug("api-master");
|
||||
|
||||
debug("Starting cron jobs");
|
||||
|
||||
void reloadIpLocationApi();
|
||||
|
||||
void new CronJob(
|
||||
// Every 5 seconds
|
||||
"*/5 * * * * *",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import process from "node:process";
|
||||
import { Counter, Gauge, Registry, collectDefaultMetrics } from "prom-client";
|
||||
import { updateActivePresenceGauge, updateActivePresenceGaugeLimit } from "./functions/updateActivePresenceGauge.js";
|
||||
import { updateExtensionVersionGauge, updateExtensionVersionGaugeLimit } from "./functions/updateVersionGauge.js";
|
||||
import { redis } from "./index.js";
|
||||
|
||||
const scanCount = Number.parseInt(process.env.SCAN_COUNT || "1000", 10);
|
||||
@@ -37,5 +38,17 @@ export const activePresencesCounter = new Gauge({
|
||||
},
|
||||
});
|
||||
|
||||
const versionCounter = new Gauge({
|
||||
name: "extension_version",
|
||||
help: "The version of the extension with the amount of users using it",
|
||||
labelNames: ["version"],
|
||||
async collect() {
|
||||
this.reset();
|
||||
updateExtensionVersionGaugeLimit.clearQueue();
|
||||
await updateExtensionVersionGauge(this);
|
||||
},
|
||||
});
|
||||
|
||||
register.registerMetric(activeSessionsCounter);
|
||||
register.registerMetric(activePresencesCounter);
|
||||
register.registerMetric(versionCounter);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@premid/api-worker",
|
||||
"type": "module",
|
||||
"version": "0.0.17",
|
||||
"version": "0.0.18",
|
||||
"private": true,
|
||||
"description": "PreMiD's api",
|
||||
"license": "MPL-2.0",
|
||||
|
||||
@@ -13,6 +13,7 @@ import { Socket } from "../classes/Socket.js";
|
||||
import { resolvers } from "../graphql/resolvers/v5/index.js";
|
||||
import { sessionKeepAlive } from "../routes/sessionKeepAlive.js";
|
||||
import { featureFlags } from "../constants.js";
|
||||
import { presences } from "../routes/presences.js";
|
||||
import createRedis from "./createRedis.js";
|
||||
|
||||
export interface FastifyContext {
|
||||
@@ -89,6 +90,7 @@ export default async function createServer() {
|
||||
});
|
||||
|
||||
app.post("/v5/session-keep-alive", sessionKeepAlive);
|
||||
app.get("/v5/presence/:service/:file", presences);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
34
apps/api-worker/src/routes/presences.ts
Normal file
34
apps/api-worker/src/routes/presences.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { Presence } from "@premid/db";
|
||||
import { type } from "arktype";
|
||||
import type { FastifyReply, FastifyRequest } from "fastify";
|
||||
|
||||
const schema = type({
|
||||
service: "string.trim",
|
||||
file: "'metadata.json'|'presence.js'|'iframe.js'",
|
||||
});
|
||||
|
||||
export async function presences(request: FastifyRequest, reply: FastifyReply) {
|
||||
const out = schema(request.params);
|
||||
|
||||
if (out instanceof type.errors)
|
||||
return reply.status(400).send({ code: "INVALID_PARAMS", message: out.message });
|
||||
|
||||
const service = decodeURIComponent(out.service);
|
||||
const { file } = out;
|
||||
|
||||
const presence = await Presence.findOne({ "metadata.service": service });
|
||||
|
||||
if (!presence)
|
||||
return reply.status(404).send({ code: "PRESENCE_NOT_FOUND", message: "The presence was not found" });
|
||||
|
||||
switch (file) {
|
||||
case "metadata.json":
|
||||
return reply.status(200).type("application/json").send(presence.metadata);
|
||||
case "presence.js":
|
||||
return reply.status(200).type("application/javascript").send(presence.presenceJs);
|
||||
case "iframe.js":
|
||||
if (!presence.iframeJs)
|
||||
return reply.status(404).send({ code: "IFRAME_NOT_FOUND", message: "The presence does not have an iframe" });
|
||||
return reply.status(200).type("application/javascript").send(presence.iframeJs);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@premid/discord-bot",
|
||||
"type": "module",
|
||||
"version": "1.0.5",
|
||||
"version": "1.0.6",
|
||||
"private": true,
|
||||
"description": "PreMiD's discord bot",
|
||||
"license": "MPL-2.0",
|
||||
|
||||
@@ -15,7 +15,7 @@ client.on(Events.GuildMemberAdd, async (member) => {
|
||||
created: member.user.createdTimestamp,
|
||||
discriminator: member.user.discriminator,
|
||||
userId: member.id,
|
||||
username: member.user.username,
|
||||
username: member.user.displayName ?? member.user.username,
|
||||
},
|
||||
},
|
||||
{ upsert: true },
|
||||
|
||||
@@ -17,7 +17,7 @@ client.on(Events.GuildMemberUpdate, async (oldMember, newMember) => {
|
||||
created: newMember.user.createdTimestamp,
|
||||
discriminator: newMember.user.discriminator,
|
||||
userId: newMember.id,
|
||||
username: newMember.user.username,
|
||||
username: newMember.user.displayName ?? newMember.user.username,
|
||||
},
|
||||
},
|
||||
{ upsert: true },
|
||||
@@ -28,7 +28,7 @@ client.on(Events.GuildMemberUpdate, async (oldMember, newMember) => {
|
||||
{
|
||||
$set: {
|
||||
userId: newMember.id,
|
||||
name: newMember.user.username,
|
||||
name: newMember.user.displayName ?? newMember.user.username,
|
||||
tag: newMember.user.discriminator,
|
||||
avatar: newMember.user.displayAvatarURL({
|
||||
extension: "png",
|
||||
|
||||
@@ -108,7 +108,7 @@ client.once(Events.ClientReady, async () => {
|
||||
update: {
|
||||
$set: {
|
||||
userId: member.id,
|
||||
name: member.user.username,
|
||||
name: member.user.displayName ?? member.user.username,
|
||||
tag: member.user.discriminator,
|
||||
avatar: member.user.displayAvatarURL({
|
||||
extension: "png",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@premid/schema-server",
|
||||
"type": "module",
|
||||
"version": "1.0.4",
|
||||
"version": "1.0.5",
|
||||
"private": true,
|
||||
"description": "A small service to serve the JSON schemas for PreMiD",
|
||||
"license": "MPL-2.0",
|
||||
|
||||
252
apps/schema-server/schemas/metadata/1.12.json
Normal file
252
apps/schema-server/schemas/metadata/1.12.json
Normal file
@@ -0,0 +1,252 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"$id": "https://schemas.premid.app/metadata/1.12",
|
||||
"title": "Metadata",
|
||||
"type": "object",
|
||||
"description": "Metadata that describes a presence.",
|
||||
"definitions": {
|
||||
"user": {
|
||||
"type": "object",
|
||||
"description": "User information.",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The name of the user."
|
||||
},
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "The Discord snowflake of the user.",
|
||||
"pattern": "^\\d+$"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"name",
|
||||
"id"
|
||||
]
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"$schema": {
|
||||
"$comment": "This is required otherwise the schema will fail itself when it is applied to a document via $schema. This is optional so that validators that use this schema don't fail if the metadata doesn't have the $schema property.",
|
||||
"type": "string",
|
||||
"description": "The metadata schema URL."
|
||||
},
|
||||
"author": {
|
||||
"$ref": "#/definitions/user",
|
||||
"description": "The author of this presence."
|
||||
},
|
||||
"contributors": {
|
||||
"type": "array",
|
||||
"description": "Any extra contributors to this presence.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/user"
|
||||
}
|
||||
},
|
||||
"service": {
|
||||
"type": "string",
|
||||
"description": "The service this presence is for."
|
||||
},
|
||||
"altnames": {
|
||||
"type": "array",
|
||||
"description": "Alternative names for the service.",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "An alternative name."
|
||||
},
|
||||
"minItems": 1
|
||||
},
|
||||
"description": {
|
||||
"type": "object",
|
||||
"description": "A description of the presence in multiple languages.",
|
||||
"propertyNames": {
|
||||
"type": "string",
|
||||
"description": "The language key. The key must be languagecode(_REGIONCODE).",
|
||||
"pattern": "^[a-z]{2}(?:_(?:[A-Z]{2}|[0-9]{1,3}))?$"
|
||||
},
|
||||
"patternProperties": {
|
||||
"^[a-z]{2}(?:_(?:[A-Z]{2}|[0-9]{1,3}))?$": {
|
||||
"type": "string",
|
||||
"description": "The description of the presence in the key's language."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"en"
|
||||
]
|
||||
},
|
||||
"url": {
|
||||
"type": [
|
||||
"string",
|
||||
"array"
|
||||
],
|
||||
"description": "The service's website URL, or an array of URLs. Protocols should not be added.",
|
||||
"pattern": "^(([a-z0-9-]+\\.)*[0-9a-z_-]+(\\.[a-z]+)+|(\\d{1,3}\\.){3}\\d{1,3}|localhost)$",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "One of the service's website URLs.",
|
||||
"pattern": "^(([a-z0-9-]+\\.)*[0-9a-z_-]+(\\.[a-z]+)+|(\\d{1,3}\\.){3}\\d{1,3}|localhost)$"
|
||||
},
|
||||
"minItems": 2
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "The SemVer version of the presence. Must just be major.minor.patch.",
|
||||
"pattern": "^\\d+\\.\\d+\\.\\d+$"
|
||||
},
|
||||
"apiVersion": {
|
||||
"type": "integer",
|
||||
"description": "The Presence System version this Presence supports.",
|
||||
"minimum": 1,
|
||||
"maximum": 2
|
||||
},
|
||||
"logo": {
|
||||
"type": "string",
|
||||
"description": "The logo of the service this presence is for.",
|
||||
"pattern": "^https?://.+\\.(png|jpe?g|gif|webp)$"
|
||||
},
|
||||
"thumbnail": {
|
||||
"type": "string",
|
||||
"description": "A thumbnail of the service this presence is for.",
|
||||
"pattern": "^https?://.+\\.(png|jpe?g|gif|webp)$"
|
||||
},
|
||||
"color": {
|
||||
"type": "string",
|
||||
"description": "The theme color of the service this presence is for. Must be either a 6 digit or a 3 digit hex code.",
|
||||
"pattern": "^#([A-Fa-f0-9]{3}){1,2}$"
|
||||
},
|
||||
"tags": {
|
||||
"type": [
|
||||
"array"
|
||||
],
|
||||
"description": "The tags for the presence.",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A tag.",
|
||||
"pattern": "^[^A-Z\\s!\"#$%&'()*+,./:;<=>?@\\[\\\\\\]^_`{|}~]+$"
|
||||
},
|
||||
"minItems": 1
|
||||
},
|
||||
"category": {
|
||||
"type": "string",
|
||||
"description": "The category the presence falls under.",
|
||||
"enum": [
|
||||
"anime",
|
||||
"games",
|
||||
"music",
|
||||
"socials",
|
||||
"videos",
|
||||
"other"
|
||||
]
|
||||
},
|
||||
"iframe": {
|
||||
"type": "boolean",
|
||||
"description": "Whether or not the presence should run in IFrames."
|
||||
},
|
||||
"readLogs": {
|
||||
"type": "boolean",
|
||||
"description": "Whether or not the extension should be reading logs."
|
||||
},
|
||||
"regExp": {
|
||||
"type": "string",
|
||||
"description": "A regular expression used to match URLs for the presence to inject into."
|
||||
},
|
||||
"iFrameRegExp": {
|
||||
"type": "string",
|
||||
"description": "A regular expression used to match IFrames for the presence to inject into."
|
||||
},
|
||||
"button": {
|
||||
"type": "boolean",
|
||||
"description": "Controls whether the presence is automatically added when the extension is installed. For partner presences only."
|
||||
},
|
||||
"warning": {
|
||||
"type": "boolean",
|
||||
"description": "Shows a warning saying that it requires additional steps for the presence to function correctly."
|
||||
},
|
||||
"settings": {
|
||||
"type": "array",
|
||||
"description": "An array of settings the user can change in the presence.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "A setting.",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "The ID of the setting."
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"description": "The title of the setting. Required only if `multiLanguage` is disabled."
|
||||
},
|
||||
"icon": {
|
||||
"type": "string",
|
||||
"description": "The icon of the setting. Required only if `multiLanguage` is disabled.",
|
||||
"pattern": "^fa([bsdrlt]|([-](brands|solid|duotone|regular|light|thin))) fa-[0-9a-z-]+$"
|
||||
},
|
||||
"if": {
|
||||
"type": "object",
|
||||
"description": "Restrict showing this setting if another setting is the defined value.",
|
||||
"propertyNames": {
|
||||
"type": "string",
|
||||
"description": "The ID of the setting."
|
||||
},
|
||||
"patternProperties": {
|
||||
"": {
|
||||
"type": [
|
||||
"string",
|
||||
"number",
|
||||
"boolean"
|
||||
],
|
||||
"description": "The value of the setting."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"placeholder": {
|
||||
"type": "string",
|
||||
"description": "The placeholder for settings that require input. Shown when the input is empty."
|
||||
},
|
||||
"value": {
|
||||
"type": [
|
||||
"string",
|
||||
"number",
|
||||
"boolean"
|
||||
],
|
||||
"description": "The default value of the setting. Not compatible with `values`."
|
||||
},
|
||||
"values": {
|
||||
"type": "array",
|
||||
"description": "The default values of the setting. Not compatible with `value`.",
|
||||
"items": {
|
||||
"type": [
|
||||
"string",
|
||||
"number",
|
||||
"boolean"
|
||||
],
|
||||
"description": "The value of the setting."
|
||||
}
|
||||
},
|
||||
"multiLanguage": {
|
||||
"type": "boolean",
|
||||
"description": "When true, strings from the `general.json` file are available for use, plus the <service>.json file. False is not allowed."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"author",
|
||||
"service",
|
||||
"description",
|
||||
"url",
|
||||
"version",
|
||||
"apiVersion",
|
||||
"logo",
|
||||
"thumbnail",
|
||||
"color",
|
||||
"tags",
|
||||
"category"
|
||||
]
|
||||
}
|
||||
@@ -62,15 +62,15 @@ const PresenceMetadataSettingSchema = new Schema<PresenceMetadataSetting>({
|
||||
placeholder: { type: String },
|
||||
title: { type: String },
|
||||
value: Schema.Types.Mixed,
|
||||
values: { type: [String] },
|
||||
values: { type: [Schema.Types.Mixed], default: undefined },
|
||||
});
|
||||
const PresenceMetadataSchema = new Schema<PresenceMetadata>({
|
||||
$schema: { required: true, type: String },
|
||||
altnames: { type: [String] },
|
||||
altnames: { type: [String], default: undefined },
|
||||
author: { required: true, type: PresenceMetadataContributorSchema },
|
||||
category: { required: true, type: String },
|
||||
color: { required: true, type: String },
|
||||
contributors: { type: [PresenceMetadataContributorSchema] },
|
||||
contributors: { type: [PresenceMetadataContributorSchema], default: undefined },
|
||||
description: { required: true, type: Schema.Types.Mixed },
|
||||
iFrameRegExp: { type: String },
|
||||
iframe: { type: Boolean },
|
||||
@@ -78,10 +78,10 @@ const PresenceMetadataSchema = new Schema<PresenceMetadata>({
|
||||
readLogs: { type: Boolean },
|
||||
regExp: { type: String },
|
||||
service: { required: true, type: String },
|
||||
settings: { type: [PresenceMetadataSettingSchema] },
|
||||
settings: { type: [PresenceMetadataSettingSchema], default: undefined },
|
||||
tags: { required: true, type: [String] },
|
||||
thumbnail: { required: true, type: String },
|
||||
url: { required: true, type: [String] },
|
||||
url: { required: true, type: Schema.Types.Mixed },
|
||||
version: { required: true, type: String },
|
||||
apiVersion: { required: true, type: Number },
|
||||
});
|
||||
|
||||
154
pnpm-lock.yaml
generated
154
pnpm-lock.yaml
generated
@@ -71,9 +71,6 @@ importers:
|
||||
ioredis:
|
||||
specifier: ^5.3.2
|
||||
version: 5.4.1
|
||||
ip-location-api:
|
||||
specifier: ^2.0.1
|
||||
version: 2.0.1(debug@4.3.7)
|
||||
ky:
|
||||
specifier: ^1.7.2
|
||||
version: 1.7.2
|
||||
@@ -1888,12 +1885,6 @@ packages:
|
||||
resolution: {integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@fast-csv/format@5.0.0':
|
||||
resolution: {integrity: sha512-IyMpHwYIOGa2f0BJi6Wk55UF0oBA5urdIydoEDYxPo88LFbeb3Yr4rgpu98OAO1glUWheSnNtUgS80LE+/dqmw==}
|
||||
|
||||
'@fast-csv/parse@5.0.0':
|
||||
resolution: {integrity: sha512-ecF8tCm3jVxeRjEB6VPzmA+1wGaJ5JgaUX2uesOXdXD6qQp0B3EdshOIed4yT1Xlj/F2f8v4zHSo0Oi31L697g==}
|
||||
|
||||
'@fastify/accept-negotiator@1.1.0':
|
||||
resolution: {integrity: sha512-OIHZrb2ImZ7XG85HXOONLcJWGosv7sIvM2ifAPQVhg9Lv7qdmMBNVaai4QTdyuaqbKM5eO6sLSQOYI7wEQeCJQ==}
|
||||
engines: {node: '>=14'}
|
||||
@@ -3176,7 +3167,6 @@ packages:
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.21.2':
|
||||
resolution: {integrity: sha512-69CF19Kp3TdMopyteO/LJbWufOzqqXzkrv4L2sP8kfMaAQ6iwky7NoXTp7bD6/irKgknDKM0P9E/1l5XxVQAhw==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.18.1':
|
||||
@@ -4362,9 +4352,6 @@ packages:
|
||||
resolution: {integrity: sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==}
|
||||
engines: {node: '>=16.20.1'}
|
||||
|
||||
buffer-crc32@0.2.13:
|
||||
resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
|
||||
|
||||
buffer-crc32@1.0.0:
|
||||
resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==}
|
||||
engines: {node: '>=8.0.0'}
|
||||
@@ -4763,9 +4750,6 @@ packages:
|
||||
typescript:
|
||||
optional: true
|
||||
|
||||
countries-list@3.1.1:
|
||||
resolution: {integrity: sha512-nPklKJ5qtmY5MdBKw1NiBAoyx5Sa7p2yPpljZyQ7gyCN1m+eMFs9I6CT37Mxt8zvR5L3VzD3DJBE4WQzX3WF4A==}
|
||||
|
||||
crawler-user-agents@1.0.143:
|
||||
resolution: {integrity: sha512-tVnQF0rrrzmiwHL/ASloGdW4wQ5Cjfd1ujiUWfeDjqXR6vTxrN4bIWnDd1tgUhDWx3z0msiktWjI51r3Dnw0CA==}
|
||||
|
||||
@@ -4894,9 +4878,6 @@ packages:
|
||||
dataloader@2.2.2:
|
||||
resolution: {integrity: sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g==}
|
||||
|
||||
dayjs@1.11.13:
|
||||
resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
|
||||
|
||||
db0@0.1.4:
|
||||
resolution: {integrity: sha512-Ft6eCwONYxlwLjBXSJxw0t0RYtA5gW9mq8JfBXn9TtC0nDPlqePAhpv9v4g9aONBi6JI1OXHTKKkUYGd+BOrCA==}
|
||||
peerDependencies:
|
||||
@@ -5598,10 +5579,6 @@ packages:
|
||||
fast-content-type-parse@1.1.0:
|
||||
resolution: {integrity: sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==}
|
||||
|
||||
fast-csv@5.0.1:
|
||||
resolution: {integrity: sha512-Q43zC4NdQD5MAWOVQOF8KA+D6ddvTJjX2ib8zqysm74jZhtk6+dc8C75/OqRV6Y9CLc4kgvbC3PLG8YL4YZfgw==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
|
||||
fast-decode-uri-component@1.0.1:
|
||||
resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==}
|
||||
|
||||
@@ -6216,14 +6193,6 @@ packages:
|
||||
resolution: {integrity: sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==}
|
||||
engines: {node: '>=12.22.0'}
|
||||
|
||||
ip-address@9.0.5:
|
||||
resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==}
|
||||
engines: {node: '>= 12'}
|
||||
|
||||
ip-location-api@2.0.1:
|
||||
resolution: {integrity: sha512-g6INF2j3+Je89rj0ENaN9w1YzzKx11Hf4Q7aooCw9wcJ5GHFvwCgtlPJWqZ32wrCv3/sLvSbLEwOh/kauTFT9w==}
|
||||
engines: {node: '>=14.8.0'}
|
||||
|
||||
ipaddr.js@1.9.1:
|
||||
resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
|
||||
engines: {node: '>= 0.10'}
|
||||
@@ -6461,9 +6430,6 @@ packages:
|
||||
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
|
||||
hasBin: true
|
||||
|
||||
jsbn@1.1.0:
|
||||
resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==}
|
||||
|
||||
jsdoc-type-pratt-parser@4.1.0:
|
||||
resolution: {integrity: sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
@@ -6624,33 +6590,12 @@ packages:
|
||||
lodash.defaults@4.2.0:
|
||||
resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==}
|
||||
|
||||
lodash.escaperegexp@4.1.2:
|
||||
resolution: {integrity: sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==}
|
||||
|
||||
lodash.groupby@4.6.0:
|
||||
resolution: {integrity: sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==}
|
||||
|
||||
lodash.isarguments@3.1.0:
|
||||
resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==}
|
||||
|
||||
lodash.isboolean@3.0.3:
|
||||
resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==}
|
||||
|
||||
lodash.isequal@4.5.0:
|
||||
resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
|
||||
|
||||
lodash.isfunction@3.0.9:
|
||||
resolution: {integrity: sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==}
|
||||
|
||||
lodash.isnil@4.0.0:
|
||||
resolution: {integrity: sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng==}
|
||||
|
||||
lodash.isplainobject@4.0.6:
|
||||
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
|
||||
|
||||
lodash.isundefined@3.0.1:
|
||||
resolution: {integrity: sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==}
|
||||
|
||||
lodash.kebabcase@4.1.1:
|
||||
resolution: {integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==}
|
||||
|
||||
@@ -7455,9 +7400,6 @@ packages:
|
||||
resolution: {integrity: sha512-U94a+eXHzct7vAd19GH3UQ2dH4Satbng0MyYTMaQatL0pvYYL5CTPR25HBhKtecl+4bfu1/i3vC6k0hydO5Vcw==}
|
||||
engines: {node: '>=14.16'}
|
||||
|
||||
pend@1.2.0:
|
||||
resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
|
||||
|
||||
perfect-debounce@1.0.0:
|
||||
resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==}
|
||||
|
||||
@@ -8268,9 +8210,6 @@ packages:
|
||||
sponge-case@1.0.1:
|
||||
resolution: {integrity: sha512-dblb9Et4DAtiZ5YSUZHLl4XhH4uK80GhAZrVXdN4O2P4gQ40Wa5UIOPUHlA/nFd2PLblBZWUioLMMAVrgpoYcA==}
|
||||
|
||||
sprintf-js@1.1.3:
|
||||
resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==}
|
||||
|
||||
stable-hash@0.0.4:
|
||||
resolution: {integrity: sha512-LjdcbuBeLcdETCrPn9i8AYAZ1eCtu4ECAWtP7UleOiZ9LzVxRzzUZEoZ8zB24nhkQnDWyET0I+3sWokSDS3E7g==}
|
||||
|
||||
@@ -9389,10 +9328,6 @@ packages:
|
||||
resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
yauzl@3.1.3:
|
||||
resolution: {integrity: sha512-JCCdmlJJWv7L0q/KylOekyRaUrdEoUxWkWVcgorosTROCFWiS9p2NNPE9Yb91ak7b1N5SxAZEliWpspbZccivw==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
yocto-queue@0.1.0:
|
||||
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -10869,23 +10804,6 @@ snapshots:
|
||||
|
||||
'@eslint/object-schema@2.1.4': {}
|
||||
|
||||
'@fast-csv/format@5.0.0':
|
||||
dependencies:
|
||||
lodash.escaperegexp: 4.1.2
|
||||
lodash.isboolean: 3.0.3
|
||||
lodash.isequal: 4.5.0
|
||||
lodash.isfunction: 3.0.9
|
||||
lodash.isnil: 4.0.0
|
||||
|
||||
'@fast-csv/parse@5.0.0':
|
||||
dependencies:
|
||||
lodash.escaperegexp: 4.1.2
|
||||
lodash.groupby: 4.6.0
|
||||
lodash.isfunction: 3.0.9
|
||||
lodash.isnil: 4.0.0
|
||||
lodash.isundefined: 3.0.1
|
||||
lodash.uniq: 4.5.0
|
||||
|
||||
'@fastify/accept-negotiator@1.1.0':
|
||||
optional: true
|
||||
|
||||
@@ -14226,7 +14144,7 @@ snapshots:
|
||||
pathe: 1.1.2
|
||||
sirv: 2.0.4
|
||||
tinyrainbow: 1.2.0
|
||||
vitest: 2.0.5(@types/node@20.16.5)(@vitest/ui@2.0.5)(happy-dom@15.7.4)(sass@1.78.0)(terser@5.33.0)
|
||||
vitest: 2.0.5(@types/node@22.6.1)(@vitest/ui@2.0.5)(happy-dom@15.0.0)(sass@1.78.0)(terser@5.33.0)
|
||||
|
||||
'@vitest/utils@2.0.5':
|
||||
dependencies:
|
||||
@@ -14469,7 +14387,7 @@ snapshots:
|
||||
'@vueuse/shared': 10.11.1(vue@3.5.4(typescript@5.6.2))
|
||||
vue-demi: 0.14.10(vue@3.5.4(typescript@5.6.2))
|
||||
optionalDependencies:
|
||||
axios: 1.7.7(debug@4.3.7)
|
||||
axios: 1.7.7
|
||||
change-case: 4.1.2
|
||||
focus-trap: 7.5.4
|
||||
transitivePeerDependencies:
|
||||
@@ -14482,7 +14400,7 @@ snapshots:
|
||||
'@vueuse/shared': 11.0.3(vue@3.5.4(typescript@5.5.4))
|
||||
vue-demi: 0.14.10(vue@3.5.4(typescript@5.5.4))
|
||||
optionalDependencies:
|
||||
axios: 1.7.7(debug@4.3.7)
|
||||
axios: 1.7.7
|
||||
focus-trap: 7.5.4
|
||||
fuse.js: 7.0.0
|
||||
transitivePeerDependencies:
|
||||
@@ -14843,13 +14761,14 @@ snapshots:
|
||||
'@fastify/error': 3.4.1
|
||||
fastq: 1.17.1
|
||||
|
||||
axios@1.7.7(debug@4.3.7):
|
||||
axios@1.7.7:
|
||||
dependencies:
|
||||
follow-redirects: 1.15.9(debug@4.3.7)
|
||||
follow-redirects: 1.15.9
|
||||
form-data: 4.0.0
|
||||
proxy-from-env: 1.1.0
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
optional: true
|
||||
|
||||
b4a@1.6.6: {}
|
||||
|
||||
@@ -14980,8 +14899,6 @@ snapshots:
|
||||
|
||||
bson@6.8.0: {}
|
||||
|
||||
buffer-crc32@0.2.13: {}
|
||||
|
||||
buffer-crc32@1.0.0: {}
|
||||
|
||||
buffer-from@1.1.2: {}
|
||||
@@ -15466,8 +15383,6 @@ snapshots:
|
||||
optionalDependencies:
|
||||
typescript: 5.6.2
|
||||
|
||||
countries-list@3.1.1: {}
|
||||
|
||||
crawler-user-agents@1.0.143: {}
|
||||
|
||||
crc-32@1.2.2: {}
|
||||
@@ -15606,8 +15521,6 @@ snapshots:
|
||||
|
||||
dataloader@2.2.2: {}
|
||||
|
||||
dayjs@1.11.13: {}
|
||||
|
||||
db0@0.1.4: {}
|
||||
|
||||
de-indent@1.0.2: {}
|
||||
@@ -16511,11 +16424,6 @@ snapshots:
|
||||
|
||||
fast-content-type-parse@1.1.0: {}
|
||||
|
||||
fast-csv@5.0.1:
|
||||
dependencies:
|
||||
'@fast-csv/format': 5.0.0
|
||||
'@fast-csv/parse': 5.0.0
|
||||
|
||||
fast-decode-uri-component@1.0.1: {}
|
||||
|
||||
fast-deep-equal@3.1.3: {}
|
||||
@@ -16690,9 +16598,8 @@ snapshots:
|
||||
dependencies:
|
||||
tabbable: 6.2.0
|
||||
|
||||
follow-redirects@1.15.9(debug@4.3.7):
|
||||
optionalDependencies:
|
||||
debug: 4.3.7
|
||||
follow-redirects@1.15.9:
|
||||
optional: true
|
||||
|
||||
fontaine@0.5.0(webpack-sources@3.2.3):
|
||||
dependencies:
|
||||
@@ -17287,23 +17194,6 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
ip-address@9.0.5:
|
||||
dependencies:
|
||||
jsbn: 1.1.0
|
||||
sprintf-js: 1.1.3
|
||||
|
||||
ip-location-api@2.0.1(debug@4.3.7):
|
||||
dependencies:
|
||||
axios: 1.7.7(debug@4.3.7)
|
||||
countries-list: 3.1.1
|
||||
cron: 3.1.7
|
||||
dayjs: 1.11.13
|
||||
fast-csv: 5.0.1
|
||||
ip-address: 9.0.5
|
||||
yauzl: 3.1.3
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
|
||||
ipaddr.js@1.9.1: {}
|
||||
|
||||
ipaddr.js@2.2.0: {}
|
||||
@@ -17529,8 +17419,6 @@ snapshots:
|
||||
dependencies:
|
||||
argparse: 2.0.1
|
||||
|
||||
jsbn@1.1.0: {}
|
||||
|
||||
jsdoc-type-pratt-parser@4.1.0: {}
|
||||
|
||||
jsesc@0.5.0: {}
|
||||
@@ -17692,24 +17580,10 @@ snapshots:
|
||||
|
||||
lodash.defaults@4.2.0: {}
|
||||
|
||||
lodash.escaperegexp@4.1.2: {}
|
||||
|
||||
lodash.groupby@4.6.0: {}
|
||||
|
||||
lodash.isarguments@3.1.0: {}
|
||||
|
||||
lodash.isboolean@3.0.3: {}
|
||||
|
||||
lodash.isequal@4.5.0: {}
|
||||
|
||||
lodash.isfunction@3.0.9: {}
|
||||
|
||||
lodash.isnil@4.0.0: {}
|
||||
|
||||
lodash.isplainobject@4.0.6: {}
|
||||
|
||||
lodash.isundefined@3.0.1: {}
|
||||
|
||||
lodash.kebabcase@4.1.1: {}
|
||||
|
||||
lodash.memoize@4.1.2: {}
|
||||
@@ -18943,8 +18817,6 @@ snapshots:
|
||||
|
||||
peek-readable@5.2.0: {}
|
||||
|
||||
pend@1.2.0: {}
|
||||
|
||||
perfect-debounce@1.0.0: {}
|
||||
|
||||
pg-int8@1.0.1: {}
|
||||
@@ -19260,7 +19132,8 @@ snapshots:
|
||||
forwarded: 0.2.0
|
||||
ipaddr.js: 1.9.1
|
||||
|
||||
proxy-from-env@1.1.0: {}
|
||||
proxy-from-env@1.1.0:
|
||||
optional: true
|
||||
|
||||
pump@3.0.0:
|
||||
dependencies:
|
||||
@@ -19802,8 +19675,6 @@ snapshots:
|
||||
dependencies:
|
||||
tslib: 2.7.0
|
||||
|
||||
sprintf-js@1.1.3: {}
|
||||
|
||||
stable-hash@0.0.4: {}
|
||||
|
||||
stack-trace@0.0.10: {}
|
||||
@@ -21178,11 +21049,6 @@ snapshots:
|
||||
y18n: 5.0.8
|
||||
yargs-parser: 21.1.1
|
||||
|
||||
yauzl@3.1.3:
|
||||
dependencies:
|
||||
buffer-crc32: 0.2.13
|
||||
pend: 1.2.0
|
||||
|
||||
yocto-queue@0.1.0: {}
|
||||
|
||||
yocto-queue@1.1.1: {}
|
||||
|
||||
Reference in New Issue
Block a user