Compare commits

...

7 Commits

Author SHA1 Message Date
Eric Allam e85fc501a6 Fix pnpm lock file 2024-04-23 17:03:53 +01:00
github-actions[bot] 0bfeb0816f chore: Update version for release (beta) (#1054)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-04-23 16:58:48 +01:00
nicktrn b207601732 v3: semi-automatic package update command (#1052)
* fix package manager detection

* fix cli update check while in beta

* add update command and warn on mismatches

* update fixes and better integration with dev and deploy

* fix for ci

* update docs

* changeset

* be more specific about prompts before updates

* fail on version mismatch during ci

* update github actions docs

* fix package manager copypasta

* remove ncu

* ignore companyicons

* improve warnings and errors
2024-04-23 16:08:46 +01:00
Matt Aitken 3913e57ef4 Trace view fixes and improvements (#1046)
* Query param for span using history.replaceState is working

* When clicking again on a node, don’t collapse it

* Close the span view using the same replacing of the search param

* Conditional rendering of the resize panels was causing the tree view re-rendering and collapsing…

* Live reloading moved to where the parent label is

* Span action bar is now deeper

* WIP on trace view navigation changes with shortcuts

* Shortcuts for expanding and collapsing en masse

* Number keys expand/collapse levels

* Changed duration toggle to a shortcut key

* Option + click expands/collapse at that level

* Option/alt left/right expands/collapse at that level

* Removed unused imports

* Link from the runs table to the specific span

* Latest lockfile

* Sorted imports

* When doing a test link directly to a span

* Replay links to the span

* CLI log links go directly to a span

* Keyboard shortcuts are in a popover if the width is narrow

* If holding alt only collapse level

* Don’t expand the individual node if you’re holding alt
2024-04-22 13:46:08 +01:00
James Ritchie 26f310397a Fixed the grid layout for v2 runs page 2024-04-22 13:06:56 +01:00
github-actions[bot] 0a845767a0 chore: Update version for release (beta) (#1049)
* chore: Update version for release (beta)

* update lockfile

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: nicktrn <55853254+nicktrn@users.noreply.github.com>
2024-04-21 15:07:11 +01:00
nicktrn ed2a26c865 v3: fix additionalFiles, uncaught exceptions, and improve errors (#1048)
* fix additionalFiles for paths up the tree

* warn if additionalFiles pattern produced no matches

* improve deploy warnings and errors, fail early

* changeset
2024-04-21 15:03:00 +01:00
102 changed files with 1928 additions and 574 deletions
+9
View File
@@ -0,0 +1,9 @@
---
"trigger.dev": patch
"@trigger.dev/core": patch
---
- Fix additionalFiles that aren't decendants
- Stop swallowing uncaught exceptions in prod
- Improve warnings and errors, fail early on critical warnings
- New arg to --save-logs even for successful builds
+5
View File
@@ -0,0 +1,5 @@
---
"trigger.dev": patch
---
v3 CLI update command and package manager detection fix
+2
View File
@@ -44,6 +44,8 @@
"@trigger.dev/yalt": "2.3.18"
},
"changesets": [
"angry-eagles-trade",
"beige-pens-dance",
"breezy-gorillas-mate",
"chilled-hornets-move",
"clean-pianos-listen",
@@ -2,8 +2,14 @@ import { Fragment } from "react";
import { Modifier, ShortcutDefinition } from "~/hooks/useShortcutKeys";
import { cn } from "~/utils/cn";
import { useOperatingSystem } from "./OperatingSystemProvider";
import {
ChevronDownIcon,
ChevronLeftIcon,
ChevronRightIcon,
ChevronUpIcon,
} from "@heroicons/react/20/solid";
const variants = {
export const variants = {
small:
"text-[0.6rem] font-medium min-w-[17px] rounded-[2px] px-1 ml-1 -mr-0.5 grid place-content-center border border-dimmed/40 text-text-dimmed group-hover:text-text-bright/80 group-hover:border-dimmed/60 transition uppercase",
medium:
@@ -23,7 +29,7 @@ export function ShortcutKey({ shortcut, variant, className }: ShortcutKeyProps)
const isMac = platform === "mac";
let relevantShortcut = "mac" in shortcut ? (isMac ? shortcut.mac : shortcut.windows) : shortcut;
const modifiers = relevantShortcut.modifiers ?? [];
const character = keyString(relevantShortcut.key, isMac);
const character = keyString(relevantShortcut.key, isMac, variant);
return (
<span className={cn(variants[variant], className)}>
@@ -35,10 +41,22 @@ export function ShortcutKey({ shortcut, variant, className }: ShortcutKeyProps)
);
}
function keyString(key: String, isMac: boolean) {
function keyString(key: String, isMac: boolean, size: "small" | "medium") {
key = key.toLowerCase();
const className = size === "small" ? "w-2.5 h-4" : "w-3 h-5";
switch (key) {
case "enter":
return isMac ? "↵" : key;
case "arrowdown":
return <ChevronDownIcon className={className} />;
case "arrowup":
return <ChevronUpIcon className={className} />;
case "arrowleft":
return <ChevronLeftIcon className={className} />;
case "arrowright":
return <ChevronRightIcon className={className} />;
default:
return key;
}
@@ -1,10 +1,10 @@
import { VirtualItem, Virtualizer, useVirtualizer } from "@tanstack/react-virtual";
import { motion } from "framer-motion";
import { MutableRefObject, RefObject, useCallback, useEffect, useReducer, useRef } from "react";
import { UnmountClosed } from "react-collapse";
import { cn } from "~/utils/cn";
import { NodeState, NodesState, reducer } from "./reducer";
import { applyFilterToState, concreteStateFromInput, selectedIdFromState } from "./utils";
import { motion } from "framer-motion";
export type TreeViewProps<TData> = {
tree: FlatTree<TData>;
@@ -165,6 +165,11 @@ export type UseTreeStateOutput = {
expandNode: (id: string, scrollToNode?: boolean) => void;
collapseNode: (id: string) => void;
toggleExpandNode: (id: string, scrollToNode?: boolean) => void;
expandAllBelowDepth: (depth: number) => void;
collapseAllBelowDepth: (depth: number) => void;
expandLevel: (level: number) => void;
collapseLevel: (level: number) => void;
toggleExpandLevel: (level: number) => void;
selectFirstVisibleNode: (scrollToNode?: boolean) => void;
selectLastVisibleNode: (scrollToNode?: boolean) => void;
selectNextVisibleNode: (scrollToNode?: boolean) => void;
@@ -333,6 +338,41 @@ export function useTree<TData>({
[state]
);
const expandAllBelowDepth = useCallback(
(depth: number) => {
dispatch({ type: "EXPAND_ALL_BELOW_DEPTH", payload: { tree, depth } });
},
[state]
);
const collapseAllBelowDepth = useCallback(
(depth: number) => {
dispatch({ type: "COLLAPSE_ALL_BELOW_DEPTH", payload: { tree, depth } });
},
[state]
);
const expandLevel = useCallback(
(level: number) => {
dispatch({ type: "EXPAND_LEVEL", payload: { tree, level } });
},
[state]
);
const collapseLevel = useCallback(
(level: number) => {
dispatch({ type: "COLLAPSE_LEVEL", payload: { tree, level } });
},
[state]
);
const toggleExpandLevel = useCallback(
(level: number) => {
dispatch({ type: "TOGGLE_EXPAND_LEVEL", payload: { tree, level } });
},
[state]
);
const getTreeProps = useCallback(() => {
return {
role: "tree",
@@ -368,25 +408,48 @@ export function useTree<TData>({
}
case "Left":
case "ArrowLeft": {
e.preventDefault();
const selected = selectedIdFromState(state.nodes);
if (selected) {
const treeNode = tree.find((node) => node.id === selected);
if (treeNode && treeNode.hasChildren && state.nodes[selected].expanded) {
if (e.altKey) {
if (treeNode && treeNode.hasChildren) {
collapseLevel(treeNode.level);
}
break;
}
const shouldCollapse =
treeNode && treeNode.hasChildren && state.nodes[selected].expanded;
if (shouldCollapse) {
collapseNode(selected);
} else {
selectParentNode(true);
}
}
e.preventDefault();
break;
}
case "Right":
case "ArrowRight": {
e.preventDefault();
const selected = selectedIdFromState(state.nodes);
if (selected) {
const treeNode = tree.find((node) => node.id === selected);
if (e.altKey) {
if (treeNode && treeNode.hasChildren) {
expandLevel(treeNode.level);
}
break;
}
expandNode(selected, true);
}
e.preventDefault();
break;
}
case "Escape": {
@@ -427,6 +490,11 @@ export function useTree<TData>({
expandNode,
collapseNode,
toggleExpandNode,
expandAllBelowDepth,
collapseAllBelowDepth,
expandLevel,
collapseLevel,
toggleExpandLevel,
selectFirstVisibleNode,
selectLastVisibleNode,
selectNextVisibleNode,
@@ -91,6 +91,46 @@ type ToggleExpandNodeAction = {
} & WithScrollToNode;
};
type ExpandAllBelowDepthAction = {
type: "EXPAND_ALL_BELOW_DEPTH";
payload: {
depth: number;
tree: FlatTree<any>;
};
};
type CollapseAllBelowDepthAction = {
type: "COLLAPSE_ALL_BELOW_DEPTH";
payload: {
depth: number;
tree: FlatTree<any>;
};
};
type ExpandLevelAction = {
type: "EXPAND_LEVEL";
payload: {
level: number;
tree: FlatTree<any>;
};
};
type CollapseLevelAction = {
type: "COLLAPSE_LEVEL";
payload: {
level: number;
tree: FlatTree<any>;
};
};
type ToggleExpandLevelAction = {
type: "TOGGLE_EXPAND_LEVEL";
payload: {
level: number;
tree: FlatTree<any>;
};
};
type SelectFirstVisibleNodeAction = {
type: "SELECT_FIRST_VISIBLE_NODE";
payload: {
@@ -135,6 +175,11 @@ export type Action =
| ExpandNodeAction
| CollapseNodeAction
| ToggleExpandNodeAction
| ExpandAllBelowDepthAction
| CollapseAllBelowDepthAction
| ExpandLevelAction
| CollapseLevelAction
| ToggleExpandLevelAction
| SelectFirstVisibleNodeAction
| SelectLastVisibleNodeAction
| SelectNextVisibleNodeAction
@@ -229,6 +274,109 @@ export function reducer(state: TreeState, action: Action): TreeState {
});
}
}
case "EXPAND_ALL_BELOW_DEPTH": {
const nodesToExpand = action.payload.tree.filter(
(n) => n.level >= action.payload.depth && n.hasChildren
);
const newNodes = Object.fromEntries(
Object.entries(state.nodes).map(([key, value]) => [
key,
{
...value,
expanded: nodesToExpand.find((n) => n.id === key) ? true : value.expanded,
},
])
);
const visibleNodes = applyVisibility(action.payload.tree, newNodes);
return { nodes: visibleNodes, changes: generateChanges(state.nodes, visibleNodes) };
}
case "COLLAPSE_ALL_BELOW_DEPTH": {
const nodesToCollapse = action.payload.tree.filter(
(n) => n.level >= action.payload.depth && n.hasChildren
);
const newNodes = Object.fromEntries(
Object.entries(state.nodes).map(([key, value]) => [
key,
{
...value,
expanded: nodesToCollapse.find((n) => n.id === key) ? false : value.expanded,
},
])
);
const visibleNodes = applyVisibility(action.payload.tree, newNodes);
return { nodes: visibleNodes, changes: generateChanges(state.nodes, visibleNodes) };
}
case "EXPAND_LEVEL": {
const nodesToExpand = action.payload.tree.filter(
(n) => n.level <= action.payload.level && n.hasChildren
);
const newNodes = Object.fromEntries(
Object.entries(state.nodes).map(([key, value]) => [
key,
{
...value,
expanded: nodesToExpand.find((n) => n.id === key) ? true : value.expanded,
},
])
);
const visibleNodes = applyVisibility(action.payload.tree, newNodes);
return { nodes: visibleNodes, changes: generateChanges(state.nodes, visibleNodes) };
}
case "COLLAPSE_LEVEL": {
const nodesToCollapse = action.payload.tree.filter(
(n) => n.level === action.payload.level && n.hasChildren
);
const newNodes = Object.fromEntries(
Object.entries(state.nodes).map(([key, value]) => [
key,
{
...value,
expanded: nodesToCollapse.find((n) => n.id === key) ? false : value.expanded,
},
])
);
const visibleNodes = applyVisibility(action.payload.tree, newNodes);
return { nodes: visibleNodes, changes: generateChanges(state.nodes, visibleNodes) };
}
case "TOGGLE_EXPAND_LEVEL": {
//first get the first item at that level in the tree. If it is expanded, collapse all nodes at that level
//if it is collapsed, expand all nodes at that level
const nodesAtLevel = action.payload.tree.filter(
(n) => n.level === action.payload.level && n.hasChildren
);
const firstNode = nodesAtLevel[0];
if (!firstNode) {
return state;
}
const currentlyExpanded = state.nodes[firstNode.id]?.expanded ?? true;
const currentVisible = state.nodes[firstNode.id]?.visible ?? true;
if (currentlyExpanded && currentVisible) {
return reducer(state, {
type: "COLLAPSE_LEVEL",
payload: {
level: action.payload.level,
tree: action.payload.tree,
},
});
} else {
return reducer(state, {
type: "EXPAND_LEVEL",
payload: {
level: action.payload.level,
tree: action.payload.tree,
},
});
}
}
case "SELECT_FIRST_VISIBLE_NODE": {
const node = firstVisibleNode(action.payload.tree, state.nodes);
if (node) {
@@ -1,10 +1,16 @@
import { ArrowPathIcon, StopCircleIcon } from "@heroicons/react/20/solid";
import { StopIcon } from "@heroicons/react/24/outline";
import { BeakerIcon, BookOpenIcon, CheckIcon } from "@heroicons/react/24/solid";
import { useLocation } from "@remix-run/react";
import { formatDuration } from "@trigger.dev/core/v3";
import { User } from "@trigger.dev/database";
import { Button, LinkButton } from "~/components/primitives/Buttons";
import { Dialog, DialogTrigger } from "~/components/primitives/Dialog";
import { useEnvironments } from "~/hooks/useEnvironments";
import { useOrganization } from "~/hooks/useOrganizations";
import { useProject } from "~/hooks/useProject";
import { RunListAppliedFilters, RunListItem } from "~/presenters/v3/RunListPresenter.server";
import { docsPath, v3RunPath, v3TestPath } from "~/utils/pathBuilder";
import { docsPath, v3RunSpanPath, v3TestPath } from "~/utils/pathBuilder";
import { EnvironmentLabel } from "../../environments/EnvironmentLabel";
import { DateTime } from "../../primitives/DateTime";
import { Paragraph } from "../../primitives/Paragraph";
@@ -14,21 +20,14 @@ import {
TableBlankRow,
TableBody,
TableCell,
TableCellChevron,
TableCellMenu,
TableHeader,
TableHeaderCell,
TableRow,
} from "../../primitives/Table";
import { formatDuration } from "@trigger.dev/core/v3";
import { TaskRunStatusCombo } from "./TaskRunStatus";
import { useEnvironments } from "~/hooks/useEnvironments";
import { Button, LinkButton } from "~/components/primitives/Buttons";
import { ArrowPathIcon, StopCircleIcon } from "@heroicons/react/20/solid";
import { Dialog, DialogTrigger } from "~/components/primitives/Dialog";
import { CancelRunDialog } from "./CancelRunDialog";
import { useLocation } from "@remix-run/react";
import { ReplayRunDialog } from "./ReplayRunDialog";
import { TaskRunStatusCombo } from "./TaskRunStatus";
type RunsTableProps = {
total: number;
@@ -78,7 +77,7 @@ export function TaskRunsTable({
<BlankState isLoading={isLoading} filters={filters} />
) : (
runs.map((run) => {
const path = v3RunPath(organization, project, run);
const path = v3RunSpanPath(organization, project, run, { spanId: run.spanId });
const usernameForEnv =
currentUser.id !== run.environment.userId ? run.environment.userName : undefined;
return (
@@ -0,0 +1,32 @@
import { useCallback, useState } from "react";
import { useOptimisticLocation } from "./useOptimisticLocation";
import type { Location } from "@remix-run/react";
export function useReplaceLocation() {
const optimisticLocation = useOptimisticLocation();
const [location, setLocation] = useState(optimisticLocation);
const replaceLocation = useCallback((location: Location<any>) => {
const fullPath = location.pathname + location.search + location.hash;
//replace the URL in the browser
history.replaceState(null, "", fullPath);
//update the state (new object in case the same location ref was modified)
const newLocation = { ...location };
setLocation(newLocation);
}, []);
const replaceSearchParam = useCallback(
(key: string, value?: string) => {
const searchParams = new URLSearchParams(location.search);
if (value) {
searchParams.set(key, value);
} else {
searchParams.delete(key);
}
replaceLocation({ ...optimisticLocation, search: "?" + searchParams.toString() });
},
[optimisticLocation, replaceLocation]
);
return { location, replaceLocation, replaceSearchParam };
}
@@ -106,6 +106,7 @@ export class RunListPresenter {
lockedAt: Date | null;
completedAt: Date | null;
isTest: boolean;
spanId: string;
attempts: BigInt;
}[]
>`
@@ -121,6 +122,7 @@ export class RunListPresenter {
tr."lockedAt" AS "lockedAt",
tra."completedAt" AS "completedAt",
tr."isTest" AS "isTest",
tr."spanId" AS "spanId",
COUNT(tra.id) AS attempts
FROM
${sqlDatabaseSchema}."TaskRun" tr
@@ -225,6 +227,7 @@ export class RunListPresenter {
status: run.status,
version: run.version,
taskIdentifier: run.taskIdentifier,
spanId: run.spanId,
attempts: Number(run.attempts),
isReplayable: true,
isCancellable: CANCELLABLE_STATUSES.includes(run.status),
@@ -60,7 +60,7 @@ export default function Page() {
const user = useUser();
return (
<>
<div className="overflow-y-auto scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-600">
{job.hasIntegrationsRequiringAction && (
<Callout variant="error" to={organizationIntegrationsPath(organization)} className="mb-2">
{simplur`This Job has ${
@@ -96,6 +96,6 @@ export default function Page() {
</div>
)}
</Help>
</>
</div>
);
}
@@ -1,10 +1,13 @@
import {
ArrowsPointingInIcon,
ArrowsPointingOutIcon,
ChevronDownIcon,
ChevronRightIcon,
MagnifyingGlassMinusIcon,
MagnifyingGlassPlusIcon,
} from "@heroicons/react/20/solid";
import { Outlet, useNavigate, useParams, useRevalidator } from "@remix-run/react";
import type { Location } from "@remix-run/react";
import { useParams, useRevalidator } from "@remix-run/react";
import { LoaderFunctionArgs } from "@remix-run/server-runtime";
import { Virtualizer } from "@tanstack/react-virtual";
import {
@@ -23,7 +26,7 @@ import { InlineCode } from "~/components/code/InlineCode";
import { EnvironmentLabel } from "~/components/environments/EnvironmentLabel";
import { MainCenteredContainer, PageBody } from "~/components/layout/AppLayout";
import { Badge } from "~/components/primitives/Badge";
import { LinkButton } from "~/components/primitives/Buttons";
import { Button, LinkButton } from "~/components/primitives/Buttons";
import { Callout } from "~/components/primitives/Callout";
import { Input } from "~/components/primitives/Input";
import { NavBar, PageAccessories, PageTitle } from "~/components/primitives/PageHeader";
@@ -33,6 +36,7 @@ import {
ResizablePanel,
ResizablePanelGroup,
} from "~/components/primitives/Resizable";
import { ShortcutKey, variants } from "~/components/primitives/ShortcutKey";
import { Slider } from "~/components/primitives/Slider";
import { Switch } from "~/components/primitives/Switch";
import * as Timeline from "~/components/primitives/Timeline";
@@ -45,8 +49,9 @@ import { useDebounce } from "~/hooks/useDebounce";
import { useEventSource } from "~/hooks/useEventSource";
import { useInitialDimensions } from "~/hooks/useInitialDimensions";
import { useOrganization } from "~/hooks/useOrganizations";
import { usePathName } from "~/hooks/usePathName";
import { useProject } from "~/hooks/useProject";
import { useReplaceLocation } from "~/hooks/useReplaceLocation";
import { Shortcut, useShortcutKeys } from "~/hooks/useShortcutKeys";
import { useUser } from "~/hooks/useUser";
import { RunEvent, RunPresenter } from "~/presenters/v3/RunPresenter.server";
import { getResizableRunSettings, setResizableRunSettings } from "~/services/resizablePanel";
@@ -60,6 +65,11 @@ import {
v3RunStreamingPath,
v3RunsPath,
} from "~/utils/pathBuilder";
import { SpanView } from "../resources.orgs.$organizationSlug.projects.v3.$projectParam.runs.$runParam.spans.$spanParam/route";
import { number } from "zod";
import { useHotkeys } from "react-hotkeys-hook";
import { Popover, PopoverArrowTrigger, PopoverContent } from "~/components/primitives/Popover";
import { Header3 } from "~/components/primitives/Headers";
export const loader = async ({ request, params }: LoaderFunctionArgs) => {
const userId = await requireUserId(request);
@@ -82,19 +92,18 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
});
};
function getSpanId(path: string): string | undefined {
const regex = /spans\/([^\/]*)/;
const match = path.match(regex);
return match ? match[1] : undefined;
function getSpanId(location: Location<any>): string | undefined {
const search = new URLSearchParams(location.search);
return search.get("span") ?? undefined;
}
export default function Page() {
const { run, trace, resizeSettings } = useTypedLoaderData<typeof loader>();
const navigate = useNavigate();
const organization = useOrganization();
const pathName = usePathName();
const project = useProject();
const user = useUser();
const { location, replaceSearchParam } = useReplaceLocation();
const selectedSpanId = getSpanId(location);
const usernameForEnv = user.id !== run.environment.userId ? run.environment.userName : undefined;
@@ -133,10 +142,8 @@ export default function Page() {
const { events, parentRunFriendlyId, duration, rootSpanStatus, rootStartedAt } = trace;
const selectedSpanId = getSpanId(pathName);
const changeToSpan = useDebounce((selectedSpan: string) => {
navigate(v3RunSpanPath(organization, project, run, { spanId: selectedSpan }));
replaceSearchParam("span", selectedSpan);
}, 250);
const revalidator = useRevalidator();
@@ -166,62 +173,47 @@ export default function Page() {
</NavBar>
<PageBody scrollable={false}>
<div className={cn("grid h-full max-h-full grid-cols-1 overflow-hidden")}>
{selectedSpanId === undefined ? (
<TasksTreeView
selectedId={selectedSpanId}
key={events[0]?.id ?? "-"}
events={events}
parentRunFriendlyId={parentRunFriendlyId}
onSelectedIdChanged={(selectedSpan) => {
//instantly close the panel if no span is selected
if (!selectedSpan) {
navigate(v3RunPath(organization, project, run));
return;
}
<ResizablePanelGroup
direction="horizontal"
className="h-full max-h-full"
onLayout={(layout) => {
if (layout.length !== 2) return;
if (!selectedSpanId) return;
setResizableRunSettings(document, layout);
}}
>
<ResizablePanel order={1} minSize={30} defaultSize={resizeSettings.layout?.[0]}>
<TasksTreeView
selectedId={selectedSpanId}
key={events[0]?.id ?? "-"}
events={events}
parentRunFriendlyId={parentRunFriendlyId}
onSelectedIdChanged={(selectedSpan) => {
//instantly close the panel if no span is selected
if (!selectedSpan) {
replaceSearchParam("span");
return;
}
changeToSpan(selectedSpan);
}}
totalDuration={duration}
rootSpanStatus={rootSpanStatus}
rootStartedAt={rootStartedAt}
environmentType={run.environment.type}
/>
) : (
<ResizablePanelGroup
direction="horizontal"
className="h-full max-h-full"
onLayout={(layout) => {
if (layout.length !== 2) return;
setResizableRunSettings(document, layout);
}}
>
<ResizablePanel order={1} minSize={30} defaultSize={resizeSettings.layout?.[0]}>
<TasksTreeView
selectedId={selectedSpanId}
key={events[0]?.id ?? "-"}
events={events}
parentRunFriendlyId={parentRunFriendlyId}
onSelectedIdChanged={(selectedSpan) => {
//instantly close the panel if no span is selected
if (!selectedSpan) {
navigate(v3RunPath(organization, project, run));
return;
}
changeToSpan(selectedSpan);
}}
totalDuration={duration}
rootSpanStatus={rootSpanStatus}
rootStartedAt={rootStartedAt}
environmentType={run.environment.type}
changeToSpan(selectedSpan);
}}
totalDuration={duration}
rootSpanStatus={rootSpanStatus}
rootStartedAt={rootStartedAt}
environmentType={run.environment.type}
/>
</ResizablePanel>
<ResizableHandle withHandle />
{selectedSpanId && (
<ResizablePanel order={2} minSize={30} defaultSize={resizeSettings.layout?.[1]}>
<SpanView
runParam={run.friendlyId}
spanId={selectedSpanId}
closePanel={() => replaceSearchParam("span")}
/>
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel order={2} minSize={30} defaultSize={resizeSettings.layout?.[1]}>
<Outlet key={selectedSpanId} />
</ResizablePanel>
</ResizablePanelGroup>
)}
)}
</ResizablePanelGroup>
</div>
</PageBody>
</>
@@ -263,6 +255,9 @@ function TasksTreeView({
getNodeProps,
toggleNodeSelection,
toggleExpandNode,
expandAllBelowDepth,
toggleExpandLevel,
collapseAllBelowDepth,
selectNode,
scrollToNode,
virtualizer,
@@ -286,7 +281,7 @@ function TasksTreeView({
});
return (
<div className="grid h-full grid-rows-[2.5rem_1fr] overflow-hidden">
<div className="grid h-full grid-rows-[2.5rem_1fr_3.25rem] overflow-hidden">
<div className="mx-3 flex items-center justify-between gap-2 border-b border-grid-dimmed">
<Input
placeholder="Search log"
@@ -297,30 +292,12 @@ function TasksTreeView({
onChange={(e) => setFilterText(e.target.value)}
/>
<div className="flex items-center gap-2">
<LiveReloadingStatus rootSpanCompleted={rootSpanStatus !== "executing"} />
<Switch
variant="small"
label="Errors only"
checked={errorsOnly}
onCheckedChange={(e) => setErrorsOnly(e.valueOf())}
/>
<Switch
variant="small"
label="Show durations"
checked={showDurations}
onCheckedChange={(e) => setShowDurations(e.valueOf())}
/>
<Slider
variant={"tertiary"}
className="w-20"
LeadingIcon={MagnifyingGlassMinusIcon}
TrailingIcon={MagnifyingGlassPlusIcon}
value={[scale]}
onValueChange={(value) => setScale(value[0])}
min={0}
max={1}
step={0.05}
/>
</div>
</div>
<ResizablePanelGroup
@@ -333,14 +310,15 @@ function TasksTreeView({
{/* Tree list */}
<ResizablePanel order={1} minSize={20} defaultSize={50} className="pl-3">
<div className="grid h-full grid-rows-[2rem_1fr] overflow-hidden">
<div className="flex items-center">
<div className="flex items-center pr-2">
{parentRunFriendlyId ? (
<ShowParentLink runFriendlyId={parentRunFriendlyId} />
) : (
<Paragraph variant="small" className="text-charcoal-500">
<Paragraph variant="small" className="flex-1 text-charcoal-500">
This is the root task
</Paragraph>
)}
<LiveReloadingStatus rootSpanCompleted={rootSpanStatus !== "executing"} />
</div>
<TreeView
parentRef={parentRef}
@@ -355,13 +333,13 @@ function TasksTreeView({
<>
<div
className={cn(
"delay-[25ms] flex h-8 cursor-pointer items-center overflow-hidden rounded-l-sm pr-2 transition-colors",
"flex h-8 cursor-pointer items-center overflow-hidden rounded-l-sm pr-2",
state.selected
? "bg-grid-dimmed hover:bg-grid-bright"
: "bg-transparent hover:bg-grid-dimmed"
)}
onClick={() => {
toggleNodeSelection(node.id);
selectNode(node.id);
}}
>
<div className="flex h-8 items-center">
@@ -379,7 +357,15 @@ function TasksTreeView({
)}
onClick={(e) => {
e.stopPropagation();
toggleExpandNode(node.id);
if (e.altKey) {
if (state.expanded) {
collapseAllBelowDepth(node.level);
} else {
expandAllBelowDepth(node.level);
}
} else {
toggleExpandNode(node.id);
}
scrollToNode(node.id);
}}
>
@@ -445,6 +431,50 @@ function TasksTreeView({
/>
</ResizablePanel>
</ResizablePanelGroup>
<div className="flex items-center justify-between gap-2 border-t border-grid-dimmed px-2">
<div className="grow @container">
<div className="hidden items-center gap-4 @[42rem]:flex">
<KeyboardShortcuts
expandAllBelowDepth={expandAllBelowDepth}
collapseAllBelowDepth={collapseAllBelowDepth}
toggleExpandLevel={toggleExpandLevel}
setShowDurations={setShowDurations}
/>
</div>
<div className="@[42rem]:hidden">
<Popover>
<PopoverArrowTrigger>Shortcuts</PopoverArrowTrigger>
<PopoverContent
className="min-w-[20rem] overflow-y-auto p-2 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-600"
align="start"
>
<Header3 spacing>Keyboard shortcuts</Header3>
<div className="flex flex-col gap-2">
<KeyboardShortcuts
expandAllBelowDepth={expandAllBelowDepth}
collapseAllBelowDepth={collapseAllBelowDepth}
toggleExpandLevel={toggleExpandLevel}
setShowDurations={setShowDurations}
/>
</div>
</PopoverContent>
</Popover>
</div>
</div>
<div className="flex items-center gap-4">
<Slider
variant={"tertiary"}
className="w-20"
LeadingIcon={MagnifyingGlassMinusIcon}
TrailingIcon={MagnifyingGlassPlusIcon}
value={[scale]}
onValueChange={(value) => setScale(value[0])}
min={0}
max={1}
step={0.05}
/>
</div>
</div>
</div>
);
}
@@ -738,6 +768,7 @@ function ShowParentLink({ runFriendlyId }: { runFriendlyId: string }) {
fullWidth
textAlignLeft
shortcut={{ key: "p" }}
className="flex-1"
>
{mouseOver ? (
<ShowParentIconSelected className="h-4 w-4 text-indigo-500" />
@@ -884,3 +915,92 @@ function ConnectedDevWarning() {
</div>
);
}
function KeyboardShortcuts({
expandAllBelowDepth,
collapseAllBelowDepth,
toggleExpandLevel,
setShowDurations,
}: {
expandAllBelowDepth: (depth: number) => void;
collapseAllBelowDepth: (depth: number) => void;
toggleExpandLevel: (depth: number) => void;
setShowDurations: (show: (show: boolean) => boolean) => void;
}) {
return (
<>
<ArrowKeyShortcuts />
<ShortcutWithAction
shortcut={{ key: "e" }}
action={() => expandAllBelowDepth(0)}
title="Expand all"
/>
<ShortcutWithAction
shortcut={{ key: "c" }}
action={() => collapseAllBelowDepth(1)}
title="Collapse all"
/>
<NumberShortcuts toggleLevel={(number) => toggleExpandLevel(number)} />
<ShortcutWithAction
shortcut={{ key: "d" }}
action={() => setShowDurations((d) => !d)}
title="Toggle durations"
/>
</>
);
}
function ArrowKeyShortcuts() {
return (
<div className="flex items-center gap-0.5">
<ShortcutKey shortcut={{ key: "arrowup" }} variant="medium" className="ml-0 mr-0" />
<ShortcutKey shortcut={{ key: "arrowdown" }} variant="medium" className="ml-0 mr-0" />
<ShortcutKey shortcut={{ key: "arrowleft" }} variant="medium" className="ml-0 mr-0" />
<ShortcutKey shortcut={{ key: "arrowright" }} variant="medium" className="ml-0 mr-0" />
<Paragraph variant="extra-small" className="ml-1.5 whitespace-nowrap">
Navigate
</Paragraph>
</div>
);
}
function ShortcutWithAction({
shortcut,
title,
action,
}: {
shortcut: Shortcut;
title: string;
action: () => void;
}) {
useShortcutKeys({
shortcut,
action,
});
return (
<div className="flex items-center gap-0.5">
<ShortcutKey shortcut={shortcut} variant="medium" className="ml-0 mr-0" />
<Paragraph variant="extra-small" className="ml-1.5 whitespace-nowrap">
{title}
</Paragraph>
</div>
);
}
function NumberShortcuts({ toggleLevel }: { toggleLevel: (depth: number) => void }) {
useHotkeys(["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"], (event, hotkeysEvent) => {
toggleLevel(Number(event.key));
});
return (
<div className="flex items-center gap-0.5">
<span className={cn(variants.medium, "ml-0 mr-0")}>0</span>
<span className="text-[0.75rem] text-text-dimmed"></span>
<span className={cn(variants.medium, "ml-0 mr-0")}>9</span>
<Paragraph variant="extra-small" className="ml-1.5 whitespace-nowrap">
Toggle level
</Paragraph>
</div>
);
}
@@ -6,7 +6,6 @@ import { ActionFunction, LoaderFunctionArgs, json } from "@remix-run/server-runt
import { TaskRunStatus } from "@trigger.dev/database";
import { useCallback, useEffect, useRef, useState } from "react";
import { typedjson, useTypedLoaderData } from "remix-typedjson";
import { z } from "zod";
import { JSONEditor } from "~/components/code/JSONEditor";
import { EnvironmentLabel } from "~/components/environments/EnvironmentLabel";
import { Button } from "~/components/primitives/Buttons";
@@ -37,7 +36,7 @@ import {
TestTaskPresenter,
} from "~/presenters/v3/TestTaskPresenter.server";
import { requireUserId } from "~/services/session.server";
import { docsPath, v3RunPath, v3TaskParamsSchema } from "~/utils/pathBuilder";
import { docsPath, v3RunSpanPath, v3TaskParamsSchema } from "~/utils/pathBuilder";
import { TestTaskService } from "~/v3/services/testTask.server";
import { TestTaskData } from "~/v3/testTask";
@@ -77,7 +76,12 @@ export const action: ActionFunction = async ({ request, params }) => {
}
return redirectWithSuccessMessage(
v3RunPath({ slug: organizationSlug }, { slug: projectParam }, { friendlyId: run.friendlyId }),
v3RunSpanPath(
{ slug: organizationSlug },
{ slug: projectParam },
{ friendlyId: run.friendlyId },
{ spanId: run.spanId }
),
request,
"Test run created"
);
@@ -2,6 +2,7 @@ import { LoaderFunctionArgs, redirect } from "@remix-run/server-runtime";
import { z } from "zod";
import { prisma } from "~/db.server";
import { requireUserId } from "~/services/session.server";
import { v3RunSpanPath } from "~/utils/pathBuilder";
const ParamsSchema = z.object({
projectRef: z.string(),
@@ -33,8 +34,20 @@ export async function loader({ params, request }: LoaderFunctionArgs) {
return new Response("Not found", { status: 404 });
}
const run = await prisma.taskRun.findUnique({
where: {
friendlyId: validatedParams.runParam,
},
});
if (!run) {
throw new Response("Not found", { status: 404 });
}
// Redirect to the project's runs page
return redirect(
`/orgs/${project.organization.slug}/projects/v3/${project.slug}/runs/${validatedParams.runParam}`
v3RunSpanPath({ slug: project.organization.slug }, { slug: project.slug }, run, {
spanId: run.spanId,
})
);
}
@@ -4,10 +4,11 @@ import {
QueueListIcon,
StopCircleIcon,
} from "@heroicons/react/20/solid";
import { useParams } from "@remix-run/react";
import { useFetcher, useParams } from "@remix-run/react";
import { LoaderFunctionArgs } from "@remix-run/server-runtime";
import { formatDurationNanoseconds, nanosecondsToMilliseconds } from "@trigger.dev/core/v3";
import { typedjson, useTypedLoaderData } from "remix-typedjson";
import { useEffect } from "react";
import { typedjson, useTypedFetcher, useTypedLoaderData } from "remix-typedjson";
import { ExitIcon } from "~/assets/icons/ExitIcon";
import { CodeBlock } from "~/components/code/CodeBlock";
import { EnvironmentLabel } from "~/components/environments/EnvironmentLabel";
@@ -17,6 +18,7 @@ import { Dialog, DialogTrigger } from "~/components/primitives/Dialog";
import { Header2 } from "~/components/primitives/Headers";
import { Paragraph } from "~/components/primitives/Paragraph";
import { Property, PropertyTable } from "~/components/primitives/PropertyTable";
import { Spinner } from "~/components/primitives/Spinner";
import { CancelRunDialog } from "~/components/runs/v3/CancelRunDialog";
import { LiveTimer } from "~/components/runs/v3/LiveTimer";
import { ReplayRunDialog } from "~/components/runs/v3/ReplayRunDialog";
@@ -58,19 +60,57 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
return typedjson({ span });
};
export default function Page() {
const {
span: { event },
} = useTypedLoaderData<typeof loader>();
export function SpanView({
runParam,
spanId,
closePanel,
}: {
runParam: string;
spanId: string | undefined;
closePanel: () => void;
}) {
const organization = useOrganization();
const project = useProject();
const { runParam } = useParams();
const fetcher = useTypedFetcher<typeof loader>();
useEffect(() => {
if (spanId === undefined) return;
fetcher.load(
`/resources/orgs/${organization.slug}/projects/v3/${project.slug}/runs/${runParam}/spans/${spanId}`
);
}, [organization.slug, project.slug, runParam, spanId]);
if (spanId === undefined) {
return null;
}
if (fetcher.state !== "idle" || fetcher.data === undefined) {
return (
<div
className={cn(
"grid h-full max-h-full grid-rows-[2.5rem_1fr] overflow-hidden bg-background-bright"
)}
>
<div className="mx-3 flex items-center gap-2 overflow-x-hidden border-b border-grid-dimmed">
<div className="size-4 bg-grid-dimmed" />
<div className="h-6 w-[60%] bg-grid-dimmed" />
</div>
<div className="flex items-center justify-center">
<Spinner />
</div>
</div>
);
}
const {
span: { event },
} = fetcher.data;
return (
<div
className={cn(
"grid h-full max-h-full overflow-hidden bg-background-bright",
event.showActionBar ? "grid-rows-[2.5rem_1fr_2.5rem]" : "grid-rows-[2.5rem_1fr]"
event.showActionBar ? "grid-rows-[2.5rem_1fr_3.25rem]" : "grid-rows-[2.5rem_1fr]"
)}
>
<div className="mx-3 flex items-center justify-between gap-2 overflow-x-hidden border-b border-grid-dimmed">
@@ -85,8 +125,8 @@ export default function Page() {
</Header2>
</div>
{runParam && (
<LinkButton
to={v3RunPath(organization, project, { friendlyId: runParam })}
<Button
onClick={closePanel}
variant="minimal/medium"
LeadingIcon={ExitIcon}
shortcut={{ key: "esc" }}
@@ -188,7 +228,7 @@ export default function Page() {
{ friendlyId: event.runId },
{ spanId: event.spanId }
)}
variant="minimal/small"
variant="minimal/medium"
LeadingIcon={QueueListIcon}
shortcut={{ key: "f" }}
>
@@ -216,7 +256,7 @@ function RunActionButtons({ span }: { span: Span }) {
return (
<Dialog>
<DialogTrigger asChild>
<Button variant="danger/small" LeadingIcon={StopCircleIcon}>
<Button variant="danger/medium" LeadingIcon={StopCircleIcon}>
Cancel run
</Button>
</DialogTrigger>
@@ -236,7 +276,7 @@ function RunActionButtons({ span }: { span: Span }) {
return (
<Dialog>
<DialogTrigger asChild>
<Button variant="tertiary/small" LeadingIcon={ArrowPathIcon}>
<Button variant="tertiary/medium" LeadingIcon={ArrowPathIcon}>
Replay run
</Button>
</DialogTrigger>
@@ -4,7 +4,7 @@ import { z } from "zod";
import { prisma } from "~/db.server";
import { redirectWithErrorMessage, redirectWithSuccessMessage } from "~/models/message.server";
import { logger } from "~/services/logger.server";
import { v3RunPath } from "~/utils/pathBuilder";
import { v3RunSpanPath } from "~/utils/pathBuilder";
import { ReplayTaskRunService } from "~/v3/services/replayTaskRun.server";
const FormSchema = z.object({
@@ -54,12 +54,13 @@ export const action: ActionFunction = async ({ request, params }) => {
);
}
const runPath = v3RunPath(
const runPath = v3RunSpanPath(
{
slug: taskRun.project.organization.slug,
},
{ slug: taskRun.project.slug },
{ friendlyId: newRun.friendlyId }
{ friendlyId: newRun.friendlyId },
{ spanId: newRun.spanId }
);
return redirectWithSuccessMessage(runPath, request, `Replaying run`);
+1 -3
View File
@@ -14,8 +14,6 @@ import { Job } from "~/models/job.server";
import type { Organization } from "~/models/organization.server";
import type { Project } from "~/models/project.server";
import { objectToSearchParams } from "./searchParams";
import { ScheduleListFilters } from "~/components/runs/v3/ScheduleFilters";
import { useLocation } from "@remix-run/react";
export type OrgForPath = Pick<Organization, "slug">;
export type ProjectForPath = Pick<Project, "slug">;
@@ -368,7 +366,7 @@ export function v3RunSpanPath(
run: v3RunForPath,
span: v3SpanForPath
) {
return `${v3RunPath(organization, project, run)}/spans/${span.spanId}`;
return `${v3RunPath(organization, project, run)}?span=${span.spanId}`;
}
export function v3TraceSpanPath(
+2
View File
@@ -2,6 +2,8 @@
The CLI `dev` command runs a server for your tasks. It will watches for changes in your `/trigger` directory and communicates with the Trigger.dev platform to register your tasks, perform runs, and send data back and forth.
It can also update your `@trigger.dev/*` packages to prevent version mismatches and failed deploys. You will always be prompted first.
<CodeGroup>
```bash npm
+8 -5
View File
@@ -21,13 +21,16 @@ yarn dlx trigger.dev@beta deploy
</CodeGroup>
<Warning>Will fail in CI if any version mismatches are detected. Ensure everything runs locally first using the [dev](/v3/cli-dev) command and don't bypass the version checks!</Warning>
It performs a few steps to deploy:
1. Typechecks the code.
2. Compiles and bundles the code.
3. Checks that [environment variables](/v3/deploy-environment-variables) are set.
4. Deploys the code to the cloud.
5. Registers the tasks as a new version in the environment (prod by default).
1. Optionally updates packages when running locally.
2. Typechecks the code.
3. Compiles and bundles the code.
4. Checks that [environment variables](/v3/deploy-environment-variables) are set.
5. Deploys the code to the cloud.
6. Registers the tasks as a new version in the environment (prod by default).
## Options
+2
View File
@@ -21,6 +21,8 @@ yarn dlx trigger.dev@beta dev
</CodeGroup>
It will first perform an update check to prevent version mismatches, failed deploys, and other errors. You will always be prompted first.
You will see in the terminal that the server is running and listening for requests. When you run a task, you will see it in the terminal along with a link to view it in the dashboard.
It is worth noting that each task runs in a separate Node process. This means that if you have a long-running task, it will not block other tasks from running.
+18
View File
@@ -5,6 +5,8 @@ description: "You can easily deploy your tasks with GitHub actions."
This simple GitHub action file will deploy you Trigger.dev tasks when new code is pushed to the `main` branch and the `trigger` directory has changes in it.
<Warning>The deploy step will fail if any version mismatches are detected. Please see the [version pinning](/v3/github-actions#version-pinning) section for more details.</Warning>
```yaml .github/workflows/release-trigger.yml
name: Deploy to Trigger.dev
@@ -42,3 +44,19 @@ If you already have a GitHub action file, you can just add the final step "🚀
You need to add the `TRIGGER_ACCESS_TOKEN` secret to your repository. You can create a new access token by going to your profile page and then clicking on the "Personal Access Tokens" tab.
To set it in GitHub go to your repository, click on "Settings", "Secrets and variables" and then "Actions". Add a new secret with the name `TRIGGER_ACCESS_TOKEN` and use the value of your access token.
## Version pinning
The CLI and `@trigger.dev/*` package versions need to be in sync, otherwise there will be errors and unpredictable behavior. Hence, the `deploy` command will automatically fail during CI on any version mismatches.
To ensure a smooth CI experience you can pin the CLI version in the deploy step, like so:
```yaml .github/workflows/release-trigger.yml
- name: 🚀 Deploy Trigger.dev
env:
TRIGGER_ACCESS_TOKEN: ${{ secrets.TRIGGER_ACCESS_TOKEN }}
run: |
npx trigger.dev@3.0.0-beta.16 deploy
```
You should use the version you run locally during dev and manual deploy. The current version is displayed in the banner, but you can also check it by appending `--version` to any command.
+20 -2
View File
@@ -53,7 +53,7 @@ export const config: TriggerConfig = {
## ESM-only packages
We'll let you know when run the CLI dev command if this is a problem. Some packages are ESM-only so they don't work directly from CJS when using Node.js. In that case you need to add them to the `dependenciesToBundle` array in your `trigger.config.ts` file.
We'll let you know when running the CLI dev command if this is a problem. Some packages are ESM-only so they don't work directly from CJS when using Node.js. In that case you need to add them to the `dependenciesToBundle` array in your `trigger.config.ts` file.
```ts trigger.config.ts
import type { TriggerConfig } from "@trigger.dev/sdk/v3";
@@ -92,7 +92,10 @@ Prisma works by generating a client from your `prisma.schema` file. This means y
<Step title="package.json postinstall `prisma generate`">
```json
<CodeGroup>
```json default path
{
"scripts": {
"postinstall": "prisma generate"
@@ -100,6 +103,16 @@ Prisma works by generating a client from your `prisma.schema` file. This means y
}
```
```json custom path
{
"scripts": {
"postinstall": "prisma generate --schema=./custom/path/to/schema.prisma"
}
}
```
</CodeGroup>
Anything you put in `postinstall` will be run as part of the install step. This is how Next.js recommends you set up Prisma anyway.
</Step>
@@ -111,7 +124,12 @@ Prisma works by generating a client from your `prisma.schema` file. This means y
export const config: TriggerConfig = {
//..other stuff
// using the default path
additionalFiles: ["./prisma/schema.prisma"],
// or a custom path, for example in a monorepo
additionalFiles: ["../../custom/path/to/schema.prisma"],
additionalPackages: ["prisma@5.11.0"],
};
```
+1 -19
View File
@@ -171,25 +171,7 @@ async function yourBackendFunction() {
## Upgrading your project
<Steps>
<Step title="Upgrade the v2 Trigger.dev packages">
You can run this command to upgrade all the packages to the beta:
```bash
npx @trigger.dev/cli@beta update --to beta
```
</Step>
<Step title="Follow the v3 quick start">
Follow the [v3 quick start](/v3/quick-start) to get started with v3.
</Step>
</Steps>
Just follow the [v3 quick start](/v3/quick-start) to get started with v3. Our new CLI will take care of the rest.
## Using v2 together with v3
+14
View File
@@ -1,5 +1,19 @@
# @trigger.dev/airtable
## 3.0.0-beta.17
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.17
- @trigger.dev/sdk@3.0.0-beta.17
## 3.0.0-beta.16
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.16
- @trigger.dev/sdk@3.0.0-beta.16
## 3.0.0-beta.15
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/airtable",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "Trigger.dev integration for airtable",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -25,8 +25,8 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.15",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.15",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.17",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.17",
"airtable": "^0.12.1",
"zod": "3.22.3"
},
+14
View File
@@ -1,5 +1,19 @@
# @trigger.dev/github
## 3.0.0-beta.17
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.17
- @trigger.dev/sdk@3.0.0-beta.17
## 3.0.0-beta.16
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.16
- @trigger.dev/sdk@3.0.0-beta.16
## 3.0.0-beta.15
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/github",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "The official GitHub integration for Trigger.dev",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -30,8 +30,8 @@
"@octokit/request-error": "^5.0.1",
"@octokit/webhooks": "^12.0.10",
"octokit": "^3.1.2",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.15",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.15",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.17",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.17",
"zod": "3.22.3"
},
"engines": {
+14
View File
@@ -1,5 +1,19 @@
# @trigger.dev/linear
## 3.0.0-beta.17
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.17
- @trigger.dev/sdk@3.0.0-beta.17
## 3.0.0-beta.16
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.16
- @trigger.dev/sdk@3.0.0-beta.16
## 3.0.0-beta.15
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/linear",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "Trigger.dev integration for @linear/sdk",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -26,8 +26,8 @@
},
"dependencies": {
"@linear/sdk": "^8.0.0",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.15",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.15",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.17",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.17",
"zod": "3.22.3"
},
"engines": {
+14
View File
@@ -1,5 +1,19 @@
# @trigger.dev/slack
## 3.0.0-beta.17
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.17
- @trigger.dev/sdk@3.0.0-beta.17
## 3.0.0-beta.16
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.16
- @trigger.dev/sdk@3.0.0-beta.16
## 3.0.0-beta.15
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/openai",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "The official OpenAI integration for Trigger.dev",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -42,8 +42,8 @@
},
"dependencies": {
"openai": "^4.16.1",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.15",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.15"
"@trigger.dev/sdk": "workspace:^3.0.0-beta.17",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.17"
},
"engines": {
"node": ">=18.0.0"
+14
View File
@@ -1,5 +1,19 @@
# @trigger.dev/plain
## 3.0.0-beta.17
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.17
- @trigger.dev/sdk@3.0.0-beta.17
## 3.0.0-beta.16
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.16
- @trigger.dev/sdk@3.0.0-beta.16
## 3.0.0-beta.15
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/plain",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "The official Plain.com integration for Trigger.dev",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -24,8 +24,8 @@
"build:tsup": "tsup"
},
"dependencies": {
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.15",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.15",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.17",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.17",
"@team-plain/typescript-sdk": "^2.7.0"
},
"engines": {
+14
View File
@@ -1,5 +1,19 @@
# @trigger.dev/replicate
## 3.0.0-beta.17
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.17
- @trigger.dev/sdk@3.0.0-beta.17
## 3.0.0-beta.16
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.16
- @trigger.dev/sdk@3.0.0-beta.16
## 3.0.0-beta.15
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/replicate",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "Trigger.dev integration for replicate",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -25,8 +25,8 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.15",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.15",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.17",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.17",
"replicate": "^0.18.1",
"zod": "3.22.3"
},
+14
View File
@@ -1,5 +1,19 @@
# @trigger.dev/resend
## 3.0.0-beta.17
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.17
- @trigger.dev/sdk@3.0.0-beta.17
## 3.0.0-beta.16
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.16
- @trigger.dev/sdk@3.0.0-beta.16
## 3.0.0-beta.15
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/resend",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "The official Resend.com integration for Trigger.dev",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -24,8 +24,8 @@
"build:tsup": "tsup"
},
"dependencies": {
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.15",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.15",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.17",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.17",
"resend": "^2.1.0"
},
"engines": {
+14
View File
@@ -1,5 +1,19 @@
# @trigger.dev/sendgrid
## 3.0.0-beta.17
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.17
- @trigger.dev/sdk@3.0.0-beta.17
## 3.0.0-beta.16
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.16
- @trigger.dev/sdk@3.0.0-beta.16
## 3.0.0-beta.15
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/sendgrid",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "Trigger.dev integration for @sendgrid/mail",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -26,8 +26,8 @@
},
"dependencies": {
"@sendgrid/mail": "^7.7.0",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.15",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.15"
"@trigger.dev/sdk": "workspace:^3.0.0-beta.17",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.17"
},
"engines": {
"node": ">=16.8.0"
+14
View File
@@ -1,5 +1,19 @@
# @trigger.dev/shopify
## 3.0.0-beta.17
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.17
- @trigger.dev/sdk@3.0.0-beta.17
## 3.0.0-beta.16
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.16
- @trigger.dev/sdk@3.0.0-beta.16
## 3.0.0-beta.15
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/shopify",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "Trigger.dev integration for @shopify/shopify-api",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -26,8 +26,8 @@
},
"dependencies": {
"@shopify/shopify-api": "^8.0.2",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.15",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.15",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.17",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.17",
"zod": "3.22.3"
},
"engines": {
+12
View File
@@ -1,5 +1,17 @@
# @trigger.dev/slack
## 3.0.0-beta.17
### Patch Changes
- @trigger.dev/sdk@3.0.0-beta.17
## 3.0.0-beta.16
### Patch Changes
- @trigger.dev/sdk@3.0.0-beta.16
## 3.0.0-beta.15
### Patch Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/slack",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "The official Slack integration for Trigger.dev",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -25,7 +25,7 @@
},
"dependencies": {
"@slack/web-api": "^6.8.1",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.15",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.17",
"zod": "3.22.3"
},
"engines": {
+14
View File
@@ -1,5 +1,19 @@
# @trigger.dev/stripe
## 3.0.0-beta.17
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.17
- @trigger.dev/sdk@3.0.0-beta.17
## 3.0.0-beta.16
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.16
- @trigger.dev/sdk@3.0.0-beta.16
## 3.0.0-beta.15
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/stripe",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "Trigger.dev integration for stripe",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -25,8 +25,8 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.15",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.15",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.17",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.17",
"stripe": "^12.14.0",
"zod": "3.22.3"
},
+14
View File
@@ -1,5 +1,19 @@
# @trigger.dev/supabase
## 3.0.0-beta.17
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.17
- @trigger.dev/sdk@3.0.0-beta.17
## 3.0.0-beta.16
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.16
- @trigger.dev/sdk@3.0.0-beta.16
## 3.0.0-beta.15
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/supabase",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "Trigger.dev integration for @supabase/supabase-js",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -26,8 +26,8 @@
},
"dependencies": {
"@supabase/supabase-js": "^2.26.0",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.15",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.15",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.17",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.17",
"supabase-management-js": "^1.0.0",
"zod": "3.22.3"
},
+14
View File
@@ -1,5 +1,19 @@
# @trigger.dev/typeform
## 3.0.0-beta.17
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.17
- @trigger.dev/sdk@3.0.0-beta.17
## 3.0.0-beta.16
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.16
- @trigger.dev/sdk@3.0.0-beta.16
## 3.0.0-beta.15
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/typeform",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "The official Typeform integration for Trigger.dev",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -24,8 +24,8 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.15",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.15",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.17",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.17",
"@typeform/api-client": "^1.8.0",
"zod": "3.22.3"
},
+12
View File
@@ -1,5 +1,17 @@
# @trigger.dev/astro
## 3.0.0-beta.17
### Patch Changes
- @trigger.dev/sdk@3.0.0-beta.17
## 3.0.0-beta.16
### Patch Changes
- @trigger.dev/sdk@3.0.0-beta.16
## 3.0.0-beta.15
### Patch Changes
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@trigger.dev/astro",
"description": "An Astro-native integration for Trigger.dev background jobs platform",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"files": [
@@ -20,7 +20,7 @@
"build:tsup": "tsup"
},
"peerDependencies": {
"@trigger.dev/sdk": "workspace:^3.0.0-beta.15"
"@trigger.dev/sdk": "workspace:^3.0.0-beta.17"
},
"devDependencies": {
"astro": "^3.0.12",
+18
View File
@@ -1,5 +1,23 @@
# trigger.dev
## 3.0.0-beta.17
### Patch Changes
- b20760173: v3 CLI update command and package manager detection fix
- @trigger.dev/core@3.0.0-beta.17
## 3.0.0-beta.16
### Patch Changes
- ed2a26c86: - Fix additionalFiles that aren't decendants
- Stop swallowing uncaught exceptions in prod
- Improve warnings and errors, fail early on critical warnings
- New arg to --save-logs even for successful builds
- Updated dependencies [ed2a26c86]
- @trigger.dev/core@3.0.0-beta.16
## 3.0.0-beta.15
### Patch Changes
+2 -3
View File
@@ -1,6 +1,6 @@
{
"name": "trigger.dev",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "A Command-Line Interface for Trigger.dev (v3) projects",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -85,7 +85,7 @@
"@opentelemetry/sdk-trace-base": "^1.22.0",
"@opentelemetry/sdk-trace-node": "^1.22.0",
"@opentelemetry/semantic-conventions": "^1.22.0",
"@trigger.dev/core": "workspace:^3.0.0-beta.15",
"@trigger.dev/core": "workspace:^3.0.0-beta.17",
"@types/degit": "^2.8.3",
"chalk": "^5.2.0",
"chokidar": "^3.5.3",
@@ -106,7 +106,6 @@
"mock-fs": "^5.2.0",
"nanoid": "^4.0.2",
"node-fetch": "^3.3.0",
"npm-check-updates": "^16.12.2",
"object-hash": "^3.0.0",
"p-debounce": "^4.0.0",
"p-throttle": "^6.1.0",
+2
View File
@@ -8,6 +8,7 @@ import { configureWhoamiCommand } from "../commands/whoami.js";
import { COMMAND_NAME } from "../consts.js";
import { getVersion } from "../utilities/getVersion.js";
import { configureListProfilesCommand } from "../commands/list-profiles.js";
import { configureUpdateCommand } from "../commands/update.js";
export const program = new Command();
@@ -23,3 +24,4 @@ configureDeployCommand(program);
configureWhoamiCommand(program);
configureLogoutCommand(program);
configureListProfilesCommand(program);
configureUpdateCommand(program);
+326 -31
View File
@@ -43,7 +43,7 @@ import { logger } from "../utilities/logger.js";
import { createTaskFileImports, gatherTaskFiles } from "../utilities/taskFiles";
import { login } from "./login";
import { Glob } from "glob";
import { Glob, GlobOptions } from "glob";
import type { SetOptional } from "type-fest";
import { bundleDependenciesPlugin, workerSetupImportConfigPlugin } from "../utilities/build";
import { chalkError, chalkPurple, chalkWarning } from "../utilities/cliOutput";
@@ -57,6 +57,8 @@ import { safeJsonParse } from "../utilities/safeJsonParse";
import { JavascriptProject } from "../utilities/javascriptProject";
import { cliRootPath } from "../utilities/resolveInternalFilePath";
import { escapeImportPath, spinner } from "../utilities/windows";
import { updateTriggerPackages } from "./update";
import { docs, getInTouch } from "../utilities/links";
const DeployCommandOptions = CommonCommandOptions.extend({
skipTypecheck: z.boolean().default(false),
@@ -72,6 +74,8 @@ const DeployCommandOptions = CommonCommandOptions.extend({
projectRef: z.string().optional(),
outputMetafile: z.string().optional(),
apiUrl: z.string().optional(),
saveLogs: z.boolean().default(false),
skipUpdateCheck: z.boolean().default(false),
});
type DeployCommandOptions = z.infer<typeof DeployCommandOptions>;
@@ -88,6 +92,7 @@ export function configureDeployCommand(program: Command) {
"prod"
)
.option("--skip-typecheck", "Whether to skip the pre-build typecheck")
.option("--skip-update-check", "Skip checking for @trigger.dev package updates")
.option(
"--ignore-env-var-check",
"Detected missing environment variables won't block deployment"
@@ -140,6 +145,12 @@ export function configureDeployCommand(program: Command) {
"If provided, will save the esbuild metafile for the build to the specified path"
).hideHelp()
)
.addOption(
new CommandOption(
"--save-logs",
"If provided, will save logs even for successful builds"
).hideHelp()
)
.action(async (path, options) => {
await handleTelemetry(async () => {
await printStandloneInitialBanner(true);
@@ -159,6 +170,10 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) {
intro("Deploying project");
if (!options.skipUpdateCheck) {
await updateTriggerPackages(dir, { ...options }, true, true);
}
const authorization = await login({
embedded: true,
defaultApiUrl: options.apiUrl,
@@ -306,25 +321,42 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) {
const image = await buildImage();
const warnings = checkLogsForWarnings(image.logs);
if (!warnings.ok) {
await failDeploy(
deploymentResponse.data.shortCode,
warnings.summary,
image.logs,
deploymentSpinner,
warnings.warnings,
warnings.errors
);
throw new SkipLoggingError(`Failed to build project image: ${warnings.summary}`);
}
if (!image.ok) {
deploymentSpinner.stop(`Failed to build project.`);
// If there are logs, let's write it out to a temporary file and include the path in the error message
if (image.logs.trim() !== "") {
const logPath = join(await createTempDir(), `build-${deploymentResponse.data.shortCode}.log`);
await writeFile(logPath, image.logs);
logger.log(
`${chalkError("X Error:")} ${image.error}. Full build logs have been saved to ${logPath})`
);
} else {
logger.log(`${chalkError("X Error:")} ${image.error}.`);
}
await failDeploy(
deploymentResponse.data.shortCode,
image.error,
image.logs,
deploymentSpinner,
warnings.warnings
);
throw new SkipLoggingError(`Failed to build project image: ${image.error}`);
}
const preExitTasks = async () => {
printWarnings(warnings.warnings);
if (options.saveLogs) {
const logPath = await saveLogs(deploymentResponse.data.shortCode, image.logs);
log.info(`Build logs have been saved to ${logPath}`);
}
};
const imageReference = options.selfHosted
? `${selfHostedRegistryHost ? `${selfHostedRegistryHost}/` : ""}${image.image}${
image.digest ? `@${image.digest}` : ""
@@ -340,6 +372,8 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) {
`Project image built: ${imageReference}. Skipping deployment as requested`
);
await preExitTasks();
throw new SkipCommandError("Skipping deployment as requested");
}
@@ -359,6 +393,8 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) {
if (!startIndexingResponse.success) {
deploymentSpinner.stop(`Failed to start indexing: ${startIndexingResponse.error}`);
await preExitTasks();
throw new SkipLoggingError(`Failed to start indexing: ${startIndexingResponse.error}`);
}
@@ -370,12 +406,16 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) {
if (!finishedDeployment) {
deploymentSpinner.stop(`Deployment failed to complete`);
await preExitTasks();
throw new SkipLoggingError("Deployment failed to complete: unknown issue");
}
if (typeof finishedDeployment === "string") {
deploymentSpinner.stop(`Deployment failed to complete: ${finishedDeployment}`);
await preExitTasks();
throw new SkipLoggingError(`Deployment failed to complete: ${finishedDeployment}`);
}
@@ -386,7 +426,13 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) {
switch (finishedDeployment.status) {
case "DEPLOYED": {
deploymentSpinner.stop("Deployment completed");
if (warnings.warnings.length > 0) {
deploymentSpinner.stop("Deployment completed with warnings");
} else {
deploymentSpinner.stop("Deployment completed");
}
await preExitTasks();
const taskCount = finishedDeployment.worker?.tasks.length ?? 0;
@@ -417,6 +463,8 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) {
logTaskMetadataParseError(parsedError.data.zodIssues, parsedError.data.tasks);
await preExitTasks();
throw new SkipLoggingError(
`Deployment encountered an error: ${finishedDeployment.errorData.name}`
);
@@ -439,6 +487,8 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) {
logESMRequireError(parsedError, resolvedConfig);
}
await preExitTasks();
throw new SkipLoggingError(
`Deployment encountered an error: ${finishedDeployment.errorData.name}`
);
@@ -447,22 +497,189 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) {
`Deployment failed with an unknown error. Please contact eric@trigger.dev for help. ${deploymentLink}`
);
await preExitTasks();
throw new SkipLoggingError("Deployment failed with an unknown error");
}
}
case "CANCELED": {
deploymentSpinner.stop(`Deployment was canceled. ${deploymentLink}`);
await preExitTasks();
throw new SkipLoggingError("Deployment was canceled");
}
case "TIMED_OUT": {
deploymentSpinner.stop(`Deployment timed out. ${deploymentLink}`);
await preExitTasks();
throw new SkipLoggingError("Deployment timed out");
}
}
}
function printErrors(errors?: string[]) {
for (const error of errors ?? []) {
log.error(`${chalkError("Error:")} ${error}`);
}
}
function printWarnings(warnings?: string[]) {
for (const warning of warnings ?? []) {
log.warn(`${chalkWarning("Warning:")} ${warning}`);
}
}
type WarningsCheckReturn =
| {
ok: true;
warnings: string[];
}
| {
ok: false;
summary: string;
errors: string[];
warnings: string[];
};
type LogParserOptions = Array<{
regex: RegExp;
message: string;
shouldFail?: boolean;
}>;
// Try to extract useful warnings from logs. Sometimes we may even want to fail the build. This won't work if the step is cached.
function checkLogsForWarnings(logs: string): WarningsCheckReturn {
const warnings: LogParserOptions = [
{
regex: /prisma:warn We could not find your Prisma schema/,
message: `Prisma generate failed to find the default schema. Did you include it in config.additionalFiles? ${terminalLink(
"Config docs",
docs.config.prisma
)}\nCustom schema paths require a postinstall script like this: \`prisma generate --schema=./custom/path/to/schema.prisma\``,
shouldFail: true,
},
];
const errorMessages: string[] = [];
const warningMessages: string[] = [];
let shouldFail = false;
for (const warning of warnings) {
const matches = logs.match(warning.regex);
if (!matches) {
continue;
}
const message = getMessageFromTemplate(warning.message, matches.groups);
if (warning.shouldFail) {
shouldFail = true;
errorMessages.push(message);
} else {
warningMessages.push(message);
}
}
if (shouldFail) {
return {
ok: false,
summary: "Build succeeded with critical warnings. Will not proceed",
warnings: warningMessages,
errors: errorMessages,
};
}
return {
ok: true,
warnings: warningMessages,
};
}
// Try to extract useful error messages from the logs
function checkLogsForErrors(logs: string) {
const errors: LogParserOptions = [
{
regex: /Error: Provided --schema at (?<schema>.*) doesn't exist/,
message: `Prisma generate failed to find the specified schema at "$schema".\nDid you include it in config.additionalFiles? ${terminalLink(
"Config docs",
docs.config.prisma
)}`,
},
{
regex: /sh: 1: (?<packageOrBinary>.*): not found/,
message: `$packageOrBinary not found\n\nIf it's a package: Include it in ${terminalLink(
"config.additionalPackages",
docs.config.prisma
)}\nIf it's a binary: Please ${terminalLink(
"get in touch",
getInTouch
)} and we'll see what we can do!`,
},
];
for (const error of errors) {
const matches = logs.match(error.regex);
if (!matches) {
continue;
}
const message = getMessageFromTemplate(error.message, matches.groups);
log.error(`${chalkError("Error:")} ${message}`);
break;
}
}
function getMessageFromTemplate(template: string, replacer: RegExpMatchArray["groups"]) {
let message = template;
if (replacer) {
for (const [key, value] of Object.entries(replacer)) {
message = message.replaceAll(`$${key}`, value);
}
}
return message;
}
async function saveLogs(shortCode: string, logs: string) {
const logPath = join(await createTempDir(), `build-${shortCode}.log`);
await writeFile(logPath, logs);
return logPath;
}
async function failDeploy(
shortCode: string,
errorSummary: string,
logs: string,
deploymentSpinner: ReturnType<typeof spinner>,
warnings?: string[],
errors?: string[]
) {
deploymentSpinner.stop(`Failed to deploy project`);
// If there are logs, let's write it out to a temporary file and include the path in the error message
if (logs.trim() !== "") {
const logPath = await saveLogs(shortCode, logs);
printWarnings(warnings);
printErrors(errors);
checkLogsForErrors(logs);
outro(`${chalkError("Error:")} ${errorSummary}. Full build logs have been saved to ${logPath}`);
} else {
outro(`${chalkError("Error:")} ${errorSummary}.`);
}
// TODO: Let platform know so it can fail the deploy with an appropriate error
}
async function checkEnvVars(
envVars: string[],
config: ResolvedConfig,
@@ -944,7 +1161,7 @@ async function compileProject(
"utf-8"
);
const workerSetupPath = join(cliRootPath(), "workers", "dev", "worker-setup.js");
const workerSetupPath = join(cliRootPath(), "workers", "prod", "worker-setup.js");
let workerContents = workerFacade
.replace("__TASKS__", createTaskFileImports(taskFiles))
@@ -1139,9 +1356,22 @@ async function compileProject(
await writeJSONFile(join(tempDir, "package.json"), packageJsonContents);
await copyAdditionalFiles(config, tempDir);
const copyResult = await copyAdditionalFiles(config, tempDir);
compileSpinner.stop("Project built successfully");
if (!copyResult.ok) {
compileSpinner.stop("Project built with warnings");
log.warn(
`No additionalFiles matches for:\n\n${copyResult.noMatches
.map((glob) => `- "${glob}"`)
.join("\n")}\n\nIf this is unexpected you should check your ${terminalLink(
"glob patterns",
"https://github.com/isaacs/node-glob?tab=readme-ov-file#glob-primer"
)} are valid.`
);
} else {
compileSpinner.stop("Project built successfully");
}
const resolvingDependenciesResult = await resolveDependencies(
tempDir,
@@ -1443,11 +1673,24 @@ async function gatherRequiredDependencies(
return Object.fromEntries(Object.entries(dependencies).sort(([a], [b]) => a.localeCompare(b)));
}
async function copyAdditionalFiles(config: ResolvedConfig, tempDir: string) {
type AdditionalFilesReturn =
| {
ok: true;
}
| {
ok: false;
noMatches: string[];
};
async function copyAdditionalFiles(
config: ResolvedConfig,
tempDir: string
): Promise<AdditionalFilesReturn> {
const additionalFiles = config.additionalFiles ?? [];
const noMatches: string[] = [];
if (additionalFiles.length === 0) {
return;
return { ok: true };
}
return await tracer.startActiveSpan(
@@ -1463,25 +1706,77 @@ async function copyAdditionalFiles(config: ResolvedConfig, tempDir: string) {
additionalFiles,
});
const glob = new Glob(additionalFiles, {
const globOptions = {
withFileTypes: true,
ignore: ["node_modules"],
cwd: config.projectDir,
nodir: true,
});
} satisfies GlobOptions;
for await (const file of glob) {
const relativeDestinationPath = join(
tempDir,
relative(config.projectDir, file.fullpath())
);
const globs: Array<GlobOptions> = [];
let i = 0;
logger.debug(`Copying file ${file.fullpath()} to ${relativeDestinationPath}`);
await mkdir(dirname(relativeDestinationPath), { recursive: true });
await copyFile(file.fullpath(), relativeDestinationPath);
for (const additionalFile of additionalFiles) {
let glob: GlobOptions | Glob<typeof globOptions>;
if (i === 0) {
glob = new Glob(additionalFile, globOptions);
} else {
const previousGlob = globs[i - 1];
if (!previousGlob) {
logger.error("No previous glob, this shouldn't happen", { i, additionalFiles });
continue;
}
// Use the previous glob's options and cache
glob = new Glob(additionalFile, previousGlob);
}
if (!(Symbol.asyncIterator in glob)) {
logger.error("Glob should be an async iterator", { glob });
throw new Error("Unrecoverable error while copying additional files");
}
let matches = 0;
for await (const file of glob) {
matches++;
// Any additional files that aren't a child of projectDir will be moved inside tempDir, so they can be part of the build context
// The file "../foo/bar" will be written to "tempDir/foo/bar"
// The file "../../bar/baz" will be written to "tempDir/bar/baz"
const pathInsideTempDir = relative(config.projectDir, file.fullpath())
.split(posix.sep)
.filter((p) => p !== "..")
.join(posix.sep);
const relativeDestinationPath = join(tempDir, pathInsideTempDir);
logger.debug(`Copying file ${file.fullpath()} to ${relativeDestinationPath}`);
await mkdir(dirname(relativeDestinationPath), { recursive: true });
await copyFile(file.fullpath(), relativeDestinationPath);
}
if (matches === 0) {
noMatches.push(additionalFile);
}
globs[i] = glob;
i++;
}
span.end();
if (noMatches.length > 0) {
return {
ok: false,
noMatches,
} as const;
}
return {
ok: true,
} as const;
} catch (error) {
recordSpanException(span, error);
+10 -1
View File
@@ -53,6 +53,7 @@ import {
import { findUp, pathExists } from "find-up";
import { cliRootPath } from "../utilities/resolveInternalFilePath";
import { escapeImportPath } from "../utilities/windows";
import { updateTriggerPackages } from "./update";
let apiClient: CliApiClient | undefined;
@@ -61,6 +62,7 @@ const DevCommandOptions = CommonCommandOptions.extend({
debugOtel: z.boolean().default(false),
config: z.string().optional(),
projectRef: z.string().optional(),
skipUpdateCheck: z.boolean().default(false),
});
type DevCommandOptions = z.infer<typeof DevCommandOptions>;
@@ -78,6 +80,7 @@ export function configureDevCommand(program: Command) {
)
.option("--debugger", "Enable the debugger")
.option("--debug-otel", "Enable OpenTelemetry debugging")
.option("--skip-update-check", "Skip checking for @trigger.dev package updates")
).action(async (path, options) => {
wrapCommandAction("dev", DevCommandOptions, options, async (opts) => {
await devCommand(path, opts);
@@ -132,7 +135,13 @@ async function startDev(
}
await printStandloneInitialBanner(true);
printDevBanner();
if (!options.skipUpdateCheck) {
console.log(); // spacing
await updateTriggerPackages(dir, { ...options }, false, true);
}
printDevBanner(!options.skipUpdateCheck);
logger.debug("Starting dev session", { dir, options, authorization });
+285 -133
View File
@@ -1,148 +1,300 @@
import { confirm } from "@clack/prompts";
import { RunOptions, run } from "npm-check-updates";
import path from "path";
import { confirm, intro, isCancel, log, outro } from "@clack/prompts";
import { z } from "zod";
import { chalkError, chalkSuccess } from "../utilities/cliOutput.js";
import { readJSONFileSync, writeJSONFile } from "../utilities/fileSystem.js";
import { installDependencies } from "../utilities/installDependencies.js";
import { readJSONFile, removeFile, writeJSONFile } from "../utilities/fileSystem.js";
import { spinner } from "../utilities/windows.js";
import { CommonCommandOptions, OutroCommandError, wrapCommandAction } from "../cli/common.js";
import { Command } from "commander";
import { logger } from "../utilities/logger.js";
import { PackageJson } from "type-fest";
import { printStandloneInitialBanner, updateCheck } from "../utilities/initialBanner.js";
import { join, resolve } from "path";
import { JavascriptProject } from "../utilities/javascriptProject.js";
import { PackageManager } from "../utilities/getUserPackageManager.js";
import { getVersion } from "../utilities/getVersion.js";
import { chalkError, prettyWarning } from "../utilities/cliOutput.js";
export const UpdateCommandOptionsSchema = z.object({
to: z.string().optional(),
export const UpdateCommandOptions = CommonCommandOptions.pick({
logLevel: true,
skipTelemetry: true,
});
export type UpdateCommandOptions = z.infer<typeof UpdateCommandOptionsSchema>;
export type UpdateCommandOptions = z.infer<typeof UpdateCommandOptions>;
type NcuRunOptionTarget = "latest" | `@${string}`;
export async function updateCommand(projectPath: string, anyOptions: any) {
const loadingSpinner = spinner();
loadingSpinner.start("Checking settings");
const parseRes = UpdateCommandOptionsSchema.safeParse(anyOptions);
if (!parseRes.success) {
loadingSpinner.stop(chalkError(parseRes.error.message));
return;
}
const options = parseRes.data;
const triggerDevPackage = "@trigger.dev";
const packageJSONPath = path.join(projectPath, "package.json");
const packageData = readJSONFileSync(packageJSONPath);
if (!packageData) {
loadingSpinner.stop(chalkError("Couldn't load package.json"));
return;
}
loadingSpinner.message("Checking for updates");
const packageMaps: { [k: string]: { type: string; version: string } } = {};
const packageDependencies = packageData.dependencies || {};
const packageDevDependencies = packageData.devDependencies || {};
Object.keys(packageDependencies).forEach((i) => {
packageMaps[i] = { type: "dependencies", version: packageDependencies[i] };
});
Object.keys(packageDevDependencies).forEach((i) => {
packageMaps[i] = {
type: "devDependencies",
version: packageDevDependencies[i],
};
});
const targetVersion = getTargetVersion(options.to);
// Use npm-check-updates to get updated dependency versions
const ncuOptions: RunOptions = {
packageData,
upgrade: true,
jsonUpgraded: true,
target: targetVersion,
};
// Can either give a json like package.json or just with deps and their new versions
const updatedDependencies: { [k: string]: any } | void = await run(ncuOptions);
if (!updatedDependencies) {
loadingSpinner.stop(chalkError("Couldn't update dependencies"));
return;
}
const ifUpdatedDependenciesIsPackageJSON =
updatedDependencies.hasOwnProperty("dependencies") ||
updatedDependencies.hasOwnProperty("devDependencies");
const dependencies = updatedDependencies.dependencies || {};
const devDependencies = updatedDependencies.devDependencies || {};
const allDependencies = ifUpdatedDependenciesIsPackageJSON
? Object.keys({ ...dependencies, ...devDependencies })
: Object.keys(updatedDependencies);
const triggerPackages = allDependencies.filter((pkg) => pkg.startsWith(triggerDevPackage));
// If there are no @trigger.dev packages
if (triggerPackages.length === 0) {
loadingSpinner.stop(chalkSuccess(`All @trigger.dev/* packages are already up to date.`));
return;
}
// Filter the packages with null and what don't match what
// they are installed with so that they can be updated
const packagesToUpdate = triggerPackages.filter((pkg: string) => updatedDependencies[pkg]);
// If no packages require any updation
if (packagesToUpdate.length === 0) {
loadingSpinner.stop(chalkSuccess(`All @trigger.dev/* packages are already up to date.`));
return;
}
let applyUpdates = targetVersion !== "latest";
if (targetVersion === "latest") {
applyUpdates = await hasUserConfirmed(packagesToUpdate, packageMaps, updatedDependencies);
}
if (applyUpdates) {
const newPackageJSON = packageData;
packagesToUpdate.forEach((packageName) => {
const tmp = packageMaps[packageName];
if (tmp) {
newPackageJSON[tmp.type][packageName] = updatedDependencies[packageName];
}
export function configureUpdateCommand(program: Command) {
return program
.command("update")
.description("Updates all @trigger.dev/* packages to match the CLI version")
.argument("[path]", "The path to the directory that contains the package.json file", ".")
.option(
"-l, --log-level <level>",
"The CLI log level to use (debug, info, log, warn, error, none). This does not effect the log level of your trigger.dev tasks.",
"log"
)
.option("--skip-telemetry", "Opt-out of sending telemetry")
.action(async (path, options) => {
wrapCommandAction("dev", UpdateCommandOptions, options, async (opts) => {
await printStandloneInitialBanner(true);
await updateCommand(path, opts);
});
});
await writeJSONFile(packageJSONPath, newPackageJSON);
await installDependencies(projectPath);
}
}
// expects a version number, or latest.
// if version number is specified, prepend it with '@' for ncu.
function getTargetVersion(toVersion?: string): NcuRunOptionTarget {
if (!toVersion) {
return "latest";
}
return toVersion === "latest" ? "latest" : `@${toVersion}`;
const triggerPackageFilter = /^@trigger\.dev/;
export async function updateCommand(dir: string, options: UpdateCommandOptions) {
await updateTriggerPackages(dir, options);
}
async function hasUserConfirmed(
packagesToUpdate: string[],
packageMaps: { [x: string]: { type: string; version: string } },
updatedDependencies: { [x: string]: any }
): Promise<boolean> {
// Inform the user of the dependencies that can be updated
console.log("\nNewer versions found for the following packages:");
console.table(
packagesToUpdate.map((i) => ({
name: i,
old: packageMaps[i]?.version,
new: updatedDependencies[i],
}))
export async function updateTriggerPackages(
dir: string,
options: UpdateCommandOptions,
embedded?: boolean,
requireUpdate?: boolean
) {
if (!embedded) {
intro("Updating packages");
}
const projectPath = resolve(process.cwd(), dir);
const { packageJson, readonlyPackageJson, packageJsonPath } = await getPackageJson(projectPath);
if (!packageJson) {
log.error("Failed to load package.json. Try to re-run with `-l debug` to see what's going on.");
return;
}
const cliVersion = getVersion();
const newCliVersion = await updateCheck();
if (newCliVersion) {
prettyWarning(
"You're not running the latest CLI version, please consider updating ASAP",
`Current: ${cliVersion}\nLatest: ${newCliVersion}`,
"Run latest: npx trigger.dev@beta"
);
}
const triggerDependencies = getTriggerDependencies(packageJson);
function getVersionMismatches(deps: Dependency[], targetVersion: string): Dependency[] {
const mismatches: Dependency[] = [];
for (const dep of deps) {
if (dep.version === targetVersion) {
continue;
}
mismatches.push(dep);
}
return mismatches;
}
const versionMismatches = getVersionMismatches(triggerDependencies, cliVersion);
if (versionMismatches.length === 0) {
if (!embedded) {
outro(`Nothing to do${newCliVersion ? " ..but you should really update your CLI!" : ""}`);
}
return;
}
prettyWarning(
"Mismatch between your CLI version and installed packages",
"We recommend pinned versions for guaranteed compatibility"
);
// Ask the user if they want to update the dependencies
const shouldContinue = await confirm({
message: "Do you want to update these packages in package.json and re-install dependencies?",
});
if (!process.stdout.isTTY) {
// Running in CI with version mismatch detected
outro("Deploy failed");
return shouldContinue as boolean;
console.log(
`ERROR: Version mismatch detected while running in CI. This won't end well. Aborting.
Please run the dev command locally and check that your CLI version matches the one printed below. Additionally, all \`@trigger.dev/*\` packages also need to match this version.
If your local CLI version doesn't match the one below, you may want to add the \`trigger.dev\` package to your dependencies. You will also have to update your workflow deploy command to \`npx trigger.dev deploy\` to ensure your pinned CLI version is used.
CLI version: ${cliVersion}
Current package versions that don't match the CLI:
${versionMismatches.map((dep) => `- ${dep.name}@${dep.version}`).join("\n")}\n`
);
process.exit(1);
}
log.message(""); // spacing
// Always require user confirmation
const userWantsToUpdate = await updateConfirmation(versionMismatches, cliVersion);
if (isCancel(userWantsToUpdate)) {
throw new OutroCommandError();
}
if (!userWantsToUpdate) {
if (requireUpdate) {
outro("You shall not pass!");
logger.log(
`${chalkError(
"X Error:"
)} Update required: Version mismatches are a common source of bugs and errors. Please update or use \`--skip-update-check\` at your own risk.\n`
);
process.exit(1);
}
if (!embedded) {
outro("You've been warned!");
}
return;
}
const installSpinner = spinner();
installSpinner.start("Writing new package.json file");
// Backup package.json
const packageJsonBackupPath = `${packageJsonPath}.bak`;
await writeJSONFile(packageJsonBackupPath, readonlyPackageJson, true);
const exitHandler = async (sig: any) => {
log.warn(
`You may have to manually roll back any package.json changes. Backup written to ${packageJsonBackupPath}`
);
};
// Add exit handler to warn about manual rollback of package.json
// Automatically rolling back can end up overwriting with an empty file instead
process.prependOnceListener("exit", exitHandler);
// Update package.json
mutatePackageJsonWithUpdatedPackages(packageJson, versionMismatches, cliVersion);
await writeJSONFile(packageJsonPath, packageJson, true);
async function revertPackageJsonChanges() {
await writeJSONFile(packageJsonPath, readonlyPackageJson, true);
await removeFile(packageJsonBackupPath);
}
installSpinner.message("Installing new package versions");
const jsProject = new JavascriptProject(projectPath);
let packageManager: PackageManager | undefined;
try {
packageManager = await jsProject.getPackageManager();
installSpinner.message(`Installing new package versions with ${packageManager}`);
await jsProject.install();
} catch (error) {
installSpinner.stop(
`Failed to install new package versions${packageManager ? ` with ${packageManager}` : ""}`
);
// Remove exit handler in case of failure
process.removeListener("exit", exitHandler);
await revertPackageJsonChanges();
throw error;
}
installSpinner.stop("Installed new package versions");
// Remove exit handler once packages have been updated, also delete backup file
process.removeListener("exit", exitHandler);
await removeFile(packageJsonBackupPath);
if (!embedded) {
outro(
`Packages updated${newCliVersion ? " ..but you should really update your CLI too!" : ""}`
);
}
}
type Dependency = {
type: "dependencies" | "devDependencies";
name: string;
version: string;
};
function getTriggerDependencies(packageJson: PackageJson): Dependency[] {
const deps: Dependency[] = [];
for (const type of ["dependencies", "devDependencies"] as const) {
for (const [name, version] of Object.entries(packageJson[type] ?? {})) {
if (!version) {
continue;
}
if (version.startsWith("workspace")) {
continue;
}
if (!triggerPackageFilter.test(name)) {
continue;
}
const ignoredPackages = ["@trigger.dev/companyicons"];
if (ignoredPackages.includes(name)) {
continue;
}
deps.push({ type, name, version });
}
}
return deps;
}
function mutatePackageJsonWithUpdatedPackages(
packageJson: PackageJson,
depsToUpdate: Dependency[],
targetVersion: string
) {
for (const { type, name, version } of depsToUpdate) {
if (!packageJson[type]) {
throw new Error(
`No ${type} entry found in package.json. Please try to upgrade manually instead.`
);
}
packageJson[type]![name] = targetVersion;
}
}
function printUpdateTable(depsToUpdate: Dependency[], targetVersion: string): void {
log.message("Suggested updates");
const tableData = depsToUpdate.map((dep) => ({
package: dep.name,
old: dep.version,
new: targetVersion,
}));
logger.table(tableData);
}
async function updateConfirmation(depsToUpdate: Dependency[], targetVersion: string) {
printUpdateTable(depsToUpdate, targetVersion);
let confirmMessage = "Would you like to apply those updates?";
return await confirm({
message: confirmMessage,
});
}
export async function getPackageJson(absoluteProjectPath: string) {
const packageJsonPath = join(absoluteProjectPath, "package.json");
const readonlyPackageJson = Object.freeze((await readJSONFile(packageJsonPath)) as PackageJson);
const packageJson = structuredClone(readonlyPackageJson);
return { packageJson, readonlyPackageJson, packageJsonPath };
}
@@ -0,0 +1,3 @@
export function assertExhaustive(x: never): never {
throw new Error("Unexpected object: " + x);
}
@@ -1,3 +1,4 @@
import { log } from "@clack/prompts";
import chalk from "chalk";
export const green = "#4FFF54";
@@ -63,3 +64,26 @@ export function prettyPrintDate(date: Date = new Date()) {
return formattedDate;
}
export function prettyWarning(header: string, body?: string, footer?: string) {
const prefix = "Warning: ";
const indent = Array(prefix.length).fill(" ").join("");
const spacing = "\n\n";
const prettyPrefix = chalkWarning(prefix);
const withIndents = (text?: string) =>
text
?.split("\n")
.map((line) => `${indent}${line}`)
.join("\n");
const prettyBody = withIndents(body);
const prettyFooter = withIndents(footer);
log.warn(
`${prettyPrefix}${header}${prettyBody ? `${spacing}${prettyBody}` : ""}${
prettyFooter ? `${spacing}${prettyFooter}` : ""
}`
);
}
@@ -3,9 +3,10 @@ import { relative } from "node:path";
import { chalkError, chalkPurple, chalkGrey, chalkGreen, chalkWarning } from "./cliOutput";
import { logger } from "./logger";
import { ReadConfigResult } from "./configFiles";
import { TaskMetadataParseError } from "../workers/common/errors";
import { z } from "zod";
import { groupTaskMetadataIssuesByTask } from "@trigger.dev/core/v3";
import terminalLink from "terminal-link";
import { docs } from "./links";
export type ESMRequireError = {
type: "esm-require-error";
@@ -86,6 +87,10 @@ export function logESMRequireError(parsedError: ESMRequireError, resolvedConfig:
)}. This will bundle the module with your code.\n`
);
}
logger.log(
`${chalkGrey("○")} For more info see the ${terminalLink("relevant docs", docs.config.esm)}.\n`
);
}
export type PackageNotFoundError = {
+2 -2
View File
@@ -67,8 +67,8 @@ export async function safeFeadJSONFile(path: string) {
}
}
export async function writeJSONFile(path: string, json: any) {
await writeFile(path, JSON.stringify(json), "utf8");
export async function writeJSONFile(path: string, json: any, pretty = false) {
await writeFile(path, JSON.stringify(json, undefined, pretty ? 2 : undefined), "utf8");
}
export function readJSONFileSync(path: string) {
@@ -1,8 +1,16 @@
import { findUp } from "find-up";
import { basename } from "path";
import { logger } from "./logger";
export type PackageManager = "npm" | "pnpm" | "yarn";
export async function getUserPackageManager(path: string): Promise<PackageManager> {
const packageManager = await detectPackageManager(path);
logger.debug("Detected package manager", { packageManager });
return packageManager;
}
async function detectPackageManager(path: string): Promise<PackageManager> {
try {
return await detectPackageManagerFromArtifacts(path);
} catch (error) {
@@ -29,19 +37,30 @@ function detectPackageManagerFromCurrentCommand(): PackageManager {
}
async function detectPackageManagerFromArtifacts(path: string): Promise<PackageManager> {
const packageFiles = [
{ name: "yarn.lock", pm: "yarn" } as const,
{ name: "pnpm-lock.yaml", pm: "pnpm" } as const,
{ name: "package-lock.json", pm: "npm" } as const,
{ name: "npm-shrinkwrap.json", pm: "npm" } as const,
];
const artifacts = {
yarn: "yarn.lock",
pnpm: "pnpm-lock.yaml",
npm: "package-lock.json",
npmShrinkwrap: "npm-shrinkwrap.json",
};
for (const { name, pm } of packageFiles) {
const foundPath = await findUp(name, { cwd: path });
if (typeof foundPath === "string") {
return pm;
}
const foundPath = await findUp(Object.values(artifacts), { cwd: path });
if (!foundPath) {
throw new Error("Could not detect package manager from artifacts");
}
throw new Error("Could not detect package manager from artifacts");
logger.debug("Found path from package manager artifacts", { foundPath });
switch (basename(foundPath)) {
case artifacts.yarn:
return "yarn";
case artifacts.pnpm:
return "pnpm";
case artifacts.npm:
case artifacts.npmShrinkwrap:
return "npm";
default:
throw new Error(`Unhandled package manager detection path: ${foundPath}`);
}
}
+11 -7
View File
@@ -8,8 +8,8 @@ import { logger } from "./logger.js";
import { spinner } from "./windows";
export async function printInitialBanner(performUpdateCheck = true) {
const packageVersion = getVersion();
const text = `\n${logo()} ${chalkGrey(`(${packageVersion})`)}\n`;
const cliVersion = getVersion();
const text = `\n${logo()} ${chalkGrey(`(${cliVersion})`)}\n`;
logger.info(text);
@@ -22,7 +22,7 @@ export async function printInitialBanner(performUpdateCheck = true) {
// Log a slightly more noticeable message if this is a major bump
if (maybeNewVersion !== undefined) {
loadingSpinner.stop(`Update available ${chalk.green(maybeNewVersion)}`);
const currentMajor = parseInt(packageVersion.split(".")[0]!);
const currentMajor = parseInt(cliVersion.split(".")[0]!);
const newMajor = parseInt(maybeNewVersion.split(".")[0]!);
if (newMajor > currentMajor) {
logger.warn(
@@ -38,9 +38,9 @@ After installation, run Trigger.dev with \`npx trigger.dev\`.`
}
export async function printStandloneInitialBanner(performUpdateCheck = true) {
const packageVersion = getVersion();
const cliVersion = getVersion();
logger.log(`\n${logo()} ${chalkGrey("(v3 Developer Preview)")}`);
logger.log(`\n${logo()} ${chalkGrey(`(${cliVersion})`)}\n`);
if (performUpdateCheck) {
const maybeNewVersion = await updateCheck();
@@ -54,7 +54,11 @@ export async function printStandloneInitialBanner(performUpdateCheck = true) {
logger.log(`${chalkGrey("-".repeat(54))}`);
}
export function printDevBanner() {
export function printDevBanner(printTopBorder = true) {
if (printTopBorder) {
logger.log(chalkGrey("-".repeat(54)));
}
logger.log(
`${chalkGrey("Key:")} ${chalkWorker("Version")} ${chalkGrey("|")} ${chalkTask(
"Task"
@@ -68,7 +72,7 @@ async function doUpdateCheck(): Promise<string | undefined> {
try {
// default cache for update check is 1 day
update = await checkForUpdate(pkg, {
distTag: pkg.version.startsWith("0.0.0") ? "beta" : "latest",
distTag: pkg.version.startsWith("3.0.0-beta") ? "beta" : "latest",
});
} catch (err) {
// ignore error
@@ -1,74 +0,0 @@
import chalk from "chalk";
import { execa } from "execa";
import { getUserPackageManager, type PackageManager } from "./getUserPackageManager.js";
import { logger } from "./logger.js";
import { spinner } from "./windows.js";
export async function installDependencies(projectDir: string) {
logger.info("Installing dependencies...");
const pkgManager = await getUserPackageManager(projectDir);
const installSpinner = await runInstallCommand(pkgManager, projectDir);
// If the spinner was used to show the progress, use succeed method on it
// If not, use the succeed on a new spinner
(installSpinner || spinner()).stop(chalk.green("Successfully installed dependencies!\n"));
}
async function runInstallCommand(
pkgManager: PackageManager,
projectDir: string
): Promise<ReturnType<typeof spinner> | null> {
switch (pkgManager) {
// When using npm, inherit the stderr stream so that the progress bar is shown
case "npm":
await execa(pkgManager, ["install"], {
cwd: projectDir,
stderr: "inherit",
});
return null;
// When using yarn or pnpm, use the stdout stream and ora spinner to show the progress
case "pnpm": {
const loadingSpinner = spinner();
loadingSpinner.start("Running pnpm install...");
const pnpmSubprocess = execa(pkgManager, ["install"], {
cwd: projectDir,
stdout: "pipe",
});
await new Promise<void>((res, rej) => {
pnpmSubprocess.stdout?.on("data", (data: Buffer) => {
const text = data.toString();
if (text.includes("Progress")) {
loadingSpinner.message(text.includes("|") ? text.split(" | ")[1] ?? "" : text);
}
});
pnpmSubprocess.on("error", (e) => rej(e));
pnpmSubprocess.on("close", () => res());
});
return loadingSpinner;
}
case "yarn": {
const loadingSpinner = spinner();
loadingSpinner.start("Running yarn...");
const yarnSubprocess = execa(pkgManager, [], {
cwd: projectDir,
stdout: "pipe",
});
await new Promise<void>((res, rej) => {
yarnSubprocess.stdout?.on("data", (data: Buffer) => {
loadingSpinner.message(data.toString());
});
yarnSubprocess.on("error", (e) => rej(e));
yarnSubprocess.on("close", () => res());
});
return loadingSpinner;
}
}
}
@@ -25,17 +25,6 @@ export async function installPackages(
);
}
async function getPackageVersion(path: string) {
try {
const packageJsonPath = join(path, "package.json");
const packageJson = await readJSONFile(packageJsonPath);
return packageJson.version;
} catch (error) {
return undefined;
}
}
// Expects path to be in the format:
// - source-map-support/register.js
// - @opentelemetry/api
@@ -3,6 +3,8 @@ import { join } from "node:path";
import { readJSONFileSync } from "./fileSystem";
import { logger } from "./logger";
import { PackageManager, getUserPackageManager } from "./getUserPackageManager";
import { PackageJson } from "type-fest";
import { assertExhaustive } from "./assertExhaustive";
export type ResolveOptions = { allowDev: boolean };
@@ -49,14 +51,14 @@ const BuiltInModules = new Set([
]);
export class JavascriptProject {
private _packageJson?: any;
private _packageJson?: PackageJson;
private _packageManager?: PackageManager;
constructor(private projectPath: string) {}
private get packageJson() {
if (!this._packageJson) {
this._packageJson = readJSONFileSync(join(this.projectPath, "package.json"));
this._packageJson = readJSONFileSync(join(this.projectPath, "package.json")) as PackageJson;
}
return this._packageJson;
@@ -64,21 +66,29 @@ export class JavascriptProject {
public get scripts(): Record<string, string> {
return {
postinstall: this.packageJson.scripts?.postinstall,
postinstall: this.packageJson.scripts?.postinstall ?? "",
};
}
async install(): Promise<void> {
const command = await this.#getCommand();
try {
await command.installDependencies({
cwd: this.projectPath,
});
} catch (error) {
logger.debug(`Failed to install dependencies using ${command.name}`, {
error,
});
}
}
async resolve(packageName: string, options?: ResolveOptions): Promise<string | undefined> {
if (BuiltInModules.has(packageName)) {
return undefined;
}
if (!this._packageManager) {
this._packageManager = await getUserPackageManager(this.projectPath);
}
const packageManager = this._packageManager;
const opts = { allowDev: false, ...options };
const packageJsonVersion = this.packageJson.dependencies?.[packageName];
@@ -95,12 +105,7 @@ export class JavascriptProject {
}
}
const command =
packageManager === "npm"
? new NPMCommands()
: packageManager === "pnpm"
? new PNPMCommands()
: new YarnCommands();
const command = await this.#getCommand();
try {
const version = await command.resolveDependencyVersion(packageName, {
@@ -117,6 +122,29 @@ export class JavascriptProject {
});
}
}
async #getCommand(): Promise<PackageManagerCommands> {
const packageManager = await this.getPackageManager();
switch (packageManager) {
case "npm":
return new NPMCommands();
case "pnpm":
return new PNPMCommands();
case "yarn":
return new YarnCommands();
default:
assertExhaustive(packageManager);
}
}
async getPackageManager(): Promise<PackageManager> {
if (!this._packageManager) {
this._packageManager = await getUserPackageManager(this.projectPath);
}
return this._packageManager;
}
}
type PnpmList = {
@@ -140,6 +168,10 @@ type PackageManagerOptions = {
};
interface PackageManagerCommands {
name: string;
installDependencies(options: PackageManagerOptions): Promise<void>;
resolveDependencyVersion(
packageName: string,
options: PackageManagerOptions
@@ -151,15 +183,21 @@ class PNPMCommands implements PackageManagerCommands {
return "pnpm";
}
async resolveDependencyVersion(
packageName: string,
options: PackageManagerOptions
): Promise<string | undefined> {
const cmd = process.platform === "win32" ? "pnpm.cmd" : "pnpm";
const { stdout } = await $({ cwd: options.cwd })`${cmd} list ${packageName} -r --json`;
private get cmd() {
return process.platform === "win32" ? "pnpm.cmd" : "pnpm";
}
async installDependencies(options: PackageManagerOptions) {
const { stdout, stderr } = await $({ cwd: options.cwd })`${this.cmd} install`;
logger.debug(`Installing dependencies using ${this.name}`, { stdout, stderr });
}
async resolveDependencyVersion(packageName: string, options: PackageManagerOptions) {
const { stdout } = await $({ cwd: options.cwd })`${this.cmd} list ${packageName} -r --json`;
const result = JSON.parse(stdout) as PnpmList;
logger.debug(`Resolving ${packageName} version using pnpm`, { result });
logger.debug(`Resolving ${packageName} version using ${this.name}`, { result });
// Return the first dependency version that matches the package name
for (const dep of result) {
@@ -189,15 +227,21 @@ class NPMCommands implements PackageManagerCommands {
return "npm";
}
async resolveDependencyVersion(
packageName: string,
options: PackageManagerOptions
): Promise<string | undefined> {
const cmd = process.platform === "win32" ? "npm.cmd" : "npm";
const { stdout } = await $({ cwd: options.cwd })`${cmd} list ${packageName} --json`;
private get cmd() {
return process.platform === "win32" ? "npm.cmd" : "npm";
}
async installDependencies(options: PackageManagerOptions) {
const { stdout, stderr } = await $({ cwd: options.cwd })`${this.cmd} install`;
logger.debug(`Installing dependencies using ${this.name}`, { stdout, stderr });
}
async resolveDependencyVersion(packageName: string, options: PackageManagerOptions) {
const { stdout } = await $({ cwd: options.cwd })`${this.cmd} list ${packageName} --json`;
const output = JSON.parse(stdout) as NpmListOutput;
logger.debug(`Resolving ${packageName} version using npm`, { output });
logger.debug(`Resolving ${packageName} version using ${this.name}`, { output });
return this.#recursivelySearchDependencies(output.dependencies, packageName);
}
@@ -227,17 +271,22 @@ class YarnCommands implements PackageManagerCommands {
return "yarn";
}
async resolveDependencyVersion(
packageName: string,
options: PackageManagerOptions
): Promise<string | undefined> {
const cmd = process.platform === "win32" ? "yarn.cmd" : "yarn";
private get cmd() {
return process.platform === "win32" ? "yarn.cmd" : "yarn";
}
const { stdout } = await $({ cwd: options.cwd })`${cmd} info ${packageName} --json`;
async installDependencies(options: PackageManagerOptions) {
const { stdout, stderr } = await $({ cwd: options.cwd })`${this.cmd} install`;
logger.debug(`Installing dependencies using ${this.name}`, { stdout, stderr });
}
async resolveDependencyVersion(packageName: string, options: PackageManagerOptions) {
const { stdout } = await $({ cwd: options.cwd })`${this.cmd} info ${packageName} --json`;
const lines = stdout.split("\n");
logger.debug(`Resolving ${packageName} version using yarn`, { lines });
logger.debug(`Resolving ${packageName} version using ${this.name}`, { lines });
for (const line of lines) {
const json = JSON.parse(line);
+10
View File
@@ -0,0 +1,10 @@
export const docs = {
config: {
home: "https://trigger.dev/docs/v3/trigger-config",
esm: "https://trigger.dev/docs/v3/trigger-config#esm-only-packages",
prisma: "https://trigger.dev/docs/v3/trigger-config#prisma-and-other-generators",
additionalPackages: "https://trigger.dev/docs/v3/trigger-config#prisma-and-other-generators",
},
};
export const getInTouch = "https://trigger.dev/contact";
+15
View File
@@ -1,5 +1,20 @@
# create-trigger
## 3.0.0-beta.17
### Patch Changes
- @trigger.dev/core@3.0.0-beta.17
- @trigger.dev/yalt@3.0.0-beta.17
## 3.0.0-beta.16
### Patch Changes
- Updated dependencies [ed2a26c86]
- @trigger.dev/core@3.0.0-beta.16
- @trigger.dev/yalt@3.0.0-beta.16
## 3.0.0-beta.15
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/cli",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "The Trigger.dev CLI",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
+4
View File
@@ -1,5 +1,9 @@
# @trigger.dev/core-apps
## 3.0.0-beta.17
## 3.0.0-beta.16
## 3.0.0-beta.15
## 3.0.0-beta.14
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@trigger.dev/core-apps",
"description": "Backend core code used across apps",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"private": true,
"license": "MIT",
"main": "./dist/index.js",
+4
View File
@@ -1,5 +1,9 @@
# @trigger.dev/core-backend
## 3.0.0-beta.17
## 3.0.0-beta.16
## 3.0.0-beta.15
## 3.0.0-beta.14
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/core-backend",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "Core code used across `@trigger.dev/sdk` and Trigger.dev server",
"license": "MIT",
"main": "./dist/index.js",
+11
View File
@@ -1,5 +1,16 @@
# internal-platform
## 3.0.0-beta.17
## 3.0.0-beta.16
### Patch Changes
- ed2a26c86: - Fix additionalFiles that aren't decendants
- Stop swallowing uncaught exceptions in prod
- Improve warnings and errors, fail early on critical warnings
- New arg to --save-logs even for successful builds
## 3.0.0-beta.15
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/core",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "Core code used across the Trigger.dev SDK and platform",
"license": "MIT",
"main": "./dist/index.js",
+2
View File
@@ -16,6 +16,8 @@ export interface ProjectConfig {
* List of additional files to include in your trigger.dev bundle. e.g. ["./prisma/schema.prisma"]
*
* Supports glob patterns.
*
* Note: The path separator for glob patterns is `/`, even on Windows!
*/
additionalFiles?: string[];
/**
+4
View File
@@ -1,5 +1,9 @@
# @trigger.dev/eslint-plugin
## 3.0.0-beta.17
## 3.0.0-beta.16
## 3.0.0-beta.15
## 3.0.0-beta.14
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/eslint-plugin",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "ESLint plugin with trigger.dev best practices",
"keywords": [
"eslint",
+12
View File
@@ -1,5 +1,17 @@
# @trigger.dev/express
## 3.0.0-beta.17
### Patch Changes
- @trigger.dev/sdk@3.0.0-beta.17
## 3.0.0-beta.16
### Patch Changes
- @trigger.dev/sdk@3.0.0-beta.16
## 3.0.0-beta.15
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/express",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "Official Express adapter for Trigger.dev",
"license": "MIT",
"main": "./dist/index.js",
@@ -23,7 +23,7 @@
"./package.json": "./package.json"
},
"devDependencies": {
"@trigger.dev/sdk": "workspace:^3.0.0-beta.15",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.17",
"@trigger.dev/tsconfig": "workspace:*",
"@types/debug": "^4.1.7",
"@types/express": "^4.17.13",
@@ -39,7 +39,7 @@
"build:tsup": "tsup"
},
"peerDependencies": {
"@trigger.dev/sdk": "workspace:^3.0.0-beta.15"
"@trigger.dev/sdk": "workspace:^3.0.0-beta.17"
},
"dependencies": {
"debug": "^4.3.4",
+12
View File
@@ -1,5 +1,17 @@
# @trigger.dev/hono
## 3.0.0-beta.17
### Patch Changes
- @trigger.dev/sdk@3.0.0-beta.17
## 3.0.0-beta.16
### Patch Changes
- @trigger.dev/sdk@3.0.0-beta.16
## 3.0.0-beta.15
### Patch Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/hono",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "A Trigger.dev adapter for Hono.dev",
"license": "MIT",
"main": "./dist/index.js",
@@ -32,7 +32,7 @@
},
"peerDependencies": {
"hono": "3.x",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.15"
"@trigger.dev/sdk": "workspace:^3.0.0-beta.17"
},
"devDependencies": {
"@trigger.dev/tsconfig": "workspace:*",
+13
View File
@@ -1,5 +1,18 @@
# @trigger.dev/integration-kit
## 3.0.0-beta.17
### Patch Changes
- @trigger.dev/core@3.0.0-beta.17
## 3.0.0-beta.16
### Patch Changes
- Updated dependencies [ed2a26c86]
- @trigger.dev/core@3.0.0-beta.16
## 3.0.0-beta.15
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/integration-kit",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "Trigger.dev Integration Kit has helpers to make creating integrations easier",
"license": "MIT",
"main": "./dist/index.js",
+12
View File
@@ -1,5 +1,17 @@
# @trigger.dev/nestjs
## 3.0.0-beta.17
### Patch Changes
- @trigger.dev/sdk@3.0.0-beta.17
## 3.0.0-beta.16
### Patch Changes
- @trigger.dev/sdk@3.0.0-beta.16
## 3.0.0-beta.15
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/nestjs",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "Official NestJS adapter for Trigger.dev",
"license": "MIT",
"main": "./dist/index.js",
@@ -23,7 +23,7 @@
"./package.json": "./package.json"
},
"devDependencies": {
"@trigger.dev/sdk": "workspace:^3.0.0-beta.15",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.17",
"@trigger.dev/tsconfig": "workspace:*",
"@types/debug": "^4.1.7",
"@types/express": "^4.17.13",
@@ -41,7 +41,7 @@
},
"peerDependencies": {
"@nestjs/common": ">=10.0.0",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.15"
"@trigger.dev/sdk": "workspace:^3.0.0-beta.17"
},
"dependencies": {
"@nestjs/common": "^10.2.4",
+12
View File
@@ -1,5 +1,17 @@
# @trigger.dev/nextjs
## 3.0.0-beta.17
### Patch Changes
- @trigger.dev/sdk@3.0.0-beta.17
## 3.0.0-beta.16
### Patch Changes
- @trigger.dev/sdk@3.0.0-beta.16
## 3.0.0-beta.15
### Patch Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/nextjs",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "Trigger.dev Next.js integration",
"license": "MIT",
"main": "./dist/index.js",
@@ -41,7 +41,7 @@
"build:tsup": "tsup"
},
"peerDependencies": {
"@trigger.dev/sdk": "workspace:^3.0.0-beta.15",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.17",
"next": ">=12.0.0"
},
"dependencies": {
+4
View File
@@ -1,5 +1,9 @@
# @trigger.dev/otlp-importer
## 3.0.0-beta.17
## 3.0.0-beta.16
## 3.0.0-beta.15
## 3.0.0-beta.14
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/otlp-importer",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "OpenTelemetry OTLP Importer for Node.js written in TypeScript",
"license": "MIT",
"main": "./dist/index.js",
+13
View File
@@ -1,5 +1,18 @@
# @trigger.dev/react
## 3.0.0-beta.17
### Patch Changes
- @trigger.dev/core@3.0.0-beta.17
## 3.0.0-beta.16
### Patch Changes
- Updated dependencies [ed2a26c86]
- @trigger.dev/core@3.0.0-beta.16
## 3.0.0-beta.15
### Patch Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/react",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "Trigger.dev React SDK",
"license": "MIT",
"types": "dist/index.d.ts",
@@ -27,7 +27,7 @@
},
"dependencies": {
"@tanstack/react-query": "5.0.0-beta.2",
"@trigger.dev/core": "workspace:^3.0.0-beta.15",
"@trigger.dev/core": "workspace:^3.0.0-beta.17",
"debug": "^4.3.4",
"zod": "3.22.3"
},
+12
View File
@@ -1,5 +1,17 @@
# @trigger.dev/remix
## 3.0.0-beta.17
### Patch Changes
- @trigger.dev/sdk@3.0.0-beta.17
## 3.0.0-beta.16
### Patch Changes
- @trigger.dev/sdk@3.0.0-beta.16
## 3.0.0-beta.15
### Patch Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/remix",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "Trigger.dev Remix integration",
"license": "MIT",
"main": "./dist/index.js",
@@ -39,7 +39,7 @@
"build:tsup": "tsup"
},
"peerDependencies": {
"@trigger.dev/sdk": "workspace:^3.0.0-beta.15",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.17",
"@remix-run/server-runtime": ">1.19.0"
},
"dependencies": {
+12
View File
@@ -1,5 +1,17 @@
# @trigger.dev/sveltekit
## 3.0.0-beta.17
### Patch Changes
- @trigger.dev/sdk@3.0.0-beta.17
## 3.0.0-beta.16
### Patch Changes
- @trigger.dev/sdk@3.0.0-beta.16
## 3.0.0-beta.15
### Patch Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/sveltekit",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "Trigger.dev svelteKit integration",
"license": "MIT",
"main": "./dist/index.js",
@@ -39,7 +39,7 @@
"build:tsup": "tsup"
},
"peerDependencies": {
"@trigger.dev/sdk": "workspace:^3.0.0-beta.15"
"@trigger.dev/sdk": "workspace:^3.0.0-beta.17"
},
"dependencies": {
"debug": "^4.3.4"
+15
View File
@@ -1,5 +1,20 @@
# @trigger.dev/testing
## 3.0.0-beta.17
### Patch Changes
- @trigger.dev/core@3.0.0-beta.17
- @trigger.dev/sdk@3.0.0-beta.17
## 3.0.0-beta.16
### Patch Changes
- Updated dependencies [ed2a26c86]
- @trigger.dev/core@3.0.0-beta.16
- @trigger.dev/sdk@3.0.0-beta.16
## 3.0.0-beta.15
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@trigger.dev/testing",
"description": "A collection of useful tools to write tests for Trigger.dev.",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"license": "MIT",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
+15
View File
@@ -1,5 +1,20 @@
# @trigger.dev/sdk
## 3.0.0-beta.17
### Patch Changes
- @trigger.dev/core@3.0.0-beta.17
- @trigger.dev/core-backend@3.0.0-beta.17
## 3.0.0-beta.16
### Patch Changes
- Updated dependencies [ed2a26c86]
- @trigger.dev/core@3.0.0-beta.16
- @trigger.dev/core-backend@3.0.0-beta.16
## 3.0.0-beta.15
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/sdk",
"version": "3.0.0-beta.15",
"version": "3.0.0-beta.17",
"description": "trigger.dev Node.JS SDK",
"license": "MIT",
"main": "./dist/index.js",
@@ -48,8 +48,8 @@
"@opentelemetry/api": "^1.8.0",
"@opentelemetry/api-logs": "^0.48.0",
"@opentelemetry/semantic-conventions": "^1.22.0",
"@trigger.dev/core": "workspace:^3.0.0-beta.15",
"@trigger.dev/core-backend": "workspace:^3.0.0-beta.15",
"@trigger.dev/core": "workspace:^3.0.0-beta.17",
"@trigger.dev/core-backend": "workspace:^3.0.0-beta.17",
"chalk": "^5.2.0",
"cronstrue": "^2.21.0",
"debug": "^4.3.4",
+4
View File
@@ -1,5 +1,9 @@
# @trigger.dev/yalt
## 3.0.0-beta.17
## 3.0.0-beta.16
## 3.0.0-beta.15
## 3.0.0-beta.14

Some files were not shown because too many files have changed in this diff Show More