diff --git a/.changeset/fluffy-weeks-sleep.md b/.changeset/fluffy-weeks-sleep.md deleted file mode 100644 index 6235b335eb..0000000000 --- a/.changeset/fluffy-weeks-sleep.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"trigger.dev": patch -"@trigger.dev/core": patch ---- - -The new `triggeredVia` field is now populated in deployments via the CLI. diff --git a/.changeset/fuzzy-ghosts-admire.md b/.changeset/fuzzy-ghosts-admire.md deleted file mode 100644 index 56982d015f..0000000000 --- a/.changeset/fuzzy-ghosts-admire.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"trigger.dev": patch ---- - -fix(dev): stop max listeners exceeded warning messages when running more than 10 runs concurrently diff --git a/.changeset/ninety-cougars-remember.md b/.changeset/ninety-cougars-remember.md deleted file mode 100644 index 2d4c7e5478..0000000000 --- a/.changeset/ninety-cougars-remember.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"trigger.dev": patch ---- - -Upgrade @modelcontextprotocol/sdk to 1.24.3 diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml index d7722a46f0..3eb98e5177 100644 --- a/.github/workflows/typecheck.yml +++ b/.github/workflows/typecheck.yml @@ -35,6 +35,8 @@ jobs: - name: 🔎 Type check run: pnpm run typecheck + env: + NODE_OPTIONS: --max-old-space-size=8192 - name: 🔎 Check exports run: pnpm run check-exports diff --git a/apps/supervisor/src/index.ts b/apps/supervisor/src/index.ts index b958897ad4..0e274b3039 100644 --- a/apps/supervisor/src/index.ts +++ b/apps/supervisor/src/index.ts @@ -244,6 +244,12 @@ class ManagedSupervisor { } try { + if (!message.deployment.friendlyId) { + // mostly a type guard, deployments always exists for deployed environments + // a proper fix would be to use a discriminated union schema to differentiate between dequeued runs in dev and in deployed environments. + throw new Error("Deployment is missing"); + } + await this.workloadManager.create({ dequeuedAt: message.dequeuedAt, envId: message.environment.id, @@ -252,6 +258,8 @@ class ManagedSupervisor { machine: message.run.machine, orgId: message.organization.id, projectId: message.project.id, + deploymentFriendlyId: message.deployment.friendlyId, + deploymentVersion: message.backgroundWorker.version, runId: message.run.id, runFriendlyId: message.run.friendlyId, version: message.version, diff --git a/apps/supervisor/src/workloadManager/docker.ts b/apps/supervisor/src/workloadManager/docker.ts index 4ebbe11ca7..d6651d325a 100644 --- a/apps/supervisor/src/workloadManager/docker.ts +++ b/apps/supervisor/src/workloadManager/docker.ts @@ -72,6 +72,8 @@ export class DockerWorkloadManager implements WorkloadManager { `TRIGGER_DEQUEUED_AT_MS=${opts.dequeuedAt.getTime()}`, `TRIGGER_POD_SCHEDULED_AT_MS=${Date.now()}`, `TRIGGER_ENV_ID=${opts.envId}`, + `TRIGGER_DEPLOYMENT_ID=${opts.deploymentFriendlyId}`, + `TRIGGER_DEPLOYMENT_VERSION=${opts.deploymentVersion}`, `TRIGGER_RUN_ID=${opts.runFriendlyId}`, `TRIGGER_SNAPSHOT_ID=${opts.snapshotFriendlyId}`, `TRIGGER_SUPERVISOR_API_PROTOCOL=${this.opts.workloadApiProtocol}`, diff --git a/apps/supervisor/src/workloadManager/kubernetes.ts b/apps/supervisor/src/workloadManager/kubernetes.ts index 2042bf8b6a..96fbd7a274 100644 --- a/apps/supervisor/src/workloadManager/kubernetes.ts +++ b/apps/supervisor/src/workloadManager/kubernetes.ts @@ -123,6 +123,14 @@ export class KubernetesWorkloadManager implements WorkloadManager { name: "TRIGGER_ENV_ID", value: opts.envId, }, + { + name: "TRIGGER_DEPLOYMENT_ID", + value: opts.deploymentFriendlyId, + }, + { + name: "TRIGGER_DEPLOYMENT_VERSION", + value: opts.deploymentVersion, + }, { name: "TRIGGER_SNAPSHOT_ID", value: opts.snapshotFriendlyId, diff --git a/apps/supervisor/src/workloadManager/types.ts b/apps/supervisor/src/workloadManager/types.ts index 64573fb3b9..90b6195779 100644 --- a/apps/supervisor/src/workloadManager/types.ts +++ b/apps/supervisor/src/workloadManager/types.ts @@ -29,6 +29,8 @@ export interface WorkloadManagerCreateOptions { envType: EnvironmentType; orgId: string; projectId: string; + deploymentFriendlyId: string; + deploymentVersion: string; runId: string; runFriendlyId: string; snapshotId: string; diff --git a/apps/webapp/app/components/BlankStatePanels.tsx b/apps/webapp/app/components/BlankStatePanels.tsx index 380a6d990c..d0e798f168 100644 --- a/apps/webapp/app/components/BlankStatePanels.tsx +++ b/apps/webapp/app/components/BlankStatePanels.tsx @@ -52,6 +52,13 @@ import { } from "./SetupCommands"; import { StepContentContainer } from "./StepContentContainer"; import { V4Badge } from "./V4Badge"; +import { + ClientTabs, + ClientTabsContent, + ClientTabsList, + ClientTabsTrigger, +} from "./primitives/ClientTabs"; +import { GitHubSettingsPanel } from "~/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.github"; export function HasNoTasksDev() { return ( @@ -93,62 +100,7 @@ export function HasNoTasksDev() { } export function HasNoTasksDeployed({ environment }: { environment: MinimumEnvironment }) { - return ( - -
-
-
- - Deploy your tasks to {environmentFullTitle(environment)} -
-
- - } - content="Deploy docs" - /> - - } - content="Troubleshooting docs" - /> - -
-
- - - - This will deploy your tasks to the {environmentFullTitle(environment)} environment. Read - the full guide. - - - - - - - Read the GitHub Actions guide to - get started. - - - - - This page will automatically refresh when your tasks are deployed. - -
-
- ); + return ; } export function SchedulesNoPossibleTaskPanel() { @@ -266,45 +218,7 @@ export function TestHasNoTasks() { } export function DeploymentsNone() { - const organization = useOrganization(); - const project = useProject(); - const environment = useEnvironment(); - - return ( - - - There are several ways to deploy your tasks. You can use the CLI or a Continuous Integration - service like GitHub Actions. Make sure you{" "} - - set your environment variables - {" "} - first. - -
- - Deploy with the CLI - - - Deploy with GitHub actions - -
-
- ); + return ; } export function DeploymentsNoneDev() { @@ -313,46 +227,52 @@ export function DeploymentsNoneDev() { const environment = useEnvironment(); return ( -
- - + <> +
+
+ + Deploy your tasks +
+
+ + } + content="Deploy docs" + /> + + } + content="Troubleshooting docs" + /> + +
+
+ + + This is the Development environment. When you're ready to deploy your tasks, switch to a different environment. - - There are several ways to deploy your tasks. You can use the CLI or a Continuous - Integration service like GitHub Actions. Make sure you{" "} - - set your environment variables - {" "} - first. - -
- - Deploy with the CLI - - - Deploy with GitHub actions - -
-
- -
+ + + ); } @@ -670,3 +590,99 @@ export function BulkActionsNone() { ); } + +function DeploymentOnboardingSteps() { + const environment = useEnvironment(); + const organization = useOrganization(); + const project = useProject(); + + return ( + +
+
+ + Deploy your tasks to {environmentFullTitle(environment)} +
+
+ + } + content="Deploy docs" + /> + + } + content="Troubleshooting docs" + /> + +
+
+ + + + GitHub + + + Manual + + + GitHub Actions + + + + + + + Deploy automatically with every push. Read the{" "} + full guide. + +
+ +
+
+
+ + + + + This will deploy your tasks to the {environmentFullTitle(environment)} environment. + Read the full guide. + + + + + + + + + Read the GitHub Actions guide to + get started. + + + +
+ + + + This page will automatically refresh when your tasks are deployed. + +
+ ); +} diff --git a/apps/webapp/app/components/primitives/Buttons.tsx b/apps/webapp/app/components/primitives/Buttons.tsx index 67ba3c0924..c2845f1040 100644 --- a/apps/webapp/app/components/primitives/Buttons.tsx +++ b/apps/webapp/app/components/primitives/Buttons.tsx @@ -331,7 +331,7 @@ export const Button = forwardRef( type LinkPropsType = Pick< LinkProps, "to" | "target" | "onClick" | "onMouseDown" | "onMouseEnter" | "onMouseLeave" | "download" -> & { disabled?: boolean } & React.ComponentProps; +> & { disabled?: boolean; replace?: boolean } & React.ComponentProps; export const LinkButton = ({ to, onClick, @@ -340,6 +340,7 @@ export const LinkButton = ({ onMouseLeave, download, disabled = false, + replace, ...props }: LinkPropsType) => { const innerRef = useRef(null); @@ -387,6 +388,7 @@ export const LinkButton = ({ (undefined); + +function useClientTabsContext() { + return React.useContext(ClientTabsContext); +} const ClientTabs = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->((props, ref) => ); +>(({ onValueChange, value: valueProp, defaultValue, ...props }, ref) => { + const [value, setValue] = React.useState(valueProp ?? defaultValue); + + React.useEffect(() => { + if (valueProp !== undefined) { + setValue(valueProp); + } + }, [valueProp]); + + const handleValueChange = React.useCallback( + (nextValue: string) => { + if (valueProp === undefined) { + setValue(nextValue); + } + onValueChange?.(nextValue); + }, + [onValueChange, valueProp] + ); + + const controlledProps = + valueProp !== undefined + ? { value: valueProp } + : defaultValue !== undefined + ? { defaultValue } + : {}; + + const contextValue = React.useMemo(() => ({ value }), [value]); + + return ( + + + + ); +}); ClientTabs.displayName = TabsPrimitive.Root.displayName; const ClientTabsList = React.forwardRef< React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); + React.ComponentPropsWithoutRef & { + variant?: Variants; + } +>(({ className, variant = "pipe-divider", ...props }, ref) => { + const variantClassName = (() => { + switch (variant) { + case "segmented": + return "relative flex h-10 w-full items-center rounded bg-charcoal-700/50 p-1"; + case "underline": + return "flex gap-x-6 border-b border-grid-bright"; + default: + return "inline-flex items-center justify-center transition duration-100"; + } + })(); + + return ; +}); ClientTabsList.displayName = TabsPrimitive.List.displayName; const ClientTabsTrigger = React.forwardRef< React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); + React.ComponentPropsWithoutRef & { + variant?: Variants; + layoutId?: string; + } +>(({ className, variant = "pipe-divider", layoutId, children, ...props }, ref) => { + const context = useClientTabsContext(); + const activeValue = context?.value; + const isActive = activeValue === props.value; + + if (variant === "segmented") { + return ( + +
+ + {children} + +
+ {isActive ? ( + layoutId ? ( + + ) : ( +
+ ) + ) : null} + + ); + } + + if (variant === "underline") { + return ( + + + {children} + + {layoutId ? ( + isActive ? ( + + ) : ( +
+ ) + ) : isActive ? ( +
+ ) : ( +
+ )} + + ); + } + + return ( + + {children} + + ); +}); ClientTabsTrigger.displayName = TabsPrimitive.Trigger.displayName; const ClientTabsContent = React.forwardRef< @@ -61,39 +205,7 @@ export type TabsProps = { currentValue: string; className?: string; layoutId: string; + variant?: Variants; }; -export function ClientTabsWithUnderline({ className, tabs, currentValue, layoutId }: TabsProps) { - return ( - - {tabs.map((tab, index) => { - const isActive = currentValue === tab.value; - return ( - - - {tab.label} - - {isActive ? ( - - ) : ( -
- )} - - ); - })} - - ); -} - -export { ClientTabs, ClientTabsList, ClientTabsTrigger, ClientTabsContent }; +export { ClientTabs, ClientTabsContent, ClientTabsList, ClientTabsTrigger }; diff --git a/apps/webapp/app/components/primitives/FormButtons.tsx b/apps/webapp/app/components/primitives/FormButtons.tsx index e7d6db75d2..d077227a2d 100644 --- a/apps/webapp/app/components/primitives/FormButtons.tsx +++ b/apps/webapp/app/components/primitives/FormButtons.tsx @@ -12,11 +12,11 @@ export function FormButtons({ return (
- {cancelButton ? cancelButton :
} {confirmButton} + {confirmButton} {cancelButton ? cancelButton :
}
); } diff --git a/apps/webapp/app/components/primitives/Tabs.tsx b/apps/webapp/app/components/primitives/Tabs.tsx index e3d3183d94..cbc5cf4275 100644 --- a/apps/webapp/app/components/primitives/Tabs.tsx +++ b/apps/webapp/app/components/primitives/Tabs.tsx @@ -1,10 +1,12 @@ import { NavLink } from "@remix-run/react"; import { motion } from "framer-motion"; -import { ReactNode, useRef } from "react"; -import { ShortcutDefinition, useShortcutKeys } from "~/hooks/useShortcutKeys"; +import { type ReactNode, useRef } from "react"; +import { type ShortcutDefinition, useShortcutKeys } from "~/hooks/useShortcutKeys"; import { cn } from "~/utils/cn"; import { ShortcutKey } from "./ShortcutKey"; +export type Variants = "underline" | "pipe-divider" | "segmented"; + export type TabsProps = { tabs: { label: string; @@ -12,13 +14,14 @@ export type TabsProps = { }[]; className?: string; layoutId: string; + variant?: Variants; }; -export function Tabs({ tabs, className, layoutId }: TabsProps) { +export function Tabs({ tabs, className, layoutId, variant = "underline" }: TabsProps) { return ( - + {tabs.map((tab, index) => ( - + {tab.label} ))} @@ -26,23 +29,107 @@ export function Tabs({ tabs, className, layoutId }: TabsProps) { ); } -export function TabContainer({ children, className }: { children: ReactNode; className?: string }) { - return ( -
- {children} -
- ); +export function TabContainer({ + children, + className, + variant = "underline", +}: { + children: ReactNode; + className?: string; + variant?: Variants; +}) { + if (variant === "segmented") { + return ( +
+ {children} +
+ ); + } + + if (variant === "underline") { + return ( +
{children}
+ ); + } + + return
{children}
; } export function TabLink({ to, children, layoutId, + variant = "underline", }: { to: string; children: ReactNode; layoutId: string; + variant?: Variants; }) { + if (variant === "segmented") { + return ( + + {({ isActive, isPending }) => { + const active = isActive || isPending; + return ( + <> +
+ + {children} + +
+ {active && ( + + )} + + ); + }} +
+ ); + } + + if (variant === "pipe-divider") { + return ( + + {({ isActive, isPending }) => { + const active = isActive || isPending; + return ( + + {children} + + ); + }} + + ); + } + + // underline variant (default) return ( {({ isActive, isPending }) => { @@ -51,13 +138,19 @@ export function TabLink({ {children} {isActive || isPending ? ( - + ) : (
)} @@ -106,17 +199,18 @@ export function TabButton({ <>
{props.children} {shortcut && }
{isActive ? ( - + ) : (
)} diff --git a/apps/webapp/app/components/primitives/TreeView/TreeView.tsx b/apps/webapp/app/components/primitives/TreeView/TreeView.tsx index 7a2e368bec..bb9ca4c462 100644 --- a/apps/webapp/app/components/primitives/TreeView/TreeView.tsx +++ b/apps/webapp/app/components/primitives/TreeView/TreeView.tsx @@ -423,6 +423,10 @@ export function useTree({ } case "Left": case "ArrowLeft": { + if (e.metaKey) { + return; + } + e.preventDefault(); const selected = selectedIdFromState(state.nodes); diff --git a/apps/webapp/app/components/runs/v3/TaskRunsTable.tsx b/apps/webapp/app/components/runs/v3/TaskRunsTable.tsx index c0ae8d2f62..14cdf5a67b 100644 --- a/apps/webapp/app/components/runs/v3/TaskRunsTable.tsx +++ b/apps/webapp/app/components/runs/v3/TaskRunsTable.tsx @@ -56,6 +56,7 @@ import { TaskRunStatusCombo, } from "./TaskRunStatus"; import { useOptimisticLocation } from "~/hooks/useOptimisticLocation"; +import { useSearchParams } from "~/hooks/useSearchParam"; type RunsTableProps = { total: number; @@ -63,9 +64,11 @@ type RunsTableProps = { filters: NextRunListAppliedFilters; showJob?: boolean; runs: NextRunListItem[]; + rootOnlyDefault?: boolean; isLoading?: boolean; allowSelection?: boolean; variant?: TableVariant; + disableAdjacentRows?: boolean; }; export function TaskRunsTable({ @@ -73,6 +76,8 @@ export function TaskRunsTable({ hasFilters, filters, runs, + rootOnlyDefault, + disableAdjacentRows = false, isLoading = false, allowSelection = false, variant = "dimmed", @@ -82,8 +87,12 @@ export function TaskRunsTable({ const checkboxes = useRef<(HTMLInputElement | null)[]>([]); const { has, hasAll, select, deselect, toggle } = useSelectedItems(allowSelection); const { isManagedCloud } = useFeatures(); + const { value } = useSearchParams(); const location = useOptimisticLocation(); - const tableStateParam = encodeURIComponent(location.search ? `${location.search}&rt=1` : "rt=1"); + const rootOnly = value("rootOnly") ? `` : `rootOnly=${rootOnlyDefault}`; + const search = rootOnly ? `${rootOnly}&${location.search}` : location.search; + /** TableState has to be encoded as a separate URI component, so it's merged under one, 'tableState' param */ + const tableStateParam = disableAdjacentRows ? '' : encodeURIComponent(search); const showCompute = isManagedCloud; diff --git a/apps/webapp/app/presenters/v3/GitHubSettingsPresenter.server.ts b/apps/webapp/app/presenters/v3/GitHubSettingsPresenter.server.ts new file mode 100644 index 0000000000..c3f715deff --- /dev/null +++ b/apps/webapp/app/presenters/v3/GitHubSettingsPresenter.server.ts @@ -0,0 +1,137 @@ +import { type PrismaClient } from "@trigger.dev/database"; +import { err, fromPromise, ok, ResultAsync } from "neverthrow"; +import { env } from "~/env.server"; +import { BranchTrackingConfigSchema } from "~/v3/github"; +import { BasePresenter } from "./basePresenter.server"; + +type GitHubSettingsOptions = { + projectId: string; + organizationId: string; +}; + +export class GitHubSettingsPresenter extends BasePresenter { + public call({ projectId, organizationId }: GitHubSettingsOptions) { + const githubAppEnabled = env.GITHUB_APP_ENABLED === "1"; + + if (!githubAppEnabled) { + return ok({ + enabled: false, + connectedRepository: undefined, + installations: undefined, + isPreviewEnvironmentEnabled: undefined, + }); + } + + const findConnectedGithubRepository = () => + fromPromise( + (this._replica as PrismaClient).connectedGithubRepository.findFirst({ + where: { + projectId, + repository: { + installation: { + deletedAt: null, + suspendedAt: null, + }, + }, + }, + select: { + branchTracking: true, + previewDeploymentsEnabled: true, + createdAt: true, + repository: { + select: { + id: true, + name: true, + fullName: true, + htmlUrl: true, + private: true, + }, + }, + }, + }), + (error) => ({ + type: "other" as const, + cause: error, + }) + ).map((connectedGithubRepository) => { + if (!connectedGithubRepository) { + return undefined; + } + + const branchTrackingOrFailure = BranchTrackingConfigSchema.safeParse( + connectedGithubRepository.branchTracking + ); + const branchTracking = branchTrackingOrFailure.success + ? branchTrackingOrFailure.data + : undefined; + + return { + ...connectedGithubRepository, + branchTracking, + }; + }); + + const listGithubAppInstallations = () => + fromPromise( + (this._replica as PrismaClient).githubAppInstallation.findMany({ + where: { + organizationId, + deletedAt: null, + suspendedAt: null, + }, + select: { + id: true, + accountHandle: true, + targetType: true, + appInstallationId: true, + repositories: { + select: { + id: true, + name: true, + fullName: true, + htmlUrl: true, + private: true, + }, + take: 200, + }, + }, + take: 20, + orderBy: { + createdAt: "desc", + }, + }), + (error) => ({ + type: "other" as const, + cause: error, + }) + ); + + const isPreviewEnvironmentEnabled = () => + fromPromise( + (this._replica as PrismaClient).runtimeEnvironment.findFirst({ + select: { + id: true, + }, + where: { + projectId: projectId, + slug: "preview", + }, + }), + (error) => ({ + type: "other" as const, + cause: error, + }) + ).map((previewEnvironment) => previewEnvironment !== null); + + return ResultAsync.combine([ + isPreviewEnvironmentEnabled(), + findConnectedGithubRepository(), + listGithubAppInstallations(), + ]).map(([isPreviewEnvironmentEnabled, connectedGithubRepository, githubAppInstallations]) => ({ + enabled: true, + connectedRepository: connectedGithubRepository, + installations: githubAppInstallations, + isPreviewEnvironmentEnabled, + })); + } +} diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments/route.tsx index 6f161eea98..9b2b78f98b 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments/route.tsx @@ -359,11 +359,11 @@ export default function Page() {
) : environment.type === "DEVELOPMENT" ? ( - + ) : ( - + )} diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx index 5253e56f2e..840a4376e2 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx @@ -23,7 +23,7 @@ import { } from "@trigger.dev/core/v3"; import type { RuntimeEnvironmentType } from "@trigger.dev/database"; import { motion } from "framer-motion"; -import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { useCallback, useEffect, useRef, useState } from "react"; import { useHotkeys } from "react-hotkeys-hook"; import { redirect } from "remix-typedjson"; import { MoveToTopIcon } from "~/assets/icons/MoveToTopIcon"; @@ -140,10 +140,10 @@ const resizableSettings = { type TraceEvent = NonNullable["trace"]>["events"][0]; type RunsListNavigation = { - runs: Array<{ friendlyId: string }>; + runs: Array<{ friendlyId: string; spanId: string }>; pagination: { next?: string; previous?: string }; - prevPageLastRun?: { friendlyId: string; cursor: string }; - nextPageFirstRun?: { friendlyId: string; cursor: string }; + prevPageLastRun?: { friendlyId: string; spanId: string; cursor: string }; + nextPageFirstRun?: { friendlyId: string; spanId: string; cursor: string }; }; async function getRunsListFromTableState({ @@ -204,6 +204,7 @@ async function getRunsListFromTableState({ if (prevPageResult.runs.length > 0) { runsList.prevPageLastRun = { friendlyId: prevPageResult.runs[0].friendlyId, + spanId: prevPageResult.runs[0].spanId, cursor: currentPageResult.pagination.previous, }; } @@ -222,6 +223,7 @@ async function getRunsListFromTableState({ if (nextPageResult.runs.length > 0) { runsList.nextPageFirstRun = { friendlyId: nextPageResult.runs[0].friendlyId, + spanId: nextPageResult.runs[0].spanId, cursor: currentPageResult.pagination.next, }; } @@ -296,7 +298,7 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => { type LoaderData = SerializeFrom; export default function Page() { - const { run, trace, resizable, maximumLiveReloadingSetting, runsList } = useLoaderData(); + const { run, trace, maximumLiveReloadingSetting, runsList } = useLoaderData(); const organization = useOrganization(); const project = useProject(); const environment = useEnvironment(); @@ -308,8 +310,10 @@ export default function Page() { const tableState = decodeURIComponent(value("tableState") ?? ""); const tableStateSearchParams = new URLSearchParams(tableState); const filters = getRunFiltersFromSearchParams(tableStateSearchParams); + const tabParam = value("tab") ?? undefined; + const spanParam = value("span") ?? undefined; - const [previousRunPath, nextRunPath] = useAdjacentRunPaths({organization, project, environment, tableState, run, runsList}); + const [previousRunPath, nextRunPath] = useAdjacentRunPaths({organization, project, environment, tableState, run, runsList, tabParam, useSpan: !!spanParam}); return ( <> @@ -320,7 +324,7 @@ export default function Page() { text: "Runs", }} title={<> - + {tableState && (
@@ -940,7 +944,6 @@ function TimelineView({ scale, rootSpanStatus, rootStartedAt, - parentRef, timelineScrollRef, virtualizer, events, @@ -1127,7 +1130,8 @@ function TimelineView({ "-ml-[0.5px] h-[0.5625rem] w-px rounded-none", eventBackgroundClassName(node.data) )} - layoutId={`${node.id}-${event.name}`} + layoutId={node.data.isPartial ? `${node.id}-${event.name}` : undefined} + animate={!node.data.isPartial ? false : undefined} /> )} @@ -1145,7 +1149,8 @@ function TimelineView({ "-ml-[0.1562rem] size-[0.3125rem] rounded-full border bg-background-bright", eventBorderClassName(node.data) )} - layoutId={`${node.id}-${event.name}`} + layoutId={node.data.isPartial ? `${node.id}-${event.name}` : undefined} + animate={!node.data.isPartial ? false : undefined} /> )} @@ -1164,7 +1169,8 @@ function TimelineView({ > ) : null} @@ -1201,7 +1207,8 @@ function TimelineView({ "-ml-0.5 size-3 rounded-full border-2 border-background-bright", eventBackgroundClassName(node.data) )} - layoutId={node.id} + layoutId={node.data.isPartial ? node.id : undefined} + animate={!node.data.isPartial ? false : undefined} /> )} @@ -1444,7 +1451,8 @@ function SpanWithDuration({ fadeLeft ? "rounded-r-sm bg-gradient-to-r from-black/50 to-transparent" : "rounded-sm" )} style={{ backgroundSize: "20px 100%", backgroundRepeat: "no-repeat" }} - layoutId={node.id} + layoutId={node.data.isPartial ? node.id : undefined} + animate={!node.data.isPartial ? false : undefined} > {node.data.isPartial && (
{formatDurationMilliseconds(props.durationMs, { style: "short", @@ -1543,12 +1553,11 @@ function KeyboardShortcuts({ expandAllBelowDepth, collapseAllBelowDepth, toggleExpandLevel, - setShowDurations, }: { expandAllBelowDepth: (depth: number) => void; collapseAllBelowDepth: (depth: number) => void; toggleExpandLevel: (depth: number) => void; - setShowDurations: (show: (show: boolean) => boolean) => void; + setShowDurations?: (show: (show: boolean) => boolean) => void; }) { return ( <> @@ -1666,63 +1675,77 @@ function useAdjacentRunPaths({ tableState, run, runsList, + tabParam, + useSpan }: { organization: { slug: string }; project: { slug: string }; environment: { slug: string }; tableState: string; - run: { friendlyId: string }; + run: { friendlyId: string, spanId: string }; runsList: RunsListNavigation | null; + tabParam?: string; + useSpan?: boolean; }): [string | null, string | null] { - return useMemo(() => { - if (!runsList || runsList.runs.length === 0) { - return [null, null]; - } - - const currentIndex = runsList.runs.findIndex((r) => r.friendlyId === run.friendlyId); - - if (currentIndex === -1) { - return [null, null]; - } + if (!runsList || runsList.runs.length === 0) { + return [null, null]; + } - // Determine previous run: use prevPageLastRun if at first position, otherwise use previous run in list - let previousRun: { friendlyId: string } | null = null; - const previousRunTableState = new URLSearchParams(tableState); - if (currentIndex > 0) { - previousRun = runsList.runs[currentIndex - 1]; - } else if (runsList.prevPageLastRun) { - previousRun = runsList.prevPageLastRun; - // Update tableState with the new cursor for the previous page - previousRunTableState.set("cursor", runsList.prevPageLastRun.cursor); - previousRunTableState.set("direction", "backward"); - } + const currentIndex = runsList.runs.findIndex((r) => r.friendlyId === run.friendlyId); + + if (currentIndex === -1) { + return [null, null]; + } - // Determine next run: use nextPageFirstRun if at last position, otherwise use next run in list - let nextRun: { friendlyId: string } | null = null; - const nextRunTableState = new URLSearchParams(tableState); - if (currentIndex < runsList.runs.length - 1) { - nextRun = runsList.runs[currentIndex + 1]; - } else if (runsList.nextPageFirstRun) { - nextRun = runsList.nextPageFirstRun; - // Update tableState with the new cursor for the next page - nextRunTableState.set("cursor", runsList.nextPageFirstRun.cursor); - nextRunTableState.set("direction", "forward"); - } + // Determine previous run: use prevPageLastRun if at first position, otherwise use previous run in list + let previousRun: { friendlyId: string; spanId: string } | null = null; + const previousRunTableState = new URLSearchParams(tableState); + if (currentIndex > 0) { + previousRun = runsList.runs[currentIndex - 1]; + } else if (runsList.prevPageLastRun) { + previousRun = runsList.prevPageLastRun; + // Update tableState with the new cursor for the previous page + previousRunTableState.set("cursor", runsList.prevPageLastRun.cursor); + previousRunTableState.set("direction", "backward"); + } - const previousURLSearchParams = new URLSearchParams(); - previousURLSearchParams.set("tableState", previousRunTableState.toString()); - const previousRunPath = previousRun - ? v3RunPath(organization, project, environment, previousRun, previousURLSearchParams) - : null; + // Determine next run: use nextPageFirstRun if at last position, otherwise use next run in list + let nextRun: { friendlyId: string; spanId: string } | null = null; + const nextRunTableState = new URLSearchParams(tableState); + if (currentIndex < runsList.runs.length - 1) { + nextRun = runsList.runs[currentIndex + 1]; + } else if (runsList.nextPageFirstRun) { + nextRun = runsList.nextPageFirstRun; + // Update tableState with the new cursor for the next page + nextRunTableState.set("cursor", runsList.nextPageFirstRun.cursor); + nextRunTableState.set("direction", "forward"); + } - const nextURLSearchParams = new URLSearchParams(); - nextURLSearchParams.set("tableState", nextRunTableState.toString()); - const nextRunPath = nextRun - ? v3RunPath(organization, project, environment, nextRun, nextURLSearchParams) - : null; + const previousURLSearchParams = new URLSearchParams(); + previousURLSearchParams.set("tableState", previousRunTableState.toString()); + if (previousRun && useSpan) { + previousURLSearchParams.set("span", previousRun.spanId); + } + if (tabParam && useSpan) { + previousURLSearchParams.set("tab", tabParam); + } + const previousRunPath = previousRun + ? v3RunPath(organization, project, environment, previousRun, previousURLSearchParams) + : null; + + const nextURLSearchParams = new URLSearchParams(); + nextURLSearchParams.set("tableState", nextRunTableState.toString()); + if (nextRun && useSpan) { + nextURLSearchParams.set("span", nextRun.spanId); + } + if (tabParam && useSpan) { + nextURLSearchParams.set("tab", tabParam); + } + const nextRunPath = nextRun + ? v3RunPath(organization, project, environment, nextRun, nextURLSearchParams) + : null; - return [previousRunPath, nextRunPath]; - }, [organization, project, environment, tableState, run.friendlyId, runsList]); + return [previousRunPath, nextRunPath]; } @@ -1741,6 +1764,7 @@ function PreviousRunButton({ to }: { to: string | null }) { shortcut={{ key: "[" }} tooltip="Previous Run" disabled={!to} + replace />
); @@ -1761,6 +1785,7 @@ function NextRunButton({ to }: { to: string | null }) { shortcut={{ key: "]" }} tooltip="Next Run" disabled={!to} + replace />
); diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs._index/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs._index/route.tsx index 8c41f0ceac..9f8cf278be 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs._index/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs._index/route.tsx @@ -55,6 +55,7 @@ import { v3CreateBulkActionPath, v3ProjectPath, v3TestPath, + v3TestTaskPath, } from "~/utils/pathBuilder"; import { ListPagination } from "../../components/ListPagination"; import { CreateBulkActionInspector } from "../resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.bulkaction"; @@ -235,7 +236,13 @@ function RunsList({ list.possibleTasks.length === 0 ? ( ) : ( - + t.slug === list.filters.tasks[0]) + : undefined + } + /> ) ) : (
@@ -291,6 +298,7 @@ function RunsList({ runs={list.runs} isLoading={isLoading} allowSelection + rootOnlyDefault={rootOnlyDefault} />
)} @@ -339,7 +347,7 @@ function CreateFirstTaskInstructions() { ); } -function RunTaskInstructions() { +function RunTaskInstructions({ task }: { task?: { slug: string } }) { const organization = useOrganization(); const project = useProject(); const environment = useEnvironment(); @@ -352,7 +360,11 @@ function RunTaskInstructions() { Perform a test run with a payload directly from the dashboard.
diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.settings/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.settings/route.tsx index 06b6f6ad8a..66ea64cb36 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.settings/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.settings/route.tsx @@ -1,35 +1,18 @@ import { conform, useForm } from "@conform-to/react"; import { parse } from "@conform-to/zod"; -import { - CheckCircleIcon, - ExclamationTriangleIcon, - FolderIcon, - TrashIcon, - LockClosedIcon, - PlusIcon, -} from "@heroicons/react/20/solid"; -import { - Form, - type MetaFunction, - useActionData, - useNavigation, - useNavigate, - useSearchParams, -} from "@remix-run/react"; +import { ExclamationTriangleIcon, FolderIcon, TrashIcon } from "@heroicons/react/20/solid"; +import { Form, type MetaFunction, useActionData, useNavigation } from "@remix-run/react"; import { type ActionFunction, type LoaderFunctionArgs, json } from "@remix-run/server-runtime"; import { typedjson, useTypedLoaderData } from "remix-typedjson"; import { z } from "zod"; import { AdminDebugTooltip } from "~/components/admin/debugTooltip"; import { InlineCode } from "~/components/code/InlineCode"; -import { Dialog, DialogContent, DialogHeader, DialogTrigger } from "~/components/primitives/Dialog"; -import { DialogClose } from "@radix-ui/react-dialog"; -import { OctoKitty } from "~/components/GitHubLoginButton"; import { MainHorizontallyCenteredContainer, PageBody, PageContainer, } from "~/components/layout/AppLayout"; -import { Button, LinkButton } from "~/components/primitives/Buttons"; +import { Button } from "~/components/primitives/Buttons"; import { CheckboxWithLabel } from "~/components/primitives/Checkbox"; import { ClipboardField } from "~/components/primitives/ClipboardField"; import { Fieldset } from "~/components/primitives/Fieldset"; @@ -55,32 +38,12 @@ import { import { ProjectSettingsService } from "~/services/projectSettings.server"; import { logger } from "~/services/logger.server"; import { requireUserId } from "~/services/session.server"; -import { - organizationPath, - v3ProjectPath, - githubAppInstallPath, - EnvironmentParamSchema, - v3ProjectSettingsPath, - docsPath, - v3BillingPath, -} from "~/utils/pathBuilder"; +import { organizationPath, v3ProjectPath, EnvironmentParamSchema, v3BillingPath } from "~/utils/pathBuilder"; import React, { useEffect, useState } from "react"; -import { Select, SelectItem } from "~/components/primitives/Select"; -import { Switch } from "~/components/primitives/Switch"; -import { type BranchTrackingConfig } from "~/v3/github"; -import { - EnvironmentIcon, - environmentFullTitle, - environmentTextClassName, -} from "~/components/environments/EnvironmentLabel"; -import { GitBranchIcon } from "lucide-react"; import { useEnvironment } from "~/hooks/useEnvironment"; -import { DateTime } from "~/components/primitives/DateTime"; -import { TextLink } from "~/components/primitives/TextLink"; -import { cn } from "~/utils/cn"; import { ProjectSettingsPresenter } from "~/services/projectSettingsPresenter.server"; import { type BuildSettings } from "~/v3/buildSettings"; -import { InfoIconTooltip } from "~/components/primitives/Tooltip"; +import { GitHubSettingsPanel } from "../resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.github"; export const meta: MetaFunction = () => { return [ @@ -128,29 +91,10 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => { return typedjson({ githubAppEnabled: gitHubApp.enabled, - githubAppInstallations: gitHubApp.installations, - connectedGithubRepository: gitHubApp.connectedRepository, - isPreviewEnvironmentEnabled: gitHubApp.isPreviewEnvironmentEnabled, buildSettings, }); }; -const ConnectGitHubRepoFormSchema = z.object({ - action: z.literal("connect-repo"), - installationId: z.string(), - repositoryId: z.string(), -}); - -const UpdateGitSettingsFormSchema = z.object({ - action: z.literal("update-git-settings"), - productionBranch: z.string().trim().optional(), - stagingBranch: z.string().trim().optional(), - previewDeploymentsEnabled: z - .string() - .optional() - .transform((val) => val === "on"), -}); - const UpdateBuildSettingsFormSchema = z.object({ action: z.literal("update-build-settings"), triggerConfigFilePath: z @@ -220,12 +164,7 @@ export function createSchema( } }), }), - ConnectGitHubRepoFormSchema, - UpdateGitSettingsFormSchema, UpdateBuildSettingsFormSchema, - z.object({ - action: z.literal("disconnect-repo"), - }), ]); } @@ -260,7 +199,7 @@ export const action: ActionFunction = async ({ request, params }) => { return json({ errors: { body: membershipResultOrFail.error.type } }, { status: 404 }); } - const { projectId, organizationId } = membershipResultOrFail.value; + const { projectId } = membershipResultOrFail.value; switch (submission.value.action) { case "rename": { @@ -316,101 +255,6 @@ export const action: ActionFunction = async ({ request, params }) => { "Project deleted" ); } - case "disconnect-repo": { - const resultOrFail = await projectSettingsService.disconnectGitHubRepo(projectId); - - if (resultOrFail.isErr()) { - switch (resultOrFail.error.type) { - case "other": - default: { - resultOrFail.error.type satisfies "other"; - - logger.error("Failed to disconnect GitHub repository", { - error: resultOrFail.error, - }); - return redirectBackWithErrorMessage(request, "Failed to disconnect GitHub repository"); - } - } - } - - return redirectBackWithSuccessMessage(request, "GitHub repository disconnected successfully"); - } - case "update-git-settings": { - const { productionBranch, stagingBranch, previewDeploymentsEnabled } = submission.value; - - const resultOrFail = await projectSettingsService.updateGitSettings( - projectId, - productionBranch, - stagingBranch, - previewDeploymentsEnabled - ); - - if (resultOrFail.isErr()) { - switch (resultOrFail.error.type) { - case "github_app_not_enabled": { - return redirectBackWithErrorMessage(request, "GitHub app is not enabled"); - } - case "connected_gh_repository_not_found": { - return redirectBackWithErrorMessage(request, "Connected GitHub repository not found"); - } - case "production_tracking_branch_not_found": { - return redirectBackWithErrorMessage(request, "Production tracking branch not found"); - } - case "staging_tracking_branch_not_found": { - return redirectBackWithErrorMessage(request, "Staging tracking branch not found"); - } - case "other": - default: { - resultOrFail.error.type satisfies "other"; - - logger.error("Failed to update Git settings", { - error: resultOrFail.error, - }); - return redirectBackWithErrorMessage(request, "Failed to update Git settings"); - } - } - } - - return redirectBackWithSuccessMessage(request, "Git settings updated successfully"); - } - case "connect-repo": { - const { repositoryId, installationId } = submission.value; - - const resultOrFail = await projectSettingsService.connectGitHubRepo( - projectId, - organizationId, - repositoryId, - installationId - ); - - if (resultOrFail.isErr()) { - switch (resultOrFail.error.type) { - case "gh_repository_not_found": { - return redirectBackWithErrorMessage(request, "GitHub repository not found"); - } - case "project_already_has_connected_repository": { - return redirectBackWithErrorMessage( - request, - "Project already has a connected repository" - ); - } - case "other": - default: { - resultOrFail.error.type satisfies "other"; - - logger.error("Failed to connect GitHub repository", { - error: resultOrFail.error, - }); - return redirectBackWithErrorMessage(request, "Failed to connect GitHub repository"); - } - } - } - - return json({ - ...submission, - success: true, - }); - } case "update-build-settings": { const { installCommand, preBuildCommand, triggerConfigFilePath, useNativeBuildServer } = submission.value; @@ -446,13 +290,7 @@ export const action: ActionFunction = async ({ request, params }) => { }; export default function Page() { - const { - githubAppInstallations, - connectedGithubRepository, - githubAppEnabled, - buildSettings, - isPreviewEnvironmentEnabled, - } = useTypedLoaderData(); + const { githubAppEnabled, buildSettings } = useTypedLoaderData(); const project = useProject(); const organization = useOrganization(); const environment = useEnvironment(); @@ -578,19 +416,12 @@ export default function Page() {
Git settings
- {connectedGithubRepository ? ( - - ) : ( - - )} +
@@ -650,489 +481,6 @@ export default function Page() { ); } -type GitHubRepository = { - id: string; - name: string; - fullName: string; - private: boolean; - htmlUrl: string; -}; - -type GitHubAppInstallation = { - id: string; - appInstallationId: bigint; - targetType: string; - accountHandle: string; - repositories: GitHubRepository[]; -}; - -function ConnectGitHubRepoModal({ - gitHubAppInstallations, - organizationSlug, - projectSlug, - environmentSlug, -}: { - gitHubAppInstallations: GitHubAppInstallation[]; - organizationSlug: string; - projectSlug: string; - environmentSlug: string; - open?: boolean; -}) { - const [isModalOpen, setIsModalOpen] = useState(false); - const lastSubmission = useActionData() as any; - const navigate = useNavigate(); - - const [selectedInstallation, setSelectedInstallation] = useState< - GitHubAppInstallation | undefined - >(gitHubAppInstallations.at(0)); - - const [selectedRepository, setSelectedRepository] = useState( - undefined - ); - - const navigation = useNavigation(); - const isConnectRepositoryLoading = - navigation.formData?.get("action") === "connect-repo" && - (navigation.state === "submitting" || navigation.state === "loading"); - - const [form, { installationId, repositoryId }] = useForm({ - id: "connect-repo", - lastSubmission: lastSubmission, - shouldRevalidate: "onSubmit", - onValidate({ formData }) { - return parse(formData, { - schema: ConnectGitHubRepoFormSchema, - }); - }, - }); - - const [searchParams, setSearchParams] = useSearchParams(); - useEffect(() => { - const params = new URLSearchParams(searchParams); - - if (params.get("openGithubRepoModal") === "1") { - setIsModalOpen(true); - params.delete("openGithubRepoModal"); - setSearchParams(params); - } - }, [searchParams, setSearchParams]); - - useEffect(() => { - if (lastSubmission && "success" in lastSubmission && lastSubmission.success === true) { - setIsModalOpen(false); - } - }, [lastSubmission]); - - return ( - - - - - - Connect GitHub repository -
-
- - Choose a GitHub repository to connect to your project. - -
- - - - {installationId.error} - - - - - - Configure repository access in{" "} - - GitHub - - . - - {repositoryId.error} - - {form.error} - - Connect repository - - } - cancelButton={ - - - - } - /> -
-
-
-
-
- ); -} - -function GitHubConnectionPrompt({ - gitHubAppInstallations, - organizationSlug, - projectSlug, - environmentSlug, -}: { - gitHubAppInstallations: GitHubAppInstallation[]; - organizationSlug: string; - projectSlug: string; - environmentSlug: string; -}) { - return ( -
- - {gitHubAppInstallations.length === 0 && ( - - Install GitHub app - - )} - {gitHubAppInstallations.length !== 0 && ( -
- - - GitHub app is installed - -
- )} - - Connect your GitHub repository to automatically deploy your changes. -
-
- ); -} - -type ConnectedGitHubRepo = { - branchTracking: BranchTrackingConfig | undefined; - previewDeploymentsEnabled: boolean; - createdAt: Date; - repository: GitHubRepository; -}; - -function ConnectedGitHubRepoForm({ - connectedGitHubRepo, - previewEnvironmentEnabled, -}: { - connectedGitHubRepo: ConnectedGitHubRepo; - previewEnvironmentEnabled?: boolean; -}) { - const lastSubmission = useActionData() as any; - const navigation = useNavigation(); - const organization = useOrganization(); - - const [hasGitSettingsChanges, setHasGitSettingsChanges] = useState(false); - const [gitSettingsValues, setGitSettingsValues] = useState({ - productionBranch: connectedGitHubRepo.branchTracking?.prod?.branch || "", - stagingBranch: connectedGitHubRepo.branchTracking?.staging?.branch || "", - previewDeploymentsEnabled: connectedGitHubRepo.previewDeploymentsEnabled, - }); - - useEffect(() => { - const hasChanges = - gitSettingsValues.productionBranch !== - (connectedGitHubRepo.branchTracking?.prod?.branch || "") || - gitSettingsValues.stagingBranch !== - (connectedGitHubRepo.branchTracking?.staging?.branch || "") || - gitSettingsValues.previewDeploymentsEnabled !== connectedGitHubRepo.previewDeploymentsEnabled; - setHasGitSettingsChanges(hasChanges); - }, [gitSettingsValues, connectedGitHubRepo]); - - const [gitSettingsForm, fields] = useForm({ - id: "update-git-settings", - lastSubmission: lastSubmission, - shouldRevalidate: "onSubmit", - onValidate({ formData }) { - return parse(formData, { - schema: UpdateGitSettingsFormSchema, - }); - }, - }); - - const isGitSettingsLoading = - navigation.formData?.get("action") === "update-git-settings" && - (navigation.state === "submitting" || navigation.state === "loading"); - - return ( - <> -
-
- - - {connectedGitHubRepo.repository.fullName} - - {connectedGitHubRepo.repository.private && ( - - )} - - - -
- - - - - - Disconnect GitHub repository -
- - Are you sure you want to disconnect{" "} - {connectedGitHubRepo.repository.fullName}? - This will stop automatic deployments from GitHub. - - - - - - } - cancelButton={ - - - - } - /> -
-
-
-
- -
-
- - - Every push to the selected tracking branch creates a deployment in the corresponding - environment. - -
-
- - - {environmentFullTitle({ type: "PRODUCTION" })} - -
- { - setGitSettingsValues((prev) => ({ - ...prev, - productionBranch: e.target.value, - })); - }} - /> -
- - - {environmentFullTitle({ type: "STAGING" })} - -
- { - setGitSettingsValues((prev) => ({ - ...prev, - stagingBranch: e.target.value, - })); - }} - /> - -
- - - {environmentFullTitle({ type: "PREVIEW" })} - -
-
- { - setGitSettingsValues((prev) => ({ - ...prev, - previewDeploymentsEnabled: checked, - })); - }} - /> - {!previewEnvironmentEnabled && ( - - Upgrade your plan to - enable preview branches - - } - /> - )} -
-
- {fields.productionBranch?.error} - {fields.stagingBranch?.error} - {fields.previewDeploymentsEnabled?.error} - {gitSettingsForm.error} -
- - - Save - - } - /> -
-
- - ); -} - function BuildSettingsForm({ buildSettings }: { buildSettings: BuildSettings }) { const lastSubmission = useActionData() as any; const navigation = useNavigation(); diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.waitpoints.tokens.$waitpointParam/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.waitpoints.tokens.$waitpointParam/route.tsx index 263baed23d..48b842d34d 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.waitpoints.tokens.$waitpointParam/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.waitpoints.tokens.$waitpointParam/route.tsx @@ -126,6 +126,7 @@ export default function Page() { runs={waitpoint.connectedRuns} isLoading={false} variant="bright" + disableAdjacentRows />
diff --git a/apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.github.tsx b/apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.github.tsx new file mode 100644 index 0000000000..bb7406ed44 --- /dev/null +++ b/apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.github.tsx @@ -0,0 +1,877 @@ +import { conform, useForm } from "@conform-to/react"; +import { parse } from "@conform-to/zod"; +import { CheckCircleIcon, LockClosedIcon, PlusIcon } from "@heroicons/react/20/solid"; +import { Form, useActionData, useNavigation, useNavigate, useSearchParams, useLocation } from "@remix-run/react"; +import { type ActionFunctionArgs, type LoaderFunctionArgs, json } from "@remix-run/server-runtime"; +import { typedjson, useTypedFetcher } from "remix-typedjson"; +import { z } from "zod"; +import { OctoKitty } from "~/components/GitHubLoginButton"; +import { Dialog, DialogContent, DialogHeader, DialogTrigger } from "~/components/primitives/Dialog"; +import { DialogClose } from "@radix-ui/react-dialog"; +import { Button, LinkButton } from "~/components/primitives/Buttons"; +import { Fieldset } from "~/components/primitives/Fieldset"; +import { FormButtons } from "~/components/primitives/FormButtons"; +import { FormError } from "~/components/primitives/FormError"; +import { Hint } from "~/components/primitives/Hint"; +import { Input } from "~/components/primitives/Input"; +import { InputGroup } from "~/components/primitives/InputGroup"; +import { Label } from "~/components/primitives/Label"; +import { Paragraph } from "~/components/primitives/Paragraph"; +import { Select, SelectItem } from "~/components/primitives/Select"; +import { SpinnerWhite } from "~/components/primitives/Spinner"; +import { Switch } from "~/components/primitives/Switch"; +import { TextLink } from "~/components/primitives/TextLink"; +import { DateTime } from "~/components/primitives/DateTime"; +import { InfoIconTooltip } from "~/components/primitives/Tooltip"; +import { + EnvironmentIcon, + environmentFullTitle, + environmentTextClassName, +} from "~/components/environments/EnvironmentLabel"; +import { GitBranchIcon } from "lucide-react"; +import { + redirectBackWithErrorMessage, + redirectBackWithSuccessMessage, + redirectWithErrorMessage, + redirectWithSuccessMessage, +} from "~/models/message.server"; +import { findProjectBySlug } from "~/models/project.server"; +import { findEnvironmentBySlug } from "~/models/runtimeEnvironment.server"; +import { ProjectSettingsService } from "~/services/projectSettings.server"; +import { logger } from "~/services/logger.server"; +import { requireUserId } from "~/services/session.server"; +import { + githubAppInstallPath, + EnvironmentParamSchema, + v3ProjectSettingsPath, +} from "~/utils/pathBuilder"; +import { cn } from "~/utils/cn"; +import { type BranchTrackingConfig } from "~/v3/github"; +import { GitHubSettingsPresenter } from "~/presenters/v3/GitHubSettingsPresenter.server"; +import { useEffect, useState } from "react"; + +// ============================================================================ +// Types +// ============================================================================ + +export type GitHubRepository = { + id: string; + name: string; + fullName: string; + private: boolean; + htmlUrl: string; +}; + +export type GitHubAppInstallation = { + id: string; + appInstallationId: bigint; + targetType: string; + accountHandle: string; + repositories: GitHubRepository[]; +}; + +export type ConnectedGitHubRepo = { + branchTracking: BranchTrackingConfig | undefined; + previewDeploymentsEnabled: boolean; + createdAt: Date; + repository: GitHubRepository; +}; + +// ============================================================================ +// Schemas +// ============================================================================ + +export const ConnectGitHubRepoFormSchema = z.object({ + action: z.literal("connect-repo"), + installationId: z.string(), + repositoryId: z.string(), + redirectUrl: z.string().optional(), +}); + +export const DisconnectGitHubRepoFormSchema = z.object({ + action: z.literal("disconnect-repo"), + redirectUrl: z.string().optional(), +}); + +export const UpdateGitSettingsFormSchema = z.object({ + action: z.literal("update-git-settings"), + productionBranch: z.string().trim().optional(), + stagingBranch: z.string().trim().optional(), + previewDeploymentsEnabled: z + .string() + .optional() + .transform((val) => val === "on"), + redirectUrl: z.string().optional(), +}); + +const GitHubActionSchema = z.discriminatedUnion("action", [ + ConnectGitHubRepoFormSchema, + DisconnectGitHubRepoFormSchema, + UpdateGitSettingsFormSchema, +]); + +// ============================================================================ +// Loader +// ============================================================================ + +export async function loader({ request, params }: LoaderFunctionArgs) { + const userId = await requireUserId(request); + const { organizationSlug, projectParam, envParam } = EnvironmentParamSchema.parse(params); + + const project = await findProjectBySlug(organizationSlug, projectParam, userId); + if (!project) { + throw new Response("Not Found", { status: 404 }); + } + + const environment = await findEnvironmentBySlug(project.id, envParam, userId); + if (!environment) { + throw new Response("Not Found", { status: 404 }); + } + + const presenter = new GitHubSettingsPresenter(); + const resultOrFail = await presenter.call({ + projectId: project.id, + organizationId: project.organizationId, + }); + + if (resultOrFail.isErr()) { + throw new Response("Failed to load GitHub settings", { status: 500 }); + } + + return typedjson(resultOrFail.value); +} + +// ============================================================================ +// Action +// ============================================================================ + +function redirectWithMessage( + request: Request, + redirectUrl: string | undefined, + message: string, + type: "success" | "error" +) { + if (type === "success") { + return redirectUrl + ? redirectWithSuccessMessage(redirectUrl, request, message) + : redirectBackWithSuccessMessage(request, message); + } + return redirectUrl + ? redirectWithErrorMessage(redirectUrl, request, message) + : redirectBackWithErrorMessage(request, message); +} + +export async function action({ request, params }: ActionFunctionArgs) { + const userId = await requireUserId(request); + const { organizationSlug, projectParam, envParam } = EnvironmentParamSchema.parse(params); + + const project = await findProjectBySlug(organizationSlug, projectParam, userId); + if (!project) { + throw new Response("Not Found", { status: 404 }); + } + + const environment = await findEnvironmentBySlug(project.id, envParam, userId); + if (!environment) { + throw new Response("Not Found", { status: 404 }); + } + + const formData = await request.formData(); + const submission = parse(formData, { schema: GitHubActionSchema }); + + if (!submission.value || submission.intent !== "submit") { + return json(submission); + } + + const projectSettingsService = new ProjectSettingsService(); + const membershipResultOrFail = await projectSettingsService.verifyProjectMembership( + organizationSlug, + projectParam, + userId + ); + + if (membershipResultOrFail.isErr()) { + return json({ errors: { body: membershipResultOrFail.error.type } }, { status: 404 }); + } + + const { projectId, organizationId } = membershipResultOrFail.value; + const { action: actionType } = submission.value; + + // Handle connect-repo action + if (actionType === "connect-repo") { + const { repositoryId, installationId, redirectUrl } = submission.value; + + const resultOrFail = await projectSettingsService.connectGitHubRepo( + projectId, + organizationId, + repositoryId, + installationId + ); + + if (resultOrFail.isOk()) { + return redirectWithMessage( + request, + redirectUrl, + "GitHub repository connected successfully", + "success" + ); + } + + const errorType = resultOrFail.error.type; + + if (errorType === "gh_repository_not_found") { + return redirectWithMessage(request, redirectUrl, "GitHub repository not found", "error"); + } + + if (errorType === "project_already_has_connected_repository") { + return redirectWithMessage( + request, + redirectUrl, + "Project already has a connected repository", + "error" + ); + } + + logger.error("Failed to connect GitHub repository", { error: resultOrFail.error }); + return redirectWithMessage( + request, + redirectUrl, + "Failed to connect GitHub repository", + "error" + ); + } + + // Handle disconnect-repo action + if (actionType === "disconnect-repo") { + const { redirectUrl } = submission.value; + + const resultOrFail = await projectSettingsService.disconnectGitHubRepo(projectId); + + if (resultOrFail.isOk()) { + return redirectWithMessage( + request, + redirectUrl, + "GitHub repository disconnected successfully", + "success" + ); + } + + logger.error("Failed to disconnect GitHub repository", { error: resultOrFail.error }); + return redirectWithMessage( + request, + redirectUrl, + "Failed to disconnect GitHub repository", + "error" + ); + } + + // Handle update-git-settings action + if (actionType === "update-git-settings") { + const { productionBranch, stagingBranch, previewDeploymentsEnabled, redirectUrl } = + submission.value; + + const resultOrFail = await projectSettingsService.updateGitSettings( + projectId, + productionBranch, + stagingBranch, + previewDeploymentsEnabled + ); + + if (resultOrFail.isOk()) { + return redirectWithMessage( + request, + redirectUrl, + "Git settings updated successfully", + "success" + ); + } + + const errorType = resultOrFail.error.type; + + const errorMessages: Record = { + github_app_not_enabled: "GitHub app is not enabled", + connected_gh_repository_not_found: "Connected GitHub repository not found", + production_tracking_branch_not_found: "Production tracking branch not found", + staging_tracking_branch_not_found: "Staging tracking branch not found", + }; + + const message = errorMessages[errorType]; + if (message) { + return redirectWithMessage(request, redirectUrl, message, "error"); + } + + logger.error("Failed to update Git settings", { error: resultOrFail.error }); + return redirectWithMessage(request, redirectUrl, "Failed to update Git settings", "error"); + } + + // Exhaustive check - this should never be reached + submission.value satisfies never; + return redirectBackWithErrorMessage(request, "Failed to process request"); +} + +// ============================================================================ +// Helper: Build resource URL for fetching GitHub data +// ============================================================================ + +export function gitHubResourcePath( + organizationSlug: string, + projectSlug: string, + environmentSlug: string +) { + return `/resources/orgs/${organizationSlug}/projects/${projectSlug}/env/${environmentSlug}/github`; +} + +// ============================================================================ +// Components +// ============================================================================ + +export function ConnectGitHubRepoModal({ + gitHubAppInstallations, + organizationSlug, + projectSlug, + environmentSlug, + redirectUrl, +}: { + gitHubAppInstallations: GitHubAppInstallation[]; + organizationSlug: string; + projectSlug: string; + environmentSlug: string; + redirectUrl?: string; +}) { + const [isModalOpen, setIsModalOpen] = useState(false); + const lastSubmission = useActionData() as any; + const navigate = useNavigate(); + + const [selectedInstallation, setSelectedInstallation] = useState< + GitHubAppInstallation | undefined + >(gitHubAppInstallations.at(0)); + + const [selectedRepository, setSelectedRepository] = useState( + undefined + ); + + const navigation = useNavigation(); + const isConnectRepositoryLoading = + navigation.formData?.get("action") === "connect-repo" && + (navigation.state === "submitting" || navigation.state === "loading"); + + const [form, { installationId, repositoryId }] = useForm({ + id: "connect-repo", + lastSubmission: lastSubmission, + shouldRevalidate: "onSubmit", + onValidate({ formData }) { + return parse(formData, { + schema: ConnectGitHubRepoFormSchema, + }); + }, + }); + + const [searchParams, setSearchParams] = useSearchParams(); + useEffect(() => { + const params = new URLSearchParams(searchParams); + + if (params.get("openGithubRepoModal") === "1") { + setIsModalOpen(true); + params.delete("openGithubRepoModal"); + setSearchParams(params); + } + }, [searchParams, setSearchParams]); + + useEffect(() => { + if (lastSubmission && "success" in lastSubmission && lastSubmission.success === true) { + setIsModalOpen(false); + } + }, [lastSubmission]); + + const actionUrl = gitHubResourcePath(organizationSlug, projectSlug, environmentSlug); + + return ( + + + + + + Connect GitHub repository +
+
+ {redirectUrl && } + + Choose a GitHub repository to connect to your project. + +
+ + + + {installationId.error} + + + + + + Configure repository access in{" "} + + GitHub + + . + + {repositoryId.error} + + {form.error} + + Connect repository + + } + cancelButton={ + + + + } + /> +
+
+
+
+
+ ); +} + +export function GitHubConnectionPrompt({ + gitHubAppInstallations, + organizationSlug, + projectSlug, + environmentSlug, + redirectUrl, +}: { + gitHubAppInstallations: GitHubAppInstallation[]; + organizationSlug: string; + projectSlug: string; + environmentSlug: string; + redirectUrl?: string; +}) { + + const githubInstallationRedirect = redirectUrl || v3ProjectSettingsPath({ slug: organizationSlug }, { slug: projectSlug }, { slug: environmentSlug }); + return ( +
+ + {gitHubAppInstallations.length === 0 && ( + + Install GitHub app + + )} + {gitHubAppInstallations.length !== 0 && ( +
+ + + GitHub app is installed + +
+ )} +
+
+ ); +} + +export function ConnectedGitHubRepoForm({ + connectedGitHubRepo, + previewEnvironmentEnabled, + organizationSlug, + projectSlug, + environmentSlug, + billingPath, + redirectUrl, +}: { + connectedGitHubRepo: ConnectedGitHubRepo; + previewEnvironmentEnabled?: boolean; + organizationSlug: string; + projectSlug: string; + environmentSlug: string; + billingPath: string; + redirectUrl?: string; +}) { + const lastSubmission = useActionData() as any; + const navigation = useNavigation(); + + const [hasGitSettingsChanges, setHasGitSettingsChanges] = useState(false); + const [gitSettingsValues, setGitSettingsValues] = useState({ + productionBranch: connectedGitHubRepo.branchTracking?.prod?.branch || "", + stagingBranch: connectedGitHubRepo.branchTracking?.staging?.branch || "", + previewDeploymentsEnabled: connectedGitHubRepo.previewDeploymentsEnabled, + }); + + useEffect(() => { + const hasChanges = + gitSettingsValues.productionBranch !== + (connectedGitHubRepo.branchTracking?.prod?.branch || "") || + gitSettingsValues.stagingBranch !== + (connectedGitHubRepo.branchTracking?.staging?.branch || "") || + gitSettingsValues.previewDeploymentsEnabled !== connectedGitHubRepo.previewDeploymentsEnabled; + setHasGitSettingsChanges(hasChanges); + }, [gitSettingsValues, connectedGitHubRepo]); + + const [gitSettingsForm, fields] = useForm({ + id: "update-git-settings", + lastSubmission: lastSubmission, + shouldRevalidate: "onSubmit", + onValidate({ formData }) { + return parse(formData, { + schema: UpdateGitSettingsFormSchema, + }); + }, + }); + + const isGitSettingsLoading = + navigation.formData?.get("action") === "update-git-settings" && + (navigation.state === "submitting" || navigation.state === "loading"); + + const actionUrl = gitHubResourcePath(organizationSlug, projectSlug, environmentSlug); + + return ( + <> +
+
+ + + {connectedGitHubRepo.repository.fullName} + + {connectedGitHubRepo.repository.private && ( + + )} + + + +
+ + + + + + Disconnect GitHub repository +
+ + Are you sure you want to disconnect{" "} + {connectedGitHubRepo.repository.fullName}? + This will stop automatic deployments from GitHub. + + + + {redirectUrl && } + + + } + cancelButton={ + + + + } + /> +
+
+
+
+ +
+ {redirectUrl && } +
+ + + Every push to the selected tracking branch creates a deployment in the corresponding + environment. + +
+
+ + + {environmentFullTitle({ type: "PRODUCTION" })} + +
+ { + setGitSettingsValues((prev) => ({ + ...prev, + productionBranch: e.target.value, + })); + }} + /> +
+ + + {environmentFullTitle({ type: "STAGING" })} + +
+ { + setGitSettingsValues((prev) => ({ + ...prev, + stagingBranch: e.target.value, + })); + }} + /> + +
+ + + {environmentFullTitle({ type: "PREVIEW" })} + +
+
+ { + setGitSettingsValues((prev) => ({ + ...prev, + previewDeploymentsEnabled: checked, + })); + }} + /> + {!previewEnvironmentEnabled && ( + + Upgrade your plan to enable preview + branches + + } + /> + )} +
+
+ {fields.productionBranch?.error} + {fields.stagingBranch?.error} + {fields.previewDeploymentsEnabled?.error} + {gitSettingsForm.error} +
+ + + Save + + } + /> +
+
+ + ); +} + +// ============================================================================ +// Main GitHub Settings Panel Component +// ============================================================================ + +export function GitHubSettingsPanel({ + organizationSlug, + projectSlug, + environmentSlug, + billingPath, +}: { + organizationSlug: string; + projectSlug: string; + environmentSlug: string; + billingPath: string; +}) { + const fetcher = useTypedFetcher(); + const location = useLocation(); + + // Use provided redirectUrl or fall back to current path (without search params) + const effectiveRedirectUrl = location.pathname; + useEffect(() => { + fetcher.load(gitHubResourcePath(organizationSlug, projectSlug, environmentSlug)); + }, [organizationSlug, projectSlug, environmentSlug]); + + const data = fetcher.data; + + // Loading state + if (fetcher.state === "loading" && !data) { + return ( +
+ + Loading GitHub settings... +
+ ); + } + + // GitHub app not enabled + if (!data || !data.enabled) { + return null; + } + + // Connected repository exists - show form + if (data.connectedRepository) { + return ( + + ); + } + + // No connected repository - show connection prompt + return ( +
+ + {!data.connectedRepository && ( + + Connect your GitHub repository to automatically deploy your changes. + + )} +
+ + ); +} diff --git a/apps/webapp/app/routes/storybook.tabs.$tabNumber/route.tsx b/apps/webapp/app/routes/storybook.tabs.$tabNumber/route.tsx index 549108143b..8cf7aaa164 100644 --- a/apps/webapp/app/routes/storybook.tabs.$tabNumber/route.tsx +++ b/apps/webapp/app/routes/storybook.tabs.$tabNumber/route.tsx @@ -3,7 +3,7 @@ import { useParams } from "@remix-run/react"; export default function Story() { const { tabNumber } = useParams(); return ( -
+

{tabNumber}

); diff --git a/apps/webapp/app/routes/storybook.tabs/route.tsx b/apps/webapp/app/routes/storybook.tabs/route.tsx index fc0c8003a4..f3389f2aff 100644 --- a/apps/webapp/app/routes/storybook.tabs/route.tsx +++ b/apps/webapp/app/routes/storybook.tabs/route.tsx @@ -1,18 +1,188 @@ import { Outlet } from "@remix-run/react"; +import { + ClientTabs, + ClientTabsContent, + ClientTabsList, + ClientTabsTrigger, +} from "~/components/primitives/ClientTabs"; +import { Header1 } from "~/components/primitives/Headers"; +import { Paragraph } from "~/components/primitives/Paragraph"; import { Tabs } from "~/components/primitives/Tabs"; export default function Story() { return ( -
- - +
+
+
+
+ {""} (updates the URL) + Variant="underline" +
+ + +
+
+ Variant="pipe-divider" + + +
+
+ Variant="segmented" + + +
+
+
+
+
+ {""} + Variant="underline" +
+ +
+ + + First tab + + + Second tab + + + Third tab + + +
+ +
+

1

+
+
+ +
+

2

+
+
+ +
+

3

+
+
+
+
+ +
+ Variant="pipe-divider" + +
+ + + First tab + + + Second tab + + + Third tab + + +
+ +
+

1

+
+
+ +
+

2

+
+
+ +
+

3

+
+
+
+
+
+ Variant="segmented" + + + + First tab + + + Second tab + + + Third tab + + + +
+

1

+
+
+ +
+

2

+
+
+ +
+

3

+
+
+
+
+
); } diff --git a/docs/self-hosting/kubernetes.mdx b/docs/self-hosting/kubernetes.mdx index f3a827701d..4506d6da9b 100644 --- a/docs/self-hosting/kubernetes.mdx +++ b/docs/self-hosting/kubernetes.mdx @@ -61,7 +61,7 @@ webapp: ```bash helm upgrade -n trigger --install trigger \ oci://ghcr.io/triggerdotdev/charts/trigger \ - --version "~4.0.0-beta" \ + --version "~4.0.0" \ --create-namespace ``` @@ -107,11 +107,11 @@ The following commands will display the default values: ```bash # Specific version helm show values oci://ghcr.io/triggerdotdev/charts/trigger \ - --version "4.0.0-beta.5" + --version "4.0.5" -# Latest v4 beta +# Latest v4 helm show values oci://ghcr.io/triggerdotdev/charts/trigger \ - --version "~4.0.0-beta" + --version "~4.0.0" ``` ### Custom values @@ -171,7 +171,7 @@ Deploy with your custom values: ```bash helm upgrade -n trigger --install trigger \ oci://ghcr.io/triggerdotdev/charts/trigger \ - --version "~4.0.0-beta" \ + --version "~4.0.0" \ --create-namespace \ -f values-custom.yaml ``` @@ -489,14 +489,14 @@ You can lock versions in two ways: # Pin to a specific version for production helm upgrade -n trigger --install trigger \ oci://ghcr.io/triggerdotdev/charts/trigger \ - --version "4.0.0-beta.5" + --version "4.0.5" # The app version will be different from the chart version # This is the version of the Trigger.dev webapp and supervisor # ..and should always match your Trigger.dev CLI version helm show chart \ oci://ghcr.io/triggerdotdev/charts/trigger \ - --version "4.0.0-beta.5" | grep appVersion + --version "4.0.5" | grep appVersion ``` **Specific image tags:** diff --git a/internal-packages/run-engine/src/engine/systems/dequeueSystem.ts b/internal-packages/run-engine/src/engine/systems/dequeueSystem.ts index a8316a9880..5a951a645c 100644 --- a/internal-packages/run-engine/src/engine/systems/dequeueSystem.ts +++ b/internal-packages/run-engine/src/engine/systems/dequeueSystem.ts @@ -559,6 +559,8 @@ export class DequeueSystem { friendlyId: result.worker.friendlyId, version: result.worker.version, }, + // TODO: use a discriminated union schema to differentiate between dequeued runs in dev and in deployed environments. + // Would help make the typechecking stricter deployment: { id: result.deployment?.id, friendlyId: result.deployment?.friendlyId, diff --git a/packages/build/CHANGELOG.md b/packages/build/CHANGELOG.md index e2bf3dc5ab..5ce6b5f6a1 100644 --- a/packages/build/CHANGELOG.md +++ b/packages/build/CHANGELOG.md @@ -1,5 +1,12 @@ # @trigger.dev/build +## 4.3.0 + +### Patch Changes + +- Updated dependencies: + - `@trigger.dev/core@4.3.0` + ## 4.2.0 ### Patch Changes diff --git a/packages/build/package.json b/packages/build/package.json index 54b09b3e23..f764f42801 100644 --- a/packages/build/package.json +++ b/packages/build/package.json @@ -1,6 +1,6 @@ { "name": "@trigger.dev/build", - "version": "4.2.0", + "version": "4.3.0", "description": "trigger.dev build extensions", "license": "MIT", "publishConfig": { @@ -78,7 +78,7 @@ }, "dependencies": { "@prisma/config": "^6.10.0", - "@trigger.dev/core": "workspace:4.2.0", + "@trigger.dev/core": "workspace:4.3.0", "mlly": "^1.7.1", "pkg-types": "^1.1.3", "resolve": "^1.22.8", diff --git a/packages/cli-v3/CHANGELOG.md b/packages/cli-v3/CHANGELOG.md index f7ae2e7ea3..0f5f8a0990 100644 --- a/packages/cli-v3/CHANGELOG.md +++ b/packages/cli-v3/CHANGELOG.md @@ -1,5 +1,22 @@ # trigger.dev +## 4.3.0 + +### Minor Changes + +- feat(cli): deterministic image builds for deployments ([#2778](https://github.com/triggerdotdev/trigger.dev/pull/2778)) +- feat(cli): enable zstd compression for deployment images ([#2773](https://github.com/triggerdotdev/trigger.dev/pull/2773)) + +### Patch Changes + +- The new `triggeredVia` field is now populated in deployments via the CLI. ([#2767](https://github.com/triggerdotdev/trigger.dev/pull/2767)) +- fix(dev): stop max listeners exceeded warning messages when running more than 10 runs concurrently ([#2771](https://github.com/triggerdotdev/trigger.dev/pull/2771)) +- Upgrade @modelcontextprotocol/sdk to 1.24.3 ([#2768](https://github.com/triggerdotdev/trigger.dev/pull/2768)) +- Updated dependencies: + - `@trigger.dev/core@4.3.0` + - `@trigger.dev/build@4.3.0` + - `@trigger.dev/schema-to-json@4.3.0` + ## 4.2.0 ### Minor Changes diff --git a/packages/cli-v3/package.json b/packages/cli-v3/package.json index 81f374099d..1dfc9aaf76 100644 --- a/packages/cli-v3/package.json +++ b/packages/cli-v3/package.json @@ -1,6 +1,6 @@ { "name": "trigger.dev", - "version": "4.2.0", + "version": "4.3.0", "description": "A Command-Line Interface for Trigger.dev projects", "type": "module", "license": "MIT", @@ -92,10 +92,10 @@ "@opentelemetry/resources": "2.0.1", "@opentelemetry/sdk-trace-node": "2.0.1", "@opentelemetry/semantic-conventions": "1.36.0", - "@trigger.dev/build": "workspace:4.2.0", - "@trigger.dev/core": "workspace:4.2.0", - "@trigger.dev/schema-to-json": "workspace:4.2.0", "@s2-dev/streamstore": "^0.17.6", + "@trigger.dev/build": "workspace:4.3.0", + "@trigger.dev/core": "workspace:4.3.0", + "@trigger.dev/schema-to-json": "workspace:4.3.0", "ansi-escapes": "^7.0.0", "braces": "^3.0.3", "c12": "^1.11.1", @@ -117,6 +117,7 @@ "import-in-the-middle": "1.11.0", "import-meta-resolve": "^4.1.0", "ini": "^5.0.0", + "json-stable-stringify": "^1.3.0", "jsonc-parser": "3.2.1", "magicast": "^0.3.4", "minimatch": "^10.0.1", diff --git a/packages/cli-v3/src/build/buildWorker.ts b/packages/cli-v3/src/build/buildWorker.ts index 6e818a0b1e..b23b802f50 100644 --- a/packages/cli-v3/src/build/buildWorker.ts +++ b/packages/cli-v3/src/build/buildWorker.ts @@ -12,7 +12,7 @@ import { join, relative, sep } from "node:path"; import { generateContainerfile } from "../deploy/buildImage.js"; import { writeFile } from "node:fs/promises"; import { buildManifestToJSON } from "../utilities/buildManifest.js"; -import { readPackageJSON, writePackageJSON } from "pkg-types"; +import { readPackageJSON } from "pkg-types"; import { writeJSONFile } from "../utilities/fileSystem.js"; import { isWindows } from "std-env"; import { pathToFileURL } from "node:url"; @@ -192,20 +192,23 @@ async function writeDeployFiles({ ) ?? {}; // Step 3: Write the resolved dependencies to the package.json file - await writePackageJSON(join(outputPath, "package.json"), { - ...packageJson, - name: packageJson.name ?? "trigger-project", - dependencies: { - ...dependencies, + await writeJSONFile( + join(outputPath, "package.json"), + { + ...packageJson, + name: packageJson.name ?? "trigger-project", + dependencies: { + ...dependencies, + }, + trustedDependencies: Object.keys(dependencies).sort(), + devDependencies: {}, + peerDependencies: {}, + scripts: {}, }, - trustedDependencies: Object.keys(dependencies), - devDependencies: {}, - peerDependencies: {}, - scripts: {}, - }); + true + ); await writeJSONFile(join(outputPath, "build.json"), buildManifestToJSON(buildManifest)); - await writeJSONFile(join(outputPath, "metafile.json"), bundleResult.metafile); await writeContainerfile(outputPath, buildManifest); } diff --git a/packages/cli-v3/src/build/bundle.ts b/packages/cli-v3/src/build/bundle.ts index c085937f68..4d1cfd53f8 100644 --- a/packages/cli-v3/src/build/bundle.ts +++ b/packages/cli-v3/src/build/bundle.ts @@ -414,7 +414,9 @@ export async function createBuildManifestFromBundle({ otelImportHook: { include: resolvedConfig.instrumentedPackageNames ?? [], }, - outputHashes: bundle.outputHashes, + // `outputHashes` is only needed for dev builds for the deduplication mechanism during rebuilds. + // For deploys builds, we omit it to ensure deterministic builds + outputHashes: target === "dev" ? bundle.outputHashes : {}, }; if (!workerDir) { diff --git a/packages/cli-v3/src/commands/deploy.ts b/packages/cli-v3/src/commands/deploy.ts index 818051d68d..f4de03281c 100644 --- a/packages/cli-v3/src/commands/deploy.ts +++ b/packages/cli-v3/src/commands/deploy.ts @@ -71,7 +71,7 @@ const DeployCommandOptions = CommonCommandOptions.extend({ saveLogs: z.boolean().default(false), skipUpdateCheck: z.boolean().default(false), skipPromotion: z.boolean().default(false), - noCache: z.boolean().default(false), + cache: z.boolean().default(true), envFile: z.string().optional(), // Local build options forceLocalBuild: z.boolean().optional(), @@ -83,6 +83,10 @@ const DeployCommandOptions = CommonCommandOptions.extend({ nativeBuildServer: z.boolean().default(false), detach: z.boolean().default(false), plain: z.boolean().default(false), + compression: z.enum(["zstd", "gzip"]).default("zstd"), + cacheCompression: z.enum(["zstd", "gzip"]).default("zstd"), + compressionLevel: z.number().optional(), + forceCompression: z.boolean().default(true), }); type DeployCommandOptions = z.infer; @@ -157,6 +161,40 @@ export function configureDeployCommand(program: Command) { "If provided, will save logs even for successful builds" ).hideHelp() ) + .addOption( + new CommandOption( + "--compression ", + "Compression algorithm for image layers: zstd or gzip (default: zstd)" + ) + .choices(["zstd", "gzip"]) + .hideHelp() + ) + .addOption( + new CommandOption( + "--cache-compression ", + "Compression algorithm for build cache: zstd or gzip (default: zstd)" + ) + .choices(["zstd", "gzip"]) + .hideHelp() + ) + .addOption( + new CommandOption( + "--compression-level ", + "The compression level to use when building the image." + ).hideHelp() + ) + .addOption( + new CommandOption( + "--force-compression", + "Force recompression of all layers. Enabled by default when using zstd." + ).hideHelp() + ) + .addOption( + new CommandOption( + "--no-force-compression", + "Disable forced recompression of layers." + ).hideHelp() + ) // Local build options .addOption( new CommandOption("--force-local-build", "Deprecated alias for --local-build").implies({ @@ -480,7 +518,7 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) { const buildResult = await buildImage({ isLocalBuild, useRegistryCache: options.useRegistryCache, - noCache: options.noCache, + noCache: !options.cache, deploymentId: deployment.id, deploymentVersion: deployment.version, imageTag: deployment.imageTag, @@ -499,6 +537,10 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) { authAccessToken: authorization.auth.accessToken, compilationPath: destination.path, buildEnvVars: buildManifest.build.env, + compression: options.compression, + cacheCompression: options.cacheCompression, + compressionLevel: options.compressionLevel, + forceCompression: options.forceCompression, onLog: (logMessage) => { if (options.plain || isCI) { console.log(logMessage); diff --git a/packages/cli-v3/src/deploy/buildImage.ts b/packages/cli-v3/src/deploy/buildImage.ts index e325b58d8f..2225d7db05 100644 --- a/packages/cli-v3/src/deploy/buildImage.ts +++ b/packages/cli-v3/src/deploy/buildImage.ts @@ -20,6 +20,10 @@ export interface BuildImageOptions { imagePlatform: string; noCache?: boolean; load?: boolean; + compression?: "zstd" | "gzip"; + cacheCompression?: "zstd" | "gzip"; + compressionLevel?: number; + forceCompression?: boolean; // Local build options push?: boolean; @@ -79,6 +83,10 @@ export async function buildImage(options: BuildImageOptions): Promise; + compression?: "zstd" | "gzip"; + compressionLevel?: number; + forceCompression?: boolean; onLog?: (log: string) => void; } @@ -180,6 +198,15 @@ async function remoteBuildImage(options: DepotBuildImageOptions): Promise value) .flatMap(([key, value]) => ["--build-arg", `${key}=${value}`]); + const outputOptions = getOutputOptions({ + imageTag: undefined, // This is already handled via the --save flag + push: true, // We always push the image to the registry + load: options.load, + compression: options.compression, + compressionLevel: options.compressionLevel, + forceCompression: options.forceCompression, + }); + const args = [ "build", "-f", @@ -187,18 +214,17 @@ async function remoteBuildImage(options: DepotBuildImageOptions): Promise void; } async function localBuildImage(options: SelfHostedBuildImageOptions): Promise { - const { builder, imageTag, deploymentId, apiClient, useRegistryCache } = options; + const { + builder, + imageTag, + deploymentId, + apiClient, + useRegistryCache, + compression, + cacheCompression, + compressionLevel, + forceCompression, + } = options; // Ensure multi-platform build is supported on the local machine let builderExists = false; @@ -489,6 +531,15 @@ async function localBuildImage(options: SelfHostedBuildImageOptions): Promise (a.name < b.name ? -1 : a.name > b.name ? 1 : 0)), deploy: {}, build: {}, }; diff --git a/packages/cli-v3/src/utilities/fileSystem.ts b/packages/cli-v3/src/utilities/fileSystem.ts index 28178881b1..87d74732eb 100644 --- a/packages/cli-v3/src/utilities/fileSystem.ts +++ b/packages/cli-v3/src/utilities/fileSystem.ts @@ -1,4 +1,5 @@ import fsSync from "fs"; +import stringify from "json-stable-stringify"; import fsModule, { writeFile } from "fs/promises"; import fs from "node:fs"; import { homedir, tmpdir } from "node:os"; @@ -159,7 +160,7 @@ export async function safeReadJSONFile(path: string) { } export async function writeJSONFile(path: string, json: any, pretty = false) { - await safeWriteFile(path, JSON.stringify(json, undefined, pretty ? 2 : undefined)); + await safeWriteFile(path, stringify(json, pretty ? { space: 2 } : undefined) ?? ""); } // Will create the directory if it doesn't exist diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index 7ee6c18dad..b364ad422f 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -1,5 +1,15 @@ # internal-platform +## 4.3.0 + +### Minor Changes + +- feat(cli): deterministic image builds for deployments ([#2778](https://github.com/triggerdotdev/trigger.dev/pull/2778)) + +### Patch Changes + +- The new `triggeredVia` field is now populated in deployments via the CLI. ([#2767](https://github.com/triggerdotdev/trigger.dev/pull/2767)) + ## 4.2.0 ### Patch Changes diff --git a/packages/core/package.json b/packages/core/package.json index 2043613945..fefd0224fe 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@trigger.dev/core", - "version": "4.2.0", + "version": "4.3.0", "description": "Core code used across the Trigger.dev SDK and platform", "license": "MIT", "publishConfig": { diff --git a/packages/python/CHANGELOG.md b/packages/python/CHANGELOG.md index 80c49a28bb..57a39087da 100644 --- a/packages/python/CHANGELOG.md +++ b/packages/python/CHANGELOG.md @@ -1,5 +1,14 @@ # @trigger.dev/python +## 4.3.0 + +### Patch Changes + +- Updated dependencies: + - `@trigger.dev/core@4.3.0` + - `@trigger.dev/build@4.3.0` + - `@trigger.dev/sdk@4.3.0` + ## 4.2.0 ### Patch Changes diff --git a/packages/python/package.json b/packages/python/package.json index 188f0d033f..f4ace48267 100644 --- a/packages/python/package.json +++ b/packages/python/package.json @@ -1,6 +1,6 @@ { "name": "@trigger.dev/python", - "version": "4.2.0", + "version": "4.3.0", "description": "Python runtime and build extension for Trigger.dev", "license": "MIT", "publishConfig": { @@ -45,7 +45,7 @@ "check-exports": "attw --pack ." }, "dependencies": { - "@trigger.dev/core": "workspace:4.2.0", + "@trigger.dev/core": "workspace:4.3.0", "tinyexec": "^0.3.2" }, "devDependencies": { @@ -56,12 +56,12 @@ "tsx": "4.17.0", "esbuild": "^0.23.0", "@arethetypeswrong/cli": "^0.15.4", - "@trigger.dev/build": "workspace:4.2.0", - "@trigger.dev/sdk": "workspace:4.2.0" + "@trigger.dev/build": "workspace:4.3.0", + "@trigger.dev/sdk": "workspace:4.3.0" }, "peerDependencies": { - "@trigger.dev/sdk": "workspace:^4.2.0", - "@trigger.dev/build": "workspace:^4.2.0" + "@trigger.dev/sdk": "workspace:^4.3.0", + "@trigger.dev/build": "workspace:^4.3.0" }, "engines": { "node": ">=18.20.0" diff --git a/packages/react-hooks/CHANGELOG.md b/packages/react-hooks/CHANGELOG.md index 8fe5c9b7d9..41febd39f0 100644 --- a/packages/react-hooks/CHANGELOG.md +++ b/packages/react-hooks/CHANGELOG.md @@ -1,5 +1,12 @@ # @trigger.dev/react-hooks +## 4.3.0 + +### Patch Changes + +- Updated dependencies: + - `@trigger.dev/core@4.3.0` + ## 4.2.0 ### Patch Changes diff --git a/packages/react-hooks/package.json b/packages/react-hooks/package.json index b2de5ecbc8..ed38284acf 100644 --- a/packages/react-hooks/package.json +++ b/packages/react-hooks/package.json @@ -1,6 +1,6 @@ { "name": "@trigger.dev/react-hooks", - "version": "4.2.0", + "version": "4.3.0", "description": "trigger.dev react hooks", "license": "MIT", "publishConfig": { @@ -37,7 +37,7 @@ "check-exports": "attw --pack ." }, "dependencies": { - "@trigger.dev/core": "workspace:^4.2.0", + "@trigger.dev/core": "workspace:^4.3.0", "swr": "^2.2.5" }, "devDependencies": { diff --git a/packages/redis-worker/CHANGELOG.md b/packages/redis-worker/CHANGELOG.md index f3400b9399..ac090b2903 100644 --- a/packages/redis-worker/CHANGELOG.md +++ b/packages/redis-worker/CHANGELOG.md @@ -1,5 +1,12 @@ # @trigger.dev/redis-worker +## 4.3.0 + +### Patch Changes + +- Updated dependencies: + - `@trigger.dev/core@4.3.0` + ## 4.2.0 ### Patch Changes diff --git a/packages/redis-worker/package.json b/packages/redis-worker/package.json index 7e8b94adea..c07239603e 100644 --- a/packages/redis-worker/package.json +++ b/packages/redis-worker/package.json @@ -1,6 +1,6 @@ { "name": "@trigger.dev/redis-worker", - "version": "4.2.0", + "version": "4.3.0", "description": "Redis worker for trigger.dev", "license": "MIT", "publishConfig": { @@ -23,7 +23,7 @@ "test": "vitest --sequence.concurrent=false --no-file-parallelism" }, "dependencies": { - "@trigger.dev/core": "workspace:4.2.0", + "@trigger.dev/core": "workspace:4.3.0", "lodash.omit": "^4.5.0", "nanoid": "^5.0.7", "p-limit": "^6.2.0", diff --git a/packages/rsc/CHANGELOG.md b/packages/rsc/CHANGELOG.md index 4cedc0a6af..93037c8a0d 100644 --- a/packages/rsc/CHANGELOG.md +++ b/packages/rsc/CHANGELOG.md @@ -1,5 +1,12 @@ # @trigger.dev/rsc +## 4.3.0 + +### Patch Changes + +- Updated dependencies: + - `@trigger.dev/core@4.3.0` + ## 4.2.0 ### Patch Changes diff --git a/packages/rsc/package.json b/packages/rsc/package.json index 3aa6eba5ba..30f3080291 100644 --- a/packages/rsc/package.json +++ b/packages/rsc/package.json @@ -1,6 +1,6 @@ { "name": "@trigger.dev/rsc", - "version": "4.2.0", + "version": "4.3.0", "description": "trigger.dev rsc", "license": "MIT", "publishConfig": { @@ -37,14 +37,14 @@ "check-exports": "attw --pack ." }, "dependencies": { - "@trigger.dev/core": "workspace:^4.2.0", + "@trigger.dev/core": "workspace:^4.3.0", "mlly": "^1.7.1", "react": "19.0.0-rc.1", "react-dom": "19.0.0-rc.1" }, "devDependencies": { "@arethetypeswrong/cli": "^0.15.4", - "@trigger.dev/build": "workspace:^4.2.0", + "@trigger.dev/build": "workspace:^4.3.0", "@types/node": "^20.14.14", "@types/react": "*", "@types/react-dom": "*", diff --git a/packages/schema-to-json/CHANGELOG.md b/packages/schema-to-json/CHANGELOG.md index a6a6372916..e17cd1a9f1 100644 --- a/packages/schema-to-json/CHANGELOG.md +++ b/packages/schema-to-json/CHANGELOG.md @@ -1,5 +1,12 @@ # @trigger.dev/schema-to-json +## 4.3.0 + +### Patch Changes + +- Updated dependencies: + - `@trigger.dev/core@4.3.0` + ## 4.2.0 ### Patch Changes diff --git a/packages/schema-to-json/package.json b/packages/schema-to-json/package.json index 610797e9b7..66c0feff7c 100644 --- a/packages/schema-to-json/package.json +++ b/packages/schema-to-json/package.json @@ -1,6 +1,6 @@ { "name": "@trigger.dev/schema-to-json", - "version": "4.2.0", + "version": "4.3.0", "description": "Convert various schema validation libraries to JSON Schema", "license": "MIT", "publishConfig": { diff --git a/packages/trigger-sdk/CHANGELOG.md b/packages/trigger-sdk/CHANGELOG.md index 9f4da3eab3..75231f0c5e 100644 --- a/packages/trigger-sdk/CHANGELOG.md +++ b/packages/trigger-sdk/CHANGELOG.md @@ -1,5 +1,12 @@ # @trigger.dev/sdk +## 4.3.0 + +### Patch Changes + +- Updated dependencies: + - `@trigger.dev/core@4.3.0` + ## 4.2.0 ### Patch Changes diff --git a/packages/trigger-sdk/package.json b/packages/trigger-sdk/package.json index fcd8485444..04aa319f55 100644 --- a/packages/trigger-sdk/package.json +++ b/packages/trigger-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@trigger.dev/sdk", - "version": "4.2.0", + "version": "4.3.0", "description": "trigger.dev Node.JS SDK", "license": "MIT", "publishConfig": { @@ -51,7 +51,7 @@ "dependencies": { "@opentelemetry/api": "1.9.0", "@opentelemetry/semantic-conventions": "1.36.0", - "@trigger.dev/core": "workspace:4.2.0", + "@trigger.dev/core": "workspace:4.3.0", "chalk": "^5.2.0", "cronstrue": "^2.21.0", "debug": "^4.3.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 000ad8ab3d..1b42585982 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -419,31 +419,31 @@ importers: version: 3.7.1(react@18.2.0) '@remix-run/express': specifier: 2.1.0 - version: 2.1.0(express@4.20.0)(typescript@5.5.4) + version: 2.1.0(express@4.20.0)(typescript@5.9.3) '@remix-run/node': specifier: 2.1.0 - version: 2.1.0(typescript@5.5.4) + version: 2.1.0(typescript@5.9.3) '@remix-run/react': specifier: 2.1.0 - version: 2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4) + version: 2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3) '@remix-run/router': specifier: ^1.15.3 version: 1.15.3 '@remix-run/serve': specifier: 2.1.0 - version: 2.1.0(typescript@5.5.4) + version: 2.1.0(typescript@5.9.3) '@remix-run/server-runtime': specifier: 2.1.0 - version: 2.1.0(typescript@5.5.4) + version: 2.1.0(typescript@5.9.3) '@remix-run/v1-meta': specifier: ^0.1.3 - version: 0.1.3(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4))(@remix-run/server-runtime@2.1.0(typescript@5.5.4)) + version: 0.1.3(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(@remix-run/server-runtime@2.1.0(typescript@5.9.3)) '@s2-dev/streamstore': specifier: ^0.17.2 - version: 0.17.3(typescript@5.5.4) + version: 0.17.3(typescript@5.9.3) '@sentry/remix': specifier: 9.46.0 - version: 9.46.0(patch_hash=146126b032581925294aaed63ab53ce3f5e0356a755f1763d7a9a76b9846943b)(@remix-run/node@2.1.0(typescript@5.5.4))(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4))(@remix-run/server-runtime@2.1.0(typescript@5.5.4))(encoding@0.1.13)(react@18.2.0) + version: 9.46.0(patch_hash=146126b032581925294aaed63ab53ce3f5e0356a755f1763d7a9a76b9846943b)(@remix-run/node@2.1.0(typescript@5.9.3))(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(@remix-run/server-runtime@2.1.0(typescript@5.9.3))(encoding@0.1.13)(react@18.2.0) '@slack/web-api': specifier: 7.9.1 version: 7.9.1 @@ -515,7 +515,7 @@ importers: version: 1.0.18 class-variance-authority: specifier: ^0.5.2 - version: 0.5.2(typescript@5.5.4) + version: 0.5.2(typescript@5.9.3) clsx: specifier: ^1.2.1 version: 1.2.1 @@ -563,7 +563,7 @@ importers: version: 10.12.11(react-dom@18.2.0(react@18.2.0))(react@18.2.0) graphile-worker: specifier: 0.16.6 - version: 0.16.6(patch_hash=798129c99ed02177430fc90a1fdef800ec94e5fd1d491b931297dc52f4c98ab1)(typescript@5.5.4) + version: 0.16.6(patch_hash=798129c99ed02177430fc90a1fdef800ec94e5fd1d491b931297dc52f4c98ab1)(typescript@5.9.3) humanize-duration: specifier: ^3.27.3 version: 3.27.3 @@ -689,22 +689,22 @@ importers: version: 2.0.1 remix-auth: specifier: ^3.6.0 - version: 3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4))(@remix-run/server-runtime@2.1.0(typescript@5.5.4)) + version: 3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(@remix-run/server-runtime@2.1.0(typescript@5.9.3)) remix-auth-email-link: specifier: 2.0.2 - version: 2.0.2(@remix-run/server-runtime@2.1.0(typescript@5.5.4))(remix-auth@3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4))(@remix-run/server-runtime@2.1.0(typescript@5.5.4))) + version: 2.0.2(@remix-run/server-runtime@2.1.0(typescript@5.9.3))(remix-auth@3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(@remix-run/server-runtime@2.1.0(typescript@5.9.3))) remix-auth-github: specifier: ^1.6.0 - version: 1.6.0(@remix-run/server-runtime@2.1.0(typescript@5.5.4))(remix-auth@3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4))(@remix-run/server-runtime@2.1.0(typescript@5.5.4))) + version: 1.6.0(@remix-run/server-runtime@2.1.0(typescript@5.9.3))(remix-auth@3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(@remix-run/server-runtime@2.1.0(typescript@5.9.3))) remix-auth-google: specifier: ^2.0.0 - version: 2.0.0(@remix-run/server-runtime@2.1.0(typescript@5.5.4))(remix-auth@3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4))(@remix-run/server-runtime@2.1.0(typescript@5.5.4))) + version: 2.0.0(@remix-run/server-runtime@2.1.0(typescript@5.9.3))(remix-auth@3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(@remix-run/server-runtime@2.1.0(typescript@5.9.3))) remix-typedjson: specifier: 0.3.1 - version: 0.3.1(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4))(@remix-run/server-runtime@2.1.0(typescript@5.5.4))(react@18.2.0) + version: 0.3.1(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(@remix-run/server-runtime@2.1.0(typescript@5.9.3))(react@18.2.0) remix-utils: specifier: ^7.7.0 - version: 7.7.0(@remix-run/node@2.1.0(typescript@5.5.4))(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4))(@remix-run/router@1.15.3)(crypto-js@4.2.0)(intl-parse-accept-language@1.0.0)(react@18.2.0)(zod@3.25.76) + version: 7.7.0(@remix-run/node@2.1.0(typescript@5.9.3))(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(@remix-run/router@1.15.3)(crypto-js@4.2.0)(intl-parse-accept-language@1.0.0)(react@18.2.0)(zod@3.25.76) seedrandom: specifier: ^3.0.5 version: 3.0.5 @@ -783,13 +783,13 @@ importers: version: link:../../internal-packages/testcontainers '@remix-run/dev': specifier: 2.1.0 - version: 2.1.0(@remix-run/serve@2.1.0(typescript@5.5.4))(@types/node@22.13.9)(bufferutil@4.0.9)(encoding@0.1.13)(lightningcss@1.29.2)(terser@5.44.1)(typescript@5.5.4) + version: 2.1.0(@remix-run/serve@2.1.0(typescript@5.9.3))(@types/node@22.13.9)(bufferutil@4.0.9)(encoding@0.1.13)(lightningcss@1.29.2)(terser@5.44.1)(typescript@5.9.3) '@remix-run/eslint-config': specifier: 2.1.0 - version: 2.1.0(eslint@8.31.0)(react@18.2.0)(typescript@5.5.4) + version: 2.1.0(eslint@8.31.0)(react@18.2.0)(typescript@5.9.3) '@remix-run/testing': specifier: ^2.1.0 - version: 2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4) + version: 2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3) '@sentry/cli': specifier: 2.50.2 version: 2.50.2(encoding@0.1.13) @@ -888,10 +888,10 @@ importers: version: 8.5.4 '@typescript-eslint/eslint-plugin': specifier: ^5.59.6 - version: 5.59.6(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.5.4))(eslint@8.31.0)(typescript@5.5.4) + version: 5.59.6(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.9.3))(eslint@8.31.0)(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^5.59.6 - version: 5.59.6(eslint@8.31.0)(typescript@5.5.4) + version: 5.59.6(eslint@8.31.0)(typescript@5.9.3) autoevals: specifier: ^0.0.130 version: 0.0.130(encoding@0.1.13)(ws@8.12.0(bufferutil@4.0.9)) @@ -918,7 +918,7 @@ importers: version: 8.6.0(eslint@8.31.0) eslint-plugin-import: specifier: ^2.29.1 - version: 2.29.1(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.5.5)(eslint@8.31.0) + version: 2.29.1(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.9.3))(eslint-import-resolver-typescript@3.5.5)(eslint@8.31.0) eslint-plugin-react-hooks: specifier: ^4.6.2 version: 4.6.2(eslint@8.31.0) @@ -936,7 +936,7 @@ importers: version: 16.0.1(postcss@8.5.6) postcss-loader: specifier: ^8.1.1 - version: 8.1.1(postcss@8.5.6)(typescript@5.5.4)(webpack@5.102.1(@swc/core@1.3.26)(esbuild@0.15.18)) + version: 8.1.1(postcss@8.5.6)(typescript@5.9.3)(webpack@5.102.1(@swc/core@1.3.26)(esbuild@0.15.18)) prettier: specifier: ^2.8.8 version: 2.8.8 @@ -969,7 +969,7 @@ importers: version: 4.20.6 vite-tsconfig-paths: specifier: ^4.0.5 - version: 4.0.5(typescript@5.5.4) + version: 4.0.5(typescript@5.9.3) docs: {} @@ -1297,7 +1297,7 @@ importers: specifier: ^6.10.0 version: 6.19.0(magicast@0.3.5) '@trigger.dev/core': - specifier: workspace:4.2.0 + specifier: workspace:4.3.0 version: link:../core mlly: specifier: ^1.7.1 @@ -1373,13 +1373,13 @@ importers: specifier: ^0.17.6 version: 0.17.6 '@trigger.dev/build': - specifier: workspace:4.2.0 + specifier: workspace:4.3.0 version: link:../build '@trigger.dev/core': - specifier: workspace:4.2.0 + specifier: workspace:4.3.0 version: link:../core '@trigger.dev/schema-to-json': - specifier: workspace:4.2.0 + specifier: workspace:4.3.0 version: link:../schema-to-json ansi-escapes: specifier: ^7.0.0 @@ -1444,6 +1444,9 @@ importers: ini: specifier: ^5.0.0 version: 5.0.0 + json-stable-stringify: + specifier: ^1.3.0 + version: 1.3.0 jsonc-parser: specifier: 3.2.1 version: 3.2.1 @@ -1636,7 +1639,7 @@ importers: version: 1.36.0 '@s2-dev/streamstore': specifier: 0.17.3 - version: 0.17.3(typescript@5.5.4) + version: 0.17.3(typescript@5.9.3) dequal: specifier: ^2.0.3 version: 2.0.3 @@ -1712,7 +1715,7 @@ importers: version: 4.0.14 ai: specifier: ^3.4.33 - version: 3.4.33(openai@4.97.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9))(zod@3.25.76))(react@19.1.0)(sswr@2.1.0(svelte@5.43.6))(svelte@5.43.6)(vue@3.5.24(typescript@5.5.4))(zod@3.25.76) + version: 3.4.33(openai@4.97.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9))(zod@3.25.76))(react@19.1.0)(sswr@2.1.0(svelte@5.43.6))(svelte@5.43.6)(vue@3.5.24(typescript@5.9.3))(zod@3.25.76) defu: specifier: ^6.1.4 version: 6.1.4 @@ -1724,7 +1727,7 @@ importers: version: 3.0.2 ts-essentials: specifier: 10.0.1 - version: 10.0.1(typescript@5.5.4) + version: 10.0.1(typescript@5.9.3) tshy: specifier: ^3.0.2 version: 3.0.2 @@ -1735,7 +1738,7 @@ importers: packages/python: dependencies: '@trigger.dev/core': - specifier: workspace:4.2.0 + specifier: workspace:4.3.0 version: link:../core tinyexec: specifier: ^0.3.2 @@ -1745,10 +1748,10 @@ importers: specifier: ^0.15.4 version: 0.15.4 '@trigger.dev/build': - specifier: workspace:4.2.0 + specifier: workspace:4.3.0 version: link:../build '@trigger.dev/sdk': - specifier: workspace:4.2.0 + specifier: workspace:4.3.0 version: link:../trigger-sdk '@types/node': specifier: 20.14.14 @@ -1772,7 +1775,7 @@ importers: packages/react-hooks: dependencies: '@trigger.dev/core': - specifier: workspace:^4.2.0 + specifier: workspace:^4.3.0 version: link:../core react: specifier: ^18.0 || ^19.0 || ^19.0.0-rc @@ -1806,7 +1809,7 @@ importers: packages/redis-worker: dependencies: '@trigger.dev/core': - specifier: workspace:4.2.0 + specifier: workspace:4.3.0 version: link:../core cron-parser: specifier: ^4.9.0 @@ -1849,7 +1852,7 @@ importers: packages/rsc: dependencies: '@trigger.dev/core': - specifier: workspace:^4.2.0 + specifier: workspace:^4.3.0 version: link:../core mlly: specifier: ^1.7.1 @@ -1865,7 +1868,7 @@ importers: specifier: ^0.15.4 version: 0.15.4 '@trigger.dev/build': - specifier: workspace:^4.2.0 + specifier: workspace:^4.3.0 version: link:../build '@types/node': specifier: ^20.14.14 @@ -1941,7 +1944,7 @@ importers: specifier: 1.36.0 version: 1.36.0 '@trigger.dev/core': - specifier: workspace:4.2.0 + specifier: workspace:4.3.0 version: link:../core chalk: specifier: ^5.2.0 @@ -11803,13 +11806,14 @@ packages: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} - call-bind@1.0.2: - resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} - call-bind@1.0.7: resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} engines: {node: '>= 0.4'} + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + call-bound@1.0.4: resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} engines: {node: '>= 0.4'} @@ -14834,6 +14838,10 @@ packages: json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + json-stable-stringify@1.3.0: + resolution: {integrity: sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg==} + engines: {node: '>= 0.4'} + json-stringify-safe@5.0.1: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} @@ -14860,6 +14868,9 @@ packages: jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + jsonify@0.0.1: + resolution: {integrity: sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==} + jsonpath-plus@10.3.0: resolution: {integrity: sha512-8TNmfeTCk2Le33A3vRRwtuworG/L5RrgMvdjhKZxvyShO+mBu2fP50OWUjRLNtvw344DdDarFh9buFAZs5ujeA==} engines: {node: '>=18.0.0'} @@ -20189,13 +20200,13 @@ snapshots: zod: 3.25.76 zod-to-json-schema: 3.24.6(zod@3.25.76) - '@ai-sdk/vue@0.0.59(vue@3.5.24(typescript@5.5.4))(zod@3.25.76)': + '@ai-sdk/vue@0.0.59(vue@3.5.24(typescript@5.9.3))(zod@3.25.76)': dependencies: '@ai-sdk/provider-utils': 1.0.22(zod@3.25.76) '@ai-sdk/ui-utils': 0.0.50(zod@3.25.76) - swrv: 1.0.4(vue@3.5.24(typescript@5.5.4)) + swrv: 1.0.4(vue@3.5.24(typescript@5.9.3)) optionalDependencies: - vue: 3.5.24(typescript@5.5.4) + vue: 3.5.24(typescript@5.9.3) transitivePeerDependencies: - zod @@ -28687,7 +28698,7 @@ snapshots: transitivePeerDependencies: - encoding - '@remix-run/dev@2.1.0(@remix-run/serve@2.1.0(typescript@5.5.4))(@types/node@22.13.9)(bufferutil@4.0.9)(encoding@0.1.13)(lightningcss@1.29.2)(terser@5.44.1)(typescript@5.5.4)': + '@remix-run/dev@2.1.0(@remix-run/serve@2.1.0(typescript@5.9.3))(@types/node@22.13.9)(bufferutil@4.0.9)(encoding@0.1.13)(lightningcss@1.29.2)(terser@5.44.1)(typescript@5.9.3)': dependencies: '@babel/core': 7.22.17 '@babel/generator': 7.24.7 @@ -28698,7 +28709,7 @@ snapshots: '@babel/traverse': 7.24.7 '@mdx-js/mdx': 2.3.0 '@npmcli/package-json': 4.0.1 - '@remix-run/server-runtime': 2.1.0(typescript@5.5.4) + '@remix-run/server-runtime': 2.1.0(typescript@5.9.3) '@types/mdx': 2.0.5 '@vanilla-extract/integration': 6.2.1(@types/node@22.13.9)(lightningcss@1.29.2)(terser@5.44.1) arg: 5.0.2 @@ -28738,8 +28749,8 @@ snapshots: tsconfig-paths: 4.2.0 ws: 7.5.9(bufferutil@4.0.9) optionalDependencies: - '@remix-run/serve': 2.1.0(typescript@5.5.4) - typescript: 5.5.4 + '@remix-run/serve': 2.1.0(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - '@types/node' - bluebird @@ -28755,43 +28766,43 @@ snapshots: - ts-node - utf-8-validate - '@remix-run/eslint-config@2.1.0(eslint@8.31.0)(react@18.2.0)(typescript@5.5.4)': + '@remix-run/eslint-config@2.1.0(eslint@8.31.0)(react@18.2.0)(typescript@5.9.3)': dependencies: '@babel/core': 7.22.17 '@babel/eslint-parser': 7.21.8(@babel/core@7.22.17)(eslint@8.31.0) '@babel/preset-react': 7.18.6(@babel/core@7.22.17) '@rushstack/eslint-patch': 1.2.0 - '@typescript-eslint/eslint-plugin': 5.59.6(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.5.4))(eslint@8.31.0)(typescript@5.5.4) - '@typescript-eslint/parser': 5.59.6(eslint@8.31.0)(typescript@5.5.4) + '@typescript-eslint/eslint-plugin': 5.59.6(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.9.3))(eslint@8.31.0)(typescript@5.9.3) + '@typescript-eslint/parser': 5.59.6(eslint@8.31.0)(typescript@5.9.3) eslint: 8.31.0 eslint-import-resolver-node: 0.3.7 - eslint-import-resolver-typescript: 3.5.5(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.31.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.5.5)(eslint@8.31.0) - eslint-plugin-jest: 26.9.0(@typescript-eslint/eslint-plugin@5.59.6(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.5.4))(eslint@8.31.0)(typescript@5.5.4))(eslint@8.31.0)(typescript@5.5.4) + eslint-import-resolver-typescript: 3.5.5(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.9.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.31.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.9.3))(eslint-import-resolver-typescript@3.5.5)(eslint@8.31.0) + eslint-plugin-jest: 26.9.0(@typescript-eslint/eslint-plugin@5.59.6(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.9.3))(eslint@8.31.0)(typescript@5.9.3))(eslint@8.31.0)(typescript@5.9.3) eslint-plugin-jest-dom: 4.0.3(eslint@8.31.0) eslint-plugin-jsx-a11y: 6.7.1(eslint@8.31.0) eslint-plugin-node: 11.1.0(eslint@8.31.0) eslint-plugin-react: 7.32.2(eslint@8.31.0) eslint-plugin-react-hooks: 4.6.2(eslint@8.31.0) - eslint-plugin-testing-library: 5.11.0(eslint@8.31.0)(typescript@5.5.4) + eslint-plugin-testing-library: 5.11.0(eslint@8.31.0)(typescript@5.9.3) react: 18.2.0 optionalDependencies: - typescript: 5.5.4 + typescript: 5.9.3 transitivePeerDependencies: - eslint-import-resolver-webpack - jest - supports-color - '@remix-run/express@2.1.0(express@4.20.0)(typescript@5.5.4)': + '@remix-run/express@2.1.0(express@4.20.0)(typescript@5.9.3)': dependencies: - '@remix-run/node': 2.1.0(typescript@5.5.4) + '@remix-run/node': 2.1.0(typescript@5.9.3) express: 4.20.0 optionalDependencies: - typescript: 5.5.4 + typescript: 5.9.3 - '@remix-run/node@2.1.0(typescript@5.5.4)': + '@remix-run/node@2.1.0(typescript@5.9.3)': dependencies: - '@remix-run/server-runtime': 2.1.0(typescript@5.5.4) + '@remix-run/server-runtime': 2.1.0(typescript@5.9.3) '@remix-run/web-fetch': 4.4.1 '@remix-run/web-file': 3.1.0 '@remix-run/web-stream': 1.1.0 @@ -28800,26 +28811,26 @@ snapshots: source-map-support: 0.5.21 stream-slice: 0.1.2 optionalDependencies: - typescript: 5.5.4 + typescript: 5.9.3 - '@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4)': + '@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)': dependencies: '@remix-run/router': 1.10.0 - '@remix-run/server-runtime': 2.1.0(typescript@5.5.4) + '@remix-run/server-runtime': 2.1.0(typescript@5.9.3) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) react-router-dom: 6.17.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) optionalDependencies: - typescript: 5.5.4 + typescript: 5.9.3 '@remix-run/router@1.10.0': {} '@remix-run/router@1.15.3': {} - '@remix-run/serve@2.1.0(typescript@5.5.4)': + '@remix-run/serve@2.1.0(typescript@5.9.3)': dependencies: - '@remix-run/express': 2.1.0(express@4.20.0)(typescript@5.5.4) - '@remix-run/node': 2.1.0(typescript@5.5.4) + '@remix-run/express': 2.1.0(express@4.20.0)(typescript@5.9.3) + '@remix-run/node': 2.1.0(typescript@5.9.3) chokidar: 3.6.0 compression: 1.7.4 express: 4.20.0 @@ -28830,7 +28841,7 @@ snapshots: - supports-color - typescript - '@remix-run/server-runtime@2.1.0(typescript@5.5.4)': + '@remix-run/server-runtime@2.1.0(typescript@5.9.3)': dependencies: '@remix-run/router': 1.10.0 '@types/cookie': 0.4.1 @@ -28839,24 +28850,24 @@ snapshots: set-cookie-parser: 2.6.0 source-map: 0.7.4 optionalDependencies: - typescript: 5.5.4 + typescript: 5.9.3 - '@remix-run/testing@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4)': + '@remix-run/testing@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)': dependencies: - '@remix-run/node': 2.1.0(typescript@5.5.4) - '@remix-run/react': 2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4) + '@remix-run/node': 2.1.0(typescript@5.9.3) + '@remix-run/react': 2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3) '@remix-run/router': 1.10.0 react: 18.2.0 react-router-dom: 6.17.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) optionalDependencies: - typescript: 5.5.4 + typescript: 5.9.3 transitivePeerDependencies: - react-dom - '@remix-run/v1-meta@0.1.3(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4))(@remix-run/server-runtime@2.1.0(typescript@5.5.4))': + '@remix-run/v1-meta@0.1.3(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(@remix-run/server-runtime@2.1.0(typescript@5.9.3))': dependencies: - '@remix-run/react': 2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4) - '@remix-run/server-runtime': 2.1.0(typescript@5.5.4) + '@remix-run/react': 2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3) + '@remix-run/server-runtime': 2.1.0(typescript@5.9.3) '@remix-run/web-blob@3.1.0': dependencies: @@ -28951,10 +28962,10 @@ snapshots: '@rushstack/eslint-patch@1.2.0': {} - '@s2-dev/streamstore@0.17.3(typescript@5.5.4)': + '@s2-dev/streamstore@0.17.3(typescript@5.9.3)': dependencies: '@protobuf-ts/runtime': 2.11.1 - typescript: 5.5.4 + typescript: 5.9.3 '@s2-dev/streamstore@0.17.6': dependencies: @@ -29108,15 +29119,15 @@ snapshots: hoist-non-react-statics: 3.3.2 react: 18.2.0 - '@sentry/remix@9.46.0(patch_hash=146126b032581925294aaed63ab53ce3f5e0356a755f1763d7a9a76b9846943b)(@remix-run/node@2.1.0(typescript@5.5.4))(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4))(@remix-run/server-runtime@2.1.0(typescript@5.5.4))(encoding@0.1.13)(react@18.2.0)': + '@sentry/remix@9.46.0(patch_hash=146126b032581925294aaed63ab53ce3f5e0356a755f1763d7a9a76b9846943b)(@remix-run/node@2.1.0(typescript@5.9.3))(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(@remix-run/server-runtime@2.1.0(typescript@5.9.3))(encoding@0.1.13)(react@18.2.0)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.36.0 - '@remix-run/node': 2.1.0(typescript@5.5.4) - '@remix-run/react': 2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4) + '@remix-run/node': 2.1.0(typescript@5.9.3) + '@remix-run/react': 2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3) '@remix-run/router': 1.15.3 - '@remix-run/server-runtime': 2.1.0(typescript@5.5.4) + '@remix-run/server-runtime': 2.1.0(typescript@5.9.3) '@sentry/cli': 2.50.2(encoding@0.1.13) '@sentry/core': 9.46.0 '@sentry/node': 9.46.0 @@ -31021,34 +31032,34 @@ snapshots: '@types/node': 20.14.14 optional: true - '@typescript-eslint/eslint-plugin@5.59.6(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.5.4))(eslint@8.31.0)(typescript@5.5.4)': + '@typescript-eslint/eslint-plugin@5.59.6(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.9.3))(eslint@8.31.0)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.5.1 - '@typescript-eslint/parser': 5.59.6(eslint@8.31.0)(typescript@5.5.4) + '@typescript-eslint/parser': 5.59.6(eslint@8.31.0)(typescript@5.9.3) '@typescript-eslint/scope-manager': 5.59.6 - '@typescript-eslint/type-utils': 5.59.6(eslint@8.31.0)(typescript@5.5.4) - '@typescript-eslint/utils': 5.59.6(eslint@8.31.0)(typescript@5.5.4) + '@typescript-eslint/type-utils': 5.59.6(eslint@8.31.0)(typescript@5.9.3) + '@typescript-eslint/utils': 5.59.6(eslint@8.31.0)(typescript@5.9.3) debug: 4.3.4 eslint: 8.31.0 grapheme-splitter: 1.0.4 ignore: 5.2.4 natural-compare-lite: 1.4.0 semver: 7.6.3 - tsutils: 3.21.0(typescript@5.5.4) + tsutils: 3.21.0(typescript@5.9.3) optionalDependencies: - typescript: 5.5.4 + typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.5.4)': + '@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.9.3)': dependencies: '@typescript-eslint/scope-manager': 5.59.6 '@typescript-eslint/types': 5.59.6 - '@typescript-eslint/typescript-estree': 5.59.6(typescript@5.5.4) + '@typescript-eslint/typescript-estree': 5.59.6(typescript@5.9.3) debug: 4.4.0 eslint: 8.31.0 optionalDependencies: - typescript: 5.5.4 + typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -31057,21 +31068,21 @@ snapshots: '@typescript-eslint/types': 5.59.6 '@typescript-eslint/visitor-keys': 5.59.6 - '@typescript-eslint/type-utils@5.59.6(eslint@8.31.0)(typescript@5.5.4)': + '@typescript-eslint/type-utils@5.59.6(eslint@8.31.0)(typescript@5.9.3)': dependencies: - '@typescript-eslint/typescript-estree': 5.59.6(typescript@5.5.4) - '@typescript-eslint/utils': 5.59.6(eslint@8.31.0)(typescript@5.5.4) + '@typescript-eslint/typescript-estree': 5.59.6(typescript@5.9.3) + '@typescript-eslint/utils': 5.59.6(eslint@8.31.0)(typescript@5.9.3) debug: 4.4.0 eslint: 8.31.0 - tsutils: 3.21.0(typescript@5.5.4) + tsutils: 3.21.0(typescript@5.9.3) optionalDependencies: - typescript: 5.5.4 + typescript: 5.9.3 transitivePeerDependencies: - supports-color '@typescript-eslint/types@5.59.6': {} - '@typescript-eslint/typescript-estree@5.59.6(typescript@5.5.4)': + '@typescript-eslint/typescript-estree@5.59.6(typescript@5.9.3)': dependencies: '@typescript-eslint/types': 5.59.6 '@typescript-eslint/visitor-keys': 5.59.6 @@ -31079,20 +31090,20 @@ snapshots: globby: 11.1.0 is-glob: 4.0.3 semver: 7.7.2 - tsutils: 3.21.0(typescript@5.5.4) + tsutils: 3.21.0(typescript@5.9.3) optionalDependencies: - typescript: 5.5.4 + typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@5.59.6(eslint@8.31.0)(typescript@5.5.4)': + '@typescript-eslint/utils@5.59.6(eslint@8.31.0)(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.31.0) '@types/json-schema': 7.0.13 '@types/semver': 7.5.1 '@typescript-eslint/scope-manager': 5.59.6 '@typescript-eslint/types': 5.59.6 - '@typescript-eslint/typescript-estree': 5.59.6(typescript@5.5.4) + '@typescript-eslint/typescript-estree': 5.59.6(typescript@5.9.3) eslint: 8.31.0 eslint-scope: 5.1.1 semver: 7.7.2 @@ -31359,11 +31370,11 @@ snapshots: '@vue/shared': 3.5.24 csstype: 3.2.0 - '@vue/server-renderer@3.5.24(vue@3.5.24(typescript@5.5.4))': + '@vue/server-renderer@3.5.24(vue@3.5.24(typescript@5.9.3))': dependencies: '@vue/compiler-ssr': 3.5.24 '@vue/shared': 3.5.24 - vue: 3.5.24(typescript@5.5.4) + vue: 3.5.24(typescript@5.9.3) '@vue/shared@3.5.24': {} @@ -31650,7 +31661,7 @@ snapshots: ahocorasick@1.0.2: {} - ai@3.4.33(openai@4.97.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9))(zod@3.25.76))(react@19.1.0)(sswr@2.1.0(svelte@5.43.6))(svelte@5.43.6)(vue@3.5.24(typescript@5.5.4))(zod@3.25.76): + ai@3.4.33(openai@4.97.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9))(zod@3.25.76))(react@19.1.0)(sswr@2.1.0(svelte@5.43.6))(svelte@5.43.6)(vue@3.5.24(typescript@5.9.3))(zod@3.25.76): dependencies: '@ai-sdk/provider': 0.0.26 '@ai-sdk/provider-utils': 1.0.22(zod@3.25.76) @@ -31658,7 +31669,7 @@ snapshots: '@ai-sdk/solid': 0.0.54(zod@3.25.76) '@ai-sdk/svelte': 0.0.57(svelte@5.43.6)(zod@3.25.76) '@ai-sdk/ui-utils': 0.0.50(zod@3.25.76) - '@ai-sdk/vue': 0.0.59(vue@3.5.24(typescript@5.5.4))(zod@3.25.76) + '@ai-sdk/vue': 0.0.59(vue@3.5.24(typescript@5.9.3))(zod@3.25.76) '@opentelemetry/api': 1.9.0 eventsource-parser: 1.1.2 json-schema: 0.4.0 @@ -31881,7 +31892,7 @@ snapshots: array.prototype.flat@1.3.2: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 es-shim-unscopables: 1.0.0 @@ -31895,7 +31906,7 @@ snapshots: array.prototype.flatmap@1.3.2: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 es-shim-unscopables: 1.0.0 @@ -32328,16 +32339,18 @@ snapshots: es-errors: 1.3.0 function-bind: 1.1.2 - call-bind@1.0.2: + call-bind@1.0.7: dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 function-bind: 1.1.2 get-intrinsic: 1.3.0 + set-function-length: 1.2.2 - call-bind@1.0.7: + call-bind@1.0.8: dependencies: + call-bind-apply-helpers: 1.0.2 es-define-property: 1.0.1 - es-errors: 1.3.0 - function-bind: 1.1.2 get-intrinsic: 1.3.0 set-function-length: 1.2.2 @@ -32482,9 +32495,9 @@ snapshots: cjs-module-lexer@1.2.3: {} - class-variance-authority@0.5.2(typescript@5.5.4): + class-variance-authority@0.5.2(typescript@5.9.3): optionalDependencies: - typescript: 5.5.4 + typescript: 5.9.3 class-variance-authority@0.7.0: dependencies: @@ -32734,15 +32747,6 @@ snapshots: dependencies: layout-base: 2.0.1 - cosmiconfig@8.3.6(typescript@5.5.4): - dependencies: - import-fresh: 3.3.0 - js-yaml: 4.1.1 - parse-json: 5.2.0 - path-type: 4.0.0 - optionalDependencies: - typescript: 5.5.4 - cosmiconfig@8.3.6(typescript@5.9.3): dependencies: import-fresh: 3.3.0 @@ -32752,14 +32756,14 @@ snapshots: optionalDependencies: typescript: 5.9.3 - cosmiconfig@9.0.0(typescript@5.5.4): + cosmiconfig@9.0.0(typescript@5.9.3): dependencies: env-paths: 2.2.1 import-fresh: 3.3.0 js-yaml: 4.1.1 parse-json: 5.2.0 optionalDependencies: - typescript: 5.5.4 + typescript: 5.9.3 cp-file@10.0.0: dependencies: @@ -33956,13 +33960,13 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.5.5(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.31.0): + eslint-import-resolver-typescript@3.5.5(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.9.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.31.0): dependencies: debug: 4.4.0 enhanced-resolve: 5.15.0 eslint: 8.31.0 - eslint-module-utils: 2.7.4(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.31.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.5.5)(eslint@8.31.0) + eslint-module-utils: 2.7.4(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.9.3))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.31.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.9.3))(eslint-import-resolver-typescript@3.5.5)(eslint@8.31.0) get-tsconfig: 4.7.2 globby: 13.2.2 is-core-module: 2.14.0 @@ -33974,25 +33978,25 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.7.4(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.31.0): + eslint-module-utils@2.7.4(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.9.3))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.31.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 5.59.6(eslint@8.31.0)(typescript@5.5.4) + '@typescript-eslint/parser': 5.59.6(eslint@8.31.0)(typescript@5.9.3) eslint: 8.31.0 eslint-import-resolver-node: 0.3.7 - eslint-import-resolver-typescript: 3.5.5(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.31.0) + eslint-import-resolver-typescript: 3.5.5(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.9.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.31.0) transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.5.5)(eslint@8.31.0): + eslint-module-utils@2.8.1(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.5.5)(eslint@8.31.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 5.59.6(eslint@8.31.0)(typescript@5.5.4) + '@typescript-eslint/parser': 5.59.6(eslint@8.31.0)(typescript@5.9.3) eslint: 8.31.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.5.5(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.31.0) + eslint-import-resolver-typescript: 3.5.5(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.9.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.31.0) transitivePeerDependencies: - supports-color @@ -34002,7 +34006,7 @@ snapshots: eslint-utils: 2.1.0 regexpp: 3.2.0 - eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.5.5)(eslint@8.31.0): + eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.9.3))(eslint-import-resolver-typescript@3.5.5)(eslint@8.31.0): dependencies: array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 @@ -34012,7 +34016,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.31.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.5.5)(eslint@8.31.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.5.5)(eslint@8.31.0) hasown: 2.0.2 is-core-module: 2.14.0 is-glob: 4.0.3 @@ -34023,7 +34027,7 @@ snapshots: semver: 6.3.1 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 5.59.6(eslint@8.31.0)(typescript@5.5.4) + '@typescript-eslint/parser': 5.59.6(eslint@8.31.0)(typescript@5.9.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -34036,12 +34040,12 @@ snapshots: eslint: 8.31.0 requireindex: 1.2.0 - eslint-plugin-jest@26.9.0(@typescript-eslint/eslint-plugin@5.59.6(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.5.4))(eslint@8.31.0)(typescript@5.5.4))(eslint@8.31.0)(typescript@5.5.4): + eslint-plugin-jest@26.9.0(@typescript-eslint/eslint-plugin@5.59.6(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.9.3))(eslint@8.31.0)(typescript@5.9.3))(eslint@8.31.0)(typescript@5.9.3): dependencies: - '@typescript-eslint/utils': 5.59.6(eslint@8.31.0)(typescript@5.5.4) + '@typescript-eslint/utils': 5.59.6(eslint@8.31.0)(typescript@5.9.3) eslint: 8.31.0 optionalDependencies: - '@typescript-eslint/eslint-plugin': 5.59.6(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.5.4))(eslint@8.31.0)(typescript@5.5.4) + '@typescript-eslint/eslint-plugin': 5.59.6(@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.9.3))(eslint@8.31.0)(typescript@5.9.3) transitivePeerDependencies: - supports-color - typescript @@ -34099,9 +34103,9 @@ snapshots: semver: 6.3.1 string.prototype.matchall: 4.0.8 - eslint-plugin-testing-library@5.11.0(eslint@8.31.0)(typescript@5.5.4): + eslint-plugin-testing-library@5.11.0(eslint@8.31.0)(typescript@5.9.3): dependencies: - '@typescript-eslint/utils': 5.59.6(eslint@8.31.0)(typescript@5.5.4) + '@typescript-eslint/utils': 5.59.6(eslint@8.31.0)(typescript@5.9.3) eslint: 8.31.0 transitivePeerDependencies: - supports-color @@ -35029,22 +35033,6 @@ snapshots: transitivePeerDependencies: - supports-color - graphile-worker@0.16.6(patch_hash=798129c99ed02177430fc90a1fdef800ec94e5fd1d491b931297dc52f4c98ab1)(typescript@5.5.4): - dependencies: - '@graphile/logger': 0.2.0 - '@types/debug': 4.1.12 - '@types/pg': 8.11.6 - cosmiconfig: 8.3.6(typescript@5.5.4) - graphile-config: 0.0.1-beta.8 - json5: 2.2.3 - pg: 8.11.5 - tslib: 2.6.2 - yargs: 17.7.2 - transitivePeerDependencies: - - pg-native - - supports-color - - typescript - graphile-worker@0.16.6(patch_hash=798129c99ed02177430fc90a1fdef800ec94e5fd1d491b931297dc52f4c98ab1)(typescript@5.9.3): dependencies: '@graphile/logger': 0.2.0 @@ -35816,6 +35804,14 @@ snapshots: json-stable-stringify-without-jsonify@1.0.1: {} + json-stable-stringify@1.3.0: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + isarray: 2.0.5 + jsonify: 0.0.1 + object-keys: 1.1.1 + json-stringify-safe@5.0.1: {} json5@1.0.2: @@ -35842,6 +35838,8 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 + jsonify@0.0.1: {} + jsonpath-plus@10.3.0: dependencies: '@jsep-plugin/assignment': 1.3.0(jsep@1.4.0) @@ -38261,9 +38259,9 @@ snapshots: tsx: 4.17.0 yaml: 2.7.1 - postcss-loader@8.1.1(postcss@8.5.6)(typescript@5.5.4)(webpack@5.102.1(@swc/core@1.3.26)(esbuild@0.15.18)): + postcss-loader@8.1.1(postcss@8.5.6)(typescript@5.9.3)(webpack@5.102.1(@swc/core@1.3.26)(esbuild@0.15.18)): dependencies: - cosmiconfig: 9.0.0(typescript@5.5.4) + cosmiconfig: 9.0.0(typescript@5.9.3) jiti: 1.21.0 postcss: 8.5.6 semver: 7.6.3 @@ -39413,54 +39411,54 @@ snapshots: mdast-util-to-markdown: 2.1.2 unified: 11.0.5 - remix-auth-email-link@2.0.2(@remix-run/server-runtime@2.1.0(typescript@5.5.4))(remix-auth@3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4))(@remix-run/server-runtime@2.1.0(typescript@5.5.4))): + remix-auth-email-link@2.0.2(@remix-run/server-runtime@2.1.0(typescript@5.9.3))(remix-auth@3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(@remix-run/server-runtime@2.1.0(typescript@5.9.3))): dependencies: - '@remix-run/server-runtime': 2.1.0(typescript@5.5.4) + '@remix-run/server-runtime': 2.1.0(typescript@5.9.3) crypto-js: 4.1.1 - remix-auth: 3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4))(@remix-run/server-runtime@2.1.0(typescript@5.5.4)) + remix-auth: 3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(@remix-run/server-runtime@2.1.0(typescript@5.9.3)) - remix-auth-github@1.6.0(@remix-run/server-runtime@2.1.0(typescript@5.5.4))(remix-auth@3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4))(@remix-run/server-runtime@2.1.0(typescript@5.5.4))): + remix-auth-github@1.6.0(@remix-run/server-runtime@2.1.0(typescript@5.9.3))(remix-auth@3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(@remix-run/server-runtime@2.1.0(typescript@5.9.3))): dependencies: - '@remix-run/server-runtime': 2.1.0(typescript@5.5.4) - remix-auth: 3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4))(@remix-run/server-runtime@2.1.0(typescript@5.5.4)) - remix-auth-oauth2: 1.11.0(@remix-run/server-runtime@2.1.0(typescript@5.5.4))(remix-auth@3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4))(@remix-run/server-runtime@2.1.0(typescript@5.5.4))) + '@remix-run/server-runtime': 2.1.0(typescript@5.9.3) + remix-auth: 3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(@remix-run/server-runtime@2.1.0(typescript@5.9.3)) + remix-auth-oauth2: 1.11.0(@remix-run/server-runtime@2.1.0(typescript@5.9.3))(remix-auth@3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(@remix-run/server-runtime@2.1.0(typescript@5.9.3))) transitivePeerDependencies: - supports-color - remix-auth-google@2.0.0(@remix-run/server-runtime@2.1.0(typescript@5.5.4))(remix-auth@3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4))(@remix-run/server-runtime@2.1.0(typescript@5.5.4))): + remix-auth-google@2.0.0(@remix-run/server-runtime@2.1.0(typescript@5.9.3))(remix-auth@3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(@remix-run/server-runtime@2.1.0(typescript@5.9.3))): dependencies: - '@remix-run/server-runtime': 2.1.0(typescript@5.5.4) - remix-auth: 3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4))(@remix-run/server-runtime@2.1.0(typescript@5.5.4)) - remix-auth-oauth2: 1.11.0(@remix-run/server-runtime@2.1.0(typescript@5.5.4))(remix-auth@3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4))(@remix-run/server-runtime@2.1.0(typescript@5.5.4))) + '@remix-run/server-runtime': 2.1.0(typescript@5.9.3) + remix-auth: 3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(@remix-run/server-runtime@2.1.0(typescript@5.9.3)) + remix-auth-oauth2: 1.11.0(@remix-run/server-runtime@2.1.0(typescript@5.9.3))(remix-auth@3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(@remix-run/server-runtime@2.1.0(typescript@5.9.3))) transitivePeerDependencies: - supports-color - remix-auth-oauth2@1.11.0(@remix-run/server-runtime@2.1.0(typescript@5.5.4))(remix-auth@3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4))(@remix-run/server-runtime@2.1.0(typescript@5.5.4))): + remix-auth-oauth2@1.11.0(@remix-run/server-runtime@2.1.0(typescript@5.9.3))(remix-auth@3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(@remix-run/server-runtime@2.1.0(typescript@5.9.3))): dependencies: - '@remix-run/server-runtime': 2.1.0(typescript@5.5.4) + '@remix-run/server-runtime': 2.1.0(typescript@5.9.3) debug: 4.4.1(supports-color@10.0.0) - remix-auth: 3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4))(@remix-run/server-runtime@2.1.0(typescript@5.5.4)) + remix-auth: 3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(@remix-run/server-runtime@2.1.0(typescript@5.9.3)) transitivePeerDependencies: - supports-color - remix-auth@3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4))(@remix-run/server-runtime@2.1.0(typescript@5.5.4)): + remix-auth@3.6.0(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(@remix-run/server-runtime@2.1.0(typescript@5.9.3)): dependencies: - '@remix-run/react': 2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4) - '@remix-run/server-runtime': 2.1.0(typescript@5.5.4) + '@remix-run/react': 2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3) + '@remix-run/server-runtime': 2.1.0(typescript@5.9.3) uuid: 8.3.2 - remix-typedjson@0.3.1(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4))(@remix-run/server-runtime@2.1.0(typescript@5.5.4))(react@18.2.0): + remix-typedjson@0.3.1(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(@remix-run/server-runtime@2.1.0(typescript@5.9.3))(react@18.2.0): dependencies: - '@remix-run/react': 2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4) - '@remix-run/server-runtime': 2.1.0(typescript@5.5.4) + '@remix-run/react': 2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3) + '@remix-run/server-runtime': 2.1.0(typescript@5.9.3) react: 18.2.0 - remix-utils@7.7.0(@remix-run/node@2.1.0(typescript@5.5.4))(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4))(@remix-run/router@1.15.3)(crypto-js@4.2.0)(intl-parse-accept-language@1.0.0)(react@18.2.0)(zod@3.25.76): + remix-utils@7.7.0(@remix-run/node@2.1.0(typescript@5.9.3))(@remix-run/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(@remix-run/router@1.15.3)(crypto-js@4.2.0)(intl-parse-accept-language@1.0.0)(react@18.2.0)(zod@3.25.76): dependencies: type-fest: 4.33.0 optionalDependencies: - '@remix-run/node': 2.1.0(typescript@5.5.4) - '@remix-run/react': 2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4) + '@remix-run/node': 2.1.0(typescript@5.9.3) + '@remix-run/react': 2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3) '@remix-run/router': 1.15.3 crypto-js: 4.2.0 intl-parse-accept-language: 1.0.0 @@ -40313,7 +40311,7 @@ snapshots: string.prototype.padend@3.1.4: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.7 define-properties: 1.1.4 es-abstract: 1.21.1 @@ -40536,9 +40534,9 @@ snapshots: swrev@4.0.0: {} - swrv@1.0.4(vue@3.5.24(typescript@5.5.4)): + swrv@1.0.4(vue@3.5.24(typescript@5.9.3)): dependencies: - vue: 3.5.24(typescript@5.5.4) + vue: 3.5.24(typescript@5.9.3) sync-content@2.0.1: dependencies: @@ -40975,10 +40973,6 @@ snapshots: ts-easing@0.2.0: {} - ts-essentials@10.0.1(typescript@5.5.4): - optionalDependencies: - typescript: 5.5.4 - ts-essentials@10.0.1(typescript@5.9.3): optionalDependencies: typescript: 5.9.3 @@ -41009,6 +41003,10 @@ snapshots: optionalDependencies: typescript: 5.5.4 + tsconfck@2.1.2(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 + tsconfck@3.1.3(typescript@5.9.3): optionalDependencies: typescript: 5.9.3 @@ -41085,10 +41083,10 @@ snapshots: - tsx - yaml - tsutils@3.21.0(typescript@5.5.4): + tsutils@3.21.0(typescript@5.9.3): dependencies: tslib: 1.14.1 - typescript: 5.5.4 + typescript: 5.9.3 tsx@3.12.2: dependencies: @@ -41250,8 +41248,7 @@ snapshots: typescript@5.5.4: {} - typescript@5.9.3: - optional: true + typescript@5.9.3: {} ufo@1.5.4: {} @@ -41652,6 +41649,15 @@ snapshots: - supports-color - typescript + vite-tsconfig-paths@4.0.5(typescript@5.9.3): + dependencies: + debug: 4.3.7(supports-color@10.0.0) + globrex: 0.1.2 + tsconfck: 2.1.2(typescript@5.9.3) + transitivePeerDependencies: + - supports-color + - typescript + vite@4.4.9(@types/node@22.13.9)(lightningcss@1.29.2)(terser@5.44.1): dependencies: esbuild: 0.18.11 @@ -41728,15 +41734,15 @@ snapshots: vscode-uri@3.0.8: {} - vue@3.5.24(typescript@5.5.4): + vue@3.5.24(typescript@5.9.3): dependencies: '@vue/compiler-dom': 3.5.24 '@vue/compiler-sfc': 3.5.24 '@vue/runtime-dom': 3.5.24 - '@vue/server-renderer': 3.5.24(vue@3.5.24(typescript@5.5.4)) + '@vue/server-renderer': 3.5.24(vue@3.5.24(typescript@5.9.3)) '@vue/shared': 3.5.24 optionalDependencies: - typescript: 5.5.4 + typescript: 5.9.3 w3c-keyname@2.2.6: {}