diff --git a/README.md b/README.md index 0609537d79..d1eefe4bb8 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,13 @@ MIT Learn follows the same [initial setup steps outlined in the common OL web ap Run through those steps **including the addition of `/etc/hosts` aliases and the optional step for running the `createsuperuser` command**. +For `/etc/hosts`, you'll need to add entries for the following domains if you are relying on the sample environment variables: +``` +api.open.odl.local +open.odl.local +kc.ol.local +``` + ### Configuration Configuration can be put in the following files which are gitignored: @@ -26,7 +33,7 @@ mit-learn/ ├── env/ │ ├── shared.local.env (provided to both frontend and backend containers) │ ├── frontend.local.env (provided only to frontend containers) - │ └── backend.local.env (provided only to frontend containers) + │ └── backend.local.env (provided only to backend containers) └── .env (legacy file) ``` @@ -43,6 +50,16 @@ The following settings must be configured before running the app: is not needed. It's recommended that you eventually configure the site to be able to send emails. Those configuration steps can be found [below](#enabling-email). +Before proceeding with any additional setup, you may want to adjust your docker settings to allow more memory to be used by the containers. Many engineers allocate the bulk of their system resources by navigating to Settings -> Resources in Docker Desktop. +Additionally, the `web` and `celery` services specify `memory_limit` values, which you can adjust using the following environment variables: +``` +MITOL_CELERY_MEM_LIMIT +MITOL_WEB_MEM_LIMIT +``` + +If any resource limits are set too low, you may encounter OOMKilled errors in the logs of those services. The primary way this will manifest is that containers may unexpectedly die during operation resulting in 500 errors or unusual celery task execution. +Given a container that is unexpectedly down, you can verify that it was OOMKilled by running `docker inspect -f '{{json .State.OOMKilled}}'`, or by checking the Docker VM kernel message logs for relevant output. + ### Loading Data The MIT Learn platform aggregates data from many sources. These data are populated by ETL (extract, transform, load) pipelines that run automatically on a regular schedule. Django [management commands](https://docs.djangoproject.com/en/4.2/howto/custom-management-commands/) are also available to force the pipelines to run—particularly useful for local development. @@ -62,12 +79,21 @@ docker compose run --rm web python manage.py backpopulate_xpro_data See [learning_resources/management/commands](learning_resources/management/commands) and [main/settings_course_etl.py](main/settings_course_etl.py) for more ETL commands and their relevant environment variables. +You may also want to generate embeddings once you have populated some data in so vector search and recommendations function as expected. See [docs/how-to/embeddings.md](docs/how-to/embeddings.md) for more details on this process. + ### Frontend Development The frontend package root is at [./frontends](./frontends). A `watch` container is provided to serve and rebuild the front end when there are changes to source files, which is started alongside backing services with `docker compose up`. Package scripts are also provided for building and serving the frontend in isolation. More detail can be found in the [Frontend README](./frontends/README.md#frontend-development). +### Connecting with Keycloak for authentication + +While not technically required to get the app running, it is the preferred way to work on features which require authentication. + +Please read [the Keycloak README](README-keycloak.md) for instructions on authenticating via +local Keycloak and APISIX containers. + ## Code Generation MIT Learn uses [drf-spectacular](https://drf-spectacular.readthedocs.io/en/latest/) to generate and OpenAPI spec from Django views. Additionally, we use [OpenAPITools/openapi-generator](https://github.com/OpenAPITools/openapi-generator) to generate Typescript declarations and an API Client. These generated files are checked into source control; CI checks that they are up-to-date. To regenerate these files, run @@ -211,11 +237,6 @@ This repo includes a config for running a [Jupyter notebook](https://jupyter.org From there, you should be able to run code snippets with a live Django app just like you would in a Django shell. -### Connecting with Keycloak for authentication - -Please read [the Keycloak README](README-keycloak.md) for instructions on authenticating via -local Keycloak and APISIX containers. - ### Configuring PostHog Support The system can use PostHog to evaluate feature flags and record views for the Learning Resource drawer. diff --git a/RELEASE.rst b/RELEASE.rst index e5daff7061..015bb748ce 100644 --- a/RELEASE.rst +++ b/RELEASE.rst @@ -1,6 +1,17 @@ Release Notes ============= +Version 0.41.7 +-------------- + +- Update dependency @sentry/nextjs to v10 (#2462) +- Update smoot version (#2459) +- Update dependency lxml to v6 (#2465) +- Update dependency tiktoken to ^0.11.0 (#2464) +- Minor tweaks to initial setup instructions, add memory env var for web container, note minimum required domain config for things to "work out of box" (#2458) +- Add (citation) urls for canvas contentfiles (#2457) +- fix one-click enrollment for the same course across multiple orgs (#2453) + Version 0.41.5 (Released August 25, 2025) -------------- diff --git a/docker-compose.apps.yml b/docker-compose.apps.yml index 70ea30d4cd..d847e01342 100644 --- a/docker-compose.apps.yml +++ b/docker-compose.apps.yml @@ -9,7 +9,7 @@ services: context: . dockerfile: Dockerfile target: final - mem_limit: 1gb + mem_limit: ${MITOL_WEB_MEM_LIMIT:-2gb} cpus: 2 command: ./scripts/run-django-dev.sh stdin_open: true @@ -54,7 +54,7 @@ services: context: . dockerfile: Dockerfile target: final - mem_limit: ${MITOL_CELERY_MEM_LIMIT:-2gb} + mem_limit: ${MITOL_CELERY_MEM_LIMIT:-4gb} cpus: ${MITOL_CELERY_CPU_LIMIT:-2} command: > /bin/bash -c ' diff --git a/docs/how-to/embeddings.md b/docs/how-to/embeddings.md index b40b0b3cbd..a38ed26e0b 100644 --- a/docs/how-to/embeddings.md +++ b/docs/how-to/embeddings.md @@ -27,7 +27,7 @@ The following embeddings related settings are available in the `settings.py` fil ## Embeddings for New Content -Embeddings are automatically generated for new conetnt by a periodic celery task. The tasks are defined `vector_search/tasks.py`. +Embeddings are automatically generated for new content by a periodic celery task. The tasks are defined `vector_search/tasks.py`. ## Embeddings for Existing Content diff --git a/env/backend.local.example.env b/env/backend.local.example.env index d85ababffa..ef9edf1fba 100644 --- a/env/backend.local.example.env +++ b/env/backend.local.example.env @@ -20,9 +20,6 @@ MAILGUN_SENDER_DOMAIN=open.odl.local MAILGUN_KEY=fake -# Set this to False if apisix/keycloak are running locally -DISABLE_APISIX_USER_MIDDLEWARE=True - # APISIX/Keycloak settings APISIX_LOGOUT_URL=http://api.open.odl.local:8065/logout/ APISIX_SESSION_SECRET_KEY=supertopsecret1234 diff --git a/env/shared.local.example.env b/env/shared.local.example.env index 46a5bf5bb5..75b6d80bd7 100644 --- a/env/shared.local.example.env +++ b/env/shared.local.example.env @@ -5,4 +5,4 @@ # EMBEDLY_KEY= # Use port 8063 if apisix/keycloak disabled MITOL_API_BASE_URL=http://api.open.odl.local:8063 -MITOL_API_DOMAIN = api.open.odl.local # dev only, should match domain of above +MITOL_API_DOMAIN=api.open.odl.local # dev only, should match domain of above diff --git a/frontends/api/src/mitxonline/hooks/contracts/index.ts b/frontends/api/src/mitxonline/hooks/contracts/index.ts new file mode 100644 index 0000000000..f084203834 --- /dev/null +++ b/frontends/api/src/mitxonline/hooks/contracts/index.ts @@ -0,0 +1,3 @@ +import { contractQueries } from "./queries" + +export { contractQueries } diff --git a/frontends/api/src/mitxonline/hooks/contracts/queries.ts b/frontends/api/src/mitxonline/hooks/contracts/queries.ts new file mode 100644 index 0000000000..af5bd481bf --- /dev/null +++ b/frontends/api/src/mitxonline/hooks/contracts/queries.ts @@ -0,0 +1,36 @@ +import { queryOptions } from "@tanstack/react-query" +import type { + B2bApiB2bContractsRetrieveRequest, + ContractPage, +} from "@mitodl/mitxonline-api-axios/v2" + +import { b2bApi } from "../../clients" + +const contractKeys = { + root: ["mitxonline", "contracts"], + contractsList: () => [...contractKeys.root, "list"], + contractDetail: (opts: B2bApiB2bContractsRetrieveRequest) => [ + ...contractKeys.root, + "detail", + opts, + ], +} + +const contractQueries = { + contractsList: () => + queryOptions({ + queryKey: contractKeys.contractsList(), + queryFn: async (): Promise => { + return b2bApi.b2bContractsList().then((res) => res.data) + }, + }), + contractDetail: (opts: B2bApiB2bContractsRetrieveRequest) => + queryOptions({ + queryKey: contractKeys.contractDetail(opts), + queryFn: async (): Promise => { + return b2bApi.b2bContractsRetrieve(opts).then((res) => res.data) + }, + }), +} + +export { contractQueries, contractKeys } diff --git a/frontends/api/src/mitxonline/test-utils/urls.ts b/frontends/api/src/mitxonline/test-utils/urls.ts index 6ebaaf6b74..c6aa36e9fc 100644 --- a/frontends/api/src/mitxonline/test-utils/urls.ts +++ b/frontends/api/src/mitxonline/test-utils/urls.ts @@ -54,6 +54,10 @@ const b2bAttach = { b2bAttachView: (code: string) => `${API_BASE_URL}/api/v0/b2b/attach/${code}/`, } +const contracts = { + contractsList: () => `${API_BASE_URL}/api/v0/b2b/contracts/`, +} + export { b2b, b2bAttach, @@ -64,4 +68,5 @@ export { courses, organization, programEnrollments, + contracts, } diff --git a/frontends/main/jest.config.ts b/frontends/main/jest.config.ts index b8af9e569e..bf299a12e8 100644 --- a/frontends/main/jest.config.ts +++ b/frontends/main/jest.config.ts @@ -13,6 +13,7 @@ const config: Config.InitialOptions = { "^rehype-mathjax/browser$": "ol-test-utilities/filemocks/filemock.js", "^rehype-raw$": "ol-test-utilities/filemocks/filemock.js", "^remark-math$": "ol-test-utilities/filemocks/filemock.js", + "^remark-supersub$": "ol-test-utilities/filemocks/filemock.js", }, } export default config diff --git a/frontends/main/package.json b/frontends/main/package.json index a46ae1ccfd..a1fd552202 100644 --- a/frontends/main/package.json +++ b/frontends/main/package.json @@ -15,10 +15,10 @@ "@emotion/styled": "^11.11.0", "@mitodl/course-search-utils": "3.3.2", "@mitodl/mitxonline-api-axios": "2025.8.12", - "@mitodl/smoot-design": "^6.10.0", + "@mitodl/smoot-design": "^6.17.0", "@next/bundle-analyzer": "^14.2.15", "@remixicon/react": "^4.2.0", - "@sentry/nextjs": "^9.0.0", + "@sentry/nextjs": "^10.0.0", "@tanstack/react-query": "^5.66", "api": "workspace:*", "classnames": "^2.5.1", diff --git a/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/DashboardCard.test.tsx b/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/DashboardCard.test.tsx index 59e167555a..c19c7658a8 100644 --- a/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/DashboardCard.test.tsx +++ b/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/DashboardCard.test.tsx @@ -99,9 +99,14 @@ describe.each([ case: "current", }, { - course: futureDashboardCourse(), + course: futureDashboardCourse({ + enrollment: { + status: EnrollmentStatus.Enrolled, + mode: EnrollmentMode.Audit, + }, + }), expected: { enabled: false }, - label: "future", + case: "future", }, ])( "Courseware CTA and is enabled/disabled (enabled=$expected.enabled) based on date (case: $case)", diff --git a/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/DashboardCard.tsx b/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/DashboardCard.tsx index 0bbf1ec12f..f36f2e1940 100644 --- a/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/DashboardCard.tsx +++ b/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/DashboardCard.tsx @@ -151,7 +151,7 @@ const CoursewareButton = styled( courseNoun, ...others }: CoursewareButtonProps) => { - const children = getCoursewareText({ + const coursewareText = getCoursewareText({ endDate, courseNoun, enrollmentStatus, @@ -162,8 +162,8 @@ const CoursewareButton = styled( const createEnrollment = useCreateEnrollment({ readable_id: coursewareId ?? "", }) - return hasStarted && href ? ( - hasEnrolled ? ( + return (hasStarted && href) || !hasEnrolled ? ( + hasEnrolled && href ? ( - {children} + {coursewareText} ) : ( ) }, @@ -364,7 +364,7 @@ const DashboardCard: React.FC = ({ {enrollment?.mode !== EnrollmentMode.Verified && offerUpgrade ? ( diff --git a/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/EnrollmentDisplay.tsx b/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/EnrollmentDisplay.tsx index 3b206908a7..18aa92e045 100644 --- a/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/EnrollmentDisplay.tsx +++ b/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/EnrollmentDisplay.tsx @@ -11,7 +11,7 @@ import { theme, } from "ol-components" import { useQuery } from "@tanstack/react-query" -import { mitxonlineEnrollments } from "./transform" +import { mitxonlineEnrollmentsToDashboardCourses } from "./transform" import { DashboardCard } from "./DashboardCard" import { DashboardCourse, EnrollmentStatus } from "./types" import { MaybeHasStatusAndDetail } from "@/app/getQueryClient" @@ -176,7 +176,7 @@ const EnrollmentExpandCollapse: React.FC = ({ const EnrollmentDisplay = () => { const { data: enrolledCourses, isLoading } = useQuery({ ...enrollmentQueries.courseRunEnrollmentsList(), - select: mitxonlineEnrollments, + select: mitxonlineEnrollmentsToDashboardCourses, throwOnError: (error) => { const err = error as MaybeHasStatusAndDetail const status = err?.response?.status diff --git a/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/test-utils.ts b/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/test-utils.ts index 72d23d8139..ae3ca0c42a 100644 --- a/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/test-utils.ts +++ b/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/test-utils.ts @@ -7,9 +7,19 @@ import { } from "./types" import type { DashboardCourse } from "./types" import * as u from "api/test-utils" +import * as mitxonline from "api/mitxonline-test-utils" import { urls, factories } from "api/mitxonline-test-utils" import { setMockResponse } from "../../../test-utils" import moment from "moment" +import { + ContractPage, + CourseRunEnrollment, + CourseWithCourseRunsSerializerV2, + IntegrationTypeEnum, + OrganizationPage, + User, + V2Program, +} from "@mitodl/mitxonline-api-axios/v2" const makeCourses = factories.courses.courses const makeProgram = factories.programs.program @@ -168,4 +178,163 @@ const setupProgramsAndCourses = () => { } } -export { dashboardCourse, setupEnrollments, setupProgramsAndCourses } +/** + * Test utility to create enrollments for contract-scoped runs + */ +const createEnrollmentsForContractRuns = ( + courses: CourseWithCourseRunsSerializerV2[], + contractIds: number[], +): CourseRunEnrollment[] => { + return courses.flatMap((course) => + course.courseruns + .filter( + (run) => run.b2b_contract && contractIds.includes(run.b2b_contract), + ) + .map((run) => + factories.enrollment.courseEnrollment({ + run: { + id: run.id, + course: { + id: course.id, + title: course.title, + }, + title: run.title, + }, + }), + ), + ) +} + +/** + * Helper function to set up organization, user, and related data + */ +function setupOrgAndUser() { + const user = u.urls.userMe.get() + const orgX = factories.organizations.organization({ name: "Test Org" }) + const mitxOnlineUser = factories.user.user({ + b2b_organizations: [ + { + ...orgX, + slug: `org-${orgX.slug}`, + }, + ], + }) + + return { orgX, user, mitxOnlineUser } +} + +/** + * Helper function to set up all necessary API mocks for organization dashboard + */ +function setupOrgDashboardMocks( + org: OrganizationPage, + user: string, + mitxOnlineUser: User, + programs: V2Program[], + courses: CourseWithCourseRunsSerializerV2[], + contracts: ContractPage[], +) { + // Basic user and org setup + setMockResponse.get(u.urls.userMe.get(), user) + setMockResponse.get(mitxonline.urls.currentUser.get(), mitxOnlineUser) + setMockResponse.get( + mitxonline.urls.organization.organizationList(org.slug), + org, + ) + + // Empty defaults + setMockResponse.get(mitxonline.urls.enrollment.enrollmentsList(), []) + setMockResponse.get(mitxonline.urls.programEnrollments.enrollmentsList(), []) + setMockResponse.get(mitxonline.urls.contracts.contractsList(), contracts) + setMockResponse.get( + mitxonline.urls.programCollections.programCollectionsList(), + { results: [] }, + ) + + // Program and course data + setMockResponse.get( + mitxonline.urls.programs.programsList({ org_id: org.id }), + { results: programs }, + ) + + programs.forEach((program) => { + setMockResponse.get( + mitxonline.urls.courses.coursesList({ + id: program.courses, + org_id: org.id, + }), + { results: courses }, + ) + }) +} + +/** + * Test utility to create B2B contracts for testing + */ +const createTestContracts = ( + orgId: number, + count: number = 1, +): ContractPage[] => { + return Array.from({ length: count }, () => ({ + id: faker.number.int(), + active: true, + contract_end: faker.date.future().toISOString(), + contract_start: faker.date.past().toISOString(), + description: faker.lorem.sentence(), + integration_type: IntegrationTypeEnum.NonSso, + name: faker.company.name(), + organization: orgId, + slug: faker.lorem.slug(), + })) +} + +/** + * Test utility to create courses with contract-scoped course runs + */ +const createCoursesWithContractRuns = (contracts: ContractPage[]) => { + const contractIds = contracts.map((c) => c.id) + + return factories.courses.courses({ count: 3 }).results.map((course) => ({ + ...course, + courseruns: [ + // First run associated with organization's contract + { + ...course.courseruns[0], + id: faker.number.int(), + b2b_contract: contractIds[0], // Associated with org contract + start_date: faker.date.future().toISOString(), + end_date: faker.date.future().toISOString(), + title: `${course.title} - Org Contract Run`, + }, + // Second run associated with different organization's contract + { + ...course.courseruns[0], + id: faker.number.int(), + b2b_contract: faker.number.int(), // Different contract ID + start_date: faker.date.past().toISOString(), + end_date: faker.date.past().toISOString(), + title: `${course.title} - Other Org Run`, + }, + // Third run with no contract (general enrollment) + { + ...course.courseruns[0], + id: faker.number.int(), + b2b_contract: null, + start_date: faker.date.future().toISOString(), + end_date: faker.date.future().toISOString(), + title: `${course.title} - General Run`, + }, + ], + })) +} + +export { + dashboardCourse, + setupEnrollments, + setupProgramsAndCourses, + setupOrgAndUser, + setupOrgDashboardMocks, + createTestContracts, + createCoursesWithContractRuns, + createEnrollmentsForContractRuns, +} diff --git a/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/transform.test.tsx b/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/transform.test.tsx index 52dc51ef12..36710115ef 100644 --- a/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/transform.test.tsx +++ b/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/transform.test.tsx @@ -1,13 +1,19 @@ -import { factories as mitx } from "api/mitxonline-test-utils" +import { factories, factories as mitx } from "api/mitxonline-test-utils" import * as transform from "./transform" import { DashboardResourceType, EnrollmentStatus } from "./types" import type { DashboardResource } from "./types" import { - mitxonlineCourses, + mitxonlineOrgCourses, mitxonlineProgram, sortDashboardCourses, } from "./transform" -import { setupProgramsAndCourses } from "./test-utils" +import { + createCoursesWithContractRuns, + createTestContracts, + setupProgramsAndCourses, + createEnrollmentsForContractRuns, +} from "./test-utils" +import { faker } from "@faker-js/faker/locale/en" describe("Transforming mitxonline enrollment data to DashboardResource", () => { test.each([ @@ -26,7 +32,9 @@ describe("Transforming mitxonline enrollment data to DashboardResource", () => { const apiData = mitx.enrollment.courseEnrollment({ grades, }) - const transformed = transform.mitxonlineEnrollments([apiData]) + const transformed = transform.mitxonlineEnrollmentsToDashboardCourses([ + apiData, + ]) expect(transformed).toHaveLength(1) expect(transformed[0]).toEqual({ key: `mitxonline-course-${apiData.run.course.id}-${apiData.run.id}`, @@ -62,7 +70,9 @@ describe("Transforming mitxonline enrollment data to DashboardResource", () => { // @ts-expect-error not fully implementing product objects run: { products: [{ price: "10" }, { price: "20" }] }, }) - const transformed = transform.mitxonlineEnrollments([apiData]) + const transformed = transform.mitxonlineEnrollmentsToDashboardCourses([ + apiData, + ]) expect(transformed).toHaveLength(1) expect(transformed[0].run.certificateUpgradePrice).toEqual("10") }) @@ -72,18 +82,24 @@ describe("Transforming mitxonline enrollment data to DashboardResource", () => { const enrollments = [ mitx.enrollment.courseEnrollment({ - run: { course: { id: coursesA[0].id } }, + run: { + id: coursesA[0].courseruns[0].id, + course: { id: coursesA[0].id }, + }, grades: [mitx.enrollment.grade({ passed: true })], enrollment_mode: "audit", }), mitx.enrollment.courseEnrollment({ - run: { course: { id: coursesA[1].id } }, + run: { + id: coursesA[1].courseruns[0].id, + course: { id: coursesA[1].id }, + }, grades: [], enrollment_mode: "verified", }), ] - const transformedCourses = mitxonlineCourses({ + const transformedCourses = mitxonlineOrgCourses({ courses: coursesA, enrollments, }) @@ -92,11 +108,220 @@ describe("Transforming mitxonline enrollment data to DashboardResource", () => { transformedCourses, ) - expect(sortedCourses).toEqual([ - transformedCourses[1], // Enrolled course - transformedCourses[0], // Completed course - transformedCourses[2], // Not enrolled course - transformedCourses[3], // Not enrolled course - ]) + const enrolledCourse = sortedCourses.find( + (course) => course.enrollment?.status === EnrollmentStatus.Enrolled, + ) + const completedCourse = sortedCourses.find( + (course) => course.enrollment?.status === EnrollmentStatus.Completed, + ) + const notEnrolledCourses = sortedCourses.filter( + (course) => + !course.enrollment || + course.enrollment.status === EnrollmentStatus.NotEnrolled, + ) + + // Verify we found all expected courses + expect(enrolledCourse).toBeDefined() + expect(completedCourse).toBeDefined() + expect(notEnrolledCourses).toHaveLength(2) + + // Verify sorting: enrolled first, then completed, then not enrolled + expect(sortedCourses[0]).toEqual(enrolledCourse) // Enrolled course should be first + expect(sortedCourses[1]).toEqual(completedCourse) // Completed course should be second + expect(sortedCourses[2]).toEqual(notEnrolledCourses[0]) // First not enrolled course + expect(sortedCourses[3]).toEqual(notEnrolledCourses[1]) // Second not enrolled course + }) + + test("selects course runs associated with organization's contract", () => { + const orgId = faker.number.int() + const contracts = createTestContracts(orgId, 2) + const contractIds = contracts.map((c) => c.id) + const courses = createCoursesWithContractRuns(contracts) + + const transformedCourses = transform.mitxonlineOrgCourses({ + courses, + contracts, + enrollments: [], + }) + + // Should have transformed all courses + expect(transformedCourses).toHaveLength(3) + + transformedCourses.forEach((transformedCourse, index) => { + const originalCourse = courses[index] + + // Should use the course run with matching contract + const expectedRun = originalCourse.courseruns.find( + (run) => run.b2b_contract && contractIds.includes(run.b2b_contract), + ) + + expect(transformedCourse.run.startDate).toBe(expectedRun?.start_date) + expect(transformedCourse.run.endDate).toBe(expectedRun?.end_date) + expect(transformedCourse.coursewareId).toBe( + expectedRun?.courseware_id ?? null, + ) + }) + }) + + test("falls back to unenrolled course when no contract-matching runs exist", () => { + const orgId = faker.number.int() + const contracts = createTestContracts(orgId, 1) + + // Create courses where runs don't match the contract + const courses = factories.courses + .courses({ count: 2 }) + .results.map((course) => ({ + ...course, + courseruns: course.courseruns.map((run) => ({ + ...run, + b2b_contract: faker.number.int(), // Different contract ID + })), + })) + + const transformedCourses = transform.mitxonlineOrgCourses({ + courses, + contracts, + enrollments: [], + }) + + transformedCourses.forEach((transformedCourse) => { + // Should not have enrollment since no matching contract runs + expect(transformedCourse.enrollment).toBeUndefined() + + // Should still have course data but with contract-scoped run or null + expect(transformedCourse.title).toBeDefined() + expect(transformedCourse.type).toBe("course") + }) + }) + + test("includes enrollments only for contract-scoped runs", () => { + const orgId = faker.number.int() + const contracts = createTestContracts(orgId, 1) + const contractIds = contracts.map((c) => c.id) + const courses = createCoursesWithContractRuns(contracts) + const enrollments = createEnrollmentsForContractRuns(courses, contractIds) + + const transformedCourses = transform.mitxonlineOrgCourses({ + courses, + contracts, + enrollments, + }) + + // Should have enrollments for courses with contract-matching runs + const enrolledCourses = transformedCourses.filter( + (course) => course.enrollment, + ) + expect(enrolledCourses.length).toBeGreaterThan(0) + + enrolledCourses.forEach((course) => { + expect(course.enrollment).toBeDefined() + expect(course.enrollment?.status).toMatch(/enrolled|completed/) + }) + }) + + test("filters out enrollments for non-contract runs", () => { + const orgId = faker.number.int() + const contracts = createTestContracts(orgId, 1) + const contractIds = contracts.map((c) => c.id) + const courses = createCoursesWithContractRuns(contracts) + + // Create enrollments for both contract and non-contract runs + const contractEnrollments = createEnrollmentsForContractRuns( + courses, + contractIds, + ) + const nonContractEnrollments = courses.flatMap((course) => + course.courseruns + .filter( + (run) => !run.b2b_contract || !contractIds.includes(run.b2b_contract), + ) + .map((run) => + factories.enrollment.courseEnrollment({ + run: { + id: run.id, + course: { id: course.id, title: course.title }, + title: run.title, + }, + }), + ), + ) + + const allEnrollments = [...contractEnrollments, ...nonContractEnrollments] + + const transformedCourses = transform.mitxonlineOrgCourses({ + courses, + contracts, + enrollments: allEnrollments, + }) + + // Should only include enrollments for contract runs + const enrolledCourses = transformedCourses.filter( + (course) => course.enrollment, + ) + + enrolledCourses.forEach((course) => { + // Verify the enrollment corresponds to a contract run + const originalCourse = courses.find( + (c) => c.id.toString() === course.key.split("-")[2], + ) + const contractRun = originalCourse?.courseruns.find( + (run) => run.b2b_contract && contractIds.includes(run.b2b_contract), + ) + expect(contractRun).toBeDefined() + }) + }) + + test("selects run associated with contract for unenrolled courses", () => { + const orgId = faker.number.int() + const contracts = createTestContracts(orgId, 1) + const contractIds = contracts.map((c) => c.id) + const courses = createCoursesWithContractRuns(contracts) + + courses.forEach((course) => { + const transformedCourse = transform.mitxonlineOrgUnenrolledCourse( + course, + contracts, + ) + + // Should select the run with matching contract + const expectedRun = course.courseruns.find( + (run) => run.b2b_contract && contractIds.includes(run.b2b_contract), + ) + + expect(transformedCourse.run.startDate).toBe(expectedRun?.start_date) + expect(transformedCourse.coursewareId).toBe( + expectedRun?.courseware_id ?? null, + ) + }) + }) + + test("handles courses with no contract-matching runs gracefully", () => { + const orgId = faker.number.int() + const contracts = createTestContracts(orgId, 1) + + const course = factories.courses.course({ + courseruns: [ + { + ...factories.courses.course().courseruns[0], + b2b_contract: faker.number.int(), // Different contract + }, + ], + }) + + const transformedCourse = transform.mitxonlineOrgUnenrolledCourse( + course, + contracts, + ) + + // Should still return a valid course object + expect(transformedCourse.title).toBe(course.title) + expect(transformedCourse.type).toBe("course") + + // Run data should be null/empty since no matching contract run found + expect(transformedCourse.run.startDate).toBeUndefined() + expect(transformedCourse.run.endDate).toBeUndefined() + expect(transformedCourse.run.coursewareUrl).toBeUndefined() + expect(transformedCourse.coursewareId).toBeNull() + expect(transformedCourse.run.canUpgrade).toBe(false) // !!undefined is false }) }) diff --git a/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/transform.ts b/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/transform.ts index b96af4ce58..6fe1cf7cbb 100644 --- a/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/transform.ts +++ b/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/transform.ts @@ -5,6 +5,7 @@ */ import { + ContractPage, CourseRunEnrollment, CourseWithCourseRunsSerializerV2, V2Program, @@ -13,7 +14,9 @@ import { import { DashboardResourceType, EnrollmentStatus } from "./types" import type { + DashboardContract, DashboardCourse, + DashboardCourseEnrollment, DashboardProgram, DashboardProgramCollection, } from "./types" @@ -33,52 +36,128 @@ const getKey = ({ source, resourceType, id, runId }: KeyOpts) => { return runId ? `${base}-${runId}` : base } -const mitxonlineEnrollment = (raw: CourseRunEnrollment): DashboardCourse => { - const course = raw.run.course - return { +const mitxonlineCourse = ( + raw: CourseWithCourseRunsSerializerV2, + enrollment?: DashboardCourseEnrollment | undefined, +): DashboardCourse => { + const run = raw.courseruns[0] + const transformedCourse = { key: getKey({ source: sources.mitxonline, resourceType: DashboardResourceType.Course, - id: course.id, - runId: raw.run.id, + id: raw.id, + runId: run?.id, }), - coursewareId: raw.run.courseware_id ?? null, + coursewareId: run?.courseware_id ?? null, type: DashboardResourceType.Course, - title: course.title, - marketingUrl: course.page?.page_url, + title: raw.title, + marketingUrl: raw.page?.page_url, run: { - startDate: raw.run.start_date, - endDate: raw.run.end_date, - certificateUpgradeDeadline: raw.run.upgrade_deadline, - certificateUpgradePrice: raw.run.products[0]?.price, - canUpgrade: raw.run.is_upgradable, - coursewareUrl: raw.run.courseware_url, - certificate: { - uuid: raw.certificate?.uuid ?? "", - link: - raw.certificate?.link?.replace( - /^\/certificate\/([^/]+)\/$/, - "/certificate/course/$1/", - ) ?? "", - }, + startDate: run?.start_date, + endDate: run?.end_date, + certificateUpgradeDeadline: run?.upgrade_deadline, + certificateUpgradePrice: run?.products[0]?.price, + coursewareUrl: run?.courseware_url, + canUpgrade: !!run?.is_upgradable, }, - enrollment: { - id: raw.id, - mode: raw.enrollment_mode, - status: raw.grades[0]?.passed + } as DashboardCourse + + if (enrollment) { + transformedCourse.enrollment = enrollment + } + return transformedCourse +} + +const mitxonlineEnrollmentsToDashboardCourses = ( + data: CourseRunEnrollment[], +): DashboardCourse[] => { + return data.map((enrollment) => { + const course = enrollment.run.course + const run = enrollment.run + return { + key: getKey({ + source: sources.mitxonline, + resourceType: DashboardResourceType.Course, + id: course.id, + runId: run.id, + }), + coursewareId: run?.courseware_id ?? null, + type: DashboardResourceType.Course, + title: course.title, + marketingUrl: course.page?.page_url, + run: { + startDate: run?.start_date, + endDate: run?.end_date, + certificateUpgradeDeadline: run?.upgrade_deadline, + certificateUpgradePrice: run?.products[0]?.price, + canUpgrade: run?.is_upgradable, + coursewareUrl: run?.courseware_url, + certificate: { + uuid: enrollment.certificate?.uuid ?? "", + link: + enrollment.certificate?.link?.replace( + /^\/certificate\/([^/]+)\/$/, + "/certificate/course/$1/", + ) ?? "", + }, + }, + enrollment: { + id: enrollment.id, + mode: enrollment.enrollment_mode, + status: + enrollment.grades.length > 0 && enrollment.grades[0]?.passed + ? EnrollmentStatus.Completed + : EnrollmentStatus.Enrolled, + receiveEmails: enrollment.edx_emails_subscription ?? true, + }, + } + }) +} + +const mitxonlineOrgContract = (raw: ContractPage): DashboardContract => { + return { + id: raw.id, + active: raw.active, + contract_end: raw.contract_end, + contract_start: raw.contract_start, + description: raw.description, + integration_type: raw.integration_type, + name: raw.name, + organization: raw.organization, + slug: raw.slug, + } +} + +const mitxonlineOrgEnrollment = ( + raw: CourseRunEnrollment, + course: CourseWithCourseRunsSerializerV2, +): DashboardCourseEnrollment => { + const run = course.courseruns.find((run) => run.id === raw.run.id) + return { + id: raw.id, + b2b_contract: run?.b2b_contract, + status: + raw.grades.length > 0 && raw.grades[0]?.passed ? EnrollmentStatus.Completed : EnrollmentStatus.Enrolled, - receiveEmails: raw.edx_emails_subscription ?? true, - }, + mode: raw.enrollment_mode, + receiveEmails: raw.edx_emails_subscription ?? true, } } -const mitxonlineEnrollments = (data: CourseRunEnrollment[]) => - data.map((course) => mitxonlineEnrollment(course)) +const mitxonlineOrgEnrollments = ( + data: CourseRunEnrollment[], + course: CourseWithCourseRunsSerializerV2, +): DashboardCourseEnrollment[] => + data.map((enrollment) => mitxonlineOrgEnrollment(enrollment, course)) -const mitxonlineUnenrolledCourse = ( +const mitxonlineOrgUnenrolledCourse = ( course: CourseWithCourseRunsSerializerV2, + contracts: ContractPage[] | undefined, ): DashboardCourse => { - const run = course.courseruns.find((run) => run.id === course.next_run_id) + const contractIds = contracts?.map((contract) => contract.id) + const run = course.courseruns.find((run) => { + return run.b2b_contract && contractIds?.includes(run.b2b_contract) + }) return { key: getKey({ source: sources.mitxonline, @@ -101,27 +180,61 @@ const mitxonlineUnenrolledCourse = ( } } -const mitxonlineCourses = (raw: { +const mitxonlineOrgCourses = (raw: { courses: CourseWithCourseRunsSerializerV2[] + contracts?: ContractPage[] // Make optional enrollments: CourseRunEnrollment[] -}) => { +}): DashboardCourse[] => { const enrollmentsByCourseId = groupBy( raw.enrollments, (enrollment) => enrollment.run.course.id, ) + + // Get contract IDs for easy lookup + const contractIds = raw.contracts?.map((contract) => contract.id) || [] + const transformedCourses = raw.courses.map((course) => { const enrollments = enrollmentsByCourseId[course.id] + if (enrollments?.length > 0) { - const transformed = mitxonlineEnrollments(enrollments) - const completed = transformed.find( - (e) => e.enrollment?.status === EnrollmentStatus.Completed, + const transformedEnrollments = mitxonlineOrgEnrollments( + enrollments, + course, ) - if (completed) { - return completed + if (raw.contracts && raw.contracts.length > 0) { + // Filter enrollments to only include those with valid contracts + const validEnrollments = transformedEnrollments.filter((enrollment) => { + const courseRunContractId = enrollment.b2b_contract + return ( + courseRunContractId && contractIds.includes(courseRunContractId) + ) + }) + + if (validEnrollments.length > 0) { + const dashboardCourse = mitxonlineCourse(course, validEnrollments[0]) + return dashboardCourse + } + + // If contracts are provided but a matching one isn't found, treat it as unenrolled + return mitxonlineOrgUnenrolledCourse(course, raw.contracts) + } else if (enrollments?.length > 0) { + // If no contracts provided, just find the matching enrollment to the course + const matchingEnrollment = enrollments.find( + (enrollment) => + course.courseruns.find((run) => run.id === enrollment.run.id) + ?.id === enrollment.run.id, + ) + if (matchingEnrollment) { + return mitxonlineCourse( + course, + mitxonlineOrgEnrollment(matchingEnrollment, course), + ) + } } - return transformed[0] } - return mitxonlineUnenrolledCourse(course) + + // If no enrollments or no matching enrollment found, treat it as unenrolled + return mitxonlineOrgUnenrolledCourse(course, raw.contracts) }) return transformedCourses } @@ -160,29 +273,23 @@ const sortDashboardCourses = ( courses: DashboardCourse[], ) => { return [...courses].sort((a, b) => { - const aCompleted = a.enrollment?.status === EnrollmentStatus.Completed - const bCompleted = b.enrollment?.status === EnrollmentStatus.Completed - const aEnrolled = a.enrollment?.status === EnrollmentStatus.Enrolled - const bEnrolled = b.enrollment?.status === EnrollmentStatus.Enrolled - if (aEnrolled && !bEnrolled) { - return -1 - } - if (!aEnrolled && bEnrolled) { - return 1 + const getStatusPriority = (course: DashboardCourse): number => { + if (course.enrollment?.status === EnrollmentStatus.Enrolled) return 1 + if (course.enrollment?.status === EnrollmentStatus.Completed) return 2 + return 3 // Not enrolled or no enrollment } - if (aCompleted && !bCompleted) { - return -1 - } - if (!aCompleted && bCompleted) { - return 1 - } - return 0 + + return getStatusPriority(a) - getStatusPriority(b) }) } export { - mitxonlineEnrollments, - mitxonlineCourses, + mitxonlineCourse, + mitxonlineEnrollmentsToDashboardCourses, + mitxonlineOrgContract, + mitxonlineOrgEnrollments, + mitxonlineOrgCourses, + mitxonlineOrgUnenrolledCourse, mitxonlineProgram, mitxonlineProgramCollection, sortDashboardCourses, diff --git a/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/types.ts b/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/types.ts index 0ad12e14d5..0faa8a8b5c 100644 --- a/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/types.ts +++ b/frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/types.ts @@ -1,4 +1,5 @@ const DashboardResourceType = { + Contract: "contract", Course: "course", Program: "program", ProgramCollection: "program_collection", @@ -19,6 +20,18 @@ const EnrollmentMode = { } as const type EnrollmentMode = (typeof EnrollmentMode)[keyof typeof EnrollmentMode] +type DashboardContract = { + id: number + active: boolean + contract_end: string | null + contract_start: string | null + description: string | null + integration_type: string | null + name: string | null + organization: number | null + slug: string | null +} + type DashboardCourse = { key: string coursewareId: string | null @@ -30,22 +43,18 @@ type DashboardCourse = { certificateUpgradeDeadline?: string | null certificateUpgradePrice?: string | null coursewareUrl?: string | null - canUpgrade: boolean + canUpgrade: boolean | undefined certificate?: { uuid: string link: string } } - enrollment?: { - id: number - status: EnrollmentStatus - mode: EnrollmentMode - receiveEmails?: boolean - } + enrollment?: DashboardCourseEnrollment marketingUrl: string } type DashboardCourseEnrollment = { id: number + b2b_contract?: number | null | undefined status: EnrollmentStatus mode: EnrollmentMode receiveEmails?: boolean @@ -78,6 +87,7 @@ type DashboardResource = export { DashboardResourceType, EnrollmentStatus, EnrollmentMode } export type { DashboardResource, + DashboardContract, DashboardCourse, DashboardCourseEnrollment, DashboardProgram, diff --git a/frontends/main/src/app-pages/DashboardPage/OrganizationContent.test.tsx b/frontends/main/src/app-pages/DashboardPage/OrganizationContent.test.tsx index 379f596741..d066d772b0 100644 --- a/frontends/main/src/app-pages/DashboardPage/OrganizationContent.test.tsx +++ b/frontends/main/src/app-pages/DashboardPage/OrganizationContent.test.tsx @@ -5,11 +5,20 @@ import { setMockResponse } from "api/test-utils" import { urls, factories } from "api/mitxonline-test-utils" import { useFeatureFlagEnabled } from "posthog-js/react" import { - mitxonlineCourses, + mitxonlineOrgCourses, mitxonlineProgram, sortDashboardCourses, } from "./CoursewareDisplay/transform" -import { setupProgramsAndCourses } from "./CoursewareDisplay/test-utils" +import { + createCoursesWithContractRuns, + createEnrollmentsForContractRuns, + createTestContracts, + setupOrgAndUser, + setupProgramsAndCourses, + setupOrgDashboardMocks, +} from "./CoursewareDisplay/test-utils" +import { EnrollmentStatus } from "./CoursewareDisplay/types" +import { faker } from "@faker-js/faker/locale/en" const makeCourseEnrollment = factories.enrollment.courseEnrollment const makeGrade = factories.enrollment.grade @@ -22,10 +31,9 @@ const mockedUseFeatureFlagEnabled = jest describe("OrganizationContent", () => { beforeEach(() => { mockedUseFeatureFlagEnabled.mockReturnValue(true) - // Set default empty enrollments for all tests setMockResponse.get(urls.enrollment.enrollmentsList(), []) - // Add missing program enrollments mock setMockResponse.get(urls.programEnrollments.enrollmentsList(), []) + setMockResponse.get(urls.contracts.contractsList(), []) }) it("displays a header for each program returned and cards for courses in program", async () => { @@ -82,16 +90,18 @@ describe("OrganizationContent", () => { expect(cards.length).toBeGreaterThan(0) const sortedCourses = sortDashboardCourses( mitxonlineProgram(programA), - mitxonlineCourses({ courses: coursesA, enrollments: enrollments }), + mitxonlineOrgCourses({ courses: coursesA, enrollments: enrollments }), ) + cards.forEach((card, i) => { const course = sortedCourses[i] expect(card).toHaveTextContent(course.title) const indicator = within(card).getByTestId("enrollment-status") - if (i === 0) { + // Check based on the actual enrollment status, not array position + if (course.enrollment?.status === EnrollmentStatus.Enrolled) { expect(indicator).toHaveTextContent("Enrolled") - } else if (i === 1) { + } else if (course.enrollment?.status === EnrollmentStatus.Completed) { expect(indicator).toHaveTextContent("Completed") } else { expect(indicator).toHaveTextContent("Not Enrolled") @@ -339,4 +349,322 @@ describe("OrganizationContent", () => { programWithCertificate.certificate.url, ) }) + + test("displays only courses with contract-scoped runs", async () => { + const { orgX, user, mitxOnlineUser } = setupOrgAndUser() + const contracts = createTestContracts(orgX.id, 1) + const courses = createCoursesWithContractRuns(contracts).map((course) => ({ + ...course, + courseruns: course.courseruns.map((run) => { + if (run.b2b_contract === contracts[0].id) { + return { + ...run, + start_date: faker.date.past().toISOString(), // Make it started + } + } + return run + }), + })) + const program = factories.programs.program({ + courses: courses.map((c) => c.id), + }) + + // Create enrollments so the button will have href + const enrollments = createEnrollmentsForContractRuns(courses, [ + contracts[0].id, + ]) + + // Setup API mocks + setupOrgDashboardMocks( + orgX, + user, + mitxOnlineUser, + [program], + courses, + contracts, + ) + + // Override enrollments for this test + setMockResponse.get(urls.enrollment.enrollmentsList(), enrollments) + + renderWithProviders() + + // Wait for programs to load + const programElements = await screen.findAllByTestId("org-program-root") + expect(programElements).toHaveLength(1) + + // Verify courses are displayed with correct run information + const cards = await within(programElements[0]).findAllByTestId( + "enrollment-card-desktop", + ) + expect(cards.length).toBeGreaterThan(0) + + // Check that each card shows course information from contract-scoped run + cards.forEach((card, index) => { + const course = courses[index] + const contractRun = course.courseruns.find( + (run) => + run.b2b_contract && contracts.some((c) => c.id === run.b2b_contract), + ) + + expect(card).toHaveTextContent(course.title) + + // Verify we're using the contract-scoped run, not the other runs + expect(contractRun).toBeDefined() + expect(contractRun?.b2b_contract).toBe(contracts[0].id) + + // Check that the card displays information from the correct course run + const coursewareButton = within(card).getByTestId("courseware-button") + + // The courseware button shows different text based on course type and enrollment status + // For enrolled users in started courses, it shows "Continue Course" or "Continue Module" + expect(coursewareButton).toHaveTextContent(/Continue (Course|Module)/i) + + // Verify the courseware button has the correct href from the contract run + // Only check href if the course has started and user is enrolled + if ( + contractRun?.courseware_url && + new Date(contractRun.start_date) <= new Date() + ) { + expect(coursewareButton).toHaveAttribute( + "href", + contractRun.courseware_url, + ) + } + + // Check for enrollment status indicator showing "Enrolled" since we created enrollments + const enrollmentStatus = within(card).getByTestId("enrollment-status") + expect(enrollmentStatus).toHaveTextContent("Enrolled") + }) + }) + + test("shows correct run dates from contract-scoped runs", async () => { + const { orgX, user, mitxOnlineUser } = setupOrgAndUser() + const contracts = createTestContracts(orgX.id, 1) + + // Create courses with specific, predictable dates for the contract runs + const specificStartDate = "2025-12-01T00:00:00Z" + const specificEndDate = "2026-01-15T00:00:00Z" + + const courses = createCoursesWithContractRuns(contracts).map((course) => ({ + ...course, + courseruns: course.courseruns.map((run) => { + if (run.b2b_contract === contracts[0].id) { + return { + ...run, + start_date: specificStartDate, + end_date: specificEndDate, + } + } + return run + }), + })) + + const program = factories.programs.program({ + courses: courses.map((c) => c.id), + }) + + setupOrgDashboardMocks( + orgX, + user, + mitxOnlineUser, + [program], + courses, + contracts, + ) + + renderWithProviders() + + const cards = await within( + await screen.findByTestId("org-program-root"), + ).findAllByTestId("enrollment-card-desktop") + + // Verify that the displayed information comes from the contract run dates + cards.forEach((card) => { + // Check for start date countdown - the actual format is "Starts in X days" + // Since we set a specific future date, it should show the countdown + expect(card).toHaveTextContent(/Starts in \d+ days?/i) + }) + }) + + test("ignores non-contract runs when displaying course information", async () => { + const { orgX, user, mitxOnlineUser } = setupOrgAndUser() + const contracts = createTestContracts(orgX.id, 1) + + // Create courses where non-contract runs have different, easily identifiable data + const courses = createCoursesWithContractRuns(contracts).map((course) => ({ + ...course, + courseruns: course.courseruns.map((run) => { + if (run.b2b_contract !== contracts[0].id) { + return { + ...run, + title: `WRONG RUN - ${run.title}`, + courseware_url: "https://wrong-run.example.com", + start_date: "2023-01-01T00:00:00Z", // Past date + } + } + return { + ...run, + title: `CORRECT RUN - ${run.title}`, + courseware_url: "https://correct-run.example.com", + start_date: "2025-12-01T00:00:00Z", // Future date + } + }), + })) + + const program = factories.programs.program({ + courses: courses.map((c) => c.id), + }) + + setupOrgDashboardMocks( + orgX, + user, + mitxOnlineUser, + [program], + courses, + contracts, + ) + + renderWithProviders() + + const cards = await within( + await screen.findByTestId("org-program-root"), + ).findAllByTestId("enrollment-card-desktop") + + cards.forEach((card) => { + // Verify we're NOT seeing data from the wrong runs + expect(card).not.toHaveTextContent("WRONG RUN") + + // Verify courseware button doesn't point to wrong run URL + const coursewareButton = within(card).getByTestId("courseware-button") + expect(coursewareButton).not.toHaveAttribute( + "href", + "https://wrong-run.example.com", + ) + + // Should show countdown for future date (from correct run), not past date + // The actual format is "Starts in X days" + expect(card).toHaveTextContent(/Starts in \d+ days?/i) + }) + }) + + test("displays correct pricing from contract-scoped runs", async () => { + const { orgX, user, mitxOnlineUser } = setupOrgAndUser() + const contracts = createTestContracts(orgX.id, 1) + + // Create courses with different pricing for contract vs non-contract runs + const courses = createCoursesWithContractRuns(contracts).map((course) => ({ + ...course, + courseruns: course.courseruns.map((run) => { + if (run.b2b_contract === contracts[0].id) { + return { + ...run, + products: [ + { + id: faker.number.int(), + price: "299.00", // Contract-specific price + description: "B2B Contract Price", + is_active: true, + product_flexible_price: null, + }, + ], + can_upgrade: true, + upgrade_deadline: faker.date.future().toISOString(), + } + } + return { + ...run, + products: [ + { + id: faker.number.int(), + price: "599.00", // Different price for non-contract + description: "Regular Price", + is_active: true, + product_flexible_price: null, + }, + ], + } + }), + })) + + const program = factories.programs.program({ + courses: courses.map((c) => c.id), + }) + + setupOrgDashboardMocks( + orgX, + user, + mitxOnlineUser, + [program], + courses, + contracts, + ) + + renderWithProviders() + + const cards = await within( + await screen.findByTestId("org-program-root"), + ).findAllByTestId("enrollment-card-desktop") + + cards.forEach((card) => { + // Should show upgrade banner with contract pricing, not regular pricing + const upgradeRoot = within(card).queryByTestId("upgrade-root") + if (upgradeRoot) { + expect(upgradeRoot).toHaveTextContent("$299") + expect(upgradeRoot).not.toHaveTextContent("$599") + } + }) + }) + + test("handles mixed scenarios with enrolled and non-enrolled contract runs", async () => { + const { orgX, user, mitxOnlineUser } = setupOrgAndUser() + const contracts = createTestContracts(orgX.id, 1) + const contractIds = contracts.map((c) => c.id) + const courses = createCoursesWithContractRuns(contracts) + + // Create enrollment for first course only + const enrollments = [ + factories.enrollment.courseEnrollment({ + run: { + id: courses[0].courseruns.find( + (r) => r.b2b_contract === contractIds[0], + )?.id, + course: { id: courses[0].id, title: courses[0].title }, + }, + grades: [], // No grades = enrolled but not completed + }), + ] + + const program = factories.programs.program({ + courses: courses.map((c) => c.id), + }) + + setupOrgDashboardMocks( + orgX, + user, + mitxOnlineUser, + [program], + courses, + contracts, + ) + + // Override enrollments for this test + setMockResponse.get(urls.enrollment.enrollmentsList(), enrollments) + + renderWithProviders() + + const cards = await within( + await screen.findByTestId("org-program-root"), + ).findAllByTestId("enrollment-card-desktop") + + // First card should show enrolled status + const firstCardStatus = within(cards[0]).getByTestId("enrollment-status") + expect(firstCardStatus).toHaveTextContent("Enrolled") + + // Remaining cards should show not enrolled + for (let i = 1; i < cards.length; i++) { + const cardStatus = within(cards[i]).getByTestId("enrollment-status") + expect(cardStatus).toHaveTextContent("Not Enrolled") + } + }) }) diff --git a/frontends/main/src/app-pages/DashboardPage/OrganizationContent.tsx b/frontends/main/src/app-pages/DashboardPage/OrganizationContent.tsx index 9a9fc29d35..27b91f0861 100644 --- a/frontends/main/src/app-pages/DashboardPage/OrganizationContent.tsx +++ b/frontends/main/src/app-pages/DashboardPage/OrganizationContent.tsx @@ -11,6 +11,7 @@ import { programCollectionQueries, } from "api/mitxonline-hooks/programs" import { coursesQueries } from "api/mitxonline-hooks/courses" +import { contractQueries } from "api/mitxonline-hooks/contracts" import * as transform from "./CoursewareDisplay/transform" import { enrollmentQueries } from "api/mitxonline-hooks/enrollment" import { DashboardCard } from "./CoursewareDisplay/DashboardCard" @@ -21,6 +22,7 @@ import { } from "./CoursewareDisplay/types" import graduateLogo from "@/public/images/dashboard/graduate.png" import { + ContractPage, CourseRunEnrollment, OrganizationPage, UserProgramEnrollmentDetail, @@ -166,9 +168,10 @@ const useProgramCollectionCourses = (programIds: number[], orgId: number) => { const OrgProgramCollectionDisplay: React.FC<{ collection: DashboardProgramCollection + contracts?: ContractPage[] enrollments?: CourseRunEnrollment[] orgId: number -}> = ({ collection, enrollments, orgId }) => { +}> = ({ collection, contracts, enrollments, orgId }) => { const sanitizedDescription = DOMPurify.sanitize(collection.description ?? "") const { isLoading, programsWithCourses, hasAnyCourses } = useProgramCollectionCourses(collection.programIds, orgId) @@ -216,6 +219,7 @@ const OrgProgramCollectionDisplay: React.FC<{ @@ -228,12 +232,14 @@ const OrgProgramCollectionDisplay: React.FC<{ const OrgProgramDisplay: React.FC<{ program: DashboardProgram + contracts?: ContractPage[] courseRunEnrollments?: CourseRunEnrollment[] programEnrollments?: UserProgramEnrollmentDetail[] programLoading: boolean orgId: number }> = ({ program, + contracts, courseRunEnrollments, programEnrollments, programLoading, @@ -250,8 +256,9 @@ const OrgProgramDisplay: React.FC<{ ) if (programLoading || courses.isLoading) return skeleton - const transformedCourses = transform.mitxonlineCourses({ + const transformedCourses = transform.mitxonlineOrgCourses({ courses: courses.data?.results ?? [], + contracts: contracts ?? [], enrollments: courseRunEnrollments ?? [], }) const sanitizedHtml = DOMPurify.sanitize(program.description) @@ -300,19 +307,26 @@ const OrgProgramDisplay: React.FC<{ const ProgramCollectionItem: React.FC<{ program: DashboardProgram + contracts?: ContractPage[] enrollments?: CourseRunEnrollment[] orgId: number -}> = ({ program, enrollments, orgId }) => { +}> = ({ program, contracts, enrollments, orgId }) => { return ( - + ) } const ProgramCard: React.FC<{ program: DashboardProgram + contracts?: ContractPage[] enrollments?: CourseRunEnrollment[] orgId: number -}> = ({ program, enrollments, orgId }) => { +}> = ({ program, contracts, enrollments, orgId }) => { const courses = useQuery( coursesQueries.coursesList({ id: program.courseIds, @@ -323,8 +337,9 @@ const ProgramCard: React.FC<{ ) if (courses.isLoading) return skeleton - const transformedCourses = transform.mitxonlineCourses({ + const transformedCourses = transform.mitxonlineOrgCourses({ courses: courses.data?.results ?? [], + contracts: contracts ?? [], enrollments: enrollments ?? [], }) if (courses.isLoading || !transformedCourses.length) return skeleton @@ -359,6 +374,10 @@ const OrganizationContentInternal: React.FC< FeatureFlags.OrganizationDashboard, ) const orgId = org.id + const contracts = useQuery(contractQueries.contractsList()) + const orgContracts = contracts.data?.filter( + (contract) => contract.organization === orgId, + ) const courseRunEnrollments = useQuery( enrollmentQueries.courseRunEnrollmentsList(), ) @@ -392,6 +411,7 @@ const OrganizationContentInternal: React.FC< : transformedPrograms.map((program) => ( diff --git a/learning_resources/etl/canvas.py b/learning_resources/etl/canvas.py index 6e0ef24042..248882a9ea 100644 --- a/learning_resources/etl/canvas.py +++ b/learning_resources/etl/canvas.py @@ -1,4 +1,5 @@ import base64 +import json import logging import sys import zipfile @@ -8,6 +9,7 @@ from io import BytesIO from pathlib import Path from tempfile import TemporaryDirectory +from urllib.parse import unquote_plus import pypdfium2 as pdfium from defusedxml import ElementTree @@ -46,10 +48,11 @@ def sync_canvas_archive(bucket, key: str, overwrite): from learning_resources.etl.loaders import load_content_files, load_problem_files course_folder = key.lstrip(settings.CANVAS_COURSE_BUCKET_PREFIX).split("/")[0] - + url_config_file = f"{key.split('.imscc')[0]}.metadata.json" with TemporaryDirectory() as export_tempdir: course_archive_path = Path(export_tempdir, key.split("/")[-1]) bucket.download_file(key, course_archive_path) + url_config = _get_url_config(bucket, export_tempdir, url_config_file) resource_readable_id, run = run_for_canvas_archive( course_archive_path, course_folder=course_folder, overwrite=overwrite ) @@ -58,7 +61,7 @@ def sync_canvas_archive(bucket, key: str, overwrite): load_content_files( run, transform_canvas_content_files( - course_archive_path, run, overwrite=overwrite + course_archive_path, run, url_config=url_config, overwrite=overwrite ), ) @@ -74,6 +77,22 @@ def sync_canvas_archive(bucket, key: str, overwrite): return resource_readable_id +def _get_url_config(bucket, export_tempdir: str, url_config_file: str) -> dict: + """ + Get URL (citation) config from the metadata JSON file + """ + url_config_path = Path(export_tempdir, url_config_file.split("/")[-1]) + # download the url config file + bucket.download_file(url_config_file, url_config_path) + url_config = {} + with Path.open(url_config_path, "rb") as f: + for url_item in json.loads(f.read().decode("utf-8")).get("course_files", []): + url_key = url_item["file_path"] + url_key = unquote_plus(url_key.lstrip(url_key.split("/")[0])) + url_config[url_key] = url_item["url"] + return url_config + + def _course_url(course_archive_path) -> str: context_info = parse_context_xml(course_archive_path) return f"https://{context_info.get('canvas_domain')}/courses/{context_info.get('course_id')}/" @@ -149,7 +168,7 @@ def parse_canvas_settings(course_archive_path): def transform_canvas_content_files( - course_zipfile: Path, run: LearningResourceRun, *, overwrite + course_zipfile: Path, run: LearningResourceRun, url_config: list, *, overwrite ) -> Generator[dict, None, None]: """ Transform content files from a Canvas course zipfile @@ -172,7 +191,14 @@ def transform_canvas_content_files( log.debug("processing active file %s", member.filename) else: log.debug("skipping unpublished file %s", member.filename) - yield from _process_olx_path(olx_path, run, overwrite=overwrite) + for content_data in _process_olx_path(olx_path, run, overwrite=overwrite): + url_path = content_data["source_path"].lstrip( + content_data["source_path"].split("/")[0] + ) + content_url = url_config.get(url_path, "") + if content_url: + content_data["url"] = content_url + yield content_data unpublished_content = run.content_files.exclude(key__in=published_keys) diff --git a/learning_resources/etl/canvas_test.py b/learning_resources/etl/canvas_test.py index 14723526f9..721d659545 100644 --- a/learning_resources/etl/canvas_test.py +++ b/learning_resources/etl/canvas_test.py @@ -2,6 +2,7 @@ import zipfile from pathlib import Path +from unittest.mock import MagicMock import pytest @@ -33,7 +34,7 @@ def canvas_platform(): return LearningResourcePlatformFactory.create(code=PlatformType.canvas.name) -def canvas_zip_with_problem_files(tmp_path: str, files: dict[tuple[str, bytes]]) -> str: +def canvas_zip_with_files(tmp_path: str, files: dict[tuple[str, bytes]]) -> str: """ Create a Canvas zip with problem files in the tutorbot folder. `files` is a list of tuples: (filename, content_bytes) @@ -41,7 +42,7 @@ def canvas_zip_with_problem_files(tmp_path: str, files: dict[tuple[str, bytes]]) zip_path = tmp_path / "canvas_course_with_problems.zip" with zipfile.ZipFile(zip_path, "w") as zf: for filename, content in files: - zf.writestr(f"tutorbot/{filename}", content) + zf.writestr(filename, content) return zip_path @@ -356,7 +357,11 @@ def test_transform_canvas_content_files_removes_unpublished_content(mocker, tmp_ # Create a fake zipfile with the published file - list(transform_canvas_content_files(Path(zip_path), run, overwrite=True)) + list( + transform_canvas_content_files( + Path(zip_path), run, url_config={}, overwrite=True + ) + ) # Ensure unpublished content is deleted and unpublished actions called bulk_unpub.assert_called_once_with([unpublished_cf.id], CONTENT_FILE_TYPE) @@ -373,7 +378,9 @@ def test_transform_canvas_problem_files_pdf_calls_pdf_to_markdown( settings.CANVAS_PDF_TRANSCRIPTION_MODEL = "fake-model" pdf_filename = "problemset1/problem.pdf" pdf_content = b"%PDF-1.4 fake pdf content" - zip_path = canvas_zip_with_problem_files(tmp_path, [(pdf_filename, pdf_content)]) + zip_path = canvas_zip_with_files( + tmp_path, [(f"tutorbot/{pdf_filename}", pdf_content)] + ) # return a file with pdf extension fake_file_data = { @@ -414,7 +421,9 @@ def test_transform_canvas_problem_files_non_pdf_does_not_call_pdf_to_markdown( settings.CANVAS_PDF_TRANSCRIPTION_MODEL = "fake-model" html_filename = "problemset2/problem.html" html_content = b"problem" - zip_path = canvas_zip_with_problem_files(tmp_path, [(html_filename, html_content)]) + zip_path = canvas_zip_with_files( + tmp_path, [(f"tutorbot/{html_filename}", html_content)] + ) fake_file_data = { "run": "run", @@ -437,3 +446,49 @@ def test_transform_canvas_problem_files_non_pdf_does_not_call_pdf_to_markdown( pdf_to_md.assert_not_called() assert results[0]["content"] == "original html content" assert results[0]["problem_title"] == "problemset2" + + +@pytest.mark.django_db +def test_transform_canvas_content_files_url_assignment(mocker, tmp_path): + """ + Test that transform_canvas_content_files assigns URLs based on url_config. + """ + run = MagicMock() + run.id = 1 + url_config = {"/folder/file1.html": "https://cdn.example.com/file1.html"} + # Patch _process_olx_path to yield content_data with source_path + mock_content_data = [ + {"source_path": "data/folder/file1.html", "key": "file1"}, + ] + mocker.patch( + "learning_resources.etl.canvas._process_olx_path", + return_value=mock_content_data, + ) + mocker.patch( + "learning_resources.etl.canvas.parse_module_meta", + return_value={"active": [], "unpublished": []}, + ) + # Use a real zip file + course_zipfile = canvas_zip_with_files( + tmp_path, [("folder/file1.html", "fake content")] + ) + # Patch published_items to always match + mocker.patch( + "learning_resources.etl.canvas.get_edx_module_id", return_value="file1" + ) + # Patch bulk_resources_unpublished_actions to do nothing + mocker.patch("learning_resources.etl.canvas.bulk_resources_unpublished_actions") + # Patch run.content_files.exclude to return a mock with delete method + run.content_files.exclude.return_value.values_list.return_value = [] + run.content_files.exclude.return_value.delete = lambda: None + + results = list( + transform_canvas_content_files( + Path(course_zipfile), + run=run, + url_config=url_config, + overwrite=False, + ) + ) + file1 = next(item for item in results if item["key"] == "file1") + assert file1["url"] == "https://cdn.example.com/file1.html" diff --git a/learning_resources/tasks.py b/learning_resources/tasks.py index 44192db255..58ae5933e9 100644 --- a/learning_resources/tasks.py +++ b/learning_resources/tasks.py @@ -501,10 +501,16 @@ def sync_canvas_courses(canvas_course_ids, overwrite): course_folder = key.lstrip(settings.CANVAS_COURSE_BUCKET_PREFIX).split("/")[0] log.info("processing course folder %s", course_folder) - if (not canvas_course_ids or course_folder in canvas_course_ids) and ( - (course_folder not in latest_archives) - or max(archive.last_modified, latest_archives[course_folder].last_modified) - == archive.last_modified + if ( + key.endswith("imscc") + and (not canvas_course_ids or course_folder in canvas_course_ids) + and ( + (course_folder not in latest_archives) + or max( + archive.last_modified, latest_archives[course_folder].last_modified + ) + == archive.last_modified + ) ): latest_archives[course_folder] = archive canvas_readable_ids = [] diff --git a/learning_resources/tasks_test.py b/learning_resources/tasks_test.py index 249cdb6cbd..1c214f90e8 100644 --- a/learning_resources/tasks_test.py +++ b/learning_resources/tasks_test.py @@ -621,10 +621,10 @@ def test_sync_canvas_courses(settings, mocker, django_assert_num_queries, canvas mocker.patch("learning_resources.tasks.get_learning_course_bucket") mock_bucket = mocker.Mock() mock_archive1 = mocker.Mock() - mock_archive1.key = "canvas/1/archive1.zip" + mock_archive1.key = "canvas/1/archive1.imscc" mock_archive1.last_modified = now_in_utc() mock_archive2 = mocker.Mock() - mock_archive2.key = "canvas/2/archive2.zip" + mock_archive2.key = "canvas/2/archive2.imscc" mock_archive2.last_modified = now_in_utc() - timedelta(days=1) mock_bucket.objects.filter.return_value = [mock_archive1, mock_archive2] mocker.patch( diff --git a/main/settings.py b/main/settings.py index 9504010afa..e268e5ac25 100644 --- a/main/settings.py +++ b/main/settings.py @@ -34,7 +34,7 @@ from main.settings_pluggy import * # noqa: F403 from openapi.settings_spectacular import open_spectacular_settings -VERSION = "0.41.5" +VERSION = "0.41.7" log = logging.getLogger() diff --git a/poetry.lock b/poetry.lock index 5a96a63f3a..d06a859767 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3878,144 +3878,128 @@ dev = ["Sphinx (==8.1.3) ; python_version >= \"3.11\"", "build (==1.2.2) ; pytho [[package]] name = "lxml" -version = "5.4.0" +version = "6.0.1" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" groups = ["main"] files = [ - {file = "lxml-5.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e7bc6df34d42322c5289e37e9971d6ed114e3776b45fa879f734bded9d1fea9c"}, - {file = "lxml-5.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6854f8bd8a1536f8a1d9a3655e6354faa6406621cf857dc27b681b69860645c7"}, - {file = "lxml-5.4.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:696ea9e87442467819ac22394ca36cb3d01848dad1be6fac3fb612d3bd5a12cf"}, - {file = "lxml-5.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ef80aeac414f33c24b3815ecd560cee272786c3adfa5f31316d8b349bfade28"}, - {file = "lxml-5.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b9c2754cef6963f3408ab381ea55f47dabc6f78f4b8ebb0f0b25cf1ac1f7609"}, - {file = "lxml-5.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7a62cc23d754bb449d63ff35334acc9f5c02e6dae830d78dab4dd12b78a524f4"}, - {file = "lxml-5.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f82125bc7203c5ae8633a7d5d20bcfdff0ba33e436e4ab0abc026a53a8960b7"}, - {file = "lxml-5.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:b67319b4aef1a6c56576ff544b67a2a6fbd7eaee485b241cabf53115e8908b8f"}, - {file = "lxml-5.4.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:a8ef956fce64c8551221f395ba21d0724fed6b9b6242ca4f2f7beb4ce2f41997"}, - {file = "lxml-5.4.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:0a01ce7d8479dce84fc03324e3b0c9c90b1ece9a9bb6a1b6c9025e7e4520e78c"}, - {file = "lxml-5.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:91505d3ddebf268bb1588eb0f63821f738d20e1e7f05d3c647a5ca900288760b"}, - {file = "lxml-5.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a3bcdde35d82ff385f4ede021df801b5c4a5bcdfb61ea87caabcebfc4945dc1b"}, - {file = "lxml-5.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:aea7c06667b987787c7d1f5e1dfcd70419b711cdb47d6b4bb4ad4b76777a0563"}, - {file = "lxml-5.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:a7fb111eef4d05909b82152721a59c1b14d0f365e2be4c742a473c5d7372f4f5"}, - {file = "lxml-5.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:43d549b876ce64aa18b2328faff70f5877f8c6dede415f80a2f799d31644d776"}, - {file = "lxml-5.4.0-cp310-cp310-win32.whl", hash = "sha256:75133890e40d229d6c5837b0312abbe5bac1c342452cf0e12523477cd3aa21e7"}, - {file = "lxml-5.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:de5b4e1088523e2b6f730d0509a9a813355b7f5659d70eb4f319c76beea2e250"}, - {file = "lxml-5.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:98a3912194c079ef37e716ed228ae0dcb960992100461b704aea4e93af6b0bb9"}, - {file = "lxml-5.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0ea0252b51d296a75f6118ed0d8696888e7403408ad42345d7dfd0d1e93309a7"}, - {file = "lxml-5.4.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b92b69441d1bd39f4940f9eadfa417a25862242ca2c396b406f9272ef09cdcaa"}, - {file = "lxml-5.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20e16c08254b9b6466526bc1828d9370ee6c0d60a4b64836bc3ac2917d1e16df"}, - {file = "lxml-5.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7605c1c32c3d6e8c990dd28a0970a3cbbf1429d5b92279e37fda05fb0c92190e"}, - {file = "lxml-5.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ecf4c4b83f1ab3d5a7ace10bafcb6f11df6156857a3c418244cef41ca9fa3e44"}, - {file = "lxml-5.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0cef4feae82709eed352cd7e97ae062ef6ae9c7b5dbe3663f104cd2c0e8d94ba"}, - {file = "lxml-5.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:df53330a3bff250f10472ce96a9af28628ff1f4efc51ccba351a8820bca2a8ba"}, - {file = "lxml-5.4.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:aefe1a7cb852fa61150fcb21a8c8fcea7b58c4cb11fbe59c97a0a4b31cae3c8c"}, - {file = "lxml-5.4.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:ef5a7178fcc73b7d8c07229e89f8eb45b2908a9238eb90dcfc46571ccf0383b8"}, - {file = "lxml-5.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d2ed1b3cb9ff1c10e6e8b00941bb2e5bb568b307bfc6b17dffbbe8be5eecba86"}, - {file = "lxml-5.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:72ac9762a9f8ce74c9eed4a4e74306f2f18613a6b71fa065495a67ac227b3056"}, - {file = "lxml-5.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f5cb182f6396706dc6cc1896dd02b1c889d644c081b0cdec38747573db88a7d7"}, - {file = "lxml-5.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:3a3178b4873df8ef9457a4875703488eb1622632a9cee6d76464b60e90adbfcd"}, - {file = "lxml-5.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e094ec83694b59d263802ed03a8384594fcce477ce484b0cbcd0008a211ca751"}, - {file = "lxml-5.4.0-cp311-cp311-win32.whl", hash = "sha256:4329422de653cdb2b72afa39b0aa04252fca9071550044904b2e7036d9d97fe4"}, - {file = "lxml-5.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:fd3be6481ef54b8cfd0e1e953323b7aa9d9789b94842d0e5b142ef4bb7999539"}, - {file = "lxml-5.4.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b5aff6f3e818e6bdbbb38e5967520f174b18f539c2b9de867b1e7fde6f8d95a4"}, - {file = "lxml-5.4.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:942a5d73f739ad7c452bf739a62a0f83e2578afd6b8e5406308731f4ce78b16d"}, - {file = "lxml-5.4.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:460508a4b07364d6abf53acaa0a90b6d370fafde5693ef37602566613a9b0779"}, - {file = "lxml-5.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:529024ab3a505fed78fe3cc5ddc079464e709f6c892733e3f5842007cec8ac6e"}, - {file = "lxml-5.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ca56ebc2c474e8f3d5761debfd9283b8b18c76c4fc0967b74aeafba1f5647f9"}, - {file = "lxml-5.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a81e1196f0a5b4167a8dafe3a66aa67c4addac1b22dc47947abd5d5c7a3f24b5"}, - {file = "lxml-5.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00b8686694423ddae324cf614e1b9659c2edb754de617703c3d29ff568448df5"}, - {file = "lxml-5.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:c5681160758d3f6ac5b4fea370495c48aac0989d6a0f01bb9a72ad8ef5ab75c4"}, - {file = "lxml-5.4.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:2dc191e60425ad70e75a68c9fd90ab284df64d9cd410ba8d2b641c0c45bc006e"}, - {file = "lxml-5.4.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:67f779374c6b9753ae0a0195a892a1c234ce8416e4448fe1e9f34746482070a7"}, - {file = "lxml-5.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:79d5bfa9c1b455336f52343130b2067164040604e41f6dc4d8313867ed540079"}, - {file = "lxml-5.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3d3c30ba1c9b48c68489dc1829a6eede9873f52edca1dda900066542528d6b20"}, - {file = "lxml-5.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1af80c6316ae68aded77e91cd9d80648f7dd40406cef73df841aa3c36f6907c8"}, - {file = "lxml-5.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4d885698f5019abe0de3d352caf9466d5de2baded00a06ef3f1216c1a58ae78f"}, - {file = "lxml-5.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aea53d51859b6c64e7c51d522c03cc2c48b9b5d6172126854cc7f01aa11f52bc"}, - {file = "lxml-5.4.0-cp312-cp312-win32.whl", hash = "sha256:d90b729fd2732df28130c064aac9bb8aff14ba20baa4aee7bd0795ff1187545f"}, - {file = "lxml-5.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1dc4ca99e89c335a7ed47d38964abcb36c5910790f9bd106f2a8fa2ee0b909d2"}, - {file = "lxml-5.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:773e27b62920199c6197130632c18fb7ead3257fce1ffb7d286912e56ddb79e0"}, - {file = "lxml-5.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ce9c671845de9699904b1e9df95acfe8dfc183f2310f163cdaa91a3535af95de"}, - {file = "lxml-5.4.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9454b8d8200ec99a224df8854786262b1bd6461f4280064c807303c642c05e76"}, - {file = "lxml-5.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cccd007d5c95279e529c146d095f1d39ac05139de26c098166c4beb9374b0f4d"}, - {file = "lxml-5.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0fce1294a0497edb034cb416ad3e77ecc89b313cff7adbee5334e4dc0d11f422"}, - {file = "lxml-5.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:24974f774f3a78ac12b95e3a20ef0931795ff04dbb16db81a90c37f589819551"}, - {file = "lxml-5.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:497cab4d8254c2a90bf988f162ace2ddbfdd806fce3bda3f581b9d24c852e03c"}, - {file = "lxml-5.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:e794f698ae4c5084414efea0f5cc9f4ac562ec02d66e1484ff822ef97c2cadff"}, - {file = "lxml-5.4.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:2c62891b1ea3094bb12097822b3d44b93fc6c325f2043c4d2736a8ff09e65f60"}, - {file = "lxml-5.4.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:142accb3e4d1edae4b392bd165a9abdee8a3c432a2cca193df995bc3886249c8"}, - {file = "lxml-5.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1a42b3a19346e5601d1b8296ff6ef3d76038058f311902edd574461e9c036982"}, - {file = "lxml-5.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4291d3c409a17febf817259cb37bc62cb7eb398bcc95c1356947e2871911ae61"}, - {file = "lxml-5.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4f5322cf38fe0e21c2d73901abf68e6329dc02a4994e483adbcf92b568a09a54"}, - {file = "lxml-5.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:0be91891bdb06ebe65122aa6bf3fc94489960cf7e03033c6f83a90863b23c58b"}, - {file = "lxml-5.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:15a665ad90054a3d4f397bc40f73948d48e36e4c09f9bcffc7d90c87410e478a"}, - {file = "lxml-5.4.0-cp313-cp313-win32.whl", hash = "sha256:d5663bc1b471c79f5c833cffbc9b87d7bf13f87e055a5c86c363ccd2348d7e82"}, - {file = "lxml-5.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:bcb7a1096b4b6b24ce1ac24d4942ad98f983cd3810f9711bcd0293f43a9d8b9f"}, - {file = "lxml-5.4.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:7be701c24e7f843e6788353c055d806e8bd8466b52907bafe5d13ec6a6dbaecd"}, - {file = "lxml-5.4.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb54f7c6bafaa808f27166569b1511fc42701a7713858dddc08afdde9746849e"}, - {file = "lxml-5.4.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97dac543661e84a284502e0cf8a67b5c711b0ad5fb661d1bd505c02f8cf716d7"}, - {file = "lxml-5.4.0-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:c70e93fba207106cb16bf852e421c37bbded92acd5964390aad07cb50d60f5cf"}, - {file = "lxml-5.4.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9c886b481aefdf818ad44846145f6eaf373a20d200b5ce1a5c8e1bc2d8745410"}, - {file = "lxml-5.4.0-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:fa0e294046de09acd6146be0ed6727d1f42ded4ce3ea1e9a19c11b6774eea27c"}, - {file = "lxml-5.4.0-cp36-cp36m-win32.whl", hash = "sha256:61c7bbf432f09ee44b1ccaa24896d21075e533cd01477966a5ff5a71d88b2f56"}, - {file = "lxml-5.4.0-cp36-cp36m-win_amd64.whl", hash = "sha256:7ce1a171ec325192c6a636b64c94418e71a1964f56d002cc28122fceff0b6121"}, - {file = "lxml-5.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:795f61bcaf8770e1b37eec24edf9771b307df3af74d1d6f27d812e15a9ff3872"}, - {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29f451a4b614a7b5b6c2e043d7b64a15bd8304d7e767055e8ab68387a8cacf4e"}, - {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:891f7f991a68d20c75cb13c5c9142b2a3f9eb161f1f12a9489c82172d1f133c0"}, - {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4aa412a82e460571fad592d0f93ce9935a20090029ba08eca05c614f99b0cc92"}, - {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:ac7ba71f9561cd7d7b55e1ea5511543c0282e2b6450f122672a2694621d63b7e"}, - {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:c5d32f5284012deaccd37da1e2cd42f081feaa76981f0eaa474351b68df813c5"}, - {file = "lxml-5.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:ce31158630a6ac85bddd6b830cffd46085ff90498b397bd0a259f59d27a12188"}, - {file = "lxml-5.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:31e63621e073e04697c1b2d23fcb89991790eef370ec37ce4d5d469f40924ed6"}, - {file = "lxml-5.4.0-cp37-cp37m-win32.whl", hash = "sha256:be2ba4c3c5b7900246a8f866580700ef0d538f2ca32535e991027bdaba944063"}, - {file = "lxml-5.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:09846782b1ef650b321484ad429217f5154da4d6e786636c38e434fa32e94e49"}, - {file = "lxml-5.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eaf24066ad0b30917186420d51e2e3edf4b0e2ea68d8cd885b14dc8afdcf6556"}, - {file = "lxml-5.4.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b31a3a77501d86d8ade128abb01082724c0dfd9524f542f2f07d693c9f1175f"}, - {file = "lxml-5.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e108352e203c7afd0eb91d782582f00a0b16a948d204d4dec8565024fafeea5"}, - {file = "lxml-5.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a11a96c3b3f7551c8a8109aa65e8594e551d5a84c76bf950da33d0fb6dfafab7"}, - {file = "lxml-5.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:ca755eebf0d9e62d6cb013f1261e510317a41bf4650f22963474a663fdfe02aa"}, - {file = "lxml-5.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:4cd915c0fb1bed47b5e6d6edd424ac25856252f09120e3e8ba5154b6b921860e"}, - {file = "lxml-5.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:226046e386556a45ebc787871d6d2467b32c37ce76c2680f5c608e25823ffc84"}, - {file = "lxml-5.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:b108134b9667bcd71236c5a02aad5ddd073e372fb5d48ea74853e009fe38acb6"}, - {file = "lxml-5.4.0-cp38-cp38-win32.whl", hash = "sha256:1320091caa89805df7dcb9e908add28166113dcd062590668514dbd510798c88"}, - {file = "lxml-5.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:073eb6dcdf1f587d9b88c8c93528b57eccda40209cf9be549d469b942b41d70b"}, - {file = "lxml-5.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bda3ea44c39eb74e2488297bb39d47186ed01342f0022c8ff407c250ac3f498e"}, - {file = "lxml-5.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9ceaf423b50ecfc23ca00b7f50b64baba85fb3fb91c53e2c9d00bc86150c7e40"}, - {file = "lxml-5.4.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:664cdc733bc87449fe781dbb1f309090966c11cc0c0cd7b84af956a02a8a4729"}, - {file = "lxml-5.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67ed8a40665b84d161bae3181aa2763beea3747f748bca5874b4af4d75998f87"}, - {file = "lxml-5.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b4a3bd174cc9cdaa1afbc4620c049038b441d6ba07629d89a83b408e54c35cd"}, - {file = "lxml-5.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:b0989737a3ba6cf2a16efb857fb0dfa20bc5c542737fddb6d893fde48be45433"}, - {file = "lxml-5.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:dc0af80267edc68adf85f2a5d9be1cdf062f973db6790c1d065e45025fa26140"}, - {file = "lxml-5.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:639978bccb04c42677db43c79bdaa23785dc7f9b83bfd87570da8207872f1ce5"}, - {file = "lxml-5.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5a99d86351f9c15e4a901fc56404b485b1462039db59288b203f8c629260a142"}, - {file = "lxml-5.4.0-cp39-cp39-win32.whl", hash = "sha256:3e6d5557989cdc3ebb5302bbdc42b439733a841891762ded9514e74f60319ad6"}, - {file = "lxml-5.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:a8c9b7f16b63e65bbba889acb436a1034a82d34fa09752d754f88d708eca80e1"}, - {file = "lxml-5.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1b717b00a71b901b4667226bba282dd462c42ccf618ade12f9ba3674e1fabc55"}, - {file = "lxml-5.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27a9ded0f0b52098ff89dd4c418325b987feed2ea5cc86e8860b0f844285d740"}, - {file = "lxml-5.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b7ce10634113651d6f383aa712a194179dcd496bd8c41e191cec2099fa09de5"}, - {file = "lxml-5.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:53370c26500d22b45182f98847243efb518d268374a9570409d2e2276232fd37"}, - {file = "lxml-5.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c6364038c519dffdbe07e3cf42e6a7f8b90c275d4d1617a69bb59734c1a2d571"}, - {file = "lxml-5.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b12cb6527599808ada9eb2cd6e0e7d3d8f13fe7bbb01c6311255a15ded4c7ab4"}, - {file = "lxml-5.4.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5f11a1526ebd0dee85e7b1e39e39a0cc0d9d03fb527f56d8457f6df48a10dc0c"}, - {file = "lxml-5.4.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48b4afaf38bf79109bb060d9016fad014a9a48fb244e11b94f74ae366a64d252"}, - {file = "lxml-5.4.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de6f6bb8a7840c7bf216fb83eec4e2f79f7325eca8858167b68708b929ab2172"}, - {file = "lxml-5.4.0-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5cca36a194a4eb4e2ed6be36923d3cffd03dcdf477515dea687185506583d4c9"}, - {file = "lxml-5.4.0-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b7c86884ad23d61b025989d99bfdd92a7351de956e01c61307cb87035960bcb1"}, - {file = "lxml-5.4.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:53d9469ab5460402c19553b56c3648746774ecd0681b1b27ea74d5d8a3ef5590"}, - {file = "lxml-5.4.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:56dbdbab0551532bb26c19c914848d7251d73edb507c3079d6805fa8bba5b706"}, - {file = "lxml-5.4.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14479c2ad1cb08b62bb941ba8e0e05938524ee3c3114644df905d2331c76cd57"}, - {file = "lxml-5.4.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32697d2ea994e0db19c1df9e40275ffe84973e4232b5c274f47e7c1ec9763cdd"}, - {file = "lxml-5.4.0-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:24f6df5f24fc3385f622c0c9d63fe34604893bc1a5bdbb2dbf5870f85f9a404a"}, - {file = "lxml-5.4.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:151d6c40bc9db11e960619d2bf2ec5829f0aaffb10b41dcf6ad2ce0f3c0b2325"}, - {file = "lxml-5.4.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4025bf2884ac4370a3243c5aa8d66d3cb9e15d3ddd0af2d796eccc5f0244390e"}, - {file = "lxml-5.4.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:9459e6892f59ecea2e2584ee1058f5d8f629446eab52ba2305ae13a32a059530"}, - {file = "lxml-5.4.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47fb24cc0f052f0576ea382872b3fc7e1f7e3028e53299ea751839418ade92a6"}, - {file = "lxml-5.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50441c9de951a153c698b9b99992e806b71c1f36d14b154592580ff4a9d0d877"}, - {file = "lxml-5.4.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:ab339536aa798b1e17750733663d272038bf28069761d5be57cb4a9b0137b4f8"}, - {file = "lxml-5.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9776af1aad5a4b4a1317242ee2bea51da54b2a7b7b48674be736d463c999f37d"}, - {file = "lxml-5.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:63e7968ff83da2eb6fdda967483a7a023aa497d85ad8f05c3ad9b1f2e8c84987"}, - {file = "lxml-5.4.0.tar.gz", hash = "sha256:d12832e1dbea4be280b22fd0ea7c9b87f0d8fc51ba06e92dc62d52f804f78ebd"}, + {file = "lxml-6.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3b38e20c578149fdbba1fd3f36cb1928a3aaca4b011dfd41ba09d11fb396e1b9"}, + {file = "lxml-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:11a052cbd013b7140bbbb38a14e2329b6192478344c99097e378c691b7119551"}, + {file = "lxml-6.0.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:21344d29c82ca8547ea23023bb8e7538fa5d4615a1773b991edf8176a870c1ea"}, + {file = "lxml-6.0.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aa8f130f4b2dc94baa909c17bb7994f0268a2a72b9941c872e8e558fd6709050"}, + {file = "lxml-6.0.1-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4588806a721552692310ebe9f90c17ac6c7c5dac438cd93e3d74dd60531c3211"}, + {file = "lxml-6.0.1-cp310-cp310-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:8466faa66b0353802fb7c054a400ac17ce2cf416e3ad8516eadeff9cba85b741"}, + {file = "lxml-6.0.1-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50b5e54f6a9461b1e9c08b4a3420415b538d4773bd9df996b9abcbfe95f4f1fd"}, + {file = "lxml-6.0.1-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:6f393e10685b37f15b1daef8aa0d734ec61860bb679ec447afa0001a31e7253f"}, + {file = "lxml-6.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:07038c62fd0fe2743e2f5326f54d464715373c791035d7dda377b3c9a5d0ad77"}, + {file = "lxml-6.0.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:7a44a5fb1edd11b3a65c12c23e1049c8ae49d90a24253ff18efbcb6aa042d012"}, + {file = "lxml-6.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a57d9eb9aadf311c9e8785230eec83c6abb9aef2adac4c0587912caf8f3010b8"}, + {file = "lxml-6.0.1-cp310-cp310-win32.whl", hash = "sha256:d877874a31590b72d1fa40054b50dc33084021bfc15d01b3a661d85a302af821"}, + {file = "lxml-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:c43460f4aac016ee0e156bfa14a9de9b3e06249b12c228e27654ac3996a46d5b"}, + {file = "lxml-6.0.1-cp310-cp310-win_arm64.whl", hash = "sha256:615bb6c73fed7929e3a477a3297a797892846b253d59c84a62c98bdce3849a0a"}, + {file = "lxml-6.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c6acde83f7a3d6399e6d83c1892a06ac9b14ea48332a5fbd55d60b9897b9570a"}, + {file = "lxml-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0d21c9cacb6a889cbb8eeb46c77ef2c1dd529cde10443fdeb1de847b3193c541"}, + {file = "lxml-6.0.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:847458b7cd0d04004895f1fb2cca8e7c0f8ec923c49c06b7a72ec2d48ea6aca2"}, + {file = "lxml-6.0.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1dc13405bf315d008fe02b1472d2a9d65ee1c73c0a06de5f5a45e6e404d9a1c0"}, + {file = "lxml-6.0.1-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:70f540c229a8c0a770dcaf6d5af56a5295e0fc314fc7ef4399d543328054bcea"}, + {file = "lxml-6.0.1-cp311-cp311-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:d2f73aef768c70e8deb8c4742fca4fd729b132fda68458518851c7735b55297e"}, + {file = "lxml-6.0.1-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e7f4066b85a4fa25ad31b75444bd578c3ebe6b8ed47237896341308e2ce923c3"}, + {file = "lxml-6.0.1-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:0cce65db0cd8c750a378639900d56f89f7d6af11cd5eda72fde054d27c54b8ce"}, + {file = "lxml-6.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c372d42f3eee5844b69dcab7b8d18b2f449efd54b46ac76970d6e06b8e8d9a66"}, + {file = "lxml-6.0.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:2e2b0e042e1408bbb1c5f3cfcb0f571ff4ac98d8e73f4bf37c5dd179276beedd"}, + {file = "lxml-6.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cc73bb8640eadd66d25c5a03175de6801f63c535f0f3cf50cac2f06a8211f420"}, + {file = "lxml-6.0.1-cp311-cp311-win32.whl", hash = "sha256:7c23fd8c839708d368e406282d7953cee5134f4592ef4900026d84566d2b4c88"}, + {file = "lxml-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:2516acc6947ecd3c41a4a4564242a87c6786376989307284ddb115f6a99d927f"}, + {file = "lxml-6.0.1-cp311-cp311-win_arm64.whl", hash = "sha256:cb46f8cfa1b0334b074f40c0ff94ce4d9a6755d492e6c116adb5f4a57fb6ad96"}, + {file = "lxml-6.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:c03ac546adaabbe0b8e4a15d9ad815a281afc8d36249c246aecf1aaad7d6f200"}, + {file = "lxml-6.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:33b862c7e3bbeb4ba2c96f3a039f925c640eeba9087a4dc7a572ec0f19d89392"}, + {file = "lxml-6.0.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7a3ec1373f7d3f519de595032d4dcafae396c29407cfd5073f42d267ba32440d"}, + {file = "lxml-6.0.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:03b12214fb1608f4cffa181ec3d046c72f7e77c345d06222144744c122ded870"}, + {file = "lxml-6.0.1-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:207ae0d5f0f03b30f95e649a6fa22aa73f5825667fee9c7ec6854d30e19f2ed8"}, + {file = "lxml-6.0.1-cp312-cp312-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:32297b09ed4b17f7b3f448de87a92fb31bb8747496623483788e9f27c98c0f00"}, + {file = "lxml-6.0.1-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7e18224ea241b657a157c85e9cac82c2b113ec90876e01e1f127312006233756"}, + {file = "lxml-6.0.1-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a07a994d3c46cd4020c1ea566345cf6815af205b1e948213a4f0f1d392182072"}, + {file = "lxml-6.0.1-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:2287fadaa12418a813b05095485c286c47ea58155930cfbd98c590d25770e225"}, + {file = "lxml-6.0.1-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b4e597efca032ed99f418bd21314745522ab9fa95af33370dcee5533f7f70136"}, + {file = "lxml-6.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9696d491f156226decdd95d9651c6786d43701e49f32bf23715c975539aa2b3b"}, + {file = "lxml-6.0.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e4e3cd3585f3c6f87cdea44cda68e692cc42a012f0131d25957ba4ce755241a7"}, + {file = "lxml-6.0.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:45cbc92f9d22c28cd3b97f8d07fcefa42e569fbd587dfdac76852b16a4924277"}, + {file = "lxml-6.0.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:f8c9bcfd2e12299a442fba94459adf0b0d001dbc68f1594439bfa10ad1ecb74b"}, + {file = "lxml-6.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1e9dc2b9f1586e7cd77753eae81f8d76220eed9b768f337dc83a3f675f2f0cf9"}, + {file = "lxml-6.0.1-cp312-cp312-win32.whl", hash = "sha256:987ad5c3941c64031f59c226167f55a04d1272e76b241bfafc968bdb778e07fb"}, + {file = "lxml-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:abb05a45394fd76bf4a60c1b7bec0e6d4e8dfc569fc0e0b1f634cd983a006ddc"}, + {file = "lxml-6.0.1-cp312-cp312-win_arm64.whl", hash = "sha256:c4be29bce35020d8579d60aa0a4e95effd66fcfce31c46ffddf7e5422f73a299"}, + {file = "lxml-6.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:485eda5d81bb7358db96a83546949c5fe7474bec6c68ef3fa1fb61a584b00eea"}, + {file = "lxml-6.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d12160adea318ce3d118f0b4fbdff7d1225c75fb7749429541b4d217b85c3f76"}, + {file = "lxml-6.0.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48c8d335d8ab72f9265e7ba598ae5105a8272437403f4032107dbcb96d3f0b29"}, + {file = "lxml-6.0.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:405e7cf9dbdbb52722c231e0f1257214202dfa192327fab3de45fd62e0554082"}, + {file = "lxml-6.0.1-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:299a790d403335a6a057ade46f92612ebab87b223e4e8c5308059f2dc36f45ed"}, + {file = "lxml-6.0.1-cp313-cp313-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:48da704672f6f9c461e9a73250440c647638cc6ff9567ead4c3b1f189a604ee8"}, + {file = "lxml-6.0.1-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:21e364e1bb731489e3f4d51db416f991a5d5da5d88184728d80ecfb0904b1d68"}, + {file = "lxml-6.0.1-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1bce45a2c32032afddbd84ed8ab092130649acb935536ef7a9559636ce7ffd4a"}, + {file = "lxml-6.0.1-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:fa164387ff20ab0e575fa909b11b92ff1481e6876835014e70280769920c4433"}, + {file = "lxml-6.0.1-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7587ac5e000e1594e62278422c5783b34a82b22f27688b1074d71376424b73e8"}, + {file = "lxml-6.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:57478424ac4c9170eabf540237125e8d30fad1940648924c058e7bc9fb9cf6dd"}, + {file = "lxml-6.0.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:09c74afc7786c10dd6afaa0be2e4805866beadc18f1d843cf517a7851151b499"}, + {file = "lxml-6.0.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7fd70681aeed83b196482d42a9b0dc5b13bab55668d09ad75ed26dff3be5a2f5"}, + {file = "lxml-6.0.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:10a72e456319b030b3dd900df6b1f19d89adf06ebb688821636dc406788cf6ac"}, + {file = "lxml-6.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b0fa45fb5f55111ce75b56c703843b36baaf65908f8b8d2fbbc0e249dbc127ed"}, + {file = "lxml-6.0.1-cp313-cp313-win32.whl", hash = "sha256:01dab65641201e00c69338c9c2b8a0f2f484b6b3a22d10779bb417599fae32b5"}, + {file = "lxml-6.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:bdf8f7c8502552d7bff9e4c98971910a0a59f60f88b5048f608d0a1a75e94d1c"}, + {file = "lxml-6.0.1-cp313-cp313-win_arm64.whl", hash = "sha256:a6aeca75959426b9fd8d4782c28723ba224fe07cfa9f26a141004210528dcbe2"}, + {file = "lxml-6.0.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:29b0e849ec7030e3ecb6112564c9f7ad6881e3b2375dd4a0c486c5c1f3a33859"}, + {file = "lxml-6.0.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:02a0f7e629f73cc0be598c8b0611bf28ec3b948c549578a26111b01307fd4051"}, + {file = "lxml-6.0.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:beab5e54de016e730875f612ba51e54c331e2fa6dc78ecf9a5415fc90d619348"}, + {file = "lxml-6.0.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:92a08aefecd19ecc4ebf053c27789dd92c87821df2583a4337131cf181a1dffa"}, + {file = "lxml-6.0.1-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36c8fa7e177649470bc3dcf7eae6bee1e4984aaee496b9ccbf30e97ac4127fa2"}, + {file = "lxml-6.0.1-cp314-cp314-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:5d08e0f1af6916267bb7eff21c09fa105620f07712424aaae09e8cb5dd4164d1"}, + {file = "lxml-6.0.1-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9705cdfc05142f8c38c97a61bd3a29581ceceb973a014e302ee4a73cc6632476"}, + {file = "lxml-6.0.1-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:74555e2da7c1636e30bff4e6e38d862a634cf020ffa591f1f63da96bf8b34772"}, + {file = "lxml-6.0.1-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:e38b5f94c5a2a5dadaddd50084098dfd005e5a2a56cd200aaf5e0a20e8941782"}, + {file = "lxml-6.0.1-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a5ec101a92ddacb4791977acfc86c1afd624c032974bfb6a21269d1083c9bc49"}, + {file = "lxml-6.0.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:5c17e70c82fd777df586c12114bbe56e4e6f823a971814fd40dec9c0de518772"}, + {file = "lxml-6.0.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:45fdd0415a0c3d91640b5d7a650a8f37410966a2e9afebb35979d06166fd010e"}, + {file = "lxml-6.0.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:d417eba28981e720a14fcb98f95e44e7a772fe25982e584db38e5d3b6ee02e79"}, + {file = "lxml-6.0.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:8e5d116b9e59be7934febb12c41cce2038491ec8fdb743aeacaaf36d6e7597e4"}, + {file = "lxml-6.0.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c238f0d0d40fdcb695c439fe5787fa69d40f45789326b3bb6ef0d61c4b588d6e"}, + {file = "lxml-6.0.1-cp314-cp314-win32.whl", hash = "sha256:537b6cf1c5ab88cfd159195d412edb3e434fee880f206cbe68dff9c40e17a68a"}, + {file = "lxml-6.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:911d0a2bb3ef3df55b3d97ab325a9ca7e438d5112c102b8495321105d25a441b"}, + {file = "lxml-6.0.1-cp314-cp314-win_arm64.whl", hash = "sha256:2834377b0145a471a654d699bdb3a2155312de492142ef5a1d426af2c60a0a31"}, + {file = "lxml-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9283997edb661ebba05314da1b9329e628354be310bbf947b0faa18263c5df1b"}, + {file = "lxml-6.0.1-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1beca37c6e7a4ddd1ca24829e2c6cb60b5aad0d6936283b5b9909a7496bd97af"}, + {file = "lxml-6.0.1-cp38-cp38-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:42897fe8cb097274087fafc8251a39b4cf8d64a7396d49479bdc00b3587331cb"}, + {file = "lxml-6.0.1-cp38-cp38-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0ef8cd44a080bfb92776047d11ab64875faf76e0d8be20ea3ff0c1e67b3fc9cb"}, + {file = "lxml-6.0.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:433ab647dad6a9fb31418ccd3075dcb4405ece75dced998789fe14a8e1e3785c"}, + {file = "lxml-6.0.1-cp38-cp38-win32.whl", hash = "sha256:bfa30ef319462242333ef8f0c7631fb8b8b8eae7dca83c1f235d2ea2b7f8ff2b"}, + {file = "lxml-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:7f36e4a2439d134b8e70f92ff27ada6fb685966de385668e21c708021733ead1"}, + {file = "lxml-6.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:edb975280633a68d0988b11940834ce2b0fece9f5278297fc50b044cb713f0e1"}, + {file = "lxml-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d4c5acb9bc22f2026bbd0ecbfdb890e9b3e5b311b992609d35034706ad111b5d"}, + {file = "lxml-6.0.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:47ab1aff82a95a07d96c1eff4eaebec84f823e0dfb4d9501b1fbf9621270c1d3"}, + {file = "lxml-6.0.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:faa7233bdb7a4365e2411a665d034c370ac82798a926e65f76c26fbbf0fd14b7"}, + {file = "lxml-6.0.1-cp39-cp39-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c71a0ce0e08c7e11e64895c720dc7752bf064bfecd3eb2c17adcd7bfa8ffb22c"}, + {file = "lxml-6.0.1-cp39-cp39-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:57744270a512a93416a149f8b6ea1dbbbee127f5edcbcd5adf28e44b6ff02f33"}, + {file = "lxml-6.0.1-cp39-cp39-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e89d977220f7b1f0c725ac76f5c65904193bd4c264577a3af9017de17560ea7e"}, + {file = "lxml-6.0.1-cp39-cp39-manylinux_2_31_armv7l.whl", hash = "sha256:0c8f7905f1971c2c408badf49ae0ef377cc54759552bcf08ae7a0a8ed18999c2"}, + {file = "lxml-6.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ea27626739e82f2be18cbb1aff7ad59301c723dc0922d9a00bc4c27023f16ab7"}, + {file = "lxml-6.0.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:21300d8c1bbcc38925aabd4b3c2d6a8b09878daf9e8f2035f09b5b002bcddd66"}, + {file = "lxml-6.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:021497a94907c5901cd49d24b5b0fdd18d198a06611f5ce26feeb67c901b92f2"}, + {file = "lxml-6.0.1-cp39-cp39-win32.whl", hash = "sha256:620869f2a3ec1475d000b608024f63259af8d200684de380ccb9650fbc14d1bb"}, + {file = "lxml-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:afae3a15889942426723839a3cf56dab5e466f7d873640a7a3c53abc671e2387"}, + {file = "lxml-6.0.1-cp39-cp39-win_arm64.whl", hash = "sha256:2719e42acda8f3444a0d88204fd90665116dda7331934da4d479dd9296c33ce2"}, + {file = "lxml-6.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0abfbaf4ebbd7fd33356217d317b6e4e2ef1648be6a9476a52b57ffc6d8d1780"}, + {file = "lxml-6.0.1-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1ebbf2d9775be149235abebdecae88fe3b3dd06b1797cd0f6dffe6948e85309d"}, + {file = "lxml-6.0.1-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a389e9f11c010bd30531325805bbe97bdf7f728a73d0ec475adef57ffec60547"}, + {file = "lxml-6.0.1-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8f5cf2addfbbe745251132c955ad62d8519bb4b2c28b0aa060eca4541798d86e"}, + {file = "lxml-6.0.1-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f1b60a3287bf33a2a54805d76b82055bcc076e445fd539ee9ae1fe85ed373691"}, + {file = "lxml-6.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f7bbfb0751551a8786915fc6b615ee56344dacc1b1033697625b553aefdd9837"}, + {file = "lxml-6.0.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b556aaa6ef393e989dac694b9c95761e32e058d5c4c11ddeef33f790518f7a5e"}, + {file = "lxml-6.0.1-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:64fac7a05ebb3737b79fd89fe5a5b6c5546aac35cfcfd9208eb6e5d13215771c"}, + {file = "lxml-6.0.1-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:038d3c08babcfce9dc89aaf498e6da205efad5b7106c3b11830a488d4eadf56b"}, + {file = "lxml-6.0.1-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:445f2cee71c404ab4259bc21e20339a859f75383ba2d7fb97dfe7c163994287b"}, + {file = "lxml-6.0.1-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e352d8578e83822d70bea88f3d08b9912528e4c338f04ab707207ab12f4b7aac"}, + {file = "lxml-6.0.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:51bd5d1a9796ca253db6045ab45ca882c09c071deafffc22e06975b7ace36300"}, + {file = "lxml-6.0.1.tar.gz", hash = "sha256:2b3a882ebf27dd026df3801a87cf49ff791336e0f94b0fad195db77e01240690"}, ] [package.extras] @@ -4023,7 +4007,6 @@ cssselect = ["cssselect (>=0.7)"] html-clean = ["lxml_html_clean"] html5 = ["html5lib"] htmlsoup = ["BeautifulSoup4"] -source = ["Cython (>=3.0.11,<3.1.0)"] [[package]] name = "markdown" @@ -8128,43 +8111,43 @@ tests = ["memory-profiler (>=0.57.0)", "pytest-benchmark (>=3.2.2)"] [[package]] name = "tiktoken" -version = "0.9.0" +version = "0.11.0" description = "tiktoken is a fast BPE tokeniser for use with OpenAI's models" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "tiktoken-0.9.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:586c16358138b96ea804c034b8acf3f5d3f0258bd2bc3b0227af4af5d622e382"}, - {file = "tiktoken-0.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d9c59ccc528c6c5dd51820b3474402f69d9a9e1d656226848ad68a8d5b2e5108"}, - {file = "tiktoken-0.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0968d5beeafbca2a72c595e8385a1a1f8af58feaebb02b227229b69ca5357fd"}, - {file = "tiktoken-0.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92a5fb085a6a3b7350b8fc838baf493317ca0e17bd95e8642f95fc69ecfed1de"}, - {file = "tiktoken-0.9.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:15a2752dea63d93b0332fb0ddb05dd909371ededa145fe6a3242f46724fa7990"}, - {file = "tiktoken-0.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:26113fec3bd7a352e4b33dbaf1bd8948de2507e30bd95a44e2b1156647bc01b4"}, - {file = "tiktoken-0.9.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:f32cc56168eac4851109e9b5d327637f15fd662aa30dd79f964b7c39fbadd26e"}, - {file = "tiktoken-0.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:45556bc41241e5294063508caf901bf92ba52d8ef9222023f83d2483a3055348"}, - {file = "tiktoken-0.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03935988a91d6d3216e2ec7c645afbb3d870b37bcb67ada1943ec48678e7ee33"}, - {file = "tiktoken-0.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b3d80aad8d2c6b9238fc1a5524542087c52b860b10cbf952429ffb714bc1136"}, - {file = "tiktoken-0.9.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b2a21133be05dc116b1d0372af051cd2c6aa1d2188250c9b553f9fa49301b336"}, - {file = "tiktoken-0.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:11a20e67fdf58b0e2dea7b8654a288e481bb4fc0289d3ad21291f8d0849915fb"}, - {file = "tiktoken-0.9.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e88f121c1c22b726649ce67c089b90ddda8b9662545a8aeb03cfef15967ddd03"}, - {file = "tiktoken-0.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a6600660f2f72369acb13a57fb3e212434ed38b045fd8cc6cdd74947b4b5d210"}, - {file = "tiktoken-0.9.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95e811743b5dfa74f4b227927ed86cbc57cad4df859cb3b643be797914e41794"}, - {file = "tiktoken-0.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99376e1370d59bcf6935c933cb9ba64adc29033b7e73f5f7569f3aad86552b22"}, - {file = "tiktoken-0.9.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:badb947c32739fb6ddde173e14885fb3de4d32ab9d8c591cbd013c22b4c31dd2"}, - {file = "tiktoken-0.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:5a62d7a25225bafed786a524c1b9f0910a1128f4232615bf3f8257a73aaa3b16"}, - {file = "tiktoken-0.9.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2b0e8e05a26eda1249e824156d537015480af7ae222ccb798e5234ae0285dbdb"}, - {file = "tiktoken-0.9.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:27d457f096f87685195eea0165a1807fae87b97b2161fe8c9b1df5bd74ca6f63"}, - {file = "tiktoken-0.9.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cf8ded49cddf825390e36dd1ad35cd49589e8161fdcb52aa25f0583e90a3e01"}, - {file = "tiktoken-0.9.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc156cb314119a8bb9748257a2eaebd5cc0753b6cb491d26694ed42fc7cb3139"}, - {file = "tiktoken-0.9.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cd69372e8c9dd761f0ab873112aba55a0e3e506332dd9f7522ca466e817b1b7a"}, - {file = "tiktoken-0.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:5ea0edb6f83dc56d794723286215918c1cde03712cbbafa0348b33448faf5b95"}, - {file = "tiktoken-0.9.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c6386ca815e7d96ef5b4ac61e0048cd32ca5a92d5781255e13b31381d28667dc"}, - {file = "tiktoken-0.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:75f6d5db5bc2c6274b674ceab1615c1778e6416b14705827d19b40e6355f03e0"}, - {file = "tiktoken-0.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e15b16f61e6f4625a57a36496d28dd182a8a60ec20a534c5343ba3cafa156ac7"}, - {file = "tiktoken-0.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebcec91babf21297022882344c3f7d9eed855931466c3311b1ad6b64befb3df"}, - {file = "tiktoken-0.9.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e5fd49e7799579240f03913447c0cdfa1129625ebd5ac440787afc4345990427"}, - {file = "tiktoken-0.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:26242ca9dc8b58e875ff4ca078b9a94d2f0813e6a535dcd2205df5d49d927cc7"}, - {file = "tiktoken-0.9.0.tar.gz", hash = "sha256:d02a5ca6a938e0490e1ff957bc48c8b078c88cb83977be1625b1fd8aac792c5d"}, + {file = "tiktoken-0.11.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:8a9b517d6331d7103f8bef29ef93b3cca95fa766e293147fe7bacddf310d5917"}, + {file = "tiktoken-0.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b4ddb1849e6bf0afa6cc1c5d809fb980ca240a5fffe585a04e119519758788c0"}, + {file = "tiktoken-0.11.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:10331d08b5ecf7a780b4fe4d0281328b23ab22cdb4ff65e68d56caeda9940ecc"}, + {file = "tiktoken-0.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b062c82300341dc87e0258c69f79bed725f87e753c21887aea90d272816be882"}, + {file = "tiktoken-0.11.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:195d84bec46169af3b1349a1495c151d37a0ff4cba73fd08282736be7f92cc6c"}, + {file = "tiktoken-0.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe91581b0ecdd8783ce8cb6e3178f2260a3912e8724d2f2d49552b98714641a1"}, + {file = "tiktoken-0.11.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4ae374c46afadad0f501046db3da1b36cd4dfbfa52af23c998773682446097cf"}, + {file = "tiktoken-0.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:25a512ff25dc6c85b58f5dd4f3d8c674dc05f96b02d66cdacf628d26a4e4866b"}, + {file = "tiktoken-0.11.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2130127471e293d385179c1f3f9cd445070c0772be73cdafb7cec9a3684c0458"}, + {file = "tiktoken-0.11.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21e43022bf2c33f733ea9b54f6a3f6b4354b909f5a73388fb1b9347ca54a069c"}, + {file = "tiktoken-0.11.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:adb4e308eb64380dc70fa30493e21c93475eaa11669dea313b6bbf8210bfd013"}, + {file = "tiktoken-0.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:ece6b76bfeeb61a125c44bbefdfccc279b5288e6007fbedc0d32bfec602df2f2"}, + {file = "tiktoken-0.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fd9e6b23e860973cf9526544e220b223c60badf5b62e80a33509d6d40e6c8f5d"}, + {file = "tiktoken-0.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6a76d53cee2da71ee2731c9caa747398762bda19d7f92665e882fef229cb0b5b"}, + {file = "tiktoken-0.11.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ef72aab3ea240646e642413cb363b73869fed4e604dcfd69eec63dc54d603e8"}, + {file = "tiktoken-0.11.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f929255c705efec7a28bf515e29dc74220b2f07544a8c81b8d69e8efc4578bd"}, + {file = "tiktoken-0.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:61f1d15822e4404953d499fd1dcc62817a12ae9fb1e4898033ec8fe3915fdf8e"}, + {file = "tiktoken-0.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:45927a71ab6643dfd3ef57d515a5db3d199137adf551f66453be098502838b0f"}, + {file = "tiktoken-0.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a5f3f25ffb152ee7fec78e90a5e5ea5b03b4ea240beed03305615847f7a6ace2"}, + {file = "tiktoken-0.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7dc6e9ad16a2a75b4c4be7208055a1f707c9510541d94d9cc31f7fbdc8db41d8"}, + {file = "tiktoken-0.11.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a0517634d67a8a48fd4a4ad73930c3022629a85a217d256a6e9b8b47439d1e4"}, + {file = "tiktoken-0.11.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fb4effe60574675118b73c6fbfd3b5868e5d7a1f570d6cc0d18724b09ecf318"}, + {file = "tiktoken-0.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:94f984c9831fd32688aef4348803b0905d4ae9c432303087bae370dc1381a2b8"}, + {file = "tiktoken-0.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:2177ffda31dec4023356a441793fed82f7af5291120751dee4d696414f54db0c"}, + {file = "tiktoken-0.11.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:13220f12c9e82e399377e768640ddfe28bea962739cc3a869cad98f42c419a89"}, + {file = "tiktoken-0.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f2db627f5c74477c0404b4089fd8a28ae22fa982a6f7d9c7d4c305c375218f3"}, + {file = "tiktoken-0.11.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2302772f035dceb2bcf8e55a735e4604a0b51a6dd50f38218ff664d46ec43807"}, + {file = "tiktoken-0.11.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20b977989afe44c94bcc50db1f76971bb26dca44218bd203ba95925ef56f8e7a"}, + {file = "tiktoken-0.11.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:669a1aa1ad6ebf1b3c26b45deb346f345da7680f845b5ea700bba45c20dea24c"}, + {file = "tiktoken-0.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:e363f33c720a055586f730c00e330df4c7ea0024bf1c83a8a9a9dbc054c4f304"}, + {file = "tiktoken-0.11.0.tar.gz", hash = "sha256:3c518641aee1c52247c2b97e74d8d07d780092af79d5911a6ab5e79359d9b06a"}, ] [package.dependencies] @@ -9079,4 +9062,4 @@ cffi = ["cffi (>=1.11)"] [metadata] lock-version = "2.1" python-versions = "~3.12" -content-hash = "5a2793f2bb546342aff222822fd0656c3a239db888f23c8e8034fdf9d74847f9" +content-hash = "03f012f37cee50fbf68ae6e155a724813182ce417504f7fbebba62aee1280c42" diff --git a/pyproject.toml b/pyproject.toml index 7f1420bdc6..2ba88eb642 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,7 +61,7 @@ langchain-openai = "^0.3.2" litellm = "1.74.14" llama-index = "^0.13.0" llama-index-llms-openai = "^0.5.0" -lxml = "^5.0.0" +lxml = "^6.0.0" markdown = "^3.7" markdown2 = "^2.4.8" mitol-django-scim = "^2025.3.31" @@ -103,7 +103,7 @@ social-auth-app-django = "^5.2.0" social-auth-core = {extras = ["openidconnect"], version = "^4.4.2"} static3 = "^0.7.0" tika = "^3.0.0" -tiktoken = "^0.9.0" +tiktoken = "^0.11.0" tldextract = "^5.0.0" toolz = "^1.0.0" ulid-py = "^1.0.0" diff --git a/yarn.lock b/yarn.lock index 9da5db8882..4a005788b4 100755 --- a/yarn.lock +++ b/yarn.lock @@ -3048,9 +3048,9 @@ __metadata: languageName: node linkType: hard -"@mitodl/smoot-design@npm:^6.10.0": - version: 6.11.0 - resolution: "@mitodl/smoot-design@npm:6.11.0" +"@mitodl/smoot-design@npm:^6.17.0": + version: 6.17.0 + resolution: "@mitodl/smoot-design@npm:6.17.0" dependencies: "@ai-sdk/react": "npm:1.2.12" "@emotion/cache": "npm:^11.14.0" @@ -3063,6 +3063,7 @@ __metadata: rehype-mathjax: "npm:^7.1.0" rehype-raw: "npm:^7.0.0" remark-math: "npm:^6.0.0" + remark-supersub: "npm:^1.0.0" tiny-invariant: "npm:^1.3.1" zod: "npm:^3.23.8" peerDependencies: @@ -3074,7 +3075,7 @@ __metadata: "@remixicon/react": ^4.2.0 react: ^18 || ^19 react-dom: ^18 || ^19 - checksum: 10/fa3f4c8412a0494e19b1f3d87b5f0250b2a45f88e30ce64c922deb3fa7411f1ec61c092e742570dd876a37ad4482bca345e410e8301cfd2e0a31b8dcbc5c02cd + checksum: 10/b3ae1b470fde25efe19de20a7089fe95b329c835cc215ed19481dcd3ac45748833fe207f5997a1aca0d5a50242aceb050e3662ce3b1cb2c89eb0eaad549075bf languageName: node linkType: hard @@ -3704,21 +3705,12 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/api-logs@npm:0.56.0": - version: 0.56.0 - resolution: "@opentelemetry/api-logs@npm:0.56.0" - dependencies: - "@opentelemetry/api": "npm:^1.3.0" - checksum: 10/5a6e25015acada7449d11124e9adbbe6670e1e9f7e8b46c60360ac89bb1537f2be326bcf18c66dcbcdee9f34e3a18bd4807c5a40faa0a4ac0135cb3675efb2a9 - languageName: node - linkType: hard - -"@opentelemetry/api-logs@npm:0.57.1": - version: 0.57.1 - resolution: "@opentelemetry/api-logs@npm:0.57.1" +"@opentelemetry/api-logs@npm:0.203.0": + version: 0.203.0 + resolution: "@opentelemetry/api-logs@npm:0.203.0" dependencies: "@opentelemetry/api": "npm:^1.3.0" - checksum: 10/4e06b34797f40245e8b51f52092cd74a44a5755a89bb80108428f7ef5490b8c812451fff3138d24d9b57e1f53a3b9815c40300dcf9852deacd64dad93990f736 + checksum: 10/e8c890cbf36f1a458ff4fc13c0d2efc81ea8f173d124d06e6878c539f2e84517013c1e2fd4b7149a3f88ba1a3b5befeb8068edea7f391c5d69fb8b02a2a13bc0 languageName: node linkType: hard @@ -3738,362 +3730,318 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/context-async-hooks@npm:^1.30.1": - version: 1.30.1 - resolution: "@opentelemetry/context-async-hooks@npm:1.30.1" - peerDependencies: - "@opentelemetry/api": ">=1.0.0 <1.10.0" - checksum: 10/95c3ec3683afb26e5d00a6efbdc459f76d1526a4f5bda07b265bb1f62a77770242695a48feb44b7b479490f89503e2283a2efdb833ed0cdf0256398feed9870f - languageName: node - linkType: hard - -"@opentelemetry/core@npm:1.30.1, @opentelemetry/core@npm:^1.26.0, @opentelemetry/core@npm:^1.30.1": - version: 1.30.1 - resolution: "@opentelemetry/core@npm:1.30.1" - dependencies: - "@opentelemetry/semantic-conventions": "npm:1.28.0" +"@opentelemetry/context-async-hooks@npm:^2.0.0": + version: 2.0.1 + resolution: "@opentelemetry/context-async-hooks@npm:2.0.1" peerDependencies: "@opentelemetry/api": ">=1.0.0 <1.10.0" - checksum: 10/fa3df9619fdbf8f607132d72915849754b71c4c5f5f705b30c8c59b209abe97206decf25cb8ebafdbb6105a4baab2acddee47468cb9d0b67f1a8df96cebc3548 + checksum: 10/198dacdce36377f6ded7062eb9fc77f86c9fcc8c86dd395e9cb276e14a01c7906ea2f0271999cae21bf251dbec44641286b8bd34a39c67c88c08ed925a986f4b languageName: node linkType: hard -"@opentelemetry/core@npm:^1.1.0, @opentelemetry/core@npm:^1.8.0": - version: 1.26.0 - resolution: "@opentelemetry/core@npm:1.26.0" +"@opentelemetry/core@npm:2.0.1, @opentelemetry/core@npm:^2.0.0": + version: 2.0.1 + resolution: "@opentelemetry/core@npm:2.0.1" dependencies: - "@opentelemetry/semantic-conventions": "npm:1.27.0" + "@opentelemetry/semantic-conventions": "npm:^1.29.0" peerDependencies: "@opentelemetry/api": ">=1.0.0 <1.10.0" - checksum: 10/474b6bcf42cd2825d56f915eb0d6e6cdcb37777a11fc2618fc2fa50754f4b9b5df23944f3aab186cb3ab930db5c3a81efa3183362802314a966930110346e6a4 + checksum: 10/dd891afd427067a9e6c610c36ab5638b0b9e5303ccca7c75ad744f5db53c6162a4b5d9cd2f5a77cdc3e4bda2eae850a4e29983ea244c929b7b872b7e086fc61c languageName: node linkType: hard -"@opentelemetry/instrumentation-amqplib@npm:^0.46.0": - version: 0.46.1 - resolution: "@opentelemetry/instrumentation-amqplib@npm:0.46.1" +"@opentelemetry/instrumentation-amqplib@npm:0.50.0": + version: 0.50.0 + resolution: "@opentelemetry/instrumentation-amqplib@npm:0.50.0" dependencies: - "@opentelemetry/core": "npm:^1.8.0" - "@opentelemetry/instrumentation": "npm:^0.57.1" + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/instrumentation": "npm:^0.203.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/4f718937b865adec3aa7756484cf4192493f1e8946a448ec74711b08f44646eab112683fbd25ed2fce3e78aaacbe6b1a61d05fc08ad2a3303ae0873d8b74159a + checksum: 10/1ff250f654bc9f3956ddee2862750b3b1ad1d5342a22903c0f07259de1748106162b5a211bf4a46eb199bb9b45c49ac6ee143685c0f088673e5eafc703327ab7 languageName: node linkType: hard -"@opentelemetry/instrumentation-connect@npm:0.43.0": - version: 0.43.0 - resolution: "@opentelemetry/instrumentation-connect@npm:0.43.0" +"@opentelemetry/instrumentation-connect@npm:0.47.0": + version: 0.47.0 + resolution: "@opentelemetry/instrumentation-connect@npm:0.47.0" dependencies: - "@opentelemetry/core": "npm:^1.8.0" - "@opentelemetry/instrumentation": "npm:^0.57.0" + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/instrumentation": "npm:^0.203.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" - "@types/connect": "npm:3.4.36" - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: 10/fd93463ff041a32e632b026307db035c26609dd232eb1ea97eaad45db4fc93fd09240e5421ceca249fb3e9c37797c0bf14171325b108cbc844117759e53fbf8a - languageName: node - linkType: hard - -"@opentelemetry/instrumentation-dataloader@npm:0.16.0": - version: 0.16.0 - resolution: "@opentelemetry/instrumentation-dataloader@npm:0.16.0" - dependencies: - "@opentelemetry/instrumentation": "npm:^0.57.0" + "@types/connect": "npm:3.4.38" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/edf4f2f2b1602b3cd5bb92020e1989c6afae918e7e4e75c4a3cf3a4b33d25effdfd5ca67adaa2747494ca923bcf6b5d2ae3ff8ce19a18a2af8d48bcaf6b45fc7 + checksum: 10/b159129037dbfff922fbec6505021bd331ed829647b9393fd75a4258df70e4d0a83236f580c494df7cbdf8b3988607d8a2d0162ca0bbba88bb182453bdfe4835 languageName: node linkType: hard -"@opentelemetry/instrumentation-express@npm:0.47.0": - version: 0.47.0 - resolution: "@opentelemetry/instrumentation-express@npm:0.47.0" +"@opentelemetry/instrumentation-dataloader@npm:0.21.0": + version: 0.21.0 + resolution: "@opentelemetry/instrumentation-dataloader@npm:0.21.0" dependencies: - "@opentelemetry/core": "npm:^1.8.0" - "@opentelemetry/instrumentation": "npm:^0.57.0" - "@opentelemetry/semantic-conventions": "npm:^1.27.0" + "@opentelemetry/instrumentation": "npm:^0.203.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/a8bffa443d869065dc7e013f02aaff0a6593db9ebca36748d940968fabcc9d61e71e4235489d867abb62c71e1f2df5ec6af6f3bdf21e750552be86b29850bd9e + checksum: 10/650c4092915acf0e0b7d0a13976405f3f1b3eff4526ea3c9c30a70130bf57d97de750b12d073d1130390f6ca778a068e0cbc53db85a3bdf9d849d5b715e8a7ae languageName: node linkType: hard -"@opentelemetry/instrumentation-fastify@npm:0.44.1": - version: 0.44.1 - resolution: "@opentelemetry/instrumentation-fastify@npm:0.44.1" +"@opentelemetry/instrumentation-express@npm:0.52.0": + version: 0.52.0 + resolution: "@opentelemetry/instrumentation-express@npm:0.52.0" dependencies: - "@opentelemetry/core": "npm:^1.8.0" - "@opentelemetry/instrumentation": "npm:^0.57.0" + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/instrumentation": "npm:^0.203.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/845d7b68755d0addf329e2ea4d40663d576676b2400d936759eb09e3d41e01df6c1673e51ac7aecdda950f7b8be8d12e2cd8811eb8b2a45ebc7dbec96d287eb7 + checksum: 10/8c6efccbaca6d94687144b1e24139b50d49503896d20d11758da9a30fcf7b35e8131cc1ae88f0c70ae8453f5d333cda5e337b423c37619d16c59b41856202a2a languageName: node linkType: hard -"@opentelemetry/instrumentation-fs@npm:0.19.0": - version: 0.19.0 - resolution: "@opentelemetry/instrumentation-fs@npm:0.19.0" +"@opentelemetry/instrumentation-fs@npm:0.23.0": + version: 0.23.0 + resolution: "@opentelemetry/instrumentation-fs@npm:0.23.0" dependencies: - "@opentelemetry/core": "npm:^1.8.0" - "@opentelemetry/instrumentation": "npm:^0.57.0" + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/instrumentation": "npm:^0.203.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/a24312c092aaec0f4f7fcae445dde17f3e8732fcc3a2583a83412ee22d284fe99752828e7afd6883cab34481008915497088f192ee91a6d6b1b43755dbcd6f0e + checksum: 10/c0b94b9fdfd00d962292c50df2c4e3a3aecffb0b0c193e860b705919fb2e021b9731e670c103d50022752e7d53460253a7f8bb691f6be70a80ec7680e706e3f6 languageName: node linkType: hard -"@opentelemetry/instrumentation-generic-pool@npm:0.43.0": - version: 0.43.0 - resolution: "@opentelemetry/instrumentation-generic-pool@npm:0.43.0" +"@opentelemetry/instrumentation-generic-pool@npm:0.47.0": + version: 0.47.0 + resolution: "@opentelemetry/instrumentation-generic-pool@npm:0.47.0" dependencies: - "@opentelemetry/instrumentation": "npm:^0.57.0" + "@opentelemetry/instrumentation": "npm:^0.203.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/2ea9570a87df53b00c866fab9074efde1d4a1ad1d8f271c7ab341dc2d40c73b60b67f3021f33f07e94e8cc0cc1b911b710d1cb03829fe29b5130fbbdd7b15a03 + checksum: 10/93c6babcd59651ecc17e156cb8a365a82e0c7068f10ad73427c5b756d4357891681f691dd47eca750b7054c32ecba6c9eda9f33ece7ac9c34d2547f7ac40c067 languageName: node linkType: hard -"@opentelemetry/instrumentation-graphql@npm:0.47.0": - version: 0.47.0 - resolution: "@opentelemetry/instrumentation-graphql@npm:0.47.0" +"@opentelemetry/instrumentation-graphql@npm:0.51.0": + version: 0.51.0 + resolution: "@opentelemetry/instrumentation-graphql@npm:0.51.0" dependencies: - "@opentelemetry/instrumentation": "npm:^0.57.0" + "@opentelemetry/instrumentation": "npm:^0.203.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/1699c89735dd9a1f25df236ba66052aca4a93e4d894657b8495249f0a7ad67691e05ac2db5e3110c85b5c15a22c19325ecee9c70c0eacacf4ec93e8f8370a654 + checksum: 10/1fe5ce6c03fcd0c919bbde562dbb409a3ef48c87f230284c00925c97fea116208b2a64ab426ca20c2d7799ce129e189fbd4bf83b96620e62a999d272030ea37c languageName: node linkType: hard -"@opentelemetry/instrumentation-hapi@npm:0.45.1": - version: 0.45.1 - resolution: "@opentelemetry/instrumentation-hapi@npm:0.45.1" +"@opentelemetry/instrumentation-hapi@npm:0.50.0": + version: 0.50.0 + resolution: "@opentelemetry/instrumentation-hapi@npm:0.50.0" dependencies: - "@opentelemetry/core": "npm:^1.8.0" - "@opentelemetry/instrumentation": "npm:^0.57.0" + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/instrumentation": "npm:^0.203.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/606f4817cae57a658dc77c9fa7c235aaadef5aaf5addd137dc9c9c1fddfedc93916e80ed5d6413d36b160d2b4223974369f18090d07501bcf72a7b07f9e0b24f + checksum: 10/171388556b5b03fd57cd2cc790756f3684ed578ada7cdd9ba467f79feb330d508caff3e4a473f1cdf2ca438e3c2e5ead0839bd9f9c1279b5956e1454c55cbae0 languageName: node linkType: hard -"@opentelemetry/instrumentation-http@npm:0.57.1": - version: 0.57.1 - resolution: "@opentelemetry/instrumentation-http@npm:0.57.1" +"@opentelemetry/instrumentation-http@npm:0.203.0": + version: 0.203.0 + resolution: "@opentelemetry/instrumentation-http@npm:0.203.0" dependencies: - "@opentelemetry/core": "npm:1.30.1" - "@opentelemetry/instrumentation": "npm:0.57.1" - "@opentelemetry/semantic-conventions": "npm:1.28.0" + "@opentelemetry/core": "npm:2.0.1" + "@opentelemetry/instrumentation": "npm:0.203.0" + "@opentelemetry/semantic-conventions": "npm:^1.29.0" forwarded-parse: "npm:2.1.2" - semver: "npm:^7.5.2" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/31371f56209362486cb4c8c8e1b31111d6846db89dae4442aaa8ffa47cfb3c7f7ef4c7d19635130a25c391499d7ee17a0c35f140b7641cc4a3749692e70aeb81 + checksum: 10/41cd9cf55de7700ca9b7825d26874d062323a07bfb383f02dd5539011f9cd0bbe3f87cb8c271c333e58f74f79245dcd58b27f7be5bf1607e57a5a7f4cab1328e languageName: node linkType: hard -"@opentelemetry/instrumentation-ioredis@npm:0.47.0": - version: 0.47.0 - resolution: "@opentelemetry/instrumentation-ioredis@npm:0.47.0" +"@opentelemetry/instrumentation-ioredis@npm:0.51.0": + version: 0.51.0 + resolution: "@opentelemetry/instrumentation-ioredis@npm:0.51.0" dependencies: - "@opentelemetry/instrumentation": "npm:^0.57.0" - "@opentelemetry/redis-common": "npm:^0.36.2" + "@opentelemetry/instrumentation": "npm:^0.203.0" + "@opentelemetry/redis-common": "npm:^0.38.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/3a885546c950db88ac71c2506544d3e977c561fbfdbe53b4e9d071a017968d5b6ef347dbd64954ae2d315fdd0209429832156438d9eb904bb6c576ed2ff79af1 + checksum: 10/fba9ccf4725e094f8436d57ca77c1c4a249da7d7ad0b5e95d90d6db7f0cf1f3df07ee2cf7abfb59b322471e5fe2b9a1385289addf9d1f5b86397fc2cbe57f9e7 languageName: node linkType: hard -"@opentelemetry/instrumentation-kafkajs@npm:0.7.0": - version: 0.7.0 - resolution: "@opentelemetry/instrumentation-kafkajs@npm:0.7.0" +"@opentelemetry/instrumentation-kafkajs@npm:0.12.0": + version: 0.12.0 + resolution: "@opentelemetry/instrumentation-kafkajs@npm:0.12.0" dependencies: - "@opentelemetry/instrumentation": "npm:^0.57.0" - "@opentelemetry/semantic-conventions": "npm:^1.27.0" + "@opentelemetry/instrumentation": "npm:^0.203.0" + "@opentelemetry/semantic-conventions": "npm:^1.30.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/a92f1ffb75e86f4f9db0e7f866c3993af9c5c1af850afcd49a928266df3394ca6fb073c92f2de670c6441b07ad113d9f3a4261bd965c80a6de701beff0f54a56 + checksum: 10/24c47c930d4fb91e7a098123d6a976554166744f2e08c563bfdbcfccd50512c1110ff6eaafa85f12e6710ab0ef36c97310d03500999ca12ab2099e70b8df1447 languageName: node linkType: hard -"@opentelemetry/instrumentation-knex@npm:0.44.0": - version: 0.44.0 - resolution: "@opentelemetry/instrumentation-knex@npm:0.44.0" +"@opentelemetry/instrumentation-knex@npm:0.48.0": + version: 0.48.0 + resolution: "@opentelemetry/instrumentation-knex@npm:0.48.0" dependencies: - "@opentelemetry/instrumentation": "npm:^0.57.0" - "@opentelemetry/semantic-conventions": "npm:^1.27.0" + "@opentelemetry/instrumentation": "npm:^0.203.0" + "@opentelemetry/semantic-conventions": "npm:^1.33.1" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/d4e8197b83f55744ee35029105e53cd2e00b6afc79528c949429a786d69c3febe847d607ecda73503b1bfdff48b468dc5390c1935253335469b9b3873cd1d58b + checksum: 10/7cf440b2511143ce2cfffd7251832b00dc08d887edbf44bb4f11375113b8a76937a69ea6ce97251db8102b118a2978d99f34dbea20d8959bb4f5842c44471b68 languageName: node linkType: hard -"@opentelemetry/instrumentation-koa@npm:0.47.0": - version: 0.47.0 - resolution: "@opentelemetry/instrumentation-koa@npm:0.47.0" +"@opentelemetry/instrumentation-koa@npm:0.51.0": + version: 0.51.0 + resolution: "@opentelemetry/instrumentation-koa@npm:0.51.0" dependencies: - "@opentelemetry/core": "npm:^1.8.0" - "@opentelemetry/instrumentation": "npm:^0.57.0" + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/instrumentation": "npm:^0.203.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/abdb5a4e27200ba776faef44f028c2629f5342480eb35a95a179552e587bfef0e1d82490174f51580ddf2bd5a550b73c24aa46e9a0aea3d53653e30bf32aeece + checksum: 10/7cdcc788f5b892e8f12ec0a03bb4915163c894b47f4bb2bb41ef455b73b48fed7587029f5c0216605b0004aed0a228556c7990254680385a5d94b820668b0f2f languageName: node linkType: hard -"@opentelemetry/instrumentation-lru-memoizer@npm:0.44.0": - version: 0.44.0 - resolution: "@opentelemetry/instrumentation-lru-memoizer@npm:0.44.0" +"@opentelemetry/instrumentation-lru-memoizer@npm:0.48.0": + version: 0.48.0 + resolution: "@opentelemetry/instrumentation-lru-memoizer@npm:0.48.0" dependencies: - "@opentelemetry/instrumentation": "npm:^0.57.0" + "@opentelemetry/instrumentation": "npm:^0.203.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/c46b48af519232ab52b6ad38e78cb8e665005167d8e2fe73c44c388b4770cdbbbda9646b9db71ab14c3516951d4ae87f106e678a8b2ba236d602f0bdb5bb9115 + checksum: 10/ef538bc5e5ebfc1a4788c564b33fd2d6b8fd3da2ca62cb1c807e686f859c8b03ab5ea075cb043128767cabc0fd2cc0c986d5624db02c5a298623739e9ca2c2cd languageName: node linkType: hard -"@opentelemetry/instrumentation-mongodb@npm:0.51.0": - version: 0.51.0 - resolution: "@opentelemetry/instrumentation-mongodb@npm:0.51.0" +"@opentelemetry/instrumentation-mongodb@npm:0.56.0": + version: 0.56.0 + resolution: "@opentelemetry/instrumentation-mongodb@npm:0.56.0" dependencies: - "@opentelemetry/instrumentation": "npm:^0.57.0" + "@opentelemetry/instrumentation": "npm:^0.203.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/c0330a18728c5f0ee8b6756b01b75e0bb66ff225b45e4556702cff2fdf199584d6435f8b66a1e10c0200678d64182be3ef7d1d2d55cd5db9b0618b247420dc02 + checksum: 10/79cad7572be8e1418e9edcaf6fec1e76a186cccf41e0b21ae0d0479665530bfc88ab960f13136475d75ff57c0d890dc102d963ee06efc2e0ec4990a9484602be languageName: node linkType: hard -"@opentelemetry/instrumentation-mongoose@npm:0.46.0": - version: 0.46.0 - resolution: "@opentelemetry/instrumentation-mongoose@npm:0.46.0" +"@opentelemetry/instrumentation-mongoose@npm:0.50.0": + version: 0.50.0 + resolution: "@opentelemetry/instrumentation-mongoose@npm:0.50.0" dependencies: - "@opentelemetry/core": "npm:^1.8.0" - "@opentelemetry/instrumentation": "npm:^0.57.0" + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/instrumentation": "npm:^0.203.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/349848f3f2213f2818186774ade0b7933659fac3346adbb8bd731ff606117e261fbcca479eb7077bac10ae0204bff0e79d06ffed6752a6cd220be1282fea10d3 + checksum: 10/f920753874aeda4579be1206a0a7ebdf97922105cdf666d8b6ac75d05f98a689743f5bda9ae649cf8d143cc9fbb2f0fdc420e2d53f84706822a9e04755c97907 languageName: node linkType: hard -"@opentelemetry/instrumentation-mysql2@npm:0.45.0": - version: 0.45.0 - resolution: "@opentelemetry/instrumentation-mysql2@npm:0.45.0" +"@opentelemetry/instrumentation-mysql2@npm:0.49.0": + version: 0.49.0 + resolution: "@opentelemetry/instrumentation-mysql2@npm:0.49.0" dependencies: - "@opentelemetry/instrumentation": "npm:^0.57.0" + "@opentelemetry/instrumentation": "npm:^0.203.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" - "@opentelemetry/sql-common": "npm:^0.40.1" + "@opentelemetry/sql-common": "npm:^0.41.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/30f1a9d9fb8d926a2330aa05ac0ca689564b557b0caa7ee404b69a9a4930e8c1444fe4115bb1419ca061ae5dce79900c8fbcd82902fe252edaf81f252945f0aa + checksum: 10/f0c186c7d1c90c7a4fa066ce5f41adce3d0813be9426f8a6dadb38f43db3b09c9dcb4faaa878534174855c3229979923eca94102d79214f9d02bbcb5ae83f20e languageName: node linkType: hard -"@opentelemetry/instrumentation-mysql@npm:0.45.0": - version: 0.45.0 - resolution: "@opentelemetry/instrumentation-mysql@npm:0.45.0" +"@opentelemetry/instrumentation-mysql@npm:0.49.0": + version: 0.49.0 + resolution: "@opentelemetry/instrumentation-mysql@npm:0.49.0" dependencies: - "@opentelemetry/instrumentation": "npm:^0.57.0" + "@opentelemetry/instrumentation": "npm:^0.203.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" - "@types/mysql": "npm:2.15.26" + "@types/mysql": "npm:2.15.27" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/b5cf28df774b5718a7845741c8facc3a532f63fcc1ef193a0706ee09e28aeea73a010a0095450553b84194e067c3932e135c7c2475fa98c336a80b06b93283c7 + checksum: 10/269247f01505d0f9c89ed341716596a8bc942cbc3b5489cde4bdc3a3f9d8961714605b6cc22eb5854a3d8a416a5e2195faf4e6dcfb9449912b1d6cb8999b9eee languageName: node linkType: hard -"@opentelemetry/instrumentation-pg@npm:0.51.0": - version: 0.51.0 - resolution: "@opentelemetry/instrumentation-pg@npm:0.51.0" +"@opentelemetry/instrumentation-pg@npm:0.55.0": + version: 0.55.0 + resolution: "@opentelemetry/instrumentation-pg@npm:0.55.0" dependencies: - "@opentelemetry/core": "npm:^1.26.0" - "@opentelemetry/instrumentation": "npm:^0.57.0" + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/instrumentation": "npm:^0.203.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" - "@opentelemetry/sql-common": "npm:^0.40.1" - "@types/pg": "npm:8.6.1" + "@opentelemetry/sql-common": "npm:^0.41.0" + "@types/pg": "npm:8.15.4" "@types/pg-pool": "npm:2.0.6" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/2d6869a78763227c352776f74580db6a81d7df3bf1014be2a0864582843528847631234d2c0289d86ad757642383cc0728a368304738251332e1aef166d72701 + checksum: 10/fa19de7d3d0e5255af4c4ed5b42668c9bd34f361247d35d5d9a66a94d0cdfe606db09a1818dbbe084680e71c9a6581a3b35911f6254b720fc0062a1d68941c64 languageName: node linkType: hard -"@opentelemetry/instrumentation-redis-4@npm:0.46.0": - version: 0.46.0 - resolution: "@opentelemetry/instrumentation-redis-4@npm:0.46.0" +"@opentelemetry/instrumentation-redis@npm:0.51.0": + version: 0.51.0 + resolution: "@opentelemetry/instrumentation-redis@npm:0.51.0" dependencies: - "@opentelemetry/instrumentation": "npm:^0.57.0" - "@opentelemetry/redis-common": "npm:^0.36.2" + "@opentelemetry/instrumentation": "npm:^0.203.0" + "@opentelemetry/redis-common": "npm:^0.38.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/e5853a906e268e3ad09cb1a18ac8e8d52ffe0cadf7bec81b2ed61eae99a6d8538798e3321091460b6cebff081c9329e04ca0d3c26d7d993f4939faf55b741775 + checksum: 10/11ea2b5e573a5cbb8604206eb622854aa55ab80218a218b9cbfbc9a12096919fb145fce1483d1124ad2db514090a6d7bf8d36150443183075fe4740a86e144ee languageName: node linkType: hard -"@opentelemetry/instrumentation-tedious@npm:0.18.0": - version: 0.18.0 - resolution: "@opentelemetry/instrumentation-tedious@npm:0.18.0" +"@opentelemetry/instrumentation-tedious@npm:0.22.0": + version: 0.22.0 + resolution: "@opentelemetry/instrumentation-tedious@npm:0.22.0" dependencies: - "@opentelemetry/instrumentation": "npm:^0.57.0" + "@opentelemetry/instrumentation": "npm:^0.203.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" "@types/tedious": "npm:^4.0.14" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/ad39241c25cce81461967590cb389a891cacfed83ec008a35ffac4322a99d8c6db07a5daea50c1db4015faeba69becc92769c9cf60f6500d8d1754c9f8ff021f + checksum: 10/8e74249f3b031dacb17f783fb000598b00d4c399367f6f0523c31c5528d2826d9ff04f17f43867ee688dcb94e49008389d0bb1ddbb2c55eb024230b464539b95 languageName: node linkType: hard -"@opentelemetry/instrumentation-undici@npm:0.10.0": - version: 0.10.0 - resolution: "@opentelemetry/instrumentation-undici@npm:0.10.0" +"@opentelemetry/instrumentation-undici@npm:0.14.0": + version: 0.14.0 + resolution: "@opentelemetry/instrumentation-undici@npm:0.14.0" dependencies: - "@opentelemetry/core": "npm:^1.8.0" - "@opentelemetry/instrumentation": "npm:^0.57.0" + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/instrumentation": "npm:^0.203.0" peerDependencies: "@opentelemetry/api": ^1.7.0 - checksum: 10/eb96ed916eb95504641a0ec3425aa4de91bdea5659b3cc8333e6bc2ffd0e4198999fdb2454969b5d37d30c04183b4da64c3659b2b8abe6370371174a89a0a8ad + checksum: 10/05527080bd54aa59790c596307e238333e3046fc9507bcc645e53f9330ddae51b834f2b29760af978a2966b945ec8647456e4fbc09fb8addbb38aedf05004f8b languageName: node linkType: hard -"@opentelemetry/instrumentation@npm:0.57.1": - version: 0.57.1 - resolution: "@opentelemetry/instrumentation@npm:0.57.1" +"@opentelemetry/instrumentation@npm:0.203.0, @opentelemetry/instrumentation@npm:^0.203.0": + version: 0.203.0 + resolution: "@opentelemetry/instrumentation@npm:0.203.0" dependencies: - "@opentelemetry/api-logs": "npm:0.57.1" - "@types/shimmer": "npm:^1.2.0" + "@opentelemetry/api-logs": "npm:0.203.0" import-in-the-middle: "npm:^1.8.1" require-in-the-middle: "npm:^7.1.1" - semver: "npm:^7.5.2" - shimmer: "npm:^1.2.1" - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: 10/8f21a1b69aab5b48f8d85da2dd944d12f498757b890d4da062f7736a2254b19fb2c678db1807889e0526d3bbb653455c24c0d89523662d358fdb4e615f099fcf - languageName: node - linkType: hard - -"@opentelemetry/instrumentation@npm:^0.52.0 || ^0.53.0 || ^0.54.0 || ^0.55.0 || ^0.56.0": - version: 0.56.0 - resolution: "@opentelemetry/instrumentation@npm:0.56.0" - dependencies: - "@opentelemetry/api-logs": "npm:0.56.0" - "@types/shimmer": "npm:^1.2.0" - import-in-the-middle: "npm:^1.8.1" - require-in-the-middle: "npm:^7.1.1" - semver: "npm:^7.5.2" - shimmer: "npm:^1.2.1" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/7c3802eb6b55b39b6904526d052b918619c9cde0f71a35bc2f23ac6c3a10ea66b08a65adf6862cdbaac7b231fb5119204b4d5531be25b96933a9d8b91a9ce062 + checksum: 10/0e85cd7df97e4a7a9cdd23d187be45dae93806bf04783c531fe847cc4b24abd96934ad1196320661190648444d726bed1f702fa96e0af3fc7edb3c04c44fde34 languageName: node linkType: hard -"@opentelemetry/instrumentation@npm:^0.57.0, @opentelemetry/instrumentation@npm:^0.57.1": +"@opentelemetry/instrumentation@npm:^0.52.0 || ^0.53.0 || ^0.54.0 || ^0.55.0 || ^0.56.0 || ^0.57.0": version: 0.57.2 resolution: "@opentelemetry/instrumentation@npm:0.57.2" dependencies: @@ -4109,67 +4057,60 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/redis-common@npm:^0.36.2": - version: 0.36.2 - resolution: "@opentelemetry/redis-common@npm:0.36.2" - checksum: 10/e7f610f79c95bab9156a9831162c7b55b94ab43c5e47ecb9efcc10c08a236395fdd54b6bb018da981e6641bac9da6fda1b50636fb49db584e87d988750d255e1 +"@opentelemetry/redis-common@npm:^0.38.0": + version: 0.38.0 + resolution: "@opentelemetry/redis-common@npm:0.38.0" + checksum: 10/c7caa450ed27ad02aeefa3e4d643e7d065d76e5f1cd275c8c3d0c7d324bf7d06434666dbd836d219f6b2e1057285f30ccaa89b949438b38118a70786ec31fa52 languageName: node linkType: hard -"@opentelemetry/resources@npm:1.30.1, @opentelemetry/resources@npm:^1.30.1": - version: 1.30.1 - resolution: "@opentelemetry/resources@npm:1.30.1" +"@opentelemetry/resources@npm:2.0.1, @opentelemetry/resources@npm:^2.0.0": + version: 2.0.1 + resolution: "@opentelemetry/resources@npm:2.0.1" dependencies: - "@opentelemetry/core": "npm:1.30.1" - "@opentelemetry/semantic-conventions": "npm:1.28.0" + "@opentelemetry/core": "npm:2.0.1" + "@opentelemetry/semantic-conventions": "npm:^1.29.0" peerDependencies: - "@opentelemetry/api": ">=1.0.0 <1.10.0" - checksum: 10/9b7544b639e8fee41315e2646615676ffb1020dba0f6c81e6ec1dd2daf5409fc6ce3d2b629bbd9cd32f85decc3a8bfa5dc8cc52bb72bd84c1777ca25b4301aa0 + "@opentelemetry/api": ">=1.3.0 <1.10.0" + checksum: 10/282f3831de2755d0fda2d8b6e37f9587ea248066d50c7d2f14c803ac9d5262a0f1db98a4185bcdc5acaeeece0b61f4fce43bc3896a79f1da79045ae4928618bf languageName: node linkType: hard -"@opentelemetry/sdk-trace-base@npm:^1.30.1": - version: 1.30.1 - resolution: "@opentelemetry/sdk-trace-base@npm:1.30.1" +"@opentelemetry/sdk-trace-base@npm:^2.0.0": + version: 2.0.1 + resolution: "@opentelemetry/sdk-trace-base@npm:2.0.1" dependencies: - "@opentelemetry/core": "npm:1.30.1" - "@opentelemetry/resources": "npm:1.30.1" - "@opentelemetry/semantic-conventions": "npm:1.28.0" + "@opentelemetry/core": "npm:2.0.1" + "@opentelemetry/resources": "npm:2.0.1" + "@opentelemetry/semantic-conventions": "npm:^1.29.0" peerDependencies: - "@opentelemetry/api": ">=1.0.0 <1.10.0" - checksum: 10/3ba794622c9ff1d147b77fcd0c8547a6a1356edb5af884cf1d09838c71a004a044ea55d4c742b956e9247e46053583bdbda533836686b2f54ee1ecfc527254ff + "@opentelemetry/api": ">=1.3.0 <1.10.0" + checksum: 10/9de1e36bbce9bd7c0563e6395765fffc0f8c78806cb33cc95267e98dffd82de33857a51288073a104c10418b934e51560bcb5dcaf4e63e5c9e096f65cadd42cd languageName: node linkType: hard -"@opentelemetry/semantic-conventions@npm:1.27.0, @opentelemetry/semantic-conventions@npm:^1.27.0": +"@opentelemetry/semantic-conventions@npm:^1.27.0": version: 1.27.0 resolution: "@opentelemetry/semantic-conventions@npm:1.27.0" checksum: 10/98166522f299e2fe3d43376adbdeb92679b75ebb172e2a3c4c71f2942bd91585e9537618efbbae6dc08177699e5719368edf66d7e69e8636f360b85217bbdbe1 languageName: node linkType: hard -"@opentelemetry/semantic-conventions@npm:1.28.0": - version: 1.28.0 - resolution: "@opentelemetry/semantic-conventions@npm:1.28.0" - checksum: 10/c182a3206769b5d5a8ab89a5c674d046fd789421cef27ea55af179990e314732433c98e5017aa23e99f15fd2b0e13cb129bb6c2282da6860ce9419adf32b2e87 +"@opentelemetry/semantic-conventions@npm:^1.29.0, @opentelemetry/semantic-conventions@npm:^1.30.0, @opentelemetry/semantic-conventions@npm:^1.33.1, @opentelemetry/semantic-conventions@npm:^1.34.0": + version: 1.36.0 + resolution: "@opentelemetry/semantic-conventions@npm:1.36.0" + checksum: 10/f1939066c30147348b326840d67cc48e73072b762f2e2af5c3ea894268d64c62fc4e73fad49a72ed4a52a543b2fa0824c969a676e658ae727f75182f52104007 languageName: node linkType: hard -"@opentelemetry/semantic-conventions@npm:^1.28.0": - version: 1.30.0 - resolution: "@opentelemetry/semantic-conventions@npm:1.30.0" - checksum: 10/78df5976f5bcfd00acaea3e609cf06fdd34517ae8db994ae216aaac16c51af97ac22c534bfcbac5218e0086db83ec5ef6cc045b95626cc6ea807686bea549a41 - languageName: node - linkType: hard - -"@opentelemetry/sql-common@npm:^0.40.1": - version: 0.40.1 - resolution: "@opentelemetry/sql-common@npm:0.40.1" +"@opentelemetry/sql-common@npm:^0.41.0": + version: 0.41.0 + resolution: "@opentelemetry/sql-common@npm:0.41.0" dependencies: - "@opentelemetry/core": "npm:^1.1.0" + "@opentelemetry/core": "npm:^2.0.0" peerDependencies: "@opentelemetry/api": ^1.1.0 - checksum: 10/f887b4135be56c9ef6e29f040c9f75f34709e38c11897d59d284d7e73175a2dd2c6267c18061144e81a0045fc461b7813769db2e49c42a8d6becc58b1456d55c + checksum: 10/182915f050b8b685f5499e9fa4ed9a9730fcd404889e5066cfc7d94e9961b1f2780216d776070a4a5c1b94323c287ab426b06f5a8828d5fea3daf664bfd397bb languageName: node linkType: hard @@ -4238,14 +4179,14 @@ __metadata: languageName: node linkType: hard -"@prisma/instrumentation@npm:6.2.1": - version: 6.2.1 - resolution: "@prisma/instrumentation@npm:6.2.1" +"@prisma/instrumentation@npm:6.13.0": + version: 6.13.0 + resolution: "@prisma/instrumentation@npm:6.13.0" dependencies: - "@opentelemetry/instrumentation": "npm:^0.52.0 || ^0.53.0 || ^0.54.0 || ^0.55.0 || ^0.56.0" + "@opentelemetry/instrumentation": "npm:^0.52.0 || ^0.53.0 || ^0.54.0 || ^0.55.0 || ^0.56.0 || ^0.57.0" peerDependencies: "@opentelemetry/api": ^1.8 - checksum: 10/d97fc1384d6167722a85065be73f20c6ab9165a92026026c627800b4947fc5b5d655e6f9e0a4727ebd6b01aee19babf273800df7eba3995903c0d6ea566e4208 + checksum: 10/f72f56c0adb990af967c6f1e13fed5cb88b5285fa7e18663ee30f3991c2d61c6af4ab93d3188e3a92fd87df10e4f7f684a71a35aa9087fb77b470815f0ca9b33 languageName: node linkType: hard @@ -4294,6 +4235,146 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-android-arm-eabi@npm:4.48.1": + version: 4.48.1 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.48.1" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@rollup/rollup-android-arm64@npm:4.48.1": + version: 4.48.1 + resolution: "@rollup/rollup-android-arm64@npm:4.48.1" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-darwin-arm64@npm:4.48.1": + version: 4.48.1 + resolution: "@rollup/rollup-darwin-arm64@npm:4.48.1" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-darwin-x64@npm:4.48.1": + version: 4.48.1 + resolution: "@rollup/rollup-darwin-x64@npm:4.48.1" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-freebsd-arm64@npm:4.48.1": + version: 4.48.1 + resolution: "@rollup/rollup-freebsd-arm64@npm:4.48.1" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-freebsd-x64@npm:4.48.1": + version: 4.48.1 + resolution: "@rollup/rollup-freebsd-x64@npm:4.48.1" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm-gnueabihf@npm:4.48.1": + version: 4.48.1 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.48.1" + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm-musleabihf@npm:4.48.1": + version: 4.48.1 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.48.1" + conditions: os=linux & cpu=arm & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm64-gnu@npm:4.48.1": + version: 4.48.1 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.48.1" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm64-musl@npm:4.48.1": + version: 4.48.1 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.48.1" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-loongarch64-gnu@npm:4.48.1": + version: 4.48.1 + resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.48.1" + conditions: os=linux & cpu=loong64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-ppc64-gnu@npm:4.48.1": + version: 4.48.1 + resolution: "@rollup/rollup-linux-ppc64-gnu@npm:4.48.1" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-riscv64-gnu@npm:4.48.1": + version: 4.48.1 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.48.1" + conditions: os=linux & cpu=riscv64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-riscv64-musl@npm:4.48.1": + version: 4.48.1 + resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.48.1" + conditions: os=linux & cpu=riscv64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-s390x-gnu@npm:4.48.1": + version: 4.48.1 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.48.1" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-x64-gnu@npm:4.48.1": + version: 4.48.1 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.48.1" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-x64-musl@npm:4.48.1": + version: 4.48.1 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.48.1" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-win32-arm64-msvc@npm:4.48.1": + version: 4.48.1 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.48.1" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-win32-ia32-msvc@npm:4.48.1": + version: 4.48.1 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.48.1" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@rollup/rollup-win32-x64-msvc@npm:4.48.1": + version: 4.48.1 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.48.1" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@rtsao/scc@npm:^1.1.0": version: 1.1.0 resolution: "@rtsao/scc@npm:1.1.0" @@ -4308,140 +4389,148 @@ __metadata: languageName: node linkType: hard -"@sentry-internal/browser-utils@npm:9.1.0": - version: 9.1.0 - resolution: "@sentry-internal/browser-utils@npm:9.1.0" +"@sentry-internal/browser-utils@npm:10.6.0": + version: 10.6.0 + resolution: "@sentry-internal/browser-utils@npm:10.6.0" dependencies: - "@sentry/core": "npm:9.1.0" - checksum: 10/d69ce2f8bd6fad76435b8d0f5747b523883ead1faaf8717f03f8392ab42cc040195cbd35ba9ea70556e04ec361ebea302aa23a989683de5e03cf070ff19e91d8 + "@sentry/core": "npm:10.6.0" + checksum: 10/1128ca29e07c1c0dda872f6cd00f4da89682ea660155820603e094f460313f50ff7f06767721d1b57e6ac6b3dc8029a20faaa6f1009c823d257bf93fe3a88992 languageName: node linkType: hard -"@sentry-internal/feedback@npm:9.1.0": - version: 9.1.0 - resolution: "@sentry-internal/feedback@npm:9.1.0" +"@sentry-internal/feedback@npm:10.6.0": + version: 10.6.0 + resolution: "@sentry-internal/feedback@npm:10.6.0" dependencies: - "@sentry/core": "npm:9.1.0" - checksum: 10/0d068eb1987618ba84cc2007d7a1ea4a661e3f5fcb24c23293e61b1f6d0c4d69deaa9f3afe9d2c895c76652540c7599d2a4ad197ee0627fd328a2a0cbf1fa9a4 + "@sentry/core": "npm:10.6.0" + checksum: 10/a568db12def5ef831f49e5f0fba9bfaada523f2b9eb35b73c9723bacf3e94efe44a0cf84aa7c73c491dc5acfe05f6de24a234a73e13eb9864c62de4831f7f9ef languageName: node linkType: hard -"@sentry-internal/replay-canvas@npm:9.1.0": - version: 9.1.0 - resolution: "@sentry-internal/replay-canvas@npm:9.1.0" +"@sentry-internal/replay-canvas@npm:10.6.0": + version: 10.6.0 + resolution: "@sentry-internal/replay-canvas@npm:10.6.0" dependencies: - "@sentry-internal/replay": "npm:9.1.0" - "@sentry/core": "npm:9.1.0" - checksum: 10/7601200b8f6d3dc08f6038804b4fef7632cf7fb03ee2e0243db93a62232d24686243ea17b4c41ce34cb8ffb7015066873c5f71d4abef23b040cc7a366833bcd9 + "@sentry-internal/replay": "npm:10.6.0" + "@sentry/core": "npm:10.6.0" + checksum: 10/d1063bcfecc67224f900d652cad941b0006ea190dc7290991849e7c34357c7be25862d5b1237e30bdba46b3d470a3181e6dba76c5816bab8a8e787b4b03487e8 languageName: node linkType: hard -"@sentry-internal/replay@npm:9.1.0": - version: 9.1.0 - resolution: "@sentry-internal/replay@npm:9.1.0" +"@sentry-internal/replay@npm:10.6.0": + version: 10.6.0 + resolution: "@sentry-internal/replay@npm:10.6.0" dependencies: - "@sentry-internal/browser-utils": "npm:9.1.0" - "@sentry/core": "npm:9.1.0" - checksum: 10/c6a59eb184e5101ea1e442be0d24d544bf92a1cf7dce806d150af632756a97d3e27641f401b0703956f6b94704ca704a2028dbfb072565e39430352abf0a398f + "@sentry-internal/browser-utils": "npm:10.6.0" + "@sentry/core": "npm:10.6.0" + checksum: 10/6dca9c3723888a78b3b8b20e9d197ec986a73a30f8184317489da4ad7f361287aff724cd179a3f6b67d989e603caf5330d2a36fe9d6d7a15bf9240205688f236 languageName: node linkType: hard -"@sentry/babel-plugin-component-annotate@npm:3.1.2": - version: 3.1.2 - resolution: "@sentry/babel-plugin-component-annotate@npm:3.1.2" - checksum: 10/753de4d5552389767dfd3b6f026d636ad2665118e368d21a28e38d5c3534abbe2cd015449e13830c5a0d0301b377158176767936a99ee2263409e06514fa1901 +"@sentry/babel-plugin-component-annotate@npm:4.1.1": + version: 4.1.1 + resolution: "@sentry/babel-plugin-component-annotate@npm:4.1.1" + checksum: 10/728f553f33c0ad52898eae7914e3a91d2a02301e26bd53eade1ff8a75bd6a57028772fb145b5edc2caaa4290f49f1403b68573d654ad7835c701ad3a72f16a9e languageName: node linkType: hard -"@sentry/browser@npm:9.1.0": - version: 9.1.0 - resolution: "@sentry/browser@npm:9.1.0" +"@sentry/browser@npm:10.6.0": + version: 10.6.0 + resolution: "@sentry/browser@npm:10.6.0" dependencies: - "@sentry-internal/browser-utils": "npm:9.1.0" - "@sentry-internal/feedback": "npm:9.1.0" - "@sentry-internal/replay": "npm:9.1.0" - "@sentry-internal/replay-canvas": "npm:9.1.0" - "@sentry/core": "npm:9.1.0" - checksum: 10/194b8a13e9ea61cf0f1f20f9a9fd9fd380e7b2e1040cc6201668f7c1d162933b92d75e5360937167d3d1945b152cd50f74618ba4ea617dc5cca1ea150729166d + "@sentry-internal/browser-utils": "npm:10.6.0" + "@sentry-internal/feedback": "npm:10.6.0" + "@sentry-internal/replay": "npm:10.6.0" + "@sentry-internal/replay-canvas": "npm:10.6.0" + "@sentry/core": "npm:10.6.0" + checksum: 10/5926a8252e7a2a4082b198022f472904739256e641e0d1618342b77d14279122a998b8fe7a1fbbe208e76e4ccf8b16fe54943de5fa9129c44f9e1284c85d7cdc languageName: node linkType: hard -"@sentry/bundler-plugin-core@npm:3.1.2": - version: 3.1.2 - resolution: "@sentry/bundler-plugin-core@npm:3.1.2" +"@sentry/bundler-plugin-core@npm:4.1.1": + version: 4.1.1 + resolution: "@sentry/bundler-plugin-core@npm:4.1.1" dependencies: "@babel/core": "npm:^7.18.5" - "@sentry/babel-plugin-component-annotate": "npm:3.1.2" - "@sentry/cli": "npm:2.41.1" + "@sentry/babel-plugin-component-annotate": "npm:4.1.1" + "@sentry/cli": "npm:^2.51.0" dotenv: "npm:^16.3.1" find-up: "npm:^5.0.0" glob: "npm:^9.3.2" magic-string: "npm:0.30.8" unplugin: "npm:1.0.1" - checksum: 10/9b1d70b0770833d5570b60461c0364a16c84c5594fe65986cbd49a4bd8aaf3b47b8cd584c36bdd4d3c125566b59b094b2e17db3b775fd60dd11e9669c95a1ee4 + checksum: 10/8fffaaa95fbef074607fe272460e9d8589f0f6db55404de4d6b36bb5d9be1c31067615a2bcd87ec6761c4bd1c3671b4d44172dadcb3d9d7be6454c4c523b9be3 languageName: node linkType: hard -"@sentry/cli-darwin@npm:2.41.1": - version: 2.41.1 - resolution: "@sentry/cli-darwin@npm:2.41.1" +"@sentry/cli-darwin@npm:2.52.0": + version: 2.52.0 + resolution: "@sentry/cli-darwin@npm:2.52.0" conditions: os=darwin languageName: node linkType: hard -"@sentry/cli-linux-arm64@npm:2.41.1": - version: 2.41.1 - resolution: "@sentry/cli-linux-arm64@npm:2.41.1" - conditions: (os=linux | os=freebsd) & cpu=arm64 +"@sentry/cli-linux-arm64@npm:2.52.0": + version: 2.52.0 + resolution: "@sentry/cli-linux-arm64@npm:2.52.0" + conditions: (os=linux | os=freebsd | os=android) & cpu=arm64 languageName: node linkType: hard -"@sentry/cli-linux-arm@npm:2.41.1": - version: 2.41.1 - resolution: "@sentry/cli-linux-arm@npm:2.41.1" - conditions: (os=linux | os=freebsd) & cpu=arm +"@sentry/cli-linux-arm@npm:2.52.0": + version: 2.52.0 + resolution: "@sentry/cli-linux-arm@npm:2.52.0" + conditions: (os=linux | os=freebsd | os=android) & cpu=arm languageName: node linkType: hard -"@sentry/cli-linux-i686@npm:2.41.1": - version: 2.41.1 - resolution: "@sentry/cli-linux-i686@npm:2.41.1" - conditions: (os=linux | os=freebsd) & (cpu=x86 | cpu=ia32) +"@sentry/cli-linux-i686@npm:2.52.0": + version: 2.52.0 + resolution: "@sentry/cli-linux-i686@npm:2.52.0" + conditions: (os=linux | os=freebsd | os=android) & (cpu=x86 | cpu=ia32) languageName: node linkType: hard -"@sentry/cli-linux-x64@npm:2.41.1": - version: 2.41.1 - resolution: "@sentry/cli-linux-x64@npm:2.41.1" - conditions: (os=linux | os=freebsd) & cpu=x64 +"@sentry/cli-linux-x64@npm:2.52.0": + version: 2.52.0 + resolution: "@sentry/cli-linux-x64@npm:2.52.0" + conditions: (os=linux | os=freebsd | os=android) & cpu=x64 languageName: node linkType: hard -"@sentry/cli-win32-i686@npm:2.41.1": - version: 2.41.1 - resolution: "@sentry/cli-win32-i686@npm:2.41.1" +"@sentry/cli-win32-arm64@npm:2.52.0": + version: 2.52.0 + resolution: "@sentry/cli-win32-arm64@npm:2.52.0" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@sentry/cli-win32-i686@npm:2.52.0": + version: 2.52.0 + resolution: "@sentry/cli-win32-i686@npm:2.52.0" conditions: os=win32 & (cpu=x86 | cpu=ia32) languageName: node linkType: hard -"@sentry/cli-win32-x64@npm:2.41.1": - version: 2.41.1 - resolution: "@sentry/cli-win32-x64@npm:2.41.1" +"@sentry/cli-win32-x64@npm:2.52.0": + version: 2.52.0 + resolution: "@sentry/cli-win32-x64@npm:2.52.0" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@sentry/cli@npm:2.41.1": - version: 2.41.1 - resolution: "@sentry/cli@npm:2.41.1" +"@sentry/cli@npm:^2.51.0": + version: 2.52.0 + resolution: "@sentry/cli@npm:2.52.0" dependencies: - "@sentry/cli-darwin": "npm:2.41.1" - "@sentry/cli-linux-arm": "npm:2.41.1" - "@sentry/cli-linux-arm64": "npm:2.41.1" - "@sentry/cli-linux-i686": "npm:2.41.1" - "@sentry/cli-linux-x64": "npm:2.41.1" - "@sentry/cli-win32-i686": "npm:2.41.1" - "@sentry/cli-win32-x64": "npm:2.41.1" + "@sentry/cli-darwin": "npm:2.52.0" + "@sentry/cli-linux-arm": "npm:2.52.0" + "@sentry/cli-linux-arm64": "npm:2.52.0" + "@sentry/cli-linux-i686": "npm:2.52.0" + "@sentry/cli-linux-x64": "npm:2.52.0" + "@sentry/cli-win32-arm64": "npm:2.52.0" + "@sentry/cli-win32-i686": "npm:2.52.0" + "@sentry/cli-win32-x64": "npm:2.52.0" https-proxy-agent: "npm:^5.0.0" node-fetch: "npm:^2.6.7" progress: "npm:^2.0.3" @@ -4458,138 +4547,160 @@ __metadata: optional: true "@sentry/cli-linux-x64": optional: true + "@sentry/cli-win32-arm64": + optional: true "@sentry/cli-win32-i686": optional: true "@sentry/cli-win32-x64": optional: true bin: sentry-cli: bin/sentry-cli - checksum: 10/acfec8a360293f06bd0e5f2f3d066b16dda517df7feffd161351bc1797f6e68f0ffe89849ed59f30d2df18654f5b0d9950031ec5c2cde2b4dcc72d0dd618e19f + checksum: 10/25213c1eb45b3afa85ca81c0cb19bea6268b1d59a262b5cc60bb7ee262bf8414ed7b68c62da6d38d673f490d297602eefa1dfb9c70ac285831536a4a3cbeed8d languageName: node linkType: hard -"@sentry/core@npm:9.1.0": - version: 9.1.0 - resolution: "@sentry/core@npm:9.1.0" - checksum: 10/ff1761202fb98facf567514fee5c9fcc1dce1937b00acc9484e27d30effc59a6b0bf4d2dccdd9749eec75b6d8a94f38b3012cb1a673d9ae25ba1d3e29e706c93 +"@sentry/core@npm:10.6.0": + version: 10.6.0 + resolution: "@sentry/core@npm:10.6.0" + checksum: 10/5d77f2844353de5e61eae5b2e711815b248a18cfb9cba21efb5957955e152f3b8a509ad9e63427f4f9c4e815c62ae9ccc4a991a08fc4063b38ff6f384cd1c918 languageName: node linkType: hard -"@sentry/nextjs@npm:^9.0.0": - version: 9.1.0 - resolution: "@sentry/nextjs@npm:9.1.0" +"@sentry/nextjs@npm:^10.0.0": + version: 10.6.0 + resolution: "@sentry/nextjs@npm:10.6.0" dependencies: "@opentelemetry/api": "npm:^1.9.0" - "@opentelemetry/semantic-conventions": "npm:^1.28.0" + "@opentelemetry/semantic-conventions": "npm:^1.34.0" "@rollup/plugin-commonjs": "npm:28.0.1" - "@sentry-internal/browser-utils": "npm:9.1.0" - "@sentry/core": "npm:9.1.0" - "@sentry/node": "npm:9.1.0" - "@sentry/opentelemetry": "npm:9.1.0" - "@sentry/react": "npm:9.1.0" - "@sentry/vercel-edge": "npm:9.1.0" - "@sentry/webpack-plugin": "npm:3.1.2" + "@sentry-internal/browser-utils": "npm:10.6.0" + "@sentry/core": "npm:10.6.0" + "@sentry/node": "npm:10.6.0" + "@sentry/opentelemetry": "npm:10.6.0" + "@sentry/react": "npm:10.6.0" + "@sentry/vercel-edge": "npm:10.6.0" + "@sentry/webpack-plugin": "npm:^4.1.0" chalk: "npm:3.0.0" resolve: "npm:1.22.8" - rollup: "npm:3.29.5" + rollup: "npm:^4.35.0" stacktrace-parser: "npm:^0.1.10" peerDependencies: next: ^13.2.0 || ^14.0 || ^15.0.0-rc.0 - checksum: 10/f90db244132eca6de7b1cf9666ab92e85365798a9a0fbb9e699534ba32e47279b34e211c6b1295976e8e9e7a35a51afb8d73e44f57f5bdebdedb72b6d81752e7 + checksum: 10/9a87c466e190308b012ac61f9d00966599b03ff47f939a0817b2e147cca028b21bf6648cba999d2aace6c82459a65ef3f0c3c2c191e613650d69ed15338cfa5f languageName: node linkType: hard -"@sentry/node@npm:9.1.0": - version: 9.1.0 - resolution: "@sentry/node@npm:9.1.0" +"@sentry/node-core@npm:10.6.0": + version: 10.6.0 + resolution: "@sentry/node-core@npm:10.6.0" + dependencies: + "@sentry/core": "npm:10.6.0" + "@sentry/opentelemetry": "npm:10.6.0" + import-in-the-middle: "npm:^1.14.2" + peerDependencies: + "@opentelemetry/api": ^1.9.0 + "@opentelemetry/context-async-hooks": ^1.30.1 || ^2.0.0 + "@opentelemetry/core": ^1.30.1 || ^2.0.0 + "@opentelemetry/instrumentation": ">=0.57.1 <1" + "@opentelemetry/resources": ^1.30.1 || ^2.0.0 + "@opentelemetry/sdk-trace-base": ^1.30.1 || ^2.0.0 + "@opentelemetry/semantic-conventions": ^1.34.0 + checksum: 10/18e995bdd1b2249f505fb4023dc30b21260e5368e452d2618d35bdf781ea2238046ad0e20784b774706036e65aca6c66eff1a49bb3f1efe50390d76d05ee297b + languageName: node + linkType: hard + +"@sentry/node@npm:10.6.0": + version: 10.6.0 + resolution: "@sentry/node@npm:10.6.0" dependencies: "@opentelemetry/api": "npm:^1.9.0" - "@opentelemetry/context-async-hooks": "npm:^1.30.1" - "@opentelemetry/core": "npm:^1.30.1" - "@opentelemetry/instrumentation": "npm:^0.57.1" - "@opentelemetry/instrumentation-amqplib": "npm:^0.46.0" - "@opentelemetry/instrumentation-connect": "npm:0.43.0" - "@opentelemetry/instrumentation-dataloader": "npm:0.16.0" - "@opentelemetry/instrumentation-express": "npm:0.47.0" - "@opentelemetry/instrumentation-fastify": "npm:0.44.1" - "@opentelemetry/instrumentation-fs": "npm:0.19.0" - "@opentelemetry/instrumentation-generic-pool": "npm:0.43.0" - "@opentelemetry/instrumentation-graphql": "npm:0.47.0" - "@opentelemetry/instrumentation-hapi": "npm:0.45.1" - "@opentelemetry/instrumentation-http": "npm:0.57.1" - "@opentelemetry/instrumentation-ioredis": "npm:0.47.0" - "@opentelemetry/instrumentation-kafkajs": "npm:0.7.0" - "@opentelemetry/instrumentation-knex": "npm:0.44.0" - "@opentelemetry/instrumentation-koa": "npm:0.47.0" - "@opentelemetry/instrumentation-lru-memoizer": "npm:0.44.0" - "@opentelemetry/instrumentation-mongodb": "npm:0.51.0" - "@opentelemetry/instrumentation-mongoose": "npm:0.46.0" - "@opentelemetry/instrumentation-mysql": "npm:0.45.0" - "@opentelemetry/instrumentation-mysql2": "npm:0.45.0" - "@opentelemetry/instrumentation-pg": "npm:0.51.0" - "@opentelemetry/instrumentation-redis-4": "npm:0.46.0" - "@opentelemetry/instrumentation-tedious": "npm:0.18.0" - "@opentelemetry/instrumentation-undici": "npm:0.10.0" - "@opentelemetry/resources": "npm:^1.30.1" - "@opentelemetry/sdk-trace-base": "npm:^1.30.1" - "@opentelemetry/semantic-conventions": "npm:^1.28.0" - "@prisma/instrumentation": "npm:6.2.1" - "@sentry/core": "npm:9.1.0" - "@sentry/opentelemetry": "npm:9.1.0" - import-in-the-middle: "npm:^1.12.0" - checksum: 10/1e3f9b98d84825d8a375e2b922d83b1d1988bbb3e23abfe3ebcb8078e2552d1527a1e37f82444efdb21eafa118d7948c7c1ae4baa8540d8e42325dc24663c1d8 - languageName: node - linkType: hard - -"@sentry/opentelemetry@npm:9.1.0": - version: 9.1.0 - resolution: "@sentry/opentelemetry@npm:9.1.0" + "@opentelemetry/context-async-hooks": "npm:^2.0.0" + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/instrumentation": "npm:^0.203.0" + "@opentelemetry/instrumentation-amqplib": "npm:0.50.0" + "@opentelemetry/instrumentation-connect": "npm:0.47.0" + "@opentelemetry/instrumentation-dataloader": "npm:0.21.0" + "@opentelemetry/instrumentation-express": "npm:0.52.0" + "@opentelemetry/instrumentation-fs": "npm:0.23.0" + "@opentelemetry/instrumentation-generic-pool": "npm:0.47.0" + "@opentelemetry/instrumentation-graphql": "npm:0.51.0" + "@opentelemetry/instrumentation-hapi": "npm:0.50.0" + "@opentelemetry/instrumentation-http": "npm:0.203.0" + "@opentelemetry/instrumentation-ioredis": "npm:0.51.0" + "@opentelemetry/instrumentation-kafkajs": "npm:0.12.0" + "@opentelemetry/instrumentation-knex": "npm:0.48.0" + "@opentelemetry/instrumentation-koa": "npm:0.51.0" + "@opentelemetry/instrumentation-lru-memoizer": "npm:0.48.0" + "@opentelemetry/instrumentation-mongodb": "npm:0.56.0" + "@opentelemetry/instrumentation-mongoose": "npm:0.50.0" + "@opentelemetry/instrumentation-mysql": "npm:0.49.0" + "@opentelemetry/instrumentation-mysql2": "npm:0.49.0" + "@opentelemetry/instrumentation-pg": "npm:0.55.0" + "@opentelemetry/instrumentation-redis": "npm:0.51.0" + "@opentelemetry/instrumentation-tedious": "npm:0.22.0" + "@opentelemetry/instrumentation-undici": "npm:0.14.0" + "@opentelemetry/resources": "npm:^2.0.0" + "@opentelemetry/sdk-trace-base": "npm:^2.0.0" + "@opentelemetry/semantic-conventions": "npm:^1.34.0" + "@prisma/instrumentation": "npm:6.13.0" + "@sentry/core": "npm:10.6.0" + "@sentry/node-core": "npm:10.6.0" + "@sentry/opentelemetry": "npm:10.6.0" + import-in-the-middle: "npm:^1.14.2" + minimatch: "npm:^9.0.0" + checksum: 10/c3e0f88d250e61ecb64984c5ea7d01d37239cd3cd2712dd8edcf71025730a20212a4744ebc78c4f98f1aa77d7e1a55053c46b0aa212456beb9ba105e401fce2e + languageName: node + linkType: hard + +"@sentry/opentelemetry@npm:10.6.0": + version: 10.6.0 + resolution: "@sentry/opentelemetry@npm:10.6.0" dependencies: - "@sentry/core": "npm:9.1.0" + "@sentry/core": "npm:10.6.0" peerDependencies: "@opentelemetry/api": ^1.9.0 - "@opentelemetry/context-async-hooks": ^1.30.1 - "@opentelemetry/core": ^1.30.1 - "@opentelemetry/instrumentation": ^0.57.1 - "@opentelemetry/sdk-trace-base": ^1.30.1 - "@opentelemetry/semantic-conventions": ^1.28.0 - checksum: 10/a4deeaa37cde7eb848330731b7637ee8782d5432aa626a1c574a6d6cdc16576beb0dfd61dbc78dd89fb4d9b344be5e5646ec7361f2c88733d99544436283d117 + "@opentelemetry/context-async-hooks": ^1.30.1 || ^2.0.0 + "@opentelemetry/core": ^1.30.1 || ^2.0.0 + "@opentelemetry/sdk-trace-base": ^1.30.1 || ^2.0.0 + "@opentelemetry/semantic-conventions": ^1.34.0 + checksum: 10/976e8a650d7d182e5f7e52ea60aaf33b07f21b915543ca49e8a4763b708baf642e0dd74d29e9137d6e2d0f44d86816bc7c08d38818b6ea756c72f01a8f034244 languageName: node linkType: hard -"@sentry/react@npm:9.1.0": - version: 9.1.0 - resolution: "@sentry/react@npm:9.1.0" +"@sentry/react@npm:10.6.0": + version: 10.6.0 + resolution: "@sentry/react@npm:10.6.0" dependencies: - "@sentry/browser": "npm:9.1.0" - "@sentry/core": "npm:9.1.0" + "@sentry/browser": "npm:10.6.0" + "@sentry/core": "npm:10.6.0" hoist-non-react-statics: "npm:^3.3.2" peerDependencies: react: ^16.14.0 || 17.x || 18.x || 19.x - checksum: 10/7cf6401de342af271f454417251c386cad6b7e9613c3988da37e88f96fc9c0c6663303d18800fcfeda744528d8fee304c89c1ad4858bfe1392b231c130ca8966 + checksum: 10/601d213ddf9e4c7277feef8bd1af1c92581676e2aab0b983bcb8604da1fdf56e68463fc99c9984068c86588fed443410186c1ff8988bece5c13c2a0f1917bccf languageName: node linkType: hard -"@sentry/vercel-edge@npm:9.1.0": - version: 9.1.0 - resolution: "@sentry/vercel-edge@npm:9.1.0" +"@sentry/vercel-edge@npm:10.6.0": + version: 10.6.0 + resolution: "@sentry/vercel-edge@npm:10.6.0" dependencies: "@opentelemetry/api": "npm:^1.9.0" - "@sentry/core": "npm:9.1.0" - checksum: 10/b98b994d497a5c773a41f5c990a1561d4e699c08f3d526f57e21795089cd51817ab616069ecf7d8cc68eaa1113ea0b6af50dbfbfaa06c40fa1bc6e227d49c740 + "@opentelemetry/resources": "npm:^2.0.0" + "@sentry/core": "npm:10.6.0" + checksum: 10/b7f60cfb87ba46f0af5a87f338f4686ecb9874536ea4f2495f762dde19b55c4afecba92d42b953e417c10912bb768c3ef8ba4134153123d612274b6e35e55c15 languageName: node linkType: hard -"@sentry/webpack-plugin@npm:3.1.2": - version: 3.1.2 - resolution: "@sentry/webpack-plugin@npm:3.1.2" +"@sentry/webpack-plugin@npm:^4.1.0": + version: 4.1.1 + resolution: "@sentry/webpack-plugin@npm:4.1.1" dependencies: - "@sentry/bundler-plugin-core": "npm:3.1.2" + "@sentry/bundler-plugin-core": "npm:4.1.1" unplugin: "npm:1.0.1" uuid: "npm:^9.0.0" peerDependencies: webpack: ">=4.40.0" - checksum: 10/a752f91e6eac47983b054736a5664bb7b2ccc75e581ac973058945e9243625515cc7bcb96895afb0303cecc6e10e545657fc47e2e03279e4aec94d3f9034ae81 + checksum: 10/2aa20aa2b4217852fcb749a3abc7830fa86d28d5fb1d17240d499faa7f9ffa8b38b4f8935028c3710a4efdac5b06fde89247763471680a47f84cd0e72f4623c2 languageName: node linkType: hard @@ -5689,7 +5800,7 @@ __metadata: languageName: node linkType: hard -"@types/connect@npm:*": +"@types/connect@npm:*, @types/connect@npm:3.4.38": version: 3.4.38 resolution: "@types/connect@npm:3.4.38" dependencies: @@ -5698,15 +5809,6 @@ __metadata: languageName: node linkType: hard -"@types/connect@npm:3.4.36": - version: 3.4.36 - resolution: "@types/connect@npm:3.4.36" - dependencies: - "@types/node": "npm:*" - checksum: 10/4dee3d966fb527b98f0cbbdcf6977c9193fc3204ed539b7522fe5e64dfa45f9017bdda4ffb1f760062262fce7701a0ee1c2f6ce2e50af36c74d4e37052303172 - languageName: node - linkType: hard - "@types/css-mediaquery@npm:^0.1.1": version: 0.1.4 resolution: "@types/css-mediaquery@npm:0.1.4" @@ -5753,6 +5855,13 @@ __metadata: languageName: node linkType: hard +"@types/estree@npm:1.0.8": + version: 1.0.8 + resolution: "@types/estree@npm:1.0.8" + checksum: 10/25a4c16a6752538ffde2826c2cc0c6491d90e69cd6187bef4a006dd2c3c45469f049e643d7e516c515f21484dc3d48fd5c870be158a5beb72f5baf3dc43e4099 + languageName: node + linkType: hard + "@types/estree@npm:^0.0.51": version: 0.0.51 resolution: "@types/estree@npm:0.0.51" @@ -5980,12 +6089,12 @@ __metadata: languageName: node linkType: hard -"@types/mysql@npm:2.15.26": - version: 2.15.26 - resolution: "@types/mysql@npm:2.15.26" +"@types/mysql@npm:2.15.27": + version: 2.15.27 + resolution: "@types/mysql@npm:2.15.27" dependencies: "@types/node": "npm:*" - checksum: 10/8f205eeaca8f94e998ce4707354bfd02b6ca0da5b7c22289f8f6ff864d549bfb95ca7ddc2f2ebe69eb8f7e3d1f5d8a5b9a2f98aee13824dbc48051bf53a1664d + checksum: 10/a8c743501036f494bb8b26ee04ce914c9cce88955d9ba48ff77d2b5b1bc403d4d99804dbf02238c1491fa93e2242983b1492ad8c2b39755dabd68683dada9e8f languageName: node linkType: hard @@ -6034,14 +6143,14 @@ __metadata: languageName: node linkType: hard -"@types/pg@npm:8.6.1": - version: 8.6.1 - resolution: "@types/pg@npm:8.6.1" +"@types/pg@npm:8.15.4": + version: 8.15.4 + resolution: "@types/pg@npm:8.15.4" dependencies: "@types/node": "npm:*" pg-protocol: "npm:*" pg-types: "npm:^2.2.0" - checksum: 10/bf1134ea194ad9cb8bfe0aab7a532713c63bae1d95909fa45e8dc1945e44ede74f2d4c5b2cd2f9712c6b970896929e0d82480f9c9da79addf405c089b590e562 + checksum: 10/dd9203ae6732acad4892513fc99eb2bc699935a95b62e9fdbdcc6d1a90f63881b5fd89d4cac1729790ab3d0bb7c64130b144c65abef34e6bbed063ff43a739a6 languageName: node linkType: hard @@ -12090,15 +12199,15 @@ __metadata: languageName: node linkType: hard -"import-in-the-middle@npm:^1.12.0": - version: 1.13.0 - resolution: "import-in-the-middle@npm:1.13.0" +"import-in-the-middle@npm:^1.14.2": + version: 1.14.2 + resolution: "import-in-the-middle@npm:1.14.2" dependencies: acorn: "npm:^8.14.0" acorn-import-attributes: "npm:^1.9.5" cjs-module-lexer: "npm:^1.2.2" module-details-from-path: "npm:^1.0.3" - checksum: 10/bf51e7845b8cc2808b254ad5404ea505893854f1e2d1e51f4b54df29f0b1c1ab5adbc99b3c18ec206c69b19ca648cc819cb59bd37e030033c1610134d20cf60c + checksum: 10/45934b366d7f344e1cbfb6141ed93d3c2ced7021d2dd49b0e2474bab4f571e11f7f377c0f510f03e2d4ba61074d64b9f04677497d3f14106c8cc6f44c749f068 languageName: node linkType: hard @@ -13961,10 +14070,10 @@ __metadata: "@faker-js/faker": "npm:^9.9.0" "@mitodl/course-search-utils": "npm:3.3.2" "@mitodl/mitxonline-api-axios": "npm:2025.8.12" - "@mitodl/smoot-design": "npm:^6.10.0" + "@mitodl/smoot-design": "npm:^6.17.0" "@next/bundle-analyzer": "npm:^14.2.15" "@remixicon/react": "npm:^4.2.0" - "@sentry/nextjs": "npm:^9.0.0" + "@sentry/nextjs": "npm:^10.0.0" "@tanstack/react-query": "npm:^5.66" "@testing-library/jest-dom": "npm:^6.4.8" "@testing-library/react": "npm:^16.1.0" @@ -17453,6 +17562,15 @@ __metadata: languageName: node linkType: hard +"remark-supersub@npm:^1.0.0": + version: 1.0.0 + resolution: "remark-supersub@npm:1.0.0" + dependencies: + unist-util-visit: "npm:^4.0.0" + checksum: 10/43d2391eea7e19f0318a853b45cae34ef5f35c4f4c8d61496fcc32e3c33c8ce630499e63438ed8ab1b3d182a4d720bfbaede040f72202a24664384be4b80c111 + languageName: node + linkType: hard + "renderkid@npm:^3.0.0": version: 3.0.0 resolution: "renderkid@npm:3.0.0" @@ -17652,17 +17770,78 @@ __metadata: languageName: node linkType: hard -"rollup@npm:3.29.5": - version: 3.29.5 - resolution: "rollup@npm:3.29.5" - dependencies: +"rollup@npm:^4.35.0": + version: 4.48.1 + resolution: "rollup@npm:4.48.1" + dependencies: + "@rollup/rollup-android-arm-eabi": "npm:4.48.1" + "@rollup/rollup-android-arm64": "npm:4.48.1" + "@rollup/rollup-darwin-arm64": "npm:4.48.1" + "@rollup/rollup-darwin-x64": "npm:4.48.1" + "@rollup/rollup-freebsd-arm64": "npm:4.48.1" + "@rollup/rollup-freebsd-x64": "npm:4.48.1" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.48.1" + "@rollup/rollup-linux-arm-musleabihf": "npm:4.48.1" + "@rollup/rollup-linux-arm64-gnu": "npm:4.48.1" + "@rollup/rollup-linux-arm64-musl": "npm:4.48.1" + "@rollup/rollup-linux-loongarch64-gnu": "npm:4.48.1" + "@rollup/rollup-linux-ppc64-gnu": "npm:4.48.1" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.48.1" + "@rollup/rollup-linux-riscv64-musl": "npm:4.48.1" + "@rollup/rollup-linux-s390x-gnu": "npm:4.48.1" + "@rollup/rollup-linux-x64-gnu": "npm:4.48.1" + "@rollup/rollup-linux-x64-musl": "npm:4.48.1" + "@rollup/rollup-win32-arm64-msvc": "npm:4.48.1" + "@rollup/rollup-win32-ia32-msvc": "npm:4.48.1" + "@rollup/rollup-win32-x64-msvc": "npm:4.48.1" + "@types/estree": "npm:1.0.8" fsevents: "npm:~2.3.2" dependenciesMeta: + "@rollup/rollup-android-arm-eabi": + optional: true + "@rollup/rollup-android-arm64": + optional: true + "@rollup/rollup-darwin-arm64": + optional: true + "@rollup/rollup-darwin-x64": + optional: true + "@rollup/rollup-freebsd-arm64": + optional: true + "@rollup/rollup-freebsd-x64": + optional: true + "@rollup/rollup-linux-arm-gnueabihf": + optional: true + "@rollup/rollup-linux-arm-musleabihf": + optional: true + "@rollup/rollup-linux-arm64-gnu": + optional: true + "@rollup/rollup-linux-arm64-musl": + optional: true + "@rollup/rollup-linux-loongarch64-gnu": + optional: true + "@rollup/rollup-linux-ppc64-gnu": + optional: true + "@rollup/rollup-linux-riscv64-gnu": + optional: true + "@rollup/rollup-linux-riscv64-musl": + optional: true + "@rollup/rollup-linux-s390x-gnu": + optional: true + "@rollup/rollup-linux-x64-gnu": + optional: true + "@rollup/rollup-linux-x64-musl": + optional: true + "@rollup/rollup-win32-arm64-msvc": + optional: true + "@rollup/rollup-win32-ia32-msvc": + optional: true + "@rollup/rollup-win32-x64-msvc": + optional: true fsevents: optional: true bin: rollup: dist/bin/rollup - checksum: 10/5ce0e5f1d9288d4954db93993477f894eb3042ec98a7c9c19980e53b1f58296481e3dc6c2b1a2a3680b20eb6c3fe64ed97942d5ff29df658a059647c33b3593c + checksum: 10/f97ec8491894197749f35f9903eb413375cfbf001eaacbf54f2dbd66a8ae4a250ea9a94ac8ab683dfb35a5ad3e30e68d1d892ec24e24a3b6062617368d5c38ec languageName: node linkType: hard @@ -19707,6 +19886,15 @@ __metadata: languageName: node linkType: hard +"unist-util-is@npm:^5.0.0": + version: 5.2.1 + resolution: "unist-util-is@npm:5.2.1" + dependencies: + "@types/unist": "npm:^2.0.0" + checksum: 10/c10f6c07aad4f4830ffa8ea82b42a2c8d5cd36c7555e27889e5fee953040af321e4e6f4e52c4edb606604de75d7230a5f4bc7b71b8ac3e874a26ab595c2057e4 + languageName: node + linkType: hard + "unist-util-is@npm:^6.0.0": version: 6.0.0 resolution: "unist-util-is@npm:6.0.0" @@ -19762,6 +19950,16 @@ __metadata: languageName: node linkType: hard +"unist-util-visit-parents@npm:^5.1.1": + version: 5.1.3 + resolution: "unist-util-visit-parents@npm:5.1.3" + dependencies: + "@types/unist": "npm:^2.0.0" + unist-util-is: "npm:^5.0.0" + checksum: 10/5381fc57a129d478d983b988d86b72a1266d6f91fc608562b00bfa76596128d6e4d1c2b26ced64d96e55eb5d27d620081b4ee9703979bab63e1210789e781372 + languageName: node + linkType: hard + "unist-util-visit-parents@npm:^6.0.0": version: 6.0.1 resolution: "unist-util-visit-parents@npm:6.0.1" @@ -19772,6 +19970,17 @@ __metadata: languageName: node linkType: hard +"unist-util-visit@npm:^4.0.0": + version: 4.1.2 + resolution: "unist-util-visit@npm:4.1.2" + dependencies: + "@types/unist": "npm:^2.0.0" + unist-util-is: "npm:^5.0.0" + unist-util-visit-parents: "npm:^5.1.1" + checksum: 10/e3b20c6b1f5ae1b7b40bbf9be49103a342d98fad98bdf958110c20d72e5923bd3f12966b6702459bc61ab832facb5af418a79af87cefa7a8a41b892369678b13 + languageName: node + linkType: hard + "unist-util-visit@npm:^5.0.0": version: 5.0.0 resolution: "unist-util-visit@npm:5.0.0"