mirror of https://github.com/BRAVO68WEB/shx.git
feat: mig to full cf wrangler api workers
This commit is contained in:
parent
5c8c76aa5c
commit
61df1cbcd4
|
@ -8,6 +8,8 @@
|
|||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "dotnev -- turbo dev",
|
||||
"build": "dotenv -- turbo build",
|
||||
"start": "dotenv -- turbo start",
|
||||
"prettier": "prettier --write \"**/*.{ts,tsx,js,jsx,json,css,scss,md}\"",
|
||||
"prepare": "husky install",
|
||||
"configure-husky": "npx husky install && npx husky add .husky/pre-commit \"npx --no-install lint-staged\""
|
||||
|
|
|
@ -12,4 +12,7 @@ uploads/*.mp4
|
|||
uploads/*.mp3
|
||||
uploads/*.zip
|
||||
uploads/*.rar
|
||||
uploads/*.pdf
|
||||
uploads/*.pdf
|
||||
|
||||
# CF secrets
|
||||
secrets.json
|
|
@ -5,17 +5,21 @@ import {
|
|||
IConfigController,
|
||||
ConfigKeysTypes,
|
||||
} from '../interfaces/config.interface';
|
||||
import { Bindings, Variables } from "../types"
|
||||
|
||||
export default class ConfigController
|
||||
extends ConfigService
|
||||
implements IConfigController
|
||||
{
|
||||
public getAllConfig = async (
|
||||
ctx: Context
|
||||
ctx: Context<{
|
||||
Bindings: Bindings,
|
||||
Variables: Variables
|
||||
}>
|
||||
) => {
|
||||
let config;
|
||||
try {
|
||||
config = await this.getAllConfigS();
|
||||
config = await this.getAllConfigS(ctx);
|
||||
} catch (error) {
|
||||
return ctx.json({
|
||||
error,
|
||||
|
@ -31,7 +35,7 @@ export default class ConfigController
|
|||
const { key, value } = await ctx.req.json();
|
||||
if (!key || !value)
|
||||
throw new Error("Invalid Request");
|
||||
await this.setConfigS(key, value);
|
||||
await this.setConfigS(ctx, key, value);
|
||||
return ctx.json(
|
||||
makeResponse({
|
||||
message: 'Config updated successfully',
|
||||
|
@ -52,7 +56,7 @@ export default class ConfigController
|
|||
const { key } = ctx.req.param() as { key: ConfigKeysTypes };
|
||||
if (!key)
|
||||
throw new Error("Invalid Request");
|
||||
const config = await this.getConfigS(key);
|
||||
const config = await this.getConfigS(ctx, key);
|
||||
ctx.json(makeResponse(config));
|
||||
} catch (error) {
|
||||
return ctx.json({
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
import { NextFunction, Response, Request } from 'express';
|
||||
import GistService from '../services/gist.service';
|
||||
import { ModRequest } from '../types';
|
||||
import { makeResponse } from '../libs';
|
||||
import {
|
||||
GistRep,
|
||||
|
@ -9,6 +7,13 @@ import {
|
|||
} from '../interfaces/gists.interface';
|
||||
import { Context } from 'hono';
|
||||
|
||||
type Bindings = {
|
||||
SHX_BUCKET: R2Bucket
|
||||
}
|
||||
type Variables = {
|
||||
user: any
|
||||
}
|
||||
|
||||
export default class GistController
|
||||
extends GistService
|
||||
implements IGistController
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
import { Context } from 'hono';
|
||||
import { makeResponse } from '../libs';
|
||||
import { CustomError } from '../libs/error';
|
||||
import InfoService from '../services/info.service';
|
||||
|
||||
export default class InfoController extends InfoService {
|
||||
public static get = async (
|
||||
ctx: Context
|
||||
) => {
|
||||
try {
|
||||
const data = await this.getSystemInfo();
|
||||
return ctx.json(makeResponse(data));
|
||||
} catch (error) {
|
||||
return ctx.json(error);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -2,83 +2,32 @@ import { Context } from 'hono';
|
|||
import Uploader from '../services/upload.service';
|
||||
import { makeResponse } from '../libs';
|
||||
import { IUploaderController, UploadRep } from '../interfaces/upload.interface';
|
||||
|
||||
import { Bindings, Variables } from '../types';
|
||||
export default class UploadController
|
||||
extends Uploader
|
||||
implements IUploaderController
|
||||
{
|
||||
public upload = async (
|
||||
ctx: Context
|
||||
ctx: Context<{ Bindings: Bindings, Variables: Variables }>
|
||||
) => {
|
||||
try {
|
||||
const { file } = await ctx.req.parseBody();
|
||||
const { file } = await ctx.req.parseBody() as {
|
||||
file: File;
|
||||
}
|
||||
if (!file) {
|
||||
throw new Error('Please upload a file');
|
||||
}
|
||||
let data: UploadRep = await this.uploadS(file, await await ctx.get("user"));
|
||||
data = {
|
||||
...data,
|
||||
url: data.upload_url,
|
||||
};
|
||||
return ctx.json(makeResponse(data));
|
||||
} catch (error) {
|
||||
return ctx.json(error)
|
||||
}
|
||||
};
|
||||
|
||||
public uploadImage = async (
|
||||
ctx: Context
|
||||
) => {
|
||||
try {
|
||||
const { file } = await ctx.req.parseBody();
|
||||
if (!file) {
|
||||
throw new Error('Please upload a image');
|
||||
}
|
||||
let data: UploadRep = await this.uploadImageS(file, await ctx.get("user"));
|
||||
data = {
|
||||
...data,
|
||||
url: data.upload_url,
|
||||
};
|
||||
return ctx.json(makeResponse(data));
|
||||
} catch (error) {
|
||||
return ctx.json(error)
|
||||
}
|
||||
};
|
||||
|
||||
public uploadImageFromURL = async (
|
||||
ctx: Context
|
||||
) => {
|
||||
try {
|
||||
const { url } = await ctx.req.json();
|
||||
if (!url) {
|
||||
throw new Error('Please provide a url');
|
||||
}
|
||||
let data: UploadRep = await this.uploadImageViaURLS(url, await ctx.get("user"));
|
||||
data = {
|
||||
...data,
|
||||
url: data.upload_url,
|
||||
};
|
||||
return ctx.json(makeResponse(data));
|
||||
} catch (error) {
|
||||
return ctx.json(error)
|
||||
}
|
||||
};
|
||||
|
||||
public uploadFileFromURL = async (
|
||||
ctx: Context
|
||||
) => {
|
||||
try {
|
||||
const { url } = await ctx.req.json();
|
||||
if (!url) {
|
||||
throw new Error('Please provide a url');
|
||||
}
|
||||
let data: UploadRep = await this.uploadFileViaURLS(url, await ctx.get("user"));
|
||||
const file_name = Date.now() + "-" + file.name;
|
||||
const shx_upload = await ctx.env.SHX_BUCKET.put(file_name, ctx.req.body);
|
||||
console.log(shx_upload);
|
||||
let data: UploadRep = await this.uploadS(file_name, await ctx.get("user"));
|
||||
data = {
|
||||
...data,
|
||||
url: data.upload_url,
|
||||
};
|
||||
return ctx.json(makeResponse(data));
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
return ctx.json(error)
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,123 +0,0 @@
|
|||
import * as redis from 'redis';
|
||||
import NodeCache from 'node-cache';
|
||||
import { logger } from '../libs';
|
||||
|
||||
export type CacheEnvironment = 'inmemory' | 'redis';
|
||||
export default class CacheClient {
|
||||
private static _clientMode: CacheEnvironment;
|
||||
private static _redisClient: redis.RedisClientType;
|
||||
private static _nodeClient: NodeCache;
|
||||
|
||||
static get client() {
|
||||
return this._clientMode === 'redis' ? this._redisClient : this._nodeClient;
|
||||
}
|
||||
|
||||
static get env() {
|
||||
return this._clientMode;
|
||||
}
|
||||
|
||||
static init(forceEnv?: CacheEnvironment) {
|
||||
const env = forceEnv || process.env.CACHE_ENV || 'inmemory';
|
||||
|
||||
if (!['inmemory', 'redis'].includes(env))
|
||||
throw new Error(
|
||||
"Invalid Caching Environment, expected - ['inmemory', 'redis'], received - " +
|
||||
env
|
||||
);
|
||||
|
||||
this._clientMode = env as CacheEnvironment;
|
||||
|
||||
const redisUrl = process.env.REDIS_URL || '';
|
||||
|
||||
if (env === 'redis') {
|
||||
this._redisClient = redis.createClient({
|
||||
url: redisUrl,
|
||||
name: '<>',
|
||||
});
|
||||
this._redisClient.connect();
|
||||
}
|
||||
|
||||
this._nodeClient = new NodeCache();
|
||||
logger.info(`🪣 Caching Client initialized in '${env}' mode`);
|
||||
}
|
||||
|
||||
static async set(key: string, value: any) {
|
||||
if (this._clientMode === 'redis') {
|
||||
await this._redisClient.set(key, value);
|
||||
} else {
|
||||
this._nodeClient.set(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
static async get(key: string): Promise<string | null> {
|
||||
if (this._clientMode === 'redis') {
|
||||
return await this._redisClient.get(key);
|
||||
} else {
|
||||
return (this._nodeClient.get(key) as string) || null;
|
||||
}
|
||||
}
|
||||
|
||||
static async keys(keysample: string): Promise<string[]> {
|
||||
if (this._clientMode === 'redis') {
|
||||
return await this._redisClient.keys(keysample);
|
||||
} else {
|
||||
return this._nodeClient.keys().filter(key => key.includes(keysample));
|
||||
}
|
||||
}
|
||||
|
||||
static async delete(key: string) {
|
||||
if (this._clientMode === 'redis') {
|
||||
await this._redisClient.del(key);
|
||||
} else {
|
||||
this._nodeClient.del(key);
|
||||
}
|
||||
}
|
||||
|
||||
static async hset(key: string, field: string, value: any) {
|
||||
if (this._clientMode === 'redis') {
|
||||
await this._redisClient.HSET(key, field, value);
|
||||
} else {
|
||||
this._nodeClient.set(key + '.' + field, value);
|
||||
}
|
||||
}
|
||||
|
||||
static async hget(key: string, field: string) {
|
||||
if (this._clientMode === 'redis') {
|
||||
return await this._redisClient.HGET(key, field);
|
||||
} else {
|
||||
return (this._nodeClient.get(key + '.' + field) as string) || null;
|
||||
}
|
||||
}
|
||||
|
||||
static async hgetall(key: string) {
|
||||
if (this._clientMode === 'redis') {
|
||||
return await this._redisClient.HGETALL(key);
|
||||
} else {
|
||||
const keys = this._nodeClient.keys();
|
||||
const filteredKeys = keys.filter(key => key.includes(key));
|
||||
const values = filteredKeys.map(key => {
|
||||
const value: any = this._nodeClient.get(key);
|
||||
if (
|
||||
typeof value === 'string' &&
|
||||
value.startsWith('"[') &&
|
||||
value.endsWith(']"')
|
||||
)
|
||||
return { [key.split('.')[1]]: JSON.parse(value) };
|
||||
else if (
|
||||
typeof value === 'string' &&
|
||||
value.startsWith('"') &&
|
||||
value.endsWith('"')
|
||||
)
|
||||
return { [key.split('.')[1]]: value.slice(1, -1) };
|
||||
else if (
|
||||
typeof value === 'string' &&
|
||||
value.startsWith('"{') &&
|
||||
value.endsWith('}"')
|
||||
)
|
||||
return { [key.split('.')[1]]: JSON.parse(value.slice(1, -1)) };
|
||||
return { [key.split('.')[1]]: value };
|
||||
});
|
||||
return Object.assign({}, ...values);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,10 @@
|
|||
import { GraphQLClient } from 'graphql-request';
|
||||
import axios from 'axios';
|
||||
import { logger } from '../libs';
|
||||
|
||||
export let client = new GraphQLClient('');
|
||||
|
||||
export const hgqlInit = async () => {
|
||||
logger.info('🚀 GraphQL Client Initialized');
|
||||
console.log('🚀 GraphQL Client Initialized');
|
||||
|
||||
let HASURA_URL: string = process.env.HASURA_GRAPHQL_ENDPOINT || '';
|
||||
HASURA_URL += HASURA_URL.endsWith('/') ? 'v1/graphql' : '/v1/graphql';
|
||||
|
@ -189,7 +188,7 @@ export const hgqlInit = async () => {
|
|||
...config,
|
||||
data: data,
|
||||
}).then(res => {
|
||||
logger.info(
|
||||
console.log(
|
||||
'🪄 Hasura Tables Metadata Tracked for ' + res.data.length + ' tables'
|
||||
);
|
||||
});
|
||||
|
@ -197,7 +196,7 @@ export const hgqlInit = async () => {
|
|||
...config,
|
||||
data: data2,
|
||||
}).then(res => {
|
||||
logger.info(
|
||||
console.log(
|
||||
'🪄 Hasura Relationships Metadata Tracked for ' +
|
||||
res.data.length +
|
||||
' relationships'
|
||||
|
@ -205,9 +204,9 @@ export const hgqlInit = async () => {
|
|||
});
|
||||
} catch (err: any) {
|
||||
if (err.response?.data?.code == 'already-tracked') {
|
||||
logger.info('🃏 Hasura Metadata Already Tracked');
|
||||
console.log('🃏 Hasura Metadata Already Tracked');
|
||||
} else {
|
||||
logger.info('🚨 Hasura Metadata Tracking Failed');
|
||||
console.log('🚨 Hasura Metadata Tracking Failed');
|
||||
|
||||
setTimeout(() => {
|
||||
hgqlInit();
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
export * from './cache.factory';
|
||||
export * from './gql_clent';
|
||||
export * from './axios_client';
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
import multer from 'multer';
|
||||
import path from 'path';
|
||||
import { FileData } from '../types';
|
||||
import { IUploadFactory, UploaderConfig } from '../interfaces/upload.interface';
|
||||
|
||||
export class UploadFactory implements IUploadFactory {
|
||||
public getUploader(config?: UploaderConfig): any {
|
||||
const storage = multer.memoryStorage();
|
||||
|
||||
return multer({
|
||||
storage: storage,
|
||||
fileFilter: (req, file: FileData, cb) => {
|
||||
file.originalname = file.originalname.replace(/\s/g, '_');
|
||||
const fileName =
|
||||
file.originalname.split('.')[
|
||||
file.originalname.split('.').length - 2
|
||||
] +
|
||||
'-' +
|
||||
Date.now() +
|
||||
path.extname(file.originalname);
|
||||
file.newName = fileName;
|
||||
if (config?.mimeFilters?.length) {
|
||||
if (config.mimeFilters.includes(file.mimetype)) {
|
||||
cb(null, true);
|
||||
} else {
|
||||
cb(null, false);
|
||||
}
|
||||
} else {
|
||||
cb(null, true);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,41 +1,53 @@
|
|||
import 'dotenv/config';
|
||||
import './configs';
|
||||
|
||||
import { Hono } from 'hono';
|
||||
import { cors } from 'hono/cors';
|
||||
import { logger as rlogger } from 'hono/logger';
|
||||
import { poweredBy } from 'hono/powered-by'
|
||||
|
||||
import { serve } from '@hono/node-server';
|
||||
|
||||
import { hgqlInit } from './helpers';
|
||||
import { notFoundHandler, logger, LogStream } from './libs';
|
||||
import { notFoundHandler } from './libs';
|
||||
import pkg from './package.json' assert { type: 'json' };
|
||||
import routes from './routes';
|
||||
|
||||
import CacheClient, { CacheEnvironment } from './helpers/cache.factory';
|
||||
import URLStoreController from './controllers/urlstore.controller';
|
||||
import ConfigService from './services/config.service';
|
||||
import { Bindings, Variables } from './types';
|
||||
|
||||
export const app = new Hono({
|
||||
export type Env = {
|
||||
ENVIRONMENT: 'development' | 'production';
|
||||
SHX_BUCKET: R2Bucket;
|
||||
SHX_SETTINGS: KVNamespace;
|
||||
R2_BUCKET_ENDPOINT: string;
|
||||
R2_CLIENT_ID: string;
|
||||
R2_CLIENT_SECRET: string;
|
||||
R2_BUCKET_NAME: number;
|
||||
R2_BUCKET_FOLDER: string;
|
||||
R2_BUCKET_URL: string;
|
||||
R2_BUCKET_REGION: string;
|
||||
HASURA_GRAPHQL_ADMIN_SECRET: string;
|
||||
HASURA_GRAPHQL_ENDPOINT: string;
|
||||
DATABASE_URL: string;
|
||||
MASTER_KEY: string;
|
||||
};
|
||||
|
||||
|
||||
export const app = new Hono<{Bindings: Bindings, Variables: Variables}>({
|
||||
strict: false
|
||||
});
|
||||
|
||||
app.use('*', rlogger())
|
||||
app.use('*', poweredBy())
|
||||
|
||||
logger.info('🚀 @' + pkg.author.name + '/' + pkg.name, 'v' + pkg.version);
|
||||
console.log('🚀 @' + pkg.author.name + '/' + pkg.name, 'v' + pkg.version);
|
||||
|
||||
const isDev: boolean = process.env.NODE_ENV == 'production';
|
||||
logger.info(isDev ? '🚀 Production Mode' : '🚀 Development Mode');
|
||||
console.log(isDev ? '🚀 Production Mode' : '🚀 Development Mode');
|
||||
|
||||
const urlStoreController = new URLStoreController();
|
||||
const logStream = new LogStream();
|
||||
|
||||
logger.info(`🔑 Master Key ${process.env.MASTER_KEY}`);
|
||||
console.log(`🔑 Master Key ${process.env.MASTER_KEY}`);
|
||||
|
||||
hgqlInit();
|
||||
CacheClient.init(process.env.CACHE_ENV as CacheEnvironment);
|
||||
|
||||
app.get('/health', (ctx) => {
|
||||
return ctx.json({
|
||||
|
@ -45,23 +57,18 @@ app.get('/health', (ctx) => {
|
|||
});
|
||||
});
|
||||
|
||||
logger.info('🦄 Base Route /');
|
||||
console.log('🦄 Base Route /');
|
||||
|
||||
app.route('/', routes);
|
||||
app.get('/:urlKey', urlStoreController.get);
|
||||
|
||||
app.all('*', notFoundHandler);
|
||||
|
||||
logger.info(`🚂 Server running on port ${process.env.PORT}`);
|
||||
console.log(`🚂 Server running on port ${process.env.PORT}`);
|
||||
|
||||
const { initConfig } = new ConfigService();
|
||||
await initConfig();
|
||||
|
||||
app.showRoutes()
|
||||
|
||||
serve({
|
||||
fetch: app.fetch,
|
||||
port: Number(process.env.PORT)
|
||||
})
|
||||
|
||||
export { logger };
|
||||
export default app
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
# wrangler r2 bucket create shx
|
||||
# wrangler kv:namespace create "SHX_SETTINGS"
|
||||
wrangler secret:bulk secrets.json
|
|
@ -15,7 +15,7 @@ export interface IConfigController {
|
|||
}
|
||||
|
||||
export interface IConfigService {
|
||||
initConfig(): Promise<boolean>;
|
||||
initConfig(T): Promise<boolean>;
|
||||
getAllConfigS(): Promise<Settings>;
|
||||
setConfigS(key: ConfigKeysTypes, value: string): Promise<void>;
|
||||
getConfigS(
|
||||
|
|
|
@ -6,15 +6,6 @@ export interface IUploaderController {
|
|||
upload(
|
||||
ctx: Context
|
||||
);
|
||||
uploadImage(
|
||||
ctx: Context
|
||||
);
|
||||
uploadImageFromURL(
|
||||
ctx: Context
|
||||
);
|
||||
uploadFileFromURL(
|
||||
ctx: Context
|
||||
);
|
||||
getFile(
|
||||
ctx: Context
|
||||
);
|
||||
|
@ -27,12 +18,7 @@ export interface IUploaderController {
|
|||
}
|
||||
|
||||
export interface IUploaderService {
|
||||
uploadImageS(file: any, meta: UserMeta): Promise<Uploads>;
|
||||
uploadS(file: any, meta: UserMeta): Promise<Uploads>;
|
||||
uploadImageViaURLS(url: string, meta: UserMeta): Promise<Uploads>;
|
||||
uploadFileViaURLS(url: string, meta: UserMeta): Promise<Uploads>;
|
||||
downloadImage(url: string): Promise<string>;
|
||||
downloadFile(url: string): Promise<string>;
|
||||
deleteFileS(fileID: string, delToken: string): Promise<Uploads>;
|
||||
listFilesS(
|
||||
searchQuery: any,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { Apikeys } from '../graphql/types';
|
||||
import { PaginationType } from '../types';
|
||||
import { createLogger, format, transports } from 'winston';
|
||||
|
||||
export const makeResponse = (
|
||||
data: any,
|
||||
|
@ -167,32 +166,3 @@ export const encapDataKeys = (data: Apikeys[]) => {
|
|||
});
|
||||
return new_data;
|
||||
};
|
||||
|
||||
const { combine, timestamp, label, printf } = format;
|
||||
const formater = printf(({ level, message, label, timestamp }) => {
|
||||
return `${timestamp} [${label}] ${level}: ${message}`;
|
||||
});
|
||||
|
||||
export const logger = createLogger({
|
||||
level: 'info',
|
||||
format: combine(label({ label: '📢' }), timestamp(), formater),
|
||||
transports: [
|
||||
new transports.Console(),
|
||||
new transports.File({ filename: 'error.log', level: 'error' }),
|
||||
new transports.File({ filename: 'combined.log' }),
|
||||
],
|
||||
});
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
logger.add(
|
||||
new transports.Console({
|
||||
format: format.simple(),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
export class LogStream {
|
||||
write(text: string) {
|
||||
logger.info(text.replace(/\n$/, ''));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,8 +37,9 @@
|
|||
},
|
||||
"scripts": {
|
||||
"dev": "concurrently \"npm run dev:api\" \"npm run dev:hasura\"",
|
||||
"deploy": "wrangler deploy --minify src/index.ts",
|
||||
"dev:hasura": "cd hasura && hasura --skip-update-check --envfile ../.env console",
|
||||
"dev:api": "dotenv -- cross-env NODE_ENV=development nodemon -x node --no-warnings --loader @esbuild-kit/esm-loader index.ts --signal SIGKILL --ignore node_modules",
|
||||
"dev:api": "dotenv -- cross-env NODE_ENV=development wrangler dev index.ts",
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"start": "node --es-module-specifier-resolution=node --loader ts-node/esm ./build/index.js",
|
||||
"fetch:schemas": "bash bin/fetch-gql-schema.sh",
|
||||
|
@ -47,6 +48,7 @@
|
|||
"watch": "tsc -w"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cloudflare/workers-types": "^4.20230914.0",
|
||||
"@esbuild-kit/esm-loader": "^2.5.5",
|
||||
"@graphql-codegen/cli": "^5.0.0",
|
||||
"@graphql-codegen/typescript": "^4.0.0",
|
||||
|
@ -66,6 +68,7 @@
|
|||
"lint-staged": "^14.0.1",
|
||||
"nodemon": "^3.0.1",
|
||||
"prettier": "^2.8.2",
|
||||
"typescript": "^5.1.6"
|
||||
"typescript": "^5.1.6",
|
||||
"wrangler": "^3.9.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,16 +3,11 @@ import { Hono } from 'hono';
|
|||
import apikey from './apikey.routes';
|
||||
import config from './config.routes';
|
||||
import gist from './gist.routes';
|
||||
import info from './info.routes';
|
||||
import settings from './settings.routes';
|
||||
import upload from './upload.routes';
|
||||
import url from './url.routes';
|
||||
|
||||
import pkg from '../package.json' assert { type: 'json' };
|
||||
import { execSync } from 'child_process';
|
||||
let gitHash = '';
|
||||
if (!process.env.DOCKER_ENV)
|
||||
gitHash = execSync('git rev-parse HEAD').toString().trim();
|
||||
|
||||
const router = new Hono();
|
||||
|
||||
|
@ -22,14 +17,12 @@ router.get('/', (ctx) => {
|
|||
status: 'OK',
|
||||
version: pkg.version,
|
||||
source_code: pkg.repository,
|
||||
git_commit_id: gitHash,
|
||||
});
|
||||
});
|
||||
|
||||
router.route('/apikey', apikey);
|
||||
router.route('/config', config);
|
||||
router.route('/gist', gist);
|
||||
router.route('/info', info);
|
||||
router.route('/settings', settings);
|
||||
router.route('/upload', upload);
|
||||
router.route('/url', url);
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
import { Hono } from 'hono';
|
||||
import APIKeyAuth from '../middlewares/apikey_check';
|
||||
import InfoController from '../controllers/info.controller';
|
||||
|
||||
const infoController = InfoController;
|
||||
const apiKeyAuth = new APIKeyAuth();
|
||||
|
||||
const router = new Hono();
|
||||
|
||||
router.get('/sys', apiKeyAuth.check, infoController.get);
|
||||
|
||||
export default router;
|
|
@ -3,11 +3,12 @@ import APIKeyAuth from '../middlewares/apikey_check';
|
|||
import ConfigController from '../controllers/config.controller';
|
||||
import { z } from 'zod';
|
||||
import { zValidator } from '@hono/zod-validator';
|
||||
import { Bindings, Variables } from '../types';
|
||||
|
||||
const configController = new ConfigController();
|
||||
const apiKeyAuth = new APIKeyAuth();
|
||||
|
||||
const router = new Hono();
|
||||
const router = new Hono<{Bindings: Bindings, Variables: Variables}>();
|
||||
|
||||
router.get('/', apiKeyAuth.check, configController.getAllConfig);
|
||||
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import { Hono } from 'hono';
|
||||
import UploadController from '../controllers/upload.controller';
|
||||
import APIKeyAuth from '../middlewares/apikey_check';
|
||||
import { Bindings, Variables } from '../types';
|
||||
|
||||
const uploadController = new UploadController();
|
||||
const apiKeyAuth = new APIKeyAuth();
|
||||
|
||||
const router = new Hono();
|
||||
const router = new Hono<{ Bindings: Bindings, Variables: Variables }>();
|
||||
|
||||
router.post(
|
||||
'/file',
|
||||
|
@ -13,24 +14,6 @@ router.post(
|
|||
uploadController.upload
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/image',
|
||||
apiKeyAuth.check,
|
||||
uploadController.uploadImage
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/image-from-url',
|
||||
apiKeyAuth.check,
|
||||
uploadController.uploadImageFromURL
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/file-from-url',
|
||||
apiKeyAuth.check,
|
||||
uploadController.uploadFileFromURL
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/',
|
||||
apiKeyAuth.check,
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"HASURA_GRAPHQL_ADMIN_SECRET": "xxxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
"HASURA_GRAPHQL_ENDPOINT": "https://xxxxxxxx.hasura.app",
|
||||
"R2_CLIENT_ID": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
"R2_CLIENT_SECRET": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
"R2_BUCKET_NAME": "xxxxxxxx",
|
||||
"R2_BUCKET_REGION": "apac",
|
||||
"R2_BUCKET_ENDPOINT": "https://xxxxxxxxxxxxxxxxxxxx.r2.cloudflarestorage.com/xxxxxxx",
|
||||
"R2_BUCKET_URL": "https://xxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
"R2_BUCKET_FOLDER": "xxxxxxxxxxxxx",
|
||||
"MASTER_KEY": "xxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
"DATABASE_URL": "postgres://xxxxxxxxxxx:xxxxxxxxxxxxxxxxxxxx@xxxxxxxxxxxxxxxxxxxxxxxxxxxx/xxxxxxxxxxx"
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import CacheClient from '../helpers/cache.factory';
|
||||
import { Context } from 'hono';
|
||||
import {
|
||||
IConfigService,
|
||||
ConfigKeysTypes,
|
||||
|
@ -6,22 +6,31 @@ import {
|
|||
ThemeType,
|
||||
LanguageType,
|
||||
} from '../interfaces/config.interface';
|
||||
import { logger } from '../libs';
|
||||
|
||||
import { Bindings, Variables } from '../types';
|
||||
import { Env } from '../index';
|
||||
export default class ConfigService implements IConfigService {
|
||||
|
||||
|
||||
public initConfig = async (): Promise<boolean> => {
|
||||
const config = await CacheClient.keys('config');
|
||||
let config = [
|
||||
await Env.SHX_SETTINGS.get('theme'),
|
||||
await SHX_SETTINGS.get('language'),
|
||||
await SHX_SETTINGS.get('imageExtensions'),
|
||||
await SHX_SETTINGS.get('fileExtensions'),
|
||||
];
|
||||
|
||||
config = await Promise.all(config);
|
||||
|
||||
if (config && config.length > 0) {
|
||||
logger.info('⚽ Config already initialized');
|
||||
return true;
|
||||
} else {
|
||||
await this.setConfigS('theme', 'dark');
|
||||
await this.setConfigS('language', 'en');
|
||||
await this.setConfigS(
|
||||
await this.setConfigS(ctx, 'theme', 'dark');
|
||||
await this.setConfigS(ctx, 'language', 'en');
|
||||
await this.setConfigS(ctx,
|
||||
'imageExtensions',
|
||||
JSON.stringify(['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'ico'])
|
||||
);
|
||||
await this.setConfigS(
|
||||
await this.setConfigS(ctx,
|
||||
'fileExtensions',
|
||||
JSON.stringify([
|
||||
'png',
|
||||
|
@ -48,21 +57,33 @@ export default class ConfigService implements IConfigService {
|
|||
'html',
|
||||
])
|
||||
);
|
||||
logger.info('⚽ Config initialized successfully');
|
||||
console.log('⚽ Config initialized successfully');
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
public getAllConfigS = async (): Promise<Settings> => {
|
||||
const settings: Partial<Settings | any> = await CacheClient.hgetall(
|
||||
'config'
|
||||
);
|
||||
public getAllConfigS = async (ctx: Context<{Bindings: Bindings, Variables: Variables}>): Promise<Settings> => {
|
||||
let config = [
|
||||
await ctx.env.SHX_SETTINGS.get('theme'),
|
||||
await ctx.env.SHX_SETTINGS.get('language'),
|
||||
await ctx.env.SHX_SETTINGS.get('imageExtensions'),
|
||||
await ctx.env.SHX_SETTINGS.get('fileExtensions'),
|
||||
];
|
||||
|
||||
const [theme, language, imageExtensions, fileExtensions] = await Promise.all(config);
|
||||
const settings: Partial<Settings | any> = {
|
||||
theme: theme as ThemeType,
|
||||
language: language as LanguageType,
|
||||
imageExtensions,
|
||||
fileExtensions,
|
||||
}
|
||||
settings.imageExtensions = JSON.parse(settings['imageExtensions']);
|
||||
settings.fileExtensions = JSON.parse(settings['fileExtensions']);
|
||||
return settings as Settings;
|
||||
};
|
||||
|
||||
public setConfigS = async (
|
||||
ctx: Context<{Bindings: Bindings, Variables: Variables}>,
|
||||
key: ConfigKeysTypes,
|
||||
value: string[] | string | boolean | number | ThemeType | LanguageType
|
||||
): Promise<void> => {
|
||||
|
@ -72,6 +93,7 @@ export default class ConfigService implements IConfigService {
|
|||
};
|
||||
|
||||
public getConfigS = async (
|
||||
ctx: Context<{Bindings: Bindings, Variables: Variables}>,
|
||||
key: ConfigKeysTypes
|
||||
): Promise<
|
||||
| string[]
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
import os from 'node:os';
|
||||
|
||||
export default class InfoService {
|
||||
static async getSystemInfo() {
|
||||
const sys = {
|
||||
platform: process.platform,
|
||||
arch: process.arch,
|
||||
nodeVersion: process.version,
|
||||
uptime: process.uptime(),
|
||||
memoryUsage: process.memoryUsage(),
|
||||
cpuUsage: process.cpuUsage(),
|
||||
kernelVersion: os.release(),
|
||||
hostname: os.hostname(),
|
||||
};
|
||||
|
||||
return sys;
|
||||
}
|
||||
}
|
|
@ -1,16 +1,9 @@
|
|||
import UploaderService from '../data/uploader.service';
|
||||
import { gql } from 'graphql-request';
|
||||
import { client } from '../helpers';
|
||||
import sharp from 'sharp';
|
||||
import { IListUploads, IUploaderService } from '../interfaces/upload.interface';
|
||||
import { UserMeta } from '../types';
|
||||
import axios from 'axios';
|
||||
import fs from 'fs';
|
||||
import { nanoid } from 'napi-nanoid';
|
||||
import sanitize from 'sanitize-filename';
|
||||
import ConfigService from './config.service';
|
||||
import { CustomError } from '../libs/error';
|
||||
import { logger } from '../libs';
|
||||
import { Uploads } from '../graphql/types';
|
||||
|
||||
export default class Uploader implements IUploaderService {
|
||||
|
@ -23,13 +16,6 @@ export default class Uploader implements IUploaderService {
|
|||
}
|
||||
|
||||
public uploadS = async (file: any, meta: UserMeta): Promise<Uploads> => {
|
||||
await this.uploaderService.uploadFile(
|
||||
process.env.R2_BUCKET_FOLDER as string,
|
||||
file.newName,
|
||||
file.buffer,
|
||||
file.mimetype,
|
||||
'public-read'
|
||||
);
|
||||
const query = gql`
|
||||
mutation uploadFile($file: uploads_insert_input!) {
|
||||
insert_uploads_one(object: $file) {
|
||||
|
@ -65,214 +51,6 @@ export default class Uploader implements IUploaderService {
|
|||
return data.insert_uploads_one;
|
||||
};
|
||||
|
||||
public uploadImageS = async (file: any, meta: UserMeta): Promise<Uploads> => {
|
||||
const image = sharp(file.buffer);
|
||||
await image.toFormat('jpeg');
|
||||
const buffer = await image.toBuffer();
|
||||
await this.uploaderService.uploadFile(
|
||||
process.env.R2_BUCKET_FOLDER as string,
|
||||
file.newName,
|
||||
buffer,
|
||||
file.mimetype,
|
||||
'public-read'
|
||||
);
|
||||
const query = gql`
|
||||
mutation uploadFile($file: uploads_insert_input!) {
|
||||
insert_uploads_one(object: $file) {
|
||||
fileID
|
||||
uploaded_at
|
||||
filename
|
||||
upload_url
|
||||
deleteToken
|
||||
}
|
||||
}
|
||||
`;
|
||||
const urlObj = {
|
||||
url:
|
||||
process.env.R2_BUCKET_URL +
|
||||
'/' +
|
||||
process.env.R2_BUCKET_NAME +
|
||||
'/' +
|
||||
process.env.R2_BUCKET_FOLDER +
|
||||
'/' +
|
||||
file.newName,
|
||||
};
|
||||
const variables = {
|
||||
file: {
|
||||
upload_url: urlObj.url,
|
||||
filename: file.originalname,
|
||||
uploader_ip: meta.ip,
|
||||
apikeyUsed: meta.apiKeyID,
|
||||
},
|
||||
};
|
||||
const data: {
|
||||
insert_uploads_one: Uploads;
|
||||
} = await client.request(query, variables);
|
||||
return data.insert_uploads_one;
|
||||
};
|
||||
|
||||
public uploadImageViaURLS = async (
|
||||
url: string,
|
||||
meta: UserMeta
|
||||
): Promise<Uploads> => {
|
||||
let filename = await this.downloadImage(url);
|
||||
filename = sanitize(filename);
|
||||
const rawImage = fs.readFileSync(`uploads/${filename}`);
|
||||
const image = sharp(rawImage);
|
||||
await image.toFormat('jpeg');
|
||||
const buffer = await image.toBuffer();
|
||||
await this.uploaderService.uploadFile(
|
||||
process.env.R2_BUCKET_FOLDER as string,
|
||||
filename,
|
||||
buffer,
|
||||
'image/jpeg',
|
||||
'public-read'
|
||||
);
|
||||
|
||||
const query = gql`
|
||||
mutation uploadFile($file: uploads_insert_input!) {
|
||||
insert_uploads_one(object: $file) {
|
||||
fileID
|
||||
uploaded_at
|
||||
filename
|
||||
upload_url
|
||||
deleteToken
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const urlObj = {
|
||||
url:
|
||||
process.env.R2_BUCKET_URL +
|
||||
'/' +
|
||||
process.env.R2_BUCKET_NAME +
|
||||
'/' +
|
||||
process.env.R2_BUCKET_FOLDER +
|
||||
'/' +
|
||||
filename,
|
||||
};
|
||||
|
||||
const variables = {
|
||||
file: {
|
||||
upload_url: urlObj.url,
|
||||
filename: filename,
|
||||
uploader_ip: meta.ip,
|
||||
apikeyUsed: meta.apiKeyID,
|
||||
},
|
||||
};
|
||||
|
||||
const data: {
|
||||
insert_uploads_one: Uploads;
|
||||
} = await client.request(query, variables);
|
||||
return data.insert_uploads_one;
|
||||
};
|
||||
|
||||
public downloadImage = async (url: string): Promise<string> => {
|
||||
let filename = nanoid() + url.split('/').pop();
|
||||
filename = sanitize(filename);
|
||||
const whitelistedExtensions = await this.configService.getConfigS(
|
||||
'imageExtensions'
|
||||
);
|
||||
if (!whitelistedExtensions.includes(filename.split('.').pop() as string)) {
|
||||
throw new CustomError({
|
||||
message: 'Image extension not whitelisted',
|
||||
statusCode: 400,
|
||||
});
|
||||
}
|
||||
await axios({
|
||||
url,
|
||||
method: 'GET',
|
||||
responseType: 'arraybuffer',
|
||||
})
|
||||
.then(res => {
|
||||
return sharp(res.data).toFile(`uploads/${filename}`);
|
||||
})
|
||||
.catch(err => {
|
||||
logger.info(`Couldn't process: ${err}`);
|
||||
});
|
||||
|
||||
return filename;
|
||||
};
|
||||
|
||||
public uploadFileViaURLS = async (
|
||||
url: string,
|
||||
meta: UserMeta
|
||||
): Promise<Uploads> => {
|
||||
let filename = await this.downloadFile(url);
|
||||
filename = sanitize(filename);
|
||||
await this.uploaderService.uploadFile(
|
||||
process.env.R2_BUCKET_FOLDER as string,
|
||||
filename,
|
||||
fs.readFileSync(`uploads/${filename}`),
|
||||
'application/octet-stream',
|
||||
'public-read'
|
||||
);
|
||||
|
||||
const query = gql`
|
||||
mutation uploadFile($file: uploads_insert_input!) {
|
||||
insert_uploads_one(object: $file) {
|
||||
fileID
|
||||
uploaded_at
|
||||
filename
|
||||
upload_url
|
||||
deleteToken
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const urlObj = {
|
||||
url:
|
||||
process.env.R2_BUCKET_URL +
|
||||
'/' +
|
||||
process.env.R2_BUCKET_NAME +
|
||||
'/' +
|
||||
process.env.R2_BUCKET_FOLDER +
|
||||
'/' +
|
||||
filename,
|
||||
};
|
||||
|
||||
const variables = {
|
||||
file: {
|
||||
upload_url: urlObj.url,
|
||||
filename: filename,
|
||||
uploader_ip: meta.ip,
|
||||
apikeyUsed: meta.apiKeyID,
|
||||
},
|
||||
};
|
||||
|
||||
const data: {
|
||||
insert_uploads_one: Uploads;
|
||||
} = await client.request(query, variables);
|
||||
return data.insert_uploads_one;
|
||||
};
|
||||
|
||||
public downloadFile = async (url: string): Promise<string> => {
|
||||
let filename = nanoid() + url.split('/').pop();
|
||||
filename = sanitize(filename);
|
||||
const whitelistedExtensions = await this.configService.getConfigS(
|
||||
'fileExtensions'
|
||||
);
|
||||
if (!whitelistedExtensions.includes(filename.split('.').pop() as string)) {
|
||||
throw new CustomError({
|
||||
message: 'File extension not whitelisted',
|
||||
statusCode: 400,
|
||||
});
|
||||
}
|
||||
await axios({
|
||||
url,
|
||||
method: 'GET',
|
||||
responseType: 'arraybuffer',
|
||||
})
|
||||
.then(res => {
|
||||
return fs.writeFileSync(`uploads/${filename}`, res.data);
|
||||
})
|
||||
.catch(err => {
|
||||
logger.info(`Couldn't process: ${err}`);
|
||||
});
|
||||
|
||||
return filename;
|
||||
};
|
||||
|
||||
public deleteFileS = async (
|
||||
fileID: string,
|
||||
delToken: string
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["es2018", "es5", "dom"],
|
||||
"typeRoots": ["node_modules/@types", "types"],
|
||||
"typeRoots": ["node_modules/@types", "types", "node_modules/@cloudflare/workers-types"],
|
||||
"resolveJsonModule": true,
|
||||
"esModuleInterop": true,
|
||||
"target": "ES2017",
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { Request } from 'express';
|
||||
export interface PaginationType {
|
||||
page: number;
|
||||
limit: number;
|
||||
|
@ -7,13 +6,6 @@ export interface PaginationType {
|
|||
filters?: { [k: string]: any };
|
||||
}
|
||||
|
||||
export interface ModRequest extends Request {
|
||||
file: any;
|
||||
files: any;
|
||||
user: UserMeta;
|
||||
image: any;
|
||||
}
|
||||
|
||||
export interface UserMeta {
|
||||
apiKeyID: string;
|
||||
ip: string;
|
||||
|
@ -43,6 +35,12 @@ export interface SXCUFile {
|
|||
ErrorMessage: string;
|
||||
}
|
||||
|
||||
export interface FileData extends Express.Multer.File {
|
||||
newName: string;
|
||||
|
||||
export type Bindings = {
|
||||
SHX_BUCKET: R2Bucket,
|
||||
SHX_SETTINGS: KVNamespace,
|
||||
}
|
||||
|
||||
export type Variables = {
|
||||
user: any
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
name = "shx-worker"
|
||||
compatibility_date = "2023-01-01"
|
||||
|
||||
[vars]
|
||||
MY_VARIABLE = "production_value"
|
||||
|
||||
[[kv_namespaces]]
|
||||
binding = "SHX_SETTINGS"
|
||||
id = "be1c00f6dc064c8aa5756fb58400d420"
|
||||
|
||||
[[r2_buckets]]
|
||||
binding = "SHX_BUCKET"
|
||||
bucket_name = "shx"
|
263
pnpm-lock.yaml
263
pnpm-lock.yaml
|
@ -342,6 +342,9 @@ importers:
|
|||
specifier: ^3.21.4
|
||||
version: 3.21.4
|
||||
devDependencies:
|
||||
'@cloudflare/workers-types':
|
||||
specifier: ^4.20230914.0
|
||||
version: 4.20230914.0
|
||||
'@esbuild-kit/esm-loader':
|
||||
specifier: ^2.5.5
|
||||
version: 2.5.5
|
||||
|
@ -402,6 +405,9 @@ importers:
|
|||
typescript:
|
||||
specifier: ^5.1.6
|
||||
version: 5.1.6
|
||||
wrangler:
|
||||
specifier: ^3.9.0
|
||||
version: 3.9.0
|
||||
|
||||
packages:
|
||||
|
||||
|
@ -3383,6 +3389,61 @@ packages:
|
|||
resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
|
||||
dev: true
|
||||
|
||||
/@cloudflare/kv-asset-handler@0.2.0:
|
||||
resolution: {integrity: sha512-MVbXLbTcAotOPUj0pAMhVtJ+3/kFkwJqc5qNOleOZTv6QkZZABDMS21dSrSlVswEHwrpWC03e4fWytjqKvuE2A==}
|
||||
dependencies:
|
||||
mime: 3.0.0
|
||||
dev: true
|
||||
|
||||
/@cloudflare/workerd-darwin-64@1.20230904.0:
|
||||
resolution: {integrity: sha512-/GDlmxAFbDtrQwP4zOXFbqOfaPvkDxdsCoEa+KEBcAl5uR98+7WW5/b8naBHX+t26uS7p4bLlImM8J5F1ienRQ==}
|
||||
engines: {node: '>=16'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@cloudflare/workerd-darwin-arm64@1.20230904.0:
|
||||
resolution: {integrity: sha512-x8WXNc2xnDqr5y1iirnNdyx8GZY3rL5xiF7ebK3mKQeB+jFjkhO71yuPTkDCzUWtOvw1Wfd4jbwy4wxacMX4mQ==}
|
||||
engines: {node: '>=16'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@cloudflare/workerd-linux-64@1.20230904.0:
|
||||
resolution: {integrity: sha512-V58xyMS3oDpKO8Dpdh0r0BXm99OzoGgvWe9ufttVraj/1NTMGELwb6i9ySb8k3F1J9m/sO26+TV7pQc/bGC1VQ==}
|
||||
engines: {node: '>=16'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@cloudflare/workerd-linux-arm64@1.20230904.0:
|
||||
resolution: {integrity: sha512-VrDaW+pjb5IAKEnNWtEaFiG377kXKmk5Fu0Era4W+jKzPON2BW/qRb/4LNHXQ4yxg/2HLm7RiUTn7JZtt1qO6A==}
|
||||
engines: {node: '>=16'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@cloudflare/workerd-windows-64@1.20230904.0:
|
||||
resolution: {integrity: sha512-/R/dE8uy+8J2YeXfDhI8/Bg7YUirdbbjH5/l/Vv00ZRE0lC3nPLcYeyBXSwXIQ6/Xht3gN+lksLQgKd0ZWRd+Q==}
|
||||
engines: {node: '>=16'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@cloudflare/workers-types@4.20230914.0:
|
||||
resolution: {integrity: sha512-OVeN4lFVu1O0PJGZ2d0FwpK8lelFcr33qYOgCh77ErEYmEBO4adwnIxcIsdQbFbhF0ffN6joiVcljD4zakdaeQ==}
|
||||
dev: true
|
||||
|
||||
/@colors/colors@1.5.0:
|
||||
resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==}
|
||||
engines: {node: '>=0.1.90'}
|
||||
|
@ -3520,6 +3581,24 @@ packages:
|
|||
'@esbuild-kit/core-utils': 3.2.2
|
||||
get-tsconfig: 4.7.0
|
||||
|
||||
/@esbuild-plugins/node-globals-polyfill@0.2.3(esbuild@0.17.19):
|
||||
resolution: {integrity: sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==}
|
||||
peerDependencies:
|
||||
esbuild: '*'
|
||||
dependencies:
|
||||
esbuild: 0.17.19
|
||||
dev: true
|
||||
|
||||
/@esbuild-plugins/node-modules-polyfill@0.2.2(esbuild@0.17.19):
|
||||
resolution: {integrity: sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA==}
|
||||
peerDependencies:
|
||||
esbuild: '*'
|
||||
dependencies:
|
||||
esbuild: 0.17.19
|
||||
escape-string-regexp: 4.0.0
|
||||
rollup-plugin-node-polyfills: 0.2.1
|
||||
dev: true
|
||||
|
||||
/@esbuild/android-arm64@0.17.19:
|
||||
resolution: {integrity: sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==}
|
||||
engines: {node: '>=12'}
|
||||
|
@ -9029,6 +9108,12 @@ packages:
|
|||
is-shared-array-buffer: 1.0.2
|
||||
dev: false
|
||||
|
||||
/as-table@1.0.55:
|
||||
resolution: {integrity: sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==}
|
||||
dependencies:
|
||||
printable-characters: 1.0.42
|
||||
dev: true
|
||||
|
||||
/asap@2.0.6:
|
||||
resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==}
|
||||
dev: true
|
||||
|
@ -9364,6 +9449,10 @@ packages:
|
|||
inherits: 2.0.4
|
||||
readable-stream: 3.6.2
|
||||
|
||||
/blake3-wasm@2.1.5:
|
||||
resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==}
|
||||
dev: true
|
||||
|
||||
/bn.js@4.12.0:
|
||||
resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==}
|
||||
dev: true
|
||||
|
@ -9663,6 +9752,15 @@ packages:
|
|||
upper-case-first: 2.0.2
|
||||
dev: true
|
||||
|
||||
/capnp-ts@0.7.0:
|
||||
resolution: {integrity: sha512-XKxXAC3HVPv7r674zP0VC3RTXz+/JKhfyw94ljvF80yynK6VkTnqE3jMuN8b3dUVmmc43TjyxjW4KTsmB3c86g==}
|
||||
dependencies:
|
||||
debug: 4.3.4(supports-color@8.1.1)
|
||||
tslib: 2.6.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/cardinal@2.1.1:
|
||||
resolution: {integrity: sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==}
|
||||
hasBin: true
|
||||
|
@ -10379,6 +10477,10 @@ packages:
|
|||
resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
|
||||
dev: false
|
||||
|
||||
/data-uri-to-buffer@2.0.2:
|
||||
resolution: {integrity: sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==}
|
||||
dev: true
|
||||
|
||||
/dataloader@2.2.2:
|
||||
resolution: {integrity: sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g==}
|
||||
dev: true
|
||||
|
@ -11463,6 +11565,10 @@ packages:
|
|||
- supports-color
|
||||
dev: true
|
||||
|
||||
/estree-walker@0.6.1:
|
||||
resolution: {integrity: sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==}
|
||||
dev: true
|
||||
|
||||
/esutils@2.0.3:
|
||||
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
@ -11539,6 +11645,11 @@ packages:
|
|||
strip-final-newline: 3.0.0
|
||||
dev: true
|
||||
|
||||
/exit-hook@2.2.1:
|
||||
resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==}
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/expand-template@2.0.3:
|
||||
resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
|
||||
engines: {node: '>=6'}
|
||||
|
@ -12132,6 +12243,13 @@ packages:
|
|||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/get-source@2.0.12:
|
||||
resolution: {integrity: sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==}
|
||||
dependencies:
|
||||
data-uri-to-buffer: 2.0.2
|
||||
source-map: 0.6.1
|
||||
dev: true
|
||||
|
||||
/get-stream@4.1.0:
|
||||
resolution: {integrity: sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==}
|
||||
engines: {node: '>=6'}
|
||||
|
@ -13941,6 +14059,12 @@ packages:
|
|||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/magic-string@0.25.9:
|
||||
resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==}
|
||||
dependencies:
|
||||
sourcemap-codec: 1.4.8
|
||||
dev: true
|
||||
|
||||
/make-dir@2.1.0:
|
||||
resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==}
|
||||
engines: {node: '>=6'}
|
||||
|
@ -14106,6 +14230,12 @@ packages:
|
|||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/mime@3.0.0:
|
||||
resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/mimic-fn@2.1.0:
|
||||
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
|
||||
engines: {node: '>=6'}
|
||||
|
@ -14130,6 +14260,28 @@ packages:
|
|||
hasBin: true
|
||||
dev: false
|
||||
|
||||
/miniflare@3.20230918.0:
|
||||
resolution: {integrity: sha512-Dd29HB7ZlT1CXB2tPH8nW6fBOOXi/m7qFZHjKm2jGS+1OaGfrv0PkT5UspWW5jQi8rWI87xtordAUiIJkwWqRw==}
|
||||
engines: {node: '>=16.13'}
|
||||
dependencies:
|
||||
acorn: 8.10.0
|
||||
acorn-walk: 8.2.0
|
||||
capnp-ts: 0.7.0
|
||||
exit-hook: 2.2.1
|
||||
glob-to-regexp: 0.4.1
|
||||
source-map-support: 0.5.21
|
||||
stoppable: 1.1.0
|
||||
undici: 5.23.0
|
||||
workerd: 1.20230904.0
|
||||
ws: 8.13.0
|
||||
youch: 3.3.2
|
||||
zod: 3.21.4
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
dev: true
|
||||
|
||||
/minimalistic-assert@1.0.1:
|
||||
resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==}
|
||||
dev: true
|
||||
|
@ -14234,7 +14386,6 @@ packages:
|
|||
/mustache@4.2.0:
|
||||
resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==}
|
||||
hasBin: true
|
||||
dev: false
|
||||
|
||||
/mute-stream@0.0.8:
|
||||
resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==}
|
||||
|
@ -14558,6 +14709,11 @@ packages:
|
|||
dependencies:
|
||||
whatwg-url: 5.0.0
|
||||
|
||||
/node-forge@1.3.1:
|
||||
resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==}
|
||||
engines: {node: '>= 6.13.0'}
|
||||
dev: true
|
||||
|
||||
/node-int64@0.4.0:
|
||||
resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==}
|
||||
dev: true
|
||||
|
@ -15200,6 +15356,10 @@ packages:
|
|||
resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==}
|
||||
dev: true
|
||||
|
||||
/path-to-regexp@6.2.1:
|
||||
resolution: {integrity: sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==}
|
||||
dev: true
|
||||
|
||||
/path-type@4.0.0:
|
||||
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -15516,6 +15676,10 @@ packages:
|
|||
engines: {node: '>= 0.8'}
|
||||
dev: true
|
||||
|
||||
/printable-characters@1.0.42:
|
||||
resolution: {integrity: sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==}
|
||||
dev: true
|
||||
|
||||
/process-nextick-args@2.0.1:
|
||||
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
|
||||
dev: true
|
||||
|
@ -16179,6 +16343,27 @@ packages:
|
|||
inherits: 2.0.4
|
||||
dev: true
|
||||
|
||||
/rollup-plugin-inject@3.0.2:
|
||||
resolution: {integrity: sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==}
|
||||
deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject.
|
||||
dependencies:
|
||||
estree-walker: 0.6.1
|
||||
magic-string: 0.25.9
|
||||
rollup-pluginutils: 2.8.2
|
||||
dev: true
|
||||
|
||||
/rollup-plugin-node-polyfills@0.2.1:
|
||||
resolution: {integrity: sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==}
|
||||
dependencies:
|
||||
rollup-plugin-inject: 3.0.2
|
||||
dev: true
|
||||
|
||||
/rollup-pluginutils@2.8.2:
|
||||
resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==}
|
||||
dependencies:
|
||||
estree-walker: 0.6.1
|
||||
dev: true
|
||||
|
||||
/run-async@2.4.1:
|
||||
resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==}
|
||||
engines: {node: '>=0.12.0'}
|
||||
|
@ -16304,6 +16489,13 @@ packages:
|
|||
resolution: {integrity: sha512-MuCAyrGZcTLfQoH2XoBlQ8C6bzwN88XT/0slOGz0pn8+gIP85BOAfYa44ZXQUTOwRwPU0QvgU+V+OSajl/59Xg==}
|
||||
dev: true
|
||||
|
||||
/selfsigned@2.1.1:
|
||||
resolution: {integrity: sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
node-forge: 1.3.1
|
||||
dev: true
|
||||
|
||||
/semver@5.7.2:
|
||||
resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==}
|
||||
hasBin: true
|
||||
|
@ -16626,6 +16818,11 @@ packages:
|
|||
engines: {node: '>= 8'}
|
||||
dev: true
|
||||
|
||||
/sourcemap-codec@1.4.8:
|
||||
resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==}
|
||||
deprecated: Please use @jridgewell/sourcemap-codec instead
|
||||
dev: true
|
||||
|
||||
/space-separated-tokens@1.1.5:
|
||||
resolution: {integrity: sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==}
|
||||
dev: true
|
||||
|
@ -16674,6 +16871,13 @@ packages:
|
|||
resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==}
|
||||
dev: true
|
||||
|
||||
/stacktracey@2.1.8:
|
||||
resolution: {integrity: sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==}
|
||||
dependencies:
|
||||
as-table: 1.0.55
|
||||
get-source: 2.0.12
|
||||
dev: true
|
||||
|
||||
/statuses@1.4.0:
|
||||
resolution: {integrity: sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
@ -16691,6 +16895,11 @@ packages:
|
|||
internal-slot: 1.0.5
|
||||
dev: true
|
||||
|
||||
/stoppable@1.1.0:
|
||||
resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==}
|
||||
engines: {node: '>=4', npm: '>=6'}
|
||||
dev: true
|
||||
|
||||
/store2@2.14.2:
|
||||
resolution: {integrity: sha512-siT1RiqlfQnGqgT/YzXVUNsom9S0H1OX+dpdGN1xkyYATo4I6sep5NmsRD/40s3IIOvlCq6akxkqG82urIZW1w==}
|
||||
dev: true
|
||||
|
@ -17677,7 +17886,6 @@ packages:
|
|||
engines: {node: '>=14.0'}
|
||||
dependencies:
|
||||
busboy: 1.6.0
|
||||
dev: false
|
||||
|
||||
/unfetch@4.2.0:
|
||||
resolution: {integrity: sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==}
|
||||
|
@ -18121,6 +18329,45 @@ packages:
|
|||
resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==}
|
||||
dev: true
|
||||
|
||||
/workerd@1.20230904.0:
|
||||
resolution: {integrity: sha512-t9znszH0rQGK4mJGvF9L3nN0qKEaObAGx0JkywFtAwH8OkSn+YfQbHNZE+YsJ4qa1hOz1DCNEk08UDFRBaYq4g==}
|
||||
engines: {node: '>=16'}
|
||||
hasBin: true
|
||||
requiresBuild: true
|
||||
optionalDependencies:
|
||||
'@cloudflare/workerd-darwin-64': 1.20230904.0
|
||||
'@cloudflare/workerd-darwin-arm64': 1.20230904.0
|
||||
'@cloudflare/workerd-linux-64': 1.20230904.0
|
||||
'@cloudflare/workerd-linux-arm64': 1.20230904.0
|
||||
'@cloudflare/workerd-windows-64': 1.20230904.0
|
||||
dev: true
|
||||
|
||||
/wrangler@3.9.0:
|
||||
resolution: {integrity: sha512-Ho1A76KxbqfcRgCsuN6xGar3BVPyn4oVWM9zx0HvEVhT9wQ7n/LvB6GlPdXKABqEBYhVe/oTH72S5TgWl0DgaA==}
|
||||
engines: {node: '>=16.13.0'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
'@cloudflare/kv-asset-handler': 0.2.0
|
||||
'@esbuild-plugins/node-globals-polyfill': 0.2.3(esbuild@0.17.19)
|
||||
'@esbuild-plugins/node-modules-polyfill': 0.2.2(esbuild@0.17.19)
|
||||
blake3-wasm: 2.1.5
|
||||
chokidar: 3.5.3
|
||||
esbuild: 0.17.19
|
||||
miniflare: 3.20230918.0
|
||||
nanoid: 3.3.6
|
||||
path-to-regexp: 6.2.1
|
||||
selfsigned: 2.1.1
|
||||
source-map: 0.6.1
|
||||
source-map-support: 0.5.21
|
||||
xxhash-wasm: 1.0.2
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
dev: true
|
||||
|
||||
/wrap-ansi@4.0.0:
|
||||
resolution: {integrity: sha512-uMTsj9rDb0/7kk1PbcbCcwvHUxp60fGDB/NNXpVa0Q+ic/e7y5+BwTxKfQ33VYgDppSwi/FBzpetYzo8s6tfbg==}
|
||||
engines: {node: '>=6'}
|
||||
|
@ -18259,6 +18506,10 @@ packages:
|
|||
engines: {node: '>=0.4'}
|
||||
dev: true
|
||||
|
||||
/xxhash-wasm@1.0.2:
|
||||
resolution: {integrity: sha512-ibF0Or+FivM9lNrg+HGJfVX8WJqgo+kCLDc4vx6xMeTce7Aj+DLttKbxxRR/gNLSAelRc1omAPlJ77N/Jem07A==}
|
||||
dev: true
|
||||
|
||||
/y18n@4.0.3:
|
||||
resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
|
||||
dev: true
|
||||
|
@ -18374,5 +18625,13 @@ packages:
|
|||
engines: {node: '>=12.20'}
|
||||
dev: true
|
||||
|
||||
/youch@3.3.2:
|
||||
resolution: {integrity: sha512-9cwz/z7abtcHOIuH45nzmUFCZbyJA1nLqlirKvyNRx4wDMhqsBaifAJzBej7L4fsVPjFxYq3NK3GAcfvZsydFw==}
|
||||
dependencies:
|
||||
cookie: 0.5.0
|
||||
mustache: 4.2.0
|
||||
stacktracey: 2.1.8
|
||||
dev: true
|
||||
|
||||
/zod@3.21.4:
|
||||
resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==}
|
||||
|
|
Loading…
Reference in New Issue