2025-06-30 18:58:24 +02:00
|
|
|
/*
|
|
|
|
SPDX-FileCopyrightText: © 2025 Hornwitser <code@hornwitser.no>
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
*/
|
2025-06-11 21:05:17 +02:00
|
|
|
import { z } from "zod/v4-mini";
|
2025-06-24 15:19:11 +02:00
|
|
|
import { idSchema, type Id } from "~/shared/types/common";
|
|
|
|
|
|
|
|
export const apiEntitySchema = z.object({
|
|
|
|
id: idSchema,
|
|
|
|
updatedAt: z.string(),
|
|
|
|
deleted: z.optional(z.literal(false)),
|
|
|
|
});
|
|
|
|
export type ApiEntity = z.infer<typeof apiEntitySchema>;
|
|
|
|
|
|
|
|
export function defineApiEntity<T extends {}>(fields: T) {
|
|
|
|
return z.extend(apiEntitySchema, fields);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function tombstonable<T extends z.ZodMiniObject>(entitySchema: T) {
|
|
|
|
return z.discriminatedUnion("deleted", [entitySchema, apiTombstoneSchema]);
|
|
|
|
}
|
|
|
|
|
|
|
|
export const apiTombstoneSchema = z.object({
|
|
|
|
id: idSchema,
|
|
|
|
updatedAt: z.string(),
|
|
|
|
deleted: z.literal(true),
|
|
|
|
});
|
|
|
|
export type ApiTombstone = z.infer<typeof apiTombstoneSchema>;
|
2025-06-11 21:05:17 +02:00
|
|
|
|
2025-06-23 00:00:18 +02:00
|
|
|
export const apiUserTypeSchema = z.union([
|
|
|
|
z.literal("anonymous"),
|
|
|
|
z.literal("regular"),
|
|
|
|
z.literal("crew"),
|
|
|
|
z.literal("admin"),
|
|
|
|
])
|
|
|
|
export type ApiUserType = z.infer<typeof apiUserTypeSchema>;
|
|
|
|
|
2025-06-11 21:05:17 +02:00
|
|
|
export interface ApiAccount {
|
|
|
|
id: Id,
|
2025-06-23 00:17:22 +02:00
|
|
|
updatedAt: string,
|
2025-06-23 00:00:18 +02:00
|
|
|
type: ApiUserType,
|
2025-06-11 21:05:17 +02:00
|
|
|
/** Name of the account. Not present on anonymous accounts */
|
|
|
|
name?: string,
|
|
|
|
interestedEventIds?: number[],
|
|
|
|
interestedEventSlotIds?: number[],
|
|
|
|
timezone?: string,
|
2025-06-13 21:50:22 +02:00
|
|
|
locale?: string,
|
2025-06-11 21:05:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export const apiAccountPatchSchema = z.object({
|
|
|
|
name: z.optional(z.string()),
|
|
|
|
interestedEventIds: z.optional(z.array(z.number())),
|
|
|
|
interestedEventSlotIds: z.optional(z.array(z.number())),
|
|
|
|
timezone: z.optional(z.string()),
|
2025-06-13 21:50:22 +02:00
|
|
|
locale: z.optional(z.string()),
|
2025-06-11 21:05:17 +02:00
|
|
|
});
|
|
|
|
export type ApiAccountPatch = z.infer<typeof apiAccountPatchSchema>;
|
|
|
|
|
|
|
|
export const apiSubscriptionSchema = z.object({
|
|
|
|
type: z.literal("push"),
|
|
|
|
sessionId: z.number(),
|
|
|
|
push: z.object({
|
|
|
|
endpoint: z.optional(z.string()),
|
|
|
|
expirationTime: z.nullish(z.number()),
|
|
|
|
keys: z.record(z.string(), z.string()),
|
|
|
|
}),
|
|
|
|
});
|
|
|
|
export type ApiSubscription = z.infer<typeof apiSubscriptionSchema>;
|
|
|
|
|
|
|
|
export interface ApiSession {
|
|
|
|
id: Id,
|
|
|
|
account?: ApiAccount,
|
|
|
|
push: boolean,
|
|
|
|
}
|
|
|
|
|
2025-06-24 15:19:11 +02:00
|
|
|
export const apiScheduleLocationSchema = defineApiEntity({
|
2025-06-11 21:05:17 +02:00
|
|
|
name: z.string(),
|
|
|
|
description: z.optional(z.string()),
|
|
|
|
});
|
|
|
|
export type ApiScheduleLocation = z.infer<typeof apiScheduleLocationSchema>;
|
|
|
|
|
|
|
|
export const apiScheduleEventSlotSchema = z.object({
|
|
|
|
id: idSchema,
|
|
|
|
start: z.string(),
|
|
|
|
end: z.string(),
|
|
|
|
locationIds: z.array(idSchema),
|
|
|
|
assigned: z.optional(z.array(z.number())),
|
|
|
|
interested: z.optional(z.number()),
|
|
|
|
});
|
|
|
|
export type ApiScheduleEventSlot = z.infer<typeof apiScheduleEventSlotSchema>;
|
|
|
|
|
2025-06-24 15:19:11 +02:00
|
|
|
export const apiScheduleEventSchema = defineApiEntity({
|
2025-06-11 21:05:17 +02:00
|
|
|
name: z.string(),
|
|
|
|
crew: z.optional(z.boolean()),
|
|
|
|
host: z.optional(z.string()),
|
|
|
|
cancelled: z.optional(z.boolean()),
|
|
|
|
description: z.optional(z.string()),
|
|
|
|
interested: z.optional(z.number()),
|
|
|
|
slots: z.array(apiScheduleEventSlotSchema),
|
|
|
|
});
|
|
|
|
export type ApiScheduleEvent = z.infer<typeof apiScheduleEventSchema>;
|
|
|
|
|
2025-06-24 15:19:11 +02:00
|
|
|
export const apiScheduleRoleSchema = defineApiEntity({
|
2025-06-11 21:05:17 +02:00
|
|
|
name: z.string(),
|
|
|
|
description: z.optional(z.string()),
|
|
|
|
});
|
|
|
|
export type ApiScheduleRole = z.infer<typeof apiScheduleRoleSchema>;
|
|
|
|
|
|
|
|
export const apiScheduleShiftSlotSchema = z.object({
|
|
|
|
id: idSchema,
|
|
|
|
start: z.string(),
|
|
|
|
end: z.string(),
|
|
|
|
assigned: z.optional(z.array(z.number())),
|
|
|
|
});
|
|
|
|
export type ApiScheduleShiftSlot = z.infer<typeof apiScheduleShiftSlotSchema>;
|
|
|
|
|
2025-06-24 15:19:11 +02:00
|
|
|
export const apiScheduleShiftSchema = defineApiEntity({
|
2025-06-30 16:14:40 +02:00
|
|
|
roleId: z.optional(idSchema),
|
2025-06-11 21:05:17 +02:00
|
|
|
name: z.string(),
|
|
|
|
description: z.optional(z.string()),
|
|
|
|
slots: z.array(apiScheduleShiftSlotSchema),
|
|
|
|
});
|
|
|
|
export type ApiScheduleShift = z.infer<typeof apiScheduleShiftSchema>;
|
|
|
|
|
2025-06-24 15:19:11 +02:00
|
|
|
export const apiScheduleSchema = defineApiEntity({
|
2025-06-11 21:05:17 +02:00
|
|
|
id: z.literal(111),
|
2025-06-24 15:19:11 +02:00
|
|
|
locations: z.optional(z.array(tombstonable(apiScheduleLocationSchema))),
|
|
|
|
events: z.optional(z.array(tombstonable(apiScheduleEventSchema))),
|
|
|
|
roles: z.optional(z.array(tombstonable(apiScheduleRoleSchema))),
|
|
|
|
shifts: z.optional(z.array(tombstonable(apiScheduleShiftSchema))),
|
2025-06-11 21:05:17 +02:00
|
|
|
});
|
|
|
|
export type ApiSchedule = z.infer<typeof apiScheduleSchema>;
|
|
|
|
|
2025-06-24 15:19:11 +02:00
|
|
|
export const apiUserSchema = defineApiEntity({
|
2025-06-23 00:00:18 +02:00
|
|
|
type: apiUserTypeSchema,
|
|
|
|
name: z.optional(z.string()),
|
|
|
|
});
|
|
|
|
export type ApiUser = z.infer<typeof apiUserSchema>;
|
|
|
|
|
2025-06-23 00:17:22 +02:00
|
|
|
export const apiUserPatchSchema = z.object({
|
|
|
|
id: idSchema,
|
|
|
|
type: z.optional(apiUserTypeSchema),
|
|
|
|
name: z.optional(z.string()),
|
|
|
|
});
|
|
|
|
export type ApiUserPatch = z.infer<typeof apiUserPatchSchema>;
|
|
|
|
|
2025-06-11 21:05:17 +02:00
|
|
|
export interface ApiAccountUpdate {
|
|
|
|
type: "account-update",
|
|
|
|
data: ApiAccount,
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface ApiScheduleUpdate {
|
|
|
|
type: "schedule-update",
|
|
|
|
updatedFrom?: string,
|
2025-06-24 15:19:11 +02:00
|
|
|
data: ApiSchedule | ApiTombstone,
|
2025-06-11 21:05:17 +02:00
|
|
|
}
|
|
|
|
|
2025-06-23 00:17:22 +02:00
|
|
|
export interface ApiUserUpdate {
|
|
|
|
type: "user-update",
|
|
|
|
updatedFrom?: string,
|
2025-06-24 15:19:11 +02:00
|
|
|
data: ApiUser | ApiTombstone,
|
2025-06-23 00:17:22 +02:00
|
|
|
}
|
|
|
|
|
2025-06-11 21:05:17 +02:00
|
|
|
export type ApiEvent =
|
|
|
|
| ApiAccountUpdate
|
|
|
|
| ApiScheduleUpdate
|
2025-06-23 00:17:22 +02:00
|
|
|
| ApiUserUpdate
|
2025-06-11 21:05:17 +02:00
|
|
|
;
|