chore: added log-elements schema

This commit is contained in:
Mattia Belletti
2025-07-07 11:43:37 +02:00
parent ab0eb4a195
commit 824166b717
3 changed files with 239 additions and 1 deletions

View File

@@ -0,0 +1,217 @@
import { Z } from "./types";
export function exportGetV1Schema(z: Z) {
const PostLogElementsMetadataNoOpenApiSchema = z
.record(z.string(), z.string().optional())
.optional();
/// common elements
const PostLogElementsMetadataSchema =
PostLogElementsMetadataNoOpenApiSchema.openapi({
title: "Metadata",
description:
"Optional metadata to provide extra information about this object",
});
/// session start
const PostLogElementsUserSchema = z.object({
platform: z.string().openapi({
title: "Platform",
description: "Name of the platform of this user",
example: "Steam",
}),
id: z.string().openapi({
title: "Id",
description: "Unique identifier for this user on the given platform",
example: "RedGlow",
}),
});
const PostLogElementsMachineSchema = z.object({
id: z.string().openapi({
title: "Id",
description:
"Unique identifier for this machine; it can be produced by hashing together a number of unique characteristics of the machine in a privacy-sensitive way",
example: "8662d7bdb037dc82a49d7579d9309397",
}),
metadata: PostLogElementsMetadataSchema,
});
const PostLogElementsGameSchema = z.object({
author: z.string().openapi({
title: "Author",
description: "The author of this game",
example: "owof games",
}),
name: z.string().openapi({
title: "Name",
description: "Name of the game",
example: "The Good Dog Show",
}),
version: z.string().openapi({
title: "Version",
description: "The version of the game",
example: "1.2.1.d352cd643ee8028826273c16af0963a4a73295b5",
}),
});
const PostLogElementsSessionStartSchema = z.object({
type: z.literal("session-start"),
id: z.string().openapi({
title: "Id",
description: "Unique id for this session",
example: "d3f53283-0e84-449c-81a0-9031b2037bfb",
}),
user: PostLogElementsUserSchema.openapi({
title: "User",
description: "User that has started this session",
}),
machine: PostLogElementsMachineSchema.openapi({
title: "Machine",
description: "Information about the machine this session started from",
}),
game: PostLogElementsGameSchema,
startTime: z.string().datetime().openapi({
title: "Start timestamp",
description: "Timestamp of the start of this session",
}),
metadata: PostLogElementsMetadataSchema,
});
/// session end
const PostLogElementsSessionEndSchema = z.object({
type: z.literal("session-end"),
id: z.string().openapi({
title: "Id",
description:
"Unique id for this session (must match the id of a start session)",
example: "d3f53283-0e84-449c-81a0-9031b2037bfb",
}),
endTime: z.string().datetime().openapi({
title: "End timestamp",
description:
"Timestamp of the end of this session (must be greater than the start time)",
}),
});
/// activity start
const PostLogElementsActivityStartSchema = z.object({
type: z.literal("activity-start"),
id: z.string().openapi({
title: "Id",
description: "Unique id for this activity",
example: "3fcfc0be-a430-4425-b033-daa2c8340d13",
}),
sessionId: z.string().openapi({
title: "Id",
description:
"Unique id for the session this activity belongs to (must be the same id of a previous session-start)",
example: "d3f53283-0e84-449c-81a0-9031b2037bfb",
}),
parentId: z.string().optional().openapi({
title: "Parent Id",
description:
"Unique id of the parent activity (an activity that contains this activity); optional",
example: "c2c62510-3b96-4be8-bad1-3acca2e559fe",
}),
saveId: z.string().optional().openapi({
title: "Save Id",
description:
"Id of the save file that is currently being used; must be unique for the user of the session this activity belongs to; optional",
example: "1442",
}),
startTime: z.string().datetime().openapi({
title: "Start timestamp",
description: "Timestamp of the start of this activity",
}),
metadata: PostLogElementsMetadataSchema,
});
/// activity end
const PostLogElementsActivityEndSchema = z.object({
type: z.literal("activity-end"),
id: z.string().openapi({
title: "Id",
description:
"Unique id for this activity (must match the id of a previous start-activity)",
example: "3fcfc0be-a430-4425-b033-daa2c8340d13",
}),
saveId: z.string().optional().openapi({
title: "Save Id",
description:
"Id of the save file that is currently being used; must be unique for the user of the session this activity belongs to; if not null, overwrites the value of the matching start-activity; optional",
example: "1442",
}),
endTime: z.string().datetime().openapi({
title: "End timestamp",
description:
"Timestamp of the end of this activity (must be greather than the startTime of the matching start-activity)",
}),
});
/// log
const PostLogElementsLogSchema = z.object({
type: z.literal("log"),
activityId: z.string().optional().openapi({
title: "Activity Id",
description:
"Id of the activity this log belongs to; can be null if it does not belong to an activity",
example: "3fcfc0be-a430-4425-b033-daa2c8340d13",
}),
sessionId: z.string().optional().openapi({
title: "Session id",
description:
"Id of the session this log belongs to; it's compulsory if activityId is missing, optional otherwise; if both are present, they must be consistent",
example: "d3f53283-0e84-449c-81a0-9031b2037bfb",
}),
level: z.number().openapi({
title: "Level",
description:
"A log level; the log levels are in range 0-599 (from least significant to most significant); they are logically mapped in blocks of 100 values at a time on the names trace, debug, information, warning, error, critical",
example: "400",
}),
category: z.string().openapi({
title: "Category",
description:
"A category for the log, used to filter them in the interface, either by full match or by prefix",
example: "UI.SaveGameView",
}),
timestamp: z.string().datetime().openapi({
title: "Timestamp",
description: "The ISO date and time at which this log was emitted",
}),
message: z.string().openapi({
title: "Log message",
description: "The message of this log",
}),
genericMetadata: PostLogElementsMetadataNoOpenApiSchema.openapi({
title: "Metadata",
description:
"Optional metadata to provide extra information about this object (e.g.: file name, line, function name)",
}),
specificMetadata: PostLogElementsMetadataNoOpenApiSchema.openapi({
title: "Metadata",
description:
"Optional metadata to provide the information used to interpolate the message line (e.g.: button name, character, item)",
}),
});
/// union and array
const PostLogElementsSchema = z
.discriminatedUnion("type", [
PostLogElementsSessionStartSchema,
PostLogElementsSessionEndSchema,
PostLogElementsActivityStartSchema,
PostLogElementsActivityEndSchema,
PostLogElementsLogSchema,
])
.array();
return { PostLogElementsSchema };
}

View File

@@ -7,6 +7,7 @@ import { exportGetSessionsSchema } from "./get-sessions";
import { exportPostLogSchema } from "./post-log";
import { exportGetEntriesSchema } from "./get-entries";
import { exportGetCategoriesSchema } from "./get-categories";
import { exportGetV1Schema } from "./get-v1-schema";
extendZodWithOpenApi(z);
@@ -27,6 +28,7 @@ const {
} = exportGetEntriesSchema(z);
const { GetCategoriesRequestQuerySchema, GetCategoriesResponseSchema } =
exportGetCategoriesSchema(z);
const { PostLogElementsSchema } = exportGetV1Schema(z);
const ErrorSchema = z.object({
code: z.number().optional().openapi({
@@ -43,6 +45,23 @@ const ErrorSchema = z.object({
const c = initContract();
const v1Contract = c.router(
{
postLogElements: {
method: "POST",
path: "/logElements",
body: PostLogElementsSchema,
responses: {
204: c.noBody(),
500: ErrorSchema,
},
},
},
{
pathPrefix: "/v1",
}
);
export const contract = c.router(
{
postLog: {
@@ -102,6 +121,7 @@ export const contract = c.router(
},
summary: "get the OpenAPI document for this API",
},
v1: v1Contract,
},
{
pathPrefix: "/api",
@@ -113,4 +133,4 @@ export const contract = c.router(
export type SingleMetadata = z.infer<typeof SingleMetadataSchema>;
export type GetSessionsResponse = z.infer<typeof GetSessionsResponseSchema>;
export type GetSessionResponse = z.infer<typeof GetSessionResponseSchema>;
export type LogEntry = z.infer<typeof LogEntrySchema>;
export type LogEntry = z.infer<typeof LogEntrySchema>;

View File

@@ -76,6 +76,7 @@ export function installRouter(app: Express, openAPIObject: OpenAPIObject) {
body: openAPIObject,
};
},
postLogElements() {
});
createExpressEndpoints(contract, router, app);