diff --git a/functions/src/auth/types.ts b/common/auth/types.ts similarity index 59% rename from functions/src/auth/types.ts rename to common/auth/types.ts index 6e570d3e5..ef701a044 100644 --- a/functions/src/auth/types.ts +++ b/common/auth/types.ts @@ -27,6 +27,49 @@ export type Claim = Static export const Frequency = Union(L("Weekly"), L("Monthly"), L("None")) export type Frequency = Static +export const OrgCategory = Union( + L("Agriculture"), + L("Animal Rights"), + L("Automotive"), + L("Civil Rights"), + L("Communications"), + L("Consumer Goods"), + L("Criminal Justice"), + L("Prison Reform"), + L("Education"), + L("Elder Care"), + L("Employment/Labor"), + L("Environment"), + L("Financial"), + L("Food"), + L("Good Government"), + L("Human Rights"), + L("Children's Rights"), + L("Death Penalty"), + L("Disabeled Rights"), + L("LGBTQ+ Rights"), + L("Housing"), + L("Immigration"), + L("Insurance"), + L("Internet & Technology"), + L("Legal"), + L("Medical/Health"), + L("Poverty"), + L("Privacy"), + L("Racial Justice"), + L("Regional"), + L("Refugee"), + L("Reproductive Health"), + L("Pharmaceuticals"), + L("Small & Local Business"), + L("Taxes"), + L("Water"), + L("Women's Rights"), + L("Multi-issue"), + L("Other") +) +export type OrgCategory = Static + export const OrgCategories = [ "Agriculture", "Animal Rights", @@ -67,6 +110,4 @@ export const OrgCategories = [ "Women's Rights", "Multi-issue", "Other" -] as const - -export type OrgCategory = (typeof OrgCategories)[number] +] diff --git a/common/bills/types.ts b/common/bills/types.ts new file mode 100644 index 000000000..387decc0f --- /dev/null +++ b/common/bills/types.ts @@ -0,0 +1,369 @@ +import { Timestamp } from "../types" + +import { + Array, + InstanceOf, + Number, + Optional, + Record, + Static, + String +} from "runtypes" +import { Id, Maybe, NullStr } from "../types" +import { withDefaults } from "../common" + +/** Represents a missing timestamp value. This allows documents without values + * to appear in results when sorting by that value. */ +export const MISSING_TIMESTAMP = Timestamp.fromMillis(0) + +export type SortOptions = + | "id" + | "cosponsorCount" + | "testimonyCount" + | "latestTestimony" + | "hearingDate" + +export type FilterOptions = + | { type: "bill"; id: string } + | { type: "primarySponsor"; id: string } + | { type: "committee"; id: string } + | { type: "city"; name: string } + +export type BillReference = Static +export const BillReference = Record({ + BillNumber: NullStr, + DocketNumber: NullStr, + GeneralCourtNumber: Number +}) + +export type BillHistoryAction = Static +export const BillHistoryAction = Record({ + Date: String, + Branch: String, + Action: String +}) + +export type BillHistory = Static +export const BillHistory = Array(BillHistoryAction) + +export type CurrentCommittee = Static +export const CommitteeMember = Record({ + id: String, + name: String, + email: NullStr + }), + CurrentCommittee = Record({ + id: String, + name: String, + houseChair: Maybe(CommitteeMember), + senateChair: Maybe(CommitteeMember) + }) + +export type BillTopic = Static +export const BillTopic = Record({ + category: String, + topic: String +}) + +export const TOPICS_BY_CATEGORY = { + Commerce: [ + "Banking and financial institutions regulation", + "Consumer protection", + "Corporation law and goverance", + "Commercial insurance", + "Marketing and advertising", + "Non-profit law and governance", + "Occupational licensing", + "Partnerships and limited liability companies", + "Retail and wholesale trades", + "Securities" + ], + "Crime and Law Enforcement": [ + "Assault and harassment offenses", + "Correctional facilities", + "Crimes against animals and natural resources", + "Crimes against children", + "Criminal investigation, prosecution, interrogation", + "Criminal justice information and records", + "Criminal justice reform", + "Criminal sentencing", + "Firearms and explosives", + "Fraud offenses and financial crimes", + "Property crimes" + ], + "Economics and Public Finance": [ + "Budget process", + "Debt collection", + "Eminent domain", + "Financial literacy", + "Financial services and investments", + "Government contractors", + "Pension and retirement benefits" + ], + Education: [ + "Academic performance and assessments", + "Adult education and literacy", + "Charter and private schools", + "Curriculum and standards", + "Education technology", + "Educational facilities and institutions", + "Elementary and secondary education", + "Higher education", + "Special education", + "Student aid and college costs", + "Teachers and educators", + "Vocational and technical education" + ], + "Emergency Management": [ + "Disaster relief and insurance", + "Emergency communications systems", + "Emergency medical services and trauma care", + "Emergency planning and evacuation", + "Hazards and emergency operations" + ], + Energy: [ + "Energy costs assistance", + "Energy efficiency and conservation", + "Energy infrastructure and storage", + "Energy prices and subsidies", + "Energy research", + "Renewable energy sources" + ], + "Environmental Protection": [ + "Air quality", + "Environmental assessment, monitoring, research", + "Environmental education", + "Environmental health", + "Environmental regulatory procedures", + "Hazardous wastes and toxic substances", + "Pollution control and abatement", + "Soil pollution", + "Trash and recycling", + "Water quality", + "Wetlands", + "Wildlife conservation" + ], + Families: [ + "Adoption and foster care", + "Family planning and birth control", + "Family relationships and status", + "Family services", + "Life insurance", + "Parenting and parental rights" + ], + "Food, Drugs, and Alcohol": [ + "Alcoholic beverages and licenses", + "Drug, alcohol, tobacco use", + "Drug safety, medical device, and laboratory regulation", + "Food industry and services", + "Food service employment", + "Food supply, safety, and labeling", + "Nutrition and diet" + ], + "Government Operations and Elections": [ + "Census and government statistics", + "Government information and archives", + "Government studies and investigations", + "Government trust funds", + "Lobbying and campaign finance", + 'Municipality oversight and "home rule petitions"', + "Political advertising", + "Public-private partnerships", + "Voting and elections" + ], + Healthcare: [ + "Alternative treatments", + "Dental care", + "Health care costs", + "Health facilities and institutions", + "Health information and medical records", + "Health insurance and coverage", + "Health technology, devices, supplies", + "Healthcare workforce", + "Medical research", + "Mental health", + "Prescription drugs", + "Sex and reproductive health", + "Substance use disorder and addiction", + "Telehealth", + "Veterinary services and pets" + ], + "Housing and Community Development": [ + "Community life and organization", + "Cooperative and condominium housing", + "Homelessness and emergency shelter", + "Housing discrimination", + "Housing finance and home ownership", + "Housing for the elderly and disabled", + "Housing industry and standards", + "Housing supply and affordability", + "Landlord and tenant", + "Low- and moderate-income housing", + "Residential rehabilitation and home repair" + ], + "Immigrants and Foreign Nationals": [ + "Immigrant health and welfare", + "Refugees, asylum, displaced persons", + "Right to shelter", + "Translation and language services" + ], + "Labor and Employment": [ + "Employee benefits", + "Employment discrimination", + "Employee leave", + "Employee pensions", + "Employee performance", + "Migrant, seasonal, agricultural labor", + "Self-employment", + "Temporary and part-time employment", + "Workers' compensation", + "Workforce development and employment training", + "Worker safety and health", + "Youth employment and child labor" + ], + "Law and Judiciary": [ + "Civil disturbances", + "Evidence and witnesses", + "Judicial and court records", + "Judicial review and appeals", + "Jurisdiction and venue", + "Legal fees and court costs" + ], + "Public and Natural Resources": [ + "Agriculture and aquaculture", + "Coastal zones and ocean", + "Forests, forestry, trees", + "Monuments and memorials", + "Watershed and water resources", + "Wildlife" + ], + "Social Services": [ + "Child care and development", + "Domestic violence and child abuse", + "Food assistance and relief", + "Home and outpatient care", + "Social work, volunteer service, charitable organizations", + "Unemployment", + "Urban and suburban affairs and development", + "Veterans' education, employment, rehabilitation", + "Veterans' loans, housing, homeless programs", + "Veterans' medical care" + ], + "Sports and Recreation": [ + "Art and culture", + "Gambling and lottery", + "Hunting and fishing", + "Outdoor recreation", + "Professional sports, stadiums and arenas", + "Public parks", + "Sports and recreation facilities" + ], + Taxation: [ + "Capital gains tax", + "Corporate tax", + "Estate tax", + "Excise tax", + "Gift tax", + "Income tax", + "Payroll and emplyoment tax", + "Property tax", + "Sales tax", + "Tax-exempt organizations", + "Transfer and inheritance taxes" + ], + "Technology and Communications": [ + "Advanced technology and technological innovations", + "Atmospheric science and weather", + "Broadband and internet access", + "Computers and information technology", + "Cybersecurity and identity theft", + "Data privacy", + "Emerging technology (artificial intelligence, blockchain, etc.)", + "Genetics", + "Internet, web applications, social media", + "Photography and imaging", + "Telecommunication rates and fees", + "Telephone and wireless communication" + ], + "Transportation and Public Works": [ + "Aviation and airports", + "Highways and roads", + "MBTA & public transportation", + "Public utilities and utility rates", + "Railroads", + "Vehicle insurance and repairs", + "Water storage", + "Water use and supply" + ] +} +export const CATEGORIES_BY_TOPIC = Object.entries(TOPICS_BY_CATEGORY).reduce( + (acc, [category, topics]) => { + topics.forEach(topic => { + acc[topic] = category + }) + + return acc + }, + {} as { [key: string]: string } +) + +export const MemberReference = Record({ + Id: String, + Name: String, + /** 1 = Legislative Member, 2 = Committee, 3 = Public Request, 4 = Special + * Request */ + Type: Number +}) +export type MemberReference = Static + +export type BillContent = Static +export const BillContent = Record({ + Title: String, + BillNumber: String, + DocketNumber: String, + GeneralCourtNumber: Number, + PrimarySponsor: Optional(MemberReference), + Cosponsors: Array(MemberReference), + LegislationTypeName: String, + Pinslip: String, + DocumentText: Maybe(String) +}) + +export type Bill = Static +export const Bill = withDefaults( + Record({ + id: Id, + court: Number, + content: BillContent, + cosponsorCount: Number, + testimonyCount: Number, + endorseCount: Number, + neutralCount: Number, + opposeCount: Number, + nextHearingAt: Optional(InstanceOf(Timestamp)), + nextHearingId: Optional(Id), + latestTestimonyAt: Optional(InstanceOf(Timestamp)), + latestTestimonyId: Optional(Id), + fetchedAt: InstanceOf(Timestamp), + history: BillHistory, + similar: Array(Id), + currentCommittee: Optional(CurrentCommittee), + city: Optional(String), + topics: Optional(Array(BillTopic)), + summary: Optional(String) + }), + { + court: 0, + cosponsorCount: 0, + testimonyCount: 0, + endorseCount: 0, + neutralCount: 0, + opposeCount: 0, + latestTestimonyAt: MISSING_TIMESTAMP, + nextHearingAt: MISSING_TIMESTAMP, + fetchedAt: MISSING_TIMESTAMP, + history: [], + similar: [], + topics: [] + } +) diff --git a/common/common.ts b/common/common.ts new file mode 100644 index 000000000..a8feb09ff --- /dev/null +++ b/common/common.ts @@ -0,0 +1,39 @@ +import { FieldValue } from "@google-cloud/firestore" +import { Record, Result, Runtype, Static } from "runtypes" + +/** Allows specifying defaults that are merged into records before validation. + * This is useful for compatibility with documents created before adding a field + * to the type. This adds `checkWithDefaults` and `valideWithDefaults` to the + * record. `checkWithDefaults` returns a shallow copy of the input. */ +export function withDefaults( + Base: Record, + defaults: Partial> +): RecordWithDefaults { + const Type = Base as RecordWithDefaults + Type.checkWithDefaults = (v: any) => Base.check(mix(v, defaults)) + Type.validateWithDefaults = (v: any) => Base.validate(mix(v, defaults)) + return Type +} + +function mix(v: any, defaults: {}) { + if (!!v && typeof v === "object") { + return { ...defaults, ...v } + } + return v +} + +type RecordWithDefaults = Record & { + checkWithDefaults(v: any): RecordType + validateWithDefaults(v: any): Result> +} + +type RecordSpec = { + [_: string]: Runtype +} + +type RecordType = Static> + +/** A Partial that also allows `FieldValue` */ +export type DocUpdate = { + [Prop in keyof T]?: T[Prop] | FieldValue +} diff --git a/functions/src/shared/constants.ts b/common/constants.ts similarity index 100% rename from functions/src/shared/constants.ts rename to common/constants.ts diff --git a/functions/src/shared/index.ts b/common/index.ts similarity index 53% rename from functions/src/shared/index.ts rename to common/index.ts index 23fdb6981..6c07e3e75 100644 --- a/functions/src/shared/index.ts +++ b/common/index.ts @@ -1 +1,2 @@ export * from "./constants" +export * from "./types" diff --git a/common/profile/types.ts b/common/profile/types.ts new file mode 100644 index 000000000..dd02a5cb5 --- /dev/null +++ b/common/profile/types.ts @@ -0,0 +1,61 @@ +import { + Boolean, + Dictionary, + Optional, + Array, + Record, + Static, + String, + Null, + Number, + InstanceOf +} from "runtypes" +import { Frequency, OrgCategory, Role } from "../auth/types" +import { Timestamp } from "../types" + +export const ProfileMember = Record({ + district: String, + id: String, + name: String +}) +export type ProfileMember = Static + +export const ContactInfo = Record({ + publicEmail: String, + publicPhone: Optional(Number), + website: Optional(String) +}) +export type ContactInfo = Static + +export const SocialLinks = Record({ + linkedIn: String, + twitter: String, + instagram: String, + fb: String, + blueSky: String, + mastodon: String +}).asPartial() + +export type SocialLinks = Static + +export const Profile = Record({ + topicName: String, + role: Role, + fullName: Optional(String), + email: Optional(String.Or(Null)), + representative: Optional(ProfileMember), + senator: Optional(ProfileMember), + public: Optional(Boolean), + notificationFrequency: Optional(Frequency), + nextDigestAt: Optional(InstanceOf(Timestamp)), + about: Optional(String), + social: Optional(Dictionary(String)), + profileImage: Optional(String), + billsFollowing: Optional(Array(String)), + contactInfo: Optional(ContactInfo), + organization: Optional(Boolean), + location: Optional(String), + orgCategories: Optional(Array(OrgCategory)) +}) + +export type Profile = Static diff --git a/common/testimony/types.ts b/common/testimony/types.ts new file mode 100644 index 000000000..b6352d712 --- /dev/null +++ b/common/testimony/types.ts @@ -0,0 +1,102 @@ +import { Role } from "../auth/types" +import { Timestamp } from "../types" +import { + Array, + Boolean, + InstanceOf, + Literal as L, + Number, + Optional, + Record as R, + Static, + String, + Union +} from "runtypes" +import { Id, Maybe } from "../types" +import { withDefaults } from "../common" + +export const maxTestimonyLength = 10_000 + +export const Position = Union(L("endorse"), L("oppose"), L("neutral")) +export type Position = Static + +export const Content = String.withConstraint( + s => s.length > 0 || "Content is empty" +).withConstraint(s => s.length < maxTestimonyLength || "Content is too long") +export type Content = Static + +export const BaseTestimony = R({ + billId: String, + court: Number, + position: Position, + content: Content, + attachmentId: Maybe(String), + editReason: Maybe(String) +}) + +export type BaseTestimony = Static + +export type Testimony = Static +export const Testimony = withDefaults( + BaseTestimony.extend({ + authorUid: Id, + id: Id, + authorDisplayName: String, + authorRole: Role, + billTitle: String, + version: Number, + public: Boolean, + publishedAt: InstanceOf(Timestamp), + updatedAt: InstanceOf(Timestamp), + representativeId: Optional(String), + senatorId: Optional(String), + senatorDistrict: Optional(String), + representativeDistrict: Optional(String), + draftAttachmentId: Maybe(String), + fullName: String + }), + { + authorRole: "user", + // ID is backfilled + id: "unknown", + publishedAt: Timestamp.fromMillis(0), + updatedAt: Timestamp.fromMillis(0), + public: true, + authorDisplayName: "Anonymous", + fullName: "Anonymous", + billTitle: "" + } +) + +export type WorkingDraft = Partial +export type DraftTestimony = Static +export const DraftTestimony = BaseTestimony.extend({ + publishedVersion: Optional(Number), + /** If present, array of legislator member codes */ + recipientMemberCodes: Maybe(Array(String)) +}) + +export const countsByPositions = { + endorse: "endorseCount", + neutral: "neutralCount", + oppose: "opposeCount" +} as const + +export const TestimonySearchRecord = R({ + id: String, + billId: String, + court: Number, + position: Union(L("endorse"), L("oppose"), L("neutral")), + content: String, + authorUid: String, + authorRole: String, + authorDisplayName: String, + version: Number, + public: Boolean, + publishedAt: Number, + updatedAt: Number, + fullName: String +}) +export type TestimonySearchRecord = Static + +export type WithId = { id: string; value: T } diff --git a/common/types.ts b/common/types.ts new file mode 100644 index 000000000..42fa8d22b --- /dev/null +++ b/common/types.ts @@ -0,0 +1,16 @@ +import { Timestamp as FirebaseTimestamp } from "firebase/firestore" +import { Null, Nullish, Optional, Runtype, String } from "runtypes" + +export const Timestamp = FirebaseTimestamp +export type Timestamp = FirebaseTimestamp + +export type Maybe = T | null | undefined + +// In particular, reject "/" in ID strings +const simpleId = /^[A-Za-z0-9-_]+$/ +/** Validates firestore-compatible ID's */ +export const Id = String.withConstraint(s => simpleId.test(s)) + +export const NullStr = String.Or(Null) +export const Nullable = (t: Runtype) => Null.Or(t) +export const Maybe = (t: Runtype) => Optional(t.Or(Nullish)) diff --git a/components/EditProfilePage/EditProfileHeader.tsx b/components/EditProfilePage/EditProfileHeader.tsx index b5c02f5b7..787b9d7e9 100644 --- a/components/EditProfilePage/EditProfileHeader.tsx +++ b/components/EditProfilePage/EditProfileHeader.tsx @@ -1,5 +1,5 @@ import { useTranslation } from "next-i18next" -import { Role } from "../auth" +import { Role } from "common/auth/types" import { Col, Row } from "../bootstrap" import { GearIcon, OutlineButton } from "../buttons" import { ProfileEditToggle } from "components/ProfilePage/ProfileButtons" diff --git a/components/EditProfilePage/EditProfilePage.tsx b/components/EditProfilePage/EditProfilePage.tsx index 09a96f3c6..2ccc67abb 100644 --- a/components/EditProfilePage/EditProfilePage.tsx +++ b/components/EditProfilePage/EditProfilePage.tsx @@ -6,7 +6,6 @@ import TabContainer from "react-bootstrap/TabContainer" import { useAuth } from "../auth" import { Container, Row, Spinner } from "../bootstrap" import { - Profile, ProfileHook, UseDraftTestimonyListing, UsePublishedTestimonyListing, @@ -26,6 +25,7 @@ import { import { TestimoniesTab } from "./TestimoniesTab" import { useFlags } from "components/featureFlags" import { PendingUpgradeBanner } from "components/PendingUpgradeBanner" +import { Profile } from "common/profile/types" const tabTitle = ["about-you", "testimonies", "following"] as const export type TabTitles = (typeof tabTitle)[number] diff --git a/components/EditProfilePage/PersonalInfoTab.tsx b/components/EditProfilePage/PersonalInfoTab.tsx index f7f00e2cb..a40680488 100644 --- a/components/EditProfilePage/PersonalInfoTab.tsx +++ b/components/EditProfilePage/PersonalInfoTab.tsx @@ -1,14 +1,15 @@ import { ChangeEvent, useEffect, useState } from "react" import { useForm } from "react-hook-form" import { Form, Row, Col, Button } from "../bootstrap" -import { Profile, ProfileHook } from "../db" +import { ProfileHook } from "../db" import Input from "../forms/Input" import { TitledSectionCard } from "../shared" import { YourLegislators } from "./YourLegislators" -import { OrgCategory, OrgCategories } from "components/auth" +import { OrgCategory, OrgCategories } from "common/auth/types" import { TooltipButton } from "components/buttons" import { useTranslation } from "next-i18next" import styled from "styled-components" +import { Profile } from "common/profile/types" type UpdateProfileData = { fullName: string diff --git a/components/EditProfilePage/ProfileSettingsModal.tsx b/components/EditProfilePage/ProfileSettingsModal.tsx index f721ec08f..91063086a 100644 --- a/components/EditProfilePage/ProfileSettingsModal.tsx +++ b/components/EditProfilePage/ProfileSettingsModal.tsx @@ -5,7 +5,7 @@ import { useTranslation } from "next-i18next" import { Dispatch, ReactNode, SetStateAction } from "react" import type { ModalProps } from "react-bootstrap" import Dropdown from "react-bootstrap/Dropdown" -import { Frequency, Role } from "../auth" +import { Frequency, Role } from "common/auth/types" import { Col, Form, Image, Modal, Row } from "../bootstrap" import { ProfileHook } from "../db" diff --git a/components/EditProfilePage/TestimoniesTab.tsx b/components/EditProfilePage/TestimoniesTab.tsx index e1541a844..42e9ee175 100644 --- a/components/EditProfilePage/TestimoniesTab.tsx +++ b/components/EditProfilePage/TestimoniesTab.tsx @@ -4,8 +4,8 @@ import { TitledSectionCard } from "../shared" import { TestimonyItem } from "components/TestimonyCard/TestimonyItem" import { SortTestimonyDropDown } from "components/TestimonyCard/SortTestimonyDropDown" import { TestimonyFAQ } from "./TestimonyFAQ" -import { Testimony } from "../db" import { useTranslation } from "next-i18next" +import { Testimony } from "common/testimony/types" export const TestimoniesTab = ({ publishedTestimonies, diff --git a/components/Newsfeed/Newsfeed.tsx b/components/Newsfeed/Newsfeed.tsx index cc124c307..2ac083f54 100644 --- a/components/Newsfeed/Newsfeed.tsx +++ b/components/Newsfeed/Newsfeed.tsx @@ -1,10 +1,10 @@ import ErrorPage from "next/error" -import { Timestamp } from "firebase/firestore" +import { Timestamp } from "common/types" import { useTranslation } from "next-i18next" import { useContext, useEffect, useState } from "react" import { useAuth } from "../auth" import { Col, Row, Spinner } from "../bootstrap" -import { Profile, useProfile, usePublicProfile } from "../db" +import { useProfile, usePublicProfile } from "../db" import { NotificationProps, Notifications } from "./NotificationProps" import notificationQuery from "./notification-query" import { @@ -16,6 +16,7 @@ import { import ProfileSettingsModal from "components/EditProfilePage/ProfileSettingsModal" import { NewsfeedCard } from "components/NewsfeedCard/NewsfeedCard" import { ProfileButtons } from "components/ProfilePage/ProfileButtons" +import { Profile } from "common/profile/types" export default function Newsfeed() { const { t } = useTranslation("common") diff --git a/components/Newsfeed/NotificationProps.tsx b/components/Newsfeed/NotificationProps.tsx index d071eb4d8..dc487ed58 100644 --- a/components/Newsfeed/NotificationProps.tsx +++ b/components/Newsfeed/NotificationProps.tsx @@ -1,4 +1,4 @@ -import { Timestamp } from "firebase/firestore" +import { Timestamp } from "common/types" export type NotificationProps = { authorUid: string // Testimony author diff --git a/components/NewsfeedCard/NewsfeedCard.tsx b/components/NewsfeedCard/NewsfeedCard.tsx index c955e6993..ab0ce5358 100644 --- a/components/NewsfeedCard/NewsfeedCard.tsx +++ b/components/NewsfeedCard/NewsfeedCard.tsx @@ -1,5 +1,5 @@ import styled from "styled-components" -import { Timestamp } from "firebase/firestore" +import { Timestamp } from "common/types" import { Card as MapleCard } from "../Card/Card" import { NewsfeedBillCardBody, diff --git a/components/ProfilePage/OrgContactInfo.tsx b/components/ProfilePage/OrgContactInfo.tsx index 4329c654e..2df4f4744 100644 --- a/components/ProfilePage/OrgContactInfo.tsx +++ b/components/ProfilePage/OrgContactInfo.tsx @@ -1,7 +1,7 @@ import { External } from "components/links" -import { Profile } from "../db" import { ContactInfoRow } from "./StyledProfileComponents" import { SocialMediaIcons } from "./SocialMediaIcons" +import { Profile } from "common/profile/types" export const OrgContactInfo = ({ profile }: { profile?: Profile }) => { const { diff --git a/components/ProfilePage/ProfileAboutSection.tsx b/components/ProfilePage/ProfileAboutSection.tsx index 9d8238ee7..0e6120815 100644 --- a/components/ProfilePage/ProfileAboutSection.tsx +++ b/components/ProfilePage/ProfileAboutSection.tsx @@ -1,4 +1,4 @@ -import { Profile } from "../db" +import { Profile } from "common/profile/types" import { TitledSectionCard } from "../shared" import { SocialMediaIcons } from "./SocialMediaIcons" import { useTranslation } from "next-i18next" diff --git a/components/ProfilePage/ProfileButtons.tsx b/components/ProfilePage/ProfileButtons.tsx index 56d74fa76..e98b26bb1 100644 --- a/components/ProfilePage/ProfileButtons.tsx +++ b/components/ProfilePage/ProfileButtons.tsx @@ -3,7 +3,7 @@ import React, { useContext } from "react" import styled from "styled-components" import { FillButton, GearIcon, OutlineButton } from "../buttons" import { Button } from "../bootstrap" -import { Role } from "components/auth/types" +import { Role } from "common/auth/types" import { Internal } from "components/links" export const StyledButton = styled(Button).attrs(props => ({ diff --git a/components/ProfilePage/ProfileHeader.tsx b/components/ProfilePage/ProfileHeader.tsx index ad69be3a6..21d97519f 100644 --- a/components/ProfilePage/ProfileHeader.tsx +++ b/components/ProfilePage/ProfileHeader.tsx @@ -2,12 +2,13 @@ import { useTranslation } from "next-i18next" import { useContext, useState } from "react" import { useMediaQuery } from "usehooks-ts" import { useAuth } from "../auth" -import { Profile, useProfile } from "../db" +import { useProfile } from "../db" import { EditProfileButton, ProfileButtons } from "./ProfileButtons" import { Header, ProfileDisplayName } from "./StyledProfileComponents" import { ProfileIcon } from "./StyledUserIcons" import ProfileSettingsModal from "components/EditProfilePage/ProfileSettingsModal" import { FollowUserButton } from "components/shared/FollowButton" +import { Profile } from "common/profile/types" export const ProfileHeader = ({ isUser, diff --git a/components/ProfilePage/ProfileLegislators.tsx b/components/ProfilePage/ProfileLegislators.tsx index 6f1cc6bd2..d999cfbef 100644 --- a/components/ProfilePage/ProfileLegislators.tsx +++ b/components/ProfilePage/ProfileLegislators.tsx @@ -1,8 +1,7 @@ import { useEffect, useState } from "react" -import { ProfileMember } from "../db" import { LabeledIcon, TitledSectionCard } from "../shared" -import { Card as MapleCard } from "components/Card" import { useTranslation } from "next-i18next" +import { ProfileMember } from "common/profile/types" type ProfileMemberPlus = (ProfileMember & { title: string }) | undefined diff --git a/components/ProfilePage/ProfilePage.tsx b/components/ProfilePage/ProfilePage.tsx index 32c492377..71373fe07 100644 --- a/components/ProfilePage/ProfilePage.tsx +++ b/components/ProfilePage/ProfilePage.tsx @@ -6,7 +6,7 @@ import { useTranslation } from "next-i18next" import ErrorPage from "next/error" import { useEffect, useState } from "react" import ViewTestimony from "../TestimonyCard/ViewTestimony" -import { Role, useAuth } from "../auth" +import { useAuth } from "../auth" import { Col, Container, Row, Spinner } from "../bootstrap" import { usePublicProfile, usePublishedTestimonyListing } from "../db" import { Banner } from "../shared/StyledSharedComponents" @@ -15,6 +15,7 @@ import { ProfileAboutSection } from "./ProfileAboutSection" import { ProfileHeader } from "./ProfileHeader" import { ProfileLegislators } from "./ProfileLegislators" import { VerifyAccountSection } from "./VerifyAccountSection" +import { Role } from "common/auth/types" export function ProfilePage(profileprops: { id: string diff --git a/components/ProfilePage/StyledUserIcons.tsx b/components/ProfilePage/StyledUserIcons.tsx index 1a34bbe1b..b6ed9a8d2 100644 --- a/components/ProfilePage/StyledUserIcons.tsx +++ b/components/ProfilePage/StyledUserIcons.tsx @@ -1,4 +1,4 @@ -import { Role } from "components/auth" +import { Role } from "common/auth/types" import { Image } from "components/bootstrap" import styled from "styled-components" import { useTranslation } from "next-i18next" diff --git a/components/TestimonyCallout/TestimonyCallout.tsx b/components/TestimonyCallout/TestimonyCallout.tsx index 14cfbea17..5918fd304 100644 --- a/components/TestimonyCallout/TestimonyCallout.tsx +++ b/components/TestimonyCallout/TestimonyCallout.tsx @@ -1,10 +1,10 @@ import { Image } from "react-bootstrap" import styled from "styled-components" -import { Testimony } from "../db" import { formatBillId } from "../formatting" import * as links from "../links" import { useTranslation } from "next-i18next" import { CSSProperties } from "react" +import { Testimony } from "common/testimony/types" export const voteHandPositionStyles: { [position in Testimony["position"]]: CSSProperties diff --git a/components/TestimonyCard/BillInfoHeader.tsx b/components/TestimonyCard/BillInfoHeader.tsx index 29c092811..a6defe7c0 100644 --- a/components/TestimonyCard/BillInfoHeader.tsx +++ b/components/TestimonyCard/BillInfoHeader.tsx @@ -1,6 +1,6 @@ import { Col, Row } from "react-bootstrap" import { Internal } from "components/links" -import { Testimony } from "components/db" +import { Testimony } from "common/testimony/types" import { formatBillId } from "components/formatting" import { PositionLabel } from "./PositionBug" diff --git a/components/TestimonyCard/TestimonyItem.tsx b/components/TestimonyCard/TestimonyItem.tsx index c619bb03b..b36ef5097 100644 --- a/components/TestimonyCard/TestimonyItem.tsx +++ b/components/TestimonyCard/TestimonyItem.tsx @@ -11,7 +11,7 @@ import { TestimonyContent } from "components/testimony" import { trimContent } from "components/TestimonyCallout/TestimonyCallout" import { ViewAttachment } from "components/ViewAttachment" import { Button, Col, Row, Stack } from "../bootstrap" -import { Testimony } from "../db" +import { Testimony } from "common/testimony/types" import { Internal, maple } from "../links" import { BillInfoHeader } from "./BillInfoHeader" import { ReportModal, RequestDeleteOwnTestimonyModal } from "./ReportModal" diff --git a/components/TestimonyCard/UserInfoHeader.tsx b/components/TestimonyCard/UserInfoHeader.tsx index 25e6eff1a..8a98a5acc 100644 --- a/components/TestimonyCard/UserInfoHeader.tsx +++ b/components/TestimonyCard/UserInfoHeader.tsx @@ -1,7 +1,6 @@ import { Col, Row, Stack } from "react-bootstrap" -import { Internal } from "components/links" import { Author } from "./Author" -import { Testimony } from "components/db" +import { Testimony } from "common/testimony/types" import { ProfilePositionLabel } from "./ProfilePositionBug" import { useTranslation } from "next-i18next" diff --git a/components/TestimonyCard/ViewTestimony.tsx b/components/TestimonyCard/ViewTestimony.tsx index 675ab85f7..c5b783ff6 100644 --- a/components/TestimonyCard/ViewTestimony.tsx +++ b/components/TestimonyCard/ViewTestimony.tsx @@ -6,10 +6,11 @@ import { Card as BootstrapCard, Col, Row } from "react-bootstrap" import styled from "styled-components" import { Card as MapleCard } from "../Card" import { useAuth } from "../auth" -import { Testimony, UsePublishedTestimonyListing } from "../db" +import { UsePublishedTestimonyListing } from "../db" import { SortTestimonyDropDown } from "./SortTestimonyDropDown" import { Tab, Tabs } from "./Tabs" import { TestimonyItem } from "./TestimonyItem" +import { Testimony } from "common/testimony/types" const Container = styled.div` font-family: Nunito; diff --git a/components/ViewAttachment.tsx b/components/ViewAttachment.tsx index 7d2897b47..6930d1c51 100644 --- a/components/ViewAttachment.tsx +++ b/components/ViewAttachment.tsx @@ -1,7 +1,8 @@ import { useTranslation } from "next-i18next" -import { Testimony, usePublishedTestimonyAttachment } from "./db" +import { usePublishedTestimonyAttachment } from "./db" import { External } from "./links" import styled from "styled-components" +import { Testimony } from "common/testimony/types" const StyledExternal = styled(External)` text-decoration: none; diff --git a/components/api/report.ts b/components/api/report.ts index 777b7a29c..e8a0eb12b 100644 --- a/components/api/report.ts +++ b/components/api/report.ts @@ -1,8 +1,8 @@ import { AxiosResponse } from "axios" import { useMutation } from "react-query" -import { Testimony } from "../db" import { Report, ReportResponse } from "../server-api/types" import { mapleClient } from "./maple-client" +import { Testimony } from "common/testimony/types" export async function reportTestimony(testimony: Testimony, report: Report) { return mapleClient.post( diff --git a/components/auth/OrgSignUpModal.tsx b/components/auth/OrgSignUpModal.tsx index ca3170452..dff4c885c 100644 --- a/components/auth/OrgSignUpModal.tsx +++ b/components/auth/OrgSignUpModal.tsx @@ -2,19 +2,10 @@ import { useEffect, useState } from "react" import clsx from "clsx" import type { ModalProps } from "react-bootstrap" import { useForm } from "react-hook-form" -import { - Alert, - Button, - Col, - FloatingLabel, - Form, - Modal, - Row, - Stack -} from "../bootstrap" +import { Alert, Button, Col, Form, Modal, Row, Stack } from "../bootstrap" import { LoadingButton } from "../buttons" import Input from "../forms/Input" -import { OrgCategories, OrgCategory } from "./types" +import { OrgCategories, OrgCategory } from "common/auth/types" import PasswordInput from "../forms/PasswordInput" import { CreateUserWithEmailAndPasswordData, @@ -79,7 +70,9 @@ export default function OrgSignUpModal({ } }, [tosStep]) - const [category, setCategory] = useState(OrgCategories[0]) + const [category, setCategory] = useState( + OrgCategories[0] as OrgCategory + ) const { t } = useTranslation("auth") diff --git a/components/auth/hooks.ts b/components/auth/hooks.ts index 0e71f07cb..ddc0c7b0c 100644 --- a/components/auth/hooks.ts +++ b/components/auth/hooks.ts @@ -12,7 +12,8 @@ import { import { useAsyncCallback } from "react-async-hook" import { setProfile } from "../db" import { auth } from "../firebase" -import { finishSignup, OrgCategory } from "./types" +import { finishSignup } from "./types" +import { OrgCategory } from "common/auth/types" const errorMessages: Record = { "auth/email-already-exists": "You already have an account.", @@ -69,7 +70,7 @@ export function useCreateUserWithEmailAndPassword(isOrg: boolean) { ) await finishSignup({ requestedRole: isOrg ? "organization" : "user" }) - const categories = orgCategory ? [orgCategory] : "" + const categories = orgCategory ? [orgCategory] : undefined if (isOrg) { await Promise.all([ diff --git a/components/auth/redux.ts b/components/auth/redux.ts index fc3c97ce3..b7235766b 100644 --- a/components/auth/redux.ts +++ b/components/auth/redux.ts @@ -1,8 +1,8 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit" import { User } from "firebase/auth" -import { Maybe } from "../db/common" import { useAppSelector } from "../hooks" -import { Claim } from "./types" +import { Claim } from "common/auth/types" +import { Maybe } from "common" export type AuthFlowStep = | "start" diff --git a/components/auth/service.tsx b/components/auth/service.tsx index f21730599..498541805 100644 --- a/components/auth/service.tsx +++ b/components/auth/service.tsx @@ -7,7 +7,7 @@ import { auth } from "../firebase" import { useAppDispatch } from "../hooks" import { createService } from "../service" import { authChanged, useAuth } from "./redux" -import { Claim } from "./types" +import { Claim } from "common/auth/types" export const { Provider } = createService(() => { const dispatch = useAppDispatch() diff --git a/components/auth/types.tsx b/components/auth/types.tsx index 04f004fc3..7f02986e3 100644 --- a/components/auth/types.tsx +++ b/components/auth/types.tsx @@ -1,8 +1,6 @@ import { functions } from "components/firebase" import { httpsCallable } from "firebase/functions" -import { Role } from "../../functions/src/auth/types" - -export * from "../../functions/src/auth/types" +import { Role } from "common/auth/types" export const finishSignup = httpsCallable<{ requestedRole: Role }, void>( functions, diff --git a/components/bill/BillDetails.tsx b/components/bill/BillDetails.tsx index 8b039e026..12018690e 100644 --- a/components/bill/BillDetails.tsx +++ b/components/bill/BillDetails.tsx @@ -14,9 +14,9 @@ import { Status } from "./Status" import { Summary } from "./Summary" import { BillProps } from "./types" import { useTranslation } from "next-i18next" -import { isCurrentCourt } from "functions/src/shared" import { FollowBillButton } from "components/shared/FollowButton" import { PendingUpgradeBanner } from "components/PendingUpgradeBanner" +import { isCurrentCourt } from "common" const StyledContainer = styled(Container)` font-family: "Nunito"; diff --git a/components/bill/Cosponsors.tsx b/components/bill/Cosponsors.tsx index 201d8f94c..78e8c147a 100644 --- a/components/bill/Cosponsors.tsx +++ b/components/bill/Cosponsors.tsx @@ -1,10 +1,11 @@ import React, { useState } from "react" import { Button, Modal, Table } from "react-bootstrap" import styled from "styled-components" -import { MemberReference, useMember } from "../db" +import { useMember } from "../db" import { memberLink } from "../links" import { FC } from "../types" import { BillProps } from "./types" +import { MemberReference } from "common/bills/types" const CoSponsorRow = ({ court, diff --git a/components/bill/HistoryTable.tsx b/components/bill/HistoryTable.tsx index fc7ac442a..3adb21034 100644 --- a/components/bill/HistoryTable.tsx +++ b/components/bill/HistoryTable.tsx @@ -1,7 +1,7 @@ import { billSiteURL, Wrap } from "components/links" import { useContext } from "react" import styled from "styled-components" -import { BillHistory } from "../db" +import { BillHistory } from "common/bills/types" import { CourtContext } from "./Status" export type HistoryProps = { billHistory: BillHistory } diff --git a/components/bill/Summary.tsx b/components/bill/Summary.tsx index 789df17ce..d683f50b3 100644 --- a/components/bill/Summary.tsx +++ b/components/bill/Summary.tsx @@ -8,8 +8,8 @@ import { SmartDisclaimer } from "./SmartDisclaimer" import { SmartIcon } from "./SmartIcon" import { TestimonyCounts } from "./TestimonyCounts" import { BillProps } from "./types" -import { currentGeneralCourt } from "functions/src/shared" -import { BillTopic } from "functions/src/bills/types" +import { currentGeneralCourt } from "common/constants" +import { BillTopic } from "common/bills/types" const SummaryContainer = styled(Container)` background-color: white; diff --git a/components/bill/types.ts b/components/bill/types.ts index dcf4e06d0..a1a4894e3 100644 --- a/components/bill/types.ts +++ b/components/bill/types.ts @@ -1,4 +1,4 @@ -import { Bill } from "../db" +import { Bill } from "common/bills/types" export type BillProps = { bill: Bill } export type { BillTracker } from "functions/src/analysis/types" diff --git a/components/db/api.ts b/components/db/api.ts index 2c5305102..d3a71891c 100644 --- a/components/db/api.ts +++ b/components/db/api.ts @@ -16,9 +16,9 @@ import { Query } from "firebase/firestore" import { first } from "lodash" -import { Bill } from "./bills" -import { Profile } from "./profile" -import { Testimony } from "./testimony" +import { Bill } from "common/bills/types" +import { Profile } from "common/profile/types" +import { Testimony } from "common/testimony/types" export type TestimonyQuery = { authorUid: string diff --git a/components/db/bills.ts b/components/db/bills.ts index d6c5569eb..fb98f56eb 100644 --- a/components/db/bills.ts +++ b/components/db/bills.ts @@ -1,83 +1,14 @@ -import { - collection, - getDocs, - limit, - orderBy, - Timestamp, - where -} from "firebase/firestore" +import { collection, getDocs, limit, orderBy, where } from "firebase/firestore" import { useAsync } from "react-async-hook" -import type { - BillHistory, - CurrentCommittee -} from "../../functions/src/bills/types" import { firestore } from "../firebase" import { loadDoc, midnight, nullableQuery } from "./common" -import { currentGeneralCourt } from "functions/src/shared" -export type { BillHistory } from "../../functions/src/bills/types" - -export type MemberReference = { - Id: string - Name: string - /** 1 = Legislative Member, 2 = Committee, 3 = Public Request, 4 = Special - * Request */ - Type: number -} - -export type BillContent = { - Title: string - BillNumber: string - DocketNumber: string - GeneralCourtNumber: number - PrimarySponsor?: MemberReference - Cosponsors: MemberReference[] - LegislationTypeName: string - Pinslip: string - DocumentText: string -} - -export type BillTopic = { - category: string - topic: string -} - -export type Bill = { - id: string - court: number - content: BillContent - cosponsorCount: number - testimonyCount: number - endorseCount: number - opposeCount: number - neutralCount: number - nextHearingAt?: Timestamp - latestTestimonyAt?: Timestamp - latestTestimonyId?: string - fetchedAt: Timestamp - history: BillHistory - currentCommittee?: CurrentCommittee - city?: string - topics?: BillTopic[] - summary?: string -} +import { currentGeneralCourt } from "common/constants" +import { Bill } from "common/bills/types" export function useBill(court: number, id: string) { return useAsync(getBill, [court, id]) } -export type SortOptions = - | "id" - | "cosponsorCount" - | "testimonyCount" - | "latestTestimony" - | "hearingDate" - -export type FilterOptions = - | { type: "bill"; id: string } - | { type: "primarySponsor"; id: string } - | { type: "committee"; id: string } - | { type: "city"; name: string } - export async function getBill( court: number, id: string diff --git a/components/db/common.ts b/components/db/common.ts index faab70306..33b42e5d2 100644 --- a/components/db/common.ts +++ b/components/db/common.ts @@ -1,6 +1,5 @@ import { doc, getDoc, Query, query, QueryConstraint } from "firebase/firestore" import { DateTime } from "luxon" -import { Null, Nullish, Optional, Runtype, String } from "runtypes" import { firestore } from "../firebase" export async function loadDoc(path: string) { @@ -22,17 +21,6 @@ export function now() { return DateTime.now() } -export type Maybe = T | null | undefined - export function midnight() { return now().set({ hour: 0, minute: 0, second: 0, millisecond: 0 }).toJSDate() } - -// In particular, reject "/" in ID strings -const simpleId = /^[A-Za-z0-9-_]+$/ -/** Validates firestore-compatible ID's */ -export const Id = String.withConstraint(s => simpleId.test(s)) - -export const NullStr = String.Or(Null) -export const Nullable = (t: Runtype) => Null.Or(t) -export const Maybe = (t: Runtype) => Optional(t.Or(Nullish)) diff --git a/components/db/events.ts b/components/db/events.ts index 6af3881ab..610b57623 100644 --- a/components/db/events.ts +++ b/components/db/events.ts @@ -1,14 +1,9 @@ -import { - collection, - getDocs, - orderBy, - Timestamp, - where -} from "firebase/firestore" +import { collection, getDocs, orderBy, where } from "firebase/firestore" import { useAsync } from "react-async-hook" import { firestore } from "../firebase" import { midnight, nullableQuery } from "./common" import { DateTime } from "luxon" +import { Timestamp } from "common/types" /** The timezone used for datetime strings returned by the API. */ export const timeZone = "America/New_York" diff --git a/components/db/members.ts b/components/db/members.ts index d4cd503bc..4cecd5858 100644 --- a/components/db/members.ts +++ b/components/db/members.ts @@ -1,7 +1,7 @@ -import { Timestamp } from "firebase/firestore" +import { Timestamp } from "common/types" import { useMemo } from "react" import { useAsync } from "react-async-hook" -import { currentGeneralCourt } from "functions/src/shared" +import { currentGeneralCourt } from "common/constants" import { loadDoc } from "./common" export type CommitteeReference = { CommitteeCode: string diff --git a/components/db/profile/index.ts b/components/db/profile/index.ts index dc91c1335..bd9b982e6 100644 --- a/components/db/profile/index.ts +++ b/components/db/profile/index.ts @@ -1,2 +1 @@ export * from "./profile" -export * from "./types" diff --git a/components/db/profile/profile.ts b/components/db/profile/profile.ts index bbeb3f583..64ae1eb8e 100644 --- a/components/db/profile/profile.ts +++ b/components/db/profile/profile.ts @@ -8,12 +8,18 @@ import { import { getDownloadURL, ref, uploadBytes } from "firebase/storage" import { useEffect, useMemo, useReducer, useState } from "react" import { useAsync } from "react-async-hook" -import { Frequency, OrgCategory, useAuth } from "../../auth" +import { useAuth } from "../../auth" import { firestore, storage } from "../../firebase" import { useProfileState } from "./redux" -import { Profile, ProfileMember, SocialLinks, ContactInfo } from "./types" +import { + Profile, + ProfileMember, + SocialLinks, + ContactInfo +} from "../../../common/profile/types" import { cleanSocialLinks, cleanOrgURL } from "./urlCleanup" import { updateUserDisplayNameTestimonies } from "../testimony/updateUserTestimonies" +import { Frequency, OrgCategory } from "common/auth/types" export type ProfileHook = ReturnType diff --git a/components/db/profile/redux.ts b/components/db/profile/redux.ts index 945950caf..35a702b94 100644 --- a/components/db/profile/redux.ts +++ b/components/db/profile/redux.ts @@ -1,6 +1,6 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit" import { useAppSelector } from "../../hooks" -import { Profile } from "./types" +import { Profile } from "../../../common/profile/types" export interface State { loading: boolean diff --git a/components/db/profile/service.ts b/components/db/profile/service.ts index 3efecfc83..7e9c08c24 100644 --- a/components/db/profile/service.ts +++ b/components/db/profile/service.ts @@ -5,7 +5,7 @@ import { useAppDispatch } from "../../hooks" import { createService } from "../../service" import { profileRef } from "./profile" import { profileChanged } from "./redux" -import { Profile } from "./types" +import { Profile } from "../../../common/profile/types" export const { Provider } = createService(() => { const uid = useAuth().user?.uid diff --git a/components/db/profile/types.ts b/components/db/profile/types.ts deleted file mode 100644 index b99b80d5d..000000000 --- a/components/db/profile/types.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Frequency, Role } from "../../auth" -import { OrgCategory } from "../../auth" - -export type ProfileMember = { - district: string - id: string - name: string -} - -export type ContactInfo = { - publicEmail: string - publicPhone?: number - website?: string -} - -export const SOCIAL_NETWORKS = [ - "linkedIn", - "twitter", - "instagram", - "fb", - "blueSky", - "mastodon" -] as const - -export type SocialLinks = Partial< - Record<(typeof SOCIAL_NETWORKS)[number], string> -> - -export type Profile = { - topicName: string - role: Role - fullName?: string - email?: string | null - representative?: ProfileMember - senator?: ProfileMember - public?: boolean - notificationFrequency?: Frequency - nextDigestAt?: FirebaseFirestore.Timestamp - about?: string - social?: SocialLinks - profileImage?: string - billsFollowing?: string[] - contactInfo?: ContactInfo - location?: string - orgCategories?: OrgCategory[] | "" -} diff --git a/components/db/profile/urlCleanup.ts b/components/db/profile/urlCleanup.ts index 26d09b13a..bec333c7f 100644 --- a/components/db/profile/urlCleanup.ts +++ b/components/db/profile/urlCleanup.ts @@ -1,4 +1,4 @@ -import { SocialLinks } from ".." +import { SocialLinks } from "../../../common/profile/types" export function cleanSocialLinks(network: keyof SocialLinks, link: string) { let path = link diff --git a/components/db/testimony/resolveTestimony.ts b/components/db/testimony/resolveTestimony.ts index 6570647d6..0f0a8e2de 100644 --- a/components/db/testimony/resolveTestimony.ts +++ b/components/db/testimony/resolveTestimony.ts @@ -7,7 +7,7 @@ import { } from "firebase/firestore" import { first } from "lodash" import { firestore } from "../../firebase" -import { DraftTestimony, Testimony } from "./types" +import { DraftTestimony, Testimony } from "../../../common/testimony/types" /** Resolves the current draft and publication refs for a given user and bill. */ export const resolveBillTestimony = async ( diff --git a/components/db/testimony/types.ts b/components/db/testimony/types.ts index bcec3fb5d..f78ea0938 100644 --- a/components/db/testimony/types.ts +++ b/components/db/testimony/types.ts @@ -1,68 +1,7 @@ -import { Role } from "components/auth" -import { Timestamp } from "firebase/firestore" import { httpsCallable } from "firebase/functions" -import { - Array, - Boolean, - InstanceOf, - Literal as L, - Number, - Optional, - Record as R, - Static, - String, - Union -} from "runtypes" import { functions } from "../../firebase" -import { Id, Maybe } from "../common" import type * as report from "functions/src/testimony/resolveReport" - -export const maxTestimonyLength = 10_000 - -export const Position = Union(L("endorse"), L("oppose"), L("neutral")) -export type Position = Static - -export const Content = String.withConstraint( - s => s.length > 0 || "Content is empty" -).withConstraint(s => s.length < maxTestimonyLength || "Content is too long") -export type Content = Static - -export const BaseTestimony = R({ - billId: String, - court: Number, - position: Position, - content: Content, - attachmentId: Maybe(String), - editReason: Maybe(String) -}) -export type BaseTestimony = Static - -export type Testimony = Static -export const Testimony = BaseTestimony.extend({ - authorUid: Id, - id: Id, - authorDisplayName: String, - authorRole: Role, - billTitle: String, - version: Number, - public: Boolean, - publishedAt: InstanceOf(Timestamp), - updatedAt: InstanceOf(Timestamp), - representativeId: Optional(String), - senatorId: Optional(String), - senatorDistrict: Optional(String), - representativeDistrict: Optional(String), - draftAttachmentId: Maybe(String), - fullName: String -}) - -export type WorkingDraft = Partial -export type DraftTestimony = Static -export const DraftTestimony = BaseTestimony.extend({ - publishedVersion: Optional(Number), - /** If present, array of legislator member codes */ - recipientMemberCodes: Maybe(Array(String)) -}) +import { Testimony, WorkingDraft } from "common/testimony/types" /** Returns true if both values are either falsy or strictly equal. */ const eqish = (a: any, b: any) => (a || undefined) === (b || undefined) @@ -81,8 +20,6 @@ export function hasDraftChanged( ) } -export type WithId = { id: string; value: T } - export const deleteTestimony = httpsCallable< { publicationId: string }, { deleted: boolean } diff --git a/components/db/testimony/useDraftTestimonyListing.ts b/components/db/testimony/useDraftTestimonyListing.ts index f23a7d6df..b819c3551 100644 --- a/components/db/testimony/useDraftTestimonyListing.ts +++ b/components/db/testimony/useDraftTestimonyListing.ts @@ -1,8 +1,8 @@ import { getDocs, collection } from "firebase/firestore" import { firestore } from "../../firebase" import { nullableQuery } from "../common" -import { Testimony } from "./types" import { useAsync } from "react-async-hook" +import { Testimony } from "common/testimony/types" export type UseDraftTestimonyListing = ReturnType< typeof useDraftTestimonyListing diff --git a/components/db/testimony/useEditTestimony.test.ts b/components/db/testimony/useEditTestimony.test.ts index 89a730a43..5c5362839 100644 --- a/components/db/testimony/useEditTestimony.test.ts +++ b/components/db/testimony/useEditTestimony.test.ts @@ -1,14 +1,15 @@ import { act, renderHook, waitFor } from "@testing-library/react" import { User } from "firebase/auth" -import { currentGeneralCourt } from "functions/src/shared" +import { currentGeneralCourt } from "common/constants" import { nanoid } from "nanoid" -import { DraftTestimony, Testimony, useEditTestimony } from "." +import { useEditTestimony } from "." import { createFakeBill, signInUser1, signInUser3 } from "../../../tests/integration/common" import { terminateFirebase, testDb } from "../../../tests/testUtils" +import { DraftTestimony, Testimony } from "common/testimony/types" let uid: string let user: User diff --git a/components/db/testimony/useEditTestimony.ts b/components/db/testimony/useEditTestimony.ts index ca6b108e9..2e91804ab 100644 --- a/components/db/testimony/useEditTestimony.ts +++ b/components/db/testimony/useEditTestimony.ts @@ -12,14 +12,8 @@ import { Dispatch, useCallback, useEffect, useMemo, useReducer } from "react" import { useAsyncCallback, UseAsyncReturn } from "react-async-hook" import { firestore } from "../../firebase" import { resolveBillTestimony } from "./resolveTestimony" -import { - deleteTestimony, - DraftTestimony, - hasDraftChanged, - publishTestimony, - Testimony, - WorkingDraft -} from "./types" +import { deleteTestimony, hasDraftChanged, publishTestimony } from "./types" +import { DraftTestimony, Testimony, WorkingDraft } from "common/testimony/types" export interface UseEditTestimony { /** The last hook error produced in loading the `draft` or `publication`. This diff --git a/components/db/testimony/usePublishedTestimonyListing.ts b/components/db/testimony/usePublishedTestimonyListing.ts index bc4d412b2..2664e867c 100644 --- a/components/db/testimony/usePublishedTestimonyListing.ts +++ b/components/db/testimony/usePublishedTestimonyListing.ts @@ -11,7 +11,7 @@ import { useEffect, useMemo } from "react" import { firestore } from "../../firebase" import { nullableQuery } from "../common" import { createTableHook } from "../createTableHook" -import { Testimony } from "./types" +import { Testimony } from "common/testimony/types" type Refinement = { senatorId?: string diff --git a/components/db/testimony/useTestimonyAttachment.ts b/components/db/testimony/useTestimonyAttachment.ts index d3ac116b9..e44fc8e9c 100644 --- a/components/db/testimony/useTestimonyAttachment.ts +++ b/components/db/testimony/useTestimonyAttachment.ts @@ -16,7 +16,7 @@ import { useState } from "react" import { storage } from "../../firebase" -import { Maybe } from "../common" +import { Maybe } from "common" export const draftAttachment = (uid: string, id: string) => ref(storage, `users/${uid}/draftAttachments/${id}`) diff --git a/components/db/testimony/useTestimonyListing.test.ts b/components/db/testimony/useTestimonyListing.test.ts index 40455e085..980016f30 100644 --- a/components/db/testimony/useTestimonyListing.test.ts +++ b/components/db/testimony/useTestimonyListing.test.ts @@ -2,7 +2,7 @@ import { act, renderHook, waitFor } from "@testing-library/react" import { useTestimonyListing } from "." import { signInUser2, signInUser3 } from "../../../tests/integration/common" import { terminateFirebase, testDb } from "../../../tests/testUtils" -import { currentGeneralCourt } from "functions/src/shared" +import { currentGeneralCourt } from "common/constants" // jest.setTimeout(10000) diff --git a/components/db/testimony/useTestimonyListing.ts b/components/db/testimony/useTestimonyListing.ts index 2dccd4b93..da932ab27 100644 --- a/components/db/testimony/useTestimonyListing.ts +++ b/components/db/testimony/useTestimonyListing.ts @@ -8,7 +8,12 @@ import { } from "firebase/firestore" import { useEffect, useMemo, useReducer } from "react" import { firestore } from "../../firebase" -import { BaseTestimony, DraftTestimony, Testimony, WithId } from "./types" +import { + BaseTestimony, + DraftTestimony, + Testimony, + WithId +} from "../../../common/testimony/types" /** Latest draft and publication for a particular user and bill */ export type BillTestimony = { diff --git a/components/db/testimony/useUnsavedTestimony.ts b/components/db/testimony/useUnsavedTestimony.ts index b99b05553..45b9e5004 100644 --- a/components/db/testimony/useUnsavedTestimony.ts +++ b/components/db/testimony/useUnsavedTestimony.ts @@ -1,5 +1,5 @@ +import { DraftTestimony } from "common/testimony/types" import { useReducer } from "react" -import { DraftTestimony } from "./types" type State = Pick diff --git a/components/db/useBillStatus.ts b/components/db/useBillStatus.ts index 351b887aa..4f38efe9f 100644 --- a/components/db/useBillStatus.ts +++ b/components/db/useBillStatus.ts @@ -1,8 +1,5 @@ import { BillTracker } from "components/bill/types" -import { BillHistoryAction } from "functions/src/bills/types" -import { useEffect, useState } from "react" import { useAsync } from "react-async-hook" -import { Bill, getBill } from "./bills" import { loadDoc } from "./common" export enum Stage { diff --git a/components/db/useUpcoming.test.ts b/components/db/useUpcoming.test.ts index a9b2e3201..f9ecd5df1 100644 --- a/components/db/useUpcoming.test.ts +++ b/components/db/useUpcoming.test.ts @@ -3,7 +3,7 @@ import { terminateFirebase, testDb, testTimestamp } from "../../tests/testUtils" import { useUpcomingBills } from "./useUpcomingBills" import { DateTime } from "luxon" -import { currentGeneralCourt } from "functions/src/shared" +import { currentGeneralCourt } from "common/constants" import { midnight } from "./common" import { useUpcomingEvents } from "./events" import { createFakeBill } from "tests/integration/common" diff --git a/components/formatting.tsx b/components/formatting.tsx index 7e34daaca..75c236490 100644 --- a/components/formatting.tsx +++ b/components/formatting.tsx @@ -1,7 +1,7 @@ -import { Timestamp } from "firebase/firestore" import { useMediaQuery } from "usehooks-ts" -import { Testimony } from "../functions/src/testimony/types" -import { Bill, BillContent } from "./db" +import { Bill, BillContent } from "common/bills/types" +import { Timestamp } from "common/types" +import { Testimony } from "common/testimony/types" const billIdFormat = /^(?\D+)(?\d+)$/ diff --git a/components/forms/Input.tsx b/components/forms/Input.tsx index 29255efbb..315e8cc3b 100644 --- a/components/forms/Input.tsx +++ b/components/forms/Input.tsx @@ -1,11 +1,11 @@ import { useId } from "@react-aria/utils" import clsx from "clsx" -import { Maybe } from "components/db/common" -import { forwardRef, ReactElement, ReactNode, useState } from "react" +import { forwardRef, ReactNode, useState } from "react" import type { FormControlProps } from "react-bootstrap" import { Form } from "../bootstrap" import { Image } from "../bootstrap" import styled from "styled-components" +import { Maybe } from "common" export type InputProps = Omit< FormControlProps, diff --git a/components/legislatorSearch.tsx b/components/legislatorSearch.tsx index 7f3775778..104c4aff7 100644 --- a/components/legislatorSearch.tsx +++ b/components/legislatorSearch.tsx @@ -4,7 +4,8 @@ import { useMemo } from "react" import { GroupBase } from "react-select" import AsyncSelect, { AsyncProps } from "react-select/async" import { Row, Spinner } from "./bootstrap" -import { MemberSearchIndexItem, ProfileMember } from "./db" +import { MemberSearchIndexItem } from "./db" +import { ProfileMember } from "common/profile/types" export const Loading = () => ( diff --git a/components/links.tsx b/components/links.tsx index 429a6afb8..c63d75415 100644 --- a/components/links.tsx +++ b/components/links.tsx @@ -1,10 +1,10 @@ import Link from "next/link" import { forwardRef, PropsWithChildren } from "react" -import { BillTopic, CurrentCommittee } from "../functions/src/bills/types" -import { Testimony } from "components/db/testimony" -import { Bill, MemberContent } from "./db" +import { Bill, BillTopic, CurrentCommittee } from "common/bills/types" +import { MemberContent } from "./db" import { formatBillId } from "./formatting" import { TFunction } from "next-i18next" +import { Testimony } from "common/testimony/types" type LinkProps = PropsWithChildren<{ href: string; className?: string }> diff --git a/components/moderation/EditReports.tsx b/components/moderation/EditReports.tsx index 1f5e5a539..2f03a36af 100644 --- a/components/moderation/EditReports.tsx +++ b/components/moderation/EditReports.tsx @@ -1,6 +1,4 @@ import { Card, CardContent, CardHeader, Stack, Typography } from "@mui/material" -import { Testimony } from "components/db" -import { Timestamp } from "functions/src/firebase" import { Edit, TextField, @@ -10,6 +8,7 @@ import { } from "react-admin" import { RemoveTestimonyForm } from "./RemoveTestimony" import { Report } from "./types" +import { Testimony } from "common/testimony/types" export function EditReports() { const { record, data } = useEditController() diff --git a/components/moderation/ListProfiles.tsx b/components/moderation/ListProfiles.tsx index f8cfc1ffc..7eb8b16a2 100644 --- a/components/moderation/ListProfiles.tsx +++ b/components/moderation/ListProfiles.tsx @@ -16,11 +16,11 @@ import { rejectOrganizationRequest, acceptOrganizationRequest } from "components/api/upgrade-org" -import { Profile } from "components/db" +import { Profile } from "../../common/profile/types" import { Internal } from "components/links" import { ButtonGroup } from "@mui/material" -import { Role } from "components/auth" +import { Role } from "common/auth/types" import { createFakeOrg } from "components/moderation" import { loremIpsum } from "lorem-ipsum" import { nanoid } from "nanoid" diff --git a/components/moderation/RemoveTestimony.tsx b/components/moderation/RemoveTestimony.tsx index 70bc93bc6..09bf08391 100644 --- a/components/moderation/RemoveTestimony.tsx +++ b/components/moderation/RemoveTestimony.tsx @@ -3,12 +3,12 @@ import { deleteTestimony } from "components/api/delete-testimony" import { resolveReport } from "components/db" import { getAuth } from "firebase/auth" import { doc, getDoc } from "firebase/firestore" -import { Timestamp } from "functions/src/firebase" import { FormEventHandler, useState } from "react" import { useRedirect, useNotify, useRefresh } from "react-admin" import { Report, Resolution } from "." import { firestore } from "components/firebase" import { refreshToken } from "firebase-admin/app" +import { Timestamp } from "common/types" export type ReportResponseValues = { reportId: string diff --git a/components/moderation/setUp/CreateMockReport.tsx b/components/moderation/setUp/CreateMockReport.tsx index 154c256ca..fca05c65b 100644 --- a/components/moderation/setUp/CreateMockReport.tsx +++ b/components/moderation/setUp/CreateMockReport.tsx @@ -1,6 +1,6 @@ +import { Testimony } from "common/testimony/types" import { ReportModal } from "components/TestimonyCard/ReportModal" import { useReportTestimony } from "components/api/report" -import { Testimony } from "components/db" import { auth, firestore } from "components/firebase" import { createFakeTestimony } from "components/moderation" import { doc, getDoc } from "firebase/firestore" diff --git a/components/moderation/setUp/MockRecords.tsx b/components/moderation/setUp/MockRecords.tsx index 2878b8f1a..7fe63d6f7 100644 --- a/components/moderation/setUp/MockRecords.tsx +++ b/components/moderation/setUp/MockRecords.tsx @@ -1,8 +1,8 @@ -import { Timestamp } from "firebase/firestore" +import { Timestamp } from "common/types" import { loremIpsum } from "lorem-ipsum" import { nanoid } from "nanoid" import { Report } from "../types" -import { BaseTestimony, Testimony } from "components/db" +import { Testimony } from "common/testimony/types" export const createFakeTestimonyReport = (uid?: string) => { const user = fakeUser(uid) diff --git a/components/moderation/types.ts b/components/moderation/types.ts index 39c3217ab..1d4b4ea48 100644 --- a/components/moderation/types.ts +++ b/components/moderation/types.ts @@ -1,5 +1,5 @@ -import { Timestamp } from "functions/src/firebase" -import { Role } from "components/auth" +import { Timestamp } from "common/types" +import { Role } from "common/auth/types" import { functions } from "components/firebase" import { httpsCallable } from "firebase/functions" diff --git a/components/publish/ChooseStance.tsx b/components/publish/ChooseStance.tsx index ac3a702d9..467ca38ca 100644 --- a/components/publish/ChooseStance.tsx +++ b/components/publish/ChooseStance.tsx @@ -1,7 +1,6 @@ import { ToggleButton, ToggleButtonProps } from "react-bootstrap" import styled from "styled-components" import { Image, Row, Col } from "../bootstrap" -import { Position } from "../db" import { useAppDispatch } from "../hooks" import { positionLabels } from "./content" import { usePublishState } from "./hooks" @@ -10,6 +9,7 @@ import { setPosition } from "./redux" import { StepHeader } from "./StepHeader" import { useMediaQuery } from "usehooks-ts" import { useTranslation } from "react-i18next" +import { Position } from "common/testimony/types" export const ChooseStance = styled(({ ...rest }) => { const { t } = useTranslation("testimony") diff --git a/components/publish/QuickInfo.tsx b/components/publish/QuickInfo.tsx index e9ad7fe8f..c67358420 100644 --- a/components/publish/QuickInfo.tsx +++ b/components/publish/QuickInfo.tsx @@ -2,8 +2,9 @@ import clsx from "clsx" import styled from "styled-components" import { useMediaQuery } from "usehooks-ts" import { Image } from "../bootstrap" -import { Bill, Profile } from "../db" +import { Bill } from "common/bills/types" import { useTranslation } from "next-i18next" +import { Profile } from "common/profile/types" export function QuickInfo({ bill, profile }: { bill: Bill; profile: Profile }) { const { diff --git a/components/publish/SubmitTestimonyForm.tsx b/components/publish/SubmitTestimonyForm.tsx index 40fe9e4b2..fab1a196d 100644 --- a/components/publish/SubmitTestimonyForm.tsx +++ b/components/publish/SubmitTestimonyForm.tsx @@ -4,7 +4,7 @@ import styled from "styled-components" import { useMediaQuery } from "usehooks-ts" import { Col, Image, Row, Spinner, Collapse } from "../bootstrap" -import { Bill, Profile } from "../db" +import { Bill } from "common/bills/types" import * as links from "../links" import { ChooseStance } from "./ChooseStance" import { useFormInfo } from "./hooks" @@ -19,6 +19,7 @@ import { WriteTestimony } from "./WriteTestimony" import { Trans, useTranslation } from "react-i18next" import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" import { faCaretDown, faCaretUp } from "@fortawesome/free-solid-svg-icons" +import { Profile } from "common/profile/types" const Background = styled.div` background: var(--bs-white); diff --git a/components/publish/TestimonyPreview.tsx b/components/publish/TestimonyPreview.tsx index 0c44dc533..f0c263427 100644 --- a/components/publish/TestimonyPreview.tsx +++ b/components/publish/TestimonyPreview.tsx @@ -8,11 +8,11 @@ import styled from "styled-components" import { CopyButton } from "../buttons" import { getDraftTestimonyAttachmentInfo, - Position, getPublishedTestimonyAttachmentInfo, AttachmentInfo } from "../db" import { usePublishState, useTestimonyEmail } from "./hooks" +import { Position } from "common/testimony/types" export const positionActions: Record = { neutral: ( diff --git a/components/publish/WriteTestimony.tsx b/components/publish/WriteTestimony.tsx index 153d362a9..5afad70ad 100644 --- a/components/publish/WriteTestimony.tsx +++ b/components/publish/WriteTestimony.tsx @@ -3,7 +3,6 @@ import styled from "styled-components" import { Attachment } from "../CommentModal/Attachment" import { useAuth } from "../auth" import { useDraftTestimonyAttachment } from "../db" -import { Maybe } from "../db/common" import { TextArea } from "../forms/Input" import { useAppDispatch } from "../hooks" import * as links from "../links" @@ -13,6 +12,7 @@ import { StepHeader } from "./StepHeader" import { useFormRedirection, usePublishState } from "./hooks" import { setAttachmentId, setContent } from "./redux" import { Trans, useTranslation } from "react-i18next" +import { Maybe } from "common" type TabKey = "text" | "import" type UseWriteTestimony = ReturnType diff --git a/components/publish/content.ts b/components/publish/content.ts index b1b211bae..03d4b30cb 100644 --- a/components/publish/content.ts +++ b/components/publish/content.ts @@ -1,4 +1,4 @@ -import type { Position } from "../db" +import { Position } from "common/testimony/types" export const positionActions: Record = { neutral: "am neutral on", diff --git a/components/publish/hooks/publishTestimonyAndProceed.ts b/components/publish/hooks/publishTestimonyAndProceed.ts index 32bf4e911..ea9202706 100644 --- a/components/publish/hooks/publishTestimonyAndProceed.ts +++ b/components/publish/hooks/publishTestimonyAndProceed.ts @@ -1,6 +1,5 @@ -import { DraftTestimony } from "../../db" +import { DraftTestimony } from "common/testimony/types" import { createAppThunk } from "../../hooks" -import { setStep } from "../redux" /** Publishes testimony and forwards the user to the correct next step */ export const publishTestimonyAndProceed = createAppThunk( diff --git a/components/publish/hooks/resolveBill.ts b/components/publish/hooks/resolveBill.ts index e6e06f7be..aa5a64cc2 100644 --- a/components/publish/hooks/resolveBill.ts +++ b/components/publish/hooks/resolveBill.ts @@ -1,4 +1,5 @@ -import { Bill, getBill } from "../../db" +import { Bill } from "common/bills/types" +import { getBill } from "../../db" import { createAppThunk } from "../../hooks" import { setBill } from "../redux" diff --git a/components/publish/hooks/useFormSync.ts b/components/publish/hooks/useFormSync.ts index 21670868d..2eab974d4 100644 --- a/components/publish/hooks/useFormSync.ts +++ b/components/publish/hooks/useFormSync.ts @@ -1,6 +1,6 @@ import { debounce, isEmpty, isEqual, pickBy } from "lodash" import { useEffect, useMemo, useRef, useState } from "react" -import { UseEditTestimony, WorkingDraft } from "../../db" +import { UseEditTestimony } from "../../db" import { useAppDispatch } from "../../hooks" import { Service, @@ -10,6 +10,7 @@ import { syncTestimony } from "../redux" import { usePublishState } from "./usePublishState" +import { WorkingDraft } from "common/testimony/types" const formDebounceMs = 1000 diff --git a/components/publish/panel/TestimonyFormPanel.tsx b/components/publish/panel/TestimonyFormPanel.tsx index 82644411a..a0e4b834c 100644 --- a/components/publish/panel/TestimonyFormPanel.tsx +++ b/components/publish/panel/TestimonyFormPanel.tsx @@ -1,6 +1,6 @@ import { useEffect } from "react" import { useAuth } from "../../auth" -import { Bill } from "../../db" +import { Bill } from "common/bills/types" import { useAppDispatch } from "../../hooks" import { resolveBill, usePanelStatus } from "../hooks" import { diff --git a/components/publish/redux.ts b/components/publish/redux.ts index ec09f3cd3..99f2314fa 100644 --- a/components/publish/redux.ts +++ b/components/publish/redux.ts @@ -3,19 +3,18 @@ import { createAppThunk } from "components/hooks" import { indexOf, isEqual, uniqBy } from "lodash" import { Literal as L, Static, Union } from "runtypes" import { authChanged } from "../auth/redux" +import { MemberSearchIndexItem, UseEditTestimony } from "../db" +import { containsSocialSecurityNumber } from "../db/testimony/validation" +import { hasDraftChanged } from "../db/testimony" import { - Bill, DraftTestimony, maxTestimonyLength, - MemberSearchIndexItem, Position, Testimony, - UseEditTestimony, WorkingDraft -} from "../db" -import { Maybe } from "../db/common" -import { containsSocialSecurityNumber } from "../db/testimony/validation" -import { hasDraftChanged } from "../db/testimony" +} from "common/testimony/types" +import { Maybe } from "common" +import { Bill } from "common/bills/types" export type Service = UseEditTestimony diff --git a/components/search/bills/BillHit.tsx b/components/search/bills/BillHit.tsx index 3e9c36a8a..bbbf3ac6e 100644 --- a/components/search/bills/BillHit.tsx +++ b/components/search/bills/BillHit.tsx @@ -12,7 +12,7 @@ import Link from "next/link" import styled from "styled-components" import { Card, Col } from "../../bootstrap" import { formatBillId } from "../../formatting" -import { Timestamp } from "firebase/firestore" +import { Timestamp } from "common/types" import { dateInFuture } from "components/db/events" type BillRecord = { diff --git a/components/search/bills/BillSearch.tsx b/components/search/bills/BillSearch.tsx index faadd018e..088e285af 100644 --- a/components/search/bills/BillSearch.tsx +++ b/components/search/bills/BillSearch.tsx @@ -7,7 +7,7 @@ import { SearchBox, useInstantSearch } from "react-instantsearch" -import { currentGeneralCourt } from "functions/src/shared" +import { currentGeneralCourt } from "common/constants" import styled from "styled-components" import TypesenseInstantSearchAdapter from "typesense-instantsearch-adapter" import { Col, Container, Row, Spinner } from "../../bootstrap" diff --git a/components/search/bills/useBillRefinements.tsx b/components/search/bills/useBillRefinements.tsx index cbd560579..0fc415e29 100644 --- a/components/search/bills/useBillRefinements.tsx +++ b/components/search/bills/useBillRefinements.tsx @@ -1,4 +1,4 @@ -import { generalCourts } from "functions/src/shared" +import { generalCourts } from "common/constants" import { RefinementListItem } from "instantsearch.js/es/connectors/refinement-list/connectRefinementList" import { useCallback } from "react" import { useRefinements } from "../useRefinements" diff --git a/components/search/testimony/TestimonyHit.tsx b/components/search/testimony/TestimonyHit.tsx index f9e62c272..4fe199059 100644 --- a/components/search/testimony/TestimonyHit.tsx +++ b/components/search/testimony/TestimonyHit.tsx @@ -1,7 +1,6 @@ import { Hit } from "instantsearch.js" import { maple } from "components/links" import Link from "next/link" -import { Testimony } from "components/db/testimony" import { trimContent } from "components/TestimonyCallout/TestimonyCallout" import { formatBillId } from "components/formatting" import { useBill } from "components/db/bills" @@ -10,6 +9,7 @@ import { Image } from "react-bootstrap" import { useFlags } from "components/featureFlags" import { useAuth } from "components/auth" import { useTranslation } from "next-i18next" +import { Testimony } from "common/testimony/types" export const TestimonyHit = ({ hit }: { hit: Hit }) => { const url = maple.testimony({ publishedId: hit.id }) diff --git a/components/search/testimony/TestimonySearch.tsx b/components/search/testimony/TestimonySearch.tsx index e77b42645..1a7a90c7d 100644 --- a/components/search/testimony/TestimonySearch.tsx +++ b/components/search/testimony/TestimonySearch.tsx @@ -10,7 +10,7 @@ import { StyledTabContent, StyledTabNav } from "components/EditProfilePage/StyledEditProfileComponents" -import { currentGeneralCourt } from "functions/src/shared" +import { currentGeneralCourt } from "common/constants" import { SortByItem } from "instantsearch.js/es/connectors/sort-by/connectSortBy" import { useState } from "react" import { TabContainer, TabPane } from "react-bootstrap" diff --git a/components/shared/FollowButton.tsx b/components/shared/FollowButton.tsx index 87fa5ec81..e088ea320 100644 --- a/components/shared/FollowButton.tsx +++ b/components/shared/FollowButton.tsx @@ -3,7 +3,7 @@ import { useTranslation } from "next-i18next" import { useEffect, useContext } from "react" import { Button } from "react-bootstrap" import { useAuth } from "../auth" -import { Bill } from "../db" +import { Bill } from "common/bills/types" import { TopicQuery, setFollow, setUnfollow } from "./FollowingQueries" import { FollowContext } from "./FollowContext" diff --git a/components/shared/FollowingQueries.tsx b/components/shared/FollowingQueries.tsx index 288da17e2..b549d9066 100644 --- a/components/shared/FollowingQueries.tsx +++ b/components/shared/FollowingQueries.tsx @@ -7,7 +7,7 @@ import { setDoc, where } from "firebase/firestore" -import { Bill } from "../db" +import { Bill } from "common/bills/types" import { firestore } from "../firebase" import { UnfollowModalConfig } from "components/EditProfilePage/UnfollowModal" diff --git a/components/store.tsx b/components/store.tsx index 1024d29f6..ec58f93ea 100644 --- a/components/store.tsx +++ b/components/store.tsx @@ -1,5 +1,4 @@ import { configureStore, isPlain } from "@reduxjs/toolkit" -import { Timestamp } from "firebase/firestore" import React, { useRef } from "react" import { Provider as ReduxProvider } from "react-redux" import { reducer as auth } from "./auth/redux" @@ -10,6 +9,7 @@ import { slice as testimonyDetail } from "./testimony/TestimonyDetailPage" import { rejectionLogger } from "./utils" import { createWrapper } from "next-redux-wrapper" import { cloneDeepWith } from "lodash" +import { Timestamp } from "common/types" const createStore = () => configureStore({ diff --git a/components/testimony/TestimonyContent/TestimonyContent.tsx b/components/testimony/TestimonyContent/TestimonyContent.tsx index 89202c9d9..66cb04ca6 100644 --- a/components/testimony/TestimonyContent/TestimonyContent.tsx +++ b/components/testimony/TestimonyContent/TestimonyContent.tsx @@ -1,4 +1,3 @@ -import { Testimony } from "components/db" import { useMemo } from "react" import styled from "styled-components" import { formatTestimony, formatTestimonyDiff } from "../formatting" diff --git a/components/testimony/TestimonyDetailPage/TestimonyDetail.tsx b/components/testimony/TestimonyDetailPage/TestimonyDetail.tsx index d119be607..e500244f4 100644 --- a/components/testimony/TestimonyDetailPage/TestimonyDetail.tsx +++ b/components/testimony/TestimonyDetailPage/TestimonyDetail.tsx @@ -1,4 +1,3 @@ -import { Position } from "components/db" import { ViewAttachment } from "components/ViewAttachment" import { FC, ImgHTMLAttributes } from "react" import styled from "styled-components" @@ -6,6 +5,7 @@ import { useCurrentTestimonyDetails } from "./testimonyDetailSlice" import { TestimonyContent } from "../TestimonyContent" import { useFlags } from "components/featureFlags" import { useTranslation } from "next-i18next" +import { Position } from "common/testimony/types" const Container = styled.div` font-family: "Nunito"; diff --git a/components/testimony/TestimonyDetailPage/content.ts b/components/testimony/TestimonyDetailPage/content.ts index 3478e8a39..67cb91508 100644 --- a/components/testimony/TestimonyDetailPage/content.ts +++ b/components/testimony/TestimonyDetailPage/content.ts @@ -1,4 +1,4 @@ -import { Position } from "components/db" +import { Position } from "common/testimony/types" export const positionLabels: Record = { neutral: "is neutral on", diff --git a/components/testimony/TestimonyDetailPage/testimonyDetailSlice.ts b/components/testimony/TestimonyDetailPage/testimonyDetailSlice.ts index 06f60cc54..dae021cbc 100644 --- a/components/testimony/TestimonyDetailPage/testimonyDetailSlice.ts +++ b/components/testimony/TestimonyDetailPage/testimonyDetailSlice.ts @@ -1,5 +1,7 @@ import { AnyAction, createSlice, PayloadAction } from "@reduxjs/toolkit" -import { Bill, Profile, Testimony } from "components/db" +import { Profile } from "common/profile/types" +import { Testimony } from "common/testimony/types" +import { Bill } from "common/bills/types" import { TestimonyQuery } from "components/db/api" import { createAppSelector, useAppSelector } from "components/hooks" import { check } from "components/utils" diff --git a/functions/package.json b/functions/package.json index 1faf3fb26..e727475b1 100644 --- a/functions/package.json +++ b/functions/package.json @@ -11,7 +11,7 @@ "enable-cors-dev": "gsutil cors set cors.json gs://digital-testimony-dev.appspot.com", "enable-cors-prod": "gsutil cors set cors.json gs://digital-testimony-prod.appspot.com" }, - "main": "lib/index.js", + "main": "lib/functions/src/index.js", "dependencies": { "@google-cloud/firestore": "^5.0.2", "@google-cloud/pubsub": "^3.0.1", @@ -47,4 +47,4 @@ "typescript": "4.5.5" }, "private": true -} +} \ No newline at end of file diff --git a/functions/src/analysis/predictBillStatus.ts b/functions/src/analysis/predictBillStatus.ts index b44568faf..6e768fa25 100644 --- a/functions/src/analysis/predictBillStatus.ts +++ b/functions/src/analysis/predictBillStatus.ts @@ -1,4 +1,4 @@ -import { BillHistory } from "../bills/types" +import { BillHistory } from "../../../common/bills/types" import { Stage } from "./types" const chamberCommittees = [ diff --git a/functions/src/analysis/types.ts b/functions/src/analysis/types.ts index 910495aa7..5ea03b386 100644 --- a/functions/src/analysis/types.ts +++ b/functions/src/analysis/types.ts @@ -6,7 +6,7 @@ // version: z.number(), // }) -import { Timestamp } from "../firebase" +import { Timestamp } from "../../../common/types" // export type Stage2 = "billIntroduced" | "firstCommittee" diff --git a/functions/src/analysis/updateBillTracker.ts b/functions/src/analysis/updateBillTracker.ts index 3b0259548..a46d5ecf9 100644 --- a/functions/src/analysis/updateBillTracker.ts +++ b/functions/src/analysis/updateBillTracker.ts @@ -1,9 +1,10 @@ import { runWith } from "firebase-functions" import { isEqual } from "lodash" -import { Bill } from "../bills/types" -import { db, Timestamp } from "../firebase" +import { Bill } from "../../../common/bills/types" +import { db } from "../firebase" import { predictBillStatus } from "./predictBillStatus" import { BillTracker } from "./types" +import { Timestamp } from "../../../common/types" const currentTrackerVersion = 1 export const billTrackerPath = (billId: string, court: number) => diff --git a/functions/src/auth/createFakeTestimony.ts b/functions/src/auth/createFakeTestimony.ts index d13740333..ad4195591 100644 --- a/functions/src/auth/createFakeTestimony.ts +++ b/functions/src/auth/createFakeTestimony.ts @@ -1,8 +1,8 @@ import * as functions from "firebase-functions" import { checkAdmin, checkAuth } from "../common" import { auth, db } from "../firebase" -import { Testimony } from "../testimony/types" -import { Timestamp } from "../firebase" +import { Timestamp } from "../../../common/types" +import { Testimony } from "../../../common/testimony/types" // for populating admin module for testing & demonstration--alert--no auth checked here. //@TODO: remove diff --git a/functions/src/auth/modifyAccount.ts b/functions/src/auth/modifyAccount.ts index 93b65409e..82bf4856a 100644 --- a/functions/src/auth/modifyAccount.ts +++ b/functions/src/auth/modifyAccount.ts @@ -4,7 +4,7 @@ import { z } from "zod" import { checkRequestZod, checkAuth, checkAdmin } from "../common" import { setRole } from "." -import { ZRole } from "./types" +import { ZRole } from "../../../common/auth/types" const Request = z.object({ uid: z.string(), diff --git a/functions/src/auth/setRole.ts b/functions/src/auth/setRole.ts index bb91ccb52..874fe8686 100644 --- a/functions/src/auth/setRole.ts +++ b/functions/src/auth/setRole.ts @@ -1,8 +1,8 @@ import type { UserRecord } from "firebase-admin/lib/auth/user-record" import { Undefined } from "runtypes" -import { Profile } from "../profile/types" import { Auth, Database } from "../types" -import { Claim, Role } from "./types" +import { Claim, Role } from "../../../common/auth/types" +import { Profile } from "../../../common/profile/types" export const setRole = async ({ email, diff --git a/functions/src/bills/BillProcessor.ts b/functions/src/bills/BillProcessor.ts index 88af95fdf..e074f02bf 100644 --- a/functions/src/bills/BillProcessor.ts +++ b/functions/src/bills/BillProcessor.ts @@ -5,8 +5,8 @@ import { Committee } from "../committees/types" import { DocUpdate } from "../common" import { db } from "../firebase" import { Member } from "../members/types" -import { Bill } from "./types" -import { currentGeneralCourt } from "../shared" +import { Bill } from "../../../common/bills/types" +import { currentGeneralCourt } from "../../../common/constants" export type BillUpdates = Map> diff --git a/functions/src/bills/backfillTestimonyCounts.ts b/functions/src/bills/backfillTestimonyCounts.ts index a34172059..3566d305d 100644 --- a/functions/src/bills/backfillTestimonyCounts.ts +++ b/functions/src/bills/backfillTestimonyCounts.ts @@ -1,9 +1,9 @@ import { groupBy } from "lodash" import { Array, Optional, Record, String } from "runtypes" import { db } from "../firebase" -import { currentGeneralCourt } from "../shared" -import { Testimony } from "../testimony/types" +import { currentGeneralCourt } from "../../../common/constants" import BillProcessor from "./BillProcessor" +import { Testimony } from "../../../common/testimony/types" export type PartialTestimony = Pick diff --git a/functions/src/bills/bills.ts b/functions/src/bills/bills.ts index f4218d2eb..0a779b2fe 100644 --- a/functions/src/bills/bills.ts +++ b/functions/src/bills/bills.ts @@ -2,7 +2,7 @@ import { isString } from "lodash" import { logFetchError } from "../common" import * as api from "../malegislature" import { createScraper } from "../scraper" -import { Bill, MISSING_TIMESTAMP } from "./types" +import { Bill, MISSING_TIMESTAMP } from "../../../common/bills/types" /** * There are around 8000 documents. With 8 batches per day, 20 parallel diff --git a/functions/src/bills/search.ts b/functions/src/bills/search.ts index cfa7c5c09..882badc5a 100644 --- a/functions/src/bills/search.ts +++ b/functions/src/bills/search.ts @@ -1,7 +1,7 @@ import { isString } from "lodash" import { db } from "../firebase" import { createSearchIndexer } from "../search" -import { Bill, BillTopic } from "./types" +import { Bill, BillTopic } from "../../../common/bills/types" export const { syncToSearchIndex: syncBillToSearchIndex, diff --git a/functions/src/bills/topicParser.ts b/functions/src/bills/topicParser.ts index 19470ec7c..537f69523 100644 --- a/functions/src/bills/topicParser.ts +++ b/functions/src/bills/topicParser.ts @@ -1,4 +1,4 @@ -import { BillTopic, CATEGORIES_BY_TOPIC } from "./types" +import { BillTopic, CATEGORIES_BY_TOPIC } from "../../../common/bills/types" // The ML model will return a list of topics without categories // We need to enrich the topics with the associated topic categories for the hierachical facets diff --git a/functions/src/bills/types.ts b/functions/src/bills/types.ts index 66686c3ba..e69de29bb 100644 --- a/functions/src/bills/types.ts +++ b/functions/src/bills/types.ts @@ -1,341 +0,0 @@ -import { - Array, - InstanceOf, - Number, - Optional, - Record, - Static, - String -} from "runtypes" -import { Id, Maybe, Nullable, NullStr, withDefaults } from "../common" -import { Timestamp } from "../firebase" - -export type BillReference = Static -export const BillReference = Record({ - BillNumber: NullStr, - DocketNumber: NullStr, - GeneralCourtNumber: Number -}) - -export type BillHistoryAction = Static -export const BillHistoryAction = Record({ - Date: String, - Branch: String, - Action: String -}) - -export type BillHistory = Static -export const BillHistory = Array(BillHistoryAction) - -export type CurrentCommittee = Static -export const CommitteeMember = Record({ - id: String, - name: String, - email: NullStr - }), - CurrentCommittee = Record({ - id: String, - name: String, - houseChair: Maybe(CommitteeMember), - senateChair: Maybe(CommitteeMember) - }) - -export type BillContent = Static -export const BillContent = Record({ - Pinslip: Nullable(String), - Title: String, - PrimarySponsor: Nullable(Record({ Name: String })), - DocumentText: Maybe(String), - Cosponsors: Array(Record({ Name: Maybe(String) })) -}) - -export type BillTopic = Static -export const BillTopic = Record({ - category: String, - topic: String -}) - -/** Represents a missing timestamp value. This allows documents without values - * to appear in results when sorting by that value. */ -export const MISSING_TIMESTAMP = Timestamp.fromMillis(0) - -export const TOPICS_BY_CATEGORY = { - Commerce: [ - "Banking and financial institutions regulation", - "Consumer protection", - "Corporation law and goverance", - "Commercial insurance", - "Marketing and advertising", - "Non-profit law and governance", - "Occupational licensing", - "Partnerships and limited liability companies", - "Retail and wholesale trades", - "Securities" - ], - "Crime and Law Enforcement": [ - "Assault and harassment offenses", - "Correctional facilities", - "Crimes against animals and natural resources", - "Crimes against children", - "Criminal investigation, prosecution, interrogation", - "Criminal justice information and records", - "Criminal justice reform", - "Criminal sentencing", - "Firearms and explosives", - "Fraud offenses and financial crimes", - "Property crimes" - ], - "Economics and Public Finance": [ - "Budget process", - "Debt collection", - "Eminent domain", - "Financial literacy", - "Financial services and investments", - "Government contractors", - "Pension and retirement benefits" - ], - Education: [ - "Academic performance and assessments", - "Adult education and literacy", - "Charter and private schools", - "Curriculum and standards", - "Education technology", - "Educational facilities and institutions", - "Elementary and secondary education", - "Higher education", - "Special education", - "Student aid and college costs", - "Teachers and educators", - "Vocational and technical education" - ], - "Emergency Management": [ - "Disaster relief and insurance", - "Emergency communications systems", - "Emergency medical services and trauma care", - "Emergency planning and evacuation", - "Hazards and emergency operations" - ], - Energy: [ - "Energy costs assistance", - "Energy efficiency and conservation", - "Energy infrastructure and storage", - "Energy prices and subsidies", - "Energy research", - "Renewable energy sources" - ], - "Environmental Protection": [ - "Air quality", - "Environmental assessment, monitoring, research", - "Environmental education", - "Environmental health", - "Environmental regulatory procedures", - "Hazardous wastes and toxic substances", - "Pollution control and abatement", - "Soil pollution", - "Trash and recycling", - "Water quality", - "Wetlands", - "Wildlife conservation" - ], - Families: [ - "Adoption and foster care", - "Family planning and birth control", - "Family relationships and status", - "Family services", - "Life insurance", - "Parenting and parental rights" - ], - "Food, Drugs, and Alcohol": [ - "Alcoholic beverages and licenses", - "Drug, alcohol, tobacco use", - "Drug safety, medical device, and laboratory regulation", - "Food industry and services", - "Food service employment", - "Food supply, safety, and labeling", - "Nutrition and diet" - ], - "Government Operations and Elections": [ - "Census and government statistics", - "Government information and archives", - "Government studies and investigations", - "Government trust funds", - "Lobbying and campaign finance", - 'Municipality oversight and "home rule petitions"', - "Political advertising", - "Public-private partnerships", - "Voting and elections" - ], - Healthcare: [ - "Alternative treatments", - "Dental care", - "Health care costs", - "Health facilities and institutions", - "Health information and medical records", - "Health insurance and coverage", - "Health technology, devices, supplies", - "Healthcare workforce", - "Medical research", - "Mental health", - "Prescription drugs", - "Sex and reproductive health", - "Substance use disorder and addiction", - "Telehealth", - "Veterinary services and pets" - ], - "Housing and Community Development": [ - "Community life and organization", - "Cooperative and condominium housing", - "Homelessness and emergency shelter", - "Housing discrimination", - "Housing finance and home ownership", - "Housing for the elderly and disabled", - "Housing industry and standards", - "Housing supply and affordability", - "Landlord and tenant", - "Low- and moderate-income housing", - "Residential rehabilitation and home repair" - ], - "Immigrants and Foreign Nationals": [ - "Immigrant health and welfare", - "Refugees, asylum, displaced persons", - "Right to shelter", - "Translation and language services" - ], - "Labor and Employment": [ - "Employee benefits", - "Employment discrimination", - "Employee leave", - "Employee pensions", - "Employee performance", - "Migrant, seasonal, agricultural labor", - "Self-employment", - "Temporary and part-time employment", - "Workers' compensation", - "Workforce development and employment training", - "Worker safety and health", - "Youth employment and child labor" - ], - "Law and Judiciary": [ - "Civil disturbances", - "Evidence and witnesses", - "Judicial and court records", - "Judicial review and appeals", - "Jurisdiction and venue", - "Legal fees and court costs" - ], - "Public and Natural Resources": [ - "Agriculture and aquaculture", - "Coastal zones and ocean", - "Forests, forestry, trees", - "Monuments and memorials", - "Watershed and water resources", - "Wildlife" - ], - "Social Services": [ - "Child care and development", - "Domestic violence and child abuse", - "Food assistance and relief", - "Home and outpatient care", - "Social work, volunteer service, charitable organizations", - "Unemployment", - "Urban and suburban affairs and development", - "Veterans' education, employment, rehabilitation", - "Veterans' loans, housing, homeless programs", - "Veterans' medical care" - ], - "Sports and Recreation": [ - "Art and culture", - "Gambling and lottery", - "Hunting and fishing", - "Outdoor recreation", - "Professional sports, stadiums and arenas", - "Public parks", - "Sports and recreation facilities" - ], - Taxation: [ - "Capital gains tax", - "Corporate tax", - "Estate tax", - "Excise tax", - "Gift tax", - "Income tax", - "Payroll and emplyoment tax", - "Property tax", - "Sales tax", - "Tax-exempt organizations", - "Transfer and inheritance taxes" - ], - "Technology and Communications": [ - "Advanced technology and technological innovations", - "Atmospheric science and weather", - "Broadband and internet access", - "Computers and information technology", - "Cybersecurity and identity theft", - "Data privacy", - "Emerging technology (artificial intelligence, blockchain, etc.)", - "Genetics", - "Internet, web applications, social media", - "Photography and imaging", - "Telecommunication rates and fees", - "Telephone and wireless communication" - ], - "Transportation and Public Works": [ - "Aviation and airports", - "Highways and roads", - "MBTA & public transportation", - "Public utilities and utility rates", - "Railroads", - "Vehicle insurance and repairs", - "Water storage", - "Water use and supply" - ] -} -export const CATEGORIES_BY_TOPIC = Object.entries(TOPICS_BY_CATEGORY).reduce( - (acc, [category, topics]) => { - topics.forEach(topic => { - acc[topic] = category - }) - - return acc - }, - {} as { [key: string]: string } -) - -export type Bill = Static -export const Bill = withDefaults( - Record({ - id: Id, - court: Number, - content: BillContent, - cosponsorCount: Number, - testimonyCount: Number, - endorseCount: Number, - neutralCount: Number, - opposeCount: Number, - nextHearingAt: Optional(InstanceOf(Timestamp)), - nextHearingId: Optional(Id), - latestTestimonyAt: Optional(InstanceOf(Timestamp)), - latestTestimonyId: Optional(Id), - fetchedAt: InstanceOf(Timestamp), - history: BillHistory, - similar: Array(Id), - currentCommittee: Optional(CurrentCommittee), - city: Optional(String), - topics: Optional(Array(BillTopic)), - summary: Optional(String) - }), - { - court: 0, - cosponsorCount: 0, - testimonyCount: 0, - endorseCount: 0, - neutralCount: 0, - opposeCount: 0, - latestTestimonyAt: MISSING_TIMESTAMP, - nextHearingAt: MISSING_TIMESTAMP, - fetchedAt: MISSING_TIMESTAMP, - history: [], - similar: [], - topics: [] - } -) diff --git a/functions/src/bills/updateBillReferences.ts b/functions/src/bills/updateBillReferences.ts index 26ceeee77..be5a9ed31 100644 --- a/functions/src/bills/updateBillReferences.ts +++ b/functions/src/bills/updateBillReferences.ts @@ -1,9 +1,10 @@ import { difference, flatten, flattenDeep } from "lodash" import { Hearing } from "../events/types" -import { db, FieldValue, Timestamp } from "../firebase" +import { db, FieldValue } from "../firebase" import { parseApiDateTime } from "../malegislature" import { Member, MemberReference } from "../members/types" import BillProcessor, { BillUpdates } from "./BillProcessor" +import { Timestamp } from "../../../common/types" /** * Updates references to other entities for each bill. diff --git a/functions/src/cities/types.ts b/functions/src/cities/types.ts index d224b3636..a10a8e850 100644 --- a/functions/src/cities/types.ts +++ b/functions/src/cities/types.ts @@ -1,6 +1,6 @@ import { Array, InstanceOf, Record, Static, String } from "runtypes" import { Id, NullStr } from "../common" -import { Timestamp } from "../firebase" +import { Timestamp } from "../../../common/types" export type CityListing = Static export const CityListing = Array(String) diff --git a/functions/src/committees/types.ts b/functions/src/committees/types.ts index e18a13048..b3c7f595a 100644 --- a/functions/src/committees/types.ts +++ b/functions/src/committees/types.ts @@ -8,7 +8,7 @@ import { Optional } from "runtypes" import { Id, Nullable } from "../common" -import { Timestamp } from "../firebase" +import { Timestamp } from "../../../common/types" export type CommitteeListItem = Static export const CommitteeListItem = Record({ diff --git a/functions/src/committees/updateCommitteeRosters.ts b/functions/src/committees/updateCommitteeRosters.ts index 2720b7c1f..c6e8c5428 100644 --- a/functions/src/committees/updateCommitteeRosters.ts +++ b/functions/src/committees/updateCommitteeRosters.ts @@ -3,7 +3,7 @@ import { DocUpdate } from "../common" import { db } from "../firebase" import { Member } from "../members/types" import { Committee } from "./types" -import { currentGeneralCourt } from "../shared" +import { currentGeneralCourt } from "../../../common/constants" /** Updates the list of members in each committee. */ export const updateCommitteeRosters = runWith({ timeoutSeconds: 120 }) diff --git a/functions/src/events/scrapeEvents.ts b/functions/src/events/scrapeEvents.ts index 0df2de036..ce867472b 100644 --- a/functions/src/events/scrapeEvents.ts +++ b/functions/src/events/scrapeEvents.ts @@ -3,7 +3,7 @@ import { DateTime } from "luxon" import { JSDOM } from "jsdom" import { AssemblyAI } from "assemblyai" import { logFetchError } from "../common" -import { db, Timestamp } from "../firebase" +import { db } from "../firebase" import * as api from "../malegislature" import { BaseEvent, @@ -16,10 +16,11 @@ import { SpecialEvent, SpecialEventContent } from "./types" -import { currentGeneralCourt } from "../shared" +import { currentGeneralCourt } from "../../../common/constants" import { randomBytes } from "node:crypto" import { sha256 } from "js-sha256" import { withinCutoff } from "./helpers" +import { Timestamp } from "../../../common/types" abstract class EventScraper { private schedule diff --git a/functions/src/events/types.ts b/functions/src/events/types.ts index b08262508..00e56b6ef 100644 --- a/functions/src/events/types.ts +++ b/functions/src/events/types.ts @@ -12,7 +12,7 @@ import { Union } from "runtypes" import { Id } from "../common" -import { Timestamp } from "../firebase" +import { Timestamp } from "../../../common/types" const Nullable = (r: T) => r.Or(Null) diff --git a/functions/src/firebase.ts b/functions/src/firebase.ts index c37fe830b..6a6cfcfbe 100644 --- a/functions/src/firebase.ts +++ b/functions/src/firebase.ts @@ -5,9 +5,7 @@ export const db = admin.firestore() export const storage = admin.storage() export const auth = admin.auth() export { admin } -// Gotta use the same Timestamp class as the admin package. -export const Timestamp = admin.firestore.Timestamp -export type Timestamp = admin.firestore.Timestamp + export const FieldValue = admin.firestore.FieldValue export type FieldValue = admin.firestore.FieldValue export const FieldPath = admin.firestore.FieldPath diff --git a/functions/src/malegislature.ts b/functions/src/malegislature.ts index 3771830d8..f5db40896 100644 --- a/functions/src/malegislature.ts +++ b/functions/src/malegislature.ts @@ -3,7 +3,7 @@ import { isString } from "lodash" import { DateTime } from "luxon" import { Array } from "runtypes" import { create as createRootCas } from "ssl-root-cas" -import { BillHistory, BillReference } from "./bills/types" +import { BillHistory, BillReference } from "../../common/bills/types" import { CityBills, CityListing } from "./cities/types" import { CommitteeContent, CommitteeListing } from "./committees/types" import { @@ -12,8 +12,9 @@ import { SessionContent, SpecialEventContent } from "./events/types" -import { Timestamp } from "./firebase" +import { Timestamp } from "../../common/types" import { MemberContent } from "./members/types" +import path from "path" /** * The MA Legislature website's SSL certificate only contains the first @@ -28,7 +29,12 @@ function addCertificates() { const rootCas = createRootCas() // rootCas.addFile(__dirname + "/ssl/DigiCert TLS RSA SHA256 2020 CA1.pem") rootCas.addFile( - __dirname + "/ssl/DigiCertGlobalG2TLSRSASHA2562020CA1.crt.pem" + path.resolve( + process.cwd(), + "lib", + "ssl", + "DigiCertGlobalG2TLSRSASHA2562020CA1.crt.pem" + ) ) require("https").globalAgent.options.ca = rootCas } diff --git a/functions/src/members/createMemberSearchIndex.ts b/functions/src/members/createMemberSearchIndex.ts index 289a6e804..fe3fa3f13 100644 --- a/functions/src/members/createMemberSearchIndex.ts +++ b/functions/src/members/createMemberSearchIndex.ts @@ -1,6 +1,6 @@ import { pubsub } from "firebase-functions" import { db } from "../firebase" -import { currentGeneralCourt } from "../shared" +import { currentGeneralCourt } from "../../../common/constants" /** Create a document that aggregates all legislative members for easier * searching on the client. */ diff --git a/functions/src/members/types.ts b/functions/src/members/types.ts index 68225e170..a87916075 100644 --- a/functions/src/members/types.ts +++ b/functions/src/members/types.ts @@ -1,6 +1,6 @@ import { Array, InstanceOf, Number, Record, Static, String } from "runtypes" import { Id, NullStr } from "../common" -import { Timestamp } from "../firebase" +import { Timestamp } from "../../../common/types" export type MemberReference = Static export const MemberReference = Record({ MemberCode: String }) diff --git a/functions/src/notifications/cleanupNotifications.ts b/functions/src/notifications/cleanupNotifications.ts index f79764825..327b52757 100644 --- a/functions/src/notifications/cleanupNotifications.ts +++ b/functions/src/notifications/cleanupNotifications.ts @@ -1,6 +1,6 @@ import * as functions from "firebase-functions" import * as admin from "firebase-admin" -import { Timestamp } from "../firebase" +import { Timestamp } from "../../../common/types" const RETENTION_PERIOD_DAYS = 60 diff --git a/functions/src/notifications/deliverNotifications.ts b/functions/src/notifications/deliverNotifications.ts index 1b196fac7..fc2242221 100644 --- a/functions/src/notifications/deliverNotifications.ts +++ b/functions/src/notifications/deliverNotifications.ts @@ -2,7 +2,7 @@ import * as functions from "firebase-functions" import * as admin from "firebase-admin" import * as handlebars from "handlebars" import * as fs from "fs" -import { Timestamp } from "../firebase" +import { Timestamp } from "../../../common/types" import { getNextDigestAt, getNotificationStartDate } from "./helpers" import { startOfDay } from "date-fns" import { TestimonySubmissionNotificationFields, Profile } from "./types" @@ -14,7 +14,7 @@ import { } from "./emailTypes" import { prepareHandlebars } from "../email/handlebarsHelpers" import { getAuth } from "firebase-admin/auth" -import { Frequency } from "../auth/types" +import { Frequency } from "../../../common/auth/types" const NUM_BILLS_TO_DISPLAY = 4 const NUM_USERS_TO_DISPLAY = 4 diff --git a/functions/src/notifications/emailTypes.ts b/functions/src/notifications/emailTypes.ts index 90c2efc30..16f7d4413 100644 --- a/functions/src/notifications/emailTypes.ts +++ b/functions/src/notifications/emailTypes.ts @@ -1,4 +1,4 @@ -import { Frequency } from "../auth/types" +import { Frequency } from "../../../common/auth/types" export type BillDigest = { billId: string diff --git a/functions/src/notifications/helpers.test.ts b/functions/src/notifications/helpers.test.ts index 3166d23bb..f6472c8f1 100644 --- a/functions/src/notifications/helpers.test.ts +++ b/functions/src/notifications/helpers.test.ts @@ -1,6 +1,6 @@ import { getNextDigestAt, getNotificationStartDate } from "./helpers" -import { Timestamp } from "../firebase" -import { Frequency } from "../auth/types" +import { Timestamp } from "../../../common/types" +import { Frequency } from "../../../common/auth/types" describe("getNextDigestAt", () => { beforeEach(() => { diff --git a/functions/src/notifications/helpers.ts b/functions/src/notifications/helpers.ts index 52c5efaf2..35665cdfc 100644 --- a/functions/src/notifications/helpers.ts +++ b/functions/src/notifications/helpers.ts @@ -1,5 +1,5 @@ -import { Timestamp } from "../firebase" -import { Frequency } from "../auth/types" +import { Timestamp } from "../../../common/types" +import { Frequency } from "../../../common/auth/types" import { startOfDay, addMonths, diff --git a/functions/src/notifications/populateBillHistoryNotificationEvents.ts b/functions/src/notifications/populateBillHistoryNotificationEvents.ts index 8c3055b76..e455570a2 100644 --- a/functions/src/notifications/populateBillHistoryNotificationEvents.ts +++ b/functions/src/notifications/populateBillHistoryNotificationEvents.ts @@ -6,7 +6,7 @@ // Import necessary Firebase modules import * as functions from "firebase-functions" import * as admin from "firebase-admin" -import { Timestamp } from "../firebase" +import { Timestamp } from "../../../common/types" import { BillHistoryUpdateNotification } from "./types" // Get a reference to the Firestore database diff --git a/functions/src/notifications/populateTestimonySubmissionNotificationEvents.ts b/functions/src/notifications/populateTestimonySubmissionNotificationEvents.ts index 500214a4a..047eb8fb0 100644 --- a/functions/src/notifications/populateTestimonySubmissionNotificationEvents.ts +++ b/functions/src/notifications/populateTestimonySubmissionNotificationEvents.ts @@ -6,7 +6,7 @@ // Import necessary Firebase modules import * as functions from "firebase-functions" import * as admin from "firebase-admin" -import { Timestamp } from "../firebase" +import { Timestamp } from "../../../common/types" import { TestimonySubmissionNotification } from "./types" // Get a reference to the Firestore database diff --git a/functions/src/notifications/publishNotifications.ts b/functions/src/notifications/publishNotifications.ts index 81a4c977b..dbf185d4e 100644 --- a/functions/src/notifications/publishNotifications.ts +++ b/functions/src/notifications/publishNotifications.ts @@ -6,7 +6,7 @@ // Import necessary Firebase modules import * as functions from "firebase-functions" import * as admin from "firebase-admin" -import { Timestamp } from "../firebase" +import { Timestamp } from "../../../common/types" import { BillHistoryUpdateNotification, BillHistoryUpdateNotificationFields, diff --git a/functions/src/notifications/types.ts b/functions/src/notifications/types.ts index b254a3960..17cf8d9b6 100644 --- a/functions/src/notifications/types.ts +++ b/functions/src/notifications/types.ts @@ -1,6 +1,6 @@ -import { Frequency } from "../auth/types" -import { BillHistory } from "../bills/types" -import { Timestamp } from "../firebase" +import { Frequency } from "../../../common/auth/types" +import { BillHistory } from "../../../common/bills/types" +import { Timestamp } from "../../../common/types" export interface Notification { type: string diff --git a/functions/src/profile/finishSignup.ts b/functions/src/profile/finishSignup.ts index 364a1edff..d2e3e6c22 100644 --- a/functions/src/profile/finishSignup.ts +++ b/functions/src/profile/finishSignup.ts @@ -3,7 +3,7 @@ import { db, auth } from "../firebase" import { z } from "zod" import { checkRequestZod, checkAuth } from "../common" import { setRole } from "../auth" -import { Role } from "../auth/types" +import { Role } from "../../../common/auth/types" const CreateProfileRequest = z.object({ requestedRole: z.enum(["user", "organization", "pendingUpgrade"]) diff --git a/functions/src/profile/types.ts b/functions/src/profile/types.ts deleted file mode 100644 index 15437ef04..000000000 --- a/functions/src/profile/types.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { - Boolean, - Dictionary, - Optional, - Array, - Record, - Static, - String, - Null -} from "runtypes" -import { Role } from "../auth/types" - -export const ProfileMember = Record({ - district: String, - id: String, - name: String -}) -export type ProfileMember = Static - -export const Profile = Record({ - fullName: Optional(String), - role: Optional(Role), - representative: Optional(ProfileMember), - senator: Optional(ProfileMember), - public: Optional(Boolean), - about: Optional(String), - social: Optional(Dictionary(String)), - organization: Optional(Boolean), - orgCategories: Optional(Array(String.Or(Null))) -}) -export type Profile = Static diff --git a/functions/src/scraper.ts b/functions/src/scraper.ts index deda99093..e530b0f26 100644 --- a/functions/src/scraper.ts +++ b/functions/src/scraper.ts @@ -1,8 +1,10 @@ import axios, { AxiosError } from "axios" import { logger, runWith } from "firebase-functions" import { last } from "lodash" -import { db, DocumentData, FieldValue, Timestamp } from "./firebase" -import { currentGeneralCourt } from "./shared" +import { db, FieldValue } from "./firebase" +import { currentGeneralCourt } from "../../common/constants" +import { Timestamp } from "../../common/types" +import { DocumentData } from "firebase-admin/firestore" /** Batch documents trigger the batch fetch function to scrape `ids` */ type Batch = { diff --git a/functions/src/search/SearchIndexer.ts b/functions/src/search/SearchIndexer.ts index 7fc7305ff..0293d943d 100644 --- a/functions/src/search/SearchIndexer.ts +++ b/functions/src/search/SearchIndexer.ts @@ -4,11 +4,11 @@ import hash from "object-hash" import Collection from "typesense/lib/Typesense/Collection" import { ImportResponse } from "typesense/lib/Typesense/Documents" import { ImportError, ObjectNotFound } from "typesense/lib/Typesense/Errors" -import { db, DocumentSnapshot, QuerySnapshot } from "../firebase" +import { db, QuerySnapshot, DocumentSnapshot } from "../firebase" import { createClient } from "./client" import { CollectionConfig } from "./config" import { z } from "zod" -import { Timestamp } from "../firebase" +import { Timestamp } from "../../../common/types" export const BackfillConfig = z.object({ numBatches: z.number().positive().optional() diff --git a/functions/src/testimony/attachments.ts b/functions/src/testimony/attachments.ts index 093b80a12..daaf58cfd 100644 --- a/functions/src/testimony/attachments.ts +++ b/functions/src/testimony/attachments.ts @@ -1,7 +1,7 @@ import { nanoid } from "nanoid" import { fail, Maybe } from "../common" import { File, storage } from "../firebase" -import { DraftTestimony } from "./types" +import { DraftTestimony } from "../../../common/testimony/types" export type PublishedAttachmentState = { prevId: string | null diff --git a/functions/src/testimony/deleteTestimony.ts b/functions/src/testimony/deleteTestimony.ts index 5e6e464ae..2313f1843 100644 --- a/functions/src/testimony/deleteTestimony.ts +++ b/functions/src/testimony/deleteTestimony.ts @@ -1,7 +1,7 @@ import { DocumentSnapshot } from "@google-cloud/firestore" import { https, logger } from "firebase-functions" import { Record } from "runtypes" -import { Bill } from "../bills/types" +import { Bill } from "../../../common/bills/types" import { checkAuth, checkRequest, @@ -12,7 +12,7 @@ import { } from "../common" import { db, FieldValue } from "../firebase" import { Attachments } from "./attachments" -import { DraftTestimony, Testimony } from "./types" +import { DraftTestimony, Testimony } from "../../../common/testimony/types" import { updateTestimonyCounts } from "./updateTestimonyCounts" const DeleteTestimonyRequest = Record({ diff --git a/functions/src/testimony/publishTestimony.ts b/functions/src/testimony/publishTestimony.ts index 33f0364ec..3e87db23b 100644 --- a/functions/src/testimony/publishTestimony.ts +++ b/functions/src/testimony/publishTestimony.ts @@ -2,12 +2,13 @@ import { DocumentReference, DocumentSnapshot } from "@google-cloud/firestore" import { https, logger } from "firebase-functions" import { nanoid } from "nanoid" import { Record } from "runtypes" -import { Bill } from "../bills/types" +import { Bill } from "../../../common/bills/types" import { checkAuth, checkRequest, DocUpdate, fail, Id } from "../common" -import { db, FieldValue, Timestamp } from "../firebase" -import { supportedGeneralCourts } from "../shared" +import { db, FieldValue } from "../firebase" +import { Timestamp } from "../../../common/types" +import { supportedGeneralCourts } from "../../../common/constants" import { Attachments, PublishedAttachmentState } from "./attachments" -import { DraftTestimony, Testimony } from "./types" +import { DraftTestimony, Testimony } from "../../../common/testimony/types" import { updateTestimonyCounts } from "./updateTestimonyCounts" const PublishTestimonyRequest = Record({ diff --git a/functions/src/testimony/resolveReport.ts b/functions/src/testimony/resolveReport.ts index b3170c5dc..d1f1238e6 100644 --- a/functions/src/testimony/resolveReport.ts +++ b/functions/src/testimony/resolveReport.ts @@ -4,8 +4,8 @@ import { z } from "zod" import { fail, checkRequestZod, checkAuth, checkAdmin } from "../common" // import { performDeleteTestimony } from "./deleteTestimony" import { first } from "lodash" -import { Testimony } from "./types" -import { Profile } from "../profile/types" +import { Profile } from "../../../common/profile/types" +import { Testimony } from "../../../common/testimony/types" export type Request = z.infer const Request = z.object({ diff --git a/functions/src/testimony/search.ts b/functions/src/testimony/search.ts index 264c41eed..484e107e9 100644 --- a/functions/src/testimony/search.ts +++ b/functions/src/testimony/search.ts @@ -1,6 +1,9 @@ import { db } from "../firebase" import { createSearchIndexer } from "../search" -import { Testimony, TestimonySearchRecord } from "./types" +import { + Testimony, + TestimonySearchRecord +} from "../../../common/testimony/types" export const { syncToSearchIndex: syncTestimonyToSearchIndex, diff --git a/functions/src/testimony/types.ts b/functions/src/testimony/types.ts deleted file mode 100644 index bf5e8e4b5..000000000 --- a/functions/src/testimony/types.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { - Boolean, - InstanceOf, - Literal as L, - Number, - Optional, - Record as R, - String as RtString, - Static, - Union -} from "runtypes" -import { Role } from "../auth/types" -import { Id, Maybe, withDefaults } from "../common" -import { Timestamp } from "../firebase" - -const maxTestimonyLength = 10_000 - -const BaseTestimony = R({ - billId: Id, - court: Number, - position: Union(L("endorse"), L("oppose"), L("neutral")), - content: RtString.withConstraint( - s => s.length > 0 && s.length < maxTestimonyLength - ), - attachmentId: Maybe(RtString), - /** Only present if testimony was edited (has a version greater than 1) */ - editReason: Maybe(RtString) -}) - -export type Testimony = Static -export const Testimony = withDefaults( - BaseTestimony.extend({ - id: Id, - authorUid: Id, - authorDisplayName: RtString, - authorRole: Role, - billTitle: RtString, - version: Number, - public: Boolean, - publishedAt: InstanceOf(Timestamp), - updatedAt: InstanceOf(Timestamp), - representativeId: Optional(RtString), - senatorId: Optional(RtString), - senatorDistrict: Optional(RtString), - representativeDistrict: Optional(RtString), - draftAttachmentId: Maybe(RtString), - fullName: RtString - }), - { - authorRole: "user", - // ID is backfilled - id: "unknown", - publishedAt: Timestamp.fromMillis(0), - updatedAt: Timestamp.fromMillis(0), - public: true, - authorDisplayName: "Anonymous", - fullName: "Anonymous", - billTitle: "" - } -) - -export type DraftTestimony = Static -export const DraftTestimony = BaseTestimony.extend({ - publishedVersion: Optional(Number) -}) - -export const countsByPositions = { - endorse: "endorseCount", - neutral: "neutralCount", - oppose: "opposeCount" -} as const - -export const TestimonySearchRecord = R({ - id: RtString, - billId: RtString, - court: Number, - position: Union(L("endorse"), L("oppose"), L("neutral")), - content: RtString, - authorUid: RtString, - authorRole: RtString, - authorDisplayName: RtString, - version: Number, - public: Boolean, - publishedAt: Number, - updatedAt: Number, - fullName: RtString -}) -export type TestimonySearchRecord = Static diff --git a/functions/src/testimony/updateTestimonyCounts.ts b/functions/src/testimony/updateTestimonyCounts.ts index 9c1a06e49..61959ba11 100644 --- a/functions/src/testimony/updateTestimonyCounts.ts +++ b/functions/src/testimony/updateTestimonyCounts.ts @@ -1,5 +1,5 @@ -import { Bill } from "../bills/types" -import { countsByPositions, Testimony } from "./types" +import { Bill } from "../../../common/bills/types" +import { countsByPositions, Testimony } from "../../../common/testimony/types" type FieldUpdate = Pick< Bill, diff --git a/functions/src/webhooks/transcription.ts b/functions/src/webhooks/transcription.ts index e156bdfed..215de4f69 100644 --- a/functions/src/webhooks/transcription.ts +++ b/functions/src/webhooks/transcription.ts @@ -1,6 +1,7 @@ import * as functions from "firebase-functions" import { AssemblyAI } from "assemblyai" -import { db, Timestamp } from "../firebase" +import { db } from "../firebase" +import { Timestamp } from "../../../common/types" import { sha256 } from "js-sha256" export const transcription = functions diff --git a/functions/tsconfig.json b/functions/tsconfig.json index 59ff18938..abaa757a1 100644 --- a/functions/tsconfig.json +++ b/functions/tsconfig.json @@ -10,5 +10,5 @@ "target": "es2017", "skipLibCheck": true }, - "include": ["src/**/*"] + "include": ["src/**/*", "../common"] } diff --git a/package.json b/package.json index a0b3465a8..a9749103d 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,7 @@ "@fortawesome/fontawesome-svg-core": "^6.5.1", "@fortawesome/free-solid-svg-icons": "^6.5.1", "@fortawesome/react-fontawesome": "^0.2.0", + "@google-cloud/firestore": "^7.11.1", "@popperjs/core": "^2.11.8", "@react-aria/ssr": "^3.2.0", "@react-aria/utils": "^3.13.1", diff --git a/pages/api/users/[uid]/testimony/[tid]/report.ts b/pages/api/users/[uid]/testimony/[tid]/report.ts index 43f68530d..19720d961 100644 --- a/pages/api/users/[uid]/testimony/[tid]/report.ts +++ b/pages/api/users/[uid]/testimony/[tid]/report.ts @@ -7,8 +7,7 @@ import { db } from "../../../../../../components/server-api/init-firebase-admin" import { ensureAuthenticated } from "../../../../../../components/server-api/middleware-fns" - -export const Timestamp = admin.firestore.Timestamp +import { Timestamp } from "common/types" export default async function handler( req: NextApiRequest, diff --git a/pages/bills/[court]/[billId].tsx b/pages/bills/[court]/[billId].tsx index 288207655..c5d1984c7 100644 --- a/pages/bills/[court]/[billId].tsx +++ b/pages/bills/[court]/[billId].tsx @@ -2,7 +2,7 @@ import { dbService } from "components/db/api" import { GetServerSideProps } from "next" import { z } from "zod" import { BillDetails } from "../../../components/bill" -import { Bill } from "../../../components/db" +import { Bill } from "common/bills/types" import { createPage } from "../../../components/page" import { usePublishService } from "../../../components/publish/hooks" import { serverSideTranslations } from "next-i18next/serverSideTranslations" diff --git a/pages/testimony/[...testimonyDetail].tsx b/pages/testimony/[...testimonyDetail].tsx index c83f64de8..f02b8a06a 100644 --- a/pages/testimony/[...testimonyDetail].tsx +++ b/pages/testimony/[...testimonyDetail].tsx @@ -1,4 +1,4 @@ -import { Testimony } from "components/db" +import { Testimony } from "common/testimony/types" import { dbService } from "components/db/api" import { wrapper } from "components/store" import { diff --git a/scripts/firebase-admin/backfillBillNotificationEvents.ts b/scripts/firebase-admin/backfillBillNotificationEvents.ts index 68400b815..2cbac6d66 100644 --- a/scripts/firebase-admin/backfillBillNotificationEvents.ts +++ b/scripts/firebase-admin/backfillBillNotificationEvents.ts @@ -1,4 +1,4 @@ -import { Timestamp } from "functions/src/firebase" +import { Timestamp } from "common/types" import { Script } from "./types" import { BillHistoryUpdateNotification } from "functions/src/notifications/types" import { Record, Number } from "runtypes" diff --git a/scripts/firebase-admin/backfillNextDigestAt.ts b/scripts/firebase-admin/backfillNextDigestAt.ts index 6102b90a9..594eca373 100644 --- a/scripts/firebase-admin/backfillNextDigestAt.ts +++ b/scripts/firebase-admin/backfillNextDigestAt.ts @@ -8,8 +8,8 @@ has been added to the profiles collection. */ +import { Profile } from "common/profile/types" import { getNextDigestAt } from "../../functions/src/notifications/helpers" -import { Profile } from "../../components/db/profile/types" import { Script } from "./types" import { Boolean, Optional, Record } from "runtypes" diff --git a/scripts/firebase-admin/generateBill.ts b/scripts/firebase-admin/generateBill.ts index eb15b71e3..6faa6b52a 100644 --- a/scripts/firebase-admin/generateBill.ts +++ b/scripts/firebase-admin/generateBill.ts @@ -1,8 +1,7 @@ -// import { Timestamp } from "firebase/firestore" -import { Timestamp } from "../../functions/src/firebase" +import { Timestamp } from "../../common/types" import { Record, String, Number } from "runtypes" import { Script } from "./types" -import { Bill, BillContent } from "../../functions/src/bills/types" +import { Bill, BillContent } from "../../common/bills/types" const Args = Record({ court: Number, @@ -20,9 +19,13 @@ export const script: Script = async ({ db, args }) => { const newBillContent: BillContent = { Pinslip: "", Title: "", - PrimarySponsor: null, + PrimarySponsor: undefined, DocumentText: "", - Cosponsors: [] + Cosponsors: [], + BillNumber: "", + DocketNumber: "", + GeneralCourtNumber: 0, + LegislationTypeName: "" } const newBill: Bill = { diff --git a/scripts/firebase-admin/generateBillHistory.ts b/scripts/firebase-admin/generateBillHistory.ts index 6bc4ffaea..0b55dfeef 100644 --- a/scripts/firebase-admin/generateBillHistory.ts +++ b/scripts/firebase-admin/generateBillHistory.ts @@ -1,7 +1,8 @@ -import { Timestamp, FieldValue } from "../../functions/src/firebase" +import { Timestamp } from "../../common/types" import { Record, String, Number } from "runtypes" import { Script } from "./types" -import { BillHistoryAction } from "../../functions/src/bills/types" +import { BillHistoryAction } from "../../common/bills/types" +import { FieldValue } from "functions/src/firebase" const Args = Record({ court: Number, diff --git a/scripts/firebase-admin/seedActiveTopicSubscriptions.ts b/scripts/firebase-admin/seedActiveTopicSubscriptions.ts index 708dc5b4a..9a96011a9 100644 --- a/scripts/firebase-admin/seedActiveTopicSubscriptions.ts +++ b/scripts/firebase-admin/seedActiveTopicSubscriptions.ts @@ -2,7 +2,7 @@ import { Script } from "./types" import { listAllUsers } from "./list-all-users" import { addTopicSubscription } from "functions/src/subscriptions/addTopicSubscription" import * as admin from "firebase-admin" -import { Timestamp } from "../../functions/src/firebase" +import { Timestamp } from "../../common/types" /** Seed users with activeTopicSubscriptions */ export const script: Script = async ({ db, auth }) => { diff --git a/scripts/firebase-admin/seedTopicEvents.ts b/scripts/firebase-admin/seedTopicEvents.ts index 13b326c7f..d033e5312 100644 --- a/scripts/firebase-admin/seedTopicEvents.ts +++ b/scripts/firebase-admin/seedTopicEvents.ts @@ -1,6 +1,6 @@ import { Script } from "./types" import * as admin from "firebase-admin" -import { Timestamp } from "functions/src/firebase" +import { Timestamp } from "common/types" /** Seed Firestore with topic events */ export const script: Script = async ({ db }) => { diff --git a/scripts/firebase-admin/sendTestEmail.ts b/scripts/firebase-admin/sendTestEmail.ts index 3e1b27b1e..b2f78b5ca 100644 --- a/scripts/firebase-admin/sendTestEmail.ts +++ b/scripts/firebase-admin/sendTestEmail.ts @@ -10,8 +10,8 @@ import { UserDigest } from "functions/src/notifications/emailTypes" import { Record, String } from "runtypes" -import { Timestamp } from "functions/src/firebase" -import { Frequency } from "components/auth" +import { Timestamp } from "common/types" +import { Frequency } from "common/auth/types" const path = require("path") diff --git a/scripts/firebase-admin/setRole.ts b/scripts/firebase-admin/setRole.ts index be3750939..b69c1fc03 100644 --- a/scripts/firebase-admin/setRole.ts +++ b/scripts/firebase-admin/setRole.ts @@ -1,6 +1,6 @@ import { Record, String } from "runtypes" import { setRole } from "../../functions/src/auth" -import { Role } from "../../functions/src/auth/types" +import { Role } from "common/auth/types" import { Script } from "./types" const Args = Record({ email: String, role: Role }) diff --git a/scripts/firebase-admin/touchBills.ts b/scripts/firebase-admin/touchBills.ts index 6e2e434e7..5e92cce5c 100644 --- a/scripts/firebase-admin/touchBills.ts +++ b/scripts/firebase-admin/touchBills.ts @@ -1,4 +1,4 @@ -import { Timestamp } from "../../functions/src/firebase" +import { Timestamp } from "../../common/types" import { Record, String, Number } from "runtypes" import { Script } from "./types" diff --git a/scripts/firebase-admin/updateDisplayNames.ts b/scripts/firebase-admin/updateDisplayNames.ts index 721698b9b..f3a7bc747 100644 --- a/scripts/firebase-admin/updateDisplayNames.ts +++ b/scripts/firebase-admin/updateDisplayNames.ts @@ -1,4 +1,4 @@ -import { Timestamp } from "functions/src/firebase" +import { Timestamp } from "common/types" import { Script } from "./types" export const script: Script = async ({ db }) => { diff --git a/scripts/firebase-admin/updateHistory.ts b/scripts/firebase-admin/updateHistory.ts index da947d200..fa4d5fdb1 100644 --- a/scripts/firebase-admin/updateHistory.ts +++ b/scripts/firebase-admin/updateHistory.ts @@ -1,6 +1,7 @@ -import { FieldValue, Timestamp } from "../../functions/src/firebase" +import { Timestamp } from "../../common/types" import { Record, String, Number } from "runtypes" import { Script } from "./types" +import { FieldValue } from "functions/src/firebase" const Args = Record({ court: Number, bills: String }) export const script: Script = async ({ db, args }) => { diff --git a/stories/emailTemplates/NotificationDigestEmail.stories.tsx b/stories/emailTemplates/NotificationDigestEmail.stories.tsx index d2cf1200c..e951093b2 100644 --- a/stories/emailTemplates/NotificationDigestEmail.stories.tsx +++ b/stories/emailTemplates/NotificationDigestEmail.stories.tsx @@ -7,7 +7,7 @@ import { NotificationEmailDigest, UserDigest } from "functions/src/notifications/emailTypes" -import { Frequency } from "components/auth" +import { Frequency } from "common/auth/types" const meta: Meta = { title: "Email Templates/Notifications Digest", diff --git a/stories/organisms/ProfileHeader.stories.tsx b/stories/organisms/ProfileHeader.stories.tsx index e443031cb..361bceb96 100644 --- a/stories/organisms/ProfileHeader.stories.tsx +++ b/stories/organisms/ProfileHeader.stories.tsx @@ -1,6 +1,5 @@ import { Meta, StoryObj } from "@storybook/react" import { ProfileHeader } from "components/ProfilePage/ProfileHeader" -import { Profile } from "components/db" import { Providers } from "components/providers" import { wrapper } from "components/store" import { Provider as Redux } from "react-redux" diff --git a/stories/organisms/SubmitTestimonyForm.stories.tsx b/stories/organisms/SubmitTestimonyForm.stories.tsx index 446fc2fff..53a2488d4 100644 --- a/stories/organisms/SubmitTestimonyForm.stories.tsx +++ b/stories/organisms/SubmitTestimonyForm.stories.tsx @@ -1,4 +1,4 @@ -import { Timestamp } from "firebase/firestore" +import { Timestamp } from "common/types" import { Meta, StoryObj } from "@storybook/react" import { Providers } from "components/providers" import { ChooseStance } from "components/publish/ChooseStance" @@ -84,7 +84,8 @@ export const FormStory = { fetchedAt: Timestamp.fromDate(new Date()), history: [], currentCommittee: undefined, - city: undefined + city: undefined, + similar: [] }} synced={false} /> diff --git a/stories/organisms/billDetail/BillSponsorCard.stories.tsx b/stories/organisms/billDetail/BillSponsorCard.stories.tsx index fcb13cc05..da0251382 100644 --- a/stories/organisms/billDetail/BillSponsorCard.stories.tsx +++ b/stories/organisms/billDetail/BillSponsorCard.stories.tsx @@ -1,8 +1,8 @@ import { Meta, StoryObj } from "@storybook/react" import { Cosponsors as PreCosponsors } from "components/bill/Cosponsors" import { BillProps } from "components/bill/types" -import { Bill, BillContent, BillHistory } from "components/db" -import { Timestamp } from "firebase/firestore" +import { Bill, BillContent, BillHistory } from "common/bills/types" +import { Timestamp } from "common/types" import { ReactNode } from "react" // TODO: move into components directory @@ -98,7 +98,8 @@ const bill: Bill = { email: "a@b.com" } }, - city: "Boston" + city: "Boston", + similar: [] } Primary.args = { diff --git a/stories/organisms/billDetail/BillStatus.stories.tsx b/stories/organisms/billDetail/BillStatus.stories.tsx index 0a139e945..6f67d63e6 100644 --- a/stories/organisms/billDetail/BillStatus.stories.tsx +++ b/stories/organisms/billDetail/BillStatus.stories.tsx @@ -1,6 +1,6 @@ import { Meta, StoryObj } from "@storybook/react" import { BillTrackerView } from "components/bill/BillTracker" -import { Timestamp } from "firebase/firestore" +import { Timestamp } from "common/types" import { Stage } from "functions/src/analysis/types" const meta: Meta = { diff --git a/stories/organisms/billDetail/BillTestimonyListCard.stories.tsx b/stories/organisms/billDetail/BillTestimonyListCard.stories.tsx index 1f2dc8010..2117eb68c 100644 --- a/stories/organisms/billDetail/BillTestimonyListCard.stories.tsx +++ b/stories/organisms/billDetail/BillTestimonyListCard.stories.tsx @@ -2,7 +2,7 @@ import { Meta, StoryObj } from "@storybook/react" import { BillTestimonies } from "components/bill/BillTestimonies" import { Providers } from "components/providers" import { wrapper } from "components/store" -import { Timestamp } from "firebase/firestore" +import { Timestamp } from "common/types" import { Provider as Redux } from "react-redux" const BillTestimonyListCard = BillTestimonies @@ -47,7 +47,8 @@ export const Primary: Story = { Branch: "1", Action: "1" } - ] + ], + similar: [] } }, name: "BillTestimonyListCard", diff --git a/stories/organisms/billDetail/MockBillData.tsx b/stories/organisms/billDetail/MockBillData.tsx index 366ccf1a0..a79aa7b10 100644 --- a/stories/organisms/billDetail/MockBillData.tsx +++ b/stories/organisms/billDetail/MockBillData.tsx @@ -1,5 +1,5 @@ -import { Timestamp } from "firebase/firestore" -import { Bill, BillContent, BillHistory } from "components/db" +import { Timestamp } from "common/types" +import { Bill, BillContent, BillHistory } from "common/bills/types" export const newBillHistory: BillHistory = [ { @@ -88,5 +88,6 @@ export const bill: Bill = { }, city: "Boston", topics: newBillTopics, - summary: "This is the summary" + summary: "This is the summary", + similar: [] } diff --git a/stories/organisms/editprofile/EditProfileHeader.stories.tsx b/stories/organisms/editprofile/EditProfileHeader.stories.tsx index 4266c508e..cf711fd7a 100644 --- a/stories/organisms/editprofile/EditProfileHeader.stories.tsx +++ b/stories/organisms/editprofile/EditProfileHeader.stories.tsx @@ -1,7 +1,5 @@ import { Meta, StoryObj } from "@storybook/react" import { EditProfileHeader } from "components/EditProfilePage/EditProfileHeader" -import { ProfileHeader } from "components/ProfilePage/ProfileHeader" -import { Profile } from "components/db" import { Providers } from "components/providers" import { wrapper } from "components/store" import { Provider as Redux } from "react-redux" diff --git a/stories_hold/organisms/newsfeed/NewsfeedCard.stories.tsx b/stories_hold/organisms/newsfeed/NewsfeedCard.stories.tsx index eb1c36bc3..9ad8be838 100644 --- a/stories_hold/organisms/newsfeed/NewsfeedCard.stories.tsx +++ b/stories_hold/organisms/newsfeed/NewsfeedCard.stories.tsx @@ -2,7 +2,7 @@ import { ComponentStory } from "@storybook/react" import React, { useState } from "react" import { createMeta } from "stories/utils" import { NewsfeedCard } from "components/NewsfeedCard/NewsfeedCard" -import { Timestamp } from "firebase/firestore" +import { Timestamp } from "common/types" export default createMeta({ title: "Dashboard/Newsfeed/NewsfeedCard", diff --git a/stories_hold/organisms/profile/ProfileAboutSection.stories.tsx b/stories_hold/organisms/profile/ProfileAboutSection.stories.tsx index c84e3bc8b..e3ab68df2 100644 --- a/stories_hold/organisms/profile/ProfileAboutSection.stories.tsx +++ b/stories_hold/organisms/profile/ProfileAboutSection.stories.tsx @@ -1,6 +1,6 @@ import { ComponentStory } from "@storybook/react" +import { Profile } from "common/profile/types" import { ProfileAboutSection } from "components/ProfilePage/ProfileAboutSection" -import { Profile } from "components/db" import { Providers } from "components/providers" import { wrapper } from "components/store" import { Provider as Redux } from "react-redux" diff --git a/stories_hold/organisms/profile/UserTestimonyListCard.stories.tsx b/stories_hold/organisms/profile/UserTestimonyListCard.stories.tsx index 6882672cc..7e652b241 100644 --- a/stories_hold/organisms/profile/UserTestimonyListCard.stories.tsx +++ b/stories_hold/organisms/profile/UserTestimonyListCard.stories.tsx @@ -2,7 +2,7 @@ import { ComponentStory } from "@storybook/react" import { TestimonyItem } from "components/TestimonyCard/TestimonyItem" import { Providers } from "components/providers" import { wrapper } from "components/store" -import { Timestamp } from "firebase/firestore" +import { Timestamp } from "common/types" import React from "react" import { Provider as Redux } from "react-redux" import { createMeta } from "stories/utils" diff --git a/stories_hold/unused/OrgAvatar.tsx b/stories_hold/unused/OrgAvatar.tsx index f88363fbd..45a040620 100644 --- a/stories_hold/unused/OrgAvatar.tsx +++ b/stories_hold/unused/OrgAvatar.tsx @@ -1,6 +1,6 @@ import { FC } from "react" import styled from "styled-components" -import { Position } from "components/db" +import { Position } from "common/testimony/types" const ImageContainer = styled.div` width: 87px; diff --git a/stories_hold/unused/OrgPriorityCard.tsx b/stories_hold/unused/OrgPriorityCard.tsx index a48bd8333..775a30699 100644 --- a/stories_hold/unused/OrgPriorityCard.tsx +++ b/stories_hold/unused/OrgPriorityCard.tsx @@ -1,5 +1,5 @@ import { Card, SeeMore } from "components/Card" -import { Position } from "components/db" +import { Position } from "common/testimony/types" import { Key } from "react" import { OrgAvatar } from "./OrgAvatar" import styled from "styled-components" diff --git a/tests/integration/auth.test.ts b/tests/integration/auth.test.ts index b4bbfdbf2..ce246da77 100644 --- a/tests/integration/auth.test.ts +++ b/tests/integration/auth.test.ts @@ -1,6 +1,6 @@ import { UserRecord } from "firebase-admin/auth" import { nanoid } from "nanoid" -import { Role } from "../../components/auth" +import { Role } from "common/auth/types" import { setRole } from "../../functions/src/auth" import { terminateFirebase, testAuth, testDb } from "../testUtils" import { getProfile } from "./common" diff --git a/tests/integration/backfillTestimonyCounts.test.ts b/tests/integration/backfillTestimonyCounts.test.ts index fb5ac68ef..b47e16caa 100644 --- a/tests/integration/backfillTestimonyCounts.test.ts +++ b/tests/integration/backfillTestimonyCounts.test.ts @@ -1,6 +1,6 @@ import { waitFor } from "@testing-library/react" import axios from "axios" -import { currentGeneralCourt } from "functions/src/shared" +import { currentGeneralCourt } from "common/constants" import { PartialTestimony } from "../../functions/src/bills/backfillTestimonyCounts" import { terminateFirebase, testDb } from "../testUtils" import { createFakeBill, getBill } from "./common" diff --git a/tests/integration/billTracker.test.ts b/tests/integration/billTracker.test.ts index 8248316ea..256a44aa7 100644 --- a/tests/integration/billTracker.test.ts +++ b/tests/integration/billTracker.test.ts @@ -1,5 +1,5 @@ import { waitFor } from "@testing-library/react" -import { BillHistory } from "components/db" +import { BillHistory } from "common/bills/types" import { billTrackerPath } from "functions/src/analysis" import { predictBillStatus } from "functions/src/analysis/predictBillStatus" import { BillTracker, Stage } from "functions/src/analysis/types" diff --git a/tests/integration/common.ts b/tests/integration/common.ts index daf5955be..9bf37805b 100644 --- a/tests/integration/common.ts +++ b/tests/integration/common.ts @@ -1,5 +1,5 @@ import { fail } from "assert" -import { Role, finishSignup } from "components/auth" +import { finishSignup } from "components/auth" import { Report } from "components/moderation/types" import { UserRecord } from "firebase-admin/auth" import { FirebaseError } from "firebase/app" @@ -9,14 +9,15 @@ import { createUserWithEmailAndPassword, signInWithEmailAndPassword } from "firebase/auth" -import { currentGeneralCourt } from "functions/src/shared" -import { Testimony } from "functions/src/testimony/types" +import { currentGeneralCourt } from "common/constants" +import { Testimony } from "common/testimony/types" import { nanoid } from "nanoid" import { auth } from "../../components/firebase" -import { Bill, BillContent } from "../../functions/src/bills/types" +import { Bill, BillContent } from "../../common/bills/types" import { testAuth, testDb, testTimestamp } from "../testUtils" -import { Timestamp } from "functions/src/firebase" +import { Timestamp } from "common/types" import { Timestamp as FirestoreTimestamp } from "@google-cloud/firestore" +import { Role } from "common/auth/types" export async function signInUser(email: string) { const { user } = await signInWithEmailAndPassword(auth, email, "password") @@ -32,10 +33,14 @@ export const signInTestAdmin = () => signInUser("testadmin@example.com") export async function createNewBill(props?: Partial) { const billId = props?.id ?? nanoid() const content: BillContent = { - Pinslip: null, + Pinslip: "", Title: "fake", - PrimarySponsor: null, - Cosponsors: [] + PrimarySponsor: undefined, + Cosponsors: [], + BillNumber: "", + DocketNumber: "", + GeneralCourtNumber: 0, + LegislationTypeName: "" } const bill: Bill = { id: billId, diff --git a/tests/integration/moderation.test.ts b/tests/integration/moderation.test.ts index 372e1f561..05aea66bf 100644 --- a/tests/integration/moderation.test.ts +++ b/tests/integration/moderation.test.ts @@ -1,30 +1,23 @@ import { waitFor } from "@testing-library/react" -import { Role } from "components/auth" +import { Role } from "common/auth/types" import { resolveReport } from "components/db" import { doc, setDoc } from "firebase/firestore" import { httpsCallable } from "firebase/functions" -import { - syncBillToSearchIndex, - syncTestimonyToSearchIndex -} from "functions/src" -import { currentGeneralCourt } from "functions/src/shared" +import { currentGeneralCourt } from "common/constants" import { nanoid } from "nanoid" import { createNewBill, createNewReport, createUser, signInTestAdmin, - signInUser, - signInUser1 + signInUser } from "tests/integration/common" import { terminateFirebase, testAuth, testDb } from "tests/testUtils" import { firestore, functions } from "../../components/firebase" import { expectPermissionDenied, genUserInfo } from "./common" -import { FirebaseError } from "@firebase/util" -import { Testimony } from "functions/src/testimony/types" -import { Timestamp } from "functions/src/firebase" +import { Testimony } from "common/testimony/types" +import { Timestamp } from "common/types" import { Report } from "components/moderation/types" -import { fakeUser } from "components/moderation/setUp/MockRecords" const deleteTestimony = httpsCallable< { uid: string; publicationId: string }, diff --git a/tests/integration/search.test.ts b/tests/integration/search.test.ts index 71431113b..0ae3acbdd 100644 --- a/tests/integration/search.test.ts +++ b/tests/integration/search.test.ts @@ -1,11 +1,11 @@ import { DocumentSnapshot } from "@google-cloud/firestore" import { waitFor } from "@testing-library/react" import axios from "axios" -import { currentGeneralCourt } from "functions/src/shared" +import { currentGeneralCourt } from "common/constants" import { first } from "lodash" import { nanoid } from "nanoid" import { CollectionAliasSchema } from "typesense/lib/Typesense/Aliases" -import { Timestamp } from "../../functions/src/firebase" +import { Timestamp } from "../../common/types" import { createClient } from "../../functions/src/search/client" import { SearchIndexer } from "../../functions/src/search/SearchIndexer" import { testDb } from "../testUtils" diff --git a/tests/integration/testimony.test.ts b/tests/integration/testimony.test.ts index ac61a935b..19f7f6ed8 100644 --- a/tests/integration/testimony.test.ts +++ b/tests/integration/testimony.test.ts @@ -1,6 +1,6 @@ -import { currentGeneralCourt } from "functions/src/shared" +import { currentGeneralCourt } from "common/constants" import { getAuth, signOut, User } from "firebase/auth" -import { doc, getDoc, setDoc, Timestamp, updateDoc } from "firebase/firestore" +import { doc, getDoc, setDoc, updateDoc } from "firebase/firestore" import { httpsCallable } from "firebase/functions" import { ref, uploadBytes } from "firebase/storage" import { nanoid } from "nanoid" @@ -16,6 +16,7 @@ import { signInUser1, signInUser2 } from "./common" +import { Timestamp } from "common/types" type BaseTestimony = { billId: string diff --git a/tests/seed/seedTestimony.test.ts b/tests/seed/seedTestimony.test.ts index 2089aa06a..610064511 100644 --- a/tests/seed/seedTestimony.test.ts +++ b/tests/seed/seedTestimony.test.ts @@ -1,9 +1,10 @@ import { testDb } from "../testUtils" -import { DraftTestimony, publishTestimony } from "../../components/db" -import { currentGeneralCourt } from "functions/src/shared" +import { publishTestimony } from "../../components/db" +import { currentGeneralCourt } from "common/constants" import { loremIpsum } from "lorem-ipsum" import { signInUser3, signInUser4 } from "../integration/common" import { User } from "firebase/auth" +import { DraftTestimony } from "common/testimony/types" type UserTestimonySeedConfig = "draft" | "testimony" | "both" | undefined type SeedConfig = { diff --git a/tests/system/testimony.test.ts b/tests/system/testimony.test.ts index 92387cf7c..f071cd952 100644 --- a/tests/system/testimony.test.ts +++ b/tests/system/testimony.test.ts @@ -1,4 +1,4 @@ -import { currentGeneralCourt } from "functions/src/shared" +import { currentGeneralCourt } from "common/constants" import { signInWithEmailAndPassword } from "firebase/auth" import { addDoc, diff --git a/tests/testUtils.ts b/tests/testUtils.ts index 5984f0ceb..160f9fffc 100644 --- a/tests/testUtils.ts +++ b/tests/testUtils.ts @@ -2,6 +2,7 @@ import * as admin from "firebase-admin" import { deleteApp } from "firebase/app" import { clearIndexedDbPersistence, terminate } from "firebase/firestore" import { app, firestore } from "../components/firebase" +import { Timestamp } from "common/types" admin.initializeApp({ storageBucket: `${process.env.GCLOUD_PROJECT}.appspot.com` @@ -11,7 +12,7 @@ export const testDb = admin.firestore() export const testStorage = admin.storage() export const testAuth = admin.auth() -export const testTimestamp = admin.firestore.Timestamp +export const testTimestamp = Timestamp export { admin as testAdmin } export async function terminateFirebase() { diff --git a/tests/unit/billdetail.test.tsx b/tests/unit/billdetail.test.tsx index f349f9572..af673d8ca 100644 --- a/tests/unit/billdetail.test.tsx +++ b/tests/unit/billdetail.test.tsx @@ -1,8 +1,8 @@ import "@testing-library/jest-dom" import { render, screen, fireEvent, waitFor } from "@testing-library/react" -import { Bill, draftAttachment } from "components/db" +import { Bill } from "common/bills/types" import { BillDetails } from "components/bill/BillDetails" -import { Timestamp } from "firebase/firestore" +import { Timestamp } from "common/types" import { Provider } from "react-redux" import { thunk } from "redux-thunk" import configureStore from "redux-mock-store" @@ -109,7 +109,8 @@ const mockBill: Bill = { Branch: "Senate" } ], - city: "Sample City" + city: "Sample City", + similar: [] } // set up Redux mock store with thunk middleware bc resolveBill is thunk @@ -162,7 +163,7 @@ describe("BillDetails", () => { const readMoreButton = screen.getByRole("button", { name: "Read more.." }) expect(readMoreButton).toBeInTheDocument fireEvent.click(readMoreButton) - expect(screen.getByText(DocumentText)).toBeInTheDocument + expect(screen.getByText(DocumentText ?? "")).toBeInTheDocument() }) // below test assumes mockBill contains a primary sponsor diff --git a/yarn.lock b/yarn.lock index a46d16150..83702819e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2080,6 +2080,17 @@ google-gax "^2.24.1" protobufjs "^6.8.6" +"@google-cloud/firestore@^7.11.1": + version "7.11.1" + resolved "https://registry.yarnpkg.com/@google-cloud/firestore/-/firestore-7.11.1.tgz#fbdb99f1e263889fc1c259986238404e7a480136" + integrity sha512-ZxOdH8Wr01hBDvKCQfMWqwUcfNcN3JY19k1LtS1fTFhEyorYPLsbWN+VxIRL46pOYGHTPkU3Or5HbT/SLQM5nA== + dependencies: + "@opentelemetry/api" "^1.3.0" + fast-deep-equal "^3.1.1" + functional-red-black-tree "^1.0.1" + google-gax "^4.3.3" + protobufjs "^7.2.6" + "@google-cloud/paginator@^3.0.7": version "3.0.7" resolved "https://registry.yarnpkg.com/@google-cloud/paginator/-/paginator-3.0.7.tgz#fb6f8e24ec841f99defaebf62c75c2e744dd419b" @@ -2167,6 +2178,14 @@ uuid "^8.0.0" xdg-basedir "^4.0.0" +"@grpc/grpc-js@^1.10.9": + version "1.13.4" + resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.13.4.tgz#922fbc496e229c5fa66802d2369bf181c1df1c5a" + integrity sha512-GsFaMXCkMqkKIvwCQjCrwH+GHbPKBjhwo/8ZuUkWHqbI73Kky9I+pQltrlT0+MWpedCoosda53lgjYfyEPgxBg== + dependencies: + "@grpc/proto-loader" "^0.7.13" + "@js-sdsl/ordered-map" "^4.4.2" + "@grpc/grpc-js@^1.3.2": version "1.9.13" resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.9.13.tgz#ad9b7dbb6089c462469653c809996f13e46aa1cd" @@ -2212,6 +2231,16 @@ protobufjs "^7.2.4" yargs "^17.7.2" +"@grpc/proto-loader@^0.7.13": + version "0.7.15" + resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.15.tgz#4cdfbf35a35461fc843abe8b9e2c0770b5095e60" + integrity sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ== + dependencies: + lodash.camelcase "^4.3.0" + long "^5.0.0" + protobufjs "^7.2.5" + yargs "^17.7.2" + "@hapi/hoek@^9.0.0": version "9.3.0" resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb" @@ -2516,6 +2545,11 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" +"@js-sdsl/ordered-map@^4.4.2": + version "4.4.2" + resolved "https://registry.yarnpkg.com/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz#9299f82874bab9e4c7f9c48d865becbfe8d6907c" + integrity sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw== + "@jsdevtools/ono@^7.1.3": version "7.1.3" resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796" @@ -2737,6 +2771,11 @@ dependencies: semver "^7.3.5" +"@opentelemetry/api@^1.3.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.9.0.tgz#d03eba68273dc0f7509e2a3d5cba21eae10379fe" + integrity sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg== + "@opentelemetry/api@^1.6.0": version "1.7.0" resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.7.0.tgz#b139c81999c23e3c8d3c0a7234480e945920fc40" @@ -4290,6 +4329,11 @@ "@types/connect" "*" "@types/node" "*" +"@types/caseless@*": + version "0.12.5" + resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.5.tgz#db9468cb1b1b5a925b8f34822f1669df0c5472f5" + integrity sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg== + "@types/connect@*": version "3.4.38" resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858" @@ -4721,6 +4765,16 @@ dependencies: redux "^4.0.5" +"@types/request@^2.48.8": + version "2.48.12" + resolved "https://registry.yarnpkg.com/@types/request/-/request-2.48.12.tgz#0f590f615a10f87da18e9790ac94c29ec4c5ef30" + integrity sha512-G3sY+NpsA9jnwm0ixhAFQSJ3Q9JkpLZpJbI3GMv0mIAT0y3mRabYeINzal5WOChIiaTEGQYlHOKgkaM9EisWHw== + dependencies: + "@types/caseless" "*" + "@types/node" "*" + "@types/tough-cookie" "*" + form-data "^2.5.0" + "@types/resolve@^1.20.2": version "1.20.6" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.6.tgz#e6e60dad29c2c8c206c026e6dd8d6d1bdda850b8" @@ -4775,6 +4829,11 @@ "@types/react" "*" csstype "^3.0.2" +"@types/tough-cookie@*": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.5.tgz#cb6e2a691b70cb177c6e3ae9c1d2e8b2ea8cd304" + integrity sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA== + "@types/triple-beam@^1.3.2": version "1.3.5" resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.5.tgz#74fef9ffbaa198eb8b588be029f38b00299caa2c" @@ -6289,6 +6348,14 @@ cacheable-request@^6.0.0: normalize-url "^4.1.0" responselike "^1.0.2" +call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.4, call-bind@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" @@ -7686,6 +7753,15 @@ dotenv@^16.0.0: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.1.tgz#369034de7d7e5b120972693352a3bf112172cc3e" integrity sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ== +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + duplexer3@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.5.tgz#0b5e4d7bad5de8901ea4440624c8e1d20099217e" @@ -7982,6 +8058,11 @@ es-define-property@^1.0.0: dependencies: get-intrinsic "^1.2.4" +es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + es-errors@^1.2.1, es-errors@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" @@ -8054,6 +8135,13 @@ es-object-atoms@^1.0.0: dependencies: es-errors "^1.3.0" +es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + es-set-tostringtag@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz#11f7cc9f63376930a5f20be4915834f4bc74f9c9" @@ -8072,6 +8160,16 @@ es-set-tostringtag@^2.0.3: has-tostringtag "^1.0.2" hasown "^2.0.1" +es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== + dependencies: + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + es-shim-unscopables@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" @@ -9098,6 +9196,17 @@ fork-ts-checker-webpack-plugin@^8.0.0: semver "^7.3.5" tapable "^2.2.1" +form-data@^2.5.0: + version "2.5.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.3.tgz#f9bcf87418ce748513c0c3494bb48ec270c97acc" + integrity sha512-XHIrMD0NpDrNM/Ckf7XJiBbLl57KEhT3+i3yY+eWm+cqYZJQTZrKo8Y8AWKnuV5GT4scfuUGt9LzNoIx3dU1nQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + es-set-tostringtag "^2.1.0" + mime-types "^2.1.35" + safe-buffer "^5.2.1" + form-data@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" @@ -9269,6 +9378,17 @@ gaxios@^5.0.0, gaxios@^5.0.1: is-stream "^2.0.0" node-fetch "^2.6.9" +gaxios@^6.0.0, gaxios@^6.1.1: + version "6.7.1" + resolved "https://registry.yarnpkg.com/gaxios/-/gaxios-6.7.1.tgz#ebd9f7093ede3ba502685e73390248bb5b7f71fb" + integrity sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ== + dependencies: + extend "^3.0.2" + https-proxy-agent "^7.0.1" + is-stream "^2.0.0" + node-fetch "^2.6.9" + uuid "^9.0.1" + gcp-metadata@^4.2.0: version "4.3.1" resolved "https://registry.yarnpkg.com/gcp-metadata/-/gcp-metadata-4.3.1.tgz#fb205fe6a90fef2fd9c85e6ba06e5559ee1eefa9" @@ -9285,6 +9405,15 @@ gcp-metadata@^5.3.0: gaxios "^5.0.0" json-bigint "^1.0.0" +gcp-metadata@^6.1.0: + version "6.1.1" + resolved "https://registry.yarnpkg.com/gcp-metadata/-/gcp-metadata-6.1.1.tgz#f65aa69f546bc56e116061d137d3f5f90bdec494" + integrity sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A== + dependencies: + gaxios "^6.1.1" + google-logging-utils "^0.0.2" + json-bigint "^1.0.0" + gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -9316,6 +9445,22 @@ get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: has-symbols "^1.0.3" hasown "^2.0.0" +get-intrinsic@^1.2.6: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + get-nonce@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3" @@ -9336,6 +9481,14 @@ get-port@^5.1.1: resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== +get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + get-stream@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" @@ -9615,6 +9768,18 @@ google-auth-library@^8.0.2: jws "^4.0.0" lru-cache "^6.0.0" +google-auth-library@^9.3.0: + version "9.15.1" + resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-9.15.1.tgz#0c5d84ed1890b2375f1cd74f03ac7b806b392928" + integrity sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng== + dependencies: + base64-js "^1.3.0" + ecdsa-sig-formatter "^1.0.11" + gaxios "^6.1.1" + gcp-metadata "^6.1.0" + gtoken "^7.0.0" + jws "^4.0.0" + google-gax@^2.24.1: version "2.30.5" resolved "https://registry.yarnpkg.com/google-gax/-/google-gax-2.30.5.tgz#e836f984f3228900a8336f608c83d75f9cb73eff" @@ -9655,6 +9820,29 @@ google-gax@^3.6.1: protobufjs-cli "1.1.1" retry-request "^5.0.0" +google-gax@^4.3.3: + version "4.6.1" + resolved "https://registry.yarnpkg.com/google-gax/-/google-gax-4.6.1.tgz#57f8e3d893d4c708a71167cdcf47eb3afab95929" + integrity sha512-V6eky/xz2mcKfAd1Ioxyd6nmA61gao3n01C+YeuIwu3vzM9EDR6wcVzMSIbLMDXWeoi9SHYctXuKYC5uJUT3eQ== + dependencies: + "@grpc/grpc-js" "^1.10.9" + "@grpc/proto-loader" "^0.7.13" + "@types/long" "^4.0.0" + abort-controller "^3.0.0" + duplexify "^4.0.0" + google-auth-library "^9.3.0" + node-fetch "^2.7.0" + object-hash "^3.0.0" + proto3-json-serializer "^2.0.2" + protobufjs "^7.3.2" + retry-request "^7.0.0" + uuid "^9.0.1" + +google-logging-utils@^0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/google-logging-utils/-/google-logging-utils-0.0.2.tgz#5fd837e06fa334da450433b9e3e1870c1594466a" + integrity sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ== + google-p12-pem@^3.1.3: version "3.1.4" resolved "https://registry.yarnpkg.com/google-p12-pem/-/google-p12-pem-3.1.4.tgz#123f7b40da204de4ed1fbf2fd5be12c047fc8b3b" @@ -9676,6 +9864,11 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" +gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + got@^9.6.0: version "9.6.0" resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" @@ -9726,6 +9919,14 @@ gtoken@^6.1.0: google-p12-pem "^4.0.0" jws "^4.0.0" +gtoken@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/gtoken/-/gtoken-7.1.0.tgz#d61b4ebd10132222817f7222b1e6064bd463fc26" + integrity sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw== + dependencies: + gaxios "^6.0.0" + jws "^4.0.0" + gunzip-maybe@^1.4.2: version "1.4.2" resolved "https://registry.yarnpkg.com/gunzip-maybe/-/gunzip-maybe-1.4.2.tgz#b913564ae3be0eda6f3de36464837a9cd94b98ac" @@ -9812,6 +10013,11 @@ has-symbols@^1.0.2, has-symbols@^1.0.3: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== +has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + has-tostringtag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" @@ -12286,6 +12492,11 @@ match-sorter@^6.0.2: "@babel/runtime" "^7.12.5" remove-accents "0.4.2" +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + md5.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" @@ -13039,7 +13250,7 @@ node-fetch@2.6.7: dependencies: whatwg-url "^5.0.0" -node-fetch@^2.0.0, node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.12, node-fetch@^2.6.7, node-fetch@^2.6.9: +node-fetch@^2.0.0, node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.12, node-fetch@^2.6.7, node-fetch@^2.6.9, node-fetch@^2.7.0: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== @@ -14109,6 +14320,13 @@ proto3-json-serializer@^1.0.0: dependencies: protobufjs "^7.0.0" +proto3-json-serializer@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/proto3-json-serializer/-/proto3-json-serializer-2.0.2.tgz#5b705203b4d58f3880596c95fad64902617529dd" + integrity sha512-SAzp/O4Yh02jGdRc+uIrGoe87dkN/XtwxfZ4ZyafJHymd79ozp5VG5nyZ7ygqPM5+cpLDjjGnYFUkngonyDPOQ== + dependencies: + protobufjs "^7.2.5" + protobufjs-cli@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/protobufjs-cli/-/protobufjs-cli-1.1.1.tgz#f531201b1c8c7772066aa822bf9a08318b24a704" @@ -14199,6 +14417,24 @@ protobufjs@^7.0.0, protobufjs@^7.2.4: "@types/node" ">=13.7.0" long "^5.0.0" +protobufjs@^7.2.5, protobufjs@^7.2.6, protobufjs@^7.3.2: + version "7.5.3" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.5.3.tgz#13f95a9e3c84669995ec3652db2ac2fb00b89363" + integrity sha512-sildjKwVqOI2kmFDiXQ6aEB0fjYTafpEvIBs8tOR8qI4spuL9OPROLVu2qZqi/xgCfsHIwVqlaF8JBjWFHnKbw== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/node" ">=13.7.0" + long "^5.0.0" + proxy-addr@~2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" @@ -15287,6 +15523,15 @@ retry-request@^5.0.0: debug "^4.1.1" extend "^3.0.2" +retry-request@^7.0.0: + version "7.0.2" + resolved "https://registry.yarnpkg.com/retry-request/-/retry-request-7.0.2.tgz#60bf48cfb424ec01b03fca6665dee91d06dd95f3" + integrity sha512-dUOvLMJ0/JJYEn8NrpOaGNE7X3vpI5XlZS/u0ANjqtcZVKnIxP7IgCFwrKTxENw29emmwug53awKtaMm4i9g5w== + dependencies: + "@types/request" "^2.48.8" + extend "^3.0.2" + teeny-request "^9.0.0" + retry@0.13.1, retry@^0.13.1: version "0.13.1" resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" @@ -16373,6 +16618,17 @@ teeny-request@^7.1.3: stream-events "^1.0.5" uuid "^8.0.0" +teeny-request@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/teeny-request/-/teeny-request-9.0.0.tgz#18140de2eb6595771b1b02203312dfad79a4716d" + integrity sha512-resvxdc6Mgb7YEThw6G6bExlXKkv6+YbuzGg9xuXxSgxJF7Ozs+o8Y9+2R3sArdWdW8nOokoQb1yrpFB0pQK2g== + dependencies: + http-proxy-agent "^5.0.0" + https-proxy-agent "^5.0.0" + node-fetch "^2.6.9" + stream-events "^1.0.5" + uuid "^9.0.0" + telejson@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/telejson/-/telejson-7.2.0.tgz#3994f6c9a8f8d7f2dba9be2c7c5bbb447e876f32" @@ -17251,7 +17507,7 @@ uuid@^8.0.0, uuid@^8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -uuid@^9.0.0: +uuid@^9.0.0, uuid@^9.0.1: version "9.0.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==