Openstatus www.openstatus.dev

๐Ÿšง workflow pause monitors (#1159)

* ๐Ÿšง workflow pause monitors

* ci: apply automated fixes

* ๐Ÿšง workflows

* ci: apply automated fixes

* ๐Ÿ”ฅ workflow

* ๐Ÿ˜ฑ improve query

* ci: apply automated fixes

* ๐Ÿš€ fix query

* ci: apply automated fixes

* cron monitor

* ci: apply automated fixes

* cron monitor

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix workflow

* ci: apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

authored by

Thibault Le Ouay
Copilot
autofix-ci[bot]
and committed by
GitHub
caf3eedd 474a93e6

+560 -75
-6
apps/web/package.json
··· 101 101 "tailwindcss": "3.4.3", 102 102 "typescript": "5.6.2", 103 103 "unified": "10.1.2" 104 - }, 105 - "pnpm": { 106 - "overrides": { 107 - "@types/react": "19.0.1", 108 - "@types/react-dom": "19.0.2" 109 - } 110 104 } 111 105 }
+1
apps/workflows/package.json
··· 10 10 "@openstatus/db": "workspace:*", 11 11 "@openstatus/emails": "workspace:*", 12 12 "@openstatus/utils": "workspace:*", 13 + "@openstatus/upstash": "workspace:*", 13 14 "hono": "4.5.3", 14 15 "zod": "3.23.8" 15 16 },
+51
apps/workflows/src/cron/index.ts
··· 3 3 import { env } from "../env"; 4 4 import { sendCheckerTasks } from "./checker"; 5 5 import { sendFollowUpEmails } from "./emails"; 6 + import { 7 + LaunchMonitorWorkflow, 8 + Step3Days, 9 + Step14Days, 10 + StepPaused, 11 + workflowStepSchema, 12 + } from "./monitor"; 6 13 7 14 const app = new Hono({ strict: false }); 8 15 ··· 41 48 console.error(e); 42 49 return c.text("Internal Server Error", 500); 43 50 } 51 + }); 52 + 53 + app.get("/monitors", async (c) => { 54 + await LaunchMonitorWorkflow(); 55 + return c.json({ success: true }, 200); 56 + }); 57 + 58 + app.get("/monitors/:step", async (c) => { 59 + const step = c.req.param("step"); 60 + const schema = workflowStepSchema.safeParse(step); 61 + 62 + const userId = c.req.query("userId"); 63 + const initialRun = c.req.query("initialRun"); 64 + if (!schema.success) { 65 + return c.json({ error: schema.error.issues?.[0].message }, 400); 66 + } 67 + 68 + if (!userId) { 69 + return c.json({ error: "userId is required" }, 400); 70 + } 71 + if (!initialRun) { 72 + return c.json({ error: "initialRun is required" }, 400); 73 + } 74 + 75 + switch (schema.data) { 76 + case "14days": 77 + // We send the first email 78 + await Step14Days(Number(userId)); 79 + break; 80 + case "3days": 81 + await Step3Days(Number(userId), Number(initialRun)); 82 + // 3 days before we send the second email 83 + break; 84 + case "paused": 85 + // Let's pause the monitor 86 + await StepPaused(Number(userId), Number(initialRun)); 87 + break; 88 + default: 89 + throw new Error("Invalid step"); 90 + } 91 + // Swith on step 92 + // and do the right action 93 + // 94 + return c.json({ success: true }, 200); 44 95 }); 45 96 46 97 export { app as cronRouter };
+365
apps/workflows/src/cron/monitor.ts
··· 1 + import type { google } from "@google-cloud/tasks/build/protos/protos"; 2 + import { 3 + and, 4 + db, 5 + desc, 6 + eq, 7 + isNull, 8 + lte, 9 + max, 10 + ne, 11 + or, 12 + schema, 13 + } from "@openstatus/db"; 14 + import { session, user } from "@openstatus/db/src/schema"; 15 + 16 + import { CloudTasksClient } from "@google-cloud/tasks"; 17 + import { 18 + MonitorDeactivationEmail, 19 + MonitorPausedEmail, 20 + } from "@openstatus/emails"; 21 + import { sendWithRender } from "@openstatus/emails/src/send"; 22 + import { Redis } from "@openstatus/upstash"; 23 + import { z } from "zod"; 24 + import { env } from "../env"; 25 + 26 + const redis = Redis.fromEnv(); 27 + 28 + const client = new CloudTasksClient({ 29 + projectId: env().GCP_PROJECT_ID, 30 + credentials: { 31 + client_email: env().GCP_CLIENT_EMAIL, 32 + private_key: env().GCP_PRIVATE_KEY.replaceAll("\\n", "\n"), 33 + }, 34 + }); 35 + 36 + const parent = client.queuePath( 37 + env().GCP_PROJECT_ID, 38 + env().GCP_LOCATION, 39 + "workflow", 40 + ); 41 + 42 + export async function LaunchMonitorWorkflow() { 43 + // Expires is one month after last connection, so if we want to reach people who connected 3 months ago we need to check for people with expires 2 months ago 44 + const twoMonthAgo = new Date().setMonth(new Date().getMonth() - 2); 45 + 46 + const date = new Date(twoMonthAgo); 47 + // User without session 48 + const userWithoutSession = db 49 + .select({ 50 + userId: schema.user.id, 51 + email: schema.user.email, 52 + updatedAt: schema.user.updatedAt, 53 + }) 54 + .from(schema.user) 55 + .leftJoin(schema.session, eq(schema.session.userId, schema.user.id)) 56 + .where(isNull(schema.session.userId)) 57 + .as("query"); 58 + // Only free users monitors are paused 59 + // We don't need to handle multi users per workspace because free workspaces only have one user 60 + // Only free users monitors are paused 61 + 62 + const u1 = await db 63 + .select({ 64 + userId: userWithoutSession.userId, 65 + email: userWithoutSession.email, 66 + workspaceId: schema.workspace.id, 67 + }) 68 + .from(userWithoutSession) 69 + .innerJoin( 70 + schema.usersToWorkspaces, 71 + eq(userWithoutSession.userId, schema.usersToWorkspaces.userId), 72 + ) 73 + .innerJoin( 74 + schema.workspace, 75 + eq(schema.usersToWorkspaces.workspaceId, schema.workspace.id), 76 + ) 77 + .where( 78 + and( 79 + or( 80 + lte(userWithoutSession.updatedAt, date), 81 + isNull(userWithoutSession.updatedAt), 82 + ), 83 + or(isNull(schema.workspace.plan), eq(schema.workspace.plan, "free")), 84 + ), 85 + ); 86 + 87 + console.log(`Found ${u1.length} users without session to start the workflow`); 88 + const maxSessionPerUser = db 89 + .select({ 90 + userId: schema.user.id, 91 + email: schema.user.email, 92 + lastConnection: max(schema.session.expires).as("lastConnection"), 93 + }) 94 + .from(schema.user) 95 + .innerJoin(schema.session, eq(schema.session.userId, schema.user.id)) 96 + .groupBy(schema.user.id) 97 + .as("maxSessionPerUser"); 98 + // Only free users monitors are paused 99 + // We don't need to handle multi users per workspace because free workspaces only have one user 100 + // Only free users monitors are paused 101 + 102 + const u = await db 103 + .select({ 104 + userId: maxSessionPerUser.userId, 105 + email: maxSessionPerUser.email, 106 + workspaceId: schema.workspace.id, 107 + }) 108 + .from(maxSessionPerUser) 109 + .innerJoin( 110 + schema.usersToWorkspaces, 111 + eq(maxSessionPerUser.userId, schema.usersToWorkspaces.userId), 112 + ) 113 + .innerJoin( 114 + schema.workspace, 115 + eq(schema.usersToWorkspaces.workspaceId, schema.workspace.id), 116 + ) 117 + .where( 118 + and( 119 + lte(maxSessionPerUser.lastConnection, date), 120 + or(isNull(schema.workspace.plan), eq(schema.workspace.plan, "free")), 121 + ), 122 + ); 123 + // Let's merge both results 124 + const users = [...u, ...u1]; 125 + // iterate over users 126 + for (const user of users) { 127 + console.log(`Starting workflow for ${user.userId}`); 128 + // Let's check if the user is in the workflow 129 + const isMember = await redis.sismember("workflow:users", user.userId); 130 + if (isMember) { 131 + continue; 132 + } 133 + // check if user has some running monitors 134 + const nbRunningMonitor = await db.$count( 135 + schema.monitor, 136 + and( 137 + eq(schema.monitor.workspaceId, user.workspaceId), 138 + eq(schema.monitor.active, true), 139 + isNull(schema.monitor.deletedAt), 140 + ), 141 + ); 142 + if (nbRunningMonitor > 0) { 143 + continue; 144 + } 145 + await CreateTask({ 146 + parent, 147 + client: client, 148 + step: "14days", 149 + userId: user.userId, 150 + initialRun: new Date().getTime(), 151 + }); 152 + // // Add our user to the list of users that have started the workflow 153 + 154 + await redis.sadd("workflow:users", user.userId); 155 + console.log(`user workflow started for ${user.userId}`); 156 + } 157 + } 158 + 159 + export async function Step14Days(userId: number) { 160 + const user = await getUser(userId); 161 + 162 + // Send email saying we are going to pause the monitors 163 + // The task has just been created we don't double check if the user has logged in :scary: 164 + // send First email 165 + // TODO: Send email 166 + 167 + if (user.email) { 168 + sendWithRender({ 169 + to: [user.email], 170 + subject: "Your OpenStatus monitors will be paused soon", 171 + from: "Thibault From OpenStatus <thibault@notifications.openstatus.dev>", 172 + react: MonitorDeactivationEmail({ 173 + lastLogin: new Date(), 174 + deactivateAt: new Date(new Date().setDate(new Date().getDate() + 14)), 175 + }), 176 + }); 177 + } 178 + } 179 + 180 + export async function Step3Days(userId: number, workFlowRunTimestamp: number) { 181 + // check if user has connected 182 + const hasConnected = await hasUserLoggedIn({ 183 + userId, 184 + date: new Date(workFlowRunTimestamp), 185 + }); 186 + 187 + if (hasConnected) { 188 + // 189 + await redis.srem("workflow:users", userId); 190 + return; 191 + } 192 + 193 + const user = await getUser(userId); 194 + 195 + if (user.email) { 196 + sendWithRender({ 197 + to: [user.email], 198 + subject: "Your OpenStatus monitors will be paused in 3 days", 199 + from: "Thibault From OpenStatus <thibault@notifications.openstatus.dev>", 200 + react: MonitorDeactivationEmail({ 201 + lastLogin: new Date(workFlowRunTimestamp), 202 + deactivateAt: new Date(new Date().setDate(new Date().getDate() + 3)), 203 + }), 204 + }); 205 + } 206 + 207 + // Send second email 208 + //TODO: Send email 209 + // Let's schedule the next task 210 + await CreateTask({ 211 + client, 212 + parent, 213 + step: "paused", 214 + userId, 215 + initialRun: workFlowRunTimestamp, 216 + }); 217 + } 218 + 219 + export async function StepPaused(userId: number, workFlowRunTimestamp: number) { 220 + const hasConnected = await hasUserLoggedIn({ 221 + userId, 222 + date: new Date(workFlowRunTimestamp), 223 + }); 224 + if (!hasConnected) { 225 + // sendSecond pause email 226 + const users = await db 227 + .select({ 228 + userId: schema.user.id, 229 + email: schema.user.email, 230 + workspaceId: schema.workspace.id, 231 + }) 232 + .from(user) 233 + .innerJoin(session, eq(schema.user.id, schema.session.userId)) 234 + .innerJoin( 235 + schema.usersToWorkspaces, 236 + eq(schema.user.id, schema.usersToWorkspaces.userId), 237 + ) 238 + .innerJoin( 239 + schema.workspace, 240 + eq(schema.usersToWorkspaces.workspaceId, schema.workspace.id), 241 + ) 242 + .where( 243 + and( 244 + or(isNull(schema.workspace.plan), eq(schema.workspace.plan, "free")), 245 + eq(schema.user.id, userId), 246 + ), 247 + ) 248 + .get(); 249 + // We should only have one user :) 250 + if (!users) { 251 + throw new Error("Too many users found"); 252 + } 253 + 254 + await db 255 + .update(schema.monitor) 256 + .set({ active: false }) 257 + .where(eq(schema.monitor.workspaceId, users.workspaceId)); 258 + // Send last email with pause monitor 259 + } 260 + 261 + const currentUser = await getUser(userId); 262 + // TODO: Send email 263 + // Remove user for workflow 264 + 265 + if (currentUser.email) { 266 + sendWithRender({ 267 + to: [currentUser.email], 268 + subject: "Your monitors have been paused", 269 + from: "Thibault From OpenStatus <thibault@notifications.openstatus.dev>", 270 + react: MonitorPausedEmail(), 271 + }); 272 + } 273 + await redis.srem("workflow:users", userId); 274 + } 275 + 276 + async function hasUserLoggedIn({ 277 + userId, 278 + date, 279 + }: { 280 + userId: number; 281 + date: Date; 282 + }) { 283 + const userResult = await db 284 + .select({ lastSession: schema.session.expires }) 285 + .from(schema.session) 286 + .where(eq(schema.session.userId, userId)) 287 + .orderBy(desc(schema.session.expires)); 288 + 289 + if (userResult.length === 0) { 290 + return false; 291 + } 292 + const user = userResult[0]; 293 + if (user.lastSession === null) { 294 + return false; 295 + } 296 + return user.lastSession > date; 297 + } 298 + 299 + function CreateTask({ 300 + parent, 301 + client, 302 + step, 303 + userId, 304 + initialRun, 305 + }: { 306 + parent: string; 307 + client: CloudTasksClient; 308 + step: z.infer<typeof workflowStepSchema>; 309 + userId: number; 310 + initialRun: number; 311 + }) { 312 + const url = `https://openstatus-workflows.fly.dev/cron/monitors/${step}?userId=${userId}&initialRun=${initialRun}`; 313 + const timestamp = getScheduledTime(step); 314 + const newTask: google.cloud.tasks.v2beta3.ITask = { 315 + httpRequest: { 316 + headers: { 317 + "Content-Type": "application/json", // Set content type to ensure compatibility your application's request parsing 318 + Authorization: `Basic ${env().CRON_SECRET}`, 319 + }, 320 + httpMethod: "GET", 321 + url, 322 + }, 323 + scheduleTime: { 324 + seconds: timestamp, 325 + }, 326 + }; 327 + 328 + const request = { parent: parent, task: newTask }; 329 + return client.createTask(request); 330 + } 331 + 332 + function getScheduledTime(step: z.infer<typeof workflowStepSchema>) { 333 + switch (step) { 334 + case "14days": 335 + // let's triger it now 336 + return new Date().getTime() / 1000; 337 + case "3days": 338 + // it's 11 days after the 14 days 339 + return new Date().setDate(new Date().getDate() + 11) / 1000; 340 + case "paused": 341 + // it's 3 days after the 3 days step 342 + return new Date().setDate(new Date().getDate() + 3) / 1000; 343 + default: 344 + throw new Error("Invalid step"); 345 + } 346 + } 347 + 348 + export const workflowStep = ["14days", "3days", "paused"] as const; 349 + export const workflowStepSchema = z.enum(workflowStep); 350 + 351 + async function getUser(userId: number) { 352 + const currentUser = await db 353 + .select() 354 + .from(user) 355 + .where(eq(schema.user.id, userId)) 356 + .get(); 357 + 358 + if (!currentUser) { 359 + throw new Error("User not found"); 360 + } 361 + if (!currentUser.email) { 362 + throw new Error("User email not found"); 363 + } 364 + return currentUser; 365 + }
+20 -10
packages/emails/emails/monitor-deactivation.tsx
··· 16 16 export const MonitorDeactivationSchema = z.object({ 17 17 lastLogin: z.coerce.date(), 18 18 deactivateAt: z.coerce.date(), 19 - reminder: z.boolean().optional(), 20 19 }); 21 20 22 21 export type MonitorDeactivationProps = z.infer< ··· 26 25 const MonitorDeactivationEmail = ({ 27 26 lastLogin, 28 27 deactivateAt, 29 - reminder, 30 28 }: MonitorDeactivationProps) => { 31 29 return ( 32 30 <Html> 33 31 <Head /> 34 32 <Preview> 35 - {reminder ? "[REMINDER] " : ""}Deactivation of your monitor(s) 33 + Login to your OpenStatus account to keep your monitors active. 36 34 </Preview> 37 35 <Body style={styles.main}> 38 36 <Layout> 39 - <Heading as="h3">Deactivation of the your monitor(s)</Heading> 37 + <Text>Hello ๐Ÿ‘‹</Text> 38 + {/* <Heading as="h3">Deactivation of the your monitor(s)</Heading> */} 39 + <Text> 40 + To save on cloud resources and avoid having stale monitors. We are 41 + deactivating monitors for free account if you have not logged in for 42 + the last 2 months. 43 + </Text> 40 44 <Text>Your last login was {lastLogin.toDateString()}.</Text> 41 45 <Text> 42 - To avoid having stale monitors and reduce the number of testing 43 - accounts, we will deactivate your monitor(s) at{" "} 44 - {deactivateAt.toDateString()}. 46 + Your monitor(s) will be deactivated on {deactivateAt.toDateString()} 47 + . 45 48 </Text> 46 49 <Text> 47 50 If you would like to keep your monitor(s) active, please login to 48 - your account or upgrade your plan. 51 + your account or upgrade to a paid plan. 49 52 </Text> 50 53 <Text style={{ textAlign: "center" }}> 51 - <Button style={styles.button} href="https://.openstatus.dev/app"> 54 + <Button style={styles.button} href="https://www.openstatus.dev/app"> 52 55 Login 53 56 </Button> 54 57 </Text> 58 + <Text>If you have any questions, please reply to this email.</Text> 59 + <Text>Thibault </Text> 60 + <Text> 61 + Check out our latest update{" "} 62 + <a href="https://www.openstatus.dev/changelog?ref=paused-email"> 63 + here 64 + </a> 65 + </Text> 55 66 </Layout> 56 67 </Body> 57 68 </Html> ··· 61 72 MonitorDeactivationEmail.PreviewProps = { 62 73 lastLogin: new Date(new Date().setDate(new Date().getDate() - 100)), 63 74 deactivateAt: new Date(new Date().setDate(new Date().getDate() + 7)), 64 - reminder: true, 65 75 } satisfies MonitorDeactivationProps; 66 76 67 77 export default MonitorDeactivationEmail;
+53
packages/emails/emails/monitor-paused.tsx
··· 1 + /** @jsxImportSource react */ 2 + 3 + import { 4 + Body, 5 + Button, 6 + Head, 7 + Heading, 8 + Html, 9 + Preview, 10 + Text, 11 + } from "@react-email/components"; 12 + import { z } from "zod"; 13 + import { Layout } from "./_components/layout"; 14 + import { styles } from "./_components/styles"; 15 + 16 + const MonitorPausedEmail = () => { 17 + return ( 18 + <Html> 19 + <Head /> 20 + <Preview>Your monitors have been paused</Preview> 21 + <Body style={styles.main}> 22 + <Layout> 23 + <Text>Hello ๐Ÿ‘‹</Text> 24 + {/* <Heading as="h3">Deactivation of the your monitor(s)</Heading> */} 25 + <Text> 26 + To save on cloud resources, your monitor(s) has been paused due to 27 + inactivity. 28 + </Text> 29 + <Text> 30 + If you would like to unpause your monitor(s), please login to your 31 + account or upgrade to a paid plan. 32 + </Text> 33 + <Text style={{ textAlign: "center" }}> 34 + <Button style={styles.button} href="https://www.openstatus.dev/app"> 35 + Login 36 + </Button> 37 + </Text> 38 + 39 + <Text>If you have any questions, please reply to this email.</Text> 40 + <Text>Thibault</Text> 41 + <Text> 42 + Check out our latest update{" "} 43 + <a href="https://www.openstatus.dev/changelog?ref=paused-email"> 44 + here 45 + </a> 46 + </Text> 47 + </Layout> 48 + </Body> 49 + </Html> 50 + ); 51 + }; 52 + 53 + export default MonitorPausedEmail;
+3
packages/emails/src/index.ts
··· 2 2 export { default as SubscribeEmail } from "../emails/subscribe"; 3 3 export { default as WelcomeEmail } from "../emails/welcome"; 4 4 export { default as TeamInvitationEmail } from "../emails/team-invitation"; 5 + export { default as MonitorPausedEmail } from "../emails/monitor-paused"; 6 + export { default as MonitorDeactivationEmail } from "../emails/monitor-deactivation"; 7 + 5 8 export { sendEmail, sendEmailHtml, sendBatchEmailHtml } from "./send"; 6 9 7 10 export { EmailClient } from "./client";
+10
packages/emails/src/send.ts
··· 1 1 import type React from "react"; 2 2 import { Resend } from "resend"; 3 3 4 + import { render } from "@react-email/render"; 4 5 import { env } from "./env"; 5 6 6 7 export const resend = new Resend(env.RESEND_API_KEY); ··· 41 42 body: JSON.stringify(emails), 42 43 }); 43 44 }; 45 + 46 + export const sendWithRender = async (email: Emails) => { 47 + if (process.env.NODE_ENV !== "production") return; 48 + const html = await render(email.react); 49 + await resend.emails.send({ 50 + ...email, 51 + html, 52 + }); 53 + };
+1 -1
packages/notifications/discord/package.json
··· 4 4 "main": "src/index.ts", 5 5 "dependencies": { 6 6 "@openstatus/db": "workspace:*", 7 - "zod": "3.22.4" 7 + "zod": "3.23.8" 8 8 }, 9 9 "devDependencies": { 10 10 "@openstatus/tsconfig": "workspace:*",
+1 -1
packages/notifications/opsgenie/package.json
··· 7 7 "@t3-oss/env-core": "0.7.1", 8 8 "@types/validator": "13.11.6", 9 9 "validator": "13.12.0", 10 - "zod": "3.22.4" 10 + "zod": "3.23.8" 11 11 }, 12 12 "devDependencies": { 13 13 "@openstatus/tsconfig": "workspace:*",
+1 -1
packages/notifications/pagerduty/package.json
··· 7 7 "@t3-oss/env-core": "0.7.1", 8 8 "@types/validator": "13.11.6", 9 9 "validator": "13.12.0", 10 - "zod": "3.22.4" 10 + "zod": "3.23.8" 11 11 }, 12 12 "devDependencies": { 13 13 "@openstatus/tsconfig": "workspace:*",
+1 -1
packages/notifications/slack/package.json
··· 4 4 "main": "src/index.ts", 5 5 "dependencies": { 6 6 "@openstatus/db": "workspace:*", 7 - "zod": "3.22.4" 7 + "zod": "3.23.8" 8 8 }, 9 9 "devDependencies": { 10 10 "@openstatus/tsconfig": "workspace:*",
+53 -55
pnpm-lock.yaml
··· 92 92 version: 2.6.2 93 93 drizzle-orm: 94 94 specifier: 0.35.3 95 - version: 0.35.3(@cloudflare/workers-types@4.20241218.0)(@libsql/client-wasm@0.14.0)(@libsql/client@0.14.0(bufferutil@4.0.8)(utf-8-validate@6.0.5))(@opentelemetry/api@1.9.0)(@types/pg@8.11.10)(@types/react@19.0.1)(better-sqlite3@11.7.0)(bun-types@1.1.40)(react@19.0.0) 95 + version: 0.35.3(@cloudflare/workers-types@4.20241230.0)(@libsql/client-wasm@0.14.0)(@libsql/client@0.14.0(bufferutil@4.0.8)(utf-8-validate@6.0.5))(@opentelemetry/api@1.9.0)(@types/pg@8.11.10)(@types/react@19.0.1)(better-sqlite3@11.7.0)(bun-types@1.1.40)(react@19.0.0) 96 96 hono: 97 97 specifier: 4.5.3 98 98 version: 4.5.3 ··· 168 168 version: link:../../packages/utils 169 169 '@scalar/hono-api-reference': 170 170 specifier: 0.5.131 171 - version: 0.5.131(postcss@8.4.49)(storybook@8.4.7(bufferutil@4.0.8)(prettier@3.4.2)(utf-8-validate@6.0.5))(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.8.0)(typescript@5.7.2)))(typescript@5.7.2) 171 + version: 0.5.131(postcss@8.4.49)(storybook@8.4.7(bufferutil@4.0.8)(prettier@3.4.2)(utf-8-validate@6.0.5))(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.10.2)(typescript@5.7.2)))(typescript@5.7.2) 172 172 '@t3-oss/env-core': 173 173 specifier: 0.7.1 174 174 version: 0.7.1(typescript@5.7.2)(zod@3.23.8) ··· 486 486 '@openstatus/emails': 487 487 specifier: workspace:* 488 488 version: link:../../packages/emails 489 + '@openstatus/upstash': 490 + specifier: workspace:* 491 + version: link:../../packages/upstash 489 492 '@openstatus/utils': 490 493 specifier: workspace:* 491 494 version: link:../../packages/utils ··· 612 615 version: 0.7.0(typescript@5.6.2)(zod@3.23.8) 613 616 drizzle-orm: 614 617 specifier: 0.35.3 615 - version: 0.35.3(@cloudflare/workers-types@4.20241218.0)(@libsql/client-wasm@0.14.0)(@libsql/client@0.14.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@opentelemetry/api@1.9.0)(@types/pg@8.11.10)(@types/react@19.0.1)(better-sqlite3@11.4.0)(bun-types@1.1.40)(react@19.0.0) 618 + version: 0.35.3(@cloudflare/workers-types@4.20241230.0)(@libsql/client-wasm@0.14.0)(@libsql/client@0.14.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@opentelemetry/api@1.9.0)(@types/pg@8.11.10)(@types/react@19.0.1)(better-sqlite3@11.4.0)(bun-types@1.1.40)(react@19.0.0) 616 619 drizzle-zod: 617 620 specifier: 0.5.1 618 - version: 0.5.1(drizzle-orm@0.35.3(@cloudflare/workers-types@4.20241218.0)(@libsql/client-wasm@0.14.0)(@libsql/client@0.14.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@opentelemetry/api@1.9.0)(@types/pg@8.11.10)(@types/react@19.0.1)(better-sqlite3@11.4.0)(bun-types@1.1.40)(react@19.0.0))(zod@3.23.8) 621 + version: 0.5.1(drizzle-orm@0.35.3(@cloudflare/workers-types@4.20241230.0)(@libsql/client-wasm@0.14.0)(@libsql/client@0.14.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@opentelemetry/api@1.9.0)(@types/pg@8.11.10)(@types/react@19.0.1)(better-sqlite3@11.4.0)(bun-types@1.1.40)(react@19.0.0))(zod@3.23.8) 619 622 zod: 620 623 specifier: 3.23.8 621 624 version: 3.23.8 ··· 728 731 specifier: workspace:* 729 732 version: link:../../db 730 733 zod: 731 - specifier: 3.22.4 732 - version: 3.22.4 734 + specifier: 3.23.8 735 + version: 3.23.8 733 736 devDependencies: 734 737 '@openstatus/tsconfig': 735 738 specifier: workspace:* ··· 785 788 version: link:../../db 786 789 '@t3-oss/env-core': 787 790 specifier: 0.7.1 788 - version: 0.7.1(typescript@5.4.5)(zod@3.22.4) 791 + version: 0.7.1(typescript@5.4.5)(zod@3.23.8) 789 792 '@types/validator': 790 793 specifier: 13.11.6 791 794 version: 13.11.6 ··· 793 796 specifier: 13.12.0 794 797 version: 13.12.0 795 798 zod: 796 - specifier: 3.22.4 797 - version: 3.22.4 799 + specifier: 3.23.8 800 + version: 3.23.8 798 801 devDependencies: 799 802 '@openstatus/tsconfig': 800 803 specifier: workspace:* ··· 819 822 version: link:../../db 820 823 '@t3-oss/env-core': 821 824 specifier: 0.7.1 822 - version: 0.7.1(typescript@5.4.5)(zod@3.22.4) 825 + version: 0.7.1(typescript@5.4.5)(zod@3.23.8) 823 826 '@types/validator': 824 827 specifier: 13.11.6 825 828 version: 13.11.6 ··· 827 830 specifier: 13.12.0 828 831 version: 13.12.0 829 832 zod: 830 - specifier: 3.22.4 831 - version: 3.22.4 833 + specifier: 3.23.8 834 + version: 3.23.8 832 835 devDependencies: 833 836 '@openstatus/tsconfig': 834 837 specifier: workspace:* ··· 852 855 specifier: workspace:* 853 856 version: link:../../db 854 857 zod: 855 - specifier: 3.22.4 856 - version: 3.22.4 858 + specifier: 3.23.8 859 + version: 3.23.8 857 860 devDependencies: 858 861 '@openstatus/tsconfig': 859 862 specifier: workspace:* ··· 1716 1719 '@chronark/zod-bird@0.3.6': 1717 1720 resolution: {integrity: sha512-hE8kCGLJK5ncH8F7uPaqPiOOqo68vUI66nusg7HO5X9BcyN8lXfeQliu6Ou1kOSq95OYshf9nB2fk2+LEvF4ng==} 1718 1721 1719 - '@cloudflare/workers-types@4.20241218.0': 1720 - resolution: {integrity: sha512-Y0brjmJHcAZBXOPI7lU5hbiXglQWniA1kQjot2ata+HFimyjPPcz+4QWBRrmWcMPo0OadR2Vmac7WStDLpvz0w==} 1722 + '@cloudflare/workers-types@4.20241230.0': 1723 + resolution: {integrity: sha512-dtLD4jY35Lb750cCVyO1i/eIfdZJg2Z0i+B1RYX6BVeRPlgaHx/H18ImKAkYmy0g09Ow8R2jZy3hIxMgXun0WQ==} 1721 1724 1722 1725 '@codemirror/autocomplete@6.17.0': 1723 1726 resolution: {integrity: sha512-fdfj6e6ZxZf8yrkMHUSJJir7OJkHkZKaOZGzLWIYp2PZ3jd+d+UjG8zVPqJF6d3bKxkhvXTPan/UZ1t7Bqm0gA==} ··· 10316 10319 peerDependencies: 10317 10320 zod: ^3.18.0 10318 10321 10319 - zod@3.22.4: 10320 - resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} 10321 - 10322 10322 zod@3.23.8: 10323 10323 resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} 10324 10324 ··· 11329 11329 dependencies: 11330 11330 zod: 3.23.8 11331 11331 11332 - '@cloudflare/workers-types@4.20241218.0': 11332 + '@cloudflare/workers-types@4.20241230.0': 11333 11333 optional: true 11334 11334 11335 11335 '@codemirror/autocomplete@6.17.0(@codemirror/language@6.10.2)(@codemirror/state@6.4.1)(@codemirror/view@6.28.4)(@lezer/common@1.2.1)': ··· 12009 12009 protobufjs: 7.2.5 12010 12010 yargs: 17.7.2 12011 12011 12012 - '@headlessui/tailwindcss@0.2.0(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.8.0)(typescript@5.7.2)))': 12012 + '@headlessui/tailwindcss@0.2.0(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.10.2)(typescript@5.7.2)))': 12013 12013 dependencies: 12014 - tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@20.8.0)(typescript@5.7.2)) 12014 + tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@22.10.2)(typescript@5.7.2)) 12015 12015 12016 12016 '@headlessui/vue@1.7.22(vue@3.4.31(typescript@5.7.2))': 12017 12017 dependencies: ··· 13695 13695 '@rollup/rollup-win32-x64-msvc@4.28.1': 13696 13696 optional: true 13697 13697 13698 - '@scalar/api-client@2.0.45(storybook@8.4.7(bufferutil@4.0.8)(prettier@3.4.2)(utf-8-validate@6.0.5))(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.8.0)(typescript@5.7.2)))(typescript@5.7.2)': 13698 + '@scalar/api-client@2.0.45(storybook@8.4.7(bufferutil@4.0.8)(prettier@3.4.2)(utf-8-validate@6.0.5))(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.10.2)(typescript@5.7.2)))(typescript@5.7.2)': 13699 13699 dependencies: 13700 - '@headlessui/tailwindcss': 0.2.0(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.8.0)(typescript@5.7.2))) 13700 + '@headlessui/tailwindcss': 0.2.0(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.10.2)(typescript@5.7.2))) 13701 13701 '@headlessui/vue': 1.7.22(vue@3.4.31(typescript@5.7.2)) 13702 13702 '@scalar/components': 0.12.28(storybook@8.4.7(bufferutil@4.0.8)(prettier@3.4.2)(utf-8-validate@6.0.5))(typescript@5.7.2) 13703 13703 '@scalar/draggable': 0.1.4(typescript@5.7.2) ··· 13733 13733 - typescript 13734 13734 - vitest 13735 13735 13736 - '@scalar/api-reference@1.24.70(postcss@8.4.49)(storybook@8.4.7(bufferutil@4.0.8)(prettier@3.4.2)(utf-8-validate@6.0.5))(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.8.0)(typescript@5.7.2)))(typescript@5.7.2)': 13736 + '@scalar/api-reference@1.24.70(postcss@8.4.49)(storybook@8.4.7(bufferutil@4.0.8)(prettier@3.4.2)(utf-8-validate@6.0.5))(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.10.2)(typescript@5.7.2)))(typescript@5.7.2)': 13737 13737 dependencies: 13738 13738 '@floating-ui/vue': 1.1.1(vue@3.4.31(typescript@5.7.2)) 13739 13739 '@headlessui/vue': 1.7.22(vue@3.4.31(typescript@5.7.2)) 13740 - '@scalar/api-client': 2.0.45(storybook@8.4.7(bufferutil@4.0.8)(prettier@3.4.2)(utf-8-validate@6.0.5))(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.8.0)(typescript@5.7.2)))(typescript@5.7.2) 13740 + '@scalar/api-client': 2.0.45(storybook@8.4.7(bufferutil@4.0.8)(prettier@3.4.2)(utf-8-validate@6.0.5))(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.10.2)(typescript@5.7.2)))(typescript@5.7.2) 13741 13741 '@scalar/components': 0.12.28(storybook@8.4.7(bufferutil@4.0.8)(prettier@3.4.2)(utf-8-validate@6.0.5))(typescript@5.7.2) 13742 13742 '@scalar/oas-utils': 0.2.26(typescript@5.7.2) 13743 13743 '@scalar/openapi-parser': 0.7.2 ··· 13822 13822 transitivePeerDependencies: 13823 13823 - typescript 13824 13824 13825 - '@scalar/hono-api-reference@0.5.131(postcss@8.4.49)(storybook@8.4.7(bufferutil@4.0.8)(prettier@3.4.2)(utf-8-validate@6.0.5))(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.8.0)(typescript@5.7.2)))(typescript@5.7.2)': 13825 + '@scalar/hono-api-reference@0.5.131(postcss@8.4.49)(storybook@8.4.7(bufferutil@4.0.8)(prettier@3.4.2)(utf-8-validate@6.0.5))(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.10.2)(typescript@5.7.2)))(typescript@5.7.2)': 13826 13826 dependencies: 13827 - '@scalar/api-reference': 1.24.70(postcss@8.4.49)(storybook@8.4.7(bufferutil@4.0.8)(prettier@3.4.2)(utf-8-validate@6.0.5))(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.8.0)(typescript@5.7.2)))(typescript@5.7.2) 13827 + '@scalar/api-reference': 1.24.70(postcss@8.4.49)(storybook@8.4.7(bufferutil@4.0.8)(prettier@3.4.2)(utf-8-validate@6.0.5))(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.10.2)(typescript@5.7.2)))(typescript@5.7.2) 13828 13828 hono: 4.5.3 13829 13829 transitivePeerDependencies: 13830 13830 - '@jest/globals' ··· 14569 14569 optionalDependencies: 14570 14570 typescript: 5.6.2 14571 14571 14572 - '@t3-oss/env-core@0.7.1(typescript@5.4.5)(zod@3.22.4)': 14572 + '@t3-oss/env-core@0.7.1(typescript@5.4.5)(zod@3.23.8)': 14573 14573 dependencies: 14574 - zod: 3.22.4 14574 + zod: 3.23.8 14575 14575 optionalDependencies: 14576 14576 typescript: 5.4.5 14577 14577 ··· 15353 15353 15354 15354 agent-base@6.0.2: 15355 15355 dependencies: 15356 - debug: 4.3.7 15356 + debug: 4.4.0 15357 15357 transitivePeerDependencies: 15358 15358 - supports-color 15359 15359 ··· 16270 16270 transitivePeerDependencies: 16271 16271 - supports-color 16272 16272 16273 - drizzle-orm@0.35.3(@cloudflare/workers-types@4.20241218.0)(@libsql/client-wasm@0.14.0)(@libsql/client@0.14.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@opentelemetry/api@1.9.0)(@types/pg@8.11.10)(@types/react@19.0.1)(better-sqlite3@11.4.0)(bun-types@1.1.40)(react@19.0.0): 16273 + drizzle-orm@0.35.3(@cloudflare/workers-types@4.20241230.0)(@libsql/client-wasm@0.14.0)(@libsql/client@0.14.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@opentelemetry/api@1.9.0)(@types/pg@8.11.10)(@types/react@19.0.1)(better-sqlite3@11.4.0)(bun-types@1.1.40)(react@19.0.0): 16274 16274 dependencies: 16275 16275 '@libsql/client-wasm': 0.14.0 16276 16276 optionalDependencies: 16277 - '@cloudflare/workers-types': 4.20241218.0 16277 + '@cloudflare/workers-types': 4.20241230.0 16278 16278 '@libsql/client': 0.14.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) 16279 16279 '@opentelemetry/api': 1.9.0 16280 16280 '@types/pg': 8.11.10 ··· 16283 16283 bun-types: 1.1.40 16284 16284 react: 19.0.0 16285 16285 16286 - drizzle-orm@0.35.3(@cloudflare/workers-types@4.20241218.0)(@libsql/client-wasm@0.14.0)(@libsql/client@0.14.0(bufferutil@4.0.8)(utf-8-validate@6.0.5))(@opentelemetry/api@1.9.0)(@types/pg@8.11.10)(@types/react@19.0.1)(better-sqlite3@11.7.0)(bun-types@1.1.40)(react@19.0.0): 16286 + drizzle-orm@0.35.3(@cloudflare/workers-types@4.20241230.0)(@libsql/client-wasm@0.14.0)(@libsql/client@0.14.0(bufferutil@4.0.8)(utf-8-validate@6.0.5))(@opentelemetry/api@1.9.0)(@types/pg@8.11.10)(@types/react@19.0.1)(better-sqlite3@11.7.0)(bun-types@1.1.40)(react@19.0.0): 16287 16287 dependencies: 16288 16288 '@libsql/client-wasm': 0.14.0 16289 16289 optionalDependencies: 16290 - '@cloudflare/workers-types': 4.20241218.0 16290 + '@cloudflare/workers-types': 4.20241230.0 16291 16291 '@libsql/client': 0.14.0(bufferutil@4.0.8)(utf-8-validate@6.0.5) 16292 16292 '@opentelemetry/api': 1.9.0 16293 16293 '@types/pg': 8.11.10 ··· 16296 16296 bun-types: 1.1.40 16297 16297 react: 19.0.0 16298 16298 16299 - drizzle-zod@0.5.1(drizzle-orm@0.35.3(@cloudflare/workers-types@4.20241218.0)(@libsql/client-wasm@0.14.0)(@libsql/client@0.14.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@opentelemetry/api@1.9.0)(@types/pg@8.11.10)(@types/react@19.0.1)(better-sqlite3@11.4.0)(bun-types@1.1.40)(react@19.0.0))(zod@3.23.8): 16299 + drizzle-zod@0.5.1(drizzle-orm@0.35.3(@cloudflare/workers-types@4.20241230.0)(@libsql/client-wasm@0.14.0)(@libsql/client@0.14.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@opentelemetry/api@1.9.0)(@types/pg@8.11.10)(@types/react@19.0.1)(better-sqlite3@11.4.0)(bun-types@1.1.40)(react@19.0.0))(zod@3.23.8): 16300 16300 dependencies: 16301 - drizzle-orm: 0.35.3(@cloudflare/workers-types@4.20241218.0)(@libsql/client-wasm@0.14.0)(@libsql/client@0.14.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@opentelemetry/api@1.9.0)(@types/pg@8.11.10)(@types/react@19.0.1)(better-sqlite3@11.4.0)(bun-types@1.1.40)(react@19.0.0) 16301 + drizzle-orm: 0.35.3(@cloudflare/workers-types@4.20241230.0)(@libsql/client-wasm@0.14.0)(@libsql/client@0.14.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@opentelemetry/api@1.9.0)(@types/pg@8.11.10)(@types/react@19.0.1)(better-sqlite3@11.4.0)(bun-types@1.1.40)(react@19.0.0) 16302 16302 zod: 3.23.8 16303 16303 16304 16304 dset@3.1.4: {} ··· 17314 17314 dependencies: 17315 17315 '@tootallnate/once': 2.0.0 17316 17316 agent-base: 6.0.2 17317 - debug: 4.3.7 17317 + debug: 4.4.0 17318 17318 transitivePeerDependencies: 17319 17319 - supports-color 17320 17320 ··· 17328 17328 https-proxy-agent@5.0.1: 17329 17329 dependencies: 17330 17330 agent-base: 6.0.2 17331 - debug: 4.3.4 17331 + debug: 4.4.0 17332 17332 transitivePeerDependencies: 17333 17333 - supports-color 17334 17334 ··· 18765 18765 isbinaryfile: 4.0.10 18766 18766 lodash.get: 4.4.2 18767 18767 mkdirp: 0.5.6 18768 - resolve: 1.22.8 18768 + resolve: 1.22.9 18769 18769 18770 18770 node-releases@2.0.14: {} 18771 18771 ··· 19151 19151 postcss: 8.4.38 19152 19152 ts-node: 10.9.2(@types/node@22.10.2)(typescript@5.6.2) 19153 19153 19154 - postcss-load-config@4.0.2(postcss@8.4.49)(ts-node@10.9.2(@types/node@20.8.0)(typescript@5.7.2)): 19154 + postcss-load-config@4.0.2(postcss@8.4.49)(ts-node@10.9.2(@types/node@22.10.2)(typescript@5.6.2)): 19155 19155 dependencies: 19156 19156 lilconfig: 3.1.2 19157 19157 yaml: 2.6.1 19158 19158 optionalDependencies: 19159 19159 postcss: 8.4.49 19160 - ts-node: 10.9.2(@types/node@20.8.0)(typescript@5.7.2) 19160 + ts-node: 10.9.2(@types/node@22.10.2)(typescript@5.6.2) 19161 19161 19162 - postcss-load-config@4.0.2(postcss@8.4.49)(ts-node@10.9.2(@types/node@22.10.2)(typescript@5.6.2)): 19162 + postcss-load-config@4.0.2(postcss@8.4.49)(ts-node@10.9.2(@types/node@22.10.2)(typescript@5.7.2)): 19163 19163 dependencies: 19164 19164 lilconfig: 3.1.2 19165 19165 yaml: 2.6.1 19166 19166 optionalDependencies: 19167 19167 postcss: 8.4.49 19168 - ts-node: 10.9.2(@types/node@22.10.2)(typescript@5.6.2) 19168 + ts-node: 10.9.2(@types/node@22.10.2)(typescript@5.7.2) 19169 19169 19170 19170 postcss-nested@6.0.1(postcss@8.4.49): 19171 19171 dependencies: ··· 20405 20405 dependencies: 20406 20406 tailwindcss: 3.4.3(ts-node@10.9.2(@types/node@22.10.2)(typescript@5.6.2)) 20407 20407 20408 - tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.8.0)(typescript@5.7.2)): 20408 + tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.10.2)(typescript@5.6.2)): 20409 20409 dependencies: 20410 20410 '@alloc/quick-lru': 5.2.0 20411 20411 arg: 5.0.2 ··· 20424 20424 postcss: 8.4.49 20425 20425 postcss-import: 15.1.0(postcss@8.4.49) 20426 20426 postcss-js: 4.0.1(postcss@8.4.49) 20427 - postcss-load-config: 4.0.2(postcss@8.4.49)(ts-node@10.9.2(@types/node@20.8.0)(typescript@5.7.2)) 20427 + postcss-load-config: 4.0.2(postcss@8.4.49)(ts-node@10.9.2(@types/node@22.10.2)(typescript@5.6.2)) 20428 20428 postcss-nested: 6.2.0(postcss@8.4.49) 20429 20429 postcss-selector-parser: 6.1.2 20430 20430 resolve: 1.22.9 ··· 20432 20432 transitivePeerDependencies: 20433 20433 - ts-node 20434 20434 20435 - tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.10.2)(typescript@5.6.2)): 20435 + tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.10.2)(typescript@5.7.2)): 20436 20436 dependencies: 20437 20437 '@alloc/quick-lru': 5.2.0 20438 20438 arg: 5.0.2 ··· 20451 20451 postcss: 8.4.49 20452 20452 postcss-import: 15.1.0(postcss@8.4.49) 20453 20453 postcss-js: 4.0.1(postcss@8.4.49) 20454 - postcss-load-config: 4.0.2(postcss@8.4.49)(ts-node@10.9.2(@types/node@22.10.2)(typescript@5.6.2)) 20454 + postcss-load-config: 4.0.2(postcss@8.4.49)(ts-node@10.9.2(@types/node@22.10.2)(typescript@5.7.2)) 20455 20455 postcss-nested: 6.2.0(postcss@8.4.49) 20456 20456 postcss-selector-parser: 6.1.2 20457 20457 resolve: 1.22.9 ··· 20702 20702 v8-compile-cache-lib: 3.0.1 20703 20703 yn: 3.1.1 20704 20704 20705 - ts-node@10.9.2(@types/node@20.8.0)(typescript@5.7.2): 20705 + ts-node@10.9.2(@types/node@22.10.2)(typescript@5.6.2): 20706 20706 dependencies: 20707 20707 '@cspotcode/source-map-support': 0.8.1 20708 20708 '@tsconfig/node10': 1.0.11 20709 20709 '@tsconfig/node12': 1.0.11 20710 20710 '@tsconfig/node14': 1.0.3 20711 20711 '@tsconfig/node16': 1.0.4 20712 - '@types/node': 20.8.0 20712 + '@types/node': 22.10.2 20713 20713 acorn: 8.11.3 20714 20714 acorn-walk: 8.3.2 20715 20715 arg: 4.1.3 20716 20716 create-require: 1.1.1 20717 20717 diff: 4.0.2 20718 20718 make-error: 1.3.6 20719 - typescript: 5.7.2 20719 + typescript: 5.6.2 20720 20720 v8-compile-cache-lib: 3.0.1 20721 20721 yn: 3.1.1 20722 20722 optional: true 20723 20723 20724 - ts-node@10.9.2(@types/node@22.10.2)(typescript@5.6.2): 20724 + ts-node@10.9.2(@types/node@22.10.2)(typescript@5.7.2): 20725 20725 dependencies: 20726 20726 '@cspotcode/source-map-support': 0.8.1 20727 20727 '@tsconfig/node10': 1.0.11 ··· 20735 20735 create-require: 1.1.1 20736 20736 diff: 4.0.2 20737 20737 make-error: 1.3.6 20738 - typescript: 5.6.2 20738 + typescript: 5.7.2 20739 20739 v8-compile-cache-lib: 3.0.1 20740 20740 yn: 3.1.1 20741 20741 optional: true ··· 21536 21536 zod-validation-error@3.3.0(zod@3.23.8): 21537 21537 dependencies: 21538 21538 zod: 3.23.8 21539 - 21540 - zod@3.22.4: {} 21541 21539 21542 21540 zod@3.23.8: {} 21543 21541