Signal-Desktop/ts/types/AttachmentBackup.ts

133 lines
3.2 KiB
TypeScript

// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { z } from 'zod';
import {
type JobManagerJobType,
jobManagerJobSchema,
} from '../jobs/JobManager';
import { type MIMEType, MIMETypeSchema } from './MIME';
export type CoreAttachmentBackupJobType =
| StandardAttachmentBackupJobType
| ThumbnailAttachmentBackupJobType;
export type StandardAttachmentBackupJobType = {
type: 'standard';
mediaName: string;
receivedAt: number;
data: {
path: string | null;
contentType: MIMEType;
keys: string;
transitCdnInfo?: {
cdnKey: string;
cdnNumber: number;
uploadTimestamp?: number;
};
size: number;
version?: 1 | 2;
localKey?: string;
};
};
export type ThumbnailAttachmentBackupJobType = {
type: 'thumbnail';
mediaName: `${string}_thumbnail`;
receivedAt: number;
data: {
fullsizePath: string | null;
fullsizeSize: number;
contentType: MIMEType;
version?: 1 | 2;
localKey?: string;
};
};
export type CoreAttachmentLocalBackupJobType = {
type: 'local';
mediaName: string;
data: {
path: string | null;
size: number;
localKey: string;
};
backupsBaseDir: string;
};
export type PartialAttachmentLocalBackupJobType = Omit<
CoreAttachmentLocalBackupJobType,
'backupsBaseDir'
>;
export type AttachmentLocalBackupJobType = CoreAttachmentLocalBackupJobType &
JobManagerJobType;
const standardBackupJobDataSchema = z.object({
type: z.literal('standard'),
mediaName: z.string(),
data: z.object({
path: z.string(),
size: z.number(),
contentType: MIMETypeSchema,
keys: z.string(),
transitCdnInfo: z
.object({
cdnKey: z.string(),
cdnNumber: z.number(),
uploadTimestamp: z.number().optional(),
})
.optional(),
version: z.union([z.literal(1), z.literal(2)]).optional(),
localKey: z.string().optional(),
}),
});
const thumbnailMediaNameSchema = z
.string()
.refine((mediaName: string): mediaName is `${string}_thumbnail` => {
return mediaName.endsWith('_thumbnail');
});
const thumbnailBackupJobDataSchema = z.object({
type: z.literal('thumbnail'),
mediaName: thumbnailMediaNameSchema,
data: z.object({
fullsizePath: z.string(),
fullsizeSize: z.number(),
contentType: MIMETypeSchema,
version: z.union([z.literal(1), z.literal(2)]).optional(),
localKey: z.string().optional(),
}),
});
export const attachmentBackupJobSchema = z
.object({
receivedAt: z.number(),
})
.and(
z.discriminatedUnion('type', [
standardBackupJobDataSchema,
thumbnailBackupJobDataSchema,
])
)
.and(jobManagerJobSchema) satisfies z.ZodType<
AttachmentBackupJobType,
z.ZodTypeDef,
// With branded types, we need to specify that the input type of the schema is just a
// string
Omit<AttachmentBackupJobType, 'data'> & {
data: Omit<AttachmentBackupJobType['data'], 'contentType'> & {
contentType: string;
};
}
>;
export const thumbnailBackupJobRecordSchema = z.object({
mediaName: thumbnailMediaNameSchema,
type: z.literal('standard'),
json: thumbnailBackupJobDataSchema.omit({ type: true }),
});
export type AttachmentBackupJobType = CoreAttachmentBackupJobType &
JobManagerJobType;