disable zodios request/response validation in runtime and use server errors instead

This commit is contained in:
Gregor Vostrak
2024-08-06 16:00:57 +02:00
parent 7c1b828ad3
commit 06a35cb447
21 changed files with 389 additions and 444 deletions

View File

@@ -167,12 +167,12 @@ const TimeEntryStoreRequest = z
end: z.union([z.string(), z.null()]).optional(), end: z.union([z.string(), z.null()]).optional(),
billable: z.boolean(), billable: z.boolean(),
description: z.union([z.string(), z.null()]).optional(), description: z.union([z.string(), z.null()]).optional(),
tags: z.union([z.array(z.string()), z.null()]).optional(), tags: z.union([z.array(z.string().uuid()), z.null()]).optional(),
}) })
.passthrough(); .passthrough();
const TimeEntryUpdateMultipleRequest = z const TimeEntryUpdateMultipleRequest = z
.object({ .object({
ids: z.array(z.string()), ids: z.array(z.string().uuid()),
changes: z changes: z
.object({ .object({
member_id: z.string().uuid(), member_id: z.string().uuid(),
@@ -180,7 +180,7 @@ const TimeEntryUpdateMultipleRequest = z
task_id: z.union([z.string(), z.null()]), task_id: z.union([z.string(), z.null()]),
billable: z.boolean(), billable: z.boolean(),
description: z.union([z.string(), z.null()]), description: z.union([z.string(), z.null()]),
tags: z.union([z.array(z.string()), z.null()]), tags: z.union([z.array(z.string().uuid()), z.null()]),
}) })
.partial() .partial()
.passthrough(), .passthrough(),
@@ -195,7 +195,7 @@ const TimeEntryUpdateRequest = z
end: z.union([z.string(), z.null()]), end: z.union([z.string(), z.null()]),
billable: z.boolean(), billable: z.boolean(),
description: z.union([z.string(), z.null()]), description: z.union([z.string(), z.null()]),
tags: z.union([z.array(z.string()), z.null()]), tags: z.union([z.array(z.string().uuid()), z.null()]),
}) })
.partial() .partial()
.passthrough(); .passthrough();
@@ -2041,22 +2041,22 @@ Users with the permission `time-entries:view:own` can only use this en
{ {
name: 'member_ids', name: 'member_ids',
type: 'Query', type: 'Query',
schema: z.array(z.string()).min(1).optional(), schema: z.array(z.string().uuid()).min(1).optional(),
}, },
{ {
name: 'project_ids', name: 'project_ids',
type: 'Query', type: 'Query',
schema: z.array(z.string()).min(1).optional(), schema: z.array(z.string().uuid()).min(1).optional(),
}, },
{ {
name: 'tag_ids', name: 'tag_ids',
type: 'Query', type: 'Query',
schema: z.array(z.string()).min(1).optional(), schema: z.array(z.string().uuid()).min(1).optional(),
}, },
{ {
name: 'task_ids', name: 'task_ids',
type: 'Query', type: 'Query',
schema: z.array(z.string()).min(1).optional(), schema: z.array(z.string().uuid()).min(1).optional(),
}, },
{ {
name: 'client_ids', name: 'client_ids',
@@ -2387,27 +2387,27 @@ If the group parameters are all set to `null` or are all missing, the
{ {
name: 'member_ids', name: 'member_ids',
type: 'Query', type: 'Query',
schema: z.array(z.string()).min(1).optional(), schema: z.array(z.string().uuid()).min(1).optional(),
}, },
{ {
name: 'project_ids', name: 'project_ids',
type: 'Query', type: 'Query',
schema: z.array(z.string()).min(1).optional(), schema: z.array(z.string().uuid()).min(1).optional(),
}, },
{ {
name: 'client_ids', name: 'client_ids',
type: 'Query', type: 'Query',
schema: z.array(z.string()).min(1).optional(), schema: z.array(z.string().uuid()).min(1).optional(),
}, },
{ {
name: 'tag_ids', name: 'tag_ids',
type: 'Query', type: 'Query',
schema: z.array(z.string()).min(1).optional(), schema: z.array(z.string().uuid()).min(1).optional(),
}, },
{ {
name: 'task_ids', name: 'task_ids',
type: 'Query', type: 'Query',
schema: z.array(z.string()).min(1).optional(), schema: z.array(z.string().uuid()).min(1).optional(),
}, },
], ],
response: z response: z

760
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -40,7 +40,7 @@
"@tailwindcss/container-queries": "^0.1.1", "@tailwindcss/container-queries": "^0.1.1",
"@vue/eslint-config-prettier": "^9.0.0", "@vue/eslint-config-prettier": "^9.0.0",
"@vue/eslint-config-typescript": "^13.0.0", "@vue/eslint-config-typescript": "^13.0.0",
"@vueuse/core": "^10.9.0", "@vueuse/core": "^10.11.0",
"dayjs": "^1.11.11", "dayjs": "^1.11.11",
"echarts": "^5.5.0", "echarts": "^5.5.0",
"parse-duration": "^1.1.0", "parse-duration": "^1.1.0",

View File

@@ -3,7 +3,7 @@ import type { Invitation } from '@/utils/api';
import TableRow from '@/Components/TableRow.vue'; import TableRow from '@/Components/TableRow.vue';
import { capitalizeFirstLetter } from '../../../utils/format'; import { capitalizeFirstLetter } from '../../../utils/format';
import InvitationMoreOptionsDropdown from '@/Components/Common/Invitation/InvitationMoreOptionsDropdown.vue'; import InvitationMoreOptionsDropdown from '@/Components/Common/Invitation/InvitationMoreOptionsDropdown.vue';
import { api } from '../../../../../openapi.json.client'; import { api } from '@/utils/api';
import { getCurrentOrganizationId } from '@/utils/useUser'; import { getCurrentOrganizationId } from '@/utils/useUser';
import { useNotificationsStore } from '@/utils/notification'; import { useNotificationsStore } from '@/utils/notification';
import { useInvitationsStore } from '@/utils/useInvitations'; import { useInvitationsStore } from '@/utils/useInvitations';

View File

@@ -14,7 +14,7 @@ import { filterRoles } from '@/utils/roles';
import { hasActiveSubscription, isBillingActivated } from '@/utils/billing'; import { hasActiveSubscription, isBillingActivated } from '@/utils/billing';
import { CreditCardIcon, UserGroupIcon } from '@heroicons/vue/20/solid'; import { CreditCardIcon, UserGroupIcon } from '@heroicons/vue/20/solid';
import { canUpdateOrganization } from '@/utils/permissions'; import { canUpdateOrganization } from '@/utils/permissions';
import { api } from '../../../../../openapi.json.client'; import { api } from '@/utils/api';
import type { MemberRole } from '@/utils/api'; import type { MemberRole } from '@/utils/api';
import { z } from 'zod'; import { z } from 'zod';
import { useNotificationsStore } from '@/utils/notification'; import { useNotificationsStore } from '@/utils/notification';

View File

@@ -5,7 +5,7 @@ import MemberMoreOptionsDropdown from '@/Components/Common/Member/MemberMoreOpti
import TableRow from '@/Components/TableRow.vue'; import TableRow from '@/Components/TableRow.vue';
import { capitalizeFirstLetter } from '../../../utils/format'; import { capitalizeFirstLetter } from '../../../utils/format';
import SecondaryButton from '@/Components/SecondaryButton.vue'; import SecondaryButton from '@/Components/SecondaryButton.vue';
import { api } from '../../../../../openapi.json.client'; import { api } from '@/utils/api';
import { getCurrentOrganizationId } from '@/utils/useUser'; import { getCurrentOrganizationId } from '@/utils/useUser';
import { useNotificationsStore } from '@/utils/notification'; import { useNotificationsStore } from '@/utils/notification';
import { canInvitePlaceholderMembers } from '@/utils/permissions'; import { canInvitePlaceholderMembers } from '@/utils/permissions';

View File

@@ -14,7 +14,7 @@ import {
import { PlusCircleIcon } from '@heroicons/vue/20/solid'; import { PlusCircleIcon } from '@heroicons/vue/20/solid';
import ProjectDropdownItem from '@/Components/Common/Project/ProjectDropdownItem.vue'; import ProjectDropdownItem from '@/Components/Common/Project/ProjectDropdownItem.vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { api } from '../../../../../openapi.json.client'; import { api } from '@/utils/api';
import { usePage } from '@inertiajs/vue3'; import { usePage } from '@inertiajs/vue3';
import { getRandomColor } from '@/utils/color'; import { getRandomColor } from '@/utils/color';
import type { Project } from '@/utils/api'; import type { Project } from '@/utils/api';

View File

@@ -53,9 +53,9 @@ const deleteTeam = () => {
<template #title> Delete Organization </template> <template #title> Delete Organization </template>
<template #content> <template #content>
Are you sure you want to delete this organization? Once a organization is Are you sure you want to delete this organization? Once a
deleted, all of its resources and data will be permanently organization is deleted, all of its resources and data will
deleted. be permanently deleted.
</template> </template>
<template #footer> <template #footer>

View File

@@ -3,7 +3,7 @@ import FormSection from '@/Components/FormSection.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue'; import PrimaryButton from '@/Components/PrimaryButton.vue';
import { computed, onMounted, ref } from 'vue'; import { computed, onMounted, ref } from 'vue';
import { useNotificationsStore } from '@/utils/notification'; import { useNotificationsStore } from '@/utils/notification';
import { api } from '../../../../../openapi.json.client'; import { api } from '@/utils/api';
import InputLabel from '@/Components/InputLabel.vue'; import InputLabel from '@/Components/InputLabel.vue';
import { DocumentIcon } from '@heroicons/vue/24/solid'; import { DocumentIcon } from '@heroicons/vue/24/solid';
import { getCurrentOrganizationId } from '@/utils/useUser'; import { getCurrentOrganizationId } from '@/utils/useUser';

View File

@@ -4,7 +4,7 @@ import type {
ZodiosBodyByAlias, ZodiosBodyByAlias,
ZodiosQueryParamsByAlias, ZodiosQueryParamsByAlias,
} from '@zodios/core'; } from '@zodios/core';
import { api } from '../../../openapi.json.client'; import { createApiClient } from '../../../openapi.json.client';
import { router } from '@inertiajs/vue3'; import { router } from '@inertiajs/vue3';
export type SolidTimeApi = ApiOf<typeof api>; export type SolidTimeApi = ApiOf<typeof api>;
@@ -147,3 +147,5 @@ export async function fetchToken() {
export function isTokenValid() { export function isTokenValid() {
return window.document.cookie.includes('solidtime_session'); return window.document.cookie.includes('solidtime_session');
} }
export const api = createApiClient('/api', { validate: 'none' });

View File

@@ -1,5 +1,5 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { api } from '../../../openapi.json.client'; import { api } from '@/utils/api';
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import type { import type {
CreateClientBody, CreateClientBody,

View File

@@ -1,6 +1,6 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { computed, reactive, ref } from 'vue'; import { computed, reactive, ref } from 'vue';
import { api } from '../../../openapi.json.client'; import { api } from '@/utils/api';
import type { TimeEntry } from '@/utils/api'; import type { TimeEntry } from '@/utils/api';
import dayjs, { Dayjs } from 'dayjs'; import dayjs, { Dayjs } from 'dayjs';
import utc from 'dayjs/plugin/utc'; import utc from 'dayjs/plugin/utc';

View File

@@ -1,5 +1,5 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { api } from '../../../openapi.json.client'; import { api } from '@/utils/api';
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import type { import type {
InvitationsIndexResponse, InvitationsIndexResponse,

View File

@@ -1,5 +1,5 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { api } from '../../../openapi.json.client'; import { api } from '@/utils/api';
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import type { import type {
Member, Member,

View File

@@ -9,7 +9,7 @@ import type {
} from '@/utils/api'; } from '@/utils/api';
import { useNotificationsStore } from '@/utils/notification'; import { useNotificationsStore } from '@/utils/notification';
import { getCurrentOrganizationId } from '@/utils/useUser'; import { getCurrentOrganizationId } from '@/utils/useUser';
import { api } from '../../../openapi.json.client'; import { api } from '@/utils/api';
export function switchOrganization(organizationId: string) { export function switchOrganization(organizationId: string) {
router.put( router.put(

View File

@@ -1,5 +1,5 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { api } from '../../../openapi.json.client'; import { api } from '@/utils/api';
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import type { import type {
CreateProjectMemberBody, CreateProjectMemberBody,

View File

@@ -1,5 +1,5 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { api } from '../../../openapi.json.client'; import { api } from '@/utils/api';
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import type { import type {
CreateProjectBody, CreateProjectBody,
@@ -34,6 +34,7 @@ export const useProjectsStore = defineStore('projects', () => {
async function createProject(projectBody: CreateProjectBody) { async function createProject(projectBody: CreateProjectBody) {
const organization = getCurrentOrganizationId(); const organization = getCurrentOrganizationId();
if (organization) { if (organization) {
const response = await handleApiRequestNotifications( const response = await handleApiRequestNotifications(
() => () =>

View File

@@ -1,5 +1,5 @@
import { defineStore, storeToRefs } from 'pinia'; import { defineStore, storeToRefs } from 'pinia';
import { api } from '../../../openapi.json.client'; import { api } from '@/utils/api';
import { type Component, computed, ref } from 'vue'; import { type Component, computed, ref } from 'vue';
import type { import type {
AggregatedTimeEntries, AggregatedTimeEntries,

View File

@@ -2,7 +2,7 @@ import { defineStore } from 'pinia';
import { ref } from 'vue'; import { ref } from 'vue';
import type { Tag } from '@/utils/api'; import type { Tag } from '@/utils/api';
import { getCurrentOrganizationId } from '@/utils/useUser'; import { getCurrentOrganizationId } from '@/utils/useUser';
import { api } from '../../../openapi.json.client'; import { api } from '@/utils/api';
import { useNotificationsStore } from '@/utils/notification'; import { useNotificationsStore } from '@/utils/notification';
export const useTagsStore = defineStore('tags', () => { export const useTagsStore = defineStore('tags', () => {

View File

@@ -1,6 +1,6 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { getCurrentOrganizationId } from '@/utils/useUser'; import { getCurrentOrganizationId } from '@/utils/useUser';
import { api } from '../../../openapi.json.client'; import { api } from '@/utils/api';
import { reactive, ref } from 'vue'; import { reactive, ref } from 'vue';
import type { CreateTaskBody, Task, UpdateTaskBody } from '@/utils/api'; import type { CreateTaskBody, Task, UpdateTaskBody } from '@/utils/api';
import { useNotificationsStore } from '@/utils/notification'; import { useNotificationsStore } from '@/utils/notification';

View File

@@ -3,9 +3,9 @@ import {
getCurrentMembershipId, getCurrentMembershipId,
getCurrentOrganizationId, getCurrentOrganizationId,
} from '@/utils/useUser'; } from '@/utils/useUser';
import { api } from '../../../openapi.json.client';
import { reactive, ref } from 'vue'; import { reactive, ref } from 'vue';
import type { CreateTimeEntryBody, TimeEntry } from '@/utils/api'; import { api, type CreateTimeEntryBody, type TimeEntry } from '@/utils/api';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { useNotificationsStore } from '@/utils/notification'; import { useNotificationsStore } from '@/utils/notification';