Add consent-gated media exchange library
This commit is contained in:
1 parent
b8e4a1bb88
commit
bf474dfe10
42 files changed
+2533
-9
No files matched your search
@@ -32,3 +32,35 @@ export const MediaSyncTriggerResponseSchema = z.union([
|
||||
|
||||
export type MediaItem = z.infer<typeof MediaItemSchema>;
|
||||
export type MediaSyncStatus = z.infer<typeof MediaSyncStatusSchema>;
|
||||
|
||||
export const MediaLibraryTagSchema = z.enum(['penis', 'chest', 'selfie', 'topless', 'feet']);
|
||||
export const MediaLibraryAssetSchema = z.strictObject({
|
||||
id: z.string().uuid(),
|
||||
tags: z.array(MediaLibraryTagSchema),
|
||||
safety: z.enum(['sfw', 'nsfw', 'unknown']),
|
||||
classificationStatus: z.enum(['ready', 'failed']),
|
||||
description: z.string().nullable(),
|
||||
confidence: z.number().min(0).max(1).nullable(),
|
||||
fileName: z.string(),
|
||||
mimeType: z.enum(['image/jpeg', 'image/png', 'image/webp']),
|
||||
sizeBytes: z.number().int().nonnegative(),
|
||||
width: z.number().int().positive(),
|
||||
height: z.number().int().positive(),
|
||||
enabled: z.boolean(),
|
||||
consentConfirmedAt: z.number(),
|
||||
createdAt: z.number(),
|
||||
updatedAt: z.number(),
|
||||
sendCount: z.number().int().nonnegative(),
|
||||
lastSentAt: z.number().nullable(),
|
||||
urlPath: z.string(),
|
||||
});
|
||||
export const MediaLibraryResponseSchema = z.array(MediaLibraryAssetSchema);
|
||||
export const MediaLibraryUpdateSchema = z.strictObject({
|
||||
tags: z.array(MediaLibraryTagSchema).min(1),
|
||||
safety: z.enum(['sfw', 'nsfw']),
|
||||
enabled: z.boolean(),
|
||||
});
|
||||
|
||||
export type MediaLibraryTag = z.infer<typeof MediaLibraryTagSchema>;
|
||||
export type MediaLibraryAsset = z.infer<typeof MediaLibraryAssetSchema>;
|
||||
export type MediaLibraryUpdate = z.infer<typeof MediaLibraryUpdateSchema>;
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
LoginStatusResponseSchema,
|
||||
LegacyDashboardStreamEventSchema,
|
||||
MediaResponseSchema,
|
||||
MediaLibraryAssetSchema,
|
||||
MediaSyncStatusSchema,
|
||||
MessagesResponseSchema,
|
||||
ProcessedPostsResponseSchema,
|
||||
@@ -215,6 +216,18 @@ describe('dashboard endpoint contracts', () => {
|
||||
expect(MediaResponseSchema.safeParse([{ id: 'sha1', timestamp: 'now' }]).success).toBe(false);
|
||||
});
|
||||
|
||||
it('validates exchange-library classifications without exposing local paths', () => {
|
||||
const payload = {
|
||||
id: '019fe789-1b99-7ce1-8402-b3cbc32a445a', tags: ['selfie', 'topless'], safety: 'nsfw',
|
||||
classificationStatus: 'ready', description: 'A self portrait', confidence: 0.9,
|
||||
fileName: 'portrait.jpg', mimeType: 'image/jpeg', sizeBytes: 100, width: 10, height: 20,
|
||||
enabled: true, consentConfirmedAt: 1, createdAt: 1, updatedAt: 1, sendCount: 0, lastSentAt: null,
|
||||
urlPath: '/library-media/id.jpg',
|
||||
};
|
||||
expect(MediaLibraryAssetSchema.safeParse(payload).success).toBe(true);
|
||||
expect(MediaLibraryAssetSchema.safeParse({ ...payload, relativePath: 'private/id.jpg' }).success).toBe(false);
|
||||
});
|
||||
|
||||
it('validates every current login-status branch', () => {
|
||||
expect(LoginStatusResponseSchema.safeParse({
|
||||
ready: true, loggedIn: true, status: 'authenticated',
|
||||
|
||||
Reference in new issue
Block a user