diff --git a/src/server/package.json b/src/server/package.json
index 029943484..8cc08cae6 100644
--- a/src/server/package.json
+++ b/src/server/package.json
@@ -58,6 +58,7 @@
"sentiment": "^5.0.2",
"sequelize": "^6.29.0",
"sequelize-typescript": "^2.1.5",
+ "sharp": "^0.32.6",
"swagger-ui-express": "^4.6.2",
"tsoa": "^5.1.1",
"user-agents": "^1.0.1307",
diff --git a/src/server/src/api/v1/schema/user/Membership.model.ts b/src/server/src/api/v1/schema/user/Membership.model.ts
deleted file mode 100644
index 11e934dc9..000000000
--- a/src/server/src/api/v1/schema/user/Membership.model.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-import {
- Column,
- DataType,
- Table,
-} from 'sequelize-typescript';
-
-import { MembershipAttributes, MembershipCreationAttributes } from './Membership.types';
-import { BaseModel } from '../base';
-
-@Table({
- modelName: 'membership',
- paranoid: true,
- timestamps: true,
-})
-export class Membership
- extends BaseModel
- implements MembershipAttributes {
-
- @Column({
- allowNull: false,
- type: DataType.NUMBER,
- })
- declare userId: number;
-
- @Column({
- allowNull: false,
- type: DataType.DATE,
- })
- declare renewsOn: Date;
-
- @Column({
- allowNull: false,
- type: DataType.NUMBER,
- })
- declare tier: number;
-
- @Column({
- allowNull: false,
- type: DataType.STRING,
- })
- declare platform: string;
-
- @Column({
- allowNull: false,
- type: DataType.STRING,
- })
- declare platformUUID: string;
-
-}
diff --git a/src/server/src/api/v1/schema/user/Membership.types.ts b/src/server/src/api/v1/schema/user/Membership.types.ts
deleted file mode 100644
index 121cd698c..000000000
--- a/src/server/src/api/v1/schema/user/Membership.types.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-
-import { DatedAttributes } from '../types';
-
-export type MembershipAttributes = DatedAttributes & {
- userId: number;
- renewsOn: Date;
- tier: number;
- platform: string;
- platformUUID: string;
-};
-
-export type MembershipCreationAttributes = {
- userId: number;
- renewsOn: Date;
- tier: number;
- platform: string;
- platformUUID: string;
-};
\ No newline at end of file
diff --git a/src/server/src/services/aws/s3/S3Service.ts b/src/server/src/services/aws/s3/S3Service.ts
index 537e2d079..c3bf42753 100644
--- a/src/server/src/services/aws/s3/S3Service.ts
+++ b/src/server/src/services/aws/s3/S3Service.ts
@@ -3,10 +3,16 @@ import p from 'path';
import { Readable } from 'stream';
import {
+ DeleteObjectCommand,
+ DeleteObjectCommandInput,
GetObjectCommand,
GetObjectCommandInput,
+ ListObjectsV2Command,
+ ListObjectsV2CommandInput,
PutObjectCommand,
PutObjectCommandInput,
+ RestoreObjectCommand,
+ RestoreObjectCommandInput,
S3Client,
} from '@aws-sdk/client-s3';
import axios from 'axios';
@@ -28,6 +34,11 @@ export type GetOptions = Omit & {
Provider?: string;
};
+export type ListOptions = Omit & {
+ Bucket?: string;
+ Provider?: string;
+};
+
export type PutOptions = Omit & {
Bucket?: string;
Body?: string;
@@ -40,6 +51,17 @@ export type PutOptions = Omit & {
+ Bucket?: string;
+ Provider?: string;
+ Folder?: string;
+};
+
+export type RestoreOptions = Omit & {
+ Bucket?: string;
+ Provider?: string;
+};
+
export class S3Service extends BaseService {
public static s3Client = new S3Client({
@@ -104,6 +126,7 @@ export class S3Service extends BaseService {
if (!filepath) {
filepath = `/tmp/${filename}`;
}
+ console.log('Downloaded', filepath);
return new Promise((resolve, reject) => {
response.data.pipe(fs.createWriteStream(filepath))
.on('error', reject)
@@ -124,6 +147,7 @@ export class S3Service extends BaseService {
throw new Error('Malformed key');
}
const response = await this.s3Client.send(new GetObjectCommand(params));
+ filepath = `${filepath}.${mime.extension(response.ContentType) || mime.extension(mime.lookup(response.ContentType) || '')}`;
const stream = response.Body as Readable;
return new Promise((resolve, reject) => {
stream.pipe(fs.createWriteStream(filepath))
@@ -131,6 +155,30 @@ export class S3Service extends BaseService {
.once('close', () => resolve(filepath));
});
}
+
+ public static async listObjects(options: ListOptions = {}) {
+ const params = {
+ ...options,
+ Bucket: options.Bucket || process.env.S3_BUCKET,
+ MaxKeys: options.MaxKeys,
+ Provider: options.Provider || process.env.S3_PROVIDER || 'nyc3.digitaloceanspaces.com',
+ };
+ if (!params.Bucket) {
+ throw new Error('Malformed bucket');
+ }
+ let isTruncated = true;
+ const items: string[] = [];
+ const command = new ListObjectsV2Command(params);
+ while (isTruncated) {
+ const {
+ Contents, IsTruncated, NextContinuationToken,
+ } = await this.s3Client.send(command);
+ items.push(...Contents.map((c) => c.Key));
+ isTruncated = IsTruncated;
+ command.input.ContinuationToken = NextContinuationToken;
+ }
+ return items;
+ }
public static async putObject(options: PutOptions) {
const params = {
@@ -159,6 +207,30 @@ export class S3Service extends BaseService {
};
}
+ public static async deleteObject(options: DeleteOptions) {
+ const params = {
+ ...options,
+ Bucket: options.Bucket || process.env.S3_BUCKET,
+ Key: options.Folder ? [options.Folder, options.Key].join('/') : options.Key,
+ Provider: options.Provider || process.env.S3_PROVIDER || 'nyc3.digitaloceanspaces.com',
+ };
+ const data = await this.s3Client.send(new DeleteObjectCommand(params));
+ return data;
+ }
+
+ public static async restoreObject(options: RestoreOptions) {
+ const params = {
+ ...options,
+ Bucket: options.Bucket || process.env.S3_BUCKET,
+ Provider: options.Provider || process.env.S3_PROVIDER || 'nyc3.digitaloceanspaces.com',
+ };
+ if (!params.Bucket) {
+ throw new Error('Malformed bucket');
+ }
+ const data = await this.s3Client.send(new RestoreObjectCommand(params));
+ return data;
+ }
+
public static async mirror(url: string, options: PutOptions) {
try {
const file = await this.download(url, {
diff --git a/src/server/src/worker/MediaWorker.ts b/src/server/src/worker/MediaWorker.ts
new file mode 100644
index 000000000..61013712b
--- /dev/null
+++ b/src/server/src/worker/MediaWorker.ts
@@ -0,0 +1,137 @@
+import fs from 'fs';
+
+import sharp from 'sharp';
+
+import { SummaryMedia } from '../api/v1/schema/models';
+import { SummaryMediaAttributes } from '../api/v1/schema/types';
+import { DBService, S3Service } from '../services';
+
+export async function main() {
+ await DBService.prepare();
+ doWork();
+}
+
+class Size {
+
+ name: string;
+ value: number;
+
+ static xs = new Size('xs', 60);
+ static sm = new Size('sm', 120);
+ static md = new Size('md', 240);
+ static lg = new Size('lg', 360);
+ static xl = new Size('xl', 480);
+ static xxl = new Size('xxl', 720);
+ static xxxl = new Size('xxxl', 1920);
+
+ constructor(name: string, value: number) {
+ this.name = name;
+ this.value = value;
+ }
+
+}
+
+type DownsampleOptions = Pick & {
+ sizes?: Size[];
+};
+
+async function downsampleImage({
+ key,
+ parentId,
+ path,
+ sizes = [Size.xs, Size.sm, Size.md, Size.lg],
+}: DownsampleOptions, folder: string) {
+ // eslint-disable-next-line no-async-promise-executor
+ return new Promise(async (resolve, reject) => {
+ const file = await S3Service.getObject({ Key: path });
+ if (!file) {
+ reject('Missing file');
+ return;
+ }
+ const results: SummaryMedia[] = [];
+ for (const [index, size] of sizes.entries()) {
+ const subkey = `${key}@${size.name}`;
+ const media = await SummaryMedia.findOne({
+ where: {
+ key: subkey,
+ parentId,
+ },
+ });
+ if (media) {
+ console.log('media already exists');
+ results.push(media);
+ if (index + 1 === sizes.length) {
+ resolve(results);
+ return;
+ }
+ continue;
+ }
+ const target = file.replace(/(\.\w+)$/, (_, $1) => `@${size.name}${$1}`);
+ sharp(file)
+ .resize(size.value)
+ .jpeg()
+ .toFile(target, async (err) => {
+ if (err) {
+ reject(err);
+ return;
+ }
+ const response = await S3Service.putObject({
+ ACL: 'public-read',
+ Accept: 'image',
+ File: target,
+ Folder: folder,
+ });
+ const media = await SummaryMedia.create({
+ key: subkey,
+ parentId,
+ path: response.key,
+ type: 'image',
+ url: response.url,
+ });
+ try {
+ fs.unlinkSync(file);
+ } catch (e) {
+ console.error(e);
+ }
+ try {
+ fs.unlinkSync(target);
+ } catch (e) {
+ console.error(e);
+ }
+ results.push(media);
+ if (index + 1 === sizes.length) {
+ resolve(results);
+ }
+ });
+ }
+ });
+}
+
+export async function doWork() {
+ console.log('fetching objects');
+ try {
+ const items = await S3Service.listObjects();
+ console.log(items.length);
+ for (const item of items) {
+ if (/^img\/s/.test(item)) {
+ const media = await SummaryMedia.findOne({ where: { path: item } });
+ if (!media) {
+ console.log('Unlinking dangling media', item);
+ await S3Service.deleteObject({ Key: item });
+ }
+ if (!/@(?:xs|sm|md|lg|x+l)\.\w+$/.test(item)) {
+ console.log('Downsampling', item);
+ const folders = item.split('/');
+ folders.pop();
+ await downsampleImage(media, folders.join('/'));
+ }
+ }
+ }
+ } catch (e) {
+ console.error(e);
+ } finally {
+ setTimeout(doWork, 3_000);
+ }
+}
+
+main();
\ No newline at end of file
diff --git a/src/server/src/worker/index.ts b/src/server/src/worker/index.ts
index c05767ee8..1f5a6c925 100644
--- a/src/server/src/worker/index.ts
+++ b/src/server/src/worker/index.ts
@@ -6,6 +6,9 @@ export async function main() {
case 'topics':
await import('./TopicWorker');
break;
+ case 'media':
+ await import('./MediaWorker');
+ break;
case 'notifs':
await import('./NotificationsWorker');
break;
diff --git a/src/server/tests/s3.test.ts b/src/server/tests/s3.test.ts
index 3cf7b8090..50cc6b002 100644
--- a/src/server/tests/s3.test.ts
+++ b/src/server/tests/s3.test.ts
@@ -45,5 +45,11 @@ describe('uploads to the s3 bucket', () => {
console.log(response);
expect(response).toBeDefined();
});
+
+ test('list files', async () => {
+ const response = await S3Service.listObjects();
+ console.log(response);
+ expect(response).toBeDefined();
+ });
});
\ No newline at end of file
diff --git a/src/server/yarn.lock b/src/server/yarn.lock
index 8a51cfe23..23f61c5a9 100644
--- a/src/server/yarn.lock
+++ b/src/server/yarn.lock
@@ -3008,6 +3008,11 @@ axios@^1.3.4:
form-data "^4.0.0"
proxy-from-env "^1.1.0"
+b4a@^1.6.4:
+ version "1.6.4"
+ resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.4.tgz#ef1c1422cae5ce6535ec191baeed7567443f36c9"
+ integrity sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==
+
babel-jest@^29.5.0:
version "29.5.0"
resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.5.0.tgz#3fe3ddb109198e78b1c88f9ebdecd5e4fc2f50a5"
@@ -3648,7 +3653,7 @@ color-name@^1.0.0, color-name@~1.1.4:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
-color-string@^1.6.0:
+color-string@^1.6.0, color-string@^1.9.0:
version "1.9.1"
resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4"
integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==
@@ -3664,6 +3669,14 @@ color@^3.1.3:
color-convert "^1.9.3"
color-string "^1.6.0"
+color@^4.2.3:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/color/-/color-4.2.3.tgz#d781ecb5e57224ee43ea9627560107c0e0c6463a"
+ integrity sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==
+ dependencies:
+ color-convert "^2.0.1"
+ color-string "^1.9.0"
+
colors@1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
@@ -3928,6 +3941,11 @@ dedent@^0.7.0:
resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c"
integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==
+deep-extend@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
+ integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
+
deep-is@~0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
@@ -3993,6 +4011,11 @@ detect-indent@~6.0.0:
resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.0.0.tgz#0abd0f549f69fc6659a254fe96786186b6f528fd"
integrity sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA==
+detect-libc@^2.0.0, detect-libc@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.2.tgz#8ccf2ba9315350e1241b88d0ac3b0e1fbd99605d"
+ integrity sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==
+
detect-newline@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651"
@@ -4544,6 +4567,11 @@ expand-brackets@^2.1.4:
snapdragon "^0.8.1"
to-regex "^3.0.1"
+expand-template@^2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c"
+ integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==
+
expect@^29.0.0, expect@^29.5.0:
version "29.5.0"
resolved "https://registry.yarnpkg.com/expect/-/expect-29.5.0.tgz#68c0509156cb2a0adb8865d413b137eeaae682f7"
@@ -4675,6 +4703,11 @@ fast-deep-equal@^3.1.1:
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
+fast-fifo@^1.1.0, fast-fifo@^1.2.0:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c"
+ integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==
+
fast-glob@^2.2.6:
version "2.2.7"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d"
@@ -5045,6 +5078,11 @@ getpass@^0.1.1:
dependencies:
assert-plus "^1.0.0"
+github-from-package@0.0.0:
+ version "0.0.0"
+ resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce"
+ integrity sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==
+
glob-parent@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
@@ -5597,6 +5635,11 @@ inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4:
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+ini@~1.3.0:
+ version "1.3.8"
+ resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
+ integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
+
internal-slot@^1.0.4, internal-slot@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986"
@@ -6932,7 +6975,7 @@ minimatch@^5.0.1, minimatch@^5.1.0:
dependencies:
brace-expansion "^2.0.1"
-minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6:
+minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6:
version "1.2.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
@@ -6965,7 +7008,7 @@ mixin-deep@^1.2.0:
for-in "^1.0.2"
is-extendable "^1.0.1"
-mkdirp-classic@^0.5.2:
+mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3:
version "0.5.3"
resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113"
integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==
@@ -7102,6 +7145,11 @@ nanomatch@^1.2.9:
snapdragon "^0.8.1"
to-regex "^3.0.1"
+napi-build-utils@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806"
+ integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==
+
natural-compare@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
@@ -7130,11 +7178,23 @@ no-case@^3.0.4:
lower-case "^2.0.2"
tslib "^2.0.3"
+node-abi@^3.3.0:
+ version "3.50.0"
+ resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.50.0.tgz#bbee6943c8812d20e241539854d7b8003404d917"
+ integrity sha512-2Gxu7Eq7vnBIRfYSmqPruEllMM14FjOQFJSoqdGWthVn+tmwEXzmdPpya6cvvwf0uZA3F5N1fMFr9mijZBplFA==
+ dependencies:
+ semver "^7.3.5"
+
node-addon-api@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32"
integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==
+node-addon-api@^6.1.0:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-6.1.0.tgz#ac8470034e58e67d0c6f1204a18ae6995d9c0d76"
+ integrity sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==
+
node-fetch@2.6.7:
version "2.6.7"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
@@ -7641,6 +7701,24 @@ postgres-interval@^1.1.0:
dependencies:
xtend "^4.0.0"
+prebuild-install@^7.1.1:
+ version "7.1.1"
+ resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.1.tgz#de97d5b34a70a0c81334fd24641f2a1702352e45"
+ integrity sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==
+ dependencies:
+ detect-libc "^2.0.0"
+ expand-template "^2.0.3"
+ github-from-package "0.0.0"
+ minimist "^1.2.3"
+ mkdirp-classic "^0.5.3"
+ napi-build-utils "^1.0.1"
+ node-abi "^3.3.0"
+ pump "^3.0.0"
+ rc "^1.2.7"
+ simple-get "^4.0.0"
+ tar-fs "^2.0.0"
+ tunnel-agent "^0.6.0"
+
prelude-ls@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
@@ -7863,6 +7941,11 @@ querystring@0.2.0:
resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
integrity sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==
+queue-tick@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/queue-tick/-/queue-tick-1.0.1.tgz#f6f07ac82c1fd60f82e098b417a80e52f1f4c142"
+ integrity sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==
+
quick-lru@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
@@ -7900,6 +7983,16 @@ raw-body@2.5.2:
iconv-lite "0.4.24"
unpipe "1.0.0"
+rc@^1.2.7:
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
+ integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
+ dependencies:
+ deep-extend "^0.6.0"
+ ini "~1.3.0"
+ minimist "^1.2.0"
+ strip-json-comments "~2.0.1"
+
react-is@^18.0.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
@@ -8173,6 +8266,13 @@ semver@^7.1.2:
dependencies:
lru-cache "^6.0.0"
+semver@^7.5.4:
+ version "7.5.4"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
+ integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
+ dependencies:
+ lru-cache "^6.0.0"
+
semver@~7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
@@ -8294,6 +8394,20 @@ sha.js@^2.4.0, sha.js@^2.4.8:
inherits "^2.0.1"
safe-buffer "^5.0.1"
+sharp@^0.32.6:
+ version "0.32.6"
+ resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.32.6.tgz#6ad30c0b7cd910df65d5f355f774aa4fce45732a"
+ integrity sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==
+ dependencies:
+ color "^4.2.3"
+ detect-libc "^2.0.2"
+ node-addon-api "^6.1.0"
+ prebuild-install "^7.1.1"
+ semver "^7.5.4"
+ simple-get "^4.0.1"
+ tar-fs "^3.0.4"
+ tunnel-agent "^0.6.0"
+
shebang-command@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
@@ -8334,6 +8448,15 @@ simple-get@^2.7.0:
once "^1.3.1"
simple-concat "^1.0.0"
+simple-get@^4.0.0, simple-get@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-4.0.1.tgz#4a39db549287c979d352112fa03fd99fd6bc3543"
+ integrity sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==
+ dependencies:
+ decompress-response "^6.0.0"
+ once "^1.3.1"
+ simple-concat "^1.0.0"
+
simple-swizzle@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
@@ -8520,6 +8643,14 @@ streamroller@^3.1.3:
debug "^4.3.4"
fs-extra "^8.1.0"
+streamx@^2.15.0:
+ version "2.15.1"
+ resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.15.1.tgz#396ad286d8bc3eeef8f5cea3f029e81237c024c6"
+ integrity sha512-fQMzy2O/Q47rgwErk/eGeLu/roaFWV0jVsogDmrszM9uIw8L5OA+t+V93MgYlufNptfjmYR1tOMWhei/Eh7TQA==
+ dependencies:
+ fast-fifo "^1.1.0"
+ queue-tick "^1.0.1"
+
strict-uri-encode@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
@@ -8610,6 +8741,11 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
+strip-json-comments@~2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+ integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==
+
strnum@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db"
@@ -8675,7 +8811,7 @@ swarm-js@^0.1.40:
tar "^4.0.2"
xhr-request "^1.0.1"
-tar-fs@2.1.1:
+tar-fs@2.1.1, tar-fs@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784"
integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==
@@ -8685,6 +8821,15 @@ tar-fs@2.1.1:
pump "^3.0.0"
tar-stream "^2.1.4"
+tar-fs@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-3.0.4.tgz#a21dc60a2d5d9f55e0089ccd78124f1d3771dbbf"
+ integrity sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==
+ dependencies:
+ mkdirp-classic "^0.5.2"
+ pump "^3.0.0"
+ tar-stream "^3.1.5"
+
tar-stream@^2.1.4:
version "2.2.0"
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287"
@@ -8696,6 +8841,15 @@ tar-stream@^2.1.4:
inherits "^2.0.3"
readable-stream "^3.1.1"
+tar-stream@^3.1.5:
+ version "3.1.6"
+ resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-3.1.6.tgz#6520607b55a06f4a2e2e04db360ba7d338cc5bab"
+ integrity sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==
+ dependencies:
+ b4a "^1.6.4"
+ fast-fifo "^1.2.0"
+ streamx "^2.15.0"
+
tar@^4.0.2:
version "4.4.19"
resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.19.tgz#2e4d7263df26f2b914dee10c825ab132123742f3"