From 67de31276ff1071a39ff298c3ac617e113d77e14 Mon Sep 17 00:00:00 2001 From: Sean Sube Date: Sat, 14 Jun 2025 17:19:39 -0500 Subject: [PATCH] fix most graphql errors --- client/src/components/CreateButtons.tsx | 87 ++++ client/src/components/CreateDialog.tsx | 116 ++++++ client/src/graphql/mutations.ts | 68 ++- client/src/graphql/queries.ts | 24 +- client/src/hooks/useTaskData.ts | 183 +++++++-- client/src/layouts/DesktopLayout.tsx | 22 +- client/src/layouts/MobileLayout.tsx | 22 +- client/src/types/index.ts | 110 +++-- client/src/utils/typeGuards.ts | 164 ++++++++ package-lock.json | 522 +++++++++++++++++++++++- server/package.json | 6 +- server/src/db/knexfile.ts | 13 +- server/src/graphql/schema.ts | 68 +-- 13 files changed, 1260 insertions(+), 145 deletions(-) create mode 100644 client/src/components/CreateButtons.tsx create mode 100644 client/src/components/CreateDialog.tsx create mode 100644 client/src/utils/typeGuards.ts diff --git a/client/src/components/CreateButtons.tsx b/client/src/components/CreateButtons.tsx new file mode 100644 index 0000000..2e551e7 --- /dev/null +++ b/client/src/components/CreateButtons.tsx @@ -0,0 +1,87 @@ +import { useState } from 'react'; +import { Button, Box } from '@mui/material'; +import { CreateDialog } from './CreateDialog'; +import { useTaskData } from '../hooks/useTaskData'; + +interface BaseCreateData { + name: string; +} + +interface CreateTaskData extends BaseCreateData { + groupId: string; +} + +interface CreateStepData extends BaseCreateData { + instructions: string; + taskId: string; + order: number; +} + +type CreateData = BaseCreateData | CreateTaskData | CreateStepData; + +interface CreateButtonsProps { + type: 'group' | 'task' | 'step'; + parentId?: string; +} + +export function CreateButtons({ type, parentId }: CreateButtonsProps) { + const [open, setOpen] = useState(false); + const { handleCreateGroup, handleCreateTask, handleCreateStep } = useTaskData(); + + const handleSubmit = (data: CreateData) => { + let stepData: CreateStepData; + switch (type) { + case 'group': + handleCreateGroup(data.name); + break; + case 'task': + if (!parentId) { + console.error('Cannot create task: no group selected'); + return; + } + handleCreateTask(data.name, parentId); + break; + case 'step': + if (!parentId) { + console.error('Cannot create step: no task selected'); + return; + } + stepData = data as CreateStepData; + handleCreateStep(stepData.name, stepData.instructions, parentId, stepData.order); + break; + } + }; + + const getTitle = () => { + switch (type) { + case 'group': + return 'Create New Group'; + case 'task': + return 'Create New Task'; + case 'step': + return 'Create New Step'; + } + }; + + const isDisabled = (type === 'task' || type === 'step') && !parentId; + + return ( + + + setOpen(false)} + onSubmit={handleSubmit} + title={getTitle()} + type={type} + parentId={parentId} + /> + + ); +} \ No newline at end of file diff --git a/client/src/components/CreateDialog.tsx b/client/src/components/CreateDialog.tsx new file mode 100644 index 0000000..8c50896 --- /dev/null +++ b/client/src/components/CreateDialog.tsx @@ -0,0 +1,116 @@ +import { useState } from 'react'; +import { + Dialog, + DialogTitle, + DialogContent, + DialogActions, + Button, + TextField, + Box, +} from '@mui/material'; + +interface BaseCreateData { + name: string; +} + +interface CreateTaskData extends BaseCreateData { + groupId: string; +} + +interface CreateStepData extends BaseCreateData { + instructions: string; + taskId: string; + order: number; +} + +type CreateData = BaseCreateData | CreateTaskData | CreateStepData; + +interface CreateDialogProps { + open: boolean; + onClose: () => void; + onSubmit: (data: CreateData) => void; + title: string; + type: 'group' | 'task' | 'step'; + parentId?: string; +} + +export function CreateDialog({ open, onClose, onSubmit, title, type, parentId }: CreateDialogProps) { + const [name, setName] = useState(''); + const [instructions, setInstructions] = useState(''); + const [order, setOrder] = useState(1); + + const handleSubmit = () => { + if (type === 'task' && !parentId) { + console.error('Cannot create task: no group selected'); + return; + } + if (type === 'step' && !parentId) { + console.error('Cannot create step: no task selected'); + return; + } + + const data: CreateData = { + name, + ...(type === 'task' && { groupId: parentId }), + ...(type === 'step' && { + instructions, + taskId: parentId, + order, + }), + }; + onSubmit(data); + handleClose(); + }; + + const handleClose = () => { + setName(''); + setInstructions(''); + setOrder(1); + onClose(); + }; + + return ( + + {title} + + + setName(e.target.value)} + fullWidth + required + /> + {type === 'step' && ( + <> + setInstructions(e.target.value)} + fullWidth + required + multiline + rows={4} + /> + setOrder(parseInt(e.target.value))} + fullWidth + required + inputProps={{ min: 1 }} + /> + + )} + + + + + + + + ); +} \ No newline at end of file diff --git a/client/src/graphql/mutations.ts b/client/src/graphql/mutations.ts index 5b82c24..b30b96d 100644 --- a/client/src/graphql/mutations.ts +++ b/client/src/graphql/mutations.ts @@ -1,35 +1,71 @@ import { gql } from '@apollo/client'; -export const PRINT_TASK = gql` - mutation PrintTask($id: ID!, $userId: ID!) { - printTask(id: $id, userId: $userId) { +export const CREATE_GROUP = gql` + mutation CreateGroup($name: String!, $parentId: ID) { + createGroup(name: $name, parentId: $parentId) { id - printCount - lastPrintedAt + name + parent_id + created_at + updated_at + } + } +`; + +export const CREATE_TASK = gql` + mutation CreateTask($name: String!, $groupId: ID!) { + createTask(name: $name, groupId: $groupId) { + id + name + group_id + print_count + created_at + updated_at + } + } +`; + +export const CREATE_STEP = gql` + mutation CreateStep($name: String!, $instructions: String!, $taskId: ID!, $order: Int!) { + createStep(name: $name, instructions: $instructions, taskId: $taskId, order: $order) { + id + name + instructions + task_id + order + created_at + updated_at + } + } +`; + +export const PRINT_TASK = gql` + mutation PrintTask($id: ID!) { + printTask(id: $id) { + id + print_count } } `; export const PRINT_STEP = gql` - mutation PrintStep($id: ID!, $userId: ID!) { - printStep(id: $id, userId: $userId) { + mutation PrintStep($id: ID!) { + printStep(id: $id) { id - printCount - lastPrintedAt + print_count } } `; export const CREATE_NOTE = gql` - mutation CreateNote($content: String!, $stepId: ID!, $userId: ID!) { - createNote(content: $content, stepId: $stepId, userId: $userId) { + mutation CreateNote($content: String!, $stepId: ID!) { + createNote(content: $content, stepId: $stepId) { id content - createdAt - user { - id - name - } + step_id + user_id + created_at + updated_at } } `; \ No newline at end of file diff --git a/client/src/graphql/queries.ts b/client/src/graphql/queries.ts index 89f98b1..36dd7a9 100644 --- a/client/src/graphql/queries.ts +++ b/client/src/graphql/queries.ts @@ -8,15 +8,15 @@ export const GET_GROUPS = gql` tasks { id name - printCount - lastPrintedAt + print_count + last_printed_at steps { id name instructions order - printCount - lastPrintedAt + print_count + last_printed_at } } } @@ -28,19 +28,19 @@ export const GET_TASKS = gql` tasks(groupId: $groupId) { id name - printCount - lastPrintedAt + print_count + last_printed_at steps { id name instructions order - printCount - lastPrintedAt + print_count + last_printed_at notes { id content - createdAt + created_at user { id name @@ -58,12 +58,12 @@ export const GET_STEP = gql` name instructions order - printCount - lastPrintedAt + print_count + last_printed_at notes { id content - createdAt + created_at user { id name diff --git a/client/src/hooks/useTaskData.ts b/client/src/hooks/useTaskData.ts index c45776a..2a617e0 100644 --- a/client/src/hooks/useTaskData.ts +++ b/client/src/hooks/useTaskData.ts @@ -1,8 +1,9 @@ import { useState } from 'react'; import { useQuery, useMutation } from '@apollo/client'; import { GET_GROUPS, GET_TASKS, GET_STEP } from '../graphql/queries'; -import { PRINT_TASK, PRINT_STEP, CREATE_NOTE } from '../graphql/mutations'; +import { PRINT_TASK, PRINT_STEP, CREATE_NOTE, CREATE_GROUP, CREATE_TASK, CREATE_STEP } from '../graphql/mutations'; import type { GroupWithTasks, TaskWithSteps, StepWithNotes } from '../types'; +import { doesExist, isArray } from '../utils/typeGuards'; interface GraphQLStep { id: number; @@ -11,19 +12,18 @@ interface GraphQLStep { taskId: number; order: number; notes: GraphQLNote[]; - printCount: number; - lastPrintedAt: string | null; + print_count: number; + last_printed_at: string | null; } interface GraphQLNote { id: number; content: string; - createdBy: number; - user?: { + created_at: string; + updated_at: string; + user: { id: number; name: string; - createdAt: Date; - updatedAt: Date; }; } @@ -33,62 +33,107 @@ interface GraphQLTask { groupId: number; steps: GraphQLStep[]; notes: GraphQLNote[]; - printCount: number; - lastPrintedAt: string | null; + print_count: number; + last_printed_at: string | null; } interface GraphQLGroup { id: number; name: string; tasks: GraphQLTask[]; + created_at: string; + updated_at: string; } -function toStepWithNotes(step: GraphQLStep): StepWithNotes { +function toStepWithNotes(step: GraphQLStep | null | undefined): StepWithNotes | null { + if (!doesExist(step)) return null; + return { - ...step, - notes: (step.notes || []).map((note: GraphQLNote) => ({ ...note })), - printCount: step.printCount ?? 0, - lastPrintedAt: step.lastPrintedAt ?? null, + id: step.id, + name: step.name, + instructions: step.instructions, + task_id: step.taskId, + order: step.order, + print_count: step.print_count, + last_printed_at: step.last_printed_at ? new Date(step.last_printed_at) : undefined, + notes: isArray(step.notes) ? step.notes.map(note => ({ + id: note.id, + content: note.content, + created_at: new Date(note.created_at), + updated_at: new Date(note.updated_at), + created_by: note.user.id, + user: { + id: note.user.id, + name: note.user.name, + }, + })) : [], }; } -function toTaskWithSteps(task: GraphQLTask): TaskWithSteps { +function toTaskWithSteps(task: GraphQLTask | null | undefined): TaskWithSteps | null { + if (!doesExist(task)) return null; + return { - ...task, - steps: (task.steps || []).map(toStepWithNotes), - notes: (task.notes || []), - printCount: task.printCount ?? 0, - lastPrintedAt: task.lastPrintedAt ?? null, + id: task.id, + name: task.name, + group_id: task.groupId, + print_count: task.print_count, + last_printed_at: task.last_printed_at ? new Date(task.last_printed_at) : undefined, + steps: isArray(task.steps) ? task.steps.map(step => toStepWithNotes(step)).filter(doesExist) : [], + notes: isArray(task.notes) ? task.notes.map(note => ({ + id: note.id, + content: note.content, + created_at: new Date(note.created_at), + updated_at: new Date(note.updated_at), + created_by: note.user.id, + user: { + id: note.user.id, + name: note.user.name, + }, + })) : [], }; } -function toGroupWithTasks(group: GraphQLGroup): GroupWithTasks { +function toGroupWithTasks(group: GraphQLGroup | null | undefined): GroupWithTasks | null { + if (!doesExist(group)) return null; + return { - ...group, - tasks: (group.tasks || []).map(toTaskWithSteps), + id: group.id, + name: group.name, + created_at: new Date(group.created_at), + updated_at: new Date(group.updated_at), + tasks: isArray(group.tasks) ? group.tasks.map(task => toTaskWithSteps(task)).filter(doesExist) : [], }; } export function useTaskData() { - const [selectedGroup, setSelectedGroup] = useState(); - const [selectedTask, setSelectedTask] = useState(); - const [selectedStep, setSelectedStep] = useState(); + const [selectedGroup, setSelectedGroup] = useState(); + const [selectedTask, setSelectedTask] = useState(); + const [selectedStep, setSelectedStep] = useState(); - const { data: groupsData, loading: groupsLoading } = useQuery(GET_GROUPS); - const { data: tasksData, loading: tasksLoading } = useQuery(GET_TASKS, { + const { data: groupsData, loading: groupsLoading, refetch: refetchGroups } = useQuery(GET_GROUPS); + const { data: tasksData, loading: tasksLoading, refetch: refetchTasks } = useQuery(GET_TASKS, { variables: { groupId: selectedGroup?.id }, - skip: !selectedGroup, + skip: !selectedGroup?.id, }); - const { data: stepData, loading: stepLoading } = useQuery(GET_STEP, { + const { data: stepData, loading: stepLoading, refetch: refetchStep } = useQuery(GET_STEP, { variables: { id: selectedStep?.id }, - skip: !selectedStep, + skip: !selectedStep?.id, }); const [printTask] = useMutation(PRINT_TASK); const [printStep] = useMutation(PRINT_STEP); const [createNote] = useMutation(CREATE_NOTE); + const [createGroup] = useMutation(CREATE_GROUP); + const [createTask] = useMutation(CREATE_TASK); + const [createStep] = useMutation(CREATE_STEP); const handlePrintTask = async (taskId: string, userId: string) => { + if (!taskId || !userId) { + console.error('Cannot print task: missing taskId or userId'); + return; + } + try { await printTask({ variables: { id: taskId, userId } }); } catch (error) { @@ -97,6 +142,11 @@ export function useTaskData() { }; const handlePrintStep = async (stepId: string, userId: string) => { + if (!stepId || !userId) { + console.error('Cannot print step: missing stepId or userId'); + return; + } + try { await printStep({ variables: { id: stepId, userId } }); } catch (error) { @@ -105,7 +155,10 @@ export function useTaskData() { }; const handleAddNote = async (content: string, userId: string) => { - if (!selectedStep) return; + if (!selectedStep?.id || !userId) { + console.error('Cannot add note: missing stepId or userId'); + return; + } try { await createNote({ @@ -120,10 +173,67 @@ export function useTaskData() { } }; + const handleCreateGroup = async (name: string) => { + if (!name) { + console.error('Cannot create group: missing name'); + return; + } + + try { + await createGroup({ variables: { name } }); + await refetchGroups(); + } catch (error) { + console.error('Error creating group:', error); + } + }; + + const handleCreateTask = async (name: string, groupId: string) => { + if (!name || !groupId) { + console.error('Cannot create task: missing name or groupId'); + return; + } + + try { + const variables = { + name, + groupId, + }; + console.log('Creating task with variables:', variables); + await createTask({ variables }); + await refetchTasks({ groupId }); + } catch (error) { + console.error('Error creating task:', error); + } + }; + + const handleCreateStep = async (name: string, instructions: string, taskId: string, order: number) => { + if (!name || !instructions || !taskId || order < 1) { + console.error('Cannot create step: missing required fields'); + return; + } + + try { + await createStep({ variables: { name, instructions, taskId, order } }); + await refetchStep({ id: taskId }); + } catch (error) { + console.error('Error creating step:', error); + } + }; + + const groups = isArray(groupsData?.groups) + ? groupsData.groups.map((group: GraphQLGroup) => toGroupWithTasks(group)).filter(doesExist) + : []; + + const tasks = isArray(tasksData?.tasks) + ? tasksData.tasks.map((task: GraphQLTask) => toTaskWithSteps(task)).filter(doesExist) + : []; + + const step = stepData?.step ? toStepWithNotes(stepData.step) : undefined; + return { - groups: (groupsData?.groups || []).map(toGroupWithTasks), - tasks: (tasksData?.tasks || []).map(toTaskWithSteps), - step: stepData?.step ? toStepWithNotes(stepData.step) : undefined, + groups, + tasks, + step, loading: groupsLoading || tasksLoading || stepLoading, selectedGroup, selectedTask, @@ -134,5 +244,8 @@ export function useTaskData() { handlePrintTask, handlePrintStep, handleAddNote, + handleCreateGroup, + handleCreateTask, + handleCreateStep, }; } \ No newline at end of file diff --git a/client/src/layouts/DesktopLayout.tsx b/client/src/layouts/DesktopLayout.tsx index 85593f1..3578c82 100644 --- a/client/src/layouts/DesktopLayout.tsx +++ b/client/src/layouts/DesktopLayout.tsx @@ -1,5 +1,6 @@ import { Box, Typography } from '@mui/material'; import type { GroupWithTasks, TaskWithSteps, StepWithNotes } from '../types'; +import { CreateButtons } from '../components/CreateButtons'; interface DesktopLayoutProps { groups: GroupWithTasks[]; @@ -24,9 +25,10 @@ export function DesktopLayout({ {/* Groups panel */} - - Groups - + + Groups + + {groups.map((group) => ( - - Tasks - + + Tasks + + {selectedGroup.tasks.map((task) => ( - - Steps - + + Steps + + {selectedTask.steps.map((step) => ( {isGroupView(selectedGroup) && ( <> - - Groups - + + Groups + + {groupList.map((group) => ( - - Tasks - + + Tasks + + {taskList.map((task) => ( - - Steps - + + Steps + + {stepList.map((step) => ( { - tasks: TaskWithSteps[]; -} - -export interface TaskWithSteps extends Omit { +export interface TaskWithSteps { + id: number; + name: string; + group_id: number; + print_count: number; + last_printed_at?: Date | string | null; + created_at?: Date | string | null; + updated_at?: Date | string | null; steps: StepWithNotes[]; notes: NoteWithUser[]; - printCount: number; - lastPrintedAt: string | null; } -export interface StepWithNotes extends Omit { +export interface StepWithNotes { + id: number; + name: string; + instructions: string; + task_id: number; + order: number; + print_count: number; + last_printed_at?: Date | string | null; + created_at?: Date | string | null; + updated_at?: Date | string | null; notes: NoteWithUser[]; - printCount: number; - lastPrintedAt: string | null; } -export interface NoteWithUser extends Omit { - user?: SharedUser; +export type Task = { + id: number; + name: string; + group_id: number; + print_count: number; + last_printed_at?: Date | string | null; + created_at?: Date | string | null; + updated_at?: Date | string | null; +}; + +export type Step = { + id: number; + name: string; + instructions: string; + task_id: number; + order: number; + print_count: number; + last_printed_at?: Date | string | null; + created_at?: Date | string | null; + updated_at?: Date | string | null; +}; + +// Define User, Note, and PrintHistory locally if needed + +export interface User { + id: number; + name: string; + created_at?: Date | string | null; + updated_at?: Date | string | null; } -export interface PrintHistoryWithDetails extends Omit { - user?: SharedUser; +export interface Note { + id: number; + content: string; + step_id?: number; + task_id?: number; + user_id?: number; + created_at?: Date | string | null; + updated_at?: Date | string | null; +} + +export interface NoteWithUser extends Note { + user?: User; +} + +export interface PrintHistory { + id: number; + user_id: number; + task_id?: number; + step_id?: number; + printed_at: Date | string; + created_at?: Date | string | null; + updated_at?: Date | string | null; +} + +export interface PrintHistoryWithDetails extends PrintHistory { + user?: User; task?: TaskWithSteps; step?: StepWithNotes; } -// Re-export shared types with client-specific modifications -export type Group = Omit; -export type Task = Omit & { lastPrintedAt: string | null }; -export type Step = Omit & { lastPrintedAt: string | null }; -export type User = Omit; -export type Note = Omit; -export type PrintHistory = Omit; \ No newline at end of file +export interface Group { + id: number; + name: string; + parent_id?: number; + created_at?: Date | string | null; + updated_at?: Date | string | null; +} + +export interface GroupWithTasks extends Group { + tasks: TaskWithSteps[]; +} + +// All types are now defined locally above. Remove all re-exports and duplicate type definitions at the bottom of the file. \ No newline at end of file diff --git a/client/src/utils/typeGuards.ts b/client/src/utils/typeGuards.ts new file mode 100644 index 0000000..3d59068 --- /dev/null +++ b/client/src/utils/typeGuards.ts @@ -0,0 +1,164 @@ +import type { GroupWithTasks, TaskWithSteps, StepWithNotes } from '../types'; + +interface GraphQLStep { + id: number; + name: string; + instructions: string; + taskId: number; + order: number; + notes: GraphQLNote[]; + print_count: number; + last_printed_at: string | null; +} + +interface GraphQLNote { + id: number; + content: string; + created_at: string; + updated_at: string; + user: { + id: number; + name: string; + }; +} + +interface GraphQLTask { + id: number; + name: string; + groupId: number; + steps: GraphQLStep[]; + notes: GraphQLNote[]; + print_count: number; + last_printed_at: string | null; +} + +interface GraphQLGroup { + id: number; + name: string; + tasks: GraphQLTask[]; + created_at: string; + updated_at: string; +} + +// Generic type guard for non-null values +export function doesExist(value: T | null | undefined): value is T { + return value !== null && value !== undefined; +} + +// Type guard for arrays +export function isArray(value: unknown): value is T[] { + return Array.isArray(value); +} + +// Type guard for objects with required properties +export function hasProperties(value: unknown, properties: (keyof T)[]): value is T { + return ( + typeof value === 'object' && + value !== null && + properties.every(prop => prop in value) + ); +} + +// Type guard for GraphQL objects +export function isGraphQLStep(value: unknown): value is GraphQLStep { + return ( + typeof value === 'object' && + value !== null && + 'id' in value && + 'name' in value && + 'instructions' in value && + 'taskId' in value && + 'order' in value && + 'notes' in value && + 'print_count' in value && + 'last_printed_at' in value + ); +} + +export function isGraphQLTask(value: unknown): value is GraphQLTask { + return ( + typeof value === 'object' && + value !== null && + 'id' in value && + 'name' in value && + 'groupId' in value && + 'steps' in value && + 'notes' in value && + 'print_count' in value && + 'last_printed_at' in value + ); +} + +export function isGraphQLGroup(value: unknown): value is GraphQLGroup { + return ( + typeof value === 'object' && + value !== null && + 'id' in value && + 'name' in value && + 'tasks' in value && + 'created_at' in value && + 'updated_at' in value + ); +} + +// Transformation functions +export function toStepWithNotes(step: GraphQLStep | null | undefined): StepWithNotes | null { + if (!doesExist(step)) return null; + + return { + id: step.id, + name: step.name, + instructions: step.instructions, + task_id: step.taskId, + order: step.order, + print_count: step.print_count, + last_printed_at: step.last_printed_at ? new Date(step.last_printed_at) : undefined, + notes: isArray(step.notes) ? step.notes.map(note => ({ + id: note.id, + content: note.content, + created_at: new Date(note.created_at), + updated_at: new Date(note.updated_at), + created_by: note.user.id, + user: { + id: note.user.id, + name: note.user.name, + }, + })) : [], + }; +} + +export function toTaskWithSteps(task: GraphQLTask | null | undefined): TaskWithSteps | null { + if (!doesExist(task)) return null; + + return { + id: task.id, + name: task.name, + group_id: task.groupId, + print_count: task.print_count, + last_printed_at: task.last_printed_at ? new Date(task.last_printed_at) : undefined, + steps: isArray(task.steps) ? task.steps.map(step => toStepWithNotes(step)).filter(doesExist) : [], + notes: isArray(task.notes) ? task.notes.map(note => ({ + id: note.id, + content: note.content, + created_at: new Date(note.created_at), + updated_at: new Date(note.updated_at), + created_by: note.user.id, + user: { + id: note.user.id, + name: note.user.name, + }, + })) : [], + }; +} + +export function toGroupWithTasks(group: GraphQLGroup | null | undefined): GroupWithTasks | null { + if (!doesExist(group)) return null; + + return { + id: group.id, + name: group.name, + created_at: new Date(group.created_at), + updated_at: new Date(group.updated_at), + tasks: isArray(group.tasks) ? group.tasks.map(task => toTaskWithSteps(task)).filter(doesExist) : [], + }; +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index e248ab9..b5ceb27 100644 --- a/package-lock.json +++ b/package-lock.json @@ -613,6 +613,28 @@ "node": ">=14" } }, + "node_modules/@apollographql/apollo-tools": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@apollographql/apollo-tools/-/apollo-tools-0.5.4.tgz", + "integrity": "sha512-shM3q7rUbNyXVVRkQJQseXv6bnYM3BUma/eZhwXR4xsuM+bqWnJKvW7SAfRjP7LuSCocrexa5AXhjjawNHrIlw==", + "license": "MIT", + "engines": { + "node": ">=8", + "npm": ">=6" + }, + "peerDependencies": { + "graphql": "^14.2.1 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/@apollographql/graphql-playground-html": { + "version": "1.6.29", + "resolved": "https://registry.npmjs.org/@apollographql/graphql-playground-html/-/graphql-playground-html-1.6.29.tgz", + "integrity": "sha512-xCcXpoz52rI4ksJSdOCxeOCn2DLocxwHf9dVT/Q90Pte1LX+LY+91SFtJF3KXVHH8kEin+g1KKCQPKBjZJfWNA==", + "license": "MIT", + "dependencies": { + "xss": "^1.0.8" + } + }, "node_modules/@babel/code-frame": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", @@ -1971,6 +1993,21 @@ "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, + "node_modules/@graphql-tools/mock": { + "version": "8.7.20", + "resolved": "https://registry.npmjs.org/@graphql-tools/mock/-/mock-8.7.20.tgz", + "integrity": "sha512-ljcHSJWjC/ZyzpXd5cfNhPI7YljRVvabKHPzKjEs5ElxWu2cdlLGvyNYepApXDsM/OJG/2xuhGM+9GWu5gEAPQ==", + "license": "MIT", + "dependencies": { + "@graphql-tools/schema": "^9.0.18", + "@graphql-tools/utils": "^9.2.1", + "fast-json-stable-stringify": "^2.1.0", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, "node_modules/@graphql-tools/schema": { "version": "9.0.19", "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-9.0.19.tgz", @@ -2390,6 +2427,12 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@josephg/resolvable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@josephg/resolvable/-/resolvable-1.0.1.tgz", + "integrity": "sha512-CtzORUwWTTOTqfVtHaKRJ0I1kNQd1bpn3sUh8I3nJDVY+5/M/Oe1DnEWzPQvqq/xPIIkzzzIP7mfCoAjFRvDhg==", + "license": "ISC" + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", @@ -3155,6 +3198,15 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/@types/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Pay9fq2lM2wXPWbteBsRAGiWH2hig4ZE2asK+mm7kUzlxRTfL961rj89I6zV/E3PcIkDqyuBEcMxFT7rccugeQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -3754,6 +3806,446 @@ "node": ">= 8" } }, + "node_modules/apollo-datasource": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/apollo-datasource/-/apollo-datasource-3.3.2.tgz", + "integrity": "sha512-L5TiS8E2Hn/Yz7SSnWIVbZw0ZfEIXZCa5VUiVxD9P53JvSrf4aStvsFDlGWPvpIdCR+aly2CfoB79B9/JjKFqg==", + "deprecated": "The `apollo-datasource` package is part of Apollo Server v2 and v3, which are now end-of-life (as of October 22nd 2023 and October 22nd 2024, respectively). See https://www.apollographql.com/docs/apollo-server/previous-versions/ for more details.", + "license": "MIT", + "dependencies": { + "@apollo/utils.keyvaluecache": "^1.0.1", + "apollo-server-env": "^4.2.1" + }, + "engines": { + "node": ">=12.0" + } + }, + "node_modules/apollo-datasource/node_modules/@apollo/utils.keyvaluecache": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@apollo/utils.keyvaluecache/-/utils.keyvaluecache-1.0.2.tgz", + "integrity": "sha512-p7PVdLPMnPzmXSQVEsy27cYEjVON+SH/Wb7COyW3rQN8+wJgT1nv9jZouYtztWW8ZgTkii5T6tC9qfoDREd4mg==", + "license": "MIT", + "dependencies": { + "@apollo/utils.logger": "^1.0.0", + "lru-cache": "7.10.1 - 7.13.1" + } + }, + "node_modules/apollo-datasource/node_modules/@apollo/utils.logger": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@apollo/utils.logger/-/utils.logger-1.0.1.tgz", + "integrity": "sha512-XdlzoY7fYNK4OIcvMD2G94RoFZbzTQaNP0jozmqqMudmaGo2I/2Jx71xlDJ801mWA/mbYRihyaw6KJii7k5RVA==", + "license": "MIT" + }, + "node_modules/apollo-datasource/node_modules/lru-cache": { + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.13.1.tgz", + "integrity": "sha512-CHqbAq7NFlW3RSnoWXLJBxCWaZVBrfa9UEHId2M3AW8iEBurbqduNexEUCGc3SHc6iCYXNJCDi903LajSVAEPQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/apollo-reporting-protobuf": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/apollo-reporting-protobuf/-/apollo-reporting-protobuf-3.4.0.tgz", + "integrity": "sha512-h0u3EbC/9RpihWOmcSsvTW2O6RXVaD/mPEjfrPkxRPTEPWqncsgOoRJw+wih4OqfH3PvTJvoEIf4LwKrUaqWog==", + "deprecated": "The `apollo-reporting-protobuf` package is part of Apollo Server v2 and v3, which are now end-of-life (as of October 22nd 2023 and October 22nd 2024, respectively). This package's functionality is now found in the `@apollo/usage-reporting-protobuf` package. See https://www.apollographql.com/docs/apollo-server/previous-versions/ for more details.", + "license": "MIT", + "dependencies": { + "@apollo/protobufjs": "1.2.6" + } + }, + "node_modules/apollo-reporting-protobuf/node_modules/@apollo/protobufjs": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@apollo/protobufjs/-/protobufjs-1.2.6.tgz", + "integrity": "sha512-Wqo1oSHNUj/jxmsVp4iR3I480p6qdqHikn38lKrFhfzcDJ7lwd7Ck7cHRl4JE81tWNArl77xhnG/OkZhxKBYOw==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.0", + "@types/node": "^10.1.0", + "long": "^4.0.0" + }, + "bin": { + "apollo-pbjs": "bin/pbjs", + "apollo-pbts": "bin/pbts" + } + }, + "node_modules/apollo-reporting-protobuf/node_modules/@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", + "license": "MIT" + }, + "node_modules/apollo-server-core": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-3.13.0.tgz", + "integrity": "sha512-v/g6DR6KuHn9DYSdtQijz8dLOkP78I5JSVJzPkARhDbhpH74QNwrQ2PP2URAPPEDJ2EeZNQDX8PvbYkAKqg+kg==", + "deprecated": "The `apollo-server-core` package is part of Apollo Server v2 and v3, which are now end-of-life (as of October 22nd 2023 and October 22nd 2024, respectively). This package's functionality is now found in the `@apollo/server` package. See https://www.apollographql.com/docs/apollo-server/previous-versions/ for more details.", + "license": "MIT", + "dependencies": { + "@apollo/utils.keyvaluecache": "^1.0.1", + "@apollo/utils.logger": "^1.0.0", + "@apollo/utils.usagereporting": "^1.0.0", + "@apollographql/apollo-tools": "^0.5.3", + "@apollographql/graphql-playground-html": "1.6.29", + "@graphql-tools/mock": "^8.1.2", + "@graphql-tools/schema": "^8.0.0", + "@josephg/resolvable": "^1.0.0", + "apollo-datasource": "^3.3.2", + "apollo-reporting-protobuf": "^3.4.0", + "apollo-server-env": "^4.2.1", + "apollo-server-errors": "^3.3.1", + "apollo-server-plugin-base": "^3.7.2", + "apollo-server-types": "^3.8.0", + "async-retry": "^1.2.1", + "fast-json-stable-stringify": "^2.1.0", + "graphql-tag": "^2.11.0", + "loglevel": "^1.6.8", + "lru-cache": "^6.0.0", + "node-abort-controller": "^3.0.1", + "sha.js": "^2.4.11", + "uuid": "^9.0.0", + "whatwg-mimetype": "^3.0.0" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "graphql": "^15.3.0 || ^16.0.0" + } + }, + "node_modules/apollo-server-core/node_modules/@apollo/utils.dropunuseddefinitions": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@apollo/utils.dropunuseddefinitions/-/utils.dropunuseddefinitions-1.1.0.tgz", + "integrity": "sha512-jU1XjMr6ec9pPoL+BFWzEPW7VHHulVdGKMkPAMiCigpVIT11VmCbnij0bWob8uS3ODJ65tZLYKAh/55vLw2rbg==", + "license": "MIT", + "engines": { + "node": ">=12.13.0" + }, + "peerDependencies": { + "graphql": "14.x || 15.x || 16.x" + } + }, + "node_modules/apollo-server-core/node_modules/@apollo/utils.keyvaluecache": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@apollo/utils.keyvaluecache/-/utils.keyvaluecache-1.0.2.tgz", + "integrity": "sha512-p7PVdLPMnPzmXSQVEsy27cYEjVON+SH/Wb7COyW3rQN8+wJgT1nv9jZouYtztWW8ZgTkii5T6tC9qfoDREd4mg==", + "license": "MIT", + "dependencies": { + "@apollo/utils.logger": "^1.0.0", + "lru-cache": "7.10.1 - 7.13.1" + } + }, + "node_modules/apollo-server-core/node_modules/@apollo/utils.keyvaluecache/node_modules/lru-cache": { + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.13.1.tgz", + "integrity": "sha512-CHqbAq7NFlW3RSnoWXLJBxCWaZVBrfa9UEHId2M3AW8iEBurbqduNexEUCGc3SHc6iCYXNJCDi903LajSVAEPQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/apollo-server-core/node_modules/@apollo/utils.logger": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@apollo/utils.logger/-/utils.logger-1.0.1.tgz", + "integrity": "sha512-XdlzoY7fYNK4OIcvMD2G94RoFZbzTQaNP0jozmqqMudmaGo2I/2Jx71xlDJ801mWA/mbYRihyaw6KJii7k5RVA==", + "license": "MIT" + }, + "node_modules/apollo-server-core/node_modules/@apollo/utils.printwithreducedwhitespace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@apollo/utils.printwithreducedwhitespace/-/utils.printwithreducedwhitespace-1.1.0.tgz", + "integrity": "sha512-GfFSkAv3n1toDZ4V6u2d7L4xMwLA+lv+6hqXicMN9KELSJ9yy9RzuEXaX73c/Ry+GzRsBy/fdSUGayGqdHfT2Q==", + "license": "MIT", + "engines": { + "node": ">=12.13.0" + }, + "peerDependencies": { + "graphql": "14.x || 15.x || 16.x" + } + }, + "node_modules/apollo-server-core/node_modules/@apollo/utils.removealiases": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@apollo/utils.removealiases/-/utils.removealiases-1.0.0.tgz", + "integrity": "sha512-6cM8sEOJW2LaGjL/0vHV0GtRaSekrPQR4DiywaApQlL9EdROASZU5PsQibe2MWeZCOhNrPRuHh4wDMwPsWTn8A==", + "license": "MIT", + "engines": { + "node": ">=12.13.0" + }, + "peerDependencies": { + "graphql": "14.x || 15.x || 16.x" + } + }, + "node_modules/apollo-server-core/node_modules/@apollo/utils.sortast": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@apollo/utils.sortast/-/utils.sortast-1.1.0.tgz", + "integrity": "sha512-VPlTsmUnOwzPK5yGZENN069y6uUHgeiSlpEhRnLFYwYNoJHsuJq2vXVwIaSmts015WTPa2fpz1inkLYByeuRQA==", + "license": "MIT", + "dependencies": { + "lodash.sortby": "^4.7.0" + }, + "engines": { + "node": ">=12.13.0" + }, + "peerDependencies": { + "graphql": "14.x || 15.x || 16.x" + } + }, + "node_modules/apollo-server-core/node_modules/@apollo/utils.stripsensitiveliterals": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@apollo/utils.stripsensitiveliterals/-/utils.stripsensitiveliterals-1.2.0.tgz", + "integrity": "sha512-E41rDUzkz/cdikM5147d8nfCFVKovXxKBcjvLEQ7bjZm/cg9zEcXvS6vFY8ugTubI3fn6zoqo0CyU8zT+BGP9w==", + "license": "MIT", + "engines": { + "node": ">=12.13.0" + }, + "peerDependencies": { + "graphql": "14.x || 15.x || 16.x" + } + }, + "node_modules/apollo-server-core/node_modules/@apollo/utils.usagereporting": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@apollo/utils.usagereporting/-/utils.usagereporting-1.0.1.tgz", + "integrity": "sha512-6dk+0hZlnDbahDBB2mP/PZ5ybrtCJdLMbeNJD+TJpKyZmSY6bA3SjI8Cr2EM9QA+AdziywuWg+SgbWUF3/zQqQ==", + "license": "MIT", + "dependencies": { + "@apollo/usage-reporting-protobuf": "^4.0.0", + "@apollo/utils.dropunuseddefinitions": "^1.1.0", + "@apollo/utils.printwithreducedwhitespace": "^1.1.0", + "@apollo/utils.removealiases": "1.0.0", + "@apollo/utils.sortast": "^1.1.0", + "@apollo/utils.stripsensitiveliterals": "^1.2.0" + }, + "engines": { + "node": ">=12.13.0" + }, + "peerDependencies": { + "graphql": "14.x || 15.x || 16.x" + } + }, + "node_modules/apollo-server-core/node_modules/@graphql-tools/merge": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.3.1.tgz", + "integrity": "sha512-BMm99mqdNZbEYeTPK3it9r9S6rsZsQKtlqJsSBknAclXq2pGEfOxjcIZi+kBSkHZKPKCRrYDd5vY0+rUmIHVLg==", + "license": "MIT", + "dependencies": { + "@graphql-tools/utils": "8.9.0", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/apollo-server-core/node_modules/@graphql-tools/schema": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-8.5.1.tgz", + "integrity": "sha512-0Esilsh0P/qYcB5DKQpiKeQs/jevzIadNTaT0jeWklPMwNbT7yMX4EqZany7mbeRRlSRwMzNzL5olyFdffHBZg==", + "license": "MIT", + "dependencies": { + "@graphql-tools/merge": "8.3.1", + "@graphql-tools/utils": "8.9.0", + "tslib": "^2.4.0", + "value-or-promise": "1.0.11" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/apollo-server-core/node_modules/@graphql-tools/utils": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.9.0.tgz", + "integrity": "sha512-pjJIWH0XOVnYGXCqej8g/u/tsfV4LvLlj0eATKQu5zwnxd/TiTHq7Cg313qUPTFFHZ3PP5wJ15chYVtLDwaymg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/apollo-server-core/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/apollo-server-core/node_modules/value-or-promise": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/value-or-promise/-/value-or-promise-1.0.11.tgz", + "integrity": "sha512-41BrgH+dIbCFXClcSapVs5M6GkENd3gQOJpEfPDNa71LsUGMXDL0jMWpI/Rh7WhX+Aalfz2TTS3Zt5pUsbnhLg==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/apollo-server-env": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/apollo-server-env/-/apollo-server-env-4.2.1.tgz", + "integrity": "sha512-vm/7c7ld+zFMxibzqZ7SSa5tBENc4B0uye9LTfjJwGoQFY5xsUPH5FpO5j0bMUDZ8YYNbrF9SNtzc5Cngcr90g==", + "deprecated": "The `apollo-server-env` package is part of Apollo Server v2 and v3, which are now end-of-life (as of October 22nd 2023 and October 22nd 2024, respectively). This package's functionality is now found in the `@apollo/utils.fetcher` package. See https://www.apollographql.com/docs/apollo-server/previous-versions/ for more details.", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.6.7" + }, + "engines": { + "node": ">=12.0" + } + }, + "node_modules/apollo-server-errors": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/apollo-server-errors/-/apollo-server-errors-3.3.1.tgz", + "integrity": "sha512-xnZJ5QWs6FixHICXHxUfm+ZWqqxrNuPlQ+kj5m6RtEgIpekOPssH/SD9gf2B4HuWV0QozorrygwZnux8POvyPA==", + "deprecated": "The `apollo-server-errors` package is part of Apollo Server v2 and v3, which are now end-of-life (as of October 22nd 2023 and October 22nd 2024, respectively). This package's functionality is now found in the `@apollo/server` package. See https://www.apollographql.com/docs/apollo-server/previous-versions/ for more details.", + "license": "MIT", + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "graphql": "^15.3.0 || ^16.0.0" + } + }, + "node_modules/apollo-server-express": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/apollo-server-express/-/apollo-server-express-3.13.0.tgz", + "integrity": "sha512-iSxICNbDUyebOuM8EKb3xOrpIwOQgKxGbR2diSr4HP3IW8T3njKFOoMce50vr+moOCe1ev8BnLcw9SNbuUtf7g==", + "deprecated": "The `apollo-server-express` package is part of Apollo Server v2 and v3, which are now end-of-life (as of October 22nd 2023 and October 22nd 2024, respectively). This package's functionality is now found in the `@apollo/server` package. See https://www.apollographql.com/docs/apollo-server/previous-versions/ for more details.", + "license": "MIT", + "dependencies": { + "@types/accepts": "^1.3.5", + "@types/body-parser": "1.19.2", + "@types/cors": "2.8.12", + "@types/express": "4.17.14", + "@types/express-serve-static-core": "4.17.31", + "accepts": "^1.3.5", + "apollo-server-core": "^3.13.0", + "apollo-server-types": "^3.8.0", + "body-parser": "^1.19.0", + "cors": "^2.8.5", + "parseurl": "^1.3.3" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "express": "^4.17.1", + "graphql": "^15.3.0 || ^16.0.0" + } + }, + "node_modules/apollo-server-express/node_modules/@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/apollo-server-express/node_modules/@types/cors": { + "version": "2.8.12", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", + "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", + "license": "MIT" + }, + "node_modules/apollo-server-express/node_modules/@types/express": { + "version": "4.17.14", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz", + "integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==", + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/apollo-server-express/node_modules/@types/express-serve-static-core": { + "version": "4.17.31", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", + "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "node_modules/apollo-server-plugin-base": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/apollo-server-plugin-base/-/apollo-server-plugin-base-3.7.2.tgz", + "integrity": "sha512-wE8dwGDvBOGehSsPTRZ8P/33Jan6/PmL0y0aN/1Z5a5GcbFhDaaJCjK5cav6npbbGL2DPKK0r6MPXi3k3N45aw==", + "deprecated": "The `apollo-server-plugin-base` package is part of Apollo Server v2 and v3, which are now end-of-life (as of October 22nd 2023 and October 22nd 2024, respectively). This package's functionality is now found in the `@apollo/server` package. See https://www.apollographql.com/docs/apollo-server/previous-versions/ for more details.", + "license": "MIT", + "dependencies": { + "apollo-server-types": "^3.8.0" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "graphql": "^15.3.0 || ^16.0.0" + } + }, + "node_modules/apollo-server-types": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/apollo-server-types/-/apollo-server-types-3.8.0.tgz", + "integrity": "sha512-ZI/8rTE4ww8BHktsVpb91Sdq7Cb71rdSkXELSwdSR0eXu600/sY+1UXhTWdiJvk+Eq5ljqoHLwLbY2+Clq2b9A==", + "deprecated": "The `apollo-server-types` package is part of Apollo Server v2 and v3, which are now end-of-life (as of October 22nd 2023 and October 22nd 2024, respectively). This package's functionality is now found in the `@apollo/server` package. See https://www.apollographql.com/docs/apollo-server/previous-versions/ for more details.", + "license": "MIT", + "dependencies": { + "@apollo/utils.keyvaluecache": "^1.0.1", + "@apollo/utils.logger": "^1.0.0", + "apollo-reporting-protobuf": "^3.4.0", + "apollo-server-env": "^4.2.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "graphql": "^15.3.0 || ^16.0.0" + } + }, + "node_modules/apollo-server-types/node_modules/@apollo/utils.keyvaluecache": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@apollo/utils.keyvaluecache/-/utils.keyvaluecache-1.0.2.tgz", + "integrity": "sha512-p7PVdLPMnPzmXSQVEsy27cYEjVON+SH/Wb7COyW3rQN8+wJgT1nv9jZouYtztWW8ZgTkii5T6tC9qfoDREd4mg==", + "license": "MIT", + "dependencies": { + "@apollo/utils.logger": "^1.0.0", + "lru-cache": "7.10.1 - 7.13.1" + } + }, + "node_modules/apollo-server-types/node_modules/@apollo/utils.logger": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@apollo/utils.logger/-/utils.logger-1.0.1.tgz", + "integrity": "sha512-XdlzoY7fYNK4OIcvMD2G94RoFZbzTQaNP0jozmqqMudmaGo2I/2Jx71xlDJ801mWA/mbYRihyaw6KJii7k5RVA==", + "license": "MIT" + }, + "node_modules/apollo-server-types/node_modules/lru-cache": { + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.13.1.tgz", + "integrity": "sha512-CHqbAq7NFlW3RSnoWXLJBxCWaZVBrfa9UEHId2M3AW8iEBurbqduNexEUCGc3SHc6iCYXNJCDi903LajSVAEPQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", @@ -4648,6 +5140,12 @@ "node": ">= 8" } }, + "node_modules/cssfilter": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz", + "integrity": "sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==", + "license": "MIT" + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -5594,7 +6092,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, "license": "MIT" }, "node_modules/fast-levenshtein": { @@ -10591,6 +11088,28 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/xss": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/xss/-/xss-1.0.15.tgz", + "integrity": "sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==", + "license": "MIT", + "dependencies": { + "commander": "^2.20.3", + "cssfilter": "0.0.10" + }, + "bin": { + "xss": "bin/xss" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/xss/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -10698,6 +11217,7 @@ "dependencies": { "@apollo/server": "^4.10.0", "@task-receipts/shared": "file:../shared", + "apollo-server-express": "^3.13.0", "cors": "^2.8.5", "dotenv": "^16.4.5", "express": "^4.18.3", diff --git a/server/package.json b/server/package.json index 1c8ea1e..21e2e70 100644 --- a/server/package.json +++ b/server/package.json @@ -12,11 +12,15 @@ "test:coverage": "jest --coverage", "lint": "eslint . --ext .ts", "lint:fix": "eslint . --ext .ts --fix", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit", + "migrate:latest": "knex migrate:latest --knexfile src/db/knexfile.ts", + "migrate:rollback": "knex migrate:rollback --knexfile src/db/knexfile.ts", + "migrate:make": "knex migrate:make --knexfile src/db/knexfile.ts" }, "dependencies": { "@apollo/server": "^4.10.0", "@task-receipts/shared": "file:../shared", + "apollo-server-express": "^3.13.0", "cors": "^2.8.5", "dotenv": "^16.4.5", "express": "^4.18.3", diff --git a/server/src/db/knexfile.ts b/server/src/db/knexfile.ts index c5e96a9..432cda6 100644 --- a/server/src/db/knexfile.ts +++ b/server/src/db/knexfile.ts @@ -1,25 +1,26 @@ import type { Knex } from 'knex'; +import path from 'path'; const config: { [key: string]: Knex.Config } = { development: { client: 'sqlite3', connection: { - filename: './dev.sqlite3' + filename: path.join(__dirname, '../../../dev.sqlite3'), }, useNullAsDefault: true, migrations: { - directory: './src/db/migrations' - } + directory: path.join(__dirname, 'migrations'), + }, }, test: { client: 'sqlite3', connection: { - filename: ':memory:' + filename: ':memory:', }, useNullAsDefault: true, migrations: { - directory: './src/db/migrations' - } + directory: path.join(__dirname, 'migrations'), + }, }, production: { client: 'sqlite3', diff --git a/server/src/graphql/schema.ts b/server/src/graphql/schema.ts index 2f30c2a..16ba1be 100644 --- a/server/src/graphql/schema.ts +++ b/server/src/graphql/schema.ts @@ -1,70 +1,72 @@ -import { gql } from 'graphql-tag'; +import { gql } from 'apollo-server-express'; export const typeDefs = gql` type Group { id: ID! name: String! - parentId: ID + parent_id: ID tasks: [Task!]! - createdAt: String! - updatedAt: String! + created_at: String! + updated_at: String! } type Task { id: ID! name: String! - groupId: ID! + group_id: ID! group: Group! steps: [Step!]! - printCount: Int! - lastPrintedAt: String - createdAt: String! - updatedAt: String! notes: [Note!]! + print_count: Int! + last_printed_at: String printHistory: [PrintHistory!]! + created_at: String! + updated_at: String! } type Step { id: ID! name: String! instructions: String! - taskId: ID! + task_id: ID! task: Task! order: Int! - images: [Image!]! - printCount: Int! - lastPrintedAt: String - createdAt: String! - updatedAt: String! notes: [Note!]! + print_count: Int! + last_printed_at: String printHistory: [PrintHistory!]! + images: [Image!]! + created_at: String! + updated_at: String! } type Image { id: ID! - stepId: ID! - originalPath: String! - bwPath: String! + step_id: ID! + step: Step! + original_path: String! + bw_path: String! order: Int! - createdAt: String! - updatedAt: String! + created_at: String! + updated_at: String! } type User { id: ID! name: String! - createdAt: String! - updatedAt: String! + created_at: String! + updated_at: String! } type Note { id: ID! content: String! - taskId: ID - stepId: ID + step_id: ID! + step: Step! + user: User! createdBy: User! - createdAt: String! - updatedAt: String! + created_at: String! + updated_at: String! } type PrintHistory { @@ -72,9 +74,9 @@ export const typeDefs = gql` user: User! task: Task step: Step - printedAt: String! - createdAt: String! - updatedAt: String! + printed_at: String! + created_at: String! + updated_at: String! } type Query { @@ -88,7 +90,7 @@ export const typeDefs = gql` frequentTasks: [Task!]! users: [User!]! user(id: ID!): User - notes(taskId: ID, stepId: ID): [Note!]! + notes(stepId: ID!): [Note!]! printHistory(taskId: ID, stepId: ID): [PrintHistory!]! } @@ -98,8 +100,8 @@ export const typeDefs = gql` createStep(name: String!, instructions: String!, taskId: ID!, order: Int!): Step! createImage(stepId: ID!, originalPath: String!, bwPath: String!, order: Int!): Image! createUser(name: String!): User! - createNote(content: String!, taskId: ID, stepId: ID, createdBy: ID!): Note! - printTask(id: ID!, userId: ID!): Task! - printStep(id: ID!, userId: ID!): Step! + createNote(content: String!, stepId: ID!): Note! + printTask(id: ID!): Task! + printStep(id: ID!): Step! } `; \ No newline at end of file