From a0af0c1230a1dbc93a28977d6d61180319220c88 Mon Sep 17 00:00:00 2001 From: Rafa <101704572+rafaelromcar-parabol@users.noreply.github.com> Date: Thu, 15 Feb 2024 12:22:25 +0000 Subject: [PATCH 01/39] chore(env vars): Stripe vars moved to the Integrations section (#9427) --- .env.example | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.env.example b/.env.example index be16a7edd47..88cdde703de 100644 --- a/.env.example +++ b/.env.example @@ -112,6 +112,9 @@ RETHINKDB_SSL='false' # RECALL_AI_KEY='' # SLACK_CLIENT_ID='key_SLACK_CLIENT_ID' # SLACK_CLIENT_SECRET='key_SLACK_CLIENT_SECRET' +# STRIPE_SECRET_KEY='sk_test_4eC39HqLyjWDarjtT1zdp7dc' +# STRIPE_PUBLISHABLE_KEY='pk_test_TYooMQauvdEDq54NiTphI7jx' +# STRIPE_WEBHOOK_SECRET='sk_test_4eC39HqLyjWDarjtT1zdp7dc' # MAIL # MAIL GLOBALS. PROVIDER: mailgun | google | debug | smtp @@ -127,9 +130,6 @@ MAIL_PROVIDER='debug' # MAIL_SMTP_PASSWORD='key_MAIL_SMTP_PASSWORD' # MAIL_SMTP_USE_TLS='1' # set to '0' for false # MAIL_SMTP_CIPHERS='HIGH:MEDIUM:!aNULL:!eNULL:@STRENGTH:!DH:!kEDH' -# STRIPE_SECRET_KEY='sk_test_4eC39HqLyjWDarjtT1zdp7dc' -# STRIPE_PUBLISHABLE_KEY='pk_test_TYooMQauvdEDq54NiTphI7jx' -# STRIPE_WEBHOOK_SECRET='sk_test_4eC39HqLyjWDarjtT1zdp7dc' # DEVELOPER VARIABLES # CI='true' From c0a2fdf8fb3deaa34f7935ae8a87d30f43381ecd Mon Sep 17 00:00:00 2001 From: Georg Bremer Date: Fri, 16 Feb 2024 21:08:31 +0100 Subject: [PATCH 02/39] chore: fix misleading `isLead` field name on `Team` (#9413) * chore: fix misleading `isLead` field name on `Team` The field indicates whether the viewer is the lead, but when used in a query for a different user, the result could be read wrong. * Fix Team.isLead dependencies --- packages/client/components/ReviewRequestToJoinOrgModal.tsx | 2 +- .../teamDashboard/components/ManageTeam/ManageTeamList.tsx | 4 ++-- .../teamDashboard/components/TeamSettings/TeamSettings.tsx | 2 +- packages/client/mutations/PromoteToTeamLeadMutation.ts | 2 +- packages/server/graphql/public/typeDefs/Team.graphql | 2 +- packages/server/graphql/types/Team.ts | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/client/components/ReviewRequestToJoinOrgModal.tsx b/packages/client/components/ReviewRequestToJoinOrgModal.tsx index 25c2bde8de0..2604455e6f6 100644 --- a/packages/client/components/ReviewRequestToJoinOrgModal.tsx +++ b/packages/client/components/ReviewRequestToJoinOrgModal.tsx @@ -21,7 +21,7 @@ const ReviewRequestToJoinOrgModalViewerFragment = graphql` teams { id name - isLead + isViewerLead teamMembers(sortBy: "preferredName") { userId } diff --git a/packages/client/modules/teamDashboard/components/ManageTeam/ManageTeamList.tsx b/packages/client/modules/teamDashboard/components/ManageTeam/ManageTeamList.tsx index a8e8933820e..7ed7de48036 100644 --- a/packages/client/modules/teamDashboard/components/ManageTeam/ManageTeamList.tsx +++ b/packages/client/modules/teamDashboard/components/ManageTeam/ManageTeamList.tsx @@ -25,7 +25,7 @@ const ManageTeamList = (props: Props) => { const team = useFragment( graphql` fragment ManageTeamList_team on Team { - isLead + isViewerLead isOrgAdmin teamMembers(sortBy: "preferredName") { id @@ -36,7 +36,7 @@ const ManageTeamList = (props: Props) => { `, props.team ) - const {isLead: isViewerLead, isOrgAdmin: isViewerOrgAdmin, teamMembers} = team + const {isViewerLead, isOrgAdmin: isViewerOrgAdmin, teamMembers} = team return ( {teamMembers.map((teamMember) => { diff --git a/packages/client/modules/teamDashboard/components/TeamSettings/TeamSettings.tsx b/packages/client/modules/teamDashboard/components/TeamSettings/TeamSettings.tsx index 829308b0006..62ffb8f934f 100644 --- a/packages/client/modules/teamDashboard/components/TeamSettings/TeamSettings.tsx +++ b/packages/client/modules/teamDashboard/components/TeamSettings/TeamSettings.tsx @@ -43,7 +43,7 @@ const query = graphql` viewer { team(teamId: $teamId) { ...ArchiveTeam_team - isLead + isViewerLead id name tier diff --git a/packages/client/mutations/PromoteToTeamLeadMutation.ts b/packages/client/mutations/PromoteToTeamLeadMutation.ts index c47310341c2..af3325b1808 100644 --- a/packages/client/mutations/PromoteToTeamLeadMutation.ts +++ b/packages/client/mutations/PromoteToTeamLeadMutation.ts @@ -5,7 +5,7 @@ import {PromoteToTeamLeadMutation as TPromoteToTeamLeadMutation} from '../__gene graphql` fragment PromoteToTeamLeadMutation_team on PromoteToTeamLeadPayload { team { - isLead + isViewerLead } oldLeader { ...DashboardAvatar_teamMember diff --git a/packages/server/graphql/public/typeDefs/Team.graphql b/packages/server/graphql/public/typeDefs/Team.graphql index 6a6d00c4c76..6e95b1c602f 100644 --- a/packages/server/graphql/public/typeDefs/Team.graphql +++ b/packages/server/graphql/public/typeDefs/Team.graphql @@ -86,7 +86,7 @@ type Team { """ true if the viewer is the team lead, else false """ - isLead: Boolean! + isViewerLead: Boolean! """ true if the viewer is an admin for the team's org, else false diff --git a/packages/server/graphql/types/Team.ts b/packages/server/graphql/types/Team.ts index 6c161bbcb35..7d737ad98b1 100644 --- a/packages/server/graphql/types/Team.ts +++ b/packages/server/graphql/types/Team.ts @@ -142,7 +142,7 @@ const Team: GraphQLObjectType = new GraphQLObjectType({ return dataLoader.get('teamInvitationsByTeamId').load(teamId) } }, - isLead: { + isViewerLead: { type: new GraphQLNonNull(GraphQLBoolean), description: 'true if the viewer is the team lead, else false', resolve: async ( From f042628fef5bbdbf566c49bab729f5b9dec058f1 Mon Sep 17 00:00:00 2001 From: Nick O'Ferrall Date: Mon, 19 Feb 2024 17:51:59 +0000 Subject: [PATCH 03/39] feat: remove team template limit (#9424) * update error message and increase template limit * remove max team template limits * remove canClone prop from CloneTemplate * remove unused threshold * remove unused threshold --- .../ActivityDetails/TemplateDetails.tsx | 2 +- .../CreateNewActivity/CreateNewActivity.tsx | 34 +------------------ .../components/AddNewPokerTemplate.tsx | 14 +------- .../components/AddNewReflectTemplate.tsx | 11 +----- .../meeting/components/CloneTemplate.tsx | 9 ++--- .../components/PokerTemplateDetails.tsx | 7 ++-- .../components/ReflectTemplateDetails.tsx | 7 ++-- packages/client/types/constEnums.ts | 2 -- .../graphql/mutations/addPokerTemplate.ts | 5 +-- .../graphql/mutations/addReflectTemplate.ts | 5 +-- 10 files changed, 13 insertions(+), 83 deletions(-) diff --git a/packages/client/components/ActivityLibrary/ActivityDetails/TemplateDetails.tsx b/packages/client/components/ActivityLibrary/ActivityDetails/TemplateDetails.tsx index 0c2b77bef15..b86554fb3ef 100644 --- a/packages/client/components/ActivityLibrary/ActivityDetails/TemplateDetails.tsx +++ b/packages/client/components/ActivityLibrary/ActivityDetails/TemplateDetails.tsx @@ -267,7 +267,7 @@ export const TemplateDetails = (props: Props) => { />
- +
)} diff --git a/packages/client/components/ActivityLibrary/CreateNewActivity/CreateNewActivity.tsx b/packages/client/components/ActivityLibrary/CreateNewActivity/CreateNewActivity.tsx index 2967f5ab866..8346b47a252 100644 --- a/packages/client/components/ActivityLibrary/CreateNewActivity/CreateNewActivity.tsx +++ b/packages/client/components/ActivityLibrary/CreateNewActivity/CreateNewActivity.tsx @@ -4,14 +4,11 @@ import graphql from 'babel-plugin-relay/macro' import * as RadioGroup from '@radix-ui/react-radio-group' import clsx from 'clsx' import {Link} from 'react-router-dom' - import newTemplate from '../../../../../static/images/illustrations/newTemplate.png' import estimatedEffortTemplate from '../../../../../static/images/illustrations/estimatedEffortTemplate.png' - import {CreateNewActivityQuery} from '~/__generated__/CreateNewActivityQuery.graphql' import {ActivityCard, ActivityCardImage} from '../ActivityCard' import {ActivityBadge} from '../ActivityBadge' - import IconLabel from '../../IconLabel' import NewMeetingTeamPicker from '../../NewMeetingTeamPicker' import sortByTier from '../../../utils/sortByTier' @@ -20,7 +17,6 @@ import {AddReflectTemplateMutation$data} from '../../../__generated__/AddReflect import useAtmosphere from '../../../hooks/useAtmosphere' import useMutationProps from '../../../hooks/useMutationProps' import AddReflectTemplateMutation from '../../../mutations/AddReflectTemplateMutation' -import {Threshold} from '../../../types/constEnums' import useRouter from '../../../hooks/useRouter' import {CATEGORY_ID_TO_NAME, CATEGORY_THEMES, CategoryID, DEFAULT_CARD_THEME} from '../Categories' import BaseButton from '../../BaseButton' @@ -111,15 +107,6 @@ const query = graphql` ...NewMeetingTeamPicker_selectedTeam ...NewMeetingTeamPicker_teams } - availableTemplates(first: 2000) @connection(key: "ActivityLibrary_availableTemplates") { - edges { - node { - name - teamId - type - } - } - } } } ` @@ -148,7 +135,7 @@ export const CreateNewActivity = (props: Props) => { return selectedActivity }) const {viewer} = data - const {teams, availableTemplates, preferredTeamId, featureFlags} = viewer + const {teams, preferredTeamId, featureFlags} = viewer const [selectedTeam, setSelectedTeam] = useState( teams.find((team) => team.id === preferredTeamId) ?? sortByTier(teams)[0]! ) @@ -160,16 +147,6 @@ export const CreateNewActivity = (props: Props) => { return } - const teamTemplates = availableTemplates.edges.filter( - (template) => - template.node.teamId === selectedTeam.id && template.node.type === 'retrospective' - ) - - if (teamTemplates.length >= Threshold.MAX_RETRO_TEAM_TEMPLATES) { - onError(new Error('You may only have 20 templates per team. Please remove one first.')) - return - } - submitMutation() AddReflectTemplateMutation( atmosphere, @@ -195,15 +172,6 @@ export const CreateNewActivity = (props: Props) => { return } - const teamTemplates = availableTemplates.edges.filter( - (template) => template.node.teamId === selectedTeam.id && template.node.type === 'poker' - ) - - if (teamTemplates.length >= Threshold.MAX_POKER_TEAM_TEMPLATES) { - onError(new Error('You may only have 20 templates per team. Please remove one first.')) - return - } - submitMutation() AddPokerTemplateMutation( atmosphere, diff --git a/packages/client/modules/meeting/components/AddNewPokerTemplate.tsx b/packages/client/modules/meeting/components/AddNewPokerTemplate.tsx index 766c85dccee..053684315a3 100644 --- a/packages/client/modules/meeting/components/AddNewPokerTemplate.tsx +++ b/packages/client/modules/meeting/components/AddNewPokerTemplate.tsx @@ -7,7 +7,6 @@ import TooltipStyled from '../../../components/TooltipStyled' import useAtmosphere from '../../../hooks/useAtmosphere' import useMutationProps from '../../../hooks/useMutationProps' import AddPokerTemplateMutation from '../../../mutations/AddPokerTemplateMutation' -import {Threshold} from '../../../types/constEnums' import {AddNewPokerTemplate_pokerTemplates$key} from '../../../__generated__/AddNewPokerTemplate_pokerTemplates.graphql' import {AddNewPokerTemplate_team$key} from '../../../__generated__/AddNewPokerTemplate_team.graphql' @@ -79,17 +78,6 @@ const AddNewPokerTemplate = (props: Props) => { displayUpgradeDetails() return } - if (pokerTemplates.length >= Threshold.MAX_RETRO_TEAM_TEMPLATES) { - onError( - new Error( - `You may only have ${Threshold.MAX_RETRO_TEAM_TEMPLATES} templates per team. Please remove one first.` - ) - ) - errorTimerId.current = window.setTimeout(() => { - onCompleted() - }, 8000) - return - } if (pokerTemplates.find((template) => template.name.startsWith('*New Template'))) { onError(new Error('You already have a new template. Try renaming that one first.')) errorTimerId.current = window.setTimeout(() => { @@ -106,7 +94,7 @@ const AddNewPokerTemplate = (props: Props) => { template.name.startsWith('*New Template') ) - if (pokerTemplates.length > Threshold.MAX_POKER_TEAM_TEMPLATES || containsNewTemplate) return null + if (containsNewTemplate) return null return (
{error && {error.message}} diff --git a/packages/client/modules/meeting/components/AddNewReflectTemplate.tsx b/packages/client/modules/meeting/components/AddNewReflectTemplate.tsx index eea0c89ab03..61429332903 100644 --- a/packages/client/modules/meeting/components/AddNewReflectTemplate.tsx +++ b/packages/client/modules/meeting/components/AddNewReflectTemplate.tsx @@ -7,7 +7,6 @@ import TooltipStyled from '../../../components/TooltipStyled' import useAtmosphere from '../../../hooks/useAtmosphere' import useMutationProps from '../../../hooks/useMutationProps' import AddReflectTemplateMutation from '../../../mutations/AddReflectTemplateMutation' -import {Threshold} from '../../../types/constEnums' import {AddNewReflectTemplate_reflectTemplates$key} from '../../../__generated__/AddNewReflectTemplate_reflectTemplates.graphql' import {AddNewReflectTemplate_team$key} from '../../../__generated__/AddNewReflectTemplate_team.graphql' @@ -79,13 +78,6 @@ const AddNewReflectTemplate = (props: Props) => { displayUpgradeDetails() return } - if (reflectTemplates.length >= Threshold.MAX_RETRO_TEAM_TEMPLATES) { - onError(new Error('You may only have 20 templates per team. Please remove one first.')) - errorTimerId.current = window.setTimeout(() => { - onCompleted() - }, 8000) - return - } if (reflectTemplates.find((template) => template.name.startsWith('*New Template'))) { onError(new Error('You already have a new template. Try renaming that one first.')) errorTimerId.current = window.setTimeout(() => { @@ -102,8 +94,7 @@ const AddNewReflectTemplate = (props: Props) => { template.name.startsWith('*New Template') ) - if (reflectTemplates.length > Threshold.MAX_RETRO_TEAM_TEMPLATES || containsNewTemplate) - return null + if (containsNewTemplate) return null return (
{error && {error.message}} diff --git a/packages/client/modules/meeting/components/CloneTemplate.tsx b/packages/client/modules/meeting/components/CloneTemplate.tsx index 66cc6cc7d3e..6fbc5a1460a 100644 --- a/packages/client/modules/meeting/components/CloneTemplate.tsx +++ b/packages/client/modules/meeting/components/CloneTemplate.tsx @@ -2,15 +2,12 @@ import React from 'react' import DetailAction from '../../../components/DetailAction' interface Props { - canClone: boolean onClick: () => void } const CloneTemplate = (props: Props) => { - const {canClone, onClick} = props - const tooltip = canClone ? 'Clone & Edit Template' : 'Too many team templates! Remove one first' - return ( - - ) + const {onClick} = props + const tooltip = 'Clone & Edit Template' + return } export default CloneTemplate diff --git a/packages/client/modules/meeting/components/PokerTemplateDetails.tsx b/packages/client/modules/meeting/components/PokerTemplateDetails.tsx index 3dcb51ec48a..c42794d1508 100644 --- a/packages/client/modules/meeting/components/PokerTemplateDetails.tsx +++ b/packages/client/modules/meeting/components/PokerTemplateDetails.tsx @@ -6,7 +6,6 @@ import useAtmosphere from '../../../hooks/useAtmosphere' import useMutationProps from '../../../hooks/useMutationProps' import AddPokerTemplateMutation from '../../../mutations/AddPokerTemplateMutation' import {PALETTE} from '../../../styles/paletteV3' -import {Threshold} from '../../../types/constEnums' import getTemplateList from '../../../utils/getTemplateList' import useTemplateDescription from '../../../utils/useTemplateDescription' import {PokerTemplateDetails_settings$key} from '../../../__generated__/PokerTemplateDetails_settings.graphql' @@ -108,12 +107,10 @@ const PokerTemplateDetails = (props: Props) => { const lowestScope = getTemplateList(teamId, orgId, activeTemplate) const isOwner = activeTemplate.teamId === teamId const description = useTemplateDescription(lowestScope, activeTemplate, tier) - const templateCount = teamTemplates.length const atmosphere = useAtmosphere() const {onError, onCompleted, submitting, submitMutation} = useMutationProps() - const canClone = templateCount < Threshold.MAX_POKER_TEAM_TEMPLATES const onClone = () => { - if (submitting || !canClone) return + if (submitting) return submitMutation() AddPokerTemplateMutation( atmosphere, @@ -145,7 +142,7 @@ const PokerTemplateDetails = (props: Props) => { type='poker' /> )} - {showClone && } + {showClone && } {description} diff --git a/packages/client/modules/meeting/components/ReflectTemplateDetails.tsx b/packages/client/modules/meeting/components/ReflectTemplateDetails.tsx index dec65509954..2d45402d52e 100644 --- a/packages/client/modules/meeting/components/ReflectTemplateDetails.tsx +++ b/packages/client/modules/meeting/components/ReflectTemplateDetails.tsx @@ -6,7 +6,6 @@ import useAtmosphere from '../../../hooks/useAtmosphere' import useMutationProps from '../../../hooks/useMutationProps' import AddReflectTemplateMutation from '../../../mutations/AddReflectTemplateMutation' import {PALETTE} from '../../../styles/paletteV3' -import {Threshold} from '../../../types/constEnums' import getTemplateList from '../../../utils/getTemplateList' import useTemplateDescription from '../../../utils/useTemplateDescription' import {ReflectTemplateDetails_settings$key} from '../../../__generated__/ReflectTemplateDetails_settings.graphql' @@ -116,12 +115,10 @@ const ReflectTemplateDetails = (props: Props) => { const lowestScope = getTemplateList(teamId, orgId, activeTemplate) const isOwner = activeTemplate.teamId === teamId const description = useTemplateDescription(lowestScope, activeTemplate, tier) - const templateCount = teamTemplates.length const atmosphere = useAtmosphere() const {onError, onCompleted, submitting, submitMutation} = useMutationProps() - const canClone = templateCount < Threshold.MAX_RETRO_TEAM_TEMPLATES const onClone = () => { - if (submitting || !canClone) return + if (submitting) return submitMutation() AddReflectTemplateMutation( atmosphere, @@ -153,7 +150,7 @@ const ReflectTemplateDetails = (props: Props) => { type='retrospective' /> )} - {showClone && } + {showClone && } {description} diff --git a/packages/client/types/constEnums.ts b/packages/client/types/constEnums.ts index fe42a13d6be..28bbd744b85 100644 --- a/packages/client/types/constEnums.ts +++ b/packages/client/types/constEnums.ts @@ -397,8 +397,6 @@ export const enum Threshold { MAX_POKER_TEMPLATE_SCALES = 12, MAX_POKER_SCALE_VALUES = 30, POKER_SCALE_VALUE_MAX_LENGTH = 3, - MAX_RETRO_TEAM_TEMPLATES = 20, - MAX_POKER_TEAM_TEMPLATES = 20, MAX_POKER_DIMENSION_NAME = 50, MAX_QUAL_AI_MEETINGS = 3, MAX_REACTJIS = 12, diff --git a/packages/server/graphql/mutations/addPokerTemplate.ts b/packages/server/graphql/mutations/addPokerTemplate.ts index ec470279865..3b4e6dbccc0 100644 --- a/packages/server/graphql/mutations/addPokerTemplate.ts +++ b/packages/server/graphql/mutations/addPokerTemplate.ts @@ -1,5 +1,5 @@ import {GraphQLID, GraphQLNonNull} from 'graphql' -import {SprintPokerDefaults, SubscriptionChannel, Threshold} from 'parabol-client/types/constEnums' +import {SprintPokerDefaults, SubscriptionChannel} from 'parabol-client/types/constEnums' import getRethink from '../../database/rethinkDriver' import PokerTemplate from '../../database/types/PokerTemplate' import TemplateDimension from '../../database/types/TemplateDimension' @@ -45,9 +45,6 @@ const addPokerTemplate = { dataLoader.get('teams').load(teamId), dataLoader.get('users').loadNonNull(viewerId) ]) - if (allTemplates.length >= Threshold.MAX_RETRO_TEAM_TEMPLATES) { - return standardError(new Error('Too many templates'), {userId: viewerId}) - } if (!viewerTeam) { return standardError(new Error('Team not found'), {userId: viewerId}) diff --git a/packages/server/graphql/mutations/addReflectTemplate.ts b/packages/server/graphql/mutations/addReflectTemplate.ts index 46c91713490..d4c3825338a 100644 --- a/packages/server/graphql/mutations/addReflectTemplate.ts +++ b/packages/server/graphql/mutations/addReflectTemplate.ts @@ -1,5 +1,5 @@ import {GraphQLID, GraphQLNonNull} from 'graphql' -import {SubscriptionChannel, Threshold} from 'parabol-client/types/constEnums' +import {SubscriptionChannel} from 'parabol-client/types/constEnums' import {PALETTE} from '../../../client/styles/paletteV3' import getRethink from '../../database/rethinkDriver' import ReflectTemplate from '../../database/types/ReflectTemplate' @@ -47,9 +47,6 @@ const addReflectTemplate = { dataLoader.get('users').loadNonNull(viewerId) ]) - if (allTemplates.length >= Threshold.MAX_RETRO_TEAM_TEMPLATES) { - return standardError(new Error('Too many templates'), {userId: viewerId}) - } if (!viewerTeam) { return standardError(new Error('Team not found'), {userId: viewerId}) } From 02dc6fa6e4687021bb46a6774eb5f0be859e4d3f Mon Sep 17 00:00:00 2001 From: Georg Bremer Date: Tue, 20 Feb 2024 10:56:57 +0100 Subject: [PATCH 04/39] feat: Add Google calendar meeting series for recurrence (#9380) * feat: Add recurrence to GCal events * Fun with timezones --- .../mutations/helpers/createGcalEvent.ts | 80 ++++++++++++++++--- .../public/mutations/startRetrospective.ts | 18 ++++- .../mutations/updateRecurrenceSettings.ts | 26 ++++++ packages/server/package.json | 1 + ...06021181176_addGCalEventToMeetingSeries.ts | 22 +++++ yarn.lock | 8 +- 6 files changed, 141 insertions(+), 14 deletions(-) create mode 100644 packages/server/postgres/migrations/1706021181176_addGCalEventToMeetingSeries.ts diff --git a/packages/server/graphql/mutations/helpers/createGcalEvent.ts b/packages/server/graphql/mutations/helpers/createGcalEvent.ts index 6e936a13cab..4382ca7dedd 100644 --- a/packages/server/graphql/mutations/helpers/createGcalEvent.ts +++ b/packages/server/graphql/mutations/helpers/createGcalEvent.ts @@ -3,23 +3,41 @@ import makeAppURL from 'parabol-client/utils/makeAppURL' import appOrigin from '../../../appOrigin' import {DataLoaderWorker} from '../../graphql' import standardError from '../../../utils/standardError' -import {CreateGcalEventInput} from '../../public/resolverTypes' +import {CreateGcalEventInput, StandardMutationError} from '../../public/resolverTypes' +import {RRule} from 'rrule' +import {pick} from 'lodash' const emailRemindMinsBeforeMeeting = 24 * 60 const popupRemindMinsBeforeMeeting = 10 +const convertRruleToGcal = (rrule: RRule | null | undefined) => { + if (!rrule) { + return [] + } + + // Google does not allow for all fields in rrule. For example DTSTART and DTEND are not allowed. + // It also has trouble with BYHOUR, BYMINUTE, and BYSECOND. It's best to stick to fields known to work. + // Also strip TZID as google wants the UNTIL field in Z, but rrule only uses that if no TZID is present. + const options = pick(rrule.options, 'freq', 'interval', 'byweekday', 'until', 'count') + const gcalRule = new RRule(options) + return [gcalRule.toString()] +} + type Input = { gcalInput?: CreateGcalEventInput | null meetingId: string viewerId: string teamId: string + rrule?: RRule | null dataLoader: DataLoaderWorker } -const createGcalEvent = async (input: Input) => { - const {gcalInput, meetingId, viewerId, dataLoader, teamId} = input +const createGcalEvent = async ( + input: Input +): Promise<{gcalSeriesId?: string; error?: StandardMutationError}> => { + const {gcalInput, meetingId, viewerId, dataLoader, teamId, rrule} = input if (!gcalInput) { - return {error: null} + return {} } const {startTimestamp, endTimestamp, title, timeZone, invitees, videoType} = gcalInput @@ -57,8 +75,9 @@ const createGcalEvent = async (input: Input) => { } } : undefined + const recurrence = convertRruleToGcal(rrule) - const event = { + const eventInput = { summary: title, description, start: { @@ -69,6 +88,7 @@ const createGcalEvent = async (input: Input) => { dateTime: endDateTime, timeZone }, + recurrence, attendees: attendeesWithEmailObjects, reminders: { useDefault: false, @@ -81,17 +101,59 @@ const createGcalEvent = async (input: Input) => { } try { - await calendar.events.insert({ + const event = await calendar.events.insert({ calendarId: 'primary', - requestBody: event, + requestBody: eventInput, conferenceDataVersion: 1 }) + return {gcalSeriesId: event.data.id ?? undefined} } catch (err) { const error = err instanceof Error ? err : new Error('Unable to create event in gcal') return standardError(error, {userId: viewerId}) } - return { - error: null +} + +export type UpdateGcalSeriesInput = { + gcalSeriesId: string + title?: string + rrule: RRule | null + userId: string + teamId: string + dataLoader: DataLoaderWorker +} +export const updateGcalSeries = async (input: UpdateGcalSeriesInput) => { + const {gcalSeriesId, title, rrule, userId, teamId, dataLoader} = input + + const gcalAuth = await dataLoader.get('freshGcalAuth').load({teamId, userId}) + if (!gcalAuth) { + return standardError(new Error('Could not retrieve Google Calendar auth'), {userId}) + } + const {accessToken: access_token, refreshToken: refresh_token, expiresAt} = gcalAuth + const CLIENT_ID = process.env.GOOGLE_OAUTH_CLIENT_ID + const CLIENT_SECRET = process.env.GOOGLE_OAUTH_CLIENT_SECRET + const REDIRECT_URI = appOrigin + + const expiry_date = expiresAt ? expiresAt.getTime() : undefined + + const oauth2Client = new google.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI) + oauth2Client.setCredentials({access_token, refresh_token, expiry_date}) + const calendar = google.calendar({version: 'v3', auth: oauth2Client}) + const recurrence = convertRruleToGcal(rrule) + + try { + const event = await calendar.events.patch({ + calendarId: 'primary', + eventId: gcalSeriesId, + requestBody: { + recurrence, + summary: title + }, + conferenceDataVersion: 1 + }) + return {gcalSeriesId: event.data.id ?? undefined} + } catch (err) { + const error = err instanceof Error ? err : new Error('Unable to create event in gcal') + return standardError(error, {userId}) } } diff --git a/packages/server/graphql/public/mutations/startRetrospective.ts b/packages/server/graphql/public/mutations/startRetrospective.ts index 29583f3d755..266664368c1 100644 --- a/packages/server/graphql/public/mutations/startRetrospective.ts +++ b/packages/server/graphql/public/mutations/startRetrospective.ts @@ -16,6 +16,7 @@ import {IntegrationNotifier} from '../../mutations/helpers/notifications/Integra import {startNewMeetingSeries} from './updateRecurrenceSettings' import safeCreateRetrospective from '../../mutations/helpers/safeCreateRetrospective' import {createMeetingSeriesTitle} from '../../mutations/helpers/createMeetingSeriesTitle' +import getKysely from '../../../postgres/getKysely' const startRetrospective: MutationResolvers['startRetrospective'] = async ( _source, @@ -118,7 +119,22 @@ const startRetrospective: MutationResolvers['startRetrospective'] = async ( } IntegrationNotifier.startMeeting(dataLoader, meetingId, teamId) analytics.meetingStarted(viewer, meeting, template) - const {error} = await createGcalEvent({gcalInput, meetingId, teamId, viewerId, dataLoader}) + const {error, gcalSeriesId} = await createGcalEvent({ + gcalInput, + meetingId, + teamId, + viewerId, + rrule: recurrenceSettings?.rrule, + dataLoader + }) + if (meetingSeries && gcalSeriesId) { + const pg = getKysely() + await pg + .updateTable('MeetingSeries') + .set({gcalSeriesId}) + .where('id', '=', meetingSeries.id) + .execute() + } const data = {teamId, meetingId, hasGcalError: !!error?.message} publish(SubscriptionChannel.TEAM, teamId, 'StartRetrospectiveSuccess', data, subOptions) return data diff --git a/packages/server/graphql/public/mutations/updateRecurrenceSettings.ts b/packages/server/graphql/public/mutations/updateRecurrenceSettings.ts index 335e08a1e84..daee90b7d61 100644 --- a/packages/server/graphql/public/mutations/updateRecurrenceSettings.ts +++ b/packages/server/graphql/public/mutations/updateRecurrenceSettings.ts @@ -12,6 +12,7 @@ import publish from '../../../utils/publish' import standardError from '../../../utils/standardError' import {MutationResolvers} from '../resolverTypes' import {MeetingTypeEnum} from '../../../postgres/types/Meeting' +import {updateGcalSeries} from '../../mutations/helpers/createGcalEvent' export const startNewMeetingSeries = async ( meeting: { @@ -111,6 +112,16 @@ const stopMeetingSeries = async (meetingSeries: MeetingSeries) => { .run() } +const updateGCalRecurrenceRule = (oldRule: RRule, newRule: RRule | null | undefined) => { + if (!newRule) { + return new RRule({ + ...oldRule.options, + until: new Date() + }) + } + return newRule +} + const updateRecurrenceSettings: MutationResolvers['updateRecurrenceSettings'] = async ( _source, {meetingId, recurrenceSettings}, @@ -138,6 +149,7 @@ const updateRecurrenceSettings: MutationResolvers['updateRecurrenceSettings'] = if (meeting.meetingSeriesId) { const meetingSeries = await dataLoader.get('meetingSeries').loadNonNull(meeting.meetingSeriesId) + const {gcalSeriesId, teamId, facilitatorId, recurrenceRule} = meetingSeries if (!recurrenceSettings.rrule) { await stopMeetingSeries(meetingSeries) @@ -146,6 +158,20 @@ const updateRecurrenceSettings: MutationResolvers['updateRecurrenceSettings'] = await updateMeetingSeries(meetingSeries, recurrenceSettings.rrule) analytics.recurrenceStarted(viewer, meetingSeries) } + if (gcalSeriesId) { + const rrule = updateGCalRecurrenceRule( + RRule.fromString(recurrenceRule), + recurrenceSettings.rrule + ) + await updateGcalSeries({ + gcalSeriesId, + title: recurrenceSettings.name ?? undefined, + rrule, + teamId, + userId: facilitatorId, + dataLoader + }) + } if (recurrenceSettings.name) { await updateMeetingSeriesQuery({title: recurrenceSettings.name}, meetingSeries.id) diff --git a/packages/server/package.json b/packages/server/package.json index ddd4076d65c..1fdd28cfd74 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -112,6 +112,7 @@ "ioredis": "^5.2.3", "jsdom": "^20.0.0", "jsonwebtoken": "^9.0.0", + "lodash.pick": "^4.4.0", "mailcomposer": "^4.0.1", "mailgun.js": "^9.3.0", "mime-types": "^2.1.16", diff --git a/packages/server/postgres/migrations/1706021181176_addGCalEventToMeetingSeries.ts b/packages/server/postgres/migrations/1706021181176_addGCalEventToMeetingSeries.ts new file mode 100644 index 00000000000..919dda62a87 --- /dev/null +++ b/packages/server/postgres/migrations/1706021181176_addGCalEventToMeetingSeries.ts @@ -0,0 +1,22 @@ +import {Client} from 'pg' +import getPgConfig from '../getPgConfig' + +export async function up() { + const client = new Client(getPgConfig()) + await client.connect() + await client.query(` + ALTER TABLE "MeetingSeries" + ADD COLUMN IF NOT EXISTS "gcalSeriesId" VARCHAR(100); + `) + await client.end() +} + +export async function down() { + const client = new Client(getPgConfig()) + await client.connect() + await client.query(` + ALTER TABLE "MeetingSeries" + DROP COLUMN IF EXISTS "gcalSeriesId"; + `) + await client.end() +} diff --git a/yarn.lock b/yarn.lock index 50e12881143..c08a4168a24 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9012,9 +9012,9 @@ camelcase@^6.2.0: integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== caniuse-lite@^1.0.30001426, caniuse-lite@^1.0.30001517, caniuse-lite@~1.0.0: - version "1.0.30001584" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001584.tgz#5e3ea0625d048d5467670051687655b1f7bf7dfd" - integrity sha512-LOz7CCQ9M1G7OjJOF9/mzmqmj3jE/7VOmrfw6Mgs0E8cjOsbRXQJHsPBfmBOXDskXKrHLyyW3n7kpDW/4BsfpQ== + version "1.0.30001587" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001587.tgz#a0bce920155fa56a1885a69c74e1163fc34b4881" + integrity sha512-HMFNotUmLXn71BQxg8cijvqxnIAofforZOwGsxyXJ0qugTdspUF4sPSJ2vhgprHCB996tIDzEq1ubumPDV8ULA== capital-case@^1.0.4: version "1.0.4" @@ -14573,7 +14573,7 @@ lodash.mergewith@4.6.2: lodash.pick@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" - integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM= + integrity sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q== lodash.setwith@^4.3.2: version "4.3.2" From b0b76f9f45789f60b55243f78eba7b656c751658 Mon Sep 17 00:00:00 2001 From: Georg Bremer Date: Tue, 20 Feb 2024 10:57:18 +0100 Subject: [PATCH 05/39] fix: Increase the number of projects fetched per request from Atlassian (#9435) We ran into timeouts in `getAllProjects`, presumably because we're doing too many roundtrips. As a quick fix, increse the number of projects fetched per request from 50 to 500. --- packages/server/utils/AtlassianServerManager.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/server/utils/AtlassianServerManager.ts b/packages/server/utils/AtlassianServerManager.ts index d3ed48c166a..dcc29a4a3b9 100644 --- a/packages/server/utils/AtlassianServerManager.ts +++ b/packages/server/utils/AtlassianServerManager.ts @@ -387,6 +387,7 @@ class AtlassianServerManager extends AtlassianManager { })) projects.push(...pagedProjects) if (res.nextPage) { + log('AtlassianServerManager.getAllProjects fetching more results', res.total) return getProjectPage(cloudId, res.nextPage) } } @@ -395,7 +396,7 @@ class AtlassianServerManager extends AtlassianManager { cloudIds.map((cloudId) => getProjectPage( cloudId, - `https://api.atlassian.com/ex/jira/${cloudId}/rest/api/3/project/search?orderBy=name` + `https://api.atlassian.com/ex/jira/${cloudId}/rest/api/3/project/search?orderBy=name&maxResults=500` ) ) ) From c2a31e6b8ef2c4f4d375323f8afbef6874024593 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Feb 2024 10:33:32 -0800 Subject: [PATCH 06/39] chore(deps): bump ip from 1.1.8 to 1.1.9 (#9442) Bumps [ip](https://github.com/indutny/node-ip) from 1.1.8 to 1.1.9. - [Commits](https://github.com/indutny/node-ip/compare/v1.1.8...v1.1.9) --- updated-dependencies: - dependency-name: ip dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/yarn.lock b/yarn.lock index c08a4168a24..99d793dc367 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12892,14 +12892,14 @@ ioredis@^5.2.3: standard-as-callback "^2.1.0" ip@^1.1.5, ip@^1.1.8: - version "1.1.8" - resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.8.tgz#ae05948f6b075435ed3307acce04629da8cdbf48" - integrity sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg== + version "1.1.9" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.9.tgz#8dfbcc99a754d07f425310b86a99546b1151e396" + integrity sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ== ip@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" - integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== + version "2.0.1" + resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105" + integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ== ipaddr.js@1.9.1: version "1.9.1" From e4a831ad5e76a16c930ffee7ffe412577040a894 Mon Sep 17 00:00:00 2001 From: "parabol-release-bot[bot]" <150284312+parabol-release-bot[bot]@users.noreply.github.com> Date: Thu, 22 Feb 2024 17:51:53 +0100 Subject: [PATCH 07/39] chore(release): release v7.17.0 (#9428) Co-authored-by: parabol-release-bot[bot] <150284312+parabol-release-bot[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- CHANGELOG.md | 20 ++++++++++++++++++++ package.json | 2 +- packages/chronos/package.json | 4 ++-- packages/client/package.json | 2 +- packages/gql-executor/package.json | 6 +++--- packages/integration-tests/package.json | 2 +- packages/server/package.json | 4 ++-- 8 files changed, 31 insertions(+), 11 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 2dcd7403b8b..0fb11cbd996 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "7.16.0" + ".": "7.17.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 3de62f10fbe..fd68e143309 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,26 @@ This project adheres to [Semantic Versioning](http://semver.org/). This CHANGELOG follows conventions [outlined here](http://keepachangelog.com/). +## [7.17.0](https://github.com/ParabolInc/parabol/compare/v7.16.0...v7.17.0) (2024-02-21) + + +### Added + +* Add Google calendar meeting series for recurrence ([#9380](https://github.com/ParabolInc/parabol/issues/9380)) ([02dc6fa](https://github.com/ParabolInc/parabol/commit/02dc6fa6e4687021bb46a6774eb5f0be859e4d3f)) +* remove team template limit ([#9424](https://github.com/ParabolInc/parabol/issues/9424)) ([f042628](https://github.com/ParabolInc/parabol/commit/f042628fef5bbdbf566c49bab729f5b9dec058f1)) + + +### Fixed + +* Increase the number of projects fetched per request from Atlassian ([#9435](https://github.com/ParabolInc/parabol/issues/9435)) ([b0b76f9](https://github.com/ParabolInc/parabol/commit/b0b76f9f45789f60b55243f78eba7b656c751658)) + + +### Changed + +* **deps:** bump ip from 1.1.8 to 1.1.9 ([#9442](https://github.com/ParabolInc/parabol/issues/9442)) ([c2a31e6](https://github.com/ParabolInc/parabol/commit/c2a31e6b8ef2c4f4d375323f8afbef6874024593)) +* **env vars:** Stripe vars moved to the Integrations section ([#9427](https://github.com/ParabolInc/parabol/issues/9427)) ([a0af0c1](https://github.com/ParabolInc/parabol/commit/a0af0c1230a1dbc93a28977d6d61180319220c88)) +* fix misleading `isLead` field name on `Team` ([#9413](https://github.com/ParabolInc/parabol/issues/9413)) ([c0a2fdf](https://github.com/ParabolInc/parabol/commit/c0a2fdf8fb3deaa34f7935ae8a87d30f43381ecd)) + ## [7.16.0](https://github.com/ParabolInc/parabol/compare/v7.15.2...v7.16.0) (2024-02-14) diff --git a/package.json b/package.json index cc585b841d9..edde1656431 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.16.0", + "version": "7.17.0", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" diff --git a/packages/chronos/package.json b/packages/chronos/package.json index 1bc7dbf47ef..5295ced9dd0 100644 --- a/packages/chronos/package.json +++ b/packages/chronos/package.json @@ -1,6 +1,6 @@ { "name": "chronos", - "version": "7.16.0", + "version": "7.17.0", "description": "A cron job scheduler", "author": "Matt Krick ", "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/chronos#readme", @@ -25,6 +25,6 @@ }, "dependencies": { "cron": "^2.3.1", - "parabol-server": "7.16.0" + "parabol-server": "7.17.0" } } diff --git a/packages/client/package.json b/packages/client/package.json index 2f4c9cec77d..9faef2216e4 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.16.0", + "version": "7.17.0", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" diff --git a/packages/gql-executor/package.json b/packages/gql-executor/package.json index 519e5f91834..1675bcaf5ea 100644 --- a/packages/gql-executor/package.json +++ b/packages/gql-executor/package.json @@ -1,6 +1,6 @@ { "name": "gql-executor", - "version": "7.16.0", + "version": "7.17.0", "description": "A Stateless GraphQL Executor", "author": "Matt Krick ", "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/gqlExecutor#readme", @@ -27,8 +27,8 @@ }, "dependencies": { "dd-trace": "^4.2.0", - "parabol-client": "7.16.0", - "parabol-server": "7.16.0", + "parabol-client": "7.17.0", + "parabol-server": "7.17.0", "undici": "^5.26.2" } } diff --git a/packages/integration-tests/package.json b/packages/integration-tests/package.json index 90e1da55dfc..0190f526ea8 100644 --- a/packages/integration-tests/package.json +++ b/packages/integration-tests/package.json @@ -2,7 +2,7 @@ "name": "integration-tests", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.16.0", + "version": "7.17.0", "description": "", "main": "index.js", "scripts": { diff --git a/packages/server/package.json b/packages/server/package.json index 1fdd28cfd74..c1bde9cbe3f 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.16.0", + "version": "7.17.0", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" @@ -124,7 +124,7 @@ "oauth-1.0a": "^2.2.6", "openai": "^4.24.1", "oy-vey": "^0.11.0", - "parabol-client": "7.16.0", + "parabol-client": "7.17.0", "pg": "^8.5.1", "react": "^17.0.2", "react-dom": "^17.0.2", From 61ba015c8310a72b7e89c64be081cd2f399fc721 Mon Sep 17 00:00:00 2001 From: Rafa <101704572+rafaelromcar-parabol@users.noreply.github.com> Date: Thu, 22 Feb 2024 22:52:30 +0000 Subject: [PATCH 08/39] feat(standalone-deployment): Standalone host deployment improved and documented (#9445) * Docker compose stack improved * Remove unused containers from docker-compse and add useful comment on .env.example about PGSSLMODE * Docker compose profiles added. Documentation extended on how to use the profiles to manage the stack. * README fixed as docker compose up and down commands were not working * Typo fixed and docker-compose command replaced by docker compose --- .../parabol-ubi/docker-host-st/.env.example | 1 + docker/parabol-ubi/docker-host-st/README.md | 33 +++- .../docker-host-st/docker-compose.yaml | 156 +++++++++++++++--- .../parabol-ubi/docker-host-st/postgres.conf | 1 - 4 files changed, 166 insertions(+), 25 deletions(-) delete mode 100644 docker/parabol-ubi/docker-host-st/postgres.conf diff --git a/docker/parabol-ubi/docker-host-st/.env.example b/docker/parabol-ubi/docker-host-st/.env.example index 82c7b2b7e29..9eadf7108e5 100644 --- a/docker/parabol-ubi/docker-host-st/.env.example +++ b/docker/parabol-ubi/docker-host-st/.env.example @@ -1 +1,2 @@ # See https://github.com/ParabolInc/parabol/blob/master/.env.example +# DO NOT SET PGSSLMODE to an empty value. Postgres will not be able to start. diff --git a/docker/parabol-ubi/docker-host-st/README.md b/docker/parabol-ubi/docker-host-st/README.md index c743187aa1d..af3a0b244ec 100644 --- a/docker/parabol-ubi/docker-host-st/README.md +++ b/docker/parabol-ubi/docker-host-st/README.md @@ -1,15 +1,42 @@ # Docker Host Single Tenant (ST) -To run the Parabol UBI in single tenant mode (e.g. simple docker-compose on a docker host). +To run Parabol in single tenant mode (e.g. simple docker-compose on a docker host). 1. Build your Parabol UBI using instructions in `docker/ubi/docker-build/README.md` 2. Create a working `.env` from `.env.example` 3. Update docker-compose.yaml `image: #image:tag` with your built image tag from `step (1.)` -4. Run `docker-compose up -d` to deploy the local stack. You can run `docker-compose down` to terminate the local stack -5. Check logs via command `docker logs -app-1` and wait for the following output to appear +4. Run `docker compose --profile databases --profile parabol up -d` to deploy the local stack. You can run `docker compose --profile databases --profile parabol down` to terminate the local stack +5. Check logs via command `docker logs -f` and wait for the following output to appear ```shell 🔥🔥🔥 Server ID: 0. Ready for Sockets: Port 3000 🔥🔥🔥 💧💧💧 Server ID: 0. Ready for GraphQL Execution 💧💧💧 💧💧💧 Server ID: 01. Ready for GraphQL Execution 💧💧💧 ``` + +## Upgrade Parabol version + +1. Edit the `docker-compose.yaml` and change the `#image:tag` changing the tag. Ex: from `v7.15.0` to `v7.15.2`. +2. (optional) In a different terminal, run `docker compose logs -f` to follow the upgrade. +3. Run `docker compose --profile databases --profile parabol up -d`. It will start the `pre-deploy` and, once it is done successfully, then it will stop and recreate the `web-server` and `gql-executor` with the new version of the image. **This step implies a downtime**. +4. Verify the application is still up and running. + +## Running Chronos + +Chronos isn't started by default. If it needs to run, it must be managed using `docker compose --profile databases --profile parabol --profile chronos up`. + +This will run `pre-deploy` and thus it will recreate the `web-server` and the `gql-executor`. + +## Database debug + +Some tools are available to debug the databases is needed: + +- pgadmin +- redis-commander + +To operate them use `docker compose up --profile databases --profile database-debug`. + +## Running the whole stack + +- Start the whole stack: `docker compose --profile databases --profile parabol --profile database-debug --profile chronos up -d`. +- Stop the stack: `docker compose --profile databases --profile parabol --profile database-debug --profile chronos down` diff --git a/docker/parabol-ubi/docker-host-st/docker-compose.yaml b/docker/parabol-ubi/docker-host-st/docker-compose.yaml index c7ff752a95b..52bb8c76a7d 100644 --- a/docker/parabol-ubi/docker-host-st/docker-compose.yaml +++ b/docker/parabol-ubi/docker-host-st/docker-compose.yaml @@ -1,51 +1,165 @@ -version: '3.7' +version: '3.9' services: - db: - image: rethinkdb:latest + postgres: + container_name: postgres + profiles: ["databases"] + image: postgres:15.4 + restart: always + env_file: .env + environment: + - PGUSER=$POSTGRES_USER + ports: + - '5432:5432' + volumes: + - './data/postgres/pgdata:/var/lib/postgresql/data' + healthcheck: + test: ["CMD-SHELL", "pg_isready", "-d", "$POSTGRES_DB", "-U", "$POSTGRES_USER"] + interval: 10s + timeout: 5s + retries: 5 + networks: + - parabol-network + pgadmin: + profiles: ["database-debug"] + container_name: pgadmin + image: dpage/pgadmin4:8.3 + depends_on: + postgres: + condition: service_healthy + env_file: .env + ports: + - "5050:80" + networks: + - parabol-network + rethinkdb: + container_name: rethinkdb + profiles: ["databases"] + image: rethinkdb:2.4.2 restart: always ports: - '8080:8080' - '29015:29015' - '28015:28015' volumes: - - ./rethink-data:/data + - ./data/rethink:/data networks: - parabol-network - postgres: - image: postgres:15.4 + redis: + container_name: redis + profiles: ["databases"] + image: redis:7.0-alpine + healthcheck: + test: "[ $$(redis-cli ping) = 'PONG' ]" + interval: 10s + timeout: 5s + retries: 5 restart: always - env_file: .env ports: - - '5432:5432' + - '6379:6379' volumes: - - './postgres.conf:/usr/local/etc/postgres/postgres.conf' - - './postgres-data/pgdata:/var/lib/postgresql/data' - command: 'postgres -c config_file=/usr/local/etc/postgres/postgres.conf' + - ./data/redis:/data networks: - parabol-network - redis: - image: redis + redis-commander: + profiles: ["database-debug"] + container_name: redis-commander + image: ghcr.io/joeferner/redis-commander:0.8.1 + depends_on: + redis: + condition: service_healthy restart: always + environment: + - REDIS_HOSTS=local:redis:6379 ports: - - '6379:6379' + - "8081:8081" + networks: + - parabol-network + pre-deploy: + container_name: pre-deploy + profiles: ["parabol"] + image: us-central1-docker.pkg.dev/prbl-tooling/parabol-production/parabol:v7.15.2 + command: bash -c "node dist/preDeploy.js" + env_file: .env + environment: + - SERVER_ID=0 volumes: - - ./redis-data:/data + - './.env:/parabol/.env' + depends_on: + rethinkdb: + condition: service_started + postgres: + condition: service_healthy + redis: + condition: service_healthy networks: - parabol-network - app: - image: #image:tag + chronos: + container_name: chronos + profiles: ["chronos"] + image: us-central1-docker.pkg.dev/prbl-tooling/parabol-production/parabol:v7.15.2 restart: always + command: bash -c "node dist/chronos.js" env_file: .env - command: bash -c "yarn predeploy && NODE_ENV=production && yarn start" + environment: + - SERVER_ID=1 + volumes: + - './.env:/parabol/.env' + depends_on: + pre-deploy: + condition: service_completed_successfully + rethinkdb: + condition: service_started + postgres: + condition: service_healthy + redis: + condition: service_healthy + networks: + - parabol-network + web-server: + container_name: web-server + profiles: ["parabol"] + image: us-central1-docker.pkg.dev/prbl-tooling/parabol-production/parabol:v7.15.2 + restart: always + command: bash -c "node dist/web.js" + env_file: .env + environment: + - SERVER_ID=5 ports: - '3000:3000' volumes: - './.env:/parabol/.env' depends_on: - - db - - redis - - postgres + pre-deploy: + condition: service_completed_successfully + rethinkdb: + condition: service_started + postgres: + condition: service_healthy + redis: + condition: service_healthy + networks: + - parabol-network + gql-executor: + container_name: gql-executor + profiles: ["parabol"] + image: us-central1-docker.pkg.dev/prbl-tooling/parabol-production/parabol:v7.15.2 + restart: always + command: bash -c "node dist/gqlExecutor.js" + env_file: .env + environment: + - SERVER_ID=10 + volumes: + - './.env:/parabol/.env' + depends_on: + pre-deploy: + condition: service_completed_successfully + rethinkdb: + condition: service_started + postgres: + condition: service_healthy + redis: + condition: service_healthy networks: - parabol-network networks: diff --git a/docker/parabol-ubi/docker-host-st/postgres.conf b/docker/parabol-ubi/docker-host-st/postgres.conf deleted file mode 100644 index 3357fd28574..00000000000 --- a/docker/parabol-ubi/docker-host-st/postgres.conf +++ /dev/null @@ -1 +0,0 @@ -listen_addresses='*' \ No newline at end of file From 92ab5be298ceb19ca8718c67a0c9da8728b6b0bf Mon Sep 17 00:00:00 2001 From: Matt Krick Date: Mon, 26 Feb 2024 12:23:28 -0800 Subject: [PATCH 09/39] feat: support env-defined saml issuer for PPMIs (#9455) * feat: support env-defined saml issuer for PPMIs Signed-off-by: Matt Krick * feat: support single SAML for entire tenant Signed-off-by: Matt Krick --------- Signed-off-by: Matt Krick --- .env.example | 2 ++ .../SAMLHelpers/getURLWithSAMLRequestParam.ts | 3 ++- packages/server/utils/getSAMLURLFromEmail.ts | 20 +++++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index 88cdde703de..25c9a9c856e 100644 --- a/.env.example +++ b/.env.example @@ -14,6 +14,8 @@ SOCKET_PORT='3001' # INVITATION_SHORTLINK='example.com' # If true, all new orgs will default to being enterprise tier. Use for PPMIs # IS_ENTERPRISE=false +# PPMI single tenant use only. Will set the SAML issuer to this value. +# SAML_ISSUER='' # AUTHENTICATION # AUTH_INTERNAL_DISABLED='false' diff --git a/packages/server/graphql/public/mutations/helpers/SAMLHelpers/getURLWithSAMLRequestParam.ts b/packages/server/graphql/public/mutations/helpers/SAMLHelpers/getURLWithSAMLRequestParam.ts index bf80ce33ac4..d3fa3b7e98f 100644 --- a/packages/server/graphql/public/mutations/helpers/SAMLHelpers/getURLWithSAMLRequestParam.ts +++ b/packages/server/graphql/public/mutations/helpers/SAMLHelpers/getURLWithSAMLRequestParam.ts @@ -2,13 +2,14 @@ import {v4 as uuid} from 'uuid' import zlib from 'zlib' const getURLWithSAMLRequestParam = (destination: string, slug: string) => { + const issuer = process.env.SAML_ISSUER || `https://${process.env.HOST}/saml-metadata/${slug}` const template = ` - https://${process.env.HOST}/saml-metadata/${slug} + ${issuer} ` diff --git a/packages/server/utils/getSAMLURLFromEmail.ts b/packages/server/utils/getSAMLURLFromEmail.ts index a2e3fc65e11..2c07d74a06d 100644 --- a/packages/server/utils/getSAMLURLFromEmail.ts +++ b/packages/server/utils/getSAMLURLFromEmail.ts @@ -2,6 +2,13 @@ import base64url from 'base64url' import getSSODomainFromEmail from 'parabol-client/utils/getSSODomainFromEmail' import {URL} from 'url' import {DataLoaderWorker} from '../graphql/graphql' +import getKysely from '../postgres/getKysely' + +const isSingleTenantSSO = + process.env.AUTH_INTERNAL_DISABLED === 'true' && + process.env.AUTH_GOOGLE_DISABLED === 'true' && + process.env.AUTH_MICROSOFT_DISABLED === 'true' && + process.env.AUTH_SSO_DISABLED === 'false' const urlWithRelayState = (url: string, isInvited?: boolean | null) => { if (!isInvited) return url @@ -18,6 +25,19 @@ const getSAMLURLFromEmail = async ( ) => { const domainName = getSSODomainFromEmail(email) if (!domainName) return null + if (isSingleTenantSSO) { + // For PPMI use + const pg = getKysely() + const instanceURLres = await pg + .selectFrom('SAML') + .select('url') + .where('url', 'is not', null) + .limit(1) + .executeTakeFirst() + const instanceURL = instanceURLres?.url + if (!instanceURL) return null + return urlWithRelayState(instanceURL, isInvited) + } const saml = await dataLoader.get('samlByDomain').load(domainName) if (!saml) return null const {url} = saml From c77925b1c0e07afc428022008143b8b7f4002280 Mon Sep 17 00:00:00 2001 From: Georg Bremer Date: Tue, 27 Feb 2024 11:09:26 +0100 Subject: [PATCH 10/39] chore: Associate logs with traces (#9444) * chore: Associate logs with traces Add trace information to log output for server side log statements. This does not include logging from code exclusively used for debugging, deploying or development. * Actually add the logger * Fix DD_LOGS_INJECTION check --- .../server/billing/helpers/adjustUserCount.ts | 3 +- .../billing/helpers/terminateSubscription.ts | 3 +- .../server/dataloader/azureDevOpsLoaders.ts | 15 ++++---- packages/server/fileStorage/GCSManager.ts | 3 +- .../server/graphql/mutations/endCheckIn.ts | 3 +- .../graphql/mutations/endSprintPoker.ts | 3 +- .../helpers/activatePrevSlackAuth.ts | 3 +- .../mutations/helpers/generateGroups.ts | 5 +-- .../mutations/helpers/getCCFromCustomer.ts | 3 +- .../mutations/helpers/removeFromOrg.ts | 3 +- .../helpers/resolveDowngradeToStarter.ts | 3 +- .../mutations/helpers/safeEndRetrospective.ts | 3 +- .../mutations/helpers/safeEndTeamPrompt.ts | 3 +- .../server/graphql/mutations/moveTeamToOrg.ts | 3 +- .../graphql/mutations/navigateMeeting.ts | 3 +- .../graphql/mutations/selectTemplate.ts | 3 +- .../updateAzureDevOpsDimensionField.ts | 5 +-- .../mutations/updateGitHubDimensionField.ts | 3 +- .../private/mutations/autopauseUsers.ts | 3 +- .../private/mutations/connectSocket.ts | 3 +- .../private/mutations/runScheduledJobs.ts | 7 ++-- .../mutations/acceptRequestToJoinDomain.ts | 3 +- .../mutations/updateGitLabDimensionField.ts | 3 +- .../graphql/public/types/TeamHealthStage.ts | 3 +- .../queries/helpers/fetchGitHubRepos.ts | 3 +- .../queries/helpers/fetchGitLabProjects.ts | 3 +- .../server/graphql/types/NewMeetingStage.ts | 3 +- packages/server/graphql/types/PokerMeeting.ts | 3 +- .../upsertAzureDevOpsDimensionFieldMap.ts | 3 +- .../safeMutations/acceptTeamInvitation.ts | 3 +- packages/server/safetyPatchRes.ts | 17 ++++----- .../server/utils/AtlassianServerManager.ts | 28 +++------------ packages/server/utils/Logger.ts | 35 +++++++++++++++++++ packages/server/utils/OpenAIServerManager.ts | 5 +-- .../server/utils/RecallAIServerManager.ts | 3 +- packages/server/utils/StaticServer.ts | 3 +- packages/server/utils/publish.ts | 3 +- packages/server/utils/stripe/StripeManager.ts | 3 +- 38 files changed, 130 insertions(+), 77 deletions(-) create mode 100644 packages/server/utils/Logger.ts diff --git a/packages/server/billing/helpers/adjustUserCount.ts b/packages/server/billing/helpers/adjustUserCount.ts index b7cf07df1a5..15c440c2834 100644 --- a/packages/server/billing/helpers/adjustUserCount.ts +++ b/packages/server/billing/helpers/adjustUserCount.ts @@ -14,6 +14,7 @@ import handleEnterpriseOrgQuantityChanges from './handleEnterpriseOrgQuantityCha import handleTeamOrgQuantityChanges from './handleTeamOrgQuantityChanges' import {getUserById} from '../../postgres/queries/getUsersByIds' import {DataLoaderWorker} from '../../graphql/graphql' +import {Logger} from '../../utils/Logger' const maybeUpdateOrganizationActiveDomain = async ( orgId: string, @@ -170,5 +171,5 @@ export default async function adjustUserCount( .run() handleEnterpriseOrgQuantityChanges(paidOrgs, dataLoader).catch() - handleTeamOrgQuantityChanges(paidOrgs).catch(console.error) + handleTeamOrgQuantityChanges(paidOrgs).catch(Logger.error) } diff --git a/packages/server/billing/helpers/terminateSubscription.ts b/packages/server/billing/helpers/terminateSubscription.ts index b5fdd8a8070..0b1c6d3f4c5 100644 --- a/packages/server/billing/helpers/terminateSubscription.ts +++ b/packages/server/billing/helpers/terminateSubscription.ts @@ -1,5 +1,6 @@ import getRethink from '../../database/rethinkDriver' import Organization from '../../database/types/Organization' +import {Logger} from '../../utils/Logger' import {getStripeManager} from '../../utils/stripe' const terminateSubscription = async (orgId: string) => { @@ -30,7 +31,7 @@ const terminateSubscription = async (orgId: string) => { try { await manager.deleteSubscription(stripeSubscriptionId) } catch (e) { - console.error(`cannot delete subscription ${stripeSubscriptionId}`, e) + Logger.error(`cannot delete subscription ${stripeSubscriptionId}`, e) } } return stripeSubscriptionId diff --git a/packages/server/dataloader/azureDevOpsLoaders.ts b/packages/server/dataloader/azureDevOpsLoaders.ts index 2c9a2b4617f..7892bce6f13 100644 --- a/packages/server/dataloader/azureDevOpsLoaders.ts +++ b/packages/server/dataloader/azureDevOpsLoaders.ts @@ -13,6 +13,7 @@ import AzureDevOpsServerManager, { TeamProjectReference, WorkItem } from '../utils/AzureDevOpsServerManager' +import {Logger} from '../utils/Logger' import sendToSentry from '../utils/sendToSentry' import RootDataLoader from './RootDataLoader' @@ -215,7 +216,7 @@ export const azureDevOpsAllWorkItems = ( const {error, workItems} = restResult if (error !== undefined || workItems === undefined) { - console.log(error) + Logger.log(error) return [] as AzureDevOpsWorkItem[] } @@ -264,7 +265,7 @@ export const azureDevUserInfo = ( const restResult = await manager.getMe() const {error, azureDevOpsUser} = restResult if (error !== undefined || azureDevOpsUser === undefined) { - console.log(error) + Logger.log(error) return undefined } return { @@ -303,7 +304,7 @@ export const allAzureDevOpsAccessibleOrgs = ( const results = await manager.getAccessibleOrgs(id) const {error, accessibleOrgs} = results // handle error if defined - console.log(error) + Logger.log(error) return accessibleOrgs.map((resource) => ({ ...resource })) @@ -340,7 +341,7 @@ export const allAzureDevOpsProjects = ( ) const {error, projects} = await manager.getAllUserProjects() if (error !== undefined) { - console.log(error) + Logger.log(error) return [] } if (projects !== null) resultReferences.push(...projects) @@ -383,7 +384,7 @@ export const azureDevOpsProject = ( ) const projectRes = await manager.getProject(instanceId, projectId) if (projectRes instanceof Error) { - console.log(projectRes) + Logger.log(projectRes) return null } return { @@ -475,7 +476,7 @@ export const azureDevOpsUserStory = ( const restResult = await manager.getWorkItemData(instanceId, workItemIds) const {error, workItems} = restResult if (error !== undefined || workItems.length !== 1 || !workItems[0]) { - console.log(error) + Logger.log(error) return null } else { const returnedWorkItem: WorkItem = workItems[0] @@ -637,7 +638,7 @@ export const azureDevOpsWorkItems = ( const workItemData = await manager.getWorkItemData(instanceId, workItemIds) const {error: workItemDataError, workItems: returnedWorkItems} = workItemData if (workItemDataError !== undefined) { - console.log(error) + Logger.log(error) return [] } diff --git a/packages/server/fileStorage/GCSManager.ts b/packages/server/fileStorage/GCSManager.ts index 0a2a6a2dba9..a3a1cb4d03e 100644 --- a/packages/server/fileStorage/GCSManager.ts +++ b/packages/server/fileStorage/GCSManager.ts @@ -1,6 +1,7 @@ import {sign} from 'jsonwebtoken' import mime from 'mime-types' import path from 'path' +import {Logger} from '../utils/Logger' import FileStoreManager from './FileStoreManager' interface CloudKey { @@ -132,7 +133,7 @@ export default class GCSManager extends FileStoreManager { // https://github.com/nodejs/undici/issues/583#issuecomment-1577475664 // GCS will cause undici to error randomly with `SocketError: other side closed` `code: 'UND_ERR_SOCKET'` if ((e as any).cause?.code === 'UND_ERR_SOCKET') { - console.log(' Retrying GCS Post:', fullPath) + Logger.log(' Retrying GCS Post:', fullPath) await this.putFile(file, fullPath) } } diff --git a/packages/server/graphql/mutations/endCheckIn.ts b/packages/server/graphql/mutations/endCheckIn.ts index 53f7a0325c2..e009f7351c2 100644 --- a/packages/server/graphql/mutations/endCheckIn.ts +++ b/packages/server/graphql/mutations/endCheckIn.ts @@ -16,6 +16,7 @@ import removeSuggestedAction from '../../safeMutations/removeSuggestedAction' import {analytics} from '../../utils/analytics/analytics' import {getUserId, isTeamMember} from '../../utils/authorization' import getPhase from '../../utils/getPhase' +import {Logger} from '../../utils/Logger' import publish from '../../utils/publish' import standardError from '../../utils/standardError' import {DataLoaderWorker, GQLContext} from '../graphql' @@ -230,7 +231,7 @@ export default { const updatedTaskIds = (result && result.updatedTaskIds) || [] analytics.checkInEnd(completedCheckIn, meetingMembers, team, dataLoader) - sendNewMeetingSummary(completedCheckIn, context).catch(console.log) + sendNewMeetingSummary(completedCheckIn, context).catch(Logger.log) checkTeamsLimit(team.orgId, dataLoader) const events = teamMembers.map( diff --git a/packages/server/graphql/mutations/endSprintPoker.ts b/packages/server/graphql/mutations/endSprintPoker.ts index 220a9d90aa7..21d18816b99 100644 --- a/packages/server/graphql/mutations/endSprintPoker.ts +++ b/packages/server/graphql/mutations/endSprintPoker.ts @@ -20,6 +20,7 @@ import sendNewMeetingSummary from './helpers/endMeeting/sendNewMeetingSummary' import {IntegrationNotifier} from './helpers/notifications/IntegrationNotifier' import removeEmptyTasks from './helpers/removeEmptyTasks' import updateTeamInsights from './helpers/updateTeamInsights' +import {Logger} from '../../utils/Logger' export default { type: new GraphQLNonNull(EndSprintPokerPayload), @@ -114,7 +115,7 @@ export default { analytics.sprintPokerEnd(completedMeeting, meetingMembers, template, dataLoader) const isKill = !!(phase && phase.phaseType !== 'ESTIMATE') if (!isKill) { - sendNewMeetingSummary(completedMeeting, context).catch(console.log) + sendNewMeetingSummary(completedMeeting, context).catch(Logger.log) checkTeamsLimit(team.orgId, dataLoader) } const events = teamMembers.map( diff --git a/packages/server/graphql/mutations/helpers/activatePrevSlackAuth.ts b/packages/server/graphql/mutations/helpers/activatePrevSlackAuth.ts index b2e39709458..030d4a30446 100644 --- a/packages/server/graphql/mutations/helpers/activatePrevSlackAuth.ts +++ b/packages/server/graphql/mutations/helpers/activatePrevSlackAuth.ts @@ -2,6 +2,7 @@ import ms from 'ms' import getRethink from '../../../database/rethinkDriver' import SlackServerManager from '../../../utils/SlackServerManager' import {upsertNotifications} from '../addSlackAuth' +import {Logger} from '../../../utils/Logger' const activatePrevSlackAuth = async (userId: string, teamId: string) => { const r = await getRethink() @@ -29,7 +30,7 @@ const activatePrevSlackAuth = async (userId: string, teamId: string) => { const manager = new SlackServerManager(botAccessToken) const authRes = await manager.isValidAuthToken(botAccessToken) if (!authRes.ok) { - console.error(authRes.error) + Logger.error(authRes.error) return } diff --git a/packages/server/graphql/mutations/helpers/generateGroups.ts b/packages/server/graphql/mutations/helpers/generateGroups.ts index 6d5e972e3b6..f487119ecc0 100644 --- a/packages/server/graphql/mutations/helpers/generateGroups.ts +++ b/packages/server/graphql/mutations/helpers/generateGroups.ts @@ -6,6 +6,7 @@ import {AutogroupReflectionGroupType} from '../../../database/types/MeetingRetro import {SubscriptionChannel} from '../../../../client/types/constEnums' import publish from '../../../utils/publish' import {analytics} from '../../../utils/analytics/analytics' +import {Logger} from '../../../utils/Logger' const generateGroups = async ( reflections: Reflection[], @@ -24,13 +25,13 @@ const generateGroups = async ( const themes = await manager.generateThemes(groupReflectionsInput) if (!themes) { - console.warn('ChatGPT was unable to generate themes') + Logger.warn('ChatGPT was unable to generate themes') return } const groupedReflections = await manager.groupReflections(groupReflectionsInput, themes) if (!groupedReflections) { - console.warn('ChatGPT was unable to group the reflections') + Logger.warn('ChatGPT was unable to group the reflections') return } const autogroupReflectionGroups: AutogroupReflectionGroupType[] = [] diff --git a/packages/server/graphql/mutations/helpers/getCCFromCustomer.ts b/packages/server/graphql/mutations/helpers/getCCFromCustomer.ts index fe6add91d77..de2bdf41696 100644 --- a/packages/server/graphql/mutations/helpers/getCCFromCustomer.ts +++ b/packages/server/graphql/mutations/helpers/getCCFromCustomer.ts @@ -1,6 +1,7 @@ import Stripe from 'stripe' import {getStripeManager} from '../../../utils/stripe' import {stripeCardToDBCard} from './stripeCardToDBCard' +import {Logger} from '../../../utils/Logger' export default async function getCCFromCustomer( customer: Stripe.Customer | Stripe.DeletedCustomer @@ -16,7 +17,7 @@ export default async function getCCFromCustomer( // customers that used Stripe Elements have default_payment_method: https://stripe.com/docs/payments/payment-methods/transitioning?locale=en-GB const cardRes = await manager.retrieveDefaultCardDetails(customer.id) if (cardRes instanceof Error) { - console.error(cardRes) + Logger.error(cardRes) return undefined } return stripeCardToDBCard(cardRes) diff --git a/packages/server/graphql/mutations/helpers/removeFromOrg.ts b/packages/server/graphql/mutations/helpers/removeFromOrg.ts index 3f0efabca2d..6d2747e227b 100644 --- a/packages/server/graphql/mutations/helpers/removeFromOrg.ts +++ b/packages/server/graphql/mutations/helpers/removeFromOrg.ts @@ -8,6 +8,7 @@ import {DataLoaderWorker} from '../../graphql' import removeTeamMember from './removeTeamMember' import resolveDowngradeToStarter from './resolveDowngradeToStarter' import {RDatum} from '../../../database/stricterR' +import {Logger} from '../../../utils/Logger' const removeFromOrg = async ( userId: string, @@ -93,7 +94,7 @@ const removeFromOrg = async ( try { await adjustUserCount(userId, orgId, InvoiceItemType.REMOVE_USER, dataLoader) } catch (e) { - console.log(e) + Logger.log(e) } await setUserTierForUserIds([userId]) return { diff --git a/packages/server/graphql/mutations/helpers/resolveDowngradeToStarter.ts b/packages/server/graphql/mutations/helpers/resolveDowngradeToStarter.ts index e2ebb39d476..ce82907ecfb 100644 --- a/packages/server/graphql/mutations/helpers/resolveDowngradeToStarter.ts +++ b/packages/server/graphql/mutations/helpers/resolveDowngradeToStarter.ts @@ -3,6 +3,7 @@ import Organization from '../../../database/types/Organization' import getKysely from '../../../postgres/getKysely' import updateTeamByOrgId from '../../../postgres/queries/updateTeamByOrgId' import {analytics} from '../../../utils/analytics/analytics' +import {Logger} from '../../../utils/Logger' import setTierForOrgUsers from '../../../utils/setTierForOrgUsers' import setUserTierForOrgId from '../../../utils/setUserTierForOrgId' import {getStripeManager} from '../../../utils/stripe' @@ -22,7 +23,7 @@ const resolveDowngradeToStarter = async ( try { await manager.deleteSubscription(stripeSubscriptionId) } catch (e) { - console.log(e) + Logger.log(e) } const [org] = await Promise.all([ diff --git a/packages/server/graphql/mutations/helpers/safeEndRetrospective.ts b/packages/server/graphql/mutations/helpers/safeEndRetrospective.ts index 7890e47ef07..cd116c65ea8 100644 --- a/packages/server/graphql/mutations/helpers/safeEndRetrospective.ts +++ b/packages/server/graphql/mutations/helpers/safeEndRetrospective.ts @@ -29,6 +29,7 @@ import removeEmptyTasks from './removeEmptyTasks' import updateQualAIMeetingsCount from './updateQualAIMeetingsCount' import gatherInsights from './gatherInsights' import NotificationMentioned from '../../../database/types/NotificationMentioned' +import {Logger} from '../../../utils/Logger' const getTranscription = async (recallBotId?: string | null) => { if (!recallBotId) return @@ -245,7 +246,7 @@ const summarizeRetroMeeting = async (meeting: MeetingRetrospective, context: Int dataLoader.get('newMeetings').clear(meetingId) // wait for whole meeting summary to be generated before sending summary email and updating qualAIMeetingCount - sendNewMeetingSummary(meeting, context).catch(console.log) + sendNewMeetingSummary(meeting, context).catch(Logger.log) updateQualAIMeetingsCount(meetingId, teamId, dataLoader) // wait for meeting stats to be generated before sending Slack notification IntegrationNotifier.endMeeting(dataLoader, meetingId, teamId) diff --git a/packages/server/graphql/mutations/helpers/safeEndTeamPrompt.ts b/packages/server/graphql/mutations/helpers/safeEndTeamPrompt.ts index 5b58f178a87..e8e6f1b6cb5 100644 --- a/packages/server/graphql/mutations/helpers/safeEndTeamPrompt.ts +++ b/packages/server/graphql/mutations/helpers/safeEndTeamPrompt.ts @@ -14,6 +14,7 @@ import updateTeamInsights from './updateTeamInsights' import generateStandupMeetingSummary from './generateStandupMeetingSummary' import updateQualAIMeetingsCount from './updateQualAIMeetingsCount' import gatherInsights from './gatherInsights' +import {Logger} from '../../../utils/Logger' const summarizeTeamPrompt = async (meeting: MeetingTeamPrompt, context: InternalContext) => { const {dataLoader} = context @@ -31,7 +32,7 @@ const summarizeTeamPrompt = async (meeting: MeetingTeamPrompt, context: Internal dataLoader.get('newMeetings').clear(meeting.id) // wait for whole meeting summary to be generated before sending summary email and updating qualAIMeetingCount - sendNewMeetingSummary(meeting, context).catch(console.log) + sendNewMeetingSummary(meeting, context).catch(Logger.log) updateQualAIMeetingsCount(meeting.id, meeting.teamId, dataLoader) // wait for meeting stats to be generated before sending Slack notification IntegrationNotifier.endMeeting(dataLoader, meeting.id, meeting.teamId) diff --git a/packages/server/graphql/mutations/moveTeamToOrg.ts b/packages/server/graphql/mutations/moveTeamToOrg.ts index 06be3517417..7fa25b2b41d 100644 --- a/packages/server/graphql/mutations/moveTeamToOrg.ts +++ b/packages/server/graphql/mutations/moveTeamToOrg.ts @@ -13,6 +13,7 @@ import standardError from '../../utils/standardError' import {DataLoaderWorker, GQLContext} from '../graphql' import isValid from '../isValid' import getKysely from '../../postgres/getKysely' +import {Logger} from '../../utils/Logger' const MAX_NUM_TEAMS = 40 @@ -168,7 +169,7 @@ export default { const successes = results.filter((result) => typeof result === 'string') const failures = results.filter((result) => typeof result !== 'string') const successStr = successes.join('\n') - console.error('failures', failures) + Logger.error('failures', failures) return successStr } } diff --git a/packages/server/graphql/mutations/navigateMeeting.ts b/packages/server/graphql/mutations/navigateMeeting.ts index 2f833970921..70340fa2401 100644 --- a/packages/server/graphql/mutations/navigateMeeting.ts +++ b/packages/server/graphql/mutations/navigateMeeting.ts @@ -11,6 +11,7 @@ import {GQLContext} from '../graphql' import NavigateMeetingPayload from '../types/NavigateMeetingPayload' import handleCompletedStage from './helpers/handleCompletedStage' import removeScheduledJobs from './helpers/removeScheduledJobs' +import {Logger} from '../../utils/Logger' export default { type: new GraphQLNonNull(NavigateMeetingPayload), @@ -84,7 +85,7 @@ export default { phaseCompleteData = await handleCompletedStage(stage, meeting, dataLoader) if (stage.scheduledEndTime) { // not critical, no await needed - removeScheduledJobs(stage.scheduledEndTime, {meetingId}).catch(console.error) + removeScheduledJobs(stage.scheduledEndTime, {meetingId}).catch(Logger.error) stage.scheduledEndTime = null } } diff --git a/packages/server/graphql/mutations/selectTemplate.ts b/packages/server/graphql/mutations/selectTemplate.ts index 5877f848b01..4d0ee10f092 100644 --- a/packages/server/graphql/mutations/selectTemplate.ts +++ b/packages/server/graphql/mutations/selectTemplate.ts @@ -8,6 +8,7 @@ import standardError from '../../utils/standardError' import {GQLContext} from '../graphql' import SelectTemplatePayload from '../types/SelectTemplatePayload' import {getFeatureTier} from '../types/helpers/getFeatureTier' +import {Logger} from '../../utils/Logger' const selectTemplate = { description: 'Set the selected template for the upcoming retro meeting', @@ -37,7 +38,7 @@ const selectTemplate = { ]) if (!template || !template.isActive) { - console.log('no template', selectedTemplateId, template) + Logger.log('no template', selectedTemplateId, template) return standardError(new Error('Template not found'), {userId: viewerId}) } diff --git a/packages/server/graphql/mutations/updateAzureDevOpsDimensionField.ts b/packages/server/graphql/mutations/updateAzureDevOpsDimensionField.ts index a366c1afc9e..7e27ad66e14 100644 --- a/packages/server/graphql/mutations/updateAzureDevOpsDimensionField.ts +++ b/packages/server/graphql/mutations/updateAzureDevOpsDimensionField.ts @@ -5,6 +5,7 @@ import upsertAzureDevOpsDimensionFieldMap, { AzureDevOpsFieldMapProps } from '../../postgres/queries/upsertAzureDevOpsDimensionFieldMap' import {isTeamMember} from '../../utils/authorization' +import {Logger} from '../../utils/Logger' import publish from '../../utils/publish' import {GQLContext} from '../graphql' import UpdateAzureDevOpsDimensionFieldPayload from '../types/UpdateAzureDevOpsDimensionFieldPayload' @@ -57,7 +58,7 @@ const updateAzureDevOpsDimensionField = { }, {authToken, dataLoader, socketId: mutatorId}: GQLContext ) => { - //console.log(`Inside updateAzureDevOpsDimensionField`) + //Logger.log(`Inside updateAzureDevOpsDimensionField`) const operationId = dataLoader.share() const subOptions = {mutatorId, operationId} @@ -91,7 +92,7 @@ const updateAzureDevOpsDimensionField = { } as AzureDevOpsFieldMapProps await upsertAzureDevOpsDimensionFieldMap(props) } catch (e) { - console.log(e) + Logger.log(e) } const data = {teamId, meetingId} diff --git a/packages/server/graphql/mutations/updateGitHubDimensionField.ts b/packages/server/graphql/mutations/updateGitHubDimensionField.ts index d6077e4d01d..703f9e601e9 100644 --- a/packages/server/graphql/mutations/updateGitHubDimensionField.ts +++ b/packages/server/graphql/mutations/updateGitHubDimensionField.ts @@ -3,6 +3,7 @@ import {SubscriptionChannel} from 'parabol-client/types/constEnums' import MeetingPoker from '../../database/types/MeetingPoker' import upsertGitHubDimensionFieldMap from '../../postgres/queries/upsertGitHubDimensionFieldMap' import {isTeamMember} from '../../utils/authorization' +import {Logger} from '../../utils/Logger' import publish from '../../utils/publish' import {GQLContext} from '../graphql' import UpdateGitHubDimensionFieldPayload from '../types/UpdateGitHubDimensionFieldPayload' @@ -66,7 +67,7 @@ const updateGitHubDimensionField = { try { await upsertGitHubDimensionFieldMap(teamId, dimensionName, nameWithOwner, labelTemplate) } catch (e) { - console.log(e) + Logger.log(e) } const data = {meetingId, teamId} diff --git a/packages/server/graphql/private/mutations/autopauseUsers.ts b/packages/server/graphql/private/mutations/autopauseUsers.ts index ed92c2e95c9..ba8e3439b0b 100644 --- a/packages/server/graphql/private/mutations/autopauseUsers.ts +++ b/packages/server/graphql/private/mutations/autopauseUsers.ts @@ -3,6 +3,7 @@ import adjustUserCount from '../../../billing/helpers/adjustUserCount' import getRethink from '../../../database/rethinkDriver' import getUserIdsToPause from '../../../postgres/queries/getUserIdsToPause' import {MutationResolvers} from '../resolverTypes' +import {Logger} from '../../../utils/Logger' const autopauseUsers: MutationResolvers['autopauseUsers'] = async ( _source, @@ -32,7 +33,7 @@ const autopauseUsers: MutationResolvers['autopauseUsers'] = async ( try { return await adjustUserCount(userId, orgIds, InvoiceItemType.AUTO_PAUSE_USER, dataLoader) } catch (e) { - console.warn(`Error adjusting user count`) + Logger.warn(`Error adjusting user count`) } return undefined }) diff --git a/packages/server/graphql/private/mutations/connectSocket.ts b/packages/server/graphql/private/mutations/connectSocket.ts index c105d0ef180..4461a506f27 100644 --- a/packages/server/graphql/private/mutations/connectSocket.ts +++ b/packages/server/graphql/private/mutations/connectSocket.ts @@ -6,6 +6,7 @@ import {analytics} from '../../../utils/analytics/analytics' import {getUserId} from '../../../utils/authorization' import getListeningUserIds, {RedisCommand} from '../../../utils/getListeningUserIds' import getRedis from '../../../utils/getRedis' +import {Logger} from '../../../utils/Logger' import publish from '../../../utils/publish' import {MutationResolvers} from '../resolverTypes' @@ -44,7 +45,7 @@ const connectSocket: MutationResolvers['connectSocket'] = async ( .getAll(userId, {index: 'userId'}) .filter({removedAt: null, inactive: true})('orgId') .run() - adjustUserCount(userId, orgIds, InvoiceItemType.UNPAUSE_USER, dataLoader).catch(console.log) + adjustUserCount(userId, orgIds, InvoiceItemType.UNPAUSE_USER, dataLoader).catch(Logger.log) // TODO: re-identify } const datesAreOnSameDay = now.toDateString() === lastSeenAt.toDateString() diff --git a/packages/server/graphql/private/mutations/runScheduledJobs.ts b/packages/server/graphql/private/mutations/runScheduledJobs.ts index 923d4617119..faee38517ec 100644 --- a/packages/server/graphql/private/mutations/runScheduledJobs.ts +++ b/packages/server/graphql/private/mutations/runScheduledJobs.ts @@ -8,6 +8,7 @@ import publish from '../../../utils/publish' import {DataLoaderWorker} from '../../graphql' import {IntegrationNotifier} from '../../mutations/helpers/notifications/IntegrationNotifier' import {MutationResolvers} from '../resolverTypes' +import {Logger} from '../../../utils/Logger' const processMeetingStageTimeLimits = async ( job: ScheduledJobMeetingStageTimeLimit, @@ -48,9 +49,9 @@ const processJob = async (job: ScheduledJobUnion, dataLoader: DataLoaderWorker) return processMeetingStageTimeLimits( job as ScheduledJobMeetingStageTimeLimit, dataLoader - ).catch(console.error) + ).catch(Logger.error) } else if (job.type === 'LOCK_ORGANIZATION' || job.type === 'WARN_ORGANIZATION') { - return processTeamsLimitsJob(job as ScheduledTeamLimitsJob, dataLoader).catch(console.error) + return processTeamsLimitsJob(job as ScheduledTeamLimitsJob, dataLoader).catch(Logger.error) } } @@ -73,7 +74,7 @@ const runScheduledJobs: MutationResolvers['runScheduledJobs'] = async ( const {runAt} = job const timeout = Math.max(0, runAt.getTime() - now.getTime()) setTimeout(() => { - processJob(job, dataLoader).catch(console.error) + processJob(job, dataLoader).catch(Logger.error) }, timeout) }) diff --git a/packages/server/graphql/public/mutations/acceptRequestToJoinDomain.ts b/packages/server/graphql/public/mutations/acceptRequestToJoinDomain.ts index b7920912068..ea12206cdd5 100644 --- a/packages/server/graphql/public/mutations/acceptRequestToJoinDomain.ts +++ b/packages/server/graphql/public/mutations/acceptRequestToJoinDomain.ts @@ -14,6 +14,7 @@ import publish from '../../../utils/publish' import toTeamMemberId from 'parabol-client/utils/relay/toTeamMemberId' import DomainJoinRequestId from 'parabol-client/shared/gqlIds/DomainJoinRequestId' import {getUserById} from '../../../postgres/queries/getUsersByIds' +import {Logger} from '../../../utils/Logger' // TODO (EXPERIMENT: prompt-to-join-org): some parts are borrowed from acceptTeamInvitation, create generic functions const acceptRequestToJoinDomain: MutationResolvers['acceptRequestToJoinDomain'] = async ( @@ -106,7 +107,7 @@ const acceptRequestToJoinDomain: MutationResolvers['acceptRequestToJoinDomain'] try { await adjustUserCount(userId, orgId, InvoiceItemType.ADD_USER, dataLoader) } catch (e) { - console.log(e) + Logger.log(e) } await setUserTierForUserIds([userId]) } diff --git a/packages/server/graphql/public/mutations/updateGitLabDimensionField.ts b/packages/server/graphql/public/mutations/updateGitLabDimensionField.ts index f03ebde9493..88ca97eb167 100644 --- a/packages/server/graphql/public/mutations/updateGitLabDimensionField.ts +++ b/packages/server/graphql/public/mutations/updateGitLabDimensionField.ts @@ -2,6 +2,7 @@ import {SubscriptionChannel} from 'parabol-client/types/constEnums' import MeetingPoker from '../../../database/types/MeetingPoker' import upsertGitLabDimensionFieldMap from '../../../postgres/queries/upsertGitLabDimensionFieldMap' import {isTeamMember} from '../../../utils/authorization' +import {Logger} from '../../../utils/Logger' import publish from '../../../utils/publish' import {MutationResolvers} from '../resolverTypes' import {getUserId} from './../../../utils/authorization' @@ -40,7 +41,7 @@ const updateGitLabDimensionField: MutationResolvers['updateGitLabDimensionField' const {providerId} = gitlabAuth await upsertGitLabDimensionFieldMap(teamId, dimensionName, projectId, providerId, labelTemplate) } catch (e) { - console.log(e) + Logger.log(e) } const data = {meetingId, teamId} diff --git a/packages/server/graphql/public/types/TeamHealthStage.ts b/packages/server/graphql/public/types/TeamHealthStage.ts index 29c7834c877..f98202ae131 100644 --- a/packages/server/graphql/public/types/TeamHealthStage.ts +++ b/packages/server/graphql/public/types/TeamHealthStage.ts @@ -2,6 +2,7 @@ import {TeamHealthStageResolvers} from '../resolverTypes' import {getUserId} from '../../../utils/authorization' import TeamHealthStageDB from '../../../database/types/TeamHealthStage' import isValid from '../../isValid' +import {Logger} from '../../../utils/Logger' export type TeamHealthStageSource = TeamHealthStageDB & { meetingId: string @@ -21,7 +22,7 @@ const TeamHealthStage: TeamHealthStageResolvers = { }, readyCount: async ({meetingId, readyToAdvance}, _args, {dataLoader}, ref) => { if (!readyToAdvance) return 0 - if (!meetingId) console.log('no meetingid', ref) + if (!meetingId) Logger.log('no meetingid', ref) const meeting = await dataLoader.get('newMeetings').load(meetingId) const {facilitatorUserId} = meeting return readyToAdvance.filter((userId) => userId !== facilitatorUserId).length diff --git a/packages/server/graphql/queries/helpers/fetchGitHubRepos.ts b/packages/server/graphql/queries/helpers/fetchGitHubRepos.ts index 17fd935ae64..14b951248c0 100644 --- a/packages/server/graphql/queries/helpers/fetchGitHubRepos.ts +++ b/packages/server/graphql/queries/helpers/fetchGitHubRepos.ts @@ -4,6 +4,7 @@ import getGitHubRequest from '../../../utils/getGitHubRequest' import getRepositories from '../../../utils/githubQueries/getRepositories.graphql' import {DataLoaderWorker} from '../../graphql' import {GQLContext} from './../../graphql' +import {Logger} from '../../../utils/Logger' export interface GitHubRepo { id: string @@ -25,7 +26,7 @@ const fetchGitHubRepos = async ( const githubRequest = getGitHubRequest(info, context, {accessToken}) const [data, error] = await githubRequest(getRepositories) if (error) { - console.error(error.message) + Logger.error(error.message) return [] } const {viewer} = data diff --git a/packages/server/graphql/queries/helpers/fetchGitLabProjects.ts b/packages/server/graphql/queries/helpers/fetchGitLabProjects.ts index 8ff83e7a8e3..72da38eddb3 100644 --- a/packages/server/graphql/queries/helpers/fetchGitLabProjects.ts +++ b/packages/server/graphql/queries/helpers/fetchGitLabProjects.ts @@ -2,6 +2,7 @@ import {GraphQLResolveInfo} from 'graphql' import {isNotNull} from 'parabol-client/utils/predicates' import GitLabServerManager from '../../../integrations/gitlab/GitLabServerManager' import {GQLContext} from '../../graphql' +import {Logger} from '../../../utils/Logger' const fetchGitLabProjects = async ( teamId: string, @@ -18,7 +19,7 @@ const fetchGitLabProjects = async ( const manager = new GitLabServerManager(auth, context, info, provider.serverBaseUrl) const [data, error] = await manager.getProjects({}) if (error) { - console.error(error.message) + Logger.error(error.message) return [] } return ( diff --git a/packages/server/graphql/types/NewMeetingStage.ts b/packages/server/graphql/types/NewMeetingStage.ts index 5eecb36a46f..0247e4ebbf2 100644 --- a/packages/server/graphql/types/NewMeetingStage.ts +++ b/packages/server/graphql/types/NewMeetingStage.ts @@ -11,6 +11,7 @@ import GenericMeetingPhase, { NewMeetingPhaseTypeEnum as NewMeetingPhaseTypeEnumType } from '../../database/types/GenericMeetingPhase' import {getUserId} from '../../utils/authorization' +import {Logger} from '../../utils/Logger' import {GQLContext} from '../graphql' import GraphQLISO8601Type from './GraphQLISO8601Type' import NewMeeting from './NewMeeting' @@ -112,7 +113,7 @@ export const newMeetingStageFields = () => ({ ref: any ) => { if (!readyToAdvance) return 0 - if (!meetingId) console.log('no meetingid', ref) + if (!meetingId) Logger.log('no meetingid', ref) const meeting = await dataLoader.get('newMeetings').load(meetingId) const {facilitatorUserId} = meeting return readyToAdvance.filter((userId: string) => userId !== facilitatorUserId).length diff --git a/packages/server/graphql/types/PokerMeeting.ts b/packages/server/graphql/types/PokerMeeting.ts index f9262f8a919..fd0116d26f2 100644 --- a/packages/server/graphql/types/PokerMeeting.ts +++ b/packages/server/graphql/types/PokerMeeting.ts @@ -1,6 +1,7 @@ import {GraphQLID, GraphQLInt, GraphQLList, GraphQLNonNull, GraphQLObjectType} from 'graphql' import toTeamMemberId from 'parabol-client/utils/relay/toTeamMemberId' import {getUserId} from '../../utils/authorization' +import {Logger} from '../../utils/Logger' import {GQLContext} from '../graphql' import NewMeeting from './NewMeeting' import PokerMeetingMember from './PokerMeetingMember' @@ -39,7 +40,7 @@ const PokerMeeting = new GraphQLObjectType({ resolve: async ({id: meetingId}, {storyId: taskId}, {dataLoader}) => { const task = await dataLoader.get('tasks').load(taskId) if (task.meetingId !== meetingId) { - console.log('naughty storyId supplied to PokerMeeting') + Logger.log('naughty storyId supplied to PokerMeeting') return null } return task diff --git a/packages/server/postgres/queries/upsertAzureDevOpsDimensionFieldMap.ts b/packages/server/postgres/queries/upsertAzureDevOpsDimensionFieldMap.ts index e19e9ad7c83..d5099ed387d 100644 --- a/packages/server/postgres/queries/upsertAzureDevOpsDimensionFieldMap.ts +++ b/packages/server/postgres/queries/upsertAzureDevOpsDimensionFieldMap.ts @@ -1,3 +1,4 @@ +import {Logger} from '../../utils/Logger' import getPg from '../getPg' import {upsertAzureDevOpsDimensionFieldMapQuery} from './generated/upsertAzureDevOpsDimensionFieldMapQuery' @@ -22,7 +23,7 @@ const upsertAzureDevOpsDimensionFieldMap = async (props: AzureDevOpsFieldMapProp projectKey, workItemType } = props - console.log(`Inside upsertAzureDevOpsDimensionFieldMap - props:${JSON.stringify(props)}`) + Logger.log(`Inside upsertAzureDevOpsDimensionFieldMap - props:${JSON.stringify(props)}`) return upsertAzureDevOpsDimensionFieldMapQuery.run( { fieldMap: { diff --git a/packages/server/safeMutations/acceptTeamInvitation.ts b/packages/server/safeMutations/acceptTeamInvitation.ts index 98563d9270f..be5ec868c6d 100644 --- a/packages/server/safeMutations/acceptTeamInvitation.ts +++ b/packages/server/safeMutations/acceptTeamInvitation.ts @@ -6,6 +6,7 @@ import generateUID from '../generateUID' import {DataLoaderWorker} from '../graphql/graphql' import {Team} from '../postgres/queries/getTeamsByIds' import getNewTeamLeadUserId from '../safeQueries/getNewTeamLeadUserId' +import {Logger} from '../utils/Logger' import setUserTierForUserIds from '../utils/setUserTierForUserIds' import addTeamIdToTMS from './addTeamIdToTMS' import insertNewTeamMember from './insertNewTeamMember' @@ -92,7 +93,7 @@ const acceptTeamInvitation = async (team: Team, userId: string, dataLoader: Data try { await adjustUserCount(userId, orgId, InvoiceItemType.ADD_USER, dataLoader) } catch (e) { - console.log(e) + Logger.log(e) } await setUserTierForUserIds([userId]) } diff --git a/packages/server/safetyPatchRes.ts b/packages/server/safetyPatchRes.ts index d48e736b5cf..aa974ebb88f 100644 --- a/packages/server/safetyPatchRes.ts +++ b/packages/server/safetyPatchRes.ts @@ -1,4 +1,5 @@ import {HttpResponse, RecognizedString} from 'uWebSockets.js' +import {Logger} from './utils/Logger' type Header = [key: RecognizedString, value: RecognizedString] @@ -36,7 +37,7 @@ const safetyPatchRes = (res: HttpResponse) => { res._end = res.end res.end = (body?: RecognizedString) => { if (res.done) { - console.warn(`uWS: Called end after done`) + Logger.warn(`uWS: Called end after done`) } if (res.done || res.aborted) return res res.done = true @@ -46,7 +47,7 @@ const safetyPatchRes = (res: HttpResponse) => { res._close = res.close res.close = () => { if (res.done) { - console.warn(`uWS: Called close after done`) + Logger.warn(`uWS: Called close after done`) } if (res.done || res.aborted) return res res.done = true @@ -61,7 +62,7 @@ const safetyPatchRes = (res: HttpResponse) => { res._tryEnd = res.tryEnd res.tryEnd = (fullBodyOrChunk: RecognizedString, totalSize: number) => { if (res.done) { - console.warn(`uWS: Called tryEnd after done`) + Logger.warn(`uWS: Called tryEnd after done`) } if (res.done || res.aborted) return [true, true] return flush(() => res._tryEnd(fullBodyOrChunk, totalSize)) @@ -70,7 +71,7 @@ const safetyPatchRes = (res: HttpResponse) => { res._write = res.write res.write = (chunk: RecognizedString) => { if (res.done) { - console.warn(`uWS: Called write after done`) + Logger.warn(`uWS: Called write after done`) } if (res.done || res.aborted) return res return res._write(chunk) @@ -79,7 +80,7 @@ const safetyPatchRes = (res: HttpResponse) => { res._writeHeader = res.writeHeader res.writeHeader = (key: RecognizedString, value: RecognizedString) => { if (res.done) { - console.warn(`uWS: Called writeHeader after done`) + Logger.warn(`uWS: Called writeHeader after done`) } res.headers.push([key, value]) return res @@ -88,7 +89,7 @@ const safetyPatchRes = (res: HttpResponse) => { res._writeStatus = res.writeStatus res.writeStatus = (status: RecognizedString) => { if (res.done) { - console.error(`uWS: Called writeStatus after done ${status}`) + Logger.error(`uWS: Called writeStatus after done ${status}`) } res.status = status return res @@ -97,7 +98,7 @@ const safetyPatchRes = (res: HttpResponse) => { res._upgrade = res.upgrade res.upgrade = (...args) => { if (res.done) { - console.error(`uWS: Called upgrade after done`) + Logger.error(`uWS: Called upgrade after done`) } if (res.done || res.aborted) return return res._cork(() => { @@ -108,7 +109,7 @@ const safetyPatchRes = (res: HttpResponse) => { res._getRemoteAddressAsText = res.getRemoteAddressAsText res.getRemoteAddressAsText = () => { if (res.done) { - console.error(`uWS: Called getRemoteAddressAsText after done`) + Logger.error(`uWS: Called getRemoteAddressAsText after done`) } if (res.done || res.aborted) return Buffer.from('') return res._getRemoteAddressAsText() diff --git a/packages/server/utils/AtlassianServerManager.ts b/packages/server/utils/AtlassianServerManager.ts index dcc29a4a3b9..d84a448f7be 100644 --- a/packages/server/utils/AtlassianServerManager.ts +++ b/packages/server/utils/AtlassianServerManager.ts @@ -11,25 +11,7 @@ import { OAuth2AuthorizationParams, OAuth2RefreshAuthorizationParams } from '../integrations/OAuth2Manager' - -import tracer from 'dd-trace' -import formats from 'dd-trace/ext/formats' -import util from 'util' - -type LogLevel = 'error' | 'warn' | 'info' | 'debug' -function trace(level: LogLevel, message: any, ...optionalParameters: any[]) { - const span = tracer.scope().active() - const time = new Date().toISOString() - const record = {time, level, message: util.format(message, optionalParameters)} - - if (span) { - tracer.inject(span.context(), formats.LOG, record) - } - - console.log(JSON.stringify(record)) -} - -const log = trace.bind(null, 'info') +import {Logger} from './Logger' export interface JiraUser { self: string @@ -343,7 +325,7 @@ class AtlassianServerManager extends AtlassianManager { } else { callback(null, {cloudId, newProjects: res.values}) if (res.nextPage) { - await this.getPaginatedProjects(cloudId, res.nextPage, callback).catch(console.error) + await this.getPaginatedProjects(cloudId, res.nextPage, callback).catch(Logger.error) } } } @@ -355,7 +337,7 @@ class AtlassianServerManager extends AtlassianManager { cloudId, `https://api.atlassian.com/ex/jira/${cloudId}/rest/api/3/project/search?orderBy=name`, callback - ).catch(console.error) + ).catch(Logger.error) }) ) } @@ -387,7 +369,7 @@ class AtlassianServerManager extends AtlassianManager { })) projects.push(...pagedProjects) if (res.nextPage) { - log('AtlassianServerManager.getAllProjects fetching more results', res.total) + Logger.log('AtlassianServerManager.getAllProjects fetching more results', res.total) return getProjectPage(cloudId, res.nextPage) } } @@ -402,7 +384,7 @@ class AtlassianServerManager extends AtlassianManager { ) if (error) { - log('getAllProjects ERROR:', error) + Logger.log('getAllProjects ERROR:', error) } return projects } diff --git a/packages/server/utils/Logger.ts b/packages/server/utils/Logger.ts new file mode 100644 index 00000000000..3cca7489c69 --- /dev/null +++ b/packages/server/utils/Logger.ts @@ -0,0 +1,35 @@ +import tracer from 'dd-trace' +import formats from 'dd-trace/ext/formats' +import util from 'util' + +type LogLevel = 'error' | 'warn' | 'info' | 'debug' +const LogFun = { + error: console.error, + warn: console.warn, + info: console.info, + debug: console.debug +} satisfies Record + +function trace(level: LogLevel, message: any, ...optionalParameters: any[]) { + if (process.env.DD_LOGS_INJECTION !== 'true') { + return LogFun[level](message, ...optionalParameters) + } + + const span = tracer.scope().active() + const time = new Date().toISOString() + const record = {time, level, message: util.format(message, optionalParameters)} + + if (span) { + tracer.inject(span.context(), formats.LOG, record) + } + + LogFun[level](JSON.stringify(record)) +} + +export const Logger = { + log: trace.bind(null, 'info'), + error: trace.bind(null, 'error'), + warn: trace.bind(null, 'warn'), + info: trace.bind(null, 'info'), + debug: trace.bind(null, 'debug') +} diff --git a/packages/server/utils/OpenAIServerManager.ts b/packages/server/utils/OpenAIServerManager.ts index 3cc48bb3868..251528770e2 100644 --- a/packages/server/utils/OpenAIServerManager.ts +++ b/packages/server/utils/OpenAIServerManager.ts @@ -3,6 +3,7 @@ import JSON5 from 'json5' import sendToSentry from './sendToSentry' import Reflection from '../database/types/Reflection' import {ModifyType} from '../graphql/public/resolverTypes' +import {Logger} from './Logger' type Prompt = { question: string @@ -188,7 +189,7 @@ class OpenAIServerManager { return themes.split(', ') } catch (e) { const error = e instanceof Error ? e : new Error('OpenAI failed to generate themes') - console.error(error.message) + Logger.error(error.message) sendToSentry(error) return null } @@ -226,7 +227,7 @@ class OpenAIServerManager { } catch (e) { const error = e instanceof Error ? e : new Error('OpenAI failed to generate the suggested template') - console.error(error.message) + Logger.error(error.message) sendToSentry(error) return null } diff --git a/packages/server/utils/RecallAIServerManager.ts b/packages/server/utils/RecallAIServerManager.ts index 5c30cfc1ceb..c5dc8e7f781 100644 --- a/packages/server/utils/RecallAIServerManager.ts +++ b/packages/server/utils/RecallAIServerManager.ts @@ -4,6 +4,7 @@ import {ExternalLinks} from '../../client/types/constEnums' import appOrigin from '../appOrigin' import {TranscriptBlock} from '../database/types/MeetingRetrospective' import sendToSentry from './sendToSentry' +import {Logger} from './Logger' const sdk = api('@recallai/v1.6#536jnqlf7d6blh') @@ -19,7 +20,7 @@ const getBase64Image = async () => { const base64Image = buffer.toString('base64') return base64Image } catch (error) { - console.error(error) + Logger.error(error) return null } } diff --git a/packages/server/utils/StaticServer.ts b/packages/server/utils/StaticServer.ts index f8cba007f00..2ba0fd3b3b6 100644 --- a/packages/server/utils/StaticServer.ts +++ b/packages/server/utils/StaticServer.ts @@ -3,6 +3,7 @@ import mime from 'mime-types' import path from 'path' import {brotliCompressSync} from 'zlib' import isCompressible from './isCompressible' +import {Logger} from './Logger' class StaticFileMeta { mtime: string size: number @@ -63,7 +64,7 @@ export default class StaticServer { } makePathnames(dirname, this.pathnames, '') } catch (e) { - console.log(e) + Logger.log(e) } }) } diff --git a/packages/server/utils/publish.ts b/packages/server/utils/publish.ts index 5203852257f..b9c7defb2ff 100644 --- a/packages/server/utils/publish.ts +++ b/packages/server/utils/publish.ts @@ -1,4 +1,5 @@ import getPubSub from './getPubSub' +import {Logger} from './Logger' export interface SubOptions { mutatorId?: string // passing the socket id of the mutator will omit sending a message to that user @@ -18,7 +19,7 @@ const publish = ( const rootValue = {[subName]: {fieldName: type, [type]: payload}} getPubSub() .publish(`${topic}.${channel}`, {rootValue, executorServerId: SERVER_ID!, ...subOptions}) - .catch(console.error) + .catch(Logger.error) } export default publish diff --git a/packages/server/utils/stripe/StripeManager.ts b/packages/server/utils/stripe/StripeManager.ts index 0ab72ac35c3..28db42bd437 100644 --- a/packages/server/utils/stripe/StripeManager.ts +++ b/packages/server/utils/stripe/StripeManager.ts @@ -1,5 +1,6 @@ import {InvoiceItemType} from 'parabol-client/types/constEnums' import Stripe from 'stripe' +import {Logger} from '../Logger' import sendToSentry from '../sendToSentry' export default class StripeManager { @@ -15,7 +16,7 @@ export default class StripeManager { try { return this.stripe.webhooks.constructEvent(rawBody, signature, StripeManager.WEBHOOK_SECRET) } catch (e) { - console.log('StripeWebhookError:', e) + Logger.log('StripeWebhookError:', e) return null } } From bd519c93bebe000ebe34dc6ea7eba2db337e2251 Mon Sep 17 00:00:00 2001 From: "parabol-release-bot[bot]" <150284312+parabol-release-bot[bot]@users.noreply.github.com> Date: Tue, 27 Feb 2024 10:46:36 -0800 Subject: [PATCH 11/39] chore(release): release v7.18.0 (#9450) Co-authored-by: parabol-release-bot[bot] <150284312+parabol-release-bot[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ package.json | 2 +- packages/chronos/package.json | 4 ++-- packages/client/package.json | 2 +- packages/gql-executor/package.json | 6 +++--- packages/integration-tests/package.json | 2 +- packages/server/package.json | 4 ++-- 8 files changed, 24 insertions(+), 11 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 0fb11cbd996..f6475935835 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "7.17.0" + ".": "7.18.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index fd68e143309..702f2ff2a5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,19 @@ This project adheres to [Semantic Versioning](http://semver.org/). This CHANGELOG follows conventions [outlined here](http://keepachangelog.com/). +## [7.18.0](https://github.com/ParabolInc/parabol/compare/v7.17.0...v7.18.0) (2024-02-27) + + +### Added + +* **standalone-deployment:** Standalone host deployment improved and documented ([#9445](https://github.com/ParabolInc/parabol/issues/9445)) ([61ba015](https://github.com/ParabolInc/parabol/commit/61ba015c8310a72b7e89c64be081cd2f399fc721)) +* support env-defined saml issuer for PPMIs ([#9455](https://github.com/ParabolInc/parabol/issues/9455)) ([92ab5be](https://github.com/ParabolInc/parabol/commit/92ab5be298ceb19ca8718c67a0c9da8728b6b0bf)) + + +### Changed + +* Associate logs with traces ([#9444](https://github.com/ParabolInc/parabol/issues/9444)) ([c77925b](https://github.com/ParabolInc/parabol/commit/c77925b1c0e07afc428022008143b8b7f4002280)) + ## [7.17.0](https://github.com/ParabolInc/parabol/compare/v7.16.0...v7.17.0) (2024-02-21) diff --git a/package.json b/package.json index edde1656431..962c45f4873 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.17.0", + "version": "7.18.0", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" diff --git a/packages/chronos/package.json b/packages/chronos/package.json index 5295ced9dd0..6be287b79d6 100644 --- a/packages/chronos/package.json +++ b/packages/chronos/package.json @@ -1,6 +1,6 @@ { "name": "chronos", - "version": "7.17.0", + "version": "7.18.0", "description": "A cron job scheduler", "author": "Matt Krick ", "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/chronos#readme", @@ -25,6 +25,6 @@ }, "dependencies": { "cron": "^2.3.1", - "parabol-server": "7.17.0" + "parabol-server": "7.18.0" } } diff --git a/packages/client/package.json b/packages/client/package.json index 9faef2216e4..3776a1094db 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.17.0", + "version": "7.18.0", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" diff --git a/packages/gql-executor/package.json b/packages/gql-executor/package.json index 1675bcaf5ea..64942d20a59 100644 --- a/packages/gql-executor/package.json +++ b/packages/gql-executor/package.json @@ -1,6 +1,6 @@ { "name": "gql-executor", - "version": "7.17.0", + "version": "7.18.0", "description": "A Stateless GraphQL Executor", "author": "Matt Krick ", "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/gqlExecutor#readme", @@ -27,8 +27,8 @@ }, "dependencies": { "dd-trace": "^4.2.0", - "parabol-client": "7.17.0", - "parabol-server": "7.17.0", + "parabol-client": "7.18.0", + "parabol-server": "7.18.0", "undici": "^5.26.2" } } diff --git a/packages/integration-tests/package.json b/packages/integration-tests/package.json index 0190f526ea8..a73d3eb3327 100644 --- a/packages/integration-tests/package.json +++ b/packages/integration-tests/package.json @@ -2,7 +2,7 @@ "name": "integration-tests", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.17.0", + "version": "7.18.0", "description": "", "main": "index.js", "scripts": { diff --git a/packages/server/package.json b/packages/server/package.json index c1bde9cbe3f..2f4bd7453ff 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.17.0", + "version": "7.18.0", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" @@ -124,7 +124,7 @@ "oauth-1.0a": "^2.2.6", "openai": "^4.24.1", "oy-vey": "^0.11.0", - "parabol-client": "7.17.0", + "parabol-client": "7.18.0", "pg": "^8.5.1", "react": "^17.0.2", "react-dom": "^17.0.2", From 6d46e1b2aab6731493de2d2547c88ae3921393f0 Mon Sep 17 00:00:00 2001 From: Matt Krick Date: Tue, 27 Feb 2024 11:09:18 -0800 Subject: [PATCH 12/39] chore: no force-push to prod (#9401) Signed-off-by: Matt Krick --- .github/workflows/release-to-staging.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release-to-staging.yml b/.github/workflows/release-to-staging.yml index 139b8472fa8..6e9225bf871 100644 --- a/.github/workflows/release-to-staging.yml +++ b/.github/workflows/release-to-staging.yml @@ -99,6 +99,7 @@ jobs: git config user.name github-actions git config user.email github-actions@github.com git checkout -b "release/v${{ env.ACTION_VERSION }}" + git merge -s ours origin/production git push --set-upstream origin "release/v${{ env.ACTION_VERSION }}" gh pr create \ --assignee ${{ github.actor }} \ From b60ff4e87951081fbee48d2a9f31a5e66fafb09b Mon Sep 17 00:00:00 2001 From: "parabol-release-bot[bot]" <150284312+parabol-release-bot[bot]@users.noreply.github.com> Date: Tue, 27 Feb 2024 11:15:58 -0800 Subject: [PATCH 13/39] chore(release): release v7.18.1 (#9459) Co-authored-by: parabol-release-bot[bot] <150284312+parabol-release-bot[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- CHANGELOG.md | 7 +++++++ package.json | 2 +- packages/chronos/package.json | 4 ++-- packages/client/package.json | 2 +- packages/gql-executor/package.json | 6 +++--- packages/integration-tests/package.json | 2 +- packages/server/package.json | 4 ++-- 8 files changed, 18 insertions(+), 11 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index f6475935835..28707a42151 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "7.18.0" + ".": "7.18.1" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 702f2ff2a5a..9d1147fe08f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ This project adheres to [Semantic Versioning](http://semver.org/). This CHANGELOG follows conventions [outlined here](http://keepachangelog.com/). +## [7.18.1](https://github.com/ParabolInc/parabol/compare/v7.18.0...v7.18.1) (2024-02-27) + + +### Changed + +* no force-push to prod ([#9401](https://github.com/ParabolInc/parabol/issues/9401)) ([6d46e1b](https://github.com/ParabolInc/parabol/commit/6d46e1b2aab6731493de2d2547c88ae3921393f0)) + ## [7.18.0](https://github.com/ParabolInc/parabol/compare/v7.17.0...v7.18.0) (2024-02-27) diff --git a/package.json b/package.json index 962c45f4873..179fed1c4cb 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.18.0", + "version": "7.18.1", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" diff --git a/packages/chronos/package.json b/packages/chronos/package.json index 6be287b79d6..5619754d830 100644 --- a/packages/chronos/package.json +++ b/packages/chronos/package.json @@ -1,6 +1,6 @@ { "name": "chronos", - "version": "7.18.0", + "version": "7.18.1", "description": "A cron job scheduler", "author": "Matt Krick ", "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/chronos#readme", @@ -25,6 +25,6 @@ }, "dependencies": { "cron": "^2.3.1", - "parabol-server": "7.18.0" + "parabol-server": "7.18.1" } } diff --git a/packages/client/package.json b/packages/client/package.json index 3776a1094db..141dca1fe36 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.18.0", + "version": "7.18.1", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" diff --git a/packages/gql-executor/package.json b/packages/gql-executor/package.json index 64942d20a59..1f7848776eb 100644 --- a/packages/gql-executor/package.json +++ b/packages/gql-executor/package.json @@ -1,6 +1,6 @@ { "name": "gql-executor", - "version": "7.18.0", + "version": "7.18.1", "description": "A Stateless GraphQL Executor", "author": "Matt Krick ", "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/gqlExecutor#readme", @@ -27,8 +27,8 @@ }, "dependencies": { "dd-trace": "^4.2.0", - "parabol-client": "7.18.0", - "parabol-server": "7.18.0", + "parabol-client": "7.18.1", + "parabol-server": "7.18.1", "undici": "^5.26.2" } } diff --git a/packages/integration-tests/package.json b/packages/integration-tests/package.json index a73d3eb3327..3331444dcae 100644 --- a/packages/integration-tests/package.json +++ b/packages/integration-tests/package.json @@ -2,7 +2,7 @@ "name": "integration-tests", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.18.0", + "version": "7.18.1", "description": "", "main": "index.js", "scripts": { diff --git a/packages/server/package.json b/packages/server/package.json index 2f4bd7453ff..18ca0f00370 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.18.0", + "version": "7.18.1", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" @@ -124,7 +124,7 @@ "oauth-1.0a": "^2.2.6", "openai": "^4.24.1", "oy-vey": "^0.11.0", - "parabol-client": "7.18.0", + "parabol-client": "7.18.1", "pg": "^8.5.1", "react": "^17.0.2", "react-dom": "^17.0.2", From 55faa17ada5b1bd49182a29341b3465a82d2ddfd Mon Sep 17 00:00:00 2001 From: Jordan Husney Date: Tue, 27 Feb 2024 14:54:40 -0800 Subject: [PATCH 14/39] feat: embedder service (#9417) * feat: add embedder service --------- Signed-off-by: Matt Krick Co-authored-by: Matt Krick --- .env.example | 5 + docker/dev.yml | 17 +- package.json | 4 +- packages/embedder/.eslintrc.js | 11 + packages/embedder/README.md | 71 ++ packages/embedder/ai_models/AbstractModel.ts | 75 ++ packages/embedder/ai_models/ModelManager.ts | 153 ++++ .../ai_models/TextEmbeddingsInference.ts | 71 ++ .../ai_models/TextGenerationInference.ts | 87 ++ .../ai_models/helpers/fetchWithRetry.ts | 65 ++ packages/embedder/embedder.ts | 253 ++++++ packages/embedder/indexing/countWords.ts | 17 + .../indexing/createEmbeddingTextFrom.ts | 15 + .../embedder/indexing/embeddingsTablesOps.ts | 198 +++++ packages/embedder/indexing/getRedisClient.ts | 11 + .../embedder/indexing/getRootDataLoader.ts | 10 + .../embedder/indexing/numberVectorToString.ts | 5 + .../indexing/orgIdsWithFeatureFlag.ts | 15 + .../indexing/retrospectiveDiscussionTopic.ts | 326 ++++++++ packages/embedder/package.json | 31 + packages/embedder/tsconfig.json | 15 + .../server/dataloader/customLoaderMakers.ts | 10 +- .../server/dataloader/customRedisQueries.ts | 10 +- packages/server/postgres/getKysely.ts | 7 + .../1708127504000_updateEmbeddingMetadata.ts | 20 + pm2.config.js | 17 +- pm2.dev.config.js | 29 +- scripts/generateGraphQLArtifacts.js | 7 +- scripts/prod.js | 28 +- scripts/runEmbedder.js | 13 + scripts/webpack/dev.servers.config.js | 2 + scripts/webpack/prod.servers.config.js | 2 + scripts/webpack/toolbox.config.js | 20 + scripts/webpack/utils/transformRules.js | 3 +- yarn.lock | 759 +++++++++++++++++- 35 files changed, 2303 insertions(+), 79 deletions(-) create mode 100644 packages/embedder/.eslintrc.js create mode 100644 packages/embedder/README.md create mode 100644 packages/embedder/ai_models/AbstractModel.ts create mode 100644 packages/embedder/ai_models/ModelManager.ts create mode 100644 packages/embedder/ai_models/TextEmbeddingsInference.ts create mode 100644 packages/embedder/ai_models/TextGenerationInference.ts create mode 100644 packages/embedder/ai_models/helpers/fetchWithRetry.ts create mode 100644 packages/embedder/embedder.ts create mode 100644 packages/embedder/indexing/countWords.ts create mode 100644 packages/embedder/indexing/createEmbeddingTextFrom.ts create mode 100644 packages/embedder/indexing/embeddingsTablesOps.ts create mode 100644 packages/embedder/indexing/getRedisClient.ts create mode 100644 packages/embedder/indexing/getRootDataLoader.ts create mode 100644 packages/embedder/indexing/numberVectorToString.ts create mode 100644 packages/embedder/indexing/orgIdsWithFeatureFlag.ts create mode 100644 packages/embedder/indexing/retrospectiveDiscussionTopic.ts create mode 100644 packages/embedder/package.json create mode 100644 packages/embedder/tsconfig.json create mode 100644 packages/server/postgres/migrations/1708127504000_updateEmbeddingMetadata.ts create mode 100644 scripts/runEmbedder.js diff --git a/.env.example b/.env.example index 25c9a9c856e..0d0a44b41f0 100644 --- a/.env.example +++ b/.env.example @@ -8,6 +8,11 @@ SERVER_ID='1' # Websocket port for the websocket server, only used in development (yarn dev) SOCKET_PORT='3001' +# AI MODELS +AI_EMBEDDING_MODELS='[{"model": "text-embeddings-inference:llmrails/ember-v1", "url": "http://localhost:3040/"}]' +AI_GENERATION_MODELS='[{"model": "text-generation-inference:TheBloke/zephyr-7b-beta", "url": "http://localhost:3050/"}]' +AI_EMBEDDER_ENABLED='true' + # APPLICATION # AMPLITUDE_WRITE_KEY='key_AMPLITUDE_WRITE_KEY' # Enter a short url redirect service for invitations, it needs to redirecto to /invitation-link diff --git a/docker/dev.yml b/docker/dev.yml index 0b7de79ddb8..c45ba6b6f6b 100644 --- a/docker/dev.yml +++ b/docker/dev.yml @@ -13,8 +13,6 @@ services: - /var/run/docker.sock:/var/run/docker.sock - /proc/:/host/proc/:ro - /sys/fs/cgroup:/host/sys/fs/cgroup:ro - - "./dd-conf.d:/etc/datadog-agent/conf.d/local.d/" - - "../dev/logs:/var/log/datadog/logs" db: image: rethinkdb:2.4.2 restart: unless-stopped @@ -72,6 +70,20 @@ services: - "8082:8081" networks: parabol-network: + text-embeddings-inference: + container_name: text-embeddings-inference + image: ghcr.io/huggingface/text-embeddings-inference:cpu-0.6 + command: + - "--model-id=llmrails/ember-v1" + platform: linux/x86_64 + hostname: text-embeddings-inference + restart: unless-stopped + ports: + - "3040:80" + volumes: + - text-embeddings-inference-data:/data + networks: + parabol-network: networks: parabol-network: volumes: @@ -79,3 +91,4 @@ volumes: rethink-data: {} postgres-data: {} pgadmin-data: {} + text-embeddings-inference-data: {} diff --git a/package.json b/package.json index 179fed1c4cb..fbc0c896925 100644 --- a/package.json +++ b/package.json @@ -103,8 +103,8 @@ "html-webpack-plugin": "^5.5.0", "husky": "^7.0.4", "jscodeshift": "^0.14.0", - "kysely": "^0.26.3", - "kysely-codegen": "^0.10.0", + "kysely": "^0.27.2", + "kysely-codegen": "^0.11.0", "lerna": "^6.4.1", "mini-css-extract-plugin": "^2.7.2", "minimist": "^1.2.5", diff --git a/packages/embedder/.eslintrc.js b/packages/embedder/.eslintrc.js new file mode 100644 index 00000000000..a6a5d110f1e --- /dev/null +++ b/packages/embedder/.eslintrc.js @@ -0,0 +1,11 @@ +module.exports = { + extends: [ + '../../.eslintrc.js' + ], + parserOptions: { + project: './tsconfig.json', + ecmaVersion: 2020, + sourceType: 'module' + }, + "ignorePatterns": ["**/lib", "*.js"] +} diff --git a/packages/embedder/README.md b/packages/embedder/README.md new file mode 100644 index 00000000000..fc3fc68f335 --- /dev/null +++ b/packages/embedder/README.md @@ -0,0 +1,71 @@ +# `Embedder` + +This service builds embedding vectors for semantic search and for other AI/ML +use cases. It does so by: + +1. Updating a list of all possible items to create embedding vectors for and + storing that list in the `EmbeddingsMetadata` table +2. Adding these items in batches to the `EmbeddingsJobQueue` table and a redis + priority queue called `embedder:queue` +3. Allowing one or more parallel embedding services to calculate embedding + vectors (EmbeddingJobQueue states transistion from `queued` -> `embedding`, + then `embedding` -> [deleting the `EmbeddingJobQueue` row] + + In addition to deleteing the `EmbeddingJobQueue` row, when a job completes + successfully: + + - A row is added to the model table with the embedding vector; the + `EmbeddingMetadataId` field on this row points the appropriate + metadata row on `EmbeddingsMetadata` + - The `EmbeddingsMetadata.models` array is updated with the name of the + table that the embedding has been generated for + +4. This process repeats forever using a silly polling loop + +In the future, it would be wonderful to enhance this service such that it were +event driven. + +## Prerequisites + +The Embedder service depends on pgvector being available in Postgres. + +The predeploy script checks for an environment variable +`POSTGRES_USE_PGVECTOR=true` to enable this extension in production. + +## Configuration + +The Embedder service takes no arguments and is controlled by the following +environment variables, here given with example configuration: + +- `AI_EMBEDDER_ENABLE`: enable/disable the embedder service from + performing work, or sleeping indefinitely + +`AI_EMBEDDER_ENABLED='true'` + +- `AI_EMBEDDING_MODELS`: JSON configuration for which embedding models + are enabled. Each model in the array will be instantiated by + `ai_models/ModelManager`. Each model instance will have its own + database table created for it (if it does not exist already) used + to store calculated vectors. See `ai_models/ModelManager` for + which configurations are supported. + + Example: + +`AI_EMBEDDING_MODELS='[{"model": "text-embeddings-inference:llmrails/ember-v1", "url": "http://localhost:3040/"}]'` + +- `AI_GENERATION_MODELS`: JSON configuration for which AI generation + models (i.e. GPTS are enabled). These models are used for summarization + text to be embedded by an embedding model if the text length would be + greater than the context window of the embedding model. Each model in + the array will be instantiated by `ai_models/ModelManager`. + See `ai_models/ModelManager` for which configurations are supported. + + Example: + +`AI_GENERATION_MODELS='[{"model": "text-generation-inference:TheBloke/zephyr-7b-beta", "url": "http://localhost:3050/"}]'` + +## Usage + +The Embedder service is stateless and takes no arguments. Multiple instances +of the service may be started in order to match embedding load, or to +catch up on history more quickly. diff --git a/packages/embedder/ai_models/AbstractModel.ts b/packages/embedder/ai_models/AbstractModel.ts new file mode 100644 index 00000000000..b0f709ce485 --- /dev/null +++ b/packages/embedder/ai_models/AbstractModel.ts @@ -0,0 +1,75 @@ +export interface ModelConfig { + model: string + url: string +} + +export interface EmbeddingModelConfig extends ModelConfig { + tableSuffix: string +} + +export interface GenerationModelConfig extends ModelConfig {} + +export abstract class AbstractModel { + public readonly url?: string + public modelInstance: any + + constructor(config: ModelConfig) { + this.url = this.normalizeUrl(config.url) + } + + // removes a trailing slash from the inputUrl + private normalizeUrl(inputUrl: string | undefined) { + if (!inputUrl) return undefined + const regex = /[/]+$/ + return inputUrl.replace(regex, '') + } +} + +export interface EmbeddingModelParams { + embeddingDimensions: number + maxInputTokens: number + tableSuffix: string +} + +export abstract class AbstractEmbeddingsModel extends AbstractModel { + readonly embeddingDimensions: number + readonly maxInputTokens: number + readonly tableName: string + constructor(config: EmbeddingModelConfig) { + super(config) + const modelParams = this.constructModelParams(config) + this.embeddingDimensions = modelParams.embeddingDimensions + this.maxInputTokens = modelParams.maxInputTokens + this.tableName = `Embeddings_${modelParams.tableSuffix}` + } + protected abstract constructModelParams(config: EmbeddingModelConfig): EmbeddingModelParams + abstract getEmbedding(content: string): Promise +} + +export interface GenerationModelParams { + maxInputTokens: number +} + +export interface GenerationOptions { + maxNewTokens?: number + seed?: number + stop?: string + temperature?: number + topK?: number + topP?: number + truncate?: boolean +} + +export abstract class AbstractGenerationModel extends AbstractModel { + readonly maxInputTokens: number + constructor(config: GenerationModelConfig) { + super(config) + const modelParams = this.constructModelParams(config) + this.maxInputTokens = modelParams.maxInputTokens + } + + protected abstract constructModelParams(config: GenerationModelConfig): GenerationModelParams + abstract summarize(content: string, options: GenerationOptions): Promise +} + +export default AbstractModel diff --git a/packages/embedder/ai_models/ModelManager.ts b/packages/embedder/ai_models/ModelManager.ts new file mode 100644 index 00000000000..ac8f04cc891 --- /dev/null +++ b/packages/embedder/ai_models/ModelManager.ts @@ -0,0 +1,153 @@ +import {Kysely, sql} from 'kysely' + +import { + AbstractEmbeddingsModel, + AbstractGenerationModel, + EmbeddingModelConfig, + GenerationModelConfig, + ModelConfig +} from './AbstractModel' +import TextEmbeddingsInference from './TextEmbeddingsInference' +import TextGenerationInference from './TextGenerationInference' + +interface ModelManagerConfig { + embeddingModels: EmbeddingModelConfig[] + generationModels: GenerationModelConfig[] +} + +export type EmbeddingsModelType = 'text-embeddings-inference' +export type GenerationModelType = 'text-generation-inference' + +export class ModelManager { + embeddingModels: AbstractEmbeddingsModel[] + embeddingModelsMapByTable: {[key: string]: AbstractEmbeddingsModel} + generationModels: AbstractGenerationModel[] + + private isValidConfig( + maybeConfig: Partial + ): maybeConfig is ModelManagerConfig { + if (!maybeConfig.embeddingModels || !Array.isArray(maybeConfig.embeddingModels)) { + throw new Error('Invalid configuration: embedding_models is missing or not an array') + } + if (!maybeConfig.generationModels || !Array.isArray(maybeConfig.generationModels)) { + throw new Error('Invalid configuration: summarization_models is missing or not an array') + } + + maybeConfig.embeddingModels.forEach((model: ModelConfig) => { + this.isValidModelConfig(model) + }) + + maybeConfig.generationModels.forEach((model: ModelConfig) => { + this.isValidModelConfig(model) + }) + + return true + } + + private isValidModelConfig(model: ModelConfig): model is ModelConfig { + if (typeof model.model !== 'string') { + throw new Error('Invalid ModelConfig: model field should be a string') + } + if (model.url !== undefined && typeof model.url !== 'string') { + throw new Error('Invalid ModelConfig: url field should be a string') + } + + return true + } + + constructor(config: ModelManagerConfig) { + // Validate configuration + this.isValidConfig(config) + + // Initialize embeddings models + this.embeddingModelsMapByTable = {} + this.embeddingModels = config.embeddingModels.map((modelConfig) => { + const [modelType] = modelConfig.model.split(':') as [EmbeddingsModelType, string] + + switch (modelType) { + case 'text-embeddings-inference': { + const embeddingsModel = new TextEmbeddingsInference(modelConfig) + this.embeddingModelsMapByTable[embeddingsModel.tableName] = embeddingsModel + return embeddingsModel + } + default: + throw new Error(`unsupported embeddings model '${modelType}'`) + } + }) + + // Initialize summarization models + this.generationModels = config.generationModels.map((modelConfig) => { + const [modelType, _] = modelConfig.model.split(':') as [GenerationModelType, string] + + switch (modelType) { + case 'text-generation-inference': { + const generator = new TextGenerationInference(modelConfig) + return generator + } + default: + throw new Error(`unsupported summarization model '${modelType}'`) + } + }) + } + + async maybeCreateTables(pg: Kysely) { + const maybePromises = this.embeddingModels.map(async (embeddingsModel) => { + const tableName = embeddingsModel.tableName + const hasTable = + ( + await sql`SELECT 1 FROM ${sql.id('pg_catalog', 'pg_tables')} WHERE ${sql.id( + 'tablename' + )} = ${tableName}`.execute(pg) + ).rows.length > 0 + if (hasTable) return undefined + const vectorDimensions = embeddingsModel.embeddingDimensions + console.log(`ModelManager: creating ${tableName} with ${vectorDimensions} dimensions`) + const query = sql` + DO $$ + BEGIN + CREATE TABLE IF NOT EXISTS ${sql.id(tableName)} ( + "id" INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + "embedText" TEXT, + "embedding" vector(${sql.raw(vectorDimensions.toString())}), + "embeddingsMetadataId" INTEGER NOT NULL, + FOREIGN KEY ("embeddingsMetadataId") + REFERENCES "EmbeddingsMetadata"("id") + ON DELETE CASCADE + ); + CREATE INDEX IF NOT EXISTS "idx_${sql.raw(tableName)}_embedding_vector_cosign_ops" + ON ${sql.id(tableName)} + USING hnsw ("embedding" vector_cosine_ops); + END $$; + + ` + return query.execute(pg) + }) + Promise.all(maybePromises) + } +} + +let modelManager: ModelManager | undefined +export function getModelManager() { + if (modelManager) return modelManager + const {AI_EMBEDDING_MODELS, AI_GENERATION_MODELS} = process.env + const config: ModelManagerConfig = { + embeddingModels: [], + generationModels: [] + } + try { + config.embeddingModels = AI_EMBEDDING_MODELS && JSON.parse(AI_EMBEDDING_MODELS) + } catch (e) { + throw new Error(`Invalid AI_EMBEDDING_MODELS .env JSON: ${e}`) + } + try { + config.generationModels = AI_GENERATION_MODELS && JSON.parse(AI_GENERATION_MODELS) + } catch (e) { + throw new Error(`Invalid AI_GENERATION_MODELS .env JSON: ${e}`) + } + + modelManager = new ModelManager(config) + + return modelManager +} + +export default getModelManager diff --git a/packages/embedder/ai_models/TextEmbeddingsInference.ts b/packages/embedder/ai_models/TextEmbeddingsInference.ts new file mode 100644 index 00000000000..93bb2c88c2f --- /dev/null +++ b/packages/embedder/ai_models/TextEmbeddingsInference.ts @@ -0,0 +1,71 @@ +import {AbstractEmbeddingsModel, EmbeddingModelConfig, EmbeddingModelParams} from './AbstractModel' +import fetchWithRetry from './helpers/fetchWithRetry' + +const MAX_REQUEST_TIME_S = 3 * 60 + +export type ModelId = 'BAAI/bge-large-en-v1.5' | 'llmrails/ember-v1' + +const modelIdDefinitions: Record = { + 'BAAI/bge-large-en-v1.5': { + embeddingDimensions: 1024, + maxInputTokens: 512, + tableSuffix: 'bge_l_en_1p5' + }, + 'llmrails/ember-v1': { + embeddingDimensions: 1024, + maxInputTokens: 512, + tableSuffix: 'ember_1' + } +} + +function isValidModelId(object: any): object is ModelId { + return Object.keys(modelIdDefinitions).includes(object) +} + +export class TextEmbeddingsInference extends AbstractEmbeddingsModel { + constructor(config: EmbeddingModelConfig) { + super(config) + } + + public async getEmbedding(content: string) { + const fetchOptions = { + body: JSON.stringify({inputs: content}), + deadline: new Date(new Date().getTime() + MAX_REQUEST_TIME_S * 1000), + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json; charset=utf-8' + }, + method: 'POST' + } + + try { + const res = await fetchWithRetry(`${this.url}/embed`, fetchOptions) + const listOfVectors = (await res.json()) as Array + if (!listOfVectors) + throw new Error('TextEmbeddingsInference.getEmbeddings(): listOfVectors is undefined') + if (listOfVectors.length !== 1 || !listOfVectors[0]) + throw new Error( + `TextEmbeddingsInference.getEmbeddings(): listOfVectors list length !== 1 (length: ${listOfVectors.length})` + ) + return listOfVectors[0] + } catch (e) { + console.log(`TextEmbeddingsInference.getEmbeddings() timeout: `, e) + throw e + } + } + + protected constructModelParams(config: EmbeddingModelConfig): EmbeddingModelParams { + const modelConfigStringSplit = config.model.split(':') + if (modelConfigStringSplit.length != 2) { + throw new Error('TextGenerationInference model string must be colon-delimited and len 2') + } + + if (!this.url) throw new Error('TextGenerationInferenceSummarizer model requires url') + const maybeModelId = modelConfigStringSplit[1] + if (!isValidModelId(maybeModelId)) + throw new Error(`TextGenerationInference model subtype unknown: ${maybeModelId}`) + return modelIdDefinitions[maybeModelId] + } +} + +export default TextEmbeddingsInference diff --git a/packages/embedder/ai_models/TextGenerationInference.ts b/packages/embedder/ai_models/TextGenerationInference.ts new file mode 100644 index 00000000000..6f12ce09974 --- /dev/null +++ b/packages/embedder/ai_models/TextGenerationInference.ts @@ -0,0 +1,87 @@ +import { + AbstractGenerationModel, + GenerationModelConfig, + GenerationModelParams, + GenerationOptions +} from './AbstractModel' +import fetchWithRetry from './helpers/fetchWithRetry' + +const MAX_REQUEST_TIME_S = 3 * 60 + +export type ModelId = 'TheBloke/zephyr-7b-beta' + +const modelIdDefinitions: Record = { + 'TheBloke/zephyr-7b-beta': { + maxInputTokens: 512 + } +} + +function isValidModelId(object: any): object is ModelId { + return Object.keys(modelIdDefinitions).includes(object) +} + +export class TextGenerationInference extends AbstractGenerationModel { + constructor(config: GenerationModelConfig) { + super(config) + } + + public async summarize(content: string, options: GenerationOptions) { + const { + maxNewTokens: max_new_tokens = 512, + seed, + stop, + temperature = 0.8, + topP, + topK, + truncate + } = options + const parameters = { + max_new_tokens, + seed, + stop, + temperature, + topP, + topK, + truncate + } + const prompt = `Create a brief, one-paragraph summary of the following: ${content}` + const fetchOptions = { + body: JSON.stringify({ + inputs: prompt, + parameters + }), + deadline: new Date(new Date().getTime() + MAX_REQUEST_TIME_S * 1000), + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json; charset=utf-8' + }, + method: 'POST' + } + + try { + // console.log(`TextGenerationInterface.summarize(): summarizing from ${this.url}/generate`) + const res = await fetchWithRetry(`${this.url}/generate`, fetchOptions) + const json = await res.json() + if (!json || !json.generated_text) + throw new Error('TextGenerationInterface.summarize(): malformed response') + return json.generated_text as string + } catch (e) { + console.log('TextGenerationInterfaceSummarizer.summarize(): timeout') + throw e + } + } + protected constructModelParams(config: GenerationModelConfig): GenerationModelParams { + const modelConfigStringSplit = config.model.split(':') + if (modelConfigStringSplit.length != 2) { + throw new Error('TextGenerationInterface model string must be colon-delimited and len 2') + } + + if (!this.url) throw new Error('TextGenerationInterfaceSummarizer model requires url') + const maybeModelId = modelConfigStringSplit[1] + if (!isValidModelId(maybeModelId)) + throw new Error(`TextGenerationInterface model subtype unknown: ${maybeModelId}`) + return modelIdDefinitions[maybeModelId] + } +} + +export default TextGenerationInference diff --git a/packages/embedder/ai_models/helpers/fetchWithRetry.ts b/packages/embedder/ai_models/helpers/fetchWithRetry.ts new file mode 100644 index 00000000000..98343ef26e6 --- /dev/null +++ b/packages/embedder/ai_models/helpers/fetchWithRetry.ts @@ -0,0 +1,65 @@ +interface FetchWithRetryOptions extends RequestInit { + deadline: Date // Deadline for the request to complete + debug?: boolean // Enable debug tracing + retryStatusCodes?: number[] // Array of status codes to retry on +} + +export default async (url: RequestInfo, options: FetchWithRetryOptions): Promise => { + const {deadline, debug = false, retryStatusCodes = [429], ...fetchOptions} = options + let attempt = 0 + const controller = new AbortController() + fetchOptions.signal = controller.signal + + const timeout = deadline.getTime() - Date.now() + if (timeout <= 0) { + throw new Error('Deadline has already passed') + } + + const timeoutId = setTimeout(() => controller.abort(), timeout) + + try { + while (Date.now() < deadline.getTime()) { + attempt++ + + if (debug) { + console.log(`Attempt ${attempt}: Fetching ${url}`) + } + + const response = await fetch(url, fetchOptions) + + if (!retryStatusCodes.includes(response.status)) { + clearTimeout(timeoutId) + return response + } + + const retryAfter = response.headers.get('Retry-After') + // if Retry-After specified, use it; else fallback to exponential backoff + let waitTime = retryAfter ? parseInt(retryAfter, 10) * 1000 : Math.pow(2, attempt) * 1000 + + // cap waitTime to prevent exceeding the deadline + waitTime = Math.min(waitTime, deadline.getTime() - Date.now()) + + if (debug) { + console.log( + `Waiting ${waitTime / 1000} seconds before retrying due to status ${response.status}...` + ) + } + await new Promise((resolve) => setTimeout(resolve, waitTime)) + } + + throw new Error('Deadline exceeded') + } catch (error) { + clearTimeout(timeoutId) + if (error instanceof Error && error.name === 'AbortError') { + throw new Error('Request aborted due to deadline') + } + if (debug) { + console.error(`Attempt ${attempt} failed: ${error}`) + } + const currentTime = Date.now() + if (currentTime >= deadline.getTime()) { + throw new Error('Deadline exceeded before a successful request') + } + throw error // Re-throw the error if it's not related to deadline exceeding + } +} diff --git a/packages/embedder/embedder.ts b/packages/embedder/embedder.ts new file mode 100644 index 00000000000..1072a546d00 --- /dev/null +++ b/packages/embedder/embedder.ts @@ -0,0 +1,253 @@ +import {Insertable} from 'kysely' +import tracer from 'dd-trace' +import Redlock, {RedlockAbortSignal} from 'redlock' + +import 'parabol-server/initSentry' +import getKysely from 'parabol-server/postgres/getKysely' +import {DB} from 'parabol-server/postgres/pg' +import {refreshRetroDiscussionTopicsMeta as refreshRetroDiscussionTopicsMeta} from './indexing/retrospectiveDiscussionTopic' +import {orgIdsWithFeatureFlag} from './indexing/orgIdsWithFeatureFlag' +import getModelManager, {ModelManager} from './ai_models/ModelManager' +import {countWords} from './indexing/countWords' +import {createEmbeddingTextFrom} from './indexing/createEmbeddingTextFrom' +import { + selectJobQueueItemById, + selectMetadataByJobQueueId, + updateJobState +} from './indexing/embeddingsTablesOps' +import {selectMetaToQueue} from './indexing/embeddingsTablesOps' +import {insertNewJobs} from './indexing/embeddingsTablesOps' +import {completeJobTxn} from './indexing/embeddingsTablesOps' +import {getRootDataLoader} from './indexing/getRootDataLoader' +import {getRedisClient} from './indexing/getRedisClient' + +/* + * TODO List + * - [ ] implement a clean-up function that re-queues items that haven't transitioned + * to a completed state, or that failed + */ + +export type DBInsert = { + [K in keyof DB]: Insertable +} + +const POLLING_PERIOD_SEC = 60 // How often do we try to grab the lock and re-index? +const Q_MAX_LENGTH = 100 // How many EmbeddingIndex items do we batch in redis? +const WORD_COUNT_TO_TOKEN_RATIO = 3.0 / 2 // We multiple the word count by this to estimate token count + +const {AI_EMBEDDER_ENABLED} = process.env +const {SERVER_ID} = process.env + +tracer.init({ + service: `embedder`, + appsec: process.env.DD_APPSEC_ENABLED === 'true', + plugins: false, + version: process.env.npm_package_version +}) +tracer.use('pg') + +const refreshMetadata = async () => { + const dataLoader = getRootDataLoader() + await refreshRetroDiscussionTopicsMeta(dataLoader) + // In the future, other sorts of objects to index could be added here... +} +const maybeQueueMetadataItems = async (modelManager: ModelManager) => { + const redisClient = getRedisClient() + const queueLength = await redisClient.zcard('embedder:queue') + if (queueLength >= Q_MAX_LENGTH) return + const itemCountToQueue = Q_MAX_LENGTH - queueLength + const modelTables = modelManager.embeddingModels.map((m) => m.tableName) + const orgIds = await orgIdsWithFeatureFlag() + + // For each configured embedding model, select rows from EmbeddingsMetadata + // that haven't been calculated nor exist in the EmbeddingsJobQueue yet + // + // Notes: + // * `em.models @> ARRAY[v.model]` is an indexed query + // * I don't love all overrides, I wish there was a better way + // see: https://github.com/kysely-org/kysely/issues/872 + + const batchToQueue = await selectMetaToQueue(modelTables, orgIds, itemCountToQueue) + + if (!batchToQueue.length) { + console.log(`embedder: no new items to queue`) + return + } + + const ejqHash: { + [key: string]: { + refUpdatedAt: Date + } + } = {} + const makeKey = (item: {objectType: string; refId: string}) => `${item.objectType}:${item.refId}` + + const ejqValues = batchToQueue.map((item) => { + ejqHash[makeKey(item)] = { + refUpdatedAt: item.refUpdatedAt + } + return { + objectType: item.objectType, + refId: item.refId as string, + model: item.model, + state: 'queued' as const + } + }) + + const ejqRows = await insertNewJobs(ejqValues) + + ejqRows.forEach((item) => { + const {refUpdatedAt} = ejqHash[makeKey(item)]! + const score = new Date(refUpdatedAt).getTime() + redisClient.zadd('embedder:queue', score, item.id) + }) + + console.log(`embedder: queued ${batchToQueue.length} items`) +} + +const dequeueAndEmbedUntilEmpty = async (modelManager: ModelManager) => { + const dataLoader = getRootDataLoader() + const redisClient = getRedisClient() + while (true) { + const maybeRedisQItem = await redisClient.zpopmax('embedder:queue', 1) + if (maybeRedisQItem.length < 2) return // Q is empty, all done! + + const [id, _] = maybeRedisQItem + if (!id) { + console.log(`embedder: de-queued undefined item from embedder:queue`) + continue + } + const jobQueueId = parseInt(id, 10) + const jobQueueItem = await selectJobQueueItemById(jobQueueId) + if (!jobQueueItem) { + console.log(`embedder: unable to fetch EmbeddingsJobQueue.id = ${id}`) + continue + } + + const metadata = await selectMetadataByJobQueueId(jobQueueId) + if (!metadata) { + await updateJobState(jobQueueId, 'failed', { + stateMessage: `unable to fetch metadata by EmbeddingsJobQueue.id = ${id}` + }) + continue + } + + let fullText = metadata?.fullText + try { + if (!fullText) { + fullText = await createEmbeddingTextFrom(jobQueueItem, dataLoader) + } + } catch (e) { + await updateJobState(jobQueueId, 'failed', { + stateMessage: `unable to create embedding text: ${e}` + }) + continue + } + + const wordCount = countWords(fullText) + + const embeddingModel = modelManager.embeddingModelsMapByTable[jobQueueItem.model] + if (!embeddingModel) { + await updateJobState(jobQueueId, 'failed', { + stateMessage: `embedding model ${jobQueueItem.model} not available` + }) + continue + } + const itemKey = `${jobQueueItem.objectType}:${jobQueueItem.refId}` + const modelTable = embeddingModel.tableName + + let embedText = fullText + const maxInputTokens = embeddingModel.maxInputTokens + // we're using word count as an appoximation of tokens + if (wordCount * WORD_COUNT_TO_TOKEN_RATIO > maxInputTokens) { + try { + const generator = modelManager.generationModels[0] // use 1st generator + if (!generator) throw new Error(`Generator unavailable`) + const summarizeOptions = {maxInputTokens, truncate: true} + console.log(`embedder: ...summarizing ${itemKey} for ${modelTable}`) + embedText = await generator.summarize(fullText, summarizeOptions) + } catch (e) { + await updateJobState(jobQueueId, 'failed', { + stateMessage: `unable to summarize long embed text: ${e}` + }) + continue + } + } + // console.log(`embedText: ${embedText}`) + + let embeddingVector: number[] + try { + embeddingVector = await embeddingModel.getEmbedding(embedText) + } catch (e) { + await updateJobState(jobQueueId, 'failed', { + stateMessage: `unable to get embeddings: ${e}` + }) + continue + } + + // complete job, do the following atomically + // (1) update EmbeddingsMetadata to reflect model completion + // (2) upsert model table row with embedding + // (3) delete EmbeddingsJobQueue row + await completeJobTxn(modelTable, jobQueueId, metadata, fullText, embedText, embeddingVector) + console.log(`embedder: completed ${itemKey} -> ${modelTable}`) + } +} + +const tick = async (modelManager: ModelManager) => { + console.log(`embedder: tick`) + const redisClient = getRedisClient() + const redlock = new Redlock([redisClient], { + driftFactor: 0.01, + retryCount: 10, + retryDelay: 250, + retryJitter: 50, + automaticExtensionThreshold: 500 + }) + + await redlock + .using(['embedder:lock'], 10000, async (signal: RedlockAbortSignal) => { + console.log(`embedder: acquired index queue lock`) + // N.B. one of the many benefits of using redlock is the using() interface + // will automatically extend the lock if these operations exceed the + // original redis timeout time + await refreshMetadata() + await maybeQueueMetadataItems(modelManager) + + if (signal.aborted) { + // Not certain which conditions this would happen, it would + // happen after operations took place, so nothing much to do here. + console.log('embedder: lock was lost!') + } + }) + .catch((err: string) => { + // Handle errors (including lock acquisition errors) + console.error('embedder: an error occurred ', err) + }) + console.log('embedder: index queue lock released') + + // get the highest priority item and embed it + await dequeueAndEmbedUntilEmpty(modelManager) + + setTimeout(() => tick(modelManager), POLLING_PERIOD_SEC * 1000) +} + +function parseEnvBoolean(envVarValue: string | undefined): boolean { + return envVarValue === 'true' +} + +const run = async () => { + console.log(`embedder: run()`) + const embedderEnabled = parseEnvBoolean(AI_EMBEDDER_ENABLED) + const modelManager = getModelManager() + if (embedderEnabled && modelManager) { + const pg = getKysely() + await modelManager.maybeCreateTables(pg) + console.log(`\n⚡⚡⚡️️ Server ID: ${SERVER_ID}. Embedder is ready ⚡⚡⚡️️️`) + tick(modelManager) + } else { + console.log(`embedder: no valid configuration (check AI_EMBEDDER_ENABLED in .env)`) + // exit + } +} + +run() diff --git a/packages/embedder/indexing/countWords.ts b/packages/embedder/indexing/countWords.ts new file mode 100644 index 00000000000..75dae3effa2 --- /dev/null +++ b/packages/embedder/indexing/countWords.ts @@ -0,0 +1,17 @@ +export function countWords(text: string) { + let count = 0 + let inWord = false + + for (const char of text) { + if (/\w/.test(char)) { + if (!inWord) { + count++ + inWord = true + } + } else { + inWord = false + } + } + + return count +} diff --git a/packages/embedder/indexing/createEmbeddingTextFrom.ts b/packages/embedder/indexing/createEmbeddingTextFrom.ts new file mode 100644 index 00000000000..9d6e66b60e7 --- /dev/null +++ b/packages/embedder/indexing/createEmbeddingTextFrom.ts @@ -0,0 +1,15 @@ +import {Selectable} from 'kysely' +import {DB} from 'parabol-server/postgres/pg' +import {DataLoaderWorker} from 'parabol-server/graphql/graphql' + +import {createText as createTextFromRetrospectiveDiscussionTopic} from './retrospectiveDiscussionTopic' + +export const createEmbeddingTextFrom = async ( + item: Selectable, + dataLoader: DataLoaderWorker +): Promise => { + switch (item.objectType) { + case 'retrospectiveDiscussionTopic': + return createTextFromRetrospectiveDiscussionTopic(item, dataLoader) + } +} diff --git a/packages/embedder/indexing/embeddingsTablesOps.ts b/packages/embedder/indexing/embeddingsTablesOps.ts new file mode 100644 index 00000000000..b68bc21ccbe --- /dev/null +++ b/packages/embedder/indexing/embeddingsTablesOps.ts @@ -0,0 +1,198 @@ +import {Insertable, Selectable, Updateable, sql} from 'kysely' +import getKysely from 'parabol-server/postgres/getKysely' +import {DB} from 'parabol-server/postgres/pg' +import {DBInsert} from '../embedder' +import {RawBuilder} from 'kysely' +import numberVectorToString from './numberVectorToString' + +function unnestedArray(maybeArray: T[] | T): RawBuilder { + let a: T[] = Array.isArray(maybeArray) ? maybeArray : [maybeArray] + return sql`unnest(ARRAY[${sql.join(a)}]::varchar[])` +} + +export const selectJobQueueItemById = async ( + id: number +): Promise | undefined> => { + const pg = getKysely() + return pg.selectFrom('EmbeddingsJobQueue').selectAll().where('id', '=', id).executeTakeFirst() +} +export const selectMetadataByJobQueueId = async ( + id: number +): Promise | undefined> => { + const pg = getKysely() + return pg + .selectFrom('EmbeddingsMetadata as em') + .selectAll() + .leftJoin('EmbeddingsJobQueue as ejq', (join) => + join.onRef('em.objectType', '=', 'ejq.objectType').onRef('em.refId', '=', 'ejq.refId') + ) + .where('ejq.id', '=', id) + .executeTakeFirstOrThrow() +} + +// For each configured embedding model, select rows from EmbeddingsMetadata +// that haven't been calculated nor exist in the EmbeddingsJobQueue yet +// +// Notes: +// * `em.models @> ARRAY[v.model]` is an indexed query +// * I don't love all overrides, I wish there was a better way +// see: https://github.com/kysely-org/kysely/issues/872 +export async function selectMetaToQueue( + configuredModels: string[], + orgIds: any[], + itemCountToQueue: number +) { + const pg = getKysely() + const maybeMetaToQueue = (await pg + .selectFrom('EmbeddingsMetadata as em') + .selectAll('em') + .leftJoinLateral(unnestedArray(configuredModels).as('model'), (join) => join.onTrue()) + .leftJoin('Team as t', 'em.teamId', 't.id') + .select('model' as any) + .where(({eb, not, or, and, exists, selectFrom}) => + and([ + or([ + not(eb('em.models', '<@', sql`ARRAY[${sql.ref('model')}]::varchar[]` as any) as any), + eb('em.models' as any, 'is', null) + ]), + not( + exists( + selectFrom('EmbeddingsJobQueue as ejq') + .select('ejq.id') + .whereRef('em.objectType', '=', 'ejq.objectType') + .whereRef('em.refId', '=', 'ejq.refId') + .whereRef('ejq.model', '=', 'model' as any) + ) + ), + eb('t.orgId', 'in', orgIds) + ]) + ) + .limit(itemCountToQueue) + .execute()) as unknown as Selectable[] + + type MetadataToQueue = Selectable< + Omit & { + refId: NonNullable + } & {model: string} + > + + return maybeMetaToQueue.filter( + (item) => item.refId !== null && item.refId !== undefined + ) as MetadataToQueue[] +} + +export const updateJobState = async ( + id: number, + state: Updateable['state'], + jobQueueFields: Updateable = {} +) => { + const pg = getKysely() + const jobQueueColumns: Updateable = { + ...jobQueueFields, + state + } + if (state === 'failed') console.log(`embedder: failed job ${id}, ${jobQueueFields.stateMessage}`) + return pg + .updateTable('EmbeddingsJobQueue') + .set(jobQueueColumns) + .where('id', '=', id) + .executeTakeFirstOrThrow() +} + +export function insertNewJobs(ejqValues: Insertable[]) { + const pg = getKysely() + return pg + .insertInto('EmbeddingsJobQueue') + .values(ejqValues) + .returning(['id', 'objectType', 'refId']) + .execute() +} + +// complete job, do the following atomically +// (1) update EmbeddingsMetadata to reflect model completion +// (2) upsert model table row with embedding +// (3) delete EmbeddingsJobQueue row +export function completeJobTxn( + modelTable: string, + jobQueueId: number, + metadata: Updateable, + fullText: string, + embedText: string, + embeddingVector: number[] +) { + const pg = getKysely() + return pg.transaction().execute(async (trx) => { + // get fields to update correct metadata row + const jobQueueItem = await trx + .selectFrom('EmbeddingsJobQueue') + .select(['objectType', 'refId', 'model']) + .where('id', '=', jobQueueId) + .executeTakeFirstOrThrow() + + // (1) update metadata row + const metadataColumnsToUpdate: { + models: RawBuilder + fullText?: string | null | undefined + } = { + // update models as a set + models: sql`( +SELECT array_agg(DISTINCT value) +FROM ( + SELECT unnest(COALESCE("models", '{}')) AS value + UNION + SELECT unnest(ARRAY[${modelTable}]::VARCHAR[]) AS value +) AS combined_values +)` + } + + if (metadata?.fullText !== fullText) { + metadataColumnsToUpdate.fullText = fullText + } + + const updatedMetadata = await trx + .updateTable('EmbeddingsMetadata') + .set(metadataColumnsToUpdate) + .where('objectType', '=', jobQueueItem.objectType) + .where('refId', '=', jobQueueItem.refId) + .returning(['id']) + .executeTakeFirstOrThrow() + + // (2) upsert into model table + await trx + .insertInto(modelTable as any) + .values({ + embedText: fullText !== embedText ? embedText : null, + embedding: numberVectorToString(embeddingVector), + embeddingsMetadataId: updatedMetadata.id + }) + .onConflict((oc) => + oc.column('id').doUpdateSet((eb) => ({ + embedText: eb.ref('excluded.embedText'), + embeddingsMetadataId: eb.ref('excluded.embeddingsMetadataId') + })) + ) + .executeTakeFirstOrThrow() + + // (3) delete completed job queue item + return await trx + .deleteFrom('EmbeddingsJobQueue') + .where('id', '=', jobQueueId) + .executeTakeFirstOrThrow() + }) +} +export async function upsertEmbeddingsMetaRows( + embeddingsMetaRows: DBInsert['EmbeddingsMetadata'][] +) { + const pg = getKysely() + return pg + .insertInto('EmbeddingsMetadata') + .values(embeddingsMetaRows) + .onConflict((oc) => + oc.columns(['objectType', 'refId']).doUpdateSet((eb) => ({ + objectType: eb.ref('excluded.objectType'), + refId: eb.ref('excluded.refId'), + refUpdatedAt: eb.ref('excluded.refUpdatedAt') + })) + ) + .execute() +} diff --git a/packages/embedder/indexing/getRedisClient.ts b/packages/embedder/indexing/getRedisClient.ts new file mode 100644 index 00000000000..7aaf65be33c --- /dev/null +++ b/packages/embedder/indexing/getRedisClient.ts @@ -0,0 +1,11 @@ +import RedisInstance from 'parabol-server/utils/RedisInstance' + +const {SERVER_ID} = process.env + +let redisClient: RedisInstance +export const getRedisClient = () => { + if (!redisClient) { + redisClient = new RedisInstance(`embedder-${SERVER_ID}`) + } + return redisClient +} diff --git a/packages/embedder/indexing/getRootDataLoader.ts b/packages/embedder/indexing/getRootDataLoader.ts new file mode 100644 index 00000000000..304c0c01058 --- /dev/null +++ b/packages/embedder/indexing/getRootDataLoader.ts @@ -0,0 +1,10 @@ +import getDataLoader from 'parabol-server/graphql/getDataLoader' +import {DataLoaderWorker} from 'parabol-server/graphql/graphql' + +let rootDataLoader: DataLoaderWorker +export const getRootDataLoader = () => { + if (!rootDataLoader) { + rootDataLoader = getDataLoader() as DataLoaderWorker + } + return rootDataLoader +} diff --git a/packages/embedder/indexing/numberVectorToString.ts b/packages/embedder/indexing/numberVectorToString.ts new file mode 100644 index 00000000000..df49a716d57 --- /dev/null +++ b/packages/embedder/indexing/numberVectorToString.ts @@ -0,0 +1,5 @@ +function numberVectorToString(vector: number[]): string { + return '[' + vector.join(', ') + ']' +} + +export default numberVectorToString diff --git a/packages/embedder/indexing/orgIdsWithFeatureFlag.ts b/packages/embedder/indexing/orgIdsWithFeatureFlag.ts new file mode 100644 index 00000000000..82d86702e67 --- /dev/null +++ b/packages/embedder/indexing/orgIdsWithFeatureFlag.ts @@ -0,0 +1,15 @@ +import getRethink from 'parabol-server/database/rethinkDriver' +import {RDatum} from 'parabol-server/database/stricterR' + +export const orgIdsWithFeatureFlag = async () => { + // I had to add a secondary index to the Organization table to get + // this query to be cheap + const r = await getRethink() + return await r + .table('Organization') + .getAll('relatedDiscussions', {index: 'featureFlagsIndex' as any}) + .filter((r: RDatum) => r('featureFlags').contains('relatedDiscussions')) + .map((r: RDatum) => r('id')) + .coerceTo('array') + .run() +} diff --git a/packages/embedder/indexing/retrospectiveDiscussionTopic.ts b/packages/embedder/indexing/retrospectiveDiscussionTopic.ts new file mode 100644 index 00000000000..f31aab74cc2 --- /dev/null +++ b/packages/embedder/indexing/retrospectiveDiscussionTopic.ts @@ -0,0 +1,326 @@ +import {Selectable} from 'kysely' +import prettier from 'prettier' + +import getRethink, {RethinkSchema} from 'parabol-server/database/rethinkDriver' +import {DataLoaderWorker} from 'parabol-server/graphql/graphql' +import getKysely from 'parabol-server/postgres/getKysely' +import {DB} from 'parabol-server/postgres/pg' + +import Comment from 'parabol-server/database/types/Comment' +import DiscussStage from 'parabol-server/database/types/DiscussStage' +import MeetingRetrospective, { + isMeetingRetrospective +} from 'parabol-server/database/types/MeetingRetrospective' + +import {upsertEmbeddingsMetaRows} from './embeddingsTablesOps' +import {AnyMeeting} from 'parabol-server/postgres/types/Meeting' + +const BATCH_SIZE = 1000 + +export interface EmbeddingsJobQueueRetrospectiveDiscussionTopic + extends Omit { + objectType: 'retrospectiveDiscussionTopic' +} + +// Here's a generic reprentation of the text generated here: + +// A topic "" was discussed during the meeting "" +// that followed the "" template. +// +// +// Participants were prompted with, ": ". +// - wrote, "" +// +// +// +// +// A discussion was held. +// + +const IGNORE_COMMENT_USER_IDS = ['parabolAIUser'] + +const pg = getKysely() + +export async function refreshRetroDiscussionTopicsMeta(dataLoader: DataLoaderWorker) { + const r = await getRethink() + const {createdAt: newestMeetingDate} = (await r + .table('NewMeeting') + .max({index: 'createdAt'}) + .run()) as unknown as RethinkSchema['NewMeeting']['type'] + const {createdAt: oldestMeetingDate} = (await r + .table('NewMeeting') + .min({index: 'createdAt'}) + .run()) as unknown as RethinkSchema['NewMeeting']['type'] + + const {newestMetaDate} = (await pg + .selectFrom('EmbeddingsMetadata') + .select(pg.fn.max('refUpdatedAt').as('newestMetaDate')) + .where('objectType', '=', 'retrospectiveDiscussionTopic') + .executeTakeFirst()) ?? {newestMetaDate: null} + let startDateTime = newestMetaDate || oldestMeetingDate + + if (startDateTime.getTime() === newestMeetingDate.getTime()) return + + console.log( + `refreshRetroDiscussionTopicsMeta(): ` + + `will consider adding items from ${startDateTime.toISOString()} to ` + + `${newestMeetingDate.toISOString()}` + ) + + let totalAdded = 0 + do { + // Process history in batches. + // + // N.B. We add historical meetings to the EmbeddingsMetadata table here. + // This query will intentionally miss meetings that haven't been completed + // (`summarySentAt` is null). These meetings will need to be added to the + // EmbeddingsMetadata table by a hook that runs when the meetings complete. + const {maxCreatedAt, completedNewMeetings} = await r + .table('NewMeeting') + .between(startDateTime, newestMeetingDate, {rightBound: 'closed', index: 'createdAt'}) + .orderBy({index: 'createdAt'}) + .limit(BATCH_SIZE) + .coerceTo('array') + .do((rows: any) => ({ + maxCreatedAt: r.expr(rows).max('createdAt')('createdAt'), // Then find the max createdAt value + completedNewMeetings: r.expr(rows).filter((r: any) => + r('meetingType') + .eq('retrospective') + .and( + r('endedAt').gt(0), + r + .hasFields('phases') + .and(r('phases').count().gt(0)) + .and( + r('phases') + .filter((phase: any) => phase('phaseType').eq('discuss')) + .filter((phase: any) => + phase.hasFields('stages').and(phase('stages').count().gt(0)) + ) + .count() + .gt(0) + ) + ) + ) + })) + .run() + const embeddingsMetaRows = ( + await Promise.all( + completedNewMeetings.map((m: AnyMeeting) => + newRetroDiscussionTopicsFromNewMeeting(m, dataLoader) + ) + ) + ).flat() + if (embeddingsMetaRows.length > 0) { + await upsertEmbeddingsMetaRows(embeddingsMetaRows) + totalAdded += embeddingsMetaRows.length + console.log( + `refreshRetroDiscussionTopicsMeta(): synced to ${maxCreatedAt.toISOString()}, added` + + ` ${embeddingsMetaRows.length} retrospectiveDiscussionTopics` + ) + } + + // N.B. In the unlikely event that we have >=BATCH_SIZE meetings that end at _exactly_ + // the same timetsamp, this will loop forever. + if ( + startDateTime.getTime() === newestMeetingDate.getTime() && + completedNewMeetings.length < BATCH_SIZE + ) + break + startDateTime = maxCreatedAt + } while (true) + + console.log( + `refreshRetroDiscussionTopicsMeta(): added ${totalAdded} total retrospectiveDiscussionTopics` + ) +} + +async function getPreferredNameByUserId(userId: string, dataLoader: DataLoaderWorker) { + const user = await dataLoader.get('users').load(userId) + return !user ? 'Unknown' : user.preferredName +} + +async function formatThread( + dataLoader: DataLoaderWorker, + comments: Comment[], + parentId: string | null = null, + depth = 0 +): Promise { + // Filter and sort comments as before + const filteredComments = comments + .filter((comment) => comment.threadParentId === parentId) + .sort((a, b) => (a.threadSortOrder < b.threadSortOrder ? -1 : 1)) + + // Use map to create an array of promises for each formatted comment string + const formattedCommentsPromises = filteredComments.map(async (comment) => { + const indent = ' '.repeat(depth + 1) + const author = comment.isAnonymous + ? 'Anonymous' + : comment.createdBy + ? await getPreferredNameByUserId(comment.createdBy, dataLoader) + : 'Unknown' + const how = depth === 0 ? 'wrote' : 'replied' + const content = comment.plaintextContent + const formattedPost = `${indent}- ${author} ${how}, "${content}"\n` + + // Recursively format child threads + const childThread = await formatThread(dataLoader, comments, comment.id, depth + 1) + return formattedPost + '\n' + childThread + }) + + // Resolve all promises and join the results + const formattedComments = await Promise.all(formattedCommentsPromises) + return formattedComments.join('') +} + +export const createTextFromNewMeetingDiscussionStage = async ( + newMeeting: MeetingRetrospective, + stageId: string, + dataLoader: DataLoaderWorker, + textForReranking: boolean = false +) => { + if (!newMeeting) throw 'newMeeting is undefined' + if (!isMeetingRetrospective(newMeeting)) throw 'newMeeting is not retrospective' + if (!newMeeting.templateId) throw 'template is undefined' + const template = await dataLoader.get('meetingTemplates').load(newMeeting.templateId) + if (!template) throw 'template is undefined' + const discussPhase = newMeeting.phases.find((phase) => phase.phaseType === 'discuss') + if (!discussPhase) throw 'newMeeting discuss phase is undefined' + if (!discussPhase.stages) throw 'newMeeting discuss phase has no stages' + const discussStage = discussPhase.stages.find((stage) => stage.id === stageId) as DiscussStage + if (!discussStage) throw 'newMeeting discuss stage not found' + const {summary: discussionSummary} = discussStage.discussionId + ? (await dataLoader.get('discussions').load(discussStage.discussionId)) ?? {summary: null} + : {summary: null} + const r = await getRethink() + if (!discussStage.reflectionGroupId) throw 'newMeeting discuss stage has no reflectionGroupId' + const reflectionGroup = await r + .table('RetroReflectionGroup') + .get(discussStage.reflectionGroupId) + .run() + if (!reflectionGroup.id) throw 'newMeeting reflectionGroup has no id' + const reflections = await r + .table('RetroReflection') + .getAll(reflectionGroup.id, {index: 'reflectionGroupId'}) + .run() + const promptIds = [...new Set(reflections.map((r) => r.promptId))] + let markdown = '' + if (!textForReranking) + markdown = + `A topic "${reflectionGroup.title}" was discussed during ` + + `the meeting "${newMeeting.name}" that followed the "${template.name}" template.\n` + + `\n` + const prompts = await dataLoader.get('reflectPrompts').loadMany(promptIds) + for (const prompt of prompts) { + if (!prompt || prompt instanceof Error) continue + if (!textForReranking) { + markdown += `Participants were prompted with, "${prompt.question}` + if (prompt.description) markdown += `: ${prompt.description}` + markdown += `".\n` + } + if (newMeeting.disableAnonymity) { + for (const reflection of reflections.filter((r) => r.promptId === prompt.id)) { + const author = await getPreferredNameByUserId(reflection.creatorId, dataLoader) + markdown += ` - ${author} wrote, "${reflection.plaintextContent}"\n` + } + } else { + for (const reflection of reflections.filter((r) => r.promptId === prompt.id)) { + markdown += ` - Anonymous wrote, "${reflection.plaintextContent}"\n` + } + } + markdown += `\n` + } + + markdown += `\n` + + /** + * The choice I made here was default to the summary of the discussion if it exists in order to make this textual + * representation of a retrospective discussion a shorter token count. Using the summary almost certainly ensures + * this text won't need to be sent to be summarized again before an embedding vector is calculated. + * + * If we included the comments all the time, then we're maximizing the chance that rarer tokens might end up in the + * embed text and these tokens might affect the final embed vector in a useful way. However, we increase the odds that + * the embed text will need to be summarized before the vector is calculated. + * + * I decided to "just be cheap" and try and minimize calls to the summarizer. + * + * If we wanted to compare and contrast these approaches, we could always generate a second set of embed vectors + * objectType: 'retrospectiveDiscussionNoSummary' or something and do a bit of testing. + */ + + if (discussionSummary) { + markdown += `Further discussion was made. ` + ` ${discussionSummary}` + } else { + const comments = await dataLoader.get('commentsByDiscussionId').load(stageId) + + const sortedComments = comments + .map((comment) => { + if (!comment.threadParentId) { + return { + ...comment, + threadParentId: null + } + } + return comment + }) + .sort((a, b) => { + if (a.threadParentId === b.threadParentId) { + return a.threadSortOrder - b.threadSortOrder + } + if (a.threadParentId == null) return 1 + if (b.threadParentId == null) return -1 + return a.threadParentId > b.threadParentId ? 1 : -1 + }) as Comment[] + + const filteredComments = sortedComments.filter( + (c) => !IGNORE_COMMENT_USER_IDS.includes(c.createdBy) + ) + if (filteredComments.length) { + markdown += `Futher discussion was made:\n` + markdown += await formatThread(dataLoader, filteredComments) + // TODO: if the discussion threads are too long, summarize them + } + } + + markdown = prettier.format(markdown, { + parser: 'markdown', + proseWrap: 'always', + printWidth: 72 + }) + + return markdown +} + +export const createText = async ( + item: Selectable, + dataLoader: DataLoaderWorker +): Promise => { + if (!item.refId) throw 'refId is undefined' + const [newMeetingId, discussionId] = item.refId.split(':') + if (!newMeetingId) throw new Error('newMeetingId cannot be undefined') + if (!discussionId) throw new Error('discussionId cannot be undefined') + const newMeeting = await dataLoader.get('newMeetings').load(newMeetingId) + return createTextFromNewMeetingDiscussionStage( + newMeeting as MeetingRetrospective, + discussionId, + dataLoader + ) +} + +export const newRetroDiscussionTopicsFromNewMeeting = async ( + newMeeting: RethinkSchema['NewMeeting']['type'], + dataLoader: DataLoaderWorker +) => { + const discussPhase = newMeeting.phases.find((phase) => phase.phaseType === 'discuss') + const orgId = (await dataLoader.get('teams').load(newMeeting.teamId))?.orgId + if (orgId && discussPhase && discussPhase.stages) { + return discussPhase.stages.map((stage) => ({ + objectType: 'retrospectiveDiscussionTopic' as const, + teamId: newMeeting.teamId, + refId: `${newMeeting.id}:${stage.id}`, + refUpdatedAt: newMeeting.createdAt + })) + } else { + return [] + } +} diff --git a/packages/embedder/package.json b/packages/embedder/package.json new file mode 100644 index 00000000000..47af8737dac --- /dev/null +++ b/packages/embedder/package.json @@ -0,0 +1,31 @@ +{ + "name": "parabol-embedder", + "version": "7.10.0", + "description": "A service that computes embedding vectors from Parabol objects", + "author": "Jordan Husney ", + "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/embedder#readme", + "license": "AGPL-3.0-or-later", + "repository": { + "type": "git", + "url": "git+https://github.com/ParabolInc/parabol.git" + }, + "scripts": { + "typecheck": "yarn tsc --noEmit -p tsconfig.json" + }, + "bugs": { + "url": "https://github.com/ParabolInc/parabol/issues" + }, + "devDependencies": { + "@babel/cli": "7.18.6", + "@babel/core": "7.18.6", + "@types/node": "^16.11.62", + "babel-plugin-inline-import": "^3.0.0", + "sucrase": "^3.32.0", + "ts-node-dev": "^1.0.0-pre.44", + "typescript": "4.9.5" + }, + "dependencies": { + "dd-trace": "^4.2.0", + "redlock": "^5.0.0-beta.2" + } +} diff --git a/packages/embedder/tsconfig.json b/packages/embedder/tsconfig.json new file mode 100644 index 00000000000..1d179d08096 --- /dev/null +++ b/packages/embedder/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "baseUrl": "../", + "paths": { + // when we import from lib, make goto-definition point to the src + "parabol-server/*": ["server/*"], + "parabol-client/*": ["client/*"] + }, + "outDir": "lib", + "lib": ["esnext"], + "types": ["node"] + }, + "files": ["../server/types/modules.d.ts"] +} diff --git a/packages/server/dataloader/customLoaderMakers.ts b/packages/server/dataloader/customLoaderMakers.ts index b39e1e42d30..8bd64c6250b 100644 --- a/packages/server/dataloader/customLoaderMakers.ts +++ b/packages/server/dataloader/customLoaderMakers.ts @@ -1,5 +1,5 @@ import DataLoader from 'dataloader' -import {Selectable, sql} from 'kysely' +import {Selectable, SqlBool, sql} from 'kysely' import {PARABOL_AI_USER_ID} from '../../client/utils/constants' import getRethink, {RethinkSchema} from '../database/rethinkDriver' import {RDatum} from '../database/stricterR' @@ -478,11 +478,11 @@ export const meetingTemplatesByOrgId = (parent: RootDataLoader) => { .selectAll() .where('orgId', 'in', orgIds) .where('isActive', '=', true) - .where(({or, cmpr}) => + .where(({or, eb}) => or([ - cmpr('hideStartingAt', 'is', null), - sql`make_date(2020 , extract(month from current_date)::integer, extract(day from current_date)::integer) between "hideEndingAt" and "hideStartingAt"`, - sql`make_date(2019 , extract(month from current_date)::integer, extract(day from current_date)::integer) between "hideEndingAt" and "hideStartingAt"` + eb('hideStartingAt', 'is', null), + sql`make_date(2020 , extract(month from current_date)::integer, extract(day from current_date)::integer) between "hideEndingAt" and "hideStartingAt"`, + sql`make_date(2019 , extract(month from current_date)::integer, extract(day from current_date)::integer) between "hideEndingAt" and "hideStartingAt"` ]) ) .orderBy('createdAt', 'desc') diff --git a/packages/server/dataloader/customRedisQueries.ts b/packages/server/dataloader/customRedisQueries.ts index b3ed754dcab..a461202ca5a 100644 --- a/packages/server/dataloader/customRedisQueries.ts +++ b/packages/server/dataloader/customRedisQueries.ts @@ -1,7 +1,7 @@ // Sometimes, a value cached is redis is harder to get than simply querying the primary key on a table // this allows redis to cache the results of arbitrarily complex rethinkdb queries -import {sql} from 'kysely' +import {sql, SqlBool} from 'kysely' import ms from 'ms' import getRethink from '../database/rethinkDriver' import {RDatum} from '../database/stricterR' @@ -38,11 +38,11 @@ const customRedisQueries = { .where('teamId', '=', 'aGhostTeam') .where('isActive', '=', true) .where('type', '=', templateType) - .where(({or, cmpr}) => + .where(({or, eb}) => or([ - cmpr('hideStartingAt', 'is', null), - sql`make_date(2020 , extract(month from current_date)::integer, extract(day from current_date)::integer) between "hideEndingAt" and "hideStartingAt"`, - sql`make_date(2019 , extract(month from current_date)::integer, extract(day from current_date)::integer) between "hideEndingAt" and "hideStartingAt"` + eb('hideStartingAt', 'is', null), + sql`make_date(2020 , extract(month from current_date)::integer, extract(day from current_date)::integer) between "hideEndingAt" and "hideStartingAt"`, + sql`make_date(2019 , extract(month from current_date)::integer, extract(day from current_date)::integer) between "hideEndingAt" and "hideStartingAt"` ]) ) .execute() diff --git a/packages/server/postgres/getKysely.ts b/packages/server/postgres/getKysely.ts index 0a8632a3eb6..f2824a800d0 100644 --- a/packages/server/postgres/getKysely.ts +++ b/packages/server/postgres/getKysely.ts @@ -10,6 +10,13 @@ const getKysely = () => { dialect: new PostgresDialect({ pool: pg }) + // query logging, if you'd like it: + // log(event) { + // if (event.level === 'query') { + // console.log(event.query.sql) + // console.log(event.query.parameters) + // } + // } }) } return kysely diff --git a/packages/server/postgres/migrations/1708127504000_updateEmbeddingMetadata.ts b/packages/server/postgres/migrations/1708127504000_updateEmbeddingMetadata.ts new file mode 100644 index 00000000000..3c93617c0b1 --- /dev/null +++ b/packages/server/postgres/migrations/1708127504000_updateEmbeddingMetadata.ts @@ -0,0 +1,20 @@ +import {Client} from 'pg' +import getPgConfig from '../getPgConfig' + +export async function up() { + const client = new Client(getPgConfig()) + await client.connect() + await client.query(` + ALTER TABLE "EmbeddingsMetadata" RENAME COLUMN "embedText" TO "fullText"; + `) + await client.end() +} + +export async function down() { + const client = new Client(getPgConfig()) + await client.connect() + await client.query(` + ALTER TABLE "EmbeddingsMetadata" RENAME COLUMN "fullText" TO "embedText"; + `) + await client.end() +} diff --git a/pm2.config.js b/pm2.config.js index 4d270b745ea..fdf09ea9ca2 100644 --- a/pm2.config.js +++ b/pm2.config.js @@ -30,6 +30,21 @@ module.exports = { NODE_ENV: 'production' } }, + { + name: 'Embedder', + script: 'dist/embedder.js', + instances: 1, + increment_var: 'SERVER_ID', + autorestart: true, + watch: false, + max_memory_restart: '4096M', + env: { + SERVER_ID: 5 + }, + env_production: { + NODE_ENV: 'production' + } + }, { name: 'GQL Executor', script: 'dist/gqlExecutor.js', @@ -39,7 +54,7 @@ module.exports = { watch: false, max_memory_restart: '24576M', env: { - SERVER_ID: 5 + SERVER_ID: 6 }, env_production: { NODE_ENV: 'production' diff --git a/pm2.dev.config.js b/pm2.dev.config.js index c5f04196dff..6cd457059ef 100644 --- a/pm2.dev.config.js +++ b/pm2.dev.config.js @@ -4,6 +4,19 @@ module.exports = { name: 'Webpack Servers', script: 'scripts/buildServers.js' }, + { + name: 'Socket Server', + script: 'scripts/runSocketServer.js', + // increase this to test scaling + instances: 1, + increment_var: 'SERVER_ID', + env: { + SERVER_ID: 0 + }, + watch: ['dev/web.js'], + // if the watched file doeesn't exist, wait for it instead of restarting + autorestart: false + }, { name: 'GraphQL Executor', script: 'scripts/runExecutor.js', @@ -15,24 +28,20 @@ module.exports = { }, watch: ['dev/gqlExecutor.js'], // if the watched file doeesn't exist, wait for it instead of restarting - autorestart: false, - log_file: 'dev/logs/gqlExecutor.log', - combine_logs: true + autorestart: false }, { - name: 'Socket Server', - script: 'scripts/runSocketServer.js', + name: 'Embedder', + script: 'scripts/runEmbedder.js', // increase this to test scaling instances: 1, increment_var: 'SERVER_ID', env: { - SERVER_ID: 0 + SERVER_ID: 6 }, - watch: ['dev/web.js'], + watch: ['dev/embedder.js'], // if the watched file doeesn't exist, wait for it instead of restarting - autorestart: false, - log_file: 'dev/logs/web.log', - combine_logs: true + autorestart: false }, { name: 'Dev Server', diff --git a/scripts/generateGraphQLArtifacts.js b/scripts/generateGraphQLArtifacts.js index de2fd452e67..9ca5cd43067 100644 --- a/scripts/generateGraphQLArtifacts.js +++ b/scripts/generateGraphQLArtifacts.js @@ -16,8 +16,11 @@ const generateGraphQLArtifacts = async () => { relayCompiler?.kill() }) }) - - await Promise.all([generate(codegenSchema), runCompiler()]) + console.log('gen graphql artifacts start') + await generate(codegenSchema) + console.log('codegen complete') + await runCompiler() + console.log('relay compiler complete') persistServer.close() } diff --git a/scripts/prod.js b/scripts/prod.js index 65d121446d8..94a7565363b 100644 --- a/scripts/prod.js +++ b/scripts/prod.js @@ -10,15 +10,25 @@ const runChild = (cmd) => { const prod = async (isDeploy, noDeps) => { console.log('🙏🙏🙏 Building Production Server 🙏🙏🙏') - await generateGraphQLArtifacts() - await Promise.all([ - runChild( - `yarn webpack --config ./scripts/webpack/prod.servers.config.js --no-stats --env=noDeps=${noDeps}` - ), - runChild( - `yarn webpack --config ./scripts/webpack/prod.client.config.js --no-stats --env=minimize=${isDeploy}` - ) - ]) + try { + await generateGraphQLArtifacts() + } catch (e) { + console.log('ERR generating artifacts', e) + } + + console.log('starting webpack build') + try { + await Promise.all([ + runChild( + `yarn webpack --config ./scripts/webpack/prod.servers.config.js --no-stats --env=noDeps=${noDeps}` + ), + runChild( + `yarn webpack --config ./scripts/webpack/prod.client.config.js --no-stats --env=minimize=${isDeploy}` + ) + ]) + } catch (e) { + console.log('error webpackifying', e) + } } if (require.main === module) { diff --git a/scripts/runEmbedder.js b/scripts/runEmbedder.js new file mode 100644 index 00000000000..c235888f861 --- /dev/null +++ b/scripts/runEmbedder.js @@ -0,0 +1,13 @@ +/** + Starts up an instance of the stateless Embedder service. + When you modify a server file, the webpack watcher in + {@link buildServers} writes the change to {@link ../dev/embedder}. + Pm2 reloads this file whenever {@link embedder} changes +*/ + +try { + require('../dev/embedder.js') +} catch (e) { + // webpack has not created the file yet + // pm2 will restart this process when the file changes +} diff --git a/scripts/webpack/dev.servers.config.js b/scripts/webpack/dev.servers.config.js index b32e586562c..80591f24b0f 100644 --- a/scripts/webpack/dev.servers.config.js +++ b/scripts/webpack/dev.servers.config.js @@ -7,6 +7,7 @@ const webpack = require('webpack') const PROJECT_ROOT = getProjectRoot() const CLIENT_ROOT = path.join(PROJECT_ROOT, 'packages', 'client') const SERVER_ROOT = path.join(PROJECT_ROOT, 'packages', 'server') +const EMBEDDER_ROOT = path.join(PROJECT_ROOT, 'packages', 'embedder') const GQL_ROOT = path.join(PROJECT_ROOT, 'packages', 'gql-executor') const DOTENV = path.join(PROJECT_ROOT, 'scripts', 'webpack', 'utils', 'dotenv.js') // const CircularDependencyPlugin = require('circular-dependency-plugin') @@ -26,6 +27,7 @@ module.exports = { }, entry: { web: [DOTENV, path.join(SERVER_ROOT, 'server.ts')], + embedder: [DOTENV, path.join(EMBEDDER_ROOT, 'embedder.ts')], gqlExecutor: [DOTENV, path.join(GQL_ROOT, 'gqlExecutor.ts')] }, output: { diff --git a/scripts/webpack/prod.servers.config.js b/scripts/webpack/prod.servers.config.js index 5db575b51e3..52feb216089 100644 --- a/scripts/webpack/prod.servers.config.js +++ b/scripts/webpack/prod.servers.config.js @@ -11,6 +11,7 @@ const cp = require('child_process') const PROJECT_ROOT = getProjectRoot() const CLIENT_ROOT = path.join(PROJECT_ROOT, 'packages', 'client') const SERVER_ROOT = path.join(PROJECT_ROOT, 'packages', 'server') +const EMBEDDER_ROOT = path.join(PROJECT_ROOT, 'packages', 'embedder') const GQL_ROOT = path.join(PROJECT_ROOT, 'packages', 'gql-executor') const DOTENV = path.join(PROJECT_ROOT, 'scripts/webpack/utils/dotenv.js') const distPath = path.join(PROJECT_ROOT, 'dist') @@ -32,6 +33,7 @@ module.exports = (config) => { path.join(PROJECT_ROOT, 'scripts/toolboxSrc/applyEnvVarsToClientAssets.ts'), path.join(SERVER_ROOT, 'server.ts') ], + embedder: [DOTENV, path.join(EMBEDDER_ROOT, 'embedder.ts')], gqlExecutor: [DOTENV, path.join(GQL_ROOT, 'gqlExecutor.ts')], preDeploy: [DOTENV, path.join(PROJECT_ROOT, 'scripts/toolboxSrc/preDeploy.ts')], pushToCDN: [DOTENV, path.join(PROJECT_ROOT, 'scripts/toolboxSrc/pushToCDN.ts')], diff --git a/scripts/webpack/toolbox.config.js b/scripts/webpack/toolbox.config.js index 3edcb77ed56..d63a8f6505c 100644 --- a/scripts/webpack/toolbox.config.js +++ b/scripts/webpack/toolbox.config.js @@ -56,6 +56,26 @@ module.exports = { new webpack.DefinePlugin({ __PRODUCTION__: true }) + // new CircularDependencyPlugin({ + // // `onStart` is called before the cycle detection starts + // onStart({compilation}) { + // console.log('start detecting webpack modules cycles') + // }, + // // `onDetected` is called for each module that is cyclical + // onDetected({module: webpackModuleRecord, paths, compilation}) { + // // `paths` will be an Array of the relative module paths that make up the cycle + // // `module` is the module record that caused the cycle + // compilation.errors.push(new Error(paths.join(' -> '))) + // }, + // // `onEnd` is called before the cycle detection ends + // onEnd({compilation}) { + // console.log('end detecting webpack modules cycles') + // }, + // // set to false to only detect cycles that include an entrypoint + // allowAsyncCycles: false, + // // set to true to detect cycles in node_modules + // cwd: process.cwd() // set the current working directory for displaying module paths + // }) ], module: { rules: [ diff --git a/scripts/webpack/utils/transformRules.js b/scripts/webpack/utils/transformRules.js index 0c44e2ae3e6..e6bc0c9dadf 100644 --- a/scripts/webpack/utils/transformRules.js +++ b/scripts/webpack/utils/transformRules.js @@ -3,6 +3,7 @@ const path = require('path') const transformRules = (projectRoot, isProd) => { const CLIENT_ROOT = path.join(projectRoot, 'packages', 'client') const SERVER_ROOT = path.join(projectRoot, 'packages', 'server') + const EMBEDDER_ROOT = path.join(projectRoot, 'packages', 'embedder') const GQL_ROOT = path.join(projectRoot, 'packages', 'gql-executor') const CHRONOS_ROOT = path.join(projectRoot, 'packages', 'chronos') const TOOLBOX_SRC = path.join(projectRoot, 'scripts', 'toolboxSrc') @@ -48,7 +49,7 @@ const transformRules = (projectRoot, isProd) => { { test: /\.(tsx?|js)$/, // things that don't need babel - include: [SERVER_ROOT, GQL_ROOT, CHRONOS_ROOT, TOOLBOX_SRC], + include: [SERVER_ROOT, EMBEDDER_ROOT, GQL_ROOT, CHRONOS_ROOT, TOOLBOX_SRC], // things that need babel exclude: path.join(SERVER_ROOT, 'email'), use: { diff --git a/yarn.lock b/yarn.lock index 99d793dc367..69cf14bcce1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1317,11 +1317,34 @@ "@babel/highlight" "^7.22.13" chalk "^2.4.2" -"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.18.6", "@babel/compat-data@^7.22.9": +"@babel/code-frame@^7.16.7", "@babel/code-frame@^7.21.4", "@babel/code-frame@^7.23.5": + version "7.23.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" + integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== + dependencies: + "@babel/highlight" "^7.23.4" + chalk "^2.4.2" + +"@babel/compat-data@^7.13.11": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.16.4.tgz#081d6bbc336ec5c2435c6346b2ae1fb98b5ac68e" + integrity sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q== + +"@babel/compat-data@^7.18.6": + version "7.18.8" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.8.tgz#2483f565faca607b8535590e84e7de323f27764d" + integrity sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ== + +"@babel/compat-data@^7.22.9": version "7.22.9" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.9.tgz#71cdb00a1ce3a329ce4cbec3a44f9fef35669730" integrity sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ== +"@babel/compat-data@^7.23.5": + version "7.23.5" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.5.tgz#ffb878728bb6bdcb6f4510aa51b1be9afb8cfd98" + integrity sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw== + "@babel/core@7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.6.tgz#54a107a3c298aee3fe5e1947a6464b9b6faca03d" @@ -1343,7 +1366,91 @@ json5 "^2.2.1" semver "^6.3.0" -"@babel/core@^7.11.1", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.13.16", "@babel/core@^7.14.0", "@babel/core@^7.20.12", "@babel/core@^7.22.9": +"@babel/core@^7.11.1": + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.2.tgz#87b2fcd7cce9becaa7f5acebdc4f09f3dd19d876" + integrity sha512-A8pri1YJiC5UnkdrWcmfZTJTV85b4UXTAfImGmCfYmax4TR9Cw8sDS0MOk++Gp2mE/BefVJ5nwy5yzqNJbP/DQ== + dependencies: + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.18.2" + "@babel/helper-compilation-targets" "^7.18.2" + "@babel/helper-module-transforms" "^7.18.0" + "@babel/helpers" "^7.18.2" + "@babel/parser" "^7.18.0" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.18.2" + "@babel/types" "^7.18.2" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.1" + semver "^6.3.0" + +"@babel/core@^7.11.6": + version "7.21.8" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.21.8.tgz#2a8c7f0f53d60100ba4c32470ba0281c92aa9aa4" + integrity sha512-YeM22Sondbo523Sz0+CirSPnbj9bG3P0CdHcBZdqUuaeOaYEFbOLoGU7lebvGP6P5J/WE9wOn7u7C4J9HvS1xQ== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.21.4" + "@babel/generator" "^7.21.5" + "@babel/helper-compilation-targets" "^7.21.5" + "@babel/helper-module-transforms" "^7.21.5" + "@babel/helpers" "^7.21.5" + "@babel/parser" "^7.21.8" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.21.5" + "@babel/types" "^7.21.5" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.2" + semver "^6.3.0" + +"@babel/core@^7.12.3", "@babel/core@^7.13.16", "@babel/core@^7.14.0": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.16.7.tgz#db990f931f6d40cb9b87a0dc7d2adc749f1dcbcf" + integrity sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.16.7" + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helpers" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.7" + "@babel/types" "^7.16.7" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.1.2" + semver "^6.3.0" + source-map "^0.5.0" + +"@babel/core@^7.20.12": + version "7.20.12" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.20.12.tgz#7930db57443c6714ad216953d1356dac0eb8496d" + integrity sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg== + dependencies: + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.20.7" + "@babel/helper-compilation-targets" "^7.20.7" + "@babel/helper-module-transforms" "^7.20.11" + "@babel/helpers" "^7.20.7" + "@babel/parser" "^7.20.7" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.20.12" + "@babel/types" "^7.20.7" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.2" + semver "^6.3.0" + +"@babel/core@^7.22.9": version "7.22.10" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.10.tgz#aad442c7bcd1582252cb4576747ace35bc122f35" integrity sha512-fTmqbbUBAwCcre6zPzNngvsI0aNrPZe77AeqvDxWM9Nm+04RrJ3CAmGHA9f7lJQY6ZMhRztNemy4uslDxTX4Qw== @@ -1374,7 +1481,24 @@ "@jridgewell/trace-mapping" "^0.3.17" jsesc "^2.5.1" -"@babel/helper-annotate-as-pure@^7.16.7", "@babel/helper-annotate-as-pure@^7.18.6": +"@babel/generator@^7.16.7", "@babel/generator@^7.18.2", "@babel/generator@^7.20.7", "@babel/generator@^7.21.5", "@babel/generator@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz#9e1fca4811c77a10580d17d26b57b036133f3c2e" + integrity sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw== + dependencies: + "@babel/types" "^7.23.6" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + +"@babel/helper-annotate-as-pure@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz#bb2339a7534a9c128e3102024c60760a3a7f3862" + integrity sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-annotate-as-pure@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA== @@ -1400,7 +1524,31 @@ lru-cache "^5.1.1" semver "^6.3.1" -"@babel/helper-create-class-features-plugin@^7.16.7", "@babel/helper-create-class-features-plugin@^7.18.6": +"@babel/helper-compilation-targets@^7.16.7", "@babel/helper-compilation-targets@^7.18.2", "@babel/helper-compilation-targets@^7.20.7", "@babel/helper-compilation-targets@^7.21.5": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz#4d79069b16cbcf1461289eccfbbd81501ae39991" + integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ== + dependencies: + "@babel/compat-data" "^7.23.5" + "@babel/helper-validator-option" "^7.23.5" + browserslist "^4.22.2" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-create-class-features-plugin@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.7.tgz#9c5b34b53a01f2097daf10678d65135c1b9f84ba" + integrity sha512-kIFozAvVfK05DM4EVQYKK+zteWvY85BFdGBRQBytRyY3y+6PX0DkDOn/CZ3lEuczCfrCxEzwt0YtP/87YPTWSw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-member-expression-to-functions" "^7.16.7" + "@babel/helper-optimise-call-expression" "^7.16.7" + "@babel/helper-replace-supers" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + +"@babel/helper-create-class-features-plugin@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.6.tgz#6f15f8459f3b523b39e00a99982e2c040871ed72" integrity sha512-YfDzdnoxHGV8CzqHGyCbFvXg5QESPFkXlHtvdCkesLjjVMT2Adxe4FGUR5ChIb3DxSaXO12iIOCWoXdsUVwnqw== @@ -1435,7 +1583,19 @@ resolve "^1.14.2" semver "^6.1.2" -"@babel/helper-environment-visitor@^7.18.6", "@babel/helper-environment-visitor@^7.22.20", "@babel/helper-environment-visitor@^7.22.5": +"@babel/helper-environment-visitor@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7" + integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-environment-visitor@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.6.tgz#b7eee2b5b9d70602e59d1a6cad7dd24de7ca6cd7" + integrity sha512-8n6gSfn2baOY+qlp+VSzsosjCVGFqWKmDF0cCWOybh52Dw3SEyoWR1KrhMJASjLwIEkkAufZ0xvr+SxLHSpy2Q== + +"@babel/helper-environment-visitor@^7.22.20", "@babel/helper-environment-visitor@^7.22.5": version "7.22.20" resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== @@ -1447,7 +1607,7 @@ dependencies: "@babel/types" "^7.18.6" -"@babel/helper-function-name@^7.18.6", "@babel/helper-function-name@^7.23.0": +"@babel/helper-function-name@^7.16.7", "@babel/helper-function-name@^7.18.6", "@babel/helper-function-name@^7.23.0": version "7.23.0" resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== @@ -1462,6 +1622,13 @@ dependencies: "@babel/types" "^7.22.5" +"@babel/helper-member-expression-to-functions@^7.16.7", "@babel/helper-member-expression-to-functions@^7.22.15": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz#9263e88cc5e41d39ec18c9a3e0eced59a3e7d366" + integrity sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA== + dependencies: + "@babel/types" "^7.23.0" + "@babel/helper-member-expression-to-functions@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.6.tgz#44802d7d602c285e1692db0bad9396d007be2afc" @@ -1469,13 +1636,45 @@ dependencies: "@babel/types" "^7.18.6" -"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.18.6", "@babel/helper-module-imports@^7.22.5": +"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" + integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-module-imports@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" + integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-module-imports@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0" + integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== + dependencies: + "@babel/types" "^7.22.15" + +"@babel/helper-module-imports@^7.22.5": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz#1a8f4c9f4027d23f520bd76b364d44434a72660c" integrity sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg== dependencies: "@babel/types" "^7.22.5" +"@babel/helper-module-transforms@^7.16.7", "@babel/helper-module-transforms@^7.18.0", "@babel/helper-module-transforms@^7.20.11", "@babel/helper-module-transforms@^7.21.5": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz#d7d12c3c5d30af5b3c0fcab2a6d5217773e2d0f1" + integrity sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ== + dependencies: + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-module-imports" "^7.22.15" + "@babel/helper-simple-access" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/helper-validator-identifier" "^7.22.20" + "@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.22.9": version "7.22.9" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz#92dfcb1fbbb2bc62529024f72d942a8c97142129" @@ -1487,6 +1686,13 @@ "@babel/helper-split-export-declaration" "^7.22.6" "@babel/helper-validator-identifier" "^7.22.5" +"@babel/helper-optimise-call-expression@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz#a34e3560605abbd31a18546bd2aad3e6d9a174f2" + integrity sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w== + dependencies: + "@babel/types" "^7.16.7" + "@babel/helper-optimise-call-expression@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz#9369aa943ee7da47edab2cb4e838acf09d290ffe" @@ -1494,7 +1700,29 @@ dependencies: "@babel/types" "^7.18.6" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": +"@babel/helper-optimise-call-expression@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz#f21531a9ccbff644fdd156b4077c16ff0c3f609e" + integrity sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5" + integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA== + +"@babel/helper-plugin-utils@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.6.tgz#9448974dd4fb1d80fefe72e8a0af37809cd30d6d" + integrity sha512-gvZnm1YAAxh13eJdkb9EWHBnF3eAub3XTLCZEehHT2kWxiKVRL64+ae5Y6Ivne0mVHmMYKT+xWgZO+gQhuLUBg== + +"@babel/helper-plugin-utils@^7.20.2": + version "7.21.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.21.5.tgz#345f2377d05a720a4e5ecfa39cbf4474a4daed56" + integrity sha512-0WDaIlXKOX/3KfBK/dwP1oQGiPh6rjMkT7HIRv7i5RR2VUMwrx5ZL0dwBkKx7+SW1zwNdgjHd34IMk5ZjTeHVg== + +"@babel/helper-plugin-utils@^7.22.5": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== @@ -1509,6 +1737,15 @@ "@babel/helper-wrap-function" "^7.18.6" "@babel/types" "^7.18.6" +"@babel/helper-replace-supers@^7.16.7": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz#e37d367123ca98fe455a9887734ed2e16eb7a793" + integrity sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw== + dependencies: + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-member-expression-to-functions" "^7.22.15" + "@babel/helper-optimise-call-expression" "^7.22.5" + "@babel/helper-replace-supers@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.18.6.tgz#efedf51cfccea7b7b8c0f00002ab317e7abfe420" @@ -1520,7 +1757,7 @@ "@babel/traverse" "^7.18.6" "@babel/types" "^7.18.6" -"@babel/helper-simple-access@^7.18.6", "@babel/helper-simple-access@^7.22.5": +"@babel/helper-simple-access@^7.16.7", "@babel/helper-simple-access@^7.18.6", "@babel/helper-simple-access@^7.22.5": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== @@ -1534,19 +1771,39 @@ dependencies: "@babel/types" "^7.18.6" -"@babel/helper-split-export-declaration@^7.18.6", "@babel/helper-split-export-declaration@^7.22.6": +"@babel/helper-split-export-declaration@^7.16.7", "@babel/helper-split-export-declaration@^7.18.6", "@babel/helper-split-export-declaration@^7.22.6": version "7.22.6" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== dependencies: "@babel/types" "^7.22.5" +"@babel/helper-string-parser@^7.19.4", "@babel/helper-string-parser@^7.21.5", "@babel/helper-string-parser@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83" + integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== + "@babel/helper-string-parser@^7.22.5": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== -"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.22.20", "@babel/helper-validator-identifier@^7.22.5": +"@babel/helper-validator-identifier@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" + integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== + +"@babel/helper-validator-identifier@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076" + integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g== + +"@babel/helper-validator-identifier@^7.19.1": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" + integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== + +"@babel/helper-validator-identifier@^7.22.20", "@babel/helper-validator-identifier@^7.22.5": version "7.22.20" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== @@ -1556,6 +1813,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz#de52000a15a177413c8234fa3a8af4ee8102d0ac" integrity sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw== +"@babel/helper-validator-option@^7.23.5": + version "7.23.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307" + integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== + "@babel/helper-wrap-function@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.18.6.tgz#ec44ea4ad9d8988b90c3e465ba2382f4de81a073" @@ -1566,6 +1828,15 @@ "@babel/traverse" "^7.18.6" "@babel/types" "^7.18.6" +"@babel/helpers@^7.16.7", "@babel/helpers@^7.18.2", "@babel/helpers@^7.20.7", "@babel/helpers@^7.21.5": + version "7.23.9" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.9.tgz#c3e20bbe7f7a7e10cb9b178384b4affdf5995c7d" + integrity sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ== + dependencies: + "@babel/template" "^7.23.9" + "@babel/traverse" "^7.23.9" + "@babel/types" "^7.23.9" + "@babel/helpers@^7.18.6", "@babel/helpers@^7.22.10": version "7.22.10" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.10.tgz#ae6005c539dfbcb5cd71fb51bfc8a52ba63bc37a" @@ -1584,11 +1855,55 @@ chalk "^2.4.2" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.13.16", "@babel/parser@^7.14.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.8", "@babel/parser@^7.18.6", "@babel/parser@^7.20.15", "@babel/parser@^7.22.10", "@babel/parser@^7.22.15", "@babel/parser@^7.23.0": +"@babel/highlight@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b" + integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== + dependencies: + "@babel/helper-validator-identifier" "^7.22.20" + chalk "^2.4.2" + js-tokens "^4.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.13.16", "@babel/parser@^7.14.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.7.tgz#d372dda9c89fcec340a82630a9f533f2fe15877e" + integrity sha512-sR4eaSrnM7BV7QPzGfEX5paG/6wrZM3I0HDzfIAK06ESvo9oy3xBuVBxE3MbQaKNhvg8g/ixjMWo2CGpzpHsDA== + +"@babel/parser@^7.16.8", "@babel/parser@^7.18.6": + version "7.18.8" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.8.tgz#822146080ac9c62dac0823bb3489622e0bc1cbdf" + integrity sha512-RSKRfYX20dyH+elbJK2uqAkVyucL+xXzhqlMD5/ZXx+dAAwpyB7HsvnHe/ZUGOF+xLr5Wx9/JoXVTj6BQE2/oA== + +"@babel/parser@^7.18.0": + version "7.18.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.4.tgz#6774231779dd700e0af29f6ad8d479582d7ce5ef" + integrity sha512-FDge0dFazETFcxGw/EXzOkN8uJp0PC7Qbm+Pe9T+av2zlBpOgunFHkQPPn+eRuClU73JF+98D531UgayY89tow== + +"@babel/parser@^7.20.15", "@babel/parser@^7.22.15", "@babel/parser@^7.23.0": version "7.23.0" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719" integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw== +"@babel/parser@^7.20.7": + version "7.20.15" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.15.tgz#eec9f36d8eaf0948bb88c87a46784b5ee9fd0c89" + integrity sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg== + +"@babel/parser@^7.21.8": + version "7.21.8" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.8.tgz#642af7d0333eab9c0ad70b14ac5e76dbde7bfdf8" + integrity sha512-6zavDGdzG3gUqAdWvlLFfk+36RilI+Pwyuuh7HItyeScCWP3k6i8vKclAQ0bM/0y/Kz/xiwvxhMv9MgTJP5gmA== + +"@babel/parser@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.10.tgz#e37634f9a12a1716136c44624ef54283cabd3f55" + integrity sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ== + +"@babel/parser@^7.23.9": + version "7.23.9" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.9.tgz#7b903b6149b0f8fa7ad564af646c4c38a77fc44b" + integrity sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA== + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2" @@ -2002,7 +2317,17 @@ "@babel/helper-plugin-utils" "^7.18.6" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-commonjs@^7.0.0", "@babel/plugin-transform-modules-commonjs@^7.13.8", "@babel/plugin-transform-modules-commonjs@^7.18.6": +"@babel/plugin-transform-modules-commonjs@^7.0.0", "@babel/plugin-transform-modules-commonjs@^7.13.8": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.7.tgz#fd119e6a433c527d368425b45df361e1e95d3c1a" + integrity sha512-h2RP2kE7He1ZWKyAlanMZrAbdv+Acw1pA8dQZhE025WJZE2z0xzFADAinXA9fxd5bn7JnM+SdOGcndGx1ARs9w== + dependencies: + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-simple-access" "^7.16.7" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-commonjs@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.6.tgz#afd243afba166cca69892e24a8fd8c9f2ca87883" integrity sha512-Qfv2ZOWikpvmedXQJDSbxNqy7Xr/j2Y8/KfijM0iJyKkBTmWuvCA1yeH1yDM7NJhBW/2aXxeucLj6i80/LAJ/Q== @@ -2101,7 +2426,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-shorthand-properties@^7.0.0", "@babel/plugin-transform-shorthand-properties@^7.18.6": +"@babel/plugin-transform-shorthand-properties@^7.0.0": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz#e8549ae4afcf8382f711794c0c7b6b934c5fbd2a" + integrity sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-shorthand-properties@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz#6d6df7983d67b195289be24909e3f12a8f664dc9" integrity sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw== @@ -2289,14 +2621,83 @@ dependencies: regenerator-runtime "^0.12.0" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.5", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.15.4", "@babel/runtime@^7.17.2", "@babel/runtime@^7.18.3", "@babel/runtime@^7.2.0", "@babel/runtime@^7.21.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.15.4", "@babel/runtime@^7.2.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.7.tgz#03ff99f64106588c9c403c6ecb8c3bafbbdff1fa" + integrity sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/runtime@^7.10.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.0.tgz#22b11c037b094d27a8a2504ea4dcff00f50e2259" + integrity sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/runtime@^7.10.5": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.8.tgz#3e56e4aff81befa55ac3ac6a0967349fd1c5bca2" + integrity sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/runtime@^7.11.2": + version "7.17.9" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.9.tgz#d19fbf802d01a8cb6cf053a64e472d42c434ba72" + integrity sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/runtime@^7.13.10": + version "7.20.13" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.13.tgz#7055ab8a7cff2b8f6058bf6ae45ff84ad2aded4b" + integrity sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA== + dependencies: + regenerator-runtime "^0.13.11" + +"@babel/runtime@^7.17.2": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.9.tgz#b4fcfce55db3d2e5e080d2490f608a3b9f407f4a" + integrity sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/runtime@^7.21.0": version "7.21.5" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.5.tgz#8492dddda9644ae3bda3b45eabe87382caee7200" integrity sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q== dependencies: regenerator-runtime "^0.13.11" -"@babel/template@^7.18.10", "@babel/template@^7.18.6", "@babel/template@^7.22.15", "@babel/template@^7.22.5", "@babel/template@^7.3.3": +"@babel/template@^7.16.7", "@babel/template@^7.3.3": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" + integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/template@^7.18.10", "@babel/template@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.20.7.tgz#a15090c2839a83b02aa996c0b4994005841fd5a8" + integrity sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + +"@babel/template@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.6.tgz#1283f4993e00b929d6e2d3c72fdc9168a2977a31" + integrity sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/parser" "^7.18.6" + "@babel/types" "^7.18.6" + +"@babel/template@^7.22.15": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== @@ -2305,6 +2706,15 @@ "@babel/parser" "^7.22.15" "@babel/types" "^7.22.15" +"@babel/template@^7.22.5", "@babel/template@^7.23.9": + version "7.23.9" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.23.9.tgz#f881d0487cba2828d3259dcb9ef5005a9731011a" + integrity sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA== + dependencies: + "@babel/code-frame" "^7.23.5" + "@babel/parser" "^7.23.9" + "@babel/types" "^7.23.9" + "@babel/traverse@^7.13.0", "@babel/traverse@^7.14.0", "@babel/traverse@^7.16.8", "@babel/traverse@^7.18.6", "@babel/traverse@^7.22.10", "@babel/traverse@^7.7.2": version "7.23.2" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8" @@ -2321,7 +2731,82 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.18.13", "@babel/types@^7.18.6", "@babel/types@^7.22.10", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": +"@babel/traverse@^7.16.7", "@babel/traverse@^7.18.2", "@babel/traverse@^7.20.12", "@babel/traverse@^7.21.5", "@babel/traverse@^7.23.9": + version "7.23.9" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.9.tgz#2f9d6aead6b564669394c5ce0f9302bb65b9d950" + integrity sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg== + dependencies: + "@babel/code-frame" "^7.23.5" + "@babel/generator" "^7.23.6" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.23.9" + "@babel/types" "^7.23.9" + debug "^4.3.1" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.16.7", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.7.tgz#4ed19d51f840ed4bd5645be6ce40775fecf03159" + integrity sha512-E8HuV7FO9qLpx6OtoGfUQ2cjIYnbFwvZWYBS+87EwtdMvmUPJSwykpovFB+8insbpF0uJcpr8KMUi64XZntZcg== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + to-fast-properties "^2.0.0" + +"@babel/types@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.8.tgz#0ba5da91dd71e0a4e7781a30f22770831062e3c1" + integrity sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + to-fast-properties "^2.0.0" + +"@babel/types@^7.18.13", "@babel/types@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.7.tgz#54ec75e252318423fc07fb644dc6a58a64c09b7f" + integrity sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg== + dependencies: + "@babel/helper-string-parser" "^7.19.4" + "@babel/helper-validator-identifier" "^7.19.1" + to-fast-properties "^2.0.0" + +"@babel/types@^7.18.2": + version "7.18.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.4.tgz#27eae9b9fd18e9dccc3f9d6ad051336f307be354" + integrity sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + to-fast-properties "^2.0.0" + +"@babel/types@^7.18.6": + version "7.18.8" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.8.tgz#c5af199951bf41ba4a6a9a6d0d8ad722b30cd42f" + integrity sha512-qwpdsmraq0aJ3osLJRApsc2ouSJCdnMeZwB0DhbtHAtRpZNZCdlbRnHIgcRKzdE1g0iOGg644fzjOBcdOz9cPw== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + to-fast-properties "^2.0.0" + +"@babel/types@^7.21.5": + version "7.21.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.5.tgz#18dfbd47c39d3904d5db3d3dc2cc80bedb60e5b6" + integrity sha512-m4AfNvVF2mVC/F7fDEdH2El3HzUg9It/XsCxZiOTTA3m3qYfcSVSbTfM6Q9xG+hYDniZssYhlXKKUMD5m8tF4Q== + dependencies: + "@babel/helper-string-parser" "^7.21.5" + "@babel/helper-validator-identifier" "^7.19.1" + to-fast-properties "^2.0.0" + +"@babel/types@^7.22.10", "@babel/types@^7.22.5": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.10.tgz#4a9e76446048f2c66982d1a989dd12b8a2d2dc03" + integrity sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg== + dependencies: + "@babel/helper-string-parser" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.5" + to-fast-properties "^2.0.0" + +"@babel/types@^7.22.15", "@babel/types@^7.23.0": version "7.23.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb" integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg== @@ -2330,6 +2815,15 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" +"@babel/types@^7.23.6", "@babel/types@^7.23.9": + version "7.23.9" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.9.tgz#1dd7b59a9a2b5c87f8b41e52770b5ecbf492e002" + integrity sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q== + dependencies: + "@babel/helper-string-parser" "^7.23.4" + "@babel/helper-validator-identifier" "^7.22.20" + to-fast-properties "^2.0.0" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" @@ -7968,13 +8462,22 @@ agent-base@^7.0.2, agent-base@^7.1.0: dependencies: debug "^4.3.4" -agentkeepalive@^4.1.3, agentkeepalive@^4.2.1: +agentkeepalive@^4.1.3: version "4.5.0" resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew== dependencies: humanize-ms "^1.2.1" +agentkeepalive@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.2.1.tgz#a7975cbb9f83b367f06c90cc51ff28fe7d499717" + integrity sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA== + dependencies: + debug "^4.1.0" + depd "^1.1.2" + humanize-ms "^1.2.1" + aggregate-error@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" @@ -8408,7 +8911,16 @@ axios@0.21.4, axios@^0.21.0, axios@^0.21.4: dependencies: follow-redirects "^1.14.0" -axios@^1.0.0, axios@^1.3.3: +axios@^1.0.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.3.2.tgz#7ac517f0fa3ec46e0e636223fd973713a09c72b3" + integrity sha512-1M3O703bYqYuPhbHeya5bnhpYVsDDRyQSabNja04mZtboLNSuZ4YrltestrLXfHgmzua4TpUqRiVKbiQuo2epw== + dependencies: + follow-redirects "^1.15.0" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +axios@^1.3.3: version "1.6.0" resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.0.tgz#f1e5292f26b2fd5c2e66876adc5b06cdbd7d2102" integrity sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg== @@ -8790,6 +9302,16 @@ browserslist@^4.14.5, browserslist@^4.21.1, browserslist@^4.21.4, browserslist@^ node-releases "^2.0.13" update-browserslist-db "^1.0.11" +browserslist@^4.22.2: + version "4.22.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.3.tgz#299d11b7e947a6b843981392721169e27d60c5a6" + integrity sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A== + dependencies: + caniuse-lite "^1.0.30001580" + electron-to-chromium "^1.4.648" + node-releases "^2.0.14" + update-browserslist-db "^1.0.13" + bs-logger@0.x: version "0.2.6" resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" @@ -9011,10 +9533,10 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -caniuse-lite@^1.0.30001426, caniuse-lite@^1.0.30001517, caniuse-lite@~1.0.0: - version "1.0.30001587" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001587.tgz#a0bce920155fa56a1885a69c74e1163fc34b4881" - integrity sha512-HMFNotUmLXn71BQxg8cijvqxnIAofforZOwGsxyXJ0qugTdspUF4sPSJ2vhgprHCB996tIDzEq1ubumPDV8ULA== +caniuse-lite@^1.0.30001426, caniuse-lite@^1.0.30001517, caniuse-lite@^1.0.30001580, caniuse-lite@~1.0.0: + version "1.0.30001571" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001571.tgz#4182e93d696ff42930f4af7eba515ddeb57917ac" + integrity sha512-tYq/6MoXhdezDLFZuCO/TKboTzuQ/xR5cFdgXPfDtM7/kchBO3b4VWghE/OAi/DV7tTdhmLjZiZBZi1fA/GheQ== capital-case@^1.0.4: version "1.0.4" @@ -9075,7 +9597,7 @@ chalk@4.1.2, chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1. ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^2.4.2: +chalk@^2.3.2, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -9177,7 +9699,22 @@ cheerio@^1.0.0-rc.10: parse5-htmlparser2-tree-adapter "^6.0.1" tslib "^2.2.0" -chokidar@^3.3.1, chokidar@^3.4.0, chokidar@^3.5.1, chokidar@^3.5.3: +chokidar@^3.3.1, chokidar@^3.4.0, chokidar@^3.5.1: + version "3.5.2" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" + integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chokidar@^3.5.3: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== @@ -10307,10 +10844,10 @@ depd@2.0.0: resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== -depd@~1.1.2: +depd@^1.1.2, depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== dependency-graph@^0.11.0: version "0.11.0" @@ -10394,6 +10931,11 @@ diff-sequences@^29.4.3: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2" integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA== +diff@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== + diff@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" @@ -10588,6 +11130,7 @@ draft-js-utils@^1.4.0: "draft-js@https://github.com/mattkrick/draft-js/tarball/559a21968370c4944511657817d601a6c4ade0f6": version "0.10.5" + uid "025fddba56f21aaf3383aee778e0b17025c9a7bc" resolved "https://github.com/mattkrick/draft-js/tarball/559a21968370c4944511657817d601a6c4ade0f6#025fddba56f21aaf3383aee778e0b17025c9a7bc" dependencies: fbjs "^0.8.15" @@ -10658,6 +11201,11 @@ electron-to-chromium@^1.4.477: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.490.tgz#d99286f6e915667fa18ea4554def1aa60eb4d5f1" integrity sha512-6s7NVJz+sATdYnIwhdshx/N/9O6rvMxmhVoDSDFdj6iA45gHR8EQje70+RYsF4GeB+k0IeNSBnP7yG9ZXJFr7A== +electron-to-chromium@^1.4.648: + version "1.4.660" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.660.tgz#80be71d08c1224980e645904ab9155f3fa54a1ea" + integrity sha512-1BqvQG0BBQrAA7FVL2EMrb5A1sVyXF3auwJneXjGWa1TpN+g0C4KbUsYWePz6OZ0mXZfXGy+RmQDELJWwE8v/Q== + email-addresses@^3.0.1: version "3.1.0" resolved "https://registry.yarnpkg.com/email-addresses/-/email-addresses-3.1.0.tgz#cabf7e085cbdb63008a70319a74e6136188812fb" @@ -11640,7 +12188,7 @@ fs-constants@^1.0.0: resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== -fs-extra@^11.0.0, fs-extra@^11.1.0: +fs-extra@^11.0.0: version "11.1.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.1.1.tgz#da69f7c39f3b002378b0954bb6ae7efdc0876e2d" integrity sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ== @@ -11649,6 +12197,15 @@ fs-extra@^11.0.0, fs-extra@^11.1.0: jsonfile "^6.0.1" universalify "^2.0.0" +fs-extra@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.1.0.tgz#5784b102104433bb0e090f48bfc4a30742c357ed" + integrity sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + fs-extra@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" @@ -11715,6 +12272,11 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + functional-red-black-tree@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" @@ -11900,6 +12462,17 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" +git-diff@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/git-diff/-/git-diff-2.0.6.tgz#4a8ece670d64d1f9f4e68191ad8b1013900f6c1e" + integrity sha512-/Iu4prUrydE3Pb3lCBMbcSNIf81tgGt0W1ZwknnyF62t3tHmtiJTRj0f+1ZIhp3+Rh0ktz1pJVoa7ZXUCskivA== + dependencies: + chalk "^2.3.2" + diff "^3.5.0" + loglevel "^1.6.1" + shelljs "^0.8.1" + shelljs.exec "^1.1.7" + git-node-fs@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/git-node-fs/-/git-node-fs-1.0.0.tgz#49b215e242ebe43aa4c7561bbba499521752080f" @@ -12350,6 +12923,13 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +hasown@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" + integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== + dependencies: + function-bind "^1.1.2" + hdr-histogram-js@^2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz#0b860534655722b6e3f3e7dca7b78867cf43dcb5" @@ -12852,6 +13432,11 @@ internal-slot@^1.0.3: has "^1.0.3" side-channel "^1.0.4" +interpret@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" + integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== + interpret@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" @@ -12968,6 +13553,13 @@ is-ci@^2.0.0: dependencies: ci-info "^2.0.0" +is-core-module@^2.13.0: + version "2.13.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + dependencies: + hasown "^2.0.0" + is-core-module@^2.2.0, is-core-module@^2.5.0, is-core-module@^2.8.1, is-core-module@^2.9.0: version "2.11.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" @@ -14172,20 +14764,21 @@ koalas@^1.0.2: resolved "https://registry.yarnpkg.com/koalas/-/koalas-1.0.2.tgz#318433f074235db78fae5661a02a8ca53ee295cd" integrity sha1-MYQz8HQjXbePrlZhoCqMpT7ilc0= -kysely-codegen@^0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/kysely-codegen/-/kysely-codegen-0.10.0.tgz#ccc4a1d9c1a2f334a35d820554880251f2386524" - integrity sha512-EV2v9yr9N9WrUPrURvFl5FPTtz39npsi1p1tLpJwEcFeOAKAPJruBpAASvnZWdqu5Pw/aaTssStE3qcI2sfxMQ== +kysely-codegen@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/kysely-codegen/-/kysely-codegen-0.11.0.tgz#7506955c4c09201b571d528b42ffec8a1869160b" + integrity sha512-8aklzXygjANshk5BoGSQ0BWukKIoPL4/k1iFWyteGUQ/VtB1GlyrELBZv1GglydjLGECSSVDpsOgEXyWQmuksg== dependencies: chalk "4.1.2" dotenv "^16.0.3" + git-diff "^2.0.6" micromatch "^4.0.5" minimist "^1.2.8" -kysely@^0.26.3: - version "0.26.3" - resolved "https://registry.yarnpkg.com/kysely/-/kysely-0.26.3.tgz#45fdd0153d8c9418b0ea9a6f05ed46b95ed27678" - integrity sha512-yWSgGi9bY13b/W06DD2OCDDHQmq1kwTGYlQ4wpZkMOJqMGCstVCFIvxCCVG4KfY1/3G0MhDAcZsip/Lw8/vJWw== +kysely@^0.27.2: + version "0.27.2" + resolved "https://registry.yarnpkg.com/kysely/-/kysely-0.27.2.tgz#b289ce5e561064ec613a17149b7155783d2b36de" + integrity sha512-DmRvEfiR/NLpgsTbSxma2ldekhsdcd65+MNiKXyd/qj7w7X5e3cLkXxcj+MypsRDjPhHQ/CD5u3Eq1sBYzX0bw== launch-editor@^2.6.0: version "2.6.0" @@ -14628,6 +15221,11 @@ log-update@^4.0.0: slice-ansi "^4.0.0" wrap-ansi "^6.2.0" +loglevel@^1.6.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.9.1.tgz#d63976ac9bcd03c7c873116d41c2a85bafff1be7" + integrity sha512-hP3I3kCrDIMuRwAwHltphhDM1r8i55H33GgqjXbrisuJhF4kRhW1dNuxsRklp4bXl8DSdLaNLuiL4A/LWRfxvg== + long@^5.0.0: version "5.2.3" resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1" @@ -15512,6 +16110,11 @@ node-releases@^2.0.13: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== +node-releases@^2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" + integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== + node-rsa@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/node-rsa/-/node-rsa-1.1.1.tgz#efd9ad382097782f506153398496f79e4464434d" @@ -17853,6 +18456,13 @@ recast@^0.21.0: source-map "~0.6.1" tslib "^2.0.1" +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + integrity sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw== + dependencies: + resolve "^1.1.6" + rechoir@^0.7.0: version "0.7.1" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.1.tgz#9478a96a1ca135b5e88fc027f03ee92d6c645686" @@ -17895,6 +18505,13 @@ redis-parser@^3.0.0: dependencies: redis-errors "^1.0.0" +redlock@^5.0.0-beta.2: + version "5.0.0-beta.2" + resolved "https://registry.yarnpkg.com/redlock/-/redlock-5.0.0-beta.2.tgz#a629c07e07d001c0fdd9f2efa614144c4416fe44" + integrity sha512-2RDWXg5jgRptDrB1w9O/JgSZC0j7y4SlaXnor93H/UJm/QyDiFgBKNtrh0TI6oCXqYSaSoXxFh6Sd3VtYfhRXw== + dependencies: + node-abort-controller "^3.0.1" + redux@^4.0.0, redux@^4.0.4: version "4.1.2" resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.2.tgz#140f35426d99bb4729af760afcf79eaaac407104" @@ -17924,11 +18541,16 @@ regenerator-runtime@^0.12.0: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg== -regenerator-runtime@^0.13.11, regenerator-runtime@^0.13.5: +regenerator-runtime@^0.13.11: version "0.13.11" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== +regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.5: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + regenerator-transform@^0.15.0: version "0.15.0" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.0.tgz#cbd9ead5d77fae1a48d957cf889ad0586adb6537" @@ -18133,6 +18755,15 @@ resolve@^1.0.0, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.14. path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +resolve@^1.1.6: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + resolve@^2.0.0-next.3: version "2.0.0-next.3" resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.3.tgz#d41016293d4a8586a39ca5d9b5f15cbea1f55e46" @@ -18560,6 +19191,20 @@ shell-quote@^1.7.3, shell-quote@^1.8.0: resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== +shelljs.exec@^1.1.7: + version "1.1.8" + resolved "https://registry.yarnpkg.com/shelljs.exec/-/shelljs.exec-1.1.8.tgz#6f3c8dd017cb96d2dea82e712b758eab4fc2f68c" + integrity sha512-vFILCw+lzUtiwBAHV8/Ex8JsFjelFMdhONIsgKNLgTzeRckp2AOYRQtHJE/9LhNvdMmE27AGtzWx0+DHpwIwSw== + +shelljs@^0.8.1: + version "0.8.5" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c" + integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow== + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + shimmer@^1.1.0, shimmer@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" @@ -18831,10 +19476,10 @@ source-map-support@0.5.21, source-map-support@^0.5.12, source-map-support@^0.5.1 buffer-from "^1.0.0" source-map "^0.6.0" -source-map@^0.5.7: +source-map@^0.5.0, source-map@^0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: version "0.6.1" @@ -19127,7 +19772,16 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string-width@^5.0.0, string-width@^5.0.1, string-width@^5.1.2: +string-width@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.0.tgz#5ab00980cfb29f43e736b113a120a73a0fb569d3" + integrity sha512-7x54QnN21P+XL/v8SuNKvfgsUre6PXpN7mc77N3HlZv+f1SBRGmjxtOud2Z6FZ8DmdkD/IdjCaf9XXbnqmTZGQ== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + +string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== @@ -20244,6 +20898,14 @@ update-browserslist-db@^1.0.11: escalade "^3.1.1" picocolors "^1.0.0" +update-browserslist-db@^1.0.13: + version "1.0.13" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" + integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + upper-case-first@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-2.0.2.tgz#992c3273f882abd19d1e02894cc147117f844324" @@ -21239,7 +21901,7 @@ yargs-parser@20.2.4: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== -yargs-parser@21.1.1, yargs-parser@^21.0.1, yargs-parser@^21.1.1: +yargs-parser@21.1.1, yargs-parser@^21.0.0, yargs-parser@^21.0.1, yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== @@ -21287,7 +21949,20 @@ yargs@^16.2.0, yargs@~16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" -yargs@^17.0.0, yargs@^17.0.1, yargs@^17.3.1, yargs@^17.6.2, yargs@^17.7.1, yargs@^17.7.2: +yargs@^17.0.0, yargs@^17.0.1: + version "17.3.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.3.1.tgz#da56b28f32e2fd45aefb402ed9c26f42be4c07b9" + integrity sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.0.0" + +yargs@^17.3.1, yargs@^17.6.2, yargs@^17.7.1, yargs@^17.7.2: version "17.7.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== From 1008578fe38979940659d239bab584e2524efcad Mon Sep 17 00:00:00 2001 From: Matt Krick Date: Tue, 27 Feb 2024 15:47:13 -0800 Subject: [PATCH 15/39] merge production to avoid force push (#9461) Signed-off-by: Matt Krick --- .github/workflows/release-to-staging.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-to-staging.yml b/.github/workflows/release-to-staging.yml index 6e9225bf871..23428e40d7c 100644 --- a/.github/workflows/release-to-staging.yml +++ b/.github/workflows/release-to-staging.yml @@ -99,7 +99,7 @@ jobs: git config user.name github-actions git config user.email github-actions@github.com git checkout -b "release/v${{ env.ACTION_VERSION }}" - git merge -s ours origin/production + git merge -s ours production git push --set-upstream origin "release/v${{ env.ACTION_VERSION }}" gh pr create \ --assignee ${{ github.actor }} \ From 20ca927985830c95e9288bc97de4d667312d5e96 Mon Sep 17 00:00:00 2001 From: "parabol-release-bot[bot]" <150284312+parabol-release-bot[bot]@users.noreply.github.com> Date: Tue, 27 Feb 2024 15:52:39 -0800 Subject: [PATCH 16/39] chore(release): release v7.19.0 (#9460) Co-authored-by: parabol-release-bot[bot] <150284312+parabol-release-bot[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- CHANGELOG.md | 7 +++++++ package.json | 2 +- packages/chronos/package.json | 4 ++-- packages/client/package.json | 2 +- packages/gql-executor/package.json | 6 +++--- packages/integration-tests/package.json | 2 +- packages/server/package.json | 4 ++-- 8 files changed, 18 insertions(+), 11 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 28707a42151..5987f97c1f9 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "7.18.1" + ".": "7.19.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d1147fe08f..95e59988ef7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ This project adheres to [Semantic Versioning](http://semver.org/). This CHANGELOG follows conventions [outlined here](http://keepachangelog.com/). +## [7.19.0](https://github.com/ParabolInc/parabol/compare/v7.18.1...v7.19.0) (2024-02-27) + + +### Added + +* embedder service ([#9417](https://github.com/ParabolInc/parabol/issues/9417)) ([55faa17](https://github.com/ParabolInc/parabol/commit/55faa17ada5b1bd49182a29341b3465a82d2ddfd)) + ## [7.18.1](https://github.com/ParabolInc/parabol/compare/v7.18.0...v7.18.1) (2024-02-27) diff --git a/package.json b/package.json index fbc0c896925..ac443d0a50b 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.18.1", + "version": "7.19.0", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" diff --git a/packages/chronos/package.json b/packages/chronos/package.json index 5619754d830..0a26dc6eab0 100644 --- a/packages/chronos/package.json +++ b/packages/chronos/package.json @@ -1,6 +1,6 @@ { "name": "chronos", - "version": "7.18.1", + "version": "7.19.0", "description": "A cron job scheduler", "author": "Matt Krick ", "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/chronos#readme", @@ -25,6 +25,6 @@ }, "dependencies": { "cron": "^2.3.1", - "parabol-server": "7.18.1" + "parabol-server": "7.19.0" } } diff --git a/packages/client/package.json b/packages/client/package.json index 141dca1fe36..d87a2711aa8 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.18.1", + "version": "7.19.0", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" diff --git a/packages/gql-executor/package.json b/packages/gql-executor/package.json index 1f7848776eb..eafe4276efd 100644 --- a/packages/gql-executor/package.json +++ b/packages/gql-executor/package.json @@ -1,6 +1,6 @@ { "name": "gql-executor", - "version": "7.18.1", + "version": "7.19.0", "description": "A Stateless GraphQL Executor", "author": "Matt Krick ", "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/gqlExecutor#readme", @@ -27,8 +27,8 @@ }, "dependencies": { "dd-trace": "^4.2.0", - "parabol-client": "7.18.1", - "parabol-server": "7.18.1", + "parabol-client": "7.19.0", + "parabol-server": "7.19.0", "undici": "^5.26.2" } } diff --git a/packages/integration-tests/package.json b/packages/integration-tests/package.json index 3331444dcae..be7381348af 100644 --- a/packages/integration-tests/package.json +++ b/packages/integration-tests/package.json @@ -2,7 +2,7 @@ "name": "integration-tests", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.18.1", + "version": "7.19.0", "description": "", "main": "index.js", "scripts": { diff --git a/packages/server/package.json b/packages/server/package.json index 18ca0f00370..482d4e39efd 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.18.1", + "version": "7.19.0", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" @@ -124,7 +124,7 @@ "oauth-1.0a": "^2.2.6", "openai": "^4.24.1", "oy-vey": "^0.11.0", - "parabol-client": "7.18.1", + "parabol-client": "7.19.0", "pg": "^8.5.1", "react": "^17.0.2", "react-dom": "^17.0.2", From 7bd880314f6f48c897a9a708b2d6435b257fae90 Mon Sep 17 00:00:00 2001 From: Matt Krick Date: Tue, 27 Feb 2024 15:59:07 -0800 Subject: [PATCH 17/39] fix: checkout prod before merging it (#9463) Signed-off-by: Matt Krick --- .github/workflows/release-to-staging.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/release-to-staging.yml b/.github/workflows/release-to-staging.yml index 23428e40d7c..965fc86deaa 100644 --- a/.github/workflows/release-to-staging.yml +++ b/.github/workflows/release-to-staging.yml @@ -14,6 +14,10 @@ jobs: id-token: "write" pull-requests: "write" steps: + - name: Checkout production + uses: actions/checkout@v3 + with: + ref: production - name: Checkout uses: actions/checkout@v3 - name: Setup environment variables From 12ba80ec5fd41496126988507929279fb15e9999 Mon Sep 17 00:00:00 2001 From: "parabol-release-bot[bot]" <150284312+parabol-release-bot[bot]@users.noreply.github.com> Date: Tue, 27 Feb 2024 16:09:11 -0800 Subject: [PATCH 18/39] chore(release): release v7.19.1 (#9464) Co-authored-by: parabol-release-bot[bot] <150284312+parabol-release-bot[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- CHANGELOG.md | 7 +++++++ package.json | 2 +- packages/chronos/package.json | 4 ++-- packages/client/package.json | 2 +- packages/gql-executor/package.json | 6 +++--- packages/integration-tests/package.json | 2 +- packages/server/package.json | 4 ++-- 8 files changed, 18 insertions(+), 11 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 5987f97c1f9..0b5216f29bb 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "7.19.0" + ".": "7.19.1" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 95e59988ef7..8fd3aabcae1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ This project adheres to [Semantic Versioning](http://semver.org/). This CHANGELOG follows conventions [outlined here](http://keepachangelog.com/). +## [7.19.1](https://github.com/ParabolInc/parabol/compare/v7.19.0...v7.19.1) (2024-02-27) + + +### Fixed + +* checkout prod before merging it ([#9463](https://github.com/ParabolInc/parabol/issues/9463)) ([7bd8803](https://github.com/ParabolInc/parabol/commit/7bd880314f6f48c897a9a708b2d6435b257fae90)) + ## [7.19.0](https://github.com/ParabolInc/parabol/compare/v7.18.1...v7.19.0) (2024-02-27) diff --git a/package.json b/package.json index ac443d0a50b..c0a3b7c159d 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.0", + "version": "7.19.1", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" diff --git a/packages/chronos/package.json b/packages/chronos/package.json index 0a26dc6eab0..93a7eb54c77 100644 --- a/packages/chronos/package.json +++ b/packages/chronos/package.json @@ -1,6 +1,6 @@ { "name": "chronos", - "version": "7.19.0", + "version": "7.19.1", "description": "A cron job scheduler", "author": "Matt Krick ", "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/chronos#readme", @@ -25,6 +25,6 @@ }, "dependencies": { "cron": "^2.3.1", - "parabol-server": "7.19.0" + "parabol-server": "7.19.1" } } diff --git a/packages/client/package.json b/packages/client/package.json index d87a2711aa8..bc0bce70b96 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.0", + "version": "7.19.1", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" diff --git a/packages/gql-executor/package.json b/packages/gql-executor/package.json index eafe4276efd..b6354eaa7c9 100644 --- a/packages/gql-executor/package.json +++ b/packages/gql-executor/package.json @@ -1,6 +1,6 @@ { "name": "gql-executor", - "version": "7.19.0", + "version": "7.19.1", "description": "A Stateless GraphQL Executor", "author": "Matt Krick ", "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/gqlExecutor#readme", @@ -27,8 +27,8 @@ }, "dependencies": { "dd-trace": "^4.2.0", - "parabol-client": "7.19.0", - "parabol-server": "7.19.0", + "parabol-client": "7.19.1", + "parabol-server": "7.19.1", "undici": "^5.26.2" } } diff --git a/packages/integration-tests/package.json b/packages/integration-tests/package.json index be7381348af..926879401ae 100644 --- a/packages/integration-tests/package.json +++ b/packages/integration-tests/package.json @@ -2,7 +2,7 @@ "name": "integration-tests", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.0", + "version": "7.19.1", "description": "", "main": "index.js", "scripts": { diff --git a/packages/server/package.json b/packages/server/package.json index 482d4e39efd..3cc17f95bd4 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.0", + "version": "7.19.1", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" @@ -124,7 +124,7 @@ "oauth-1.0a": "^2.2.6", "openai": "^4.24.1", "oy-vey": "^0.11.0", - "parabol-client": "7.19.0", + "parabol-client": "7.19.1", "pg": "^8.5.1", "react": "^17.0.2", "react-dom": "^17.0.2", From 9e90b9df95b8505c0e1e50d4e8e4f18c73ef17cd Mon Sep 17 00:00:00 2001 From: Matt Krick Date: Tue, 27 Feb 2024 16:13:57 -0800 Subject: [PATCH 19/39] fix: mrege origin/production strategy (#9465) Signed-off-by: Matt Krick --- .github/workflows/release-to-staging.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-to-staging.yml b/.github/workflows/release-to-staging.yml index 965fc86deaa..22efc4326c4 100644 --- a/.github/workflows/release-to-staging.yml +++ b/.github/workflows/release-to-staging.yml @@ -103,7 +103,7 @@ jobs: git config user.name github-actions git config user.email github-actions@github.com git checkout -b "release/v${{ env.ACTION_VERSION }}" - git merge -s ours production + git merge -s ours origin/production git push --set-upstream origin "release/v${{ env.ACTION_VERSION }}" gh pr create \ --assignee ${{ github.actor }} \ From e67ca9100406b1da5e757ceebe7954525e889091 Mon Sep 17 00:00:00 2001 From: "parabol-release-bot[bot]" <150284312+parabol-release-bot[bot]@users.noreply.github.com> Date: Tue, 27 Feb 2024 16:19:34 -0800 Subject: [PATCH 20/39] chore(release): release v7.19.2 (#9466) Co-authored-by: parabol-release-bot[bot] <150284312+parabol-release-bot[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- CHANGELOG.md | 7 +++++++ package.json | 2 +- packages/chronos/package.json | 4 ++-- packages/client/package.json | 2 +- packages/gql-executor/package.json | 6 +++--- packages/integration-tests/package.json | 2 +- packages/server/package.json | 4 ++-- 8 files changed, 18 insertions(+), 11 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 0b5216f29bb..f7e3c7439f1 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "7.19.1" + ".": "7.19.2" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fd3aabcae1..b59c8a24c45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ This project adheres to [Semantic Versioning](http://semver.org/). This CHANGELOG follows conventions [outlined here](http://keepachangelog.com/). +## [7.19.2](https://github.com/ParabolInc/parabol/compare/v7.19.1...v7.19.2) (2024-02-28) + + +### Fixed + +* mrege origin/production strategy ([#9465](https://github.com/ParabolInc/parabol/issues/9465)) ([9e90b9d](https://github.com/ParabolInc/parabol/commit/9e90b9df95b8505c0e1e50d4e8e4f18c73ef17cd)) + ## [7.19.1](https://github.com/ParabolInc/parabol/compare/v7.19.0...v7.19.1) (2024-02-27) diff --git a/package.json b/package.json index c0a3b7c159d..0b090221999 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.1", + "version": "7.19.2", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" diff --git a/packages/chronos/package.json b/packages/chronos/package.json index 93a7eb54c77..9b0cdf6e408 100644 --- a/packages/chronos/package.json +++ b/packages/chronos/package.json @@ -1,6 +1,6 @@ { "name": "chronos", - "version": "7.19.1", + "version": "7.19.2", "description": "A cron job scheduler", "author": "Matt Krick ", "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/chronos#readme", @@ -25,6 +25,6 @@ }, "dependencies": { "cron": "^2.3.1", - "parabol-server": "7.19.1" + "parabol-server": "7.19.2" } } diff --git a/packages/client/package.json b/packages/client/package.json index bc0bce70b96..fde694d8712 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.1", + "version": "7.19.2", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" diff --git a/packages/gql-executor/package.json b/packages/gql-executor/package.json index b6354eaa7c9..90360640290 100644 --- a/packages/gql-executor/package.json +++ b/packages/gql-executor/package.json @@ -1,6 +1,6 @@ { "name": "gql-executor", - "version": "7.19.1", + "version": "7.19.2", "description": "A Stateless GraphQL Executor", "author": "Matt Krick ", "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/gqlExecutor#readme", @@ -27,8 +27,8 @@ }, "dependencies": { "dd-trace": "^4.2.0", - "parabol-client": "7.19.1", - "parabol-server": "7.19.1", + "parabol-client": "7.19.2", + "parabol-server": "7.19.2", "undici": "^5.26.2" } } diff --git a/packages/integration-tests/package.json b/packages/integration-tests/package.json index 926879401ae..6bf9e8fb58f 100644 --- a/packages/integration-tests/package.json +++ b/packages/integration-tests/package.json @@ -2,7 +2,7 @@ "name": "integration-tests", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.1", + "version": "7.19.2", "description": "", "main": "index.js", "scripts": { diff --git a/packages/server/package.json b/packages/server/package.json index 3cc17f95bd4..03c796234f6 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.1", + "version": "7.19.2", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" @@ -124,7 +124,7 @@ "oauth-1.0a": "^2.2.6", "openai": "^4.24.1", "oy-vey": "^0.11.0", - "parabol-client": "7.19.1", + "parabol-client": "7.19.2", "pg": "^8.5.1", "react": "^17.0.2", "react-dom": "^17.0.2", From 581f0cfa2255bbeb438c53b2b5f4d8ceb6a0b0cc Mon Sep 17 00:00:00 2001 From: Matt Krick Date: Tue, 27 Feb 2024 16:28:34 -0800 Subject: [PATCH 21/39] fix: force push 5 (#9467) Signed-off-by: Matt Krick --- .github/workflows/release-to-staging.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-to-staging.yml b/.github/workflows/release-to-staging.yml index 22efc4326c4..c6e3601f2ff 100644 --- a/.github/workflows/release-to-staging.yml +++ b/.github/workflows/release-to-staging.yml @@ -103,7 +103,7 @@ jobs: git config user.name github-actions git config user.email github-actions@github.com git checkout -b "release/v${{ env.ACTION_VERSION }}" - git merge -s ours origin/production + git merge -s ours origin/production --allow-unrelated-histories git push --set-upstream origin "release/v${{ env.ACTION_VERSION }}" gh pr create \ --assignee ${{ github.actor }} \ From b52faf2accf88492fdf641825e554f8451bd2fd7 Mon Sep 17 00:00:00 2001 From: "parabol-release-bot[bot]" <150284312+parabol-release-bot[bot]@users.noreply.github.com> Date: Tue, 27 Feb 2024 16:34:40 -0800 Subject: [PATCH 22/39] chore(release): release v7.19.3 (#9468) Co-authored-by: parabol-release-bot[bot] <150284312+parabol-release-bot[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- CHANGELOG.md | 7 +++++++ package.json | 2 +- packages/chronos/package.json | 4 ++-- packages/client/package.json | 2 +- packages/gql-executor/package.json | 6 +++--- packages/integration-tests/package.json | 2 +- packages/server/package.json | 4 ++-- 8 files changed, 18 insertions(+), 11 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index f7e3c7439f1..517aeb7a63e 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "7.19.2" + ".": "7.19.3" } diff --git a/CHANGELOG.md b/CHANGELOG.md index b59c8a24c45..579182dc3f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ This project adheres to [Semantic Versioning](http://semver.org/). This CHANGELOG follows conventions [outlined here](http://keepachangelog.com/). +## [7.19.3](https://github.com/ParabolInc/parabol/compare/v7.19.2...v7.19.3) (2024-02-28) + + +### Fixed + +* force push 5 ([#9467](https://github.com/ParabolInc/parabol/issues/9467)) ([581f0cf](https://github.com/ParabolInc/parabol/commit/581f0cfa2255bbeb438c53b2b5f4d8ceb6a0b0cc)) + ## [7.19.2](https://github.com/ParabolInc/parabol/compare/v7.19.1...v7.19.2) (2024-02-28) diff --git a/package.json b/package.json index 0b090221999..cc2eb303c5d 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.2", + "version": "7.19.3", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" diff --git a/packages/chronos/package.json b/packages/chronos/package.json index 9b0cdf6e408..ff73a275826 100644 --- a/packages/chronos/package.json +++ b/packages/chronos/package.json @@ -1,6 +1,6 @@ { "name": "chronos", - "version": "7.19.2", + "version": "7.19.3", "description": "A cron job scheduler", "author": "Matt Krick ", "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/chronos#readme", @@ -25,6 +25,6 @@ }, "dependencies": { "cron": "^2.3.1", - "parabol-server": "7.19.2" + "parabol-server": "7.19.3" } } diff --git a/packages/client/package.json b/packages/client/package.json index fde694d8712..364dbda0932 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.2", + "version": "7.19.3", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" diff --git a/packages/gql-executor/package.json b/packages/gql-executor/package.json index 90360640290..84dbff4bdfb 100644 --- a/packages/gql-executor/package.json +++ b/packages/gql-executor/package.json @@ -1,6 +1,6 @@ { "name": "gql-executor", - "version": "7.19.2", + "version": "7.19.3", "description": "A Stateless GraphQL Executor", "author": "Matt Krick ", "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/gqlExecutor#readme", @@ -27,8 +27,8 @@ }, "dependencies": { "dd-trace": "^4.2.0", - "parabol-client": "7.19.2", - "parabol-server": "7.19.2", + "parabol-client": "7.19.3", + "parabol-server": "7.19.3", "undici": "^5.26.2" } } diff --git a/packages/integration-tests/package.json b/packages/integration-tests/package.json index 6bf9e8fb58f..f105f56d7da 100644 --- a/packages/integration-tests/package.json +++ b/packages/integration-tests/package.json @@ -2,7 +2,7 @@ "name": "integration-tests", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.2", + "version": "7.19.3", "description": "", "main": "index.js", "scripts": { diff --git a/packages/server/package.json b/packages/server/package.json index 03c796234f6..625dc427b3f 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.2", + "version": "7.19.3", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" @@ -124,7 +124,7 @@ "oauth-1.0a": "^2.2.6", "openai": "^4.24.1", "oy-vey": "^0.11.0", - "parabol-client": "7.19.2", + "parabol-client": "7.19.3", "pg": "^8.5.1", "react": "^17.0.2", "react-dom": "^17.0.2", From 5b9526c092f7f8675ad2a442da4440e2507cbdcc Mon Sep 17 00:00:00 2001 From: Nick O'Ferrall Date: Wed, 28 Feb 2024 09:59:59 +0000 Subject: [PATCH 23/39] fix: limit invites from spammers (#9416) * fix: limit invites from spammers * update where we check pending emails * check total plus pending invites * use invitees instead of pending --- .../mutations/helpers/inviteToTeamHelper.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/server/graphql/mutations/helpers/inviteToTeamHelper.ts b/packages/server/graphql/mutations/helpers/inviteToTeamHelper.ts index c78036add14..053ca0f381f 100644 --- a/packages/server/graphql/mutations/helpers/inviteToTeamHelper.ts +++ b/packages/server/graphql/mutations/helpers/inviteToTeamHelper.ts @@ -37,6 +37,21 @@ const inviteToTeamHelper = async ( const operationId = dataLoader.share() const subOptions = {mutatorId, operationId} + const [total, pending] = await Promise.all([ + r.table('TeamInvitation').getAll(teamId, {index: 'teamId'}).count().run(), + r + .table('TeamInvitation') + .getAll(teamId, {index: 'teamId'}) + .filter({acceptedAt: null}) + .count() + .run() + ]) + const accepted = total - pending + // if no one has accepted one of their 100+ invites, don't trust them + if (accepted === 0 && total + invitees.length >= 100) { + return standardError(new Error('Exceeded unaccepted invitation limit'), {userId: viewerId}) + } + const untrustedDomains = ['tempmail.cn', 'qq.com'] const filteredInvitees = invitees.filter( (invitee) => !untrustedDomains.includes(getDomainFromEmail(invitee).toLowerCase()) From 9cec00a5fd0b46c73ebdde27e6d966b485216132 Mon Sep 17 00:00:00 2001 From: Georg Bremer Date: Wed, 28 Feb 2024 19:20:49 +0100 Subject: [PATCH 24/39] fix: Fetch Jira projects in parallel (#9456) Previously we tried to fetch more projects per page, but Jira only ever returns 50 max. Instead once we know how many projects there are after fetching the first page, we fetch all remaining pages in parallel. --- .../server/utils/AtlassianServerManager.ts | 54 +++++++++++++++---- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/packages/server/utils/AtlassianServerManager.ts b/packages/server/utils/AtlassianServerManager.ts index d84a448f7be..2cd82d3e8e4 100644 --- a/packages/server/utils/AtlassianServerManager.ts +++ b/packages/server/utils/AtlassianServerManager.ts @@ -358,7 +358,38 @@ class AtlassianServerManager extends AtlassianManager { async getAllProjects(cloudIds: string[]) { const projects = [] as (JiraProject & {cloudId: string})[] let error: Error | undefined - const getProjectPage = async (cloudId: string, url: string): Promise => { + const getProjectsPage = async ( + cloudId: string, + startAt: number, + maxResults: number + ): Promise => { + const url = `https://api.atlassian.com/ex/jira/${cloudId}/rest/api/3/project/search?orderBy=name&startAt=${startAt}` + const res = await this.get(url) + if (res instanceof Error || res instanceof RateLimitError) { + error = res + } else { + const pagedProjects = res.values.map((project) => ({ + ...project, + cloudId + })) + projects.push(...pagedProjects) + + if (pagedProjects.length < maxResults && res.nextPage) { + Logger.log( + 'Underfetched in getAllProjects, requested', + maxResults, + 'got', + pagedProjects.length + ) + const nextStart = res.startAt + pagedProjects.length + const nextMaxResults = maxResults - pagedProjects.length + return getProjectsPage(cloudId, nextStart, nextMaxResults) + } + } + } + + const getProjects = async (cloudId: string) => { + const url = `https://api.atlassian.com/ex/jira/${cloudId}/rest/api/3/project/search?orderBy=name` const res = await this.get(url) if (res instanceof Error || res instanceof RateLimitError) { error = res @@ -369,19 +400,20 @@ class AtlassianServerManager extends AtlassianManager { })) projects.push(...pagedProjects) if (res.nextPage) { - Logger.log('AtlassianServerManager.getAllProjects fetching more results', res.total) - return getProjectPage(cloudId, res.nextPage) + const {total} = res + const nextStart = res.startAt + pagedProjects.length + const fetches = [] as Array> + // 50 is the default maxResults for Jira, Jira does not respond with more than that + const maxResults = 50 + for (let i = nextStart; i < total; i += maxResults) { + fetches.push(getProjectsPage(cloudId, i, maxResults)) + } + await Promise.all(fetches) } } } - await Promise.all( - cloudIds.map((cloudId) => - getProjectPage( - cloudId, - `https://api.atlassian.com/ex/jira/${cloudId}/rest/api/3/project/search?orderBy=name&maxResults=500` - ) - ) - ) + + await Promise.all(cloudIds.map((cloudId) => getProjects(cloudId))) if (error) { Logger.log('getAllProjects ERROR:', error) From 00092ec55659d1441e9566d501940dcc6fcf07f4 Mon Sep 17 00:00:00 2001 From: Matt Krick Date: Wed, 28 Feb 2024 12:56:50 -0800 Subject: [PATCH 25/39] fix: replace lone surrogates in draft-js content (#9415) * fix: replace lone surrogates in draft-js content Signed-off-by: Matt Krick * fix typo Signed-off-by: Matt Krick * fix: eslint errors Signed-off-by: Matt Krick --------- Signed-off-by: Matt Krick --- .eslintrc.js | 1 + package.json | 7 +- packages/chronos/package.json | 2 +- packages/client/package.json | 2 +- packages/client/utils/AtlassianManager.ts | 2 +- .../draftjs/extractTextFromDraftString.ts | 3 +- packages/gql-executor/package.json | 4 +- packages/integration-tests/package.json | 5 +- packages/server/package.json | 4 +- packages/server/tsconfig.json | 15 +- yarn.lock | 249 ++++++++++++------ 11 files changed, 181 insertions(+), 113 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 111e259c651..1962c0f1b60 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -20,6 +20,7 @@ module.exports = { '@typescript-eslint/no-use-before-define': 'off', '@typescript-eslint/explicit-member-accessibility': 'off', '@typescript-eslint/interface-name-prefix': 'off', + '@typescript-eslint/no-duplicate-enum-values': 'off', '@typescript-eslint/no-unused-vars': 'off', '@typescript-eslint/no-var-requires': 'off', '@typescript-eslint/no-parameter-properties': 'off', diff --git a/package.json b/package.json index cc2eb303c5d..5b7253fec2e 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "test:server": "yarn workspace parabol-server test" }, "resolutions": { - "typescript": "4.9.5", + "typescript": "^5.3.3", "hoist-non-react-statics": "^3.3.0", "@types/react": "16.9.11", "@types/react-dom": "16.9.4", @@ -92,8 +92,8 @@ "@types/dotenv": "^6.1.1", "@types/jscodeshift": "^0.11.3", "@types/lodash.toarray": "^4.4.7", - "@typescript-eslint/eslint-plugin": "5.17.0", - "@typescript-eslint/parser": "5.17.0", + "@typescript-eslint/eslint-plugin": "^6.21.0", + "@typescript-eslint/parser": "^6.21.0", "autoprefixer": "^10.4.13", "babel-loader": "^9.1.2", "concurrently": "^8.0.1", @@ -123,6 +123,7 @@ "tailwindcss": "^3.2.7", "terser-webpack-plugin": "^5.3.9", "ts-loader": "9.2.6", + "typescript": "^5.3.3", "vscode-apollo-relay": "^1.5.0", "webpack": "^5.89.0", "webpack-cli": "4.9.1", diff --git a/packages/chronos/package.json b/packages/chronos/package.json index ff73a275826..39bec48dcf6 100644 --- a/packages/chronos/package.json +++ b/packages/chronos/package.json @@ -21,7 +21,7 @@ }, "devDependencies": { "@types/cron": "^2.0.1", - "@types/node": "^16.11.62" + "@types/node": "^20.11.17" }, "dependencies": { "cron": "^2.3.1", diff --git a/packages/client/package.json b/packages/client/package.json index 364dbda0932..19a38863130 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -60,7 +60,7 @@ "prettier": "^2.8.8", "react-refresh": "^0.9.0", "strict-event-emitter-types": "^2.0.0", - "typescript": "4.9.5", + "typescript": "^5.3.3", "webpack-dev-server": "^4.15.1" }, "dependencies": { diff --git a/packages/client/utils/AtlassianManager.ts b/packages/client/utils/AtlassianManager.ts index c501b9bc768..5726a0e5636 100644 --- a/packages/client/utils/AtlassianManager.ts +++ b/packages/client/utils/AtlassianManager.ts @@ -40,7 +40,7 @@ export type JiraPermissionScope = export class RateLimitError { retryAt: Date - name: 'RateLimitError' = 'RateLimitError' + name = 'RateLimitError' as const message: string constructor(message: string, retryAt: Date) { diff --git a/packages/client/utils/draftjs/extractTextFromDraftString.ts b/packages/client/utils/draftjs/extractTextFromDraftString.ts index a7ac9f22b4f..95e03014184 100644 --- a/packages/client/utils/draftjs/extractTextFromDraftString.ts +++ b/packages/client/utils/draftjs/extractTextFromDraftString.ts @@ -2,7 +2,8 @@ import {RawDraftContentState} from 'draft-js' const extractTextFromDraftString = (content: string) => { const parsedContent = JSON.parse(content) as RawDraftContentState - const textBlocks = parsedContent.blocks.map(({text}) => text) + // toWellFormed replaces lone surrogates with replacement char (e.g. emoji that only has its first code point) + const textBlocks = parsedContent.blocks.map(({text}) => (text as any).toWellFormed()) return textBlocks.join('\n') } diff --git a/packages/gql-executor/package.json b/packages/gql-executor/package.json index 84dbff4bdfb..10852a68c4a 100644 --- a/packages/gql-executor/package.json +++ b/packages/gql-executor/package.json @@ -18,12 +18,12 @@ "devDependencies": { "@babel/cli": "7.18.6", "@babel/core": "7.18.6", - "@types/node": "^16.11.62", + "@types/node": "^20.11.17", "babel-plugin-inline-import": "^3.0.0", "chokidar": "^3.3.1", "sucrase": "^3.32.0", "ts-node-dev": "^1.0.0-pre.44", - "typescript": "4.9.5" + "typescript": "^5.3.3" }, "dependencies": { "dd-trace": "^4.2.0", diff --git a/packages/integration-tests/package.json b/packages/integration-tests/package.json index f105f56d7da..a70463e1320 100644 --- a/packages/integration-tests/package.json +++ b/packages/integration-tests/package.json @@ -11,13 +11,10 @@ }, "devDependencies": { "@playwright/test": "^1.34.3", - "@types/node": "^16.11.62", - "@typescript-eslint/eslint-plugin": "^5.17.0", - "@typescript-eslint/parser": "^5.17.0", "eslint": "^8.8.0", "eslint-config-prettier": "^8.5.0", "lint-staged": "^12.3.3", "ts-app-env": "^1.4.2", - "typescript": "^4.5.5" + "typescript": "^5.3.3" } } diff --git a/packages/server/package.json b/packages/server/package.json index 625dc427b3f..79b79743566 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -39,7 +39,7 @@ "@types/jsonwebtoken": "^8.3.0", "@types/mime-types": "^2.1.0", "@types/ms": "^0.7.30", - "@types/node": "^16.11.62", + "@types/node": "^20.11.17", "@types/nodemailer": "^6.4.14", "@types/relay-runtime": "^14.1.9", "@types/sharp": "^0.32.0", @@ -68,7 +68,7 @@ "sucrase": "^3.32.0", "ts-jest": "^29.1.0", "ts-node": "^8.6.2", - "typescript": "4.9.5", + "typescript": "^5.3.3", "url-loader": "4.1.1", "vscode-apollo-relay": "^1.5.0", "webpack-bundle-analyzer": "4.3.0", diff --git a/packages/server/tsconfig.json b/packages/server/tsconfig.json index 4a095c384e0..a1a9c3130df 100644 --- a/packages/server/tsconfig.json +++ b/packages/server/tsconfig.json @@ -8,15 +8,8 @@ "parabol-client/*": ["client/*"], "~/*": ["client/*"] }, - "lib": [ - "esnext", - "dom" - ], - "types": [ - "node", - "jest", - "jest-extended" - ] + "lib": ["esnext", "dom"], + "types": ["node", "jest", "jest-extended"] }, "exclude": [ @@ -31,9 +24,7 @@ "server.ts", "../client/modules/email/components/SummaryEmail/MeetingSummaryEmail/MeetingSummaryEmail.tsx" ], - "include": [ - "graphql/**/*.ts", - ] + "include": ["graphql/**/*.ts"] // if "include" or "files" is added, even if they are empty arrays, then strictNullChecks breaks // repro: https://www.typescriptlang.org/play?strictFunctionTypes=false&strictPropertyInitialization=false&strictBindCallApply=false&noImplicitThis=false&noImplicitReturns=false&alwaysStrict=false&declaration=false&experimentalDecorators=false&emitDecoratorMetadata=false&target=6&ts=3.5.1#code/C4TwDgpgBA8gRgKygXigbwFBSgWwIYhwQDKwATgIJlkD8AXFAM7kCWAdgOYDaAuhgL4ZQkKFTIpYiLgHJ8hEuTHS+AYwD2bZlDwS2AVwA2B7Y21sQJ0dQx4AdADM1ZAKJ4VACwAUngF4BKFAA+KH8MIA diff --git a/yarn.lock b/yarn.lock index 69cf14bcce1..5054b6dcddb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3159,6 +3159,18 @@ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz#ea89004119dc42db2e1dba0f97d553f7372f6fcb" integrity sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg== +"@eslint-community/eslint-utils@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.5.1": + version "4.10.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" + integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== + "@eslint/eslintrc@^1.0.5": version "1.0.5" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.0.5.tgz#33f1b838dbf1f923bfa517e008362b78ddbbf318" @@ -7572,6 +7584,11 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== +"@types/json-schema@^7.0.12": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + "@types/json-stable-stringify@^1.0.32": version "1.0.33" resolved "https://registry.yarnpkg.com/@types/json-stable-stringify/-/json-stable-stringify-1.0.33.tgz#099b0712d824d15e2660c20e1c16e6a8381f308c" @@ -7699,15 +7716,22 @@ undici-types "~5.25.1" "@types/node@^16.11.62": - version "16.11.62" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.62.tgz#bab2e6208531321d147eda20c38e389548cd5ffc" - integrity sha512-K/ggecSdwAAy2NUW4WKmF4Rc03GKbsfP+k326UWgckoS+Rzd2PaWbjk76dSmqdLQvLTJAO9axiTUJ6488mFsYQ== + version "16.18.85" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.85.tgz#17b5338c958efd67b064b92fbef41ad0333c397b" + integrity sha512-un7Bj6CPCRLxG2qp+9enNVFuRWCDKKOS6Q/FSpJ4xyrpLNJnRdAQERM2sJ6esaGvl02nK6kiGcMTb0pqknm62g== "@types/node@^18.11.18": version "18.17.18" resolved "https://registry.yarnpkg.com/@types/node/-/node-18.17.18.tgz#acae19ad9011a2ab3d792232501c95085ba1838f" integrity sha512-/4QOuy3ZpV7Ya1GTRz5CYSz3DgkKpyUptXuQ5PPce7uuyJAOR7r9FhkmxJfvcNUXyklbC63a+YvB3jxy7s9ngw== +"@types/node@^20.11.17": + version "20.11.17" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.17.tgz#cdd642d0e62ef3a861f88ddbc2b61e32578a9292" + integrity sha512-QmgQZGWu1Yw9TDyAP9ZzpFJKynYNeOvwMJmaxABfieQoVoiVOS6MN1WSpqpRcbeA5+RW82kraAVxCCJg+780Qw== + dependencies: + undici-types "~5.26.4" + "@types/nodemailer@^6.4.14": version "6.4.14" resolved "https://registry.yarnpkg.com/@types/nodemailer/-/nodemailer-6.4.14.tgz#5c81a5e856db7f8ede80013e6dbad7c5fb2283e2" @@ -7892,6 +7916,11 @@ "@types/glob" "*" "@types/node" "*" +"@types/semver@^7.5.0": + version "7.5.6" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.6.tgz#c65b2bfce1bec346582c07724e3f8c1017a20339" + integrity sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A== + "@types/send@*": version "0.17.1" resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.1.tgz#ed4932b8a2a805f1fe362a70f4e62d0ac994e301" @@ -8044,85 +8073,91 @@ resolved "https://registry.yarnpkg.com/@types/yup/-/yup-0.29.11.tgz#d654a112973f5e004bf8438122bd7e56a8e5cd7e" integrity sha512-9cwk3c87qQKZrT251EDoibiYRILjCmxBvvcb4meofCmx1vdnNcR9gyildy5vOHASpOKMsn42CugxUvcwK5eu1g== -"@typescript-eslint/eslint-plugin@5.17.0", "@typescript-eslint/eslint-plugin@^5.17.0": - version "5.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.17.0.tgz#704eb4e75039000531255672bf1c85ee85cf1d67" - integrity sha512-qVstvQilEd89HJk3qcbKt/zZrfBZ+9h2ynpAGlWjWiizA7m/MtLT9RoX6gjtpE500vfIg8jogAkDzdCxbsFASQ== +"@typescript-eslint/eslint-plugin@^6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz#30830c1ca81fd5f3c2714e524c4303e0194f9cd3" + integrity sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA== dependencies: - "@typescript-eslint/scope-manager" "5.17.0" - "@typescript-eslint/type-utils" "5.17.0" - "@typescript-eslint/utils" "5.17.0" - debug "^4.3.2" - functional-red-black-tree "^1.0.1" - ignore "^5.1.8" - regexpp "^3.2.0" - semver "^7.3.5" - tsutils "^3.21.0" + "@eslint-community/regexpp" "^4.5.1" + "@typescript-eslint/scope-manager" "6.21.0" + "@typescript-eslint/type-utils" "6.21.0" + "@typescript-eslint/utils" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" + debug "^4.3.4" + graphemer "^1.4.0" + ignore "^5.2.4" + natural-compare "^1.4.0" + semver "^7.5.4" + ts-api-utils "^1.0.1" -"@typescript-eslint/parser@5.17.0", "@typescript-eslint/parser@^5.17.0": - version "5.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.17.0.tgz#7def77d5bcd8458d12d52909118cf3f0a45f89d5" - integrity sha512-aRzW9Jg5Rlj2t2/crzhA2f23SIYFlF9mchGudyP0uiD6SenIxzKoLjwzHbafgHn39dNV/TV7xwQkLfFTZlJ4ig== +"@typescript-eslint/parser@^6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.21.0.tgz#af8fcf66feee2edc86bc5d1cf45e33b0630bf35b" + integrity sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ== dependencies: - "@typescript-eslint/scope-manager" "5.17.0" - "@typescript-eslint/types" "5.17.0" - "@typescript-eslint/typescript-estree" "5.17.0" - debug "^4.3.2" + "@typescript-eslint/scope-manager" "6.21.0" + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/typescript-estree" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" + debug "^4.3.4" -"@typescript-eslint/scope-manager@5.17.0": - version "5.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.17.0.tgz#4cea7d0e0bc0e79eb60cad431c89120987c3f952" - integrity sha512-062iCYQF/doQ9T2WWfJohQKKN1zmmXVfAcS3xaiialiw8ZUGy05Em6QVNYJGO34/sU1a7a+90U3dUNfqUDHr3w== +"@typescript-eslint/scope-manager@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz#ea8a9bfc8f1504a6ac5d59a6df308d3a0630a2b1" + integrity sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg== dependencies: - "@typescript-eslint/types" "5.17.0" - "@typescript-eslint/visitor-keys" "5.17.0" + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" -"@typescript-eslint/type-utils@5.17.0": - version "5.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.17.0.tgz#1c4549d68c89877662224aabb29fbbebf5fc9672" - integrity sha512-3hU0RynUIlEuqMJA7dragb0/75gZmwNwFf/QJokWzPehTZousP/MNifVSgjxNcDCkM5HI2K22TjQWUmmHUINSg== +"@typescript-eslint/type-utils@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz#6473281cfed4dacabe8004e8521cee0bd9d4c01e" + integrity sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag== dependencies: - "@typescript-eslint/utils" "5.17.0" - debug "^4.3.2" - tsutils "^3.21.0" + "@typescript-eslint/typescript-estree" "6.21.0" + "@typescript-eslint/utils" "6.21.0" + debug "^4.3.4" + ts-api-utils "^1.0.1" -"@typescript-eslint/types@5.17.0": - version "5.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.17.0.tgz#861ec9e669ffa2aa9b873dd4d28d9b1ce26d216f" - integrity sha512-AgQ4rWzmCxOZLioFEjlzOI3Ch8giDWx8aUDxyNw9iOeCvD3GEYAB7dxWGQy4T/rPVe8iPmu73jPHuaSqcjKvxw== +"@typescript-eslint/types@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.21.0.tgz#205724c5123a8fef7ecd195075fa6e85bac3436d" + integrity sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg== -"@typescript-eslint/typescript-estree@5.17.0": - version "5.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.17.0.tgz#a7cba7dfc8f9cc2ac78c18584e684507df4f2488" - integrity sha512-X1gtjEcmM7Je+qJRhq7ZAAaNXYhTgqMkR10euC4Si6PIjb+kwEQHSxGazXUQXFyqfEXdkGf6JijUu5R0uceQzg== +"@typescript-eslint/typescript-estree@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz#c47ae7901db3b8bddc3ecd73daff2d0895688c46" + integrity sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ== dependencies: - "@typescript-eslint/types" "5.17.0" - "@typescript-eslint/visitor-keys" "5.17.0" - debug "^4.3.2" - globby "^11.0.4" + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" + debug "^4.3.4" + globby "^11.1.0" is-glob "^4.0.3" - semver "^7.3.5" - tsutils "^3.21.0" - -"@typescript-eslint/utils@5.17.0": - version "5.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.17.0.tgz#549a9e1d491c6ccd3624bc3c1b098f5cfb45f306" - integrity sha512-DVvndq1QoxQH+hFv+MUQHrrWZ7gQ5KcJzyjhzcqB1Y2Xes1UQQkTRPUfRpqhS8mhTWsSb2+iyvDW1Lef5DD7vA== - dependencies: - "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.17.0" - "@typescript-eslint/types" "5.17.0" - "@typescript-eslint/typescript-estree" "5.17.0" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" + minimatch "9.0.3" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/utils@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.21.0.tgz#4714e7a6b39e773c1c8e97ec587f520840cd8134" + integrity sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@types/json-schema" "^7.0.12" + "@types/semver" "^7.5.0" + "@typescript-eslint/scope-manager" "6.21.0" + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/typescript-estree" "6.21.0" + semver "^7.5.4" -"@typescript-eslint/visitor-keys@5.17.0": - version "5.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.17.0.tgz#52daae45c61b0211b4c81b53a71841911e479128" - integrity sha512-6K/zlc4OfCagUu7Am/BD5k8PSWQOgh34Nrv9Rxe2tBzlJ7uOeJ/h7ugCGDCeEZHT6k2CJBhbk9IsbkPI0uvUkA== +"@typescript-eslint/visitor-keys@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz#87a99d077aa507e20e238b11d56cc26ade45fe47" + integrity sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A== dependencies: - "@typescript-eslint/types" "5.17.0" - eslint-visitor-keys "^3.0.0" + "@typescript-eslint/types" "6.21.0" + eslint-visitor-keys "^3.4.1" "@webassemblyjs/ast@1.11.5", "@webassemblyjs/ast@^1.11.5": version "1.11.5" @@ -11130,7 +11165,6 @@ draft-js-utils@^1.4.0: "draft-js@https://github.com/mattkrick/draft-js/tarball/559a21968370c4944511657817d601a6c4ade0f6": version "0.10.5" - uid "025fddba56f21aaf3383aee778e0b17025c9a7bc" resolved "https://github.com/mattkrick/draft-js/tarball/559a21968370c4944511657817d601a6c4ade0f6#025fddba56f21aaf3383aee778e0b17025c9a7bc" dependencies: fbjs "^0.8.15" @@ -11498,7 +11532,7 @@ eslint-plugin-react@^7.16.0: semver "^6.3.0" string.prototype.matchall "^4.0.6" -eslint-scope@5.1.1, eslint-scope@^5.1.1: +eslint-scope@5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== @@ -11526,7 +11560,7 @@ eslint-visitor-keys@^2.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.2.0, eslint-visitor-keys@^3.4.1: +eslint-visitor-keys@^3.2.0, eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1: version "3.4.3" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== @@ -11836,6 +11870,17 @@ fast-glob@^3.1.1, fast-glob@^3.2.11, fast-glob@^3.2.12, fast-glob@^3.2.4: merge2 "^1.3.0" micromatch "^4.0.4" +fast-glob@^3.2.9: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + fast-json-patch@^3.0.0-1: version "3.1.1" resolved "https://registry.yarnpkg.com/fast-json-patch/-/fast-json-patch-3.1.1.tgz#85064ea1b1ebf97a3f7ad01e23f9337e72c66947" @@ -12619,7 +12664,7 @@ globals@^13.6.0, globals@^13.9.0: dependencies: type-fest "^0.20.2" -globby@^11.0.1, globby@^11.0.2, globby@^11.0.3, globby@^11.0.4: +globby@^11.0.1, globby@^11.0.2, globby@^11.0.3: version "11.0.4" resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== @@ -12631,6 +12676,18 @@ globby@^11.0.1, globby@^11.0.2, globby@^11.0.3, globby@^11.0.4: merge2 "^1.3.0" slash "^3.0.0" +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + globby@^13.1.1: version "13.1.3" resolved "https://registry.yarnpkg.com/globby/-/globby-13.1.3.tgz#f62baf5720bcb2c1330c8d4ef222ee12318563ff" @@ -12726,6 +12783,11 @@ grapheme-splitter@^1.0.4: resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + graphiql@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/graphiql/-/graphiql-3.0.0.tgz#9ea10cb552759ae69a14c72bf219e9f425a607d7" @@ -13269,11 +13331,16 @@ ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -ignore@^5.0.4, ignore@^5.1.4, ignore@^5.1.8, ignore@^5.2.0: +ignore@^5.0.4, ignore@^5.1.4, ignore@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== +ignore@^5.2.4: + version "5.3.1" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" + integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== + image-size@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/image-size/-/image-size-1.0.0.tgz#58b31fe4743b1cec0a0ac26f5c914d3c5b2f0750" @@ -15637,6 +15704,13 @@ minimatch@3.0.5: dependencies: brace-expansion "^1.1.7" +minimatch@9.0.3: + version "9.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== + dependencies: + brace-expansion "^2.0.1" + minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.0.5: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -20457,6 +20531,11 @@ ts-algebra@^1.2.0: resolved "https://registry.yarnpkg.com/ts-algebra/-/ts-algebra-1.2.0.tgz#f91c481207a770f0d14d055c376cbee040afdfc9" integrity sha512-kMuJJd8B2N/swCvIvn1hIFcIOrLGbWl9m/J6O3kHx9VRaevh00nvgjPiEGaRee7DRaAczMYR2uwWvXU22VFltw== +ts-api-utils@^1.0.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.2.1.tgz#f716c7e027494629485b21c0df6180f4d08f5e8b" + integrity sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA== + ts-app-env@^1.4.2: version "1.4.2" resolved "https://registry.yarnpkg.com/ts-app-env/-/ts-app-env-1.4.2.tgz#2a76d19d61b66c6bc92ff90e3a0e6db6c545a776" @@ -20574,7 +20653,7 @@ tslib@1.9.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== -tslib@^1.10.0, tslib@^1.11.1, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: +tslib@^1.10.0, tslib@^1.11.1, tslib@^1.9.0, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== @@ -20599,13 +20678,6 @@ tslib@~2.5.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== -tsutils@^3.21.0: - version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" - tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" @@ -20729,10 +20801,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@4.9.5, "typescript@^3 || ^4", typescript@^4.2.4, typescript@^4.5.5: - version "4.9.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" - integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== +typescript@4.9.5, "typescript@^3 || ^4", typescript@^4.2.4, typescript@^5.3.3: + version "5.3.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37" + integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw== uWebSockets.js@uNetworking/uWebSockets.js#v20.34.0: version "20.34.0" @@ -20778,6 +20850,11 @@ undici-types@~5.25.1: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.25.3.tgz#e044115914c85f0bcbb229f346ab739f064998c3" integrity sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA== +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + undici@^5.26.2: version "5.26.3" resolved "https://registry.yarnpkg.com/undici/-/undici-5.26.3.tgz#ab3527b3d5bb25b12f898dfd22165d472dd71b79" From 92f0be917d4bd182bc6ea249f5dc40c05b98320a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 28 Feb 2024 12:57:26 -0800 Subject: [PATCH 26/39] chore(deps): bump es5-ext from 0.10.62 to 0.10.64 (#9457) Bumps [es5-ext](https://github.com/medikoo/es5-ext) from 0.10.62 to 0.10.64. - [Release notes](https://github.com/medikoo/es5-ext/releases) - [Changelog](https://github.com/medikoo/es5-ext/blob/main/CHANGELOG.md) - [Commits](https://github.com/medikoo/es5-ext/compare/v0.10.62...v0.10.64) --- updated-dependencies: - dependency-name: es5-ext dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/yarn.lock b/yarn.lock index 5054b6dcddb..5b2a827fe6d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11408,13 +11408,14 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" -es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@^0.10.53, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46: - version "0.10.62" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.62.tgz#5e6adc19a6da524bf3d1e02bbc8960e5eb49a9a5" - integrity sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA== +es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@^0.10.53, es5-ext@^0.10.62, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46: + version "0.10.64" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.64.tgz#12e4ffb48f1ba2ea777f1fcdd1918ef73ea21714" + integrity sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg== dependencies: es6-iterator "^2.0.3" es6-symbol "^3.1.3" + esniff "^2.0.1" next-tick "^1.1.0" es6-iterator@^2.0.3: @@ -11606,6 +11607,16 @@ eslint@^8.2.0, eslint@^8.8.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" +esniff@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/esniff/-/esniff-2.0.1.tgz#a4d4b43a5c71c7ec51c51098c1d8a29081f9b308" + integrity sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg== + dependencies: + d "^1.0.1" + es5-ext "^0.10.62" + event-emitter "^0.3.5" + type "^2.7.2" + espree@^9.0.0, espree@^9.2.0, espree@^9.3.0: version "9.6.1" resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" From 1e0075e843ce3cf52966a0b77293d72f1d9c60b9 Mon Sep 17 00:00:00 2001 From: adaniels-parabol <71724289+adaniels-parabol@users.noreply.github.com> Date: Wed, 28 Feb 2024 14:58:35 -0600 Subject: [PATCH 27/39] fix: packages/server/package.json to reduce vulnerabilities (#9434) The following vulnerabilities are fixed with an upgrade: - https://snyk.io/vuln/SNYK-JS-UNDICI-6252336 Co-authored-by: snyk-bot --- packages/server/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/package.json b/packages/server/package.json index 79b79743566..0da2cdd6a75 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -137,6 +137,6 @@ "stripe": "^9.13.0", "tslib": "^2.4.0", "uWebSockets.js": "uNetworking/uWebSockets.js#v20.34.0", - "undici": "^5.26.2" + "undici": "^5.28.3" } } From fd833f541ef7f915b40331c9d12e94243c8fa24f Mon Sep 17 00:00:00 2001 From: adaniels-parabol <71724289+adaniels-parabol@users.noreply.github.com> Date: Wed, 28 Feb 2024 14:59:29 -0600 Subject: [PATCH 28/39] fix: packages/server/package.json to reduce vulnerabilities (#9392) The following vulnerabilities are fixed with an upgrade: - https://snyk.io/vuln/SNYK-JS-NODEMAILER-6219989 Co-authored-by: snyk-bot From fd75d3f2a907888bb461d55ac945d9449071a414 Mon Sep 17 00:00:00 2001 From: adaniels-parabol <71724289+adaniels-parabol@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:01:26 -0600 Subject: [PATCH 29/39] fix: packages/server/package.json to reduce vulnerabilities (#9298) The following vulnerabilities are fixed with an upgrade: - https://snyk.io/vuln/SNYK-JS-FOLLOWREDIRECTS-6141137 Co-authored-by: snyk-bot --- packages/server/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/package.json b/packages/server/package.json index 0da2cdd6a75..29150a626a0 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -87,7 +87,7 @@ "@sentry/integrations": "^7.74.1", "@sentry/node": "^7.74.1", "adaptivecards": "^2.10.0", - "analytics-node": "^5.0.0", + "analytics-node": "^6.0.0", "api": "^5.0.7", "base64url": "^3.0.1", "bcryptjs": "^2.4.3", From 9441b2727deefb7e27e4015f37d64ff933415c8d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 28 Feb 2024 13:01:41 -0800 Subject: [PATCH 30/39] chore(deps): bump follow-redirects from 1.14.8 to 1.15.4 (#9312) Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.8 to 1.15.4. - [Release notes](https://github.com/follow-redirects/follow-redirects/releases) - [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.8...v1.15.4) --- updated-dependencies: - dependency-name: follow-redirects dependency-type: indirect ... Signed-off-by: dependabot[bot] Signed-off-by: Matt Krick Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Matt Krick --- yarn.lock | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/yarn.lock b/yarn.lock index 5b2a827fe6d..b240f3b0964 100644 --- a/yarn.lock +++ b/yarn.lock @@ -20873,6 +20873,13 @@ undici@^5.26.2: dependencies: "@fastify/busboy" "^2.0.0" +undici@^5.28.3: + version "5.28.3" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.3.tgz#a731e0eff2c3fcfd41c1169a869062be222d1e5b" + integrity sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA== + dependencies: + "@fastify/busboy" "^2.0.0" + unicode-canonical-property-names-ecmascript@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" From 7bfec9188a42b38eb69930fdd86e6fb39249ed7e Mon Sep 17 00:00:00 2001 From: Dale Bumblis <135627447+dbumblis-parabol@users.noreply.github.com> Date: Wed, 28 Feb 2024 14:30:17 -0800 Subject: [PATCH 31/39] chore: add upload to GCS step in ironbank (#9471) * add upload to GCS step in ironbank * update workflow name --- .github/workflows/ironbank.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ironbank.yml b/.github/workflows/ironbank.yml index b6a15acd539..e9782493f43 100644 --- a/.github/workflows/ironbank.yml +++ b/.github/workflows/ironbank.yml @@ -1,4 +1,4 @@ -name: Ironbank S3 Upload +name: Ironbank Image Upload on: workflow_dispatch: @@ -64,3 +64,11 @@ jobs: - name: Upload to S3 run: | aws s3 cp ${{ github.event.inputs.version_number }}.zip s3://ironbank-proving-ground-action-files.parabol.co/${{ github.event.inputs.version_number }}.zip + + - name: Upload to GCS + uses: actions-hub/gcloud@master + env: + CLOUDSDK_AUTH_ACCESS_TOKEN: "${{ steps.auth.outputs.access_token }}" + with: + args: storage cp ${{ github.event.inputs.version_number }}.zip gs://ironbank-proving-ground/${{ github.event.inputs.version_number }}.zip + cli: gcloud From c1da6baf2d3dbead396561b6da41d43c46cbe3c0 Mon Sep 17 00:00:00 2001 From: "parabol-release-bot[bot]" <150284312+parabol-release-bot[bot]@users.noreply.github.com> Date: Thu, 29 Feb 2024 09:36:22 +0100 Subject: [PATCH 32/39] chore(release): release v7.19.4 (#9470) Co-authored-by: parabol-release-bot[bot] <150284312+parabol-release-bot[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- CHANGELOG.md | 19 +++++++++++++++++++ package.json | 2 +- packages/chronos/package.json | 4 ++-- packages/client/package.json | 2 +- packages/gql-executor/package.json | 6 +++--- packages/integration-tests/package.json | 2 +- packages/server/package.json | 4 ++-- 8 files changed, 30 insertions(+), 11 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 517aeb7a63e..909f7972a63 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "7.19.3" + ".": "7.19.4" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 579182dc3f5..56ea22e2f03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,25 @@ This project adheres to [Semantic Versioning](http://semver.org/). This CHANGELOG follows conventions [outlined here](http://keepachangelog.com/). +## [7.19.4](https://github.com/ParabolInc/parabol/compare/v7.19.3...v7.19.4) (2024-02-28) + + +### Fixed + +* Fetch Jira projects in parallel ([#9456](https://github.com/ParabolInc/parabol/issues/9456)) ([9cec00a](https://github.com/ParabolInc/parabol/commit/9cec00a5fd0b46c73ebdde27e6d966b485216132)) +* limit invites from spammers ([#9416](https://github.com/ParabolInc/parabol/issues/9416)) ([5b9526c](https://github.com/ParabolInc/parabol/commit/5b9526c092f7f8675ad2a442da4440e2507cbdcc)) +* packages/server/package.json to reduce vulnerabilities ([#9298](https://github.com/ParabolInc/parabol/issues/9298)) ([fd75d3f](https://github.com/ParabolInc/parabol/commit/fd75d3f2a907888bb461d55ac945d9449071a414)) +* packages/server/package.json to reduce vulnerabilities ([#9392](https://github.com/ParabolInc/parabol/issues/9392)) ([fd833f5](https://github.com/ParabolInc/parabol/commit/fd833f541ef7f915b40331c9d12e94243c8fa24f)) +* packages/server/package.json to reduce vulnerabilities ([#9434](https://github.com/ParabolInc/parabol/issues/9434)) ([1e0075e](https://github.com/ParabolInc/parabol/commit/1e0075e843ce3cf52966a0b77293d72f1d9c60b9)) +* replace lone surrogates in draft-js content ([#9415](https://github.com/ParabolInc/parabol/issues/9415)) ([00092ec](https://github.com/ParabolInc/parabol/commit/00092ec55659d1441e9566d501940dcc6fcf07f4)) + + +### Changed + +* add upload to GCS step in ironbank ([#9471](https://github.com/ParabolInc/parabol/issues/9471)) ([7bfec91](https://github.com/ParabolInc/parabol/commit/7bfec9188a42b38eb69930fdd86e6fb39249ed7e)) +* **deps:** bump es5-ext from 0.10.62 to 0.10.64 ([#9457](https://github.com/ParabolInc/parabol/issues/9457)) ([92f0be9](https://github.com/ParabolInc/parabol/commit/92f0be917d4bd182bc6ea249f5dc40c05b98320a)) +* **deps:** bump follow-redirects from 1.14.8 to 1.15.4 ([#9312](https://github.com/ParabolInc/parabol/issues/9312)) ([9441b27](https://github.com/ParabolInc/parabol/commit/9441b2727deefb7e27e4015f37d64ff933415c8d)) + ## [7.19.3](https://github.com/ParabolInc/parabol/compare/v7.19.2...v7.19.3) (2024-02-28) diff --git a/package.json b/package.json index 5b7253fec2e..2603f250ca4 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.3", + "version": "7.19.4", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" diff --git a/packages/chronos/package.json b/packages/chronos/package.json index 39bec48dcf6..c53c697fef2 100644 --- a/packages/chronos/package.json +++ b/packages/chronos/package.json @@ -1,6 +1,6 @@ { "name": "chronos", - "version": "7.19.3", + "version": "7.19.4", "description": "A cron job scheduler", "author": "Matt Krick ", "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/chronos#readme", @@ -25,6 +25,6 @@ }, "dependencies": { "cron": "^2.3.1", - "parabol-server": "7.19.3" + "parabol-server": "7.19.4" } } diff --git a/packages/client/package.json b/packages/client/package.json index 19a38863130..2d0ec1344e3 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.3", + "version": "7.19.4", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" diff --git a/packages/gql-executor/package.json b/packages/gql-executor/package.json index 10852a68c4a..bfb366858cf 100644 --- a/packages/gql-executor/package.json +++ b/packages/gql-executor/package.json @@ -1,6 +1,6 @@ { "name": "gql-executor", - "version": "7.19.3", + "version": "7.19.4", "description": "A Stateless GraphQL Executor", "author": "Matt Krick ", "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/gqlExecutor#readme", @@ -27,8 +27,8 @@ }, "dependencies": { "dd-trace": "^4.2.0", - "parabol-client": "7.19.3", - "parabol-server": "7.19.3", + "parabol-client": "7.19.4", + "parabol-server": "7.19.4", "undici": "^5.26.2" } } diff --git a/packages/integration-tests/package.json b/packages/integration-tests/package.json index a70463e1320..7c7c4ffe520 100644 --- a/packages/integration-tests/package.json +++ b/packages/integration-tests/package.json @@ -2,7 +2,7 @@ "name": "integration-tests", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.3", + "version": "7.19.4", "description": "", "main": "index.js", "scripts": { diff --git a/packages/server/package.json b/packages/server/package.json index 29150a626a0..1699bdf5d11 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.3", + "version": "7.19.4", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" @@ -124,7 +124,7 @@ "oauth-1.0a": "^2.2.6", "openai": "^4.24.1", "oy-vey": "^0.11.0", - "parabol-client": "7.19.3", + "parabol-client": "7.19.4", "pg": "^8.5.1", "react": "^17.0.2", "react-dom": "^17.0.2", From 419d104757d905c468d6a72ce607430d01f3b97f Mon Sep 17 00:00:00 2001 From: Georg Bremer Date: Thu, 29 Feb 2024 11:20:04 +0100 Subject: [PATCH 33/39] fix: Fix seasonal templates for leap years (#9476) * fix: Fix seasonal templates for leap years It would produce invalid dates on February 29th. * Master was not clean --- .../server/dataloader/customLoaderMakers.ts | 4 +-- yarn.lock | 25 ++++++++++++++----- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/packages/server/dataloader/customLoaderMakers.ts b/packages/server/dataloader/customLoaderMakers.ts index 8bd64c6250b..ac7e1ea6ec7 100644 --- a/packages/server/dataloader/customLoaderMakers.ts +++ b/packages/server/dataloader/customLoaderMakers.ts @@ -481,8 +481,8 @@ export const meetingTemplatesByOrgId = (parent: RootDataLoader) => { .where(({or, eb}) => or([ eb('hideStartingAt', 'is', null), - sql`make_date(2020 , extract(month from current_date)::integer, extract(day from current_date)::integer) between "hideEndingAt" and "hideStartingAt"`, - sql`make_date(2019 , extract(month from current_date)::integer, extract(day from current_date)::integer) between "hideEndingAt" and "hideStartingAt"` + sql`DATE '2020-01-01' + EXTRACT(DOY FROM CURRENT_DATE)::INTEGER - 1 between "hideEndingAt" and "hideStartingAt"`, + sql`DATE '2019-01-01' + EXTRACT(DOY FROM CURRENT_DATE)::INTEGER - 1 between "hideEndingAt" and "hideStartingAt"` ]) ) .orderBy('createdAt', 'desc') diff --git a/yarn.lock b/yarn.lock index b240f3b0964..17637e0e348 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8577,13 +8577,13 @@ amp@0.3.1, amp@~0.3.1: resolved "https://registry.yarnpkg.com/amp/-/amp-0.3.1.tgz#6adf8d58a74f361e82c1fa8d389c079e139fc47d" integrity sha1-at+NWKdPNh6CwfqNOJwHnhOfxH0= -analytics-node@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/analytics-node/-/analytics-node-5.2.0.tgz#ef167bbf0d51f630e96d3abe604ce449b50a2584" - integrity sha512-JAc0K7J//QKGGX2mfwBE7wyG/Rh4W0BATB6CncwYhVX1qLjiXwHmB7bYr9PgJIer5M6jKMOhZoO5lxiruQk9BQ== +analytics-node@^6.0.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/analytics-node/-/analytics-node-6.2.0.tgz#8ae2ebc73d85e5b2aac8d366b974ad36996f629d" + integrity sha512-NLU4tCHlWt0tzEaFQL7NIoWhq2KmQSmz0JvyS2lYn6fc4fEjTMSabhJUx8H1r5995FX8fE3rZ15uIHU6u+ovlQ== dependencies: "@segment/loosely-validate-event" "^2.0.0" - axios "^0.21.4" + axios "^0.27.2" axios-retry "3.2.0" lodash.isstring "^4.0.1" md5 "^2.2.1" @@ -8939,13 +8939,21 @@ axios-retry@3.2.0: dependencies: is-retry-allowed "^1.1.0" -axios@0.21.4, axios@^0.21.0, axios@^0.21.4: +axios@0.21.4, axios@^0.21.0: version "0.21.4" resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== dependencies: follow-redirects "^1.14.0" +axios@^0.27.2: + version "0.27.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972" + integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== + dependencies: + follow-redirects "^1.14.9" + form-data "^4.0.0" + axios@^1.0.0: version "1.3.2" resolved "https://registry.yarnpkg.com/axios/-/axios-1.3.2.tgz#7ac517f0fa3ec46e0e636223fd973713a09c72b3" @@ -12154,6 +12162,11 @@ follow-redirects@^1.0.0, follow-redirects@^1.14.0, follow-redirects@^1.15.0: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== +follow-redirects@^1.14.9: + version "1.15.5" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.5.tgz#54d4d6d062c0fa7d9d17feb008461550e3ba8020" + integrity sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw== + foreground-child@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" From ba67da80878dab73a32ba187c418cc6ac3f2dfef Mon Sep 17 00:00:00 2001 From: "parabol-release-bot[bot]" <150284312+parabol-release-bot[bot]@users.noreply.github.com> Date: Thu, 29 Feb 2024 11:20:39 +0100 Subject: [PATCH 34/39] chore(release): release v7.19.5 (#9477) Co-authored-by: parabol-release-bot[bot] <150284312+parabol-release-bot[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- CHANGELOG.md | 7 +++++++ package.json | 2 +- packages/chronos/package.json | 4 ++-- packages/client/package.json | 2 +- packages/gql-executor/package.json | 6 +++--- packages/integration-tests/package.json | 2 +- packages/server/package.json | 4 ++-- 8 files changed, 18 insertions(+), 11 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 909f7972a63..6e9dcf42d00 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "7.19.4" + ".": "7.19.5" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 56ea22e2f03..080f2ea136c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ This project adheres to [Semantic Versioning](http://semver.org/). This CHANGELOG follows conventions [outlined here](http://keepachangelog.com/). +## [7.19.5](https://github.com/ParabolInc/parabol/compare/v7.19.4...v7.19.5) (2024-02-29) + + +### Fixed + +* Fix seasonal templates for leap years ([#9476](https://github.com/ParabolInc/parabol/issues/9476)) ([419d104](https://github.com/ParabolInc/parabol/commit/419d104757d905c468d6a72ce607430d01f3b97f)) + ## [7.19.4](https://github.com/ParabolInc/parabol/compare/v7.19.3...v7.19.4) (2024-02-28) diff --git a/package.json b/package.json index 2603f250ca4..ee9f994f9d9 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.4", + "version": "7.19.5", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" diff --git a/packages/chronos/package.json b/packages/chronos/package.json index c53c697fef2..f9c5675491e 100644 --- a/packages/chronos/package.json +++ b/packages/chronos/package.json @@ -1,6 +1,6 @@ { "name": "chronos", - "version": "7.19.4", + "version": "7.19.5", "description": "A cron job scheduler", "author": "Matt Krick ", "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/chronos#readme", @@ -25,6 +25,6 @@ }, "dependencies": { "cron": "^2.3.1", - "parabol-server": "7.19.4" + "parabol-server": "7.19.5" } } diff --git a/packages/client/package.json b/packages/client/package.json index 2d0ec1344e3..b5e0427873c 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.4", + "version": "7.19.5", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" diff --git a/packages/gql-executor/package.json b/packages/gql-executor/package.json index bfb366858cf..0e97990948c 100644 --- a/packages/gql-executor/package.json +++ b/packages/gql-executor/package.json @@ -1,6 +1,6 @@ { "name": "gql-executor", - "version": "7.19.4", + "version": "7.19.5", "description": "A Stateless GraphQL Executor", "author": "Matt Krick ", "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/gqlExecutor#readme", @@ -27,8 +27,8 @@ }, "dependencies": { "dd-trace": "^4.2.0", - "parabol-client": "7.19.4", - "parabol-server": "7.19.4", + "parabol-client": "7.19.5", + "parabol-server": "7.19.5", "undici": "^5.26.2" } } diff --git a/packages/integration-tests/package.json b/packages/integration-tests/package.json index 7c7c4ffe520..1b7a9030731 100644 --- a/packages/integration-tests/package.json +++ b/packages/integration-tests/package.json @@ -2,7 +2,7 @@ "name": "integration-tests", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.4", + "version": "7.19.5", "description": "", "main": "index.js", "scripts": { diff --git a/packages/server/package.json b/packages/server/package.json index 1699bdf5d11..5dc86873eb0 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.4", + "version": "7.19.5", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" @@ -124,7 +124,7 @@ "oauth-1.0a": "^2.2.6", "openai": "^4.24.1", "oy-vey": "^0.11.0", - "parabol-client": "7.19.4", + "parabol-client": "7.19.5", "pg": "^8.5.1", "react": "^17.0.2", "react-dom": "^17.0.2", From 052acd14035fe7c96af8d17ca4763be91d863a80 Mon Sep 17 00:00:00 2001 From: Georg Bremer Date: Thu, 29 Feb 2024 13:56:44 +0100 Subject: [PATCH 35/39] fix: After parameter for meetingCount was ignored (#9479) --- packages/server/graphql/public/types/Company.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/graphql/public/types/Company.ts b/packages/server/graphql/public/types/Company.ts index 2e01f3b8beb..351d4fb7981 100644 --- a/packages/server/graphql/public/types/Company.ts +++ b/packages/server/graphql/public/types/Company.ts @@ -139,7 +139,7 @@ const Company: CompanyResolvers = { const teams = await getTeamsByOrgIds(orgIds, dataLoader, true) const teamIds = teams.map(({id}) => id) if (teamIds.length === 0) return 0 - const filterFn = after ? () => true : (meeting: any) => meeting('createdAt').ge(after) + const filterFn = after ? (meeting: any) => meeting('createdAt').ge(after) : () => true return r .table('NewMeeting') .getAll(r.args(teamIds), {index: 'teamId'}) From 5e356c2566db8e32e45a1393e1b1ea27c4be0a5c Mon Sep 17 00:00:00 2001 From: Rafa <101704572+rafaelromcar-parabol@users.noreply.github.com> Date: Thu, 29 Feb 2024 16:02:45 +0000 Subject: [PATCH 36/39] chore(docker-build): simplify the docker build process and reduce docker image size (#9447) * Dockerfile basic created. Improvements added to reduce build time and size (down from 795MB to 445MB, depending on systemtap). Readme reduced, removing the old process used to build the image. * basic-env file using a RethinkDB database name that is clearly dedicated to the building proces. * Readme improved to run all three components * Unused dockerfiles removed. Docker entrypoint renamed. Docker Readme adapted * Legacy build kept in both dockerfile and env file. Readme adapted to use the new basic image. Build GH workflow adapted to use the new basic.dockerfile. --- .github/workflows/build.yml | 3 +- docker/parabol-ubi/docker-build/README.md | 82 ++++-------- .../docker-build/dockerfiles/basic.dockerfile | 26 ++++ .../dockerfiles/parabol.dockerfile | 5 +- .../dockerfiles/pipeline.dockerfile | 117 ------------------ .../dockerfiles/security-test.dockerfile | 60 --------- .../{buildenv => docker-entrypoint.sh} | 0 .../docker-build/environments/basic-env | 17 +++ .../environments/{buildenv => legacy-build} | 0 .../docker-build/environments/local-buildenv | 54 -------- 10 files changed, 69 insertions(+), 295 deletions(-) create mode 100644 docker/parabol-ubi/docker-build/dockerfiles/basic.dockerfile delete mode 100644 docker/parabol-ubi/docker-build/dockerfiles/pipeline.dockerfile delete mode 100644 docker/parabol-ubi/docker-build/dockerfiles/security-test.dockerfile rename docker/parabol-ubi/docker-build/entrypoints/{buildenv => docker-entrypoint.sh} (100%) create mode 100644 docker/parabol-ubi/docker-build/environments/basic-env rename docker/parabol-ubi/docker-build/environments/{buildenv => legacy-build} (100%) delete mode 100644 docker/parabol-ubi/docker-build/environments/local-buildenv diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8b7cf97ce90..9e2e74b3df6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,7 +11,7 @@ concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number }} cancel-in-progress: true env: - PARABOL_DOCKERFILE: ./docker/parabol-ubi/docker-build/dockerfiles/pipeline.dockerfile + PARABOL_DOCKERFILE: ./docker/parabol-ubi/docker-build/dockerfiles/basic.dockerfile PARABOL_BUILD_ENV_PATH: docker/parabol-ubi/docker-build/environments/pipeline jobs: build: @@ -114,7 +114,6 @@ jobs: context: . build-args: | "_NODE_VERSION=${{ env.NODE_VERSION }}" - "_SECURITY_ENABLED=true" push: true tags: | "${{ secrets.GCP_AR_PARABOL_DEV }}:${{github.sha}}" diff --git a/docker/parabol-ubi/docker-build/README.md b/docker/parabol-ubi/docker-build/README.md index 57233e4dbcb..85c1a2d42b3 100644 --- a/docker/parabol-ubi/docker-build/README.md +++ b/docker/parabol-ubi/docker-build/README.md @@ -1,17 +1,8 @@ # docker-image-parabol -This repo was created to build a **secure** Parabol base image that is **agnostic to configuration and can be used anywhere**. Once an image is built, it can be pushed to any repository. +This repo was created to build a Parabol base image that is **agnostic to configuration and can be used anywhere**. Once an image is built, it can be pushed to any repository. -There are two possible ways to build the application: - -- **Standard build:** duild using local files, using the same Dockerfile and process used in our Docker Build pipeline. -- **Build from git:** build using a simplified process that downloads the source code and builds from scratch. - -The processes are different and the details of it can be checked in both dockerfiles. - -## Standard build - -### Requirements +## Requirements Required: @@ -21,37 +12,35 @@ Required: Recommended: -- jq installed. +- [jq](https://jqlang.github.io/jq/) installed. It is used to get the version of the application. -### Variables +## Variables | Name | Description | Possible values | Recommended value | | -------------------- | ----------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- | ------------------------------------------------------------------- | | `postgresql_tag` | PostgreSQL version from the [Docker image](https://hub.docker.com/_/postgres) | `Any tag` | `15.4` | | `rethinkdb_tag` | RethinkDB version from the [Docker image](https://hub.docker.com/_/rethinkdb) | `Any tag` | `2.4.2` | | `redis_tag` | Redis version from the [Docker image](https://hub.docker.com/_/redis) | `Any tag` | `7.0-alpine` | -| `_BUILD_ENV_PATH` | File `.env` used by the application during the build process | `Relative path from the root level of the repository` | `docker/parabol-ubi/docker-build/environments/pipeline` | +| `_BUILD_ENV_PATH` | File `.env` used by the application during the build process | `Relative path from the root level of the repository` | `docker/parabol-ubi/docker-build/environments/basic-env` | | `_NODE_VERSION` | Node version, used by Docker to use the Docker image node:\_NODE_VERSION as base image to build | `Same as in root package.json` | | -| `_DOCKERFILE` | Dockerfile used to build the image | `Relative path from the root level of the repository` | `./docker/parabol-ubi/docker-build/dockerfiles/pipeline.dockerfile` | -| `_SECURITY_ENABLED` | Enable or disable security configurations. It will add some MBs to the final image, but it will produce a secured image | `true/false` | `true` | +| `_DOCKERFILE` | Dockerfile used to build the image | `Relative path from the root level of the repository` | `./docker/parabol-ubi/docker-build/dockerfiles/basic.dockerfile` | | `_DOCKER_REPOSITORY` | The destination repository | `String` | `parabol` | | `_DOCKER_TAG` | Tag for the produced image | `String` | | Example of variables: ```commandLine -export postgresql_tag=15.4-alpine; \ +export postgresql_tag=15.4; \ export rethinkdb_tag=2.4.2; \ export redis_tag=7.0-alpine; \ -export _BUILD_ENV_PATH=docker/parabol-ubi/docker-build/environments/pipeline; \ +export _BUILD_ENV_PATH=docker/parabol-ubi/docker-build/environments/basic-env; \ export _NODE_VERSION=$(jq -r -j '.engines.node|ltrimstr("^")' package.json); \ -export _DOCKERFILE=./docker/parabol-ubi/docker-build/dockerfiles/pipeline.dockerfile; \ -export _SECURITY_ENABLED=true; \ +export _DOCKERFILE=./docker/parabol-ubi/docker-build/dockerfiles/basic.dockerfile; \ export _DOCKER_REPOSITORY=parabol; \ export _DOCKER_TAG=test-image ``` -### Building the image +## Building the image The application must be already built locally using the command `yarn build --no-deps` mode. @@ -90,7 +79,7 @@ yarn build --no-deps - **Build the docker image:** ```commandLine -docker build -t $_DOCKER_REPOSITORY:$_DOCKER_TAG -f $_DOCKERFILE --build-arg _NODE_VERSION=$_NODE_VERSION --build-arg _SECURITY_ENABLED=$_SECURITY_ENABLED . +docker build -t $_DOCKER_REPOSITORY:$_DOCKER_TAG -f $_DOCKERFILE --build-arg _NODE_VERSION=$_NODE_VERSION . ``` > Some build tips @@ -119,57 +108,30 @@ It will produce a Docker image tagged as `${_DOCKER_REPOSITORY}:${_DOCKER_TAG}`. docker images $_DOCKER_REPOSITORY:$_DOCKER_TAG ``` -## Build from git - -This version of the Dockerfile downloads the application during the docker build process and differs in other +## Run the application using a docker image -Modify the version export below e.g. update vX.X.X and run the export command and the docker command. The command below will create a temp postgres container (this allows pgtype files to be generated) and then build the docker image with a temp .env file. +_Assumes redis, rethinkdb, and postgres already running to have operational stack._ -- Change `environments/buildenv` connection string names form container names to localhost for local image build. -- Use `_PARABOL_GIT_REF` to select the reference in Parabol's Git repository. It can be any tag or branch, but it is recommended to use released tags as `v6.69.0`. By default it buils a local image using only `parabol` as repository. -- Use `_DOCKER_REPOSITORY` to build the image for a remote repository (ex: `gcr.io/parabol-proving-ground/parabol`) -- Use `_DOCKER_TAG` to define the tag for the new image. +The commands below will start a Parabol container on the target tag specified in \_DOCKER_TAG export. It will volume mount a .env in your current working directory to the container, so you can pass in any .env in your current working directory. -```commandLine -export postgresql_tag=15.4-alpine; \ -export rethinkdb_tag=2.4.2; \ -export redis_tag=7.0-alpine; \ -export _BUILD_ENV_PATH=environments/local-buildenv \ -export _NODE_VERSION=20.11.0 \ -export _DOCKER_REPOSITORY=parabol \ -export _PARABOL_GIT_REF=vX.X.X \ -export _DOCKER_TAG=vX.X.X -``` +For a more detailed how-to deploy Parabol, please go to the section [docker-host-st](https://github.com/ParabolInc/parabol/tree/master/docker/parabol-ubi/docker-host-st) -Now you can build the image +- Run the PreDeploy script ```commandLine -docker run --name temp-postgres --network=host -e POSTGRES_PASSWORD=temppassword -e POSTGRES_USER=tempuser -e POSTGRES_DB=tempdb -d -p 5432:5432 postgres:${postgresql_tag} && \ -docker run --name temp-rethinkdb --network=host -d -p 28015:28015 -p 29015:29015 -p 8080:8080 rethinkdb:${rethinkdb_tag} && \ -docker run --name temp-redis --network=host -d -p 6379:6379 redis:${redis_tag} && \ -docker build --no-cache --network=host -t ${_DOCKER_REPOSITORY}:${_DOCKER_TAG} -f ./dockerfiles/parabol.dockerfile --build-arg _PARABOL_GIT_REF=${_PARABOL_GIT_REF} --build-arg _NODE_VERSION=$_NODE_VERSION --build-arg _BUILD_ENV_PATH=${_BUILD_ENV_PATH} . && \ -docker stop temp-postgres temp-rethinkdb temp-redis && docker rm temp-postgres temp-rethinkdb temp-redis -f || docker stop temp-postgres temp-rethinkdb temp-redis && docker rm temp-postgres temp-rethinkdb temp-redis -f -``` - -If `_DOCKER_REPOSITORY` wasn't local and you want to push the image, you can run then: +export _DOCKER_REPOSITORY=parabol; \ +export _DOCKER_TAG=vX.X.X -```commandLine -docker push ${_DOCKER_REPOSITORY}:${_DOCKER_TAG} +docker run --name=parabol-predeploy --network=host -v $(pwd)/.env:/home/node/parabol/.env ${_DOCKER_REPOSITORY}:${_DOCKER_TAG} /bin/bash -c "node dist/preDeploy.js" ``` -## Run the application using a docker image - -_Assumes redis, rethinkdb, and postgres already running to have operational stack._ - -The commands below will start a Parabol container on the target tag specified in \_DOCKER_TAG export. It will volume mount a .env in your current working directory to the container, so you can pass in any .env in your current working directory. - - Start GraphQL ```commandLine export _DOCKER_REPOSITORY=parabol; \ export _DOCKER_TAG=vX.X.X -docker run --name=parabolgraphql --network=host -v $(pwd)/.env:/home/node/parabol/.env ${_DOCKER_REPOSITORY}:${_DOCKER_TAG} /bin/bash -c "yarn predeploy && NODE_ENV=production && node ./dist/gqlExecutor.js" || docker container rm parabolgraphql -f +docker run --name=parabol-gql-executor --network=host -v $(pwd)/.env:/home/node/parabol/.env ${_DOCKER_REPOSITORY}:${_DOCKER_TAG} /bin/bash -c "node ./dist/gqlExecutor.js" || docker container rm parabol-gql-executor -f ``` - Start Web Server @@ -178,7 +140,7 @@ docker run --name=parabolgraphql --network=host -v $(pwd)/.env:/home/node/parabo export _DOCKER_REPOSITORY=parabol; \ export _DOCKER_TAG=vX.X.X -docker run --name=parabol --network=host -v $(pwd)/.env:/home/node/parabol/.env -p 3000:3000 ${_DOCKER_REPOSITORY}:${_DOCKER_TAG} /bin/bash -c "yarn predeploy && NODE_ENV=production && node ./dist/web.js" || docker container rm parabol -f +docker run --name=parabol-web-server --network=host -v $(pwd)/.env:/home/node/parabol/.env -p 3000:3000 ${_DOCKER_REPOSITORY}:${_DOCKER_TAG} /bin/bash -c "node ./dist/web.js" || docker container rm parabol-web-server -f ``` -To stop the container, just open another terminal and enter `docker container stop parabol` +To stop the container, just open another terminal and enter `docker container stop parabol-COMPONENT` diff --git a/docker/parabol-ubi/docker-build/dockerfiles/basic.dockerfile b/docker/parabol-ubi/docker-build/dockerfiles/basic.dockerfile new file mode 100644 index 00000000000..025862bedfe --- /dev/null +++ b/docker/parabol-ubi/docker-build/dockerfiles/basic.dockerfile @@ -0,0 +1,26 @@ +ARG _NODE_VERSION=${_NODE_VERSION} +FROM node:${_NODE_VERSION}-bookworm-slim as base + +ENV NPM_CONFIG_PREFIX=/home/node/.npm-global +ENV PORT=3000 + +COPY --chown=node --chmod=755 docker/parabol-ubi/docker-build/entrypoints/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh +COPY --chown=node docker/parabol-ubi/docker-build/tools/ip-to-server_id ${HOME}/tools/ip-to-server_id + +# Required for pushToCDN to work with FILE_STORE_PROVIDER set to 'local' +RUN mkdir -p ${HOME}/parabol/self-hosted && \ + chown node:node ${HOME}/parabol/self-hosted + +COPY --chown=node .env.example ${HOME}/parabol/.env.example + +# The application requires a yarn.lock file on the root folder to identify it +COPY --chown=node yarn.lock ${HOME}/parabol/yarn.lock +COPY --chown=node build ${HOME}/parabol/build +COPY --chown=node dist ${HOME}/parabol/dist + +WORKDIR ${HOME}/parabol/ + +USER node +EXPOSE ${PORT} + +ENTRYPOINT ["docker-entrypoint.sh"] diff --git a/docker/parabol-ubi/docker-build/dockerfiles/parabol.dockerfile b/docker/parabol-ubi/docker-build/dockerfiles/parabol.dockerfile index f2f7466af8b..2688d19ee8d 100644 --- a/docker/parabol-ubi/docker-build/dockerfiles/parabol.dockerfile +++ b/docker/parabol-ubi/docker-build/dockerfiles/parabol.dockerfile @@ -1,9 +1,10 @@ +# DO NOT DELETE. Legacy docker file for versions still in use. Delete only when all Parabol instances are using the newest docker image. ARG _NODE_VERSION=${_NODE_VERSION} #base build for dev deps FROM node:${_NODE_VERSION} as base ARG _PARABOL_GIT_REF=${_PARABOL_GIT_REF} -ARG _BUILD_ENV_PATH=environments/buildenv +ARG _BUILD_ENV_PATH=environments/legacy-build ENV NPM_CONFIG_PREFIX=/home/node/.npm-global WORKDIR /home/node @@ -45,7 +46,7 @@ COPY --from=base /usr/local/lib/node_modules /usr/local/lib/node_modules COPY --from=base /opt /opt COPY --from=base /home/node/parabol/ ${HOME}/parabol RUN rm -rf ${HOME}/parabol/.env -COPY entrypoints/buildenv /usr/local/bin/docker-entrypoint.sh +COPY entrypoints/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh COPY security /security COPY ./tools/ip-to-server_id /home/node/tools/ip-to-server_id diff --git a/docker/parabol-ubi/docker-build/dockerfiles/pipeline.dockerfile b/docker/parabol-ubi/docker-build/dockerfiles/pipeline.dockerfile deleted file mode 100644 index 5194efcbe4d..00000000000 --- a/docker/parabol-ubi/docker-build/dockerfiles/pipeline.dockerfile +++ /dev/null @@ -1,117 +0,0 @@ -ARG _NODE_VERSION=${_NODE_VERSION} -FROM node:${_NODE_VERSION} as base - -ENV NPM_CONFIG_PREFIX=/home/node/.npm-global -ENV PORT=3000 - -RUN apt update -y && \ - apt install systemtap -y - -USER node -EXPOSE ${PORT} - -ENTRYPOINT ["docker-entrypoint.sh"] - -# Final image - copies in parabol build and applies all security configurations to container if enabled -FROM redhat/ubi9:9.2 - -ARG _SECURITY_ENABLED="true" - -ENV HOME=/home/node \ - USER=node - -ENV PORT=3000 - -RUN groupadd -g 1000 node && \ - useradd -r -u 1000 -m -s /sbin/nologin -g node node - -COPY --from=base /usr/local/bin /usr/local/bin -COPY --from=base /usr/local/include /usr/local/include -COPY --from=base /usr/local/share/man /usr/local/share/man -COPY --from=base /usr/local/share/doc /usr/local/share/doc -COPY --from=base /usr/share/systemtap /usr/local/share/systemtap -COPY --from=base /usr/local/lib/node_modules /usr/local/lib/node_modules -COPY --from=base /opt /opt - -# Security -COPY docker/parabol-ubi/docker-build/security /security - -RUN if [ "$_SECURITY_ENABLED" = "true" ]; then \ - echo Update packages and install security patches && \ - sed -i "s/enabled=1/enabled=0/" /etc/dnf/plugins/subscription-manager.conf && \ - echo "exclude=filesystem-*" >> /etc/dnf/dnf.conf && \ - chmod +x /security/*.sh && \ - dnf repolist && \ - dnf update -y && \ - echo "* hard maxlogins 10" > /etc/security/limits.d/maxlogins.conf && \ - /security/xccdf_org.ssgproject.content_rule_account_disable_post_pw_expiration.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_logon_fail_delay.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_max_concurrent_login_sessions.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_maximum_age_login_defs.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_minimum_age_login_defs.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_minlen_login_defs.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_pam_dcredit.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_pam_dictcheck.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_pam_difok.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_pam_lcredit.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_pam_maxclassrepeat.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_pam_maxrepeat.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_pam_minclass.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_pam_minlen.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_pam_ocredit.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_password_auth.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_system_auth.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_pam_ucredit.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_pam_unix_remember.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_passwords_pam_faillock_deny.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_passwords_pam_faillock_deny_root.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_passwords_pam_faillock_interval.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_passwords_pam_faillock_unlock_time.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_passwords_pam_faillock.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_umask_etc_bashrc.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_umask_etc_csh_cshrc.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_umask_etc_login_defs.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_umask_etc_profile.sh && \ - /security/xccdf_org.ssgproject.content_rule_banner_etc_issue.sh && \ - /security/xccdf_org.ssgproject.content_rule_configure_kerberos_crypto_policy.sh && \ - /security/xccdf_org.ssgproject.content_rule_configure_openssl_crypto_policy.sh && \ - /security/xccdf_org.ssgproject.content_rule_coredump_disable_backtraces.sh && \ - /security/xccdf_org.ssgproject.content_rule_coredump_disable_storage.sh && \ - /security/xccdf_org.ssgproject.content_rule_disable_ctrlaltdel_burstaction.sh && \ - /security/xccdf_org.ssgproject.content_rule_disable_users_coredumps.sh && \ - /security/xccdf_org.ssgproject.content_rule_display_login_attempts.sh && \ - /security/xccdf_org.ssgproject.content_rule_ensure_gpgcheck_local_packages.sh && \ - /security/xccdf_org.ssgproject.content_rule_file_groupownership_system_commands_dirs.sh && \ - /security/xccdf_org.ssgproject.content_rule_no_empty_passwords.sh && \ - /security/xccdf_org.ssgproject.content_rule_openssl_use_strong_entropy.sh && \ - /security/xccdf_org.ssgproject.content_rule_package_crypto-policies_installed.sh && \ - /security/xccdf_org.ssgproject.content_rule_package_iptables_installed.sh && \ - dnf clean all && \ - rm -rf /var/cache/dnf/ /var/tmp/* /tmp/* /var/tmp/.???* /tmp/.???* && \ - chmod g-s /opt/yarn-v*/bin /opt/yarn-v*/lib && \ - chgrp -R root /opt/yarn-v* && \ - chgrp root /opt/yarn-v*/lib/* /opt/yarn-v*/bin/* /opt/yarn-v*/*; \ - else \ - echo "Security checks disabled."; \ - fi - -RUN rm -rf /security/ - -COPY --chown=node --chmod=755 docker/parabol-ubi/docker-build/entrypoints/buildenv /usr/local/bin/docker-entrypoint.sh -COPY --chown=node docker/parabol-ubi/docker-build/tools/ip-to-server_id ${HOME}/tools/ip-to-server_id - -# The application requires a yarn.lock file on the root folder to identify it -COPY --chown=node yarn.lock ${HOME}/parabol/yarn.lock -# Required for pushToCDN to work with FILE_STORE_PROVIDER set to 'local' -RUN mkdir -p ${HOME}/parabol/self-hosted && \ - chown node:node ${HOME}/parabol/self-hosted - -COPY --chown=node .env.example ${HOME}/parabol/.env.example -COPY --chown=node build ${HOME}/parabol/build -COPY --chown=node dist ${HOME}/parabol/dist - -WORKDIR ${HOME}/parabol/ -USER node -EXPOSE ${PORT} - -ENTRYPOINT ["docker-entrypoint.sh"] diff --git a/docker/parabol-ubi/docker-build/dockerfiles/security-test.dockerfile b/docker/parabol-ubi/docker-build/dockerfiles/security-test.dockerfile deleted file mode 100644 index 246eba76add..00000000000 --- a/docker/parabol-ubi/docker-build/dockerfiles/security-test.dockerfile +++ /dev/null @@ -1,60 +0,0 @@ -#final image -FROM redhat/ubi9:9.2 - -COPY entrypoints/buildenv /usr/local/bin/docker-entrypoint.sh -COPY security /security - -RUN echo Update packages and install security patches && \ - sed -i "s/enabled=1/enabled=0/" /etc/dnf/plugins/subscription-manager.conf && \ - echo "exclude=filesystem-*" >> /etc/dnf/dnf.conf && \ - chmod +x /security/*.sh && \ - dnf repolist && \ - dnf update -y && \ - echo "* hard maxlogins 10" > /etc/security/limits.d/maxlogins.conf && \ - /security/xccdf_org.ssgproject.content_rule_account_disable_post_pw_expiration.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_logon_fail_delay.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_max_concurrent_login_sessions.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_maximum_age_login_defs.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_minimum_age_login_defs.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_minlen_login_defs.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_pam_dcredit.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_pam_dictcheck.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_pam_difok.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_pam_lcredit.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_pam_maxclassrepeat.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_pam_maxrepeat.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_pam_minclass.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_pam_minlen.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_pam_ocredit.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_password_auth.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_system_auth.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_pam_ucredit.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_password_pam_unix_remember.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_passwords_pam_faillock_deny.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_passwords_pam_faillock_deny_root.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_passwords_pam_faillock_interval.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_passwords_pam_faillock_unlock_time.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_passwords_pam_faillock.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_umask_etc_bashrc.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_umask_etc_csh_cshrc.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_umask_etc_login_defs.sh && \ - /security/xccdf_org.ssgproject.content_rule_accounts_umask_etc_profile.sh && \ - /security/xccdf_org.ssgproject.content_rule_banner_etc_issue.sh && \ - /security/xccdf_org.ssgproject.content_rule_configure_kerberos_crypto_policy.sh && \ - /security/xccdf_org.ssgproject.content_rule_configure_openssl_crypto_policy.sh && \ - /security/xccdf_org.ssgproject.content_rule_coredump_disable_backtraces.sh && \ - /security/xccdf_org.ssgproject.content_rule_coredump_disable_storage.sh && \ - /security/xccdf_org.ssgproject.content_rule_disable_ctrlaltdel_burstaction.sh && \ - /security/xccdf_org.ssgproject.content_rule_disable_users_coredumps.sh && \ - /security/xccdf_org.ssgproject.content_rule_display_login_attempts.sh && \ - /security/xccdf_org.ssgproject.content_rule_ensure_gpgcheck_local_packages.sh && \ - /security/xccdf_org.ssgproject.content_rule_file_groupownership_system_commands_dirs.sh && \ - /security/xccdf_org.ssgproject.content_rule_no_empty_passwords.sh && \ - /security/xccdf_org.ssgproject.content_rule_openssl_use_strong_entropy.sh && \ - /security/xccdf_org.ssgproject.content_rule_package_crypto-policies_installed.sh && \ - /security/xccdf_org.ssgproject.content_rule_package_iptables_installed.sh && \ - dnf clean all && \ - rm -rf /security/ /var/cache/dnf/ /var/tmp/* /tmp/* /var/tmp/.???* /tmp/.???* && \ - chmod 755 /usr/local/bin/docker-entrypoint.sh - -ENTRYPOINT ["docker-entrypoint.sh"] diff --git a/docker/parabol-ubi/docker-build/entrypoints/buildenv b/docker/parabol-ubi/docker-build/entrypoints/docker-entrypoint.sh similarity index 100% rename from docker/parabol-ubi/docker-build/entrypoints/buildenv rename to docker/parabol-ubi/docker-build/entrypoints/docker-entrypoint.sh diff --git a/docker/parabol-ubi/docker-build/environments/basic-env b/docker/parabol-ubi/docker-build/environments/basic-env new file mode 100644 index 00000000000..86bbad9252d --- /dev/null +++ b/docker/parabol-ubi/docker-build/environments/basic-env @@ -0,0 +1,17 @@ +FILE_STORE_PROVIDER='local' +HOST='localhost' +NODE_ENV='production' +NODE_EXTRA_CA_CERTS='' +PROTO='https' +PORT='3000' +# Database configurations must be the same used in the docker-build.yml Github workflow +POSTGRES_PASSWORD='temppassword' +POSTGRES_USER='tempuser' +POSTGRES_DB='tempdb' +POSTGRES_HOST='localhost' +POSTGRES_PORT='5432' +REDIS_URL='redis://localhost:6379' +RETHINKDB_SSL='' +RETHINKDB_URL='rethinkdb://localhost:28015/buildDB' +SERVER_ID='0' +SERVER_SECRET='FAKE_VALUE' diff --git a/docker/parabol-ubi/docker-build/environments/buildenv b/docker/parabol-ubi/docker-build/environments/legacy-build similarity index 100% rename from docker/parabol-ubi/docker-build/environments/buildenv rename to docker/parabol-ubi/docker-build/environments/legacy-build diff --git a/docker/parabol-ubi/docker-build/environments/local-buildenv b/docker/parabol-ubi/docker-build/environments/local-buildenv deleted file mode 100644 index f5f7c27ab83..00000000000 --- a/docker/parabol-ubi/docker-build/environments/local-buildenv +++ /dev/null @@ -1,54 +0,0 @@ -ATLASSIAN_CLIENT_ID='' -ATLASSIAN_CLIENT_SECRET='' -AWS_ACCESS_KEY_ID='' -AWS_REGION='' -AWS_S3_BUCKET='' -AWS_SECRET_ACCESS_KEY='' -CDN_BASE_URL='' -FILE_STORE_PROVIDER='local' -GITHUB_CLIENT_ID='' -GITHUB_CLIENT_SECRET='' -GITHUB_WEBHOOK_SECRET='' -GITLAB_CLIENT_ID='' -GITLAB_CLIENT_SECRET='' -GOOGLE_CLOUD_CLIENT_EMAIL='' -GOOGLE_CLOUD_PRIVATE_KEY='' -GOOGLE_CLOUD_PRIVATE_KEY_ID='' -GOOGLE_OAUTH_CLIENT_ID='' -GOOGLE_OAUTH_CLIENT_SECRET='' -GOOGLE_TAG_MANAGER_CONTAINER_ID='' -GRAPHQL_HOST='' -GRAPHQL_PROTOCOL='' -HOST='' -INVITATION_SHORTLINK='' -MAIL_PROVIDER='' -MAIL_GOOGLE_USER='' -MAIL_GOOGLE_PASS='' -MAILGUN_API_KEY='' -MAILGUN_DOMAIN='' -MAILGUN_PUBLIC_KEY='' -MAIL_FROM='' -NODE_ENV='production' -NODE_EXTRA_CA_CERTS='' -PROTO='https' -PGADMIN_DEFAULT_EMAIL='' -PGADMIN_DEFAULT_PASSWORD='' -PGSSLMODE='' -PORT='' -POSTGRES_PASSWORD='temppassword' -POSTGRES_USER='tempuser' -POSTGRES_DB='tempdb' -POSTGRES_HOST='localhost' -POSTGRES_PORT='5432' -REDIS_URL='redis://localhost:6379' -RETHINKDB_SSL='' -RETHINKDB_URL='rethinkdb://localhost:28015/actionProduction' -SENTRY_DSN='' -SERVER_ID='' -SERVER_SECRET='FAKE_VALUE' -SLACK_CLIENT_ID='' -SLACK_CLIENT_SECRET='' -STRIPE_PUBLISHABLE_KEY='' -STRIPE_SECRET_KEY='' -STRIPE_WEBHOOK_SECRET='' -HUBSPOT_API_KEY='' From aa88da0205d2434ab3376169ce9cd37e5e5f0db1 Mon Sep 17 00:00:00 2001 From: "parabol-release-bot[bot]" <150284312+parabol-release-bot[bot]@users.noreply.github.com> Date: Thu, 29 Feb 2024 16:08:39 +0000 Subject: [PATCH 37/39] chore(release): release v7.19.6 (#9480) Co-authored-by: parabol-release-bot[bot] <150284312+parabol-release-bot[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- CHANGELOG.md | 12 ++++++++++++ package.json | 2 +- packages/chronos/package.json | 4 ++-- packages/client/package.json | 2 +- packages/gql-executor/package.json | 6 +++--- packages/integration-tests/package.json | 2 +- packages/server/package.json | 4 ++-- 8 files changed, 23 insertions(+), 11 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 6e9dcf42d00..a1ce62b5bc5 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "7.19.5" + ".": "7.19.6" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 080f2ea136c..8fbd69d25fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,18 @@ This project adheres to [Semantic Versioning](http://semver.org/). This CHANGELOG follows conventions [outlined here](http://keepachangelog.com/). +## [7.19.6](https://github.com/ParabolInc/parabol/compare/v7.19.5...v7.19.6) (2024-02-29) + + +### Fixed + +* After parameter for meetingCount was ignored ([#9479](https://github.com/ParabolInc/parabol/issues/9479)) ([052acd1](https://github.com/ParabolInc/parabol/commit/052acd14035fe7c96af8d17ca4763be91d863a80)) + + +### Changed + +* **docker-build:** simplify the docker build process and reduce docker image size ([#9447](https://github.com/ParabolInc/parabol/issues/9447)) ([5e356c2](https://github.com/ParabolInc/parabol/commit/5e356c2566db8e32e45a1393e1b1ea27c4be0a5c)) + ## [7.19.5](https://github.com/ParabolInc/parabol/compare/v7.19.4...v7.19.5) (2024-02-29) diff --git a/package.json b/package.json index ee9f994f9d9..f582fbc4f5d 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.5", + "version": "7.19.6", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" diff --git a/packages/chronos/package.json b/packages/chronos/package.json index f9c5675491e..8a2a986bd03 100644 --- a/packages/chronos/package.json +++ b/packages/chronos/package.json @@ -1,6 +1,6 @@ { "name": "chronos", - "version": "7.19.5", + "version": "7.19.6", "description": "A cron job scheduler", "author": "Matt Krick ", "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/chronos#readme", @@ -25,6 +25,6 @@ }, "dependencies": { "cron": "^2.3.1", - "parabol-server": "7.19.5" + "parabol-server": "7.19.6" } } diff --git a/packages/client/package.json b/packages/client/package.json index b5e0427873c..7dac5ea4e99 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.5", + "version": "7.19.6", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" diff --git a/packages/gql-executor/package.json b/packages/gql-executor/package.json index 0e97990948c..8bc4c541782 100644 --- a/packages/gql-executor/package.json +++ b/packages/gql-executor/package.json @@ -1,6 +1,6 @@ { "name": "gql-executor", - "version": "7.19.5", + "version": "7.19.6", "description": "A Stateless GraphQL Executor", "author": "Matt Krick ", "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/gqlExecutor#readme", @@ -27,8 +27,8 @@ }, "dependencies": { "dd-trace": "^4.2.0", - "parabol-client": "7.19.5", - "parabol-server": "7.19.5", + "parabol-client": "7.19.6", + "parabol-server": "7.19.6", "undici": "^5.26.2" } } diff --git a/packages/integration-tests/package.json b/packages/integration-tests/package.json index 1b7a9030731..ad76a9338b1 100644 --- a/packages/integration-tests/package.json +++ b/packages/integration-tests/package.json @@ -2,7 +2,7 @@ "name": "integration-tests", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.5", + "version": "7.19.6", "description": "", "main": "index.js", "scripts": { diff --git a/packages/server/package.json b/packages/server/package.json index 5dc86873eb0..439b2f4ab0f 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.5", + "version": "7.19.6", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" @@ -124,7 +124,7 @@ "oauth-1.0a": "^2.2.6", "openai": "^4.24.1", "oy-vey": "^0.11.0", - "parabol-client": "7.19.5", + "parabol-client": "7.19.6", "pg": "^8.5.1", "react": "^17.0.2", "react-dom": "^17.0.2", From 2ff4a6e6328bf437a31e9ac7984af4a55aae3d11 Mon Sep 17 00:00:00 2001 From: Rafa <101704572+rafaelromcar-parabol@users.noreply.github.com> Date: Thu, 29 Feb 2024 17:08:29 +0000 Subject: [PATCH 38/39] fix(docker-build): home folder is /home/node now (#9482) --- docker/parabol-ubi/docker-build/dockerfiles/basic.dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docker/parabol-ubi/docker-build/dockerfiles/basic.dockerfile b/docker/parabol-ubi/docker-build/dockerfiles/basic.dockerfile index 025862bedfe..077d95a8fb6 100644 --- a/docker/parabol-ubi/docker-build/dockerfiles/basic.dockerfile +++ b/docker/parabol-ubi/docker-build/dockerfiles/basic.dockerfile @@ -1,6 +1,9 @@ ARG _NODE_VERSION=${_NODE_VERSION} FROM node:${_NODE_VERSION}-bookworm-slim as base +ENV HOME=/home/node \ + USER=node + ENV NPM_CONFIG_PREFIX=/home/node/.npm-global ENV PORT=3000 From 9c44e23c4d223735551dbae2a0897040840b9e10 Mon Sep 17 00:00:00 2001 From: "parabol-release-bot[bot]" <150284312+parabol-release-bot[bot]@users.noreply.github.com> Date: Thu, 29 Feb 2024 17:17:19 +0000 Subject: [PATCH 39/39] chore(release): release v7.19.7 (#9483) Co-authored-by: parabol-release-bot[bot] <150284312+parabol-release-bot[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- CHANGELOG.md | 7 +++++++ package.json | 2 +- packages/chronos/package.json | 4 ++-- packages/client/package.json | 2 +- packages/gql-executor/package.json | 6 +++--- packages/integration-tests/package.json | 2 +- packages/server/package.json | 4 ++-- 8 files changed, 18 insertions(+), 11 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index a1ce62b5bc5..57085bcbc6b 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "7.19.6" + ".": "7.19.7" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fbd69d25fa..7191952d8a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ This project adheres to [Semantic Versioning](http://semver.org/). This CHANGELOG follows conventions [outlined here](http://keepachangelog.com/). +## [7.19.7](https://github.com/ParabolInc/parabol/compare/v7.19.6...v7.19.7) (2024-02-29) + + +### Fixed + +* **docker-build:** home folder is /home/node now ([#9482](https://github.com/ParabolInc/parabol/issues/9482)) ([2ff4a6e](https://github.com/ParabolInc/parabol/commit/2ff4a6e6328bf437a31e9ac7984af4a55aae3d11)) + ## [7.19.6](https://github.com/ParabolInc/parabol/compare/v7.19.5...v7.19.6) (2024-02-29) diff --git a/package.json b/package.json index f582fbc4f5d..8749898ad6a 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.6", + "version": "7.19.7", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" diff --git a/packages/chronos/package.json b/packages/chronos/package.json index 8a2a986bd03..f44740aee53 100644 --- a/packages/chronos/package.json +++ b/packages/chronos/package.json @@ -1,6 +1,6 @@ { "name": "chronos", - "version": "7.19.6", + "version": "7.19.7", "description": "A cron job scheduler", "author": "Matt Krick ", "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/chronos#readme", @@ -25,6 +25,6 @@ }, "dependencies": { "cron": "^2.3.1", - "parabol-server": "7.19.6" + "parabol-server": "7.19.7" } } diff --git a/packages/client/package.json b/packages/client/package.json index 7dac5ea4e99..a065260e9ad 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.6", + "version": "7.19.7", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" diff --git a/packages/gql-executor/package.json b/packages/gql-executor/package.json index 8bc4c541782..ea18a30925c 100644 --- a/packages/gql-executor/package.json +++ b/packages/gql-executor/package.json @@ -1,6 +1,6 @@ { "name": "gql-executor", - "version": "7.19.6", + "version": "7.19.7", "description": "A Stateless GraphQL Executor", "author": "Matt Krick ", "homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/gqlExecutor#readme", @@ -27,8 +27,8 @@ }, "dependencies": { "dd-trace": "^4.2.0", - "parabol-client": "7.19.6", - "parabol-server": "7.19.6", + "parabol-client": "7.19.7", + "parabol-server": "7.19.7", "undici": "^5.26.2" } } diff --git a/packages/integration-tests/package.json b/packages/integration-tests/package.json index ad76a9338b1..a1780c8c5b4 100644 --- a/packages/integration-tests/package.json +++ b/packages/integration-tests/package.json @@ -2,7 +2,7 @@ "name": "integration-tests", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.6", + "version": "7.19.7", "description": "", "main": "index.js", "scripts": { diff --git a/packages/server/package.json b/packages/server/package.json index 439b2f4ab0f..4e47bbb8ad0 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -3,7 +3,7 @@ "description": "An open-source app for building smarter, more agile teams.", "author": "Parabol Inc. (http://github.com/ParabolInc)", "license": "AGPL-3.0", - "version": "7.19.6", + "version": "7.19.7", "repository": { "type": "git", "url": "https://github.com/ParabolInc/parabol" @@ -124,7 +124,7 @@ "oauth-1.0a": "^2.2.6", "openai": "^4.24.1", "oy-vey": "^0.11.0", - "parabol-client": "7.19.6", + "parabol-client": "7.19.7", "pg": "^8.5.1", "react": "^17.0.2", "react-dom": "^17.0.2",