Openstatus www.openstatus.dev

๐Ÿš€ Threshold monitor (#778)

* ๐Ÿšง wip

* ๐Ÿšง wip

* ๐Ÿš€ degraded

* ๐Ÿš€ degraded

* ๐Ÿš€ degraded

* ๐Ÿš€ degraded

* ๐Ÿค” strange

* ๐Ÿค” trying

* ๐Ÿค” empty value

* ๐Ÿš€ degraded

* ๐Ÿ”ฅ degraded

* ๐Ÿš€ degraded

* ๐Ÿ”ฅ update pr

* ๐Ÿ›‚ pr

* ๐Ÿ“ changelog

* ๐Ÿš€ update image

authored by

Thibault Le Ouay and committed by
GitHub
db163f6e b79b052f

+2576 -227
+28 -3
apps/checker/cmd/main.go
··· 95 } 96 // We need a new client for each request to avoid connection reuse. 97 requestClient := &http.Client{ 98 - Timeout: 45 * time.Second, 99 } 100 defer requestClient.CloseIdleConnections() 101 ··· 171 } 172 173 res.Assertions = assertionAsString 174 if !isSuccessfull && req.Status == "active" { 175 // Q: Why here we do not check if the status was previously active? 176 checker.UpdateStatus(ctx, checker.UpdateData{ ··· 182 CronTimestamp: req.CronTimestamp, 183 }) 184 } 185 - 186 - if req.Status == "error" && isSuccessfull { 187 // Q: Why here we check the data before updating the status in this scenario? 188 checker.UpdateStatus(ctx, checker.UpdateData{ 189 MonitorId: req.MonitorID, ··· 192 StatusCode: res.StatusCode, 193 CronTimestamp: req.CronTimestamp, 194 }) 195 } 196 197 if err := tinybirdClient.SendEvent(ctx, res, dataSourceName); err != nil {
··· 95 } 96 // We need a new client for each request to avoid connection reuse. 97 requestClient := &http.Client{ 98 + Timeout: time.Duration(req.Timeout) * time.Millisecond, 99 } 100 defer requestClient.CloseIdleConnections() 101 ··· 171 } 172 173 res.Assertions = assertionAsString 174 + // That part could be refactored 175 if !isSuccessfull && req.Status == "active" { 176 // Q: Why here we do not check if the status was previously active? 177 checker.UpdateStatus(ctx, checker.UpdateData{ ··· 183 CronTimestamp: req.CronTimestamp, 184 }) 185 } 186 + // Check if the status is degraded 187 + if isSuccessfull && req.Status == "active" { 188 + if req.DegradedAfter > 0 && res.Latency > req.DegradedAfter { 189 + checker.UpdateStatus(ctx, checker.UpdateData{ 190 + MonitorId: req.MonitorID, 191 + Status: "degraded", 192 + Region: flyRegion, 193 + StatusCode: res.StatusCode, 194 + CronTimestamp: req.CronTimestamp, 195 + }) 196 + } 197 + } 198 + // We were in error and now we are successful don't check for degraded 199 + if isSuccessfull && req.Status == "error" { 200 // Q: Why here we check the data before updating the status in this scenario? 201 checker.UpdateStatus(ctx, checker.UpdateData{ 202 MonitorId: req.MonitorID, ··· 205 StatusCode: res.StatusCode, 206 CronTimestamp: req.CronTimestamp, 207 }) 208 + } 209 + // if we were in degraded and now we are successful, we should update the status to active 210 + if isSuccessfull && req.Status == "degraded" { 211 + if req.DegradedAfter > 0 && res.Latency <= req.DegradedAfter { 212 + checker.UpdateStatus(ctx, checker.UpdateData{ 213 + MonitorId: req.MonitorID, 214 + Status: "active", 215 + Region: flyRegion, 216 + StatusCode: res.StatusCode, 217 + CronTimestamp: req.CronTimestamp, 218 + }) 219 + } 220 } 221 222 if err := tinybirdClient.SendEvent(ctx, res, dataSourceName); err != nil {
+2
apps/checker/request/request.go
··· 52 Method string `json:"method"` 53 CronTimestamp int64 `json:"cronTimestamp"` 54 Body string `json:"body"` 55 Headers []struct { 56 Key string `json:"key"` 57 Value string `json:"value"`
··· 52 Method string `json:"method"` 53 CronTimestamp int64 `json:"cronTimestamp"` 54 Body string `json:"body"` 55 + Timeout int64 `json:"timeout"` 56 + DegradedAfter int64 `json:"degradedAfter,omitempty"` 57 Headers []struct { 58 Key string `json:"key"` 59 Value string `json:"value"`
+9 -1
apps/server/src/checker/alerting.ts
··· 21 monitorId: string; 22 statusCode?: number; 23 message?: string; 24 - notifType: "alert" | "recovery"; 25 incidentId?: string; 26 }) => { 27 console.log(`๐Ÿ’Œ triggerAlerting for ${monitorId}`); ··· 60 statusCode, 61 message, 62 incidentId, 63 }); 64 break; 65 }
··· 21 monitorId: string; 22 statusCode?: number; 23 message?: string; 24 + notifType: "alert" | "recovery" | "degraded"; 25 incidentId?: string; 26 }) => { 27 console.log(`๐Ÿ’Œ triggerAlerting for ${monitorId}`); ··· 60 statusCode, 61 message, 62 incidentId, 63 + }); 64 + break; 65 + case "degraded": 66 + await providerToFunction[notif.notification.provider].sendDegraded({ 67 + monitor, 68 + notification: selectNotificationSchema.parse(notif.notification), 69 + statusCode, 70 + message, 71 }); 72 break; 73 }
+49 -8
apps/server/src/checker/index.ts
··· 59 and( 60 eq(incidentTable.monitorId, Number(monitorId)), 61 isNull(incidentTable.resolvedAt), 62 - isNull(incidentTable.acknowledgedAt), 63 - ), 64 ) 65 .get(); 66 67 // if we are in error 68 if (status === "error") { 69 // trigger alerting ··· 100 const numberOfRegions = monitor.regions.length; 101 102 console.log( 103 - `๐Ÿค“ MonitorID ${monitorId} incident current affected ${nbAffectedRegion} total region ${numberOfRegions}`, 104 ); 105 // If the number of affected regions is greater than half of the total region, we trigger the alerting 106 // 4 of 6 monitor need to fail to trigger an alerting ··· 114 eq(incidentTable.monitorId, Number(monitorId)), 115 isNull(incidentTable.resolvedAt), 116 isNull(incidentTable.acknowledgedAt), 117 - eq(incidentTable.startedAt, new Date(cronTimestamp)), 118 - ), 119 ) 120 .get(); 121 ··· 192 const numberOfRegions = monitor.regions.length; 193 194 console.log( 195 - `๐Ÿค“ MonitorId ${monitorId} recovering incident current ${nbAffectedRegion} total region ${numberOfRegions}`, 196 ); 197 // // If the number of affected regions is greater than half of the total region, we trigger the alerting 198 // // 4 of 6 monitor need to fail to trigger an alerting ··· 204 and( 205 eq(incidentTable.monitorId, Number(monitorId)), 206 isNull(incidentTable.resolvedAt), 207 - isNull(incidentTable.acknowledgedAt), 208 - ), 209 ) 210 .get(); 211 if (incident) {
··· 59 and( 60 eq(incidentTable.monitorId, Number(monitorId)), 61 isNull(incidentTable.resolvedAt), 62 + isNull(incidentTable.acknowledgedAt) 63 + ) 64 ) 65 .get(); 66 67 + if (status === "degraded") { 68 + // We upsert the status of the monitor 69 + await upsertMonitorStatus({ 70 + monitorId: monitorId, 71 + status: "degraded", 72 + region: region, 73 + }); 74 + await checkerAudit.publishAuditLog({ 75 + id: `monitor:${monitorId}`, 76 + action: "monitor.degraded", 77 + targets: [{ id: monitorId, type: "monitor" }], 78 + metadata: { region, statusCode: Number(statusCode) }, 79 + }); 80 + const currentMonitor = await db 81 + .select() 82 + .from(schema.monitor) 83 + .where(eq(schema.monitor.id, Number(monitorId))) 84 + .get(); 85 + if (currentMonitor?.status === "active") { 86 + const redisKey = `${monitorId}-${cronTimestamp}-degraded`; 87 + // We add the new region to the set 88 + await redis.sadd(redisKey, region); 89 + // let's add an expire to the set 90 + await redis.expire(redisKey, 60 * 60 * 24); 91 + // We get the number of regions affected 92 + const nbAffectedRegion = await redis.scard(redisKey); 93 + 94 + const monitor = selectMonitorSchema.parse(currentMonitor); 95 + 96 + const numberOfRegions = monitor.regions.length; 97 + 98 + if (nbAffectedRegion > numberOfRegions / 2) { 99 + await triggerNotifications({ 100 + monitorId, 101 + statusCode, 102 + message, 103 + notifType: "degraded", 104 + }); 105 + } 106 + } 107 + } 108 // if we are in error 109 if (status === "error") { 110 // trigger alerting ··· 141 const numberOfRegions = monitor.regions.length; 142 143 console.log( 144 + `๐Ÿค“ MonitorID ${monitorId} incident current affected ${nbAffectedRegion} total region ${numberOfRegions}` 145 ); 146 // If the number of affected regions is greater than half of the total region, we trigger the alerting 147 // 4 of 6 monitor need to fail to trigger an alerting ··· 155 eq(incidentTable.monitorId, Number(monitorId)), 156 isNull(incidentTable.resolvedAt), 157 isNull(incidentTable.acknowledgedAt), 158 + eq(incidentTable.startedAt, new Date(cronTimestamp)) 159 + ) 160 ) 161 .get(); 162 ··· 233 const numberOfRegions = monitor.regions.length; 234 235 console.log( 236 + `๐Ÿค“ MonitorId ${monitorId} recovering incident current ${nbAffectedRegion} total region ${numberOfRegions}` 237 ); 238 // // If the number of affected regions is greater than half of the total region, we trigger the alerting 239 // // 4 of 6 monitor need to fail to trigger an alerting ··· 245 and( 246 eq(incidentTable.monitorId, Number(monitorId)), 247 isNull(incidentTable.resolvedAt), 248 + isNull(incidentTable.acknowledgedAt) 249 + ) 250 ) 251 .get(); 252 if (incident) {
+20 -2
apps/server/src/checker/utils.ts
··· 6 import { 7 sendAlert as sendDiscordAlert, 8 sendRecovery as sendDiscordRecovery, 9 } from "@openstatus/notification-discord"; 10 import { 11 sendAlert as sendEmailAlert, 12 sendRecovery as sendEmailRecovery, 13 } from "@openstatus/notification-emails"; 14 import { 15 sendAlert as sendSlackAlert, 16 sendRecovery as sendSlackRecovery, 17 } from "@openstatus/notification-slack"; 18 import { 19 sendAlert as sendSmsAlert, 20 sendRecovery as sendSmsRecovery, 21 } from "@openstatus/notification-twillio-sms"; 22 23 import { 24 sendAlert as sendPagerdutyAlert, 25 sendRecovery as sendPagerDutyRecovery, 26 } from "@openstatus/notification-pagerduty"; 27 28 type SendNotification = ({ ··· 42 type Notif = { 43 sendAlert: SendNotification; 44 sendRecovery: SendNotification; 45 }; 46 export const providerToFunction = { 47 email: { 48 sendAlert: sendEmailAlert, 49 sendRecovery: sendEmailRecovery, 50 }, 51 slack: { 52 sendAlert: sendSlackAlert, 53 sendRecovery: sendSlackRecovery, 54 }, 55 - discord: { sendAlert: sendDiscordAlert, sendRecovery: sendDiscordRecovery }, 56 - sms: { sendAlert: sendSmsAlert, sendRecovery: sendSmsRecovery }, 57 pagerduty: { 58 sendAlert: sendPagerdutyAlert, 59 sendRecovery: sendPagerDutyRecovery, 60 }, 61 } satisfies Record<NotificationProvider, Notif>;
··· 6 import { 7 sendAlert as sendDiscordAlert, 8 sendRecovery as sendDiscordRecovery, 9 + sendDegraded as sendDiscordDegraded, 10 } from "@openstatus/notification-discord"; 11 import { 12 sendAlert as sendEmailAlert, 13 sendRecovery as sendEmailRecovery, 14 + sendDegraded as sendEmailDegraded, 15 } from "@openstatus/notification-emails"; 16 import { 17 sendAlert as sendSlackAlert, 18 sendRecovery as sendSlackRecovery, 19 + sendDegraded as sendSlackDegraded, 20 } from "@openstatus/notification-slack"; 21 import { 22 sendAlert as sendSmsAlert, 23 sendRecovery as sendSmsRecovery, 24 + sendDegraded as sendSmsDegraded, 25 } from "@openstatus/notification-twillio-sms"; 26 27 import { 28 sendAlert as sendPagerdutyAlert, 29 sendRecovery as sendPagerDutyRecovery, 30 + sendDegraded as sendPagerDutyDegraded, 31 } from "@openstatus/notification-pagerduty"; 32 33 type SendNotification = ({ ··· 47 type Notif = { 48 sendAlert: SendNotification; 49 sendRecovery: SendNotification; 50 + sendDegraded: SendNotification; 51 }; 52 export const providerToFunction = { 53 email: { 54 sendAlert: sendEmailAlert, 55 sendRecovery: sendEmailRecovery, 56 + sendDegraded: sendEmailDegraded, 57 }, 58 slack: { 59 sendAlert: sendSlackAlert, 60 sendRecovery: sendSlackRecovery, 61 + sendDegraded: sendSlackDegraded, 62 }, 63 + discord: { 64 + sendAlert: sendDiscordAlert, 65 + sendRecovery: sendDiscordRecovery, 66 + sendDegraded: sendDiscordDegraded, 67 + }, 68 + sms: { 69 + sendAlert: sendSmsAlert, 70 + sendRecovery: sendSmsRecovery, 71 + sendDegraded: sendSmsDegraded, 72 + }, 73 + 74 pagerduty: { 75 sendAlert: sendPagerdutyAlert, 76 sendRecovery: sendPagerDutyRecovery, 77 + sendDegraded: sendPagerDutyDegraded, 78 }, 79 } satisfies Record<NotificationProvider, Notif>;
apps/web/public/assets/changelog/monitor-threshold.png

This is a binary file and will not be displayed.

+2
apps/web/src/app/api/checker/cron/_cron.ts
··· 156 headers: row.headers, 157 status: status, 158 assertions: row.assertions ? JSON.parse(row.assertions) : null, 159 }; 160 161 const newTask: google.cloud.tasks.v2beta3.ITask = {
··· 156 headers: row.headers, 157 status: status, 158 assertions: row.assertions ? JSON.parse(row.assertions) : null, 159 + degradedAfter: row.degradedAfter, 160 + timeout: row.timeout, 161 }; 162 163 const newTask: google.cloud.tasks.v2beta3.ITask = {
+2
apps/web/src/app/api/checker/schema.ts
··· 13 cronTimestamp: z.number(), 14 status: z.enum(monitorStatus), 15 assertions: z.array(base).nullable(), 16 }); 17 18 export type Payload = z.infer<typeof payloadSchema>;
··· 13 cronTimestamp: z.number(), 14 status: z.enum(monitorStatus), 15 assertions: z.array(base).nullable(), 16 + timeout: z.number().default(45000), 17 + degradedAfter: z.number().nullable(), 18 }); 19 20 export type Payload = z.infer<typeof payloadSchema>;
+4 -2
apps/web/src/app/app/[workspaceSlug]/(dashboard)/monitors/[id]/edit/page.tsx
··· 36 defaultSection={search.success ? search.data.section : undefined} 37 defaultValues={{ 38 ...monitor, 39 pages: pages 40 .filter((page) => 41 - page.monitorsToPages.map(({ monitorId }) => monitorId).includes(id), 42 ) 43 .map(({ id }) => id), 44 notifications: monitorNotifications?.map(({ id }) => id), 45 tags: tags 46 .filter((tag) => 47 - tag.monitor.map(({ monitorId }) => monitorId).includes(id), 48 ) 49 .map(({ id }) => id), 50 }}
··· 36 defaultSection={search.success ? search.data.section : undefined} 37 defaultValues={{ 38 ...monitor, 39 + // FIXME - Why is this not working? 40 + degradedAfter: monitor.degradedAfter ?? undefined, 41 pages: pages 42 .filter((page) => 43 + page.monitorsToPages.map(({ monitorId }) => monitorId).includes(id) 44 ) 45 .map(({ id }) => id), 46 notifications: monitorNotifications?.map(({ id }) => id), 47 tags: tags 48 .filter((tag) => 49 + tag.monitor.map(({ monitorId }) => monitorId).includes(id) 50 ) 51 .map(({ id }) => id), 52 }}
+2 -2
apps/web/src/components/content/changelog.tsx
··· 12 {formatDate(new Date(post.publishedAt))} 13 </p> 14 <h1 className="mb-5 font-cal text-3xl">{post.title}</h1> 15 - <div className="relative h-64 w-full overflow-hidden rounded-lg border border-border"> 16 <Image 17 src={post.image} 18 fill={true} 19 alt={post.title} 20 - className="object-cover" 21 /> 22 </div> 23 </div>
··· 12 {formatDate(new Date(post.publishedAt))} 13 </p> 14 <h1 className="mb-5 font-cal text-3xl">{post.title}</h1> 15 + <div className="relative aspect-video w-full overflow-hidden rounded-lg border border-border"> 16 <Image 17 src={post.image} 18 fill={true} 19 alt={post.title} 20 + className="object-contain" 21 /> 22 </div> 23 </div>
+5 -3
apps/web/src/components/forms/monitor/form.tsx
··· 29 import { toast, toastAction } from "@/lib/toast"; 30 import { formatDuration } from "@/lib/utils"; 31 import { api } from "@/trpc/client"; 32 - import type { Writeable } from "@/types/utils"; 33 import { SaveButton } from "../shared/save-button"; 34 import { General } from "./general"; 35 import { RequestTestButton } from "./request-test-button"; ··· 87 statusAssertions: _assertions.filter((a) => a.type === "status") as any, // TS considers a.type === "header" 88 // biome-ignore lint/suspicious/noExplicitAny: <explanation> 89 headerAssertions: _assertions.filter((a) => a.type === "header") as any, // TS considers a.type === "status" 90 }, 91 }); 92 const router = useRouter(); ··· 257 > 258 <TabsList> 259 <TabsTrigger value="request">Request</TabsTrigger> 260 - <TabsTrigger value="scheduling">Scheduling</TabsTrigger> 261 <TabsTrigger value="assertions"> 262 - Assertions{" "} 263 {_assertions.length ? ( 264 <Badge variant="secondary" className="ml-1"> 265 {_assertions.length}
··· 29 import { toast, toastAction } from "@/lib/toast"; 30 import { formatDuration } from "@/lib/utils"; 31 import { api } from "@/trpc/client"; 32 import { SaveButton } from "../shared/save-button"; 33 import { General } from "./general"; 34 import { RequestTestButton } from "./request-test-button"; ··· 86 statusAssertions: _assertions.filter((a) => a.type === "status") as any, // TS considers a.type === "header" 87 // biome-ignore lint/suspicious/noExplicitAny: <explanation> 88 headerAssertions: _assertions.filter((a) => a.type === "header") as any, // TS considers a.type === "status" 89 + 90 + degradedAfter: defaultValues?.degradedAfter, 91 + timeout: defaultValues?.timeout || 45000, 92 }, 93 }); 94 const router = useRouter(); ··· 259 > 260 <TabsList> 261 <TabsTrigger value="request">Request</TabsTrigger> 262 + <TabsTrigger value="scheduling">Scheduling & Regions</TabsTrigger> 263 <TabsTrigger value="assertions"> 264 + Timing & Assertions{" "} 265 {_assertions.length ? ( 266 <Badge variant="secondary" className="ml-1"> 267 {_assertions.length}
+63
apps/web/src/components/forms/monitor/section-assertions.tsx
··· 13 import { 14 Button, 15 FormControl, 16 FormField, 17 FormItem, 18 Input, 19 Select, 20 SelectContent, ··· 53 54 return ( 55 <div className="grid w-full gap-4"> 56 <SectionHeader 57 title="Assertions" 58 description={
··· 13 import { 14 Button, 15 FormControl, 16 + FormDescription, 17 FormField, 18 FormItem, 19 + FormLabel, 20 Input, 21 Select, 22 SelectContent, ··· 55 56 return ( 57 <div className="grid w-full gap-4"> 58 + <SectionHeader 59 + title="Timing Setting" 60 + description={ 61 + <> 62 + Add specific time limits to your requests to receive notifications 63 + if an endpoint takes longer than expected. 64 + </> 65 + } 66 + /> 67 + <div className="grid w-full gap-4 sm:grid-cols-6"> 68 + <FormField 69 + control={form.control} 70 + name="degradedAfter" 71 + render={({ field }) => ( 72 + <FormItem className="col-span-6 sm:col-span-3"> 73 + <FormLabel>Degraded</FormLabel> 74 + <FormControl> 75 + <Input 76 + className="bg-muted" 77 + type="number" 78 + min={0} 79 + max={60000} 80 + placeholder="30000" 81 + {...form.register(field.name, { 82 + setValueAs: (v) => (v === "" ? null : v), 83 + })} 84 + /> 85 + </FormControl> 86 + <FormDescription> 87 + In milliseconds, the time after which the endpoint is considered 88 + degraded. 89 + </FormDescription> 90 + </FormItem> 91 + )} 92 + /> 93 + <FormField 94 + control={form.control} 95 + name="timeout" 96 + render={({ field }) => ( 97 + <FormItem className="col-span-6 sm:col-span-3"> 98 + <FormLabel>Timeout</FormLabel> 99 + <FormControl> 100 + <Input 101 + className="bg-muted" 102 + type="number" 103 + placeholder="45000" 104 + min={0} 105 + max={60000} 106 + {...field} 107 + /> 108 + </FormControl> 109 + <FormDescription> 110 + In milliseconds, the maximum time allowed for the request to 111 + complete. 112 + </FormDescription> 113 + 114 + {/* <FormMessage /> */} 115 + </FormItem> 116 + )} 117 + /> 118 + </div> 119 <SectionHeader 120 title="Assertions" 121 description={
+1 -1
apps/web/src/components/forms/monitor/section-requests.tsx
··· 111 control={form.control} 112 name="url" 113 render={({ field }) => ( 114 - <FormItem className="sm:col-span-5"> 115 <FormLabel>URL</FormLabel> 116 <FormControl> 117 {/* <InputWithAddons
··· 111 control={form.control} 112 name="url" 113 render={({ field }) => ( 114 + <FormItem className="sm:col-span-6"> 115 <FormLabel>URL</FormLabel> 116 <FormControl> 117 {/* <InputWithAddons
+1
apps/web/src/components/monitor/status-dot-with-tooltip.tsx
··· 23 if (!active) return "Monitor is inactive"; 24 if (maintenance) return "Monitor in maintenance"; 25 if (status === "error") return "Monitor has failed"; 26 return "Monitor is active"; 27 })()} 28 </TooltipContent>
··· 23 if (!active) return "Monitor is inactive"; 24 if (maintenance) return "Monitor in maintenance"; 25 if (status === "error") return "Monitor has failed"; 26 + if (status === "degraded") return "Monitor is degraded"; 27 return "Monitor is active"; 28 })()} 29 </TooltipContent>
+8
apps/web/src/components/monitor/status-dot.tsx
··· 30 </span> 31 ); 32 } 33 34 return ( 35 <span className="relative flex h-2 w-2">
··· 30 </span> 31 ); 32 } 33 + if (status === "degraded") { 34 + return ( 35 + <span className="relative flex h-2 w-2"> 36 + <span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-yellow-500/80 opacity-75 duration-[2000ms]" /> 37 + <span className="relative inline-flex h-2 w-2 rounded-full bg-yellow-500" /> 38 + </span> 39 + ); 40 + } 41 42 return ( 43 <span className="relative flex h-2 w-2">
+12
apps/web/src/content/changelog/monitor-threshold.mdx
···
··· 1 + --- 2 + title: Monitor Threshold 3 + description: Set custom request timeouts and degradation timing. 4 + image: /assets/changelog/monitor-threshold.png 5 + publishedAt: 2024-07-01 6 + --- 7 + Sometimes you need to get notified if your monitor is taking too long to respond or if it's degrading. 8 + 9 + You can set custom request timeouts and degradation timing for your monitors. 10 + 11 + We have added this feature to the monitor settings. 12 +
+2
packages/db/drizzle/0033_solid_colossus.sql
···
··· 1 + ALTER TABLE `monitor` ADD `timeout` integer DEFAULT 45000 NOT NULL;--> statement-breakpoint 2 + ALTER TABLE `monitor` ADD `degraded_after` integer;
+64 -199
packages/db/drizzle/meta/0025_snapshot.json
··· 33 "status_report_to_monitors_monitor_id_monitor_id_fk": { 34 "name": "status_report_to_monitors_monitor_id_monitor_id_fk", 35 "tableFrom": "status_report_to_monitors", 36 - "columnsFrom": [ 37 - "monitor_id" 38 - ], 39 "tableTo": "monitor", 40 - "columnsTo": [ 41 - "id" 42 - ], 43 "onUpdate": "no action", 44 "onDelete": "cascade" 45 }, 46 "status_report_to_monitors_status_report_id_status_report_id_fk": { 47 "name": "status_report_to_monitors_status_report_id_status_report_id_fk", 48 "tableFrom": "status_report_to_monitors", 49 - "columnsFrom": [ 50 - "status_report_id" 51 - ], 52 "tableTo": "status_report", 53 - "columnsTo": [ 54 - "id" 55 - ], 56 "onUpdate": "no action", 57 "onDelete": "cascade" 58 } 59 }, 60 "compositePrimaryKeys": { 61 "status_report_to_monitors_monitor_id_status_report_id_pk": { 62 - "columns": [ 63 - "monitor_id", 64 - "status_report_id" 65 - ], 66 "name": "status_report_to_monitors_monitor_id_status_report_id_pk" 67 } 68 }, ··· 99 "status_reports_to_pages_page_id_page_id_fk": { 100 "name": "status_reports_to_pages_page_id_page_id_fk", 101 "tableFrom": "status_reports_to_pages", 102 - "columnsFrom": [ 103 - "page_id" 104 - ], 105 "tableTo": "page", 106 - "columnsTo": [ 107 - "id" 108 - ], 109 "onUpdate": "no action", 110 "onDelete": "cascade" 111 }, 112 "status_reports_to_pages_status_report_id_status_report_id_fk": { 113 "name": "status_reports_to_pages_status_report_id_status_report_id_fk", 114 "tableFrom": "status_reports_to_pages", 115 - "columnsFrom": [ 116 - "status_report_id" 117 - ], 118 "tableTo": "status_report", 119 - "columnsTo": [ 120 - "id" 121 - ], 122 "onUpdate": "no action", 123 "onDelete": "cascade" 124 } 125 }, 126 "compositePrimaryKeys": { 127 "status_reports_to_pages_page_id_status_report_id_pk": { 128 - "columns": [ 129 - "page_id", 130 - "status_report_id" 131 - ], 132 "name": "status_reports_to_pages_page_id_status_report_id_pk" 133 } 134 }, ··· 187 "status_report_workspace_id_workspace_id_fk": { 188 "name": "status_report_workspace_id_workspace_id_fk", 189 "tableFrom": "status_report", 190 - "columnsFrom": [ 191 - "workspace_id" 192 - ], 193 "tableTo": "workspace", 194 - "columnsTo": [ 195 - "id" 196 - ], 197 "onUpdate": "no action", 198 "onDelete": "no action" 199 } ··· 261 "status_report_update_status_report_id_status_report_id_fk": { 262 "name": "status_report_update_status_report_id_status_report_id_fk", 263 "tableFrom": "status_report_update", 264 - "columnsFrom": [ 265 - "status_report_id" 266 - ], 267 "tableTo": "status_report", 268 - "columnsTo": [ 269 - "id" 270 - ], 271 "onUpdate": "no action", 272 "onDelete": "cascade" 273 } ··· 342 "integration_workspace_id_workspace_id_fk": { 343 "name": "integration_workspace_id_workspace_id_fk", 344 "tableFrom": "integration", 345 - "columnsFrom": [ 346 - "workspace_id" 347 - ], 348 "tableTo": "workspace", 349 - "columnsTo": [ 350 - "id" 351 - ], 352 "onUpdate": "no action", 353 "onDelete": "no action" 354 } ··· 437 "indexes": { 438 "page_slug_unique": { 439 "name": "page_slug_unique", 440 - "columns": [ 441 - "slug" 442 - ], 443 "isUnique": true 444 } 445 }, ··· 447 "page_workspace_id_workspace_id_fk": { 448 "name": "page_workspace_id_workspace_id_fk", 449 "tableFrom": "page", 450 - "columnsFrom": [ 451 - "workspace_id" 452 - ], 453 "tableTo": "workspace", 454 - "columnsTo": [ 455 - "id" 456 - ], 457 "onUpdate": "no action", 458 "onDelete": "cascade" 459 } ··· 609 "monitor_workspace_id_workspace_id_fk": { 610 "name": "monitor_workspace_id_workspace_id_fk", 611 "tableFrom": "monitor", 612 - "columnsFrom": [ 613 - "workspace_id" 614 - ], 615 "tableTo": "workspace", 616 - "columnsTo": [ 617 - "id" 618 - ], 619 "onUpdate": "no action", 620 "onDelete": "no action" 621 } ··· 654 "monitors_to_pages_monitor_id_monitor_id_fk": { 655 "name": "monitors_to_pages_monitor_id_monitor_id_fk", 656 "tableFrom": "monitors_to_pages", 657 - "columnsFrom": [ 658 - "monitor_id" 659 - ], 660 "tableTo": "monitor", 661 - "columnsTo": [ 662 - "id" 663 - ], 664 "onUpdate": "no action", 665 "onDelete": "cascade" 666 }, 667 "monitors_to_pages_page_id_page_id_fk": { 668 "name": "monitors_to_pages_page_id_page_id_fk", 669 "tableFrom": "monitors_to_pages", 670 - "columnsFrom": [ 671 - "page_id" 672 - ], 673 "tableTo": "page", 674 - "columnsTo": [ 675 - "id" 676 - ], 677 "onUpdate": "no action", 678 "onDelete": "cascade" 679 } 680 }, 681 "compositePrimaryKeys": { 682 "monitors_to_pages_monitor_id_page_id_pk": { 683 - "columns": [ 684 - "monitor_id", 685 - "page_id" 686 - ], 687 "name": "monitors_to_pages_monitor_id_page_id_pk" 688 } 689 }, ··· 758 "indexes": { 759 "user_tenant_id_unique": { 760 "name": "user_tenant_id_unique", 761 - "columns": [ 762 - "tenant_id" 763 - ], 764 "isUnique": true 765 } 766 }, ··· 807 "users_to_workspaces_user_id_user_id_fk": { 808 "name": "users_to_workspaces_user_id_user_id_fk", 809 "tableFrom": "users_to_workspaces", 810 - "columnsFrom": [ 811 - "user_id" 812 - ], 813 "tableTo": "user", 814 - "columnsTo": [ 815 - "id" 816 - ], 817 "onUpdate": "no action", 818 "onDelete": "no action" 819 }, 820 "users_to_workspaces_workspace_id_workspace_id_fk": { 821 "name": "users_to_workspaces_workspace_id_workspace_id_fk", 822 "tableFrom": "users_to_workspaces", 823 - "columnsFrom": [ 824 - "workspace_id" 825 - ], 826 "tableTo": "workspace", 827 - "columnsTo": [ 828 - "id" 829 - ], 830 "onUpdate": "no action", 831 "onDelete": "no action" 832 } 833 }, 834 "compositePrimaryKeys": { 835 "users_to_workspaces_user_id_workspace_id_pk": { 836 - "columns": [ 837 - "user_id", 838 - "workspace_id" 839 - ], 840 "name": "users_to_workspaces_user_id_workspace_id_pk" 841 } 842 }, ··· 909 "page_subscriber_page_id_page_id_fk": { 910 "name": "page_subscriber_page_id_page_id_fk", 911 "tableFrom": "page_subscriber", 912 - "columnsFrom": [ 913 - "page_id" 914 - ], 915 "tableTo": "page", 916 - "columnsTo": [ 917 - "id" 918 - ], 919 "onUpdate": "no action", 920 "onDelete": "no action" 921 } ··· 1002 "indexes": { 1003 "workspace_slug_unique": { 1004 "name": "workspace_slug_unique", 1005 - "columns": [ 1006 - "slug" 1007 - ], 1008 "isUnique": true 1009 }, 1010 "workspace_stripe_id_unique": { 1011 "name": "workspace_stripe_id_unique", 1012 - "columns": [ 1013 - "stripe_id" 1014 - ], 1015 "isUnique": true 1016 } 1017 }, ··· 1080 "notification_workspace_id_workspace_id_fk": { 1081 "name": "notification_workspace_id_workspace_id_fk", 1082 "tableFrom": "notification", 1083 - "columnsFrom": [ 1084 - "workspace_id" 1085 - ], 1086 "tableTo": "workspace", 1087 - "columnsTo": [ 1088 - "id" 1089 - ], 1090 "onUpdate": "no action", 1091 "onDelete": "no action" 1092 } ··· 1125 "notifications_to_monitors_monitor_id_monitor_id_fk": { 1126 "name": "notifications_to_monitors_monitor_id_monitor_id_fk", 1127 "tableFrom": "notifications_to_monitors", 1128 - "columnsFrom": [ 1129 - "monitor_id" 1130 - ], 1131 "tableTo": "monitor", 1132 - "columnsTo": [ 1133 - "id" 1134 - ], 1135 "onUpdate": "no action", 1136 "onDelete": "cascade" 1137 }, 1138 "notifications_to_monitors_notification_id_notification_id_fk": { 1139 "name": "notifications_to_monitors_notification_id_notification_id_fk", 1140 "tableFrom": "notifications_to_monitors", 1141 - "columnsFrom": [ 1142 - "notification_id" 1143 - ], 1144 "tableTo": "notification", 1145 - "columnsTo": [ 1146 - "id" 1147 - ], 1148 "onUpdate": "no action", 1149 "onDelete": "cascade" 1150 } 1151 }, 1152 "compositePrimaryKeys": { 1153 "notifications_to_monitors_monitor_id_notification_id_pk": { 1154 - "columns": [ 1155 - "monitor_id", 1156 - "notification_id" 1157 - ], 1158 "name": "notifications_to_monitors_monitor_id_notification_id_pk" 1159 } 1160 }, ··· 1206 "indexes": { 1207 "monitor_status_idx": { 1208 "name": "monitor_status_idx", 1209 - "columns": [ 1210 - "monitor_id", 1211 - "region" 1212 - ], 1213 "isUnique": false 1214 } 1215 }, ··· 1217 "monitor_status_monitor_id_monitor_id_fk": { 1218 "name": "monitor_status_monitor_id_monitor_id_fk", 1219 "tableFrom": "monitor_status", 1220 - "columnsFrom": [ 1221 - "monitor_id" 1222 - ], 1223 "tableTo": "monitor", 1224 - "columnsTo": [ 1225 - "id" 1226 - ], 1227 "onUpdate": "no action", 1228 "onDelete": "cascade" 1229 } 1230 }, 1231 "compositePrimaryKeys": { 1232 "monitor_status_monitor_id_region_pk": { 1233 - "columns": [ 1234 - "monitor_id", 1235 - "region" 1236 - ], 1237 "name": "monitor_status_monitor_id_region_pk" 1238 } 1239 }, ··· 1432 "indexes": { 1433 "incident_monitor_id_started_at_unique": { 1434 "name": "incident_monitor_id_started_at_unique", 1435 - "columns": [ 1436 - "monitor_id", 1437 - "started_at" 1438 - ], 1439 "isUnique": true 1440 } 1441 }, ··· 1443 "incident_monitor_id_monitor_id_fk": { 1444 "name": "incident_monitor_id_monitor_id_fk", 1445 "tableFrom": "incident", 1446 - "columnsFrom": [ 1447 - "monitor_id" 1448 - ], 1449 "tableTo": "monitor", 1450 - "columnsTo": [ 1451 - "id" 1452 - ], 1453 "onUpdate": "no action", 1454 "onDelete": "set default" 1455 }, 1456 "incident_workspace_id_workspace_id_fk": { 1457 "name": "incident_workspace_id_workspace_id_fk", 1458 "tableFrom": "incident", 1459 - "columnsFrom": [ 1460 - "workspace_id" 1461 - ], 1462 "tableTo": "workspace", 1463 - "columnsTo": [ 1464 - "id" 1465 - ], 1466 "onUpdate": "no action", 1467 "onDelete": "no action" 1468 }, 1469 "incident_acknowledged_by_user_id_fk": { 1470 "name": "incident_acknowledged_by_user_id_fk", 1471 "tableFrom": "incident", 1472 - "columnsFrom": [ 1473 - "acknowledged_by" 1474 - ], 1475 "tableTo": "user", 1476 - "columnsTo": [ 1477 - "id" 1478 - ], 1479 "onUpdate": "no action", 1480 "onDelete": "no action" 1481 }, 1482 "incident_resolved_by_user_id_fk": { 1483 "name": "incident_resolved_by_user_id_fk", 1484 "tableFrom": "incident", 1485 - "columnsFrom": [ 1486 - "resolved_by" 1487 - ], 1488 "tableTo": "user", 1489 - "columnsTo": [ 1490 - "id" 1491 - ], 1492 "onUpdate": "no action", 1493 "onDelete": "no action" 1494 } ··· 1549 "monitor_tag_workspace_id_workspace_id_fk": { 1550 "name": "monitor_tag_workspace_id_workspace_id_fk", 1551 "tableFrom": "monitor_tag", 1552 - "columnsFrom": [ 1553 - "workspace_id" 1554 - ], 1555 "tableTo": "workspace", 1556 - "columnsTo": [ 1557 - "id" 1558 - ], 1559 "onUpdate": "no action", 1560 "onDelete": "cascade" 1561 } ··· 1594 "monitor_tag_to_monitor_monitor_id_monitor_id_fk": { 1595 "name": "monitor_tag_to_monitor_monitor_id_monitor_id_fk", 1596 "tableFrom": "monitor_tag_to_monitor", 1597 - "columnsFrom": [ 1598 - "monitor_id" 1599 - ], 1600 "tableTo": "monitor", 1601 - "columnsTo": [ 1602 - "id" 1603 - ], 1604 "onUpdate": "no action", 1605 "onDelete": "cascade" 1606 }, 1607 "monitor_tag_to_monitor_monitor_tag_id_monitor_tag_id_fk": { 1608 "name": "monitor_tag_to_monitor_monitor_tag_id_monitor_tag_id_fk", 1609 "tableFrom": "monitor_tag_to_monitor", 1610 - "columnsFrom": [ 1611 - "monitor_tag_id" 1612 - ], 1613 "tableTo": "monitor_tag", 1614 - "columnsTo": [ 1615 - "id" 1616 - ], 1617 "onUpdate": "no action", 1618 "onDelete": "cascade" 1619 } 1620 }, 1621 "compositePrimaryKeys": { 1622 "monitor_tag_to_monitor_monitor_id_monitor_tag_id_pk": { 1623 - "columns": [ 1624 - "monitor_id", 1625 - "monitor_tag_id" 1626 - ], 1627 "name": "monitor_tag_to_monitor_monitor_id_monitor_tag_id_pk" 1628 } 1629 }, ··· 1637 }, 1638 "id": "40ddc769-9652-470e-87af-71f269131bc3", 1639 "prevId": "96f82403-94f3-49fd-871b-946bc0a687f2" 1640 - }
··· 33 "status_report_to_monitors_monitor_id_monitor_id_fk": { 34 "name": "status_report_to_monitors_monitor_id_monitor_id_fk", 35 "tableFrom": "status_report_to_monitors", 36 + "columnsFrom": ["monitor_id"], 37 "tableTo": "monitor", 38 + "columnsTo": ["id"], 39 "onUpdate": "no action", 40 "onDelete": "cascade" 41 }, 42 "status_report_to_monitors_status_report_id_status_report_id_fk": { 43 "name": "status_report_to_monitors_status_report_id_status_report_id_fk", 44 "tableFrom": "status_report_to_monitors", 45 + "columnsFrom": ["status_report_id"], 46 "tableTo": "status_report", 47 + "columnsTo": ["id"], 48 "onUpdate": "no action", 49 "onDelete": "cascade" 50 } 51 }, 52 "compositePrimaryKeys": { 53 "status_report_to_monitors_monitor_id_status_report_id_pk": { 54 + "columns": ["monitor_id", "status_report_id"], 55 "name": "status_report_to_monitors_monitor_id_status_report_id_pk" 56 } 57 }, ··· 88 "status_reports_to_pages_page_id_page_id_fk": { 89 "name": "status_reports_to_pages_page_id_page_id_fk", 90 "tableFrom": "status_reports_to_pages", 91 + "columnsFrom": ["page_id"], 92 "tableTo": "page", 93 + "columnsTo": ["id"], 94 "onUpdate": "no action", 95 "onDelete": "cascade" 96 }, 97 "status_reports_to_pages_status_report_id_status_report_id_fk": { 98 "name": "status_reports_to_pages_status_report_id_status_report_id_fk", 99 "tableFrom": "status_reports_to_pages", 100 + "columnsFrom": ["status_report_id"], 101 "tableTo": "status_report", 102 + "columnsTo": ["id"], 103 "onUpdate": "no action", 104 "onDelete": "cascade" 105 } 106 }, 107 "compositePrimaryKeys": { 108 "status_reports_to_pages_page_id_status_report_id_pk": { 109 + "columns": ["page_id", "status_report_id"], 110 "name": "status_reports_to_pages_page_id_status_report_id_pk" 111 } 112 }, ··· 165 "status_report_workspace_id_workspace_id_fk": { 166 "name": "status_report_workspace_id_workspace_id_fk", 167 "tableFrom": "status_report", 168 + "columnsFrom": ["workspace_id"], 169 "tableTo": "workspace", 170 + "columnsTo": ["id"], 171 "onUpdate": "no action", 172 "onDelete": "no action" 173 } ··· 235 "status_report_update_status_report_id_status_report_id_fk": { 236 "name": "status_report_update_status_report_id_status_report_id_fk", 237 "tableFrom": "status_report_update", 238 + "columnsFrom": ["status_report_id"], 239 "tableTo": "status_report", 240 + "columnsTo": ["id"], 241 "onUpdate": "no action", 242 "onDelete": "cascade" 243 } ··· 312 "integration_workspace_id_workspace_id_fk": { 313 "name": "integration_workspace_id_workspace_id_fk", 314 "tableFrom": "integration", 315 + "columnsFrom": ["workspace_id"], 316 "tableTo": "workspace", 317 + "columnsTo": ["id"], 318 "onUpdate": "no action", 319 "onDelete": "no action" 320 } ··· 403 "indexes": { 404 "page_slug_unique": { 405 "name": "page_slug_unique", 406 + "columns": ["slug"], 407 "isUnique": true 408 } 409 }, ··· 411 "page_workspace_id_workspace_id_fk": { 412 "name": "page_workspace_id_workspace_id_fk", 413 "tableFrom": "page", 414 + "columnsFrom": ["workspace_id"], 415 "tableTo": "workspace", 416 + "columnsTo": ["id"], 417 "onUpdate": "no action", 418 "onDelete": "cascade" 419 } ··· 569 "monitor_workspace_id_workspace_id_fk": { 570 "name": "monitor_workspace_id_workspace_id_fk", 571 "tableFrom": "monitor", 572 + "columnsFrom": ["workspace_id"], 573 "tableTo": "workspace", 574 + "columnsTo": ["id"], 575 "onUpdate": "no action", 576 "onDelete": "no action" 577 } ··· 610 "monitors_to_pages_monitor_id_monitor_id_fk": { 611 "name": "monitors_to_pages_monitor_id_monitor_id_fk", 612 "tableFrom": "monitors_to_pages", 613 + "columnsFrom": ["monitor_id"], 614 "tableTo": "monitor", 615 + "columnsTo": ["id"], 616 "onUpdate": "no action", 617 "onDelete": "cascade" 618 }, 619 "monitors_to_pages_page_id_page_id_fk": { 620 "name": "monitors_to_pages_page_id_page_id_fk", 621 "tableFrom": "monitors_to_pages", 622 + "columnsFrom": ["page_id"], 623 "tableTo": "page", 624 + "columnsTo": ["id"], 625 "onUpdate": "no action", 626 "onDelete": "cascade" 627 } 628 }, 629 "compositePrimaryKeys": { 630 "monitors_to_pages_monitor_id_page_id_pk": { 631 + "columns": ["monitor_id", "page_id"], 632 "name": "monitors_to_pages_monitor_id_page_id_pk" 633 } 634 }, ··· 703 "indexes": { 704 "user_tenant_id_unique": { 705 "name": "user_tenant_id_unique", 706 + "columns": ["tenant_id"], 707 "isUnique": true 708 } 709 }, ··· 750 "users_to_workspaces_user_id_user_id_fk": { 751 "name": "users_to_workspaces_user_id_user_id_fk", 752 "tableFrom": "users_to_workspaces", 753 + "columnsFrom": ["user_id"], 754 "tableTo": "user", 755 + "columnsTo": ["id"], 756 "onUpdate": "no action", 757 "onDelete": "no action" 758 }, 759 "users_to_workspaces_workspace_id_workspace_id_fk": { 760 "name": "users_to_workspaces_workspace_id_workspace_id_fk", 761 "tableFrom": "users_to_workspaces", 762 + "columnsFrom": ["workspace_id"], 763 "tableTo": "workspace", 764 + "columnsTo": ["id"], 765 "onUpdate": "no action", 766 "onDelete": "no action" 767 } 768 }, 769 "compositePrimaryKeys": { 770 "users_to_workspaces_user_id_workspace_id_pk": { 771 + "columns": ["user_id", "workspace_id"], 772 "name": "users_to_workspaces_user_id_workspace_id_pk" 773 } 774 }, ··· 841 "page_subscriber_page_id_page_id_fk": { 842 "name": "page_subscriber_page_id_page_id_fk", 843 "tableFrom": "page_subscriber", 844 + "columnsFrom": ["page_id"], 845 "tableTo": "page", 846 + "columnsTo": ["id"], 847 "onUpdate": "no action", 848 "onDelete": "no action" 849 } ··· 930 "indexes": { 931 "workspace_slug_unique": { 932 "name": "workspace_slug_unique", 933 + "columns": ["slug"], 934 "isUnique": true 935 }, 936 "workspace_stripe_id_unique": { 937 "name": "workspace_stripe_id_unique", 938 + "columns": ["stripe_id"], 939 "isUnique": true 940 } 941 }, ··· 1004 "notification_workspace_id_workspace_id_fk": { 1005 "name": "notification_workspace_id_workspace_id_fk", 1006 "tableFrom": "notification", 1007 + "columnsFrom": ["workspace_id"], 1008 "tableTo": "workspace", 1009 + "columnsTo": ["id"], 1010 "onUpdate": "no action", 1011 "onDelete": "no action" 1012 } ··· 1045 "notifications_to_monitors_monitor_id_monitor_id_fk": { 1046 "name": "notifications_to_monitors_monitor_id_monitor_id_fk", 1047 "tableFrom": "notifications_to_monitors", 1048 + "columnsFrom": ["monitor_id"], 1049 "tableTo": "monitor", 1050 + "columnsTo": ["id"], 1051 "onUpdate": "no action", 1052 "onDelete": "cascade" 1053 }, 1054 "notifications_to_monitors_notification_id_notification_id_fk": { 1055 "name": "notifications_to_monitors_notification_id_notification_id_fk", 1056 "tableFrom": "notifications_to_monitors", 1057 + "columnsFrom": ["notification_id"], 1058 "tableTo": "notification", 1059 + "columnsTo": ["id"], 1060 "onUpdate": "no action", 1061 "onDelete": "cascade" 1062 } 1063 }, 1064 "compositePrimaryKeys": { 1065 "notifications_to_monitors_monitor_id_notification_id_pk": { 1066 + "columns": ["monitor_id", "notification_id"], 1067 "name": "notifications_to_monitors_monitor_id_notification_id_pk" 1068 } 1069 }, ··· 1115 "indexes": { 1116 "monitor_status_idx": { 1117 "name": "monitor_status_idx", 1118 + "columns": ["monitor_id", "region"], 1119 "isUnique": false 1120 } 1121 }, ··· 1123 "monitor_status_monitor_id_monitor_id_fk": { 1124 "name": "monitor_status_monitor_id_monitor_id_fk", 1125 "tableFrom": "monitor_status", 1126 + "columnsFrom": ["monitor_id"], 1127 "tableTo": "monitor", 1128 + "columnsTo": ["id"], 1129 "onUpdate": "no action", 1130 "onDelete": "cascade" 1131 } 1132 }, 1133 "compositePrimaryKeys": { 1134 "monitor_status_monitor_id_region_pk": { 1135 + "columns": ["monitor_id", "region"], 1136 "name": "monitor_status_monitor_id_region_pk" 1137 } 1138 }, ··· 1331 "indexes": { 1332 "incident_monitor_id_started_at_unique": { 1333 "name": "incident_monitor_id_started_at_unique", 1334 + "columns": ["monitor_id", "started_at"], 1335 "isUnique": true 1336 } 1337 }, ··· 1339 "incident_monitor_id_monitor_id_fk": { 1340 "name": "incident_monitor_id_monitor_id_fk", 1341 "tableFrom": "incident", 1342 + "columnsFrom": ["monitor_id"], 1343 "tableTo": "monitor", 1344 + "columnsTo": ["id"], 1345 "onUpdate": "no action", 1346 "onDelete": "set default" 1347 }, 1348 "incident_workspace_id_workspace_id_fk": { 1349 "name": "incident_workspace_id_workspace_id_fk", 1350 "tableFrom": "incident", 1351 + "columnsFrom": ["workspace_id"], 1352 "tableTo": "workspace", 1353 + "columnsTo": ["id"], 1354 "onUpdate": "no action", 1355 "onDelete": "no action" 1356 }, 1357 "incident_acknowledged_by_user_id_fk": { 1358 "name": "incident_acknowledged_by_user_id_fk", 1359 "tableFrom": "incident", 1360 + "columnsFrom": ["acknowledged_by"], 1361 "tableTo": "user", 1362 + "columnsTo": ["id"], 1363 "onUpdate": "no action", 1364 "onDelete": "no action" 1365 }, 1366 "incident_resolved_by_user_id_fk": { 1367 "name": "incident_resolved_by_user_id_fk", 1368 "tableFrom": "incident", 1369 + "columnsFrom": ["resolved_by"], 1370 "tableTo": "user", 1371 + "columnsTo": ["id"], 1372 "onUpdate": "no action", 1373 "onDelete": "no action" 1374 } ··· 1429 "monitor_tag_workspace_id_workspace_id_fk": { 1430 "name": "monitor_tag_workspace_id_workspace_id_fk", 1431 "tableFrom": "monitor_tag", 1432 + "columnsFrom": ["workspace_id"], 1433 "tableTo": "workspace", 1434 + "columnsTo": ["id"], 1435 "onUpdate": "no action", 1436 "onDelete": "cascade" 1437 } ··· 1470 "monitor_tag_to_monitor_monitor_id_monitor_id_fk": { 1471 "name": "monitor_tag_to_monitor_monitor_id_monitor_id_fk", 1472 "tableFrom": "monitor_tag_to_monitor", 1473 + "columnsFrom": ["monitor_id"], 1474 "tableTo": "monitor", 1475 + "columnsTo": ["id"], 1476 "onUpdate": "no action", 1477 "onDelete": "cascade" 1478 }, 1479 "monitor_tag_to_monitor_monitor_tag_id_monitor_tag_id_fk": { 1480 "name": "monitor_tag_to_monitor_monitor_tag_id_monitor_tag_id_fk", 1481 "tableFrom": "monitor_tag_to_monitor", 1482 + "columnsFrom": ["monitor_tag_id"], 1483 "tableTo": "monitor_tag", 1484 + "columnsTo": ["id"], 1485 "onUpdate": "no action", 1486 "onDelete": "cascade" 1487 } 1488 }, 1489 "compositePrimaryKeys": { 1490 "monitor_tag_to_monitor_monitor_id_monitor_tag_id_pk": { 1491 + "columns": ["monitor_id", "monitor_tag_id"], 1492 "name": "monitor_tag_to_monitor_monitor_id_monitor_tag_id_pk" 1493 } 1494 }, ··· 1502 }, 1503 "id": "40ddc769-9652-470e-87af-71f269131bc3", 1504 "prevId": "96f82403-94f3-49fd-871b-946bc0a687f2" 1505 + }
+2051
packages/db/drizzle/meta/0033_snapshot.json
···
··· 1 + { 2 + "version": "6", 3 + "dialect": "sqlite", 4 + "id": "447f81c0-1837-4e85-bb0e-9ecce75e95d9", 5 + "prevId": "de3d58e5-d801-4b9e-a35a-39cfc09b7807", 6 + "tables": { 7 + "status_report_to_monitors": { 8 + "name": "status_report_to_monitors", 9 + "columns": { 10 + "monitor_id": { 11 + "name": "monitor_id", 12 + "type": "integer", 13 + "primaryKey": false, 14 + "notNull": true, 15 + "autoincrement": false 16 + }, 17 + "status_report_id": { 18 + "name": "status_report_id", 19 + "type": "integer", 20 + "primaryKey": false, 21 + "notNull": true, 22 + "autoincrement": false 23 + }, 24 + "created_at": { 25 + "name": "created_at", 26 + "type": "integer", 27 + "primaryKey": false, 28 + "notNull": false, 29 + "autoincrement": false, 30 + "default": "(strftime('%s', 'now'))" 31 + } 32 + }, 33 + "indexes": {}, 34 + "foreignKeys": { 35 + "status_report_to_monitors_monitor_id_monitor_id_fk": { 36 + "name": "status_report_to_monitors_monitor_id_monitor_id_fk", 37 + "tableFrom": "status_report_to_monitors", 38 + "tableTo": "monitor", 39 + "columnsFrom": ["monitor_id"], 40 + "columnsTo": ["id"], 41 + "onDelete": "cascade", 42 + "onUpdate": "no action" 43 + }, 44 + "status_report_to_monitors_status_report_id_status_report_id_fk": { 45 + "name": "status_report_to_monitors_status_report_id_status_report_id_fk", 46 + "tableFrom": "status_report_to_monitors", 47 + "tableTo": "status_report", 48 + "columnsFrom": ["status_report_id"], 49 + "columnsTo": ["id"], 50 + "onDelete": "cascade", 51 + "onUpdate": "no action" 52 + } 53 + }, 54 + "compositePrimaryKeys": { 55 + "status_report_to_monitors_monitor_id_status_report_id_pk": { 56 + "columns": ["monitor_id", "status_report_id"], 57 + "name": "status_report_to_monitors_monitor_id_status_report_id_pk" 58 + } 59 + }, 60 + "uniqueConstraints": {} 61 + }, 62 + "status_reports_to_pages": { 63 + "name": "status_reports_to_pages", 64 + "columns": { 65 + "page_id": { 66 + "name": "page_id", 67 + "type": "integer", 68 + "primaryKey": false, 69 + "notNull": true, 70 + "autoincrement": false 71 + }, 72 + "status_report_id": { 73 + "name": "status_report_id", 74 + "type": "integer", 75 + "primaryKey": false, 76 + "notNull": true, 77 + "autoincrement": false 78 + }, 79 + "created_at": { 80 + "name": "created_at", 81 + "type": "integer", 82 + "primaryKey": false, 83 + "notNull": false, 84 + "autoincrement": false, 85 + "default": "(strftime('%s', 'now'))" 86 + } 87 + }, 88 + "indexes": {}, 89 + "foreignKeys": { 90 + "status_reports_to_pages_page_id_page_id_fk": { 91 + "name": "status_reports_to_pages_page_id_page_id_fk", 92 + "tableFrom": "status_reports_to_pages", 93 + "tableTo": "page", 94 + "columnsFrom": ["page_id"], 95 + "columnsTo": ["id"], 96 + "onDelete": "cascade", 97 + "onUpdate": "no action" 98 + }, 99 + "status_reports_to_pages_status_report_id_status_report_id_fk": { 100 + "name": "status_reports_to_pages_status_report_id_status_report_id_fk", 101 + "tableFrom": "status_reports_to_pages", 102 + "tableTo": "status_report", 103 + "columnsFrom": ["status_report_id"], 104 + "columnsTo": ["id"], 105 + "onDelete": "cascade", 106 + "onUpdate": "no action" 107 + } 108 + }, 109 + "compositePrimaryKeys": { 110 + "status_reports_to_pages_page_id_status_report_id_pk": { 111 + "columns": ["page_id", "status_report_id"], 112 + "name": "status_reports_to_pages_page_id_status_report_id_pk" 113 + } 114 + }, 115 + "uniqueConstraints": {} 116 + }, 117 + "status_report": { 118 + "name": "status_report", 119 + "columns": { 120 + "id": { 121 + "name": "id", 122 + "type": "integer", 123 + "primaryKey": true, 124 + "notNull": true, 125 + "autoincrement": false 126 + }, 127 + "status": { 128 + "name": "status", 129 + "type": "text", 130 + "primaryKey": false, 131 + "notNull": true, 132 + "autoincrement": false 133 + }, 134 + "title": { 135 + "name": "title", 136 + "type": "text(256)", 137 + "primaryKey": false, 138 + "notNull": true, 139 + "autoincrement": false 140 + }, 141 + "workspace_id": { 142 + "name": "workspace_id", 143 + "type": "integer", 144 + "primaryKey": false, 145 + "notNull": false, 146 + "autoincrement": false 147 + }, 148 + "created_at": { 149 + "name": "created_at", 150 + "type": "integer", 151 + "primaryKey": false, 152 + "notNull": false, 153 + "autoincrement": false, 154 + "default": "(strftime('%s', 'now'))" 155 + }, 156 + "updated_at": { 157 + "name": "updated_at", 158 + "type": "integer", 159 + "primaryKey": false, 160 + "notNull": false, 161 + "autoincrement": false, 162 + "default": "(strftime('%s', 'now'))" 163 + } 164 + }, 165 + "indexes": {}, 166 + "foreignKeys": { 167 + "status_report_workspace_id_workspace_id_fk": { 168 + "name": "status_report_workspace_id_workspace_id_fk", 169 + "tableFrom": "status_report", 170 + "tableTo": "workspace", 171 + "columnsFrom": ["workspace_id"], 172 + "columnsTo": ["id"], 173 + "onDelete": "no action", 174 + "onUpdate": "no action" 175 + } 176 + }, 177 + "compositePrimaryKeys": {}, 178 + "uniqueConstraints": {} 179 + }, 180 + "status_report_update": { 181 + "name": "status_report_update", 182 + "columns": { 183 + "id": { 184 + "name": "id", 185 + "type": "integer", 186 + "primaryKey": true, 187 + "notNull": true, 188 + "autoincrement": false 189 + }, 190 + "status": { 191 + "name": "status", 192 + "type": "text(4)", 193 + "primaryKey": false, 194 + "notNull": true, 195 + "autoincrement": false 196 + }, 197 + "date": { 198 + "name": "date", 199 + "type": "integer", 200 + "primaryKey": false, 201 + "notNull": true, 202 + "autoincrement": false 203 + }, 204 + "message": { 205 + "name": "message", 206 + "type": "text", 207 + "primaryKey": false, 208 + "notNull": true, 209 + "autoincrement": false 210 + }, 211 + "status_report_id": { 212 + "name": "status_report_id", 213 + "type": "integer", 214 + "primaryKey": false, 215 + "notNull": true, 216 + "autoincrement": false 217 + }, 218 + "created_at": { 219 + "name": "created_at", 220 + "type": "integer", 221 + "primaryKey": false, 222 + "notNull": false, 223 + "autoincrement": false, 224 + "default": "(strftime('%s', 'now'))" 225 + }, 226 + "updated_at": { 227 + "name": "updated_at", 228 + "type": "integer", 229 + "primaryKey": false, 230 + "notNull": false, 231 + "autoincrement": false, 232 + "default": "(strftime('%s', 'now'))" 233 + } 234 + }, 235 + "indexes": {}, 236 + "foreignKeys": { 237 + "status_report_update_status_report_id_status_report_id_fk": { 238 + "name": "status_report_update_status_report_id_status_report_id_fk", 239 + "tableFrom": "status_report_update", 240 + "tableTo": "status_report", 241 + "columnsFrom": ["status_report_id"], 242 + "columnsTo": ["id"], 243 + "onDelete": "cascade", 244 + "onUpdate": "no action" 245 + } 246 + }, 247 + "compositePrimaryKeys": {}, 248 + "uniqueConstraints": {} 249 + }, 250 + "integration": { 251 + "name": "integration", 252 + "columns": { 253 + "id": { 254 + "name": "id", 255 + "type": "integer", 256 + "primaryKey": true, 257 + "notNull": true, 258 + "autoincrement": false 259 + }, 260 + "name": { 261 + "name": "name", 262 + "type": "text(256)", 263 + "primaryKey": false, 264 + "notNull": true, 265 + "autoincrement": false 266 + }, 267 + "workspace_id": { 268 + "name": "workspace_id", 269 + "type": "integer", 270 + "primaryKey": false, 271 + "notNull": false, 272 + "autoincrement": false 273 + }, 274 + "credential": { 275 + "name": "credential", 276 + "type": "text", 277 + "primaryKey": false, 278 + "notNull": false, 279 + "autoincrement": false 280 + }, 281 + "external_id": { 282 + "name": "external_id", 283 + "type": "text", 284 + "primaryKey": false, 285 + "notNull": true, 286 + "autoincrement": false 287 + }, 288 + "created_at": { 289 + "name": "created_at", 290 + "type": "integer", 291 + "primaryKey": false, 292 + "notNull": false, 293 + "autoincrement": false, 294 + "default": "(strftime('%s', 'now'))" 295 + }, 296 + "updated_at": { 297 + "name": "updated_at", 298 + "type": "integer", 299 + "primaryKey": false, 300 + "notNull": false, 301 + "autoincrement": false, 302 + "default": "(strftime('%s', 'now'))" 303 + }, 304 + "data": { 305 + "name": "data", 306 + "type": "text", 307 + "primaryKey": false, 308 + "notNull": true, 309 + "autoincrement": false 310 + } 311 + }, 312 + "indexes": {}, 313 + "foreignKeys": { 314 + "integration_workspace_id_workspace_id_fk": { 315 + "name": "integration_workspace_id_workspace_id_fk", 316 + "tableFrom": "integration", 317 + "tableTo": "workspace", 318 + "columnsFrom": ["workspace_id"], 319 + "columnsTo": ["id"], 320 + "onDelete": "no action", 321 + "onUpdate": "no action" 322 + } 323 + }, 324 + "compositePrimaryKeys": {}, 325 + "uniqueConstraints": {} 326 + }, 327 + "page": { 328 + "name": "page", 329 + "columns": { 330 + "id": { 331 + "name": "id", 332 + "type": "integer", 333 + "primaryKey": true, 334 + "notNull": true, 335 + "autoincrement": false 336 + }, 337 + "workspace_id": { 338 + "name": "workspace_id", 339 + "type": "integer", 340 + "primaryKey": false, 341 + "notNull": true, 342 + "autoincrement": false 343 + }, 344 + "title": { 345 + "name": "title", 346 + "type": "text", 347 + "primaryKey": false, 348 + "notNull": true, 349 + "autoincrement": false 350 + }, 351 + "description": { 352 + "name": "description", 353 + "type": "text", 354 + "primaryKey": false, 355 + "notNull": true, 356 + "autoincrement": false 357 + }, 358 + "icon": { 359 + "name": "icon", 360 + "type": "text(256)", 361 + "primaryKey": false, 362 + "notNull": false, 363 + "autoincrement": false, 364 + "default": "''" 365 + }, 366 + "slug": { 367 + "name": "slug", 368 + "type": "text(256)", 369 + "primaryKey": false, 370 + "notNull": true, 371 + "autoincrement": false 372 + }, 373 + "custom_domain": { 374 + "name": "custom_domain", 375 + "type": "text(256)", 376 + "primaryKey": false, 377 + "notNull": true, 378 + "autoincrement": false 379 + }, 380 + "published": { 381 + "name": "published", 382 + "type": "integer", 383 + "primaryKey": false, 384 + "notNull": false, 385 + "autoincrement": false, 386 + "default": false 387 + }, 388 + "password": { 389 + "name": "password", 390 + "type": "text(256)", 391 + "primaryKey": false, 392 + "notNull": false, 393 + "autoincrement": false 394 + }, 395 + "password_protected": { 396 + "name": "password_protected", 397 + "type": "integer", 398 + "primaryKey": false, 399 + "notNull": false, 400 + "autoincrement": false, 401 + "default": false 402 + }, 403 + "created_at": { 404 + "name": "created_at", 405 + "type": "integer", 406 + "primaryKey": false, 407 + "notNull": false, 408 + "autoincrement": false, 409 + "default": "(strftime('%s', 'now'))" 410 + }, 411 + "updated_at": { 412 + "name": "updated_at", 413 + "type": "integer", 414 + "primaryKey": false, 415 + "notNull": false, 416 + "autoincrement": false, 417 + "default": "(strftime('%s', 'now'))" 418 + } 419 + }, 420 + "indexes": { 421 + "page_slug_unique": { 422 + "name": "page_slug_unique", 423 + "columns": ["slug"], 424 + "isUnique": true 425 + } 426 + }, 427 + "foreignKeys": { 428 + "page_workspace_id_workspace_id_fk": { 429 + "name": "page_workspace_id_workspace_id_fk", 430 + "tableFrom": "page", 431 + "tableTo": "workspace", 432 + "columnsFrom": ["workspace_id"], 433 + "columnsTo": ["id"], 434 + "onDelete": "cascade", 435 + "onUpdate": "no action" 436 + } 437 + }, 438 + "compositePrimaryKeys": {}, 439 + "uniqueConstraints": {} 440 + }, 441 + "monitor": { 442 + "name": "monitor", 443 + "columns": { 444 + "id": { 445 + "name": "id", 446 + "type": "integer", 447 + "primaryKey": true, 448 + "notNull": true, 449 + "autoincrement": false 450 + }, 451 + "job_type": { 452 + "name": "job_type", 453 + "type": "text", 454 + "primaryKey": false, 455 + "notNull": true, 456 + "autoincrement": false, 457 + "default": "'other'" 458 + }, 459 + "periodicity": { 460 + "name": "periodicity", 461 + "type": "text", 462 + "primaryKey": false, 463 + "notNull": true, 464 + "autoincrement": false, 465 + "default": "'other'" 466 + }, 467 + "status": { 468 + "name": "status", 469 + "type": "text", 470 + "primaryKey": false, 471 + "notNull": true, 472 + "autoincrement": false, 473 + "default": "'active'" 474 + }, 475 + "active": { 476 + "name": "active", 477 + "type": "integer", 478 + "primaryKey": false, 479 + "notNull": false, 480 + "autoincrement": false, 481 + "default": false 482 + }, 483 + "regions": { 484 + "name": "regions", 485 + "type": "text", 486 + "primaryKey": false, 487 + "notNull": true, 488 + "autoincrement": false, 489 + "default": "''" 490 + }, 491 + "url": { 492 + "name": "url", 493 + "type": "text(2048)", 494 + "primaryKey": false, 495 + "notNull": true, 496 + "autoincrement": false 497 + }, 498 + "name": { 499 + "name": "name", 500 + "type": "text(256)", 501 + "primaryKey": false, 502 + "notNull": true, 503 + "autoincrement": false, 504 + "default": "''" 505 + }, 506 + "description": { 507 + "name": "description", 508 + "type": "text", 509 + "primaryKey": false, 510 + "notNull": true, 511 + "autoincrement": false, 512 + "default": "''" 513 + }, 514 + "headers": { 515 + "name": "headers", 516 + "type": "text", 517 + "primaryKey": false, 518 + "notNull": false, 519 + "autoincrement": false, 520 + "default": "''" 521 + }, 522 + "body": { 523 + "name": "body", 524 + "type": "text", 525 + "primaryKey": false, 526 + "notNull": false, 527 + "autoincrement": false, 528 + "default": "''" 529 + }, 530 + "method": { 531 + "name": "method", 532 + "type": "text", 533 + "primaryKey": false, 534 + "notNull": false, 535 + "autoincrement": false, 536 + "default": "'GET'" 537 + }, 538 + "workspace_id": { 539 + "name": "workspace_id", 540 + "type": "integer", 541 + "primaryKey": false, 542 + "notNull": false, 543 + "autoincrement": false 544 + }, 545 + "timeout": { 546 + "name": "timeout", 547 + "type": "integer", 548 + "primaryKey": false, 549 + "notNull": true, 550 + "autoincrement": false, 551 + "default": 45000 552 + }, 553 + "degraded_after": { 554 + "name": "degraded_after", 555 + "type": "integer", 556 + "primaryKey": false, 557 + "notNull": false, 558 + "autoincrement": false 559 + }, 560 + "assertions": { 561 + "name": "assertions", 562 + "type": "text", 563 + "primaryKey": false, 564 + "notNull": false, 565 + "autoincrement": false 566 + }, 567 + "public": { 568 + "name": "public", 569 + "type": "integer", 570 + "primaryKey": false, 571 + "notNull": false, 572 + "autoincrement": false, 573 + "default": false 574 + }, 575 + "created_at": { 576 + "name": "created_at", 577 + "type": "integer", 578 + "primaryKey": false, 579 + "notNull": false, 580 + "autoincrement": false, 581 + "default": "(strftime('%s', 'now'))" 582 + }, 583 + "updated_at": { 584 + "name": "updated_at", 585 + "type": "integer", 586 + "primaryKey": false, 587 + "notNull": false, 588 + "autoincrement": false, 589 + "default": "(strftime('%s', 'now'))" 590 + }, 591 + "deleted_at": { 592 + "name": "deleted_at", 593 + "type": "integer", 594 + "primaryKey": false, 595 + "notNull": false, 596 + "autoincrement": false 597 + } 598 + }, 599 + "indexes": {}, 600 + "foreignKeys": { 601 + "monitor_workspace_id_workspace_id_fk": { 602 + "name": "monitor_workspace_id_workspace_id_fk", 603 + "tableFrom": "monitor", 604 + "tableTo": "workspace", 605 + "columnsFrom": ["workspace_id"], 606 + "columnsTo": ["id"], 607 + "onDelete": "no action", 608 + "onUpdate": "no action" 609 + } 610 + }, 611 + "compositePrimaryKeys": {}, 612 + "uniqueConstraints": {} 613 + }, 614 + "monitors_to_pages": { 615 + "name": "monitors_to_pages", 616 + "columns": { 617 + "monitor_id": { 618 + "name": "monitor_id", 619 + "type": "integer", 620 + "primaryKey": false, 621 + "notNull": true, 622 + "autoincrement": false 623 + }, 624 + "page_id": { 625 + "name": "page_id", 626 + "type": "integer", 627 + "primaryKey": false, 628 + "notNull": true, 629 + "autoincrement": false 630 + }, 631 + "created_at": { 632 + "name": "created_at", 633 + "type": "integer", 634 + "primaryKey": false, 635 + "notNull": false, 636 + "autoincrement": false, 637 + "default": "(strftime('%s', 'now'))" 638 + }, 639 + "order": { 640 + "name": "order", 641 + "type": "integer", 642 + "primaryKey": false, 643 + "notNull": false, 644 + "autoincrement": false, 645 + "default": 0 646 + } 647 + }, 648 + "indexes": {}, 649 + "foreignKeys": { 650 + "monitors_to_pages_monitor_id_monitor_id_fk": { 651 + "name": "monitors_to_pages_monitor_id_monitor_id_fk", 652 + "tableFrom": "monitors_to_pages", 653 + "tableTo": "monitor", 654 + "columnsFrom": ["monitor_id"], 655 + "columnsTo": ["id"], 656 + "onDelete": "cascade", 657 + "onUpdate": "no action" 658 + }, 659 + "monitors_to_pages_page_id_page_id_fk": { 660 + "name": "monitors_to_pages_page_id_page_id_fk", 661 + "tableFrom": "monitors_to_pages", 662 + "tableTo": "page", 663 + "columnsFrom": ["page_id"], 664 + "columnsTo": ["id"], 665 + "onDelete": "cascade", 666 + "onUpdate": "no action" 667 + } 668 + }, 669 + "compositePrimaryKeys": { 670 + "monitors_to_pages_monitor_id_page_id_pk": { 671 + "columns": ["monitor_id", "page_id"], 672 + "name": "monitors_to_pages_monitor_id_page_id_pk" 673 + } 674 + }, 675 + "uniqueConstraints": {} 676 + }, 677 + "account": { 678 + "name": "account", 679 + "columns": { 680 + "user_id": { 681 + "name": "user_id", 682 + "type": "integer", 683 + "primaryKey": false, 684 + "notNull": true, 685 + "autoincrement": false 686 + }, 687 + "type": { 688 + "name": "type", 689 + "type": "text", 690 + "primaryKey": false, 691 + "notNull": true, 692 + "autoincrement": false 693 + }, 694 + "provider": { 695 + "name": "provider", 696 + "type": "text", 697 + "primaryKey": false, 698 + "notNull": true, 699 + "autoincrement": false 700 + }, 701 + "provider_account_id": { 702 + "name": "provider_account_id", 703 + "type": "text", 704 + "primaryKey": false, 705 + "notNull": true, 706 + "autoincrement": false 707 + }, 708 + "refresh_token": { 709 + "name": "refresh_token", 710 + "type": "text", 711 + "primaryKey": false, 712 + "notNull": false, 713 + "autoincrement": false 714 + }, 715 + "access_token": { 716 + "name": "access_token", 717 + "type": "text", 718 + "primaryKey": false, 719 + "notNull": false, 720 + "autoincrement": false 721 + }, 722 + "expires_at": { 723 + "name": "expires_at", 724 + "type": "integer", 725 + "primaryKey": false, 726 + "notNull": false, 727 + "autoincrement": false 728 + }, 729 + "token_type": { 730 + "name": "token_type", 731 + "type": "text", 732 + "primaryKey": false, 733 + "notNull": false, 734 + "autoincrement": false 735 + }, 736 + "scope": { 737 + "name": "scope", 738 + "type": "text", 739 + "primaryKey": false, 740 + "notNull": false, 741 + "autoincrement": false 742 + }, 743 + "id_token": { 744 + "name": "id_token", 745 + "type": "text", 746 + "primaryKey": false, 747 + "notNull": false, 748 + "autoincrement": false 749 + }, 750 + "session_state": { 751 + "name": "session_state", 752 + "type": "text", 753 + "primaryKey": false, 754 + "notNull": false, 755 + "autoincrement": false 756 + } 757 + }, 758 + "indexes": {}, 759 + "foreignKeys": { 760 + "account_user_id_user_id_fk": { 761 + "name": "account_user_id_user_id_fk", 762 + "tableFrom": "account", 763 + "tableTo": "user", 764 + "columnsFrom": ["user_id"], 765 + "columnsTo": ["id"], 766 + "onDelete": "cascade", 767 + "onUpdate": "no action" 768 + } 769 + }, 770 + "compositePrimaryKeys": { 771 + "account_provider_provider_account_id_pk": { 772 + "columns": ["provider", "provider_account_id"], 773 + "name": "account_provider_provider_account_id_pk" 774 + } 775 + }, 776 + "uniqueConstraints": {} 777 + }, 778 + "session": { 779 + "name": "session", 780 + "columns": { 781 + "session_token": { 782 + "name": "session_token", 783 + "type": "text", 784 + "primaryKey": true, 785 + "notNull": true, 786 + "autoincrement": false 787 + }, 788 + "user_id": { 789 + "name": "user_id", 790 + "type": "integer", 791 + "primaryKey": false, 792 + "notNull": true, 793 + "autoincrement": false 794 + }, 795 + "expires": { 796 + "name": "expires", 797 + "type": "integer", 798 + "primaryKey": false, 799 + "notNull": true, 800 + "autoincrement": false 801 + } 802 + }, 803 + "indexes": {}, 804 + "foreignKeys": { 805 + "session_user_id_user_id_fk": { 806 + "name": "session_user_id_user_id_fk", 807 + "tableFrom": "session", 808 + "tableTo": "user", 809 + "columnsFrom": ["user_id"], 810 + "columnsTo": ["id"], 811 + "onDelete": "cascade", 812 + "onUpdate": "no action" 813 + } 814 + }, 815 + "compositePrimaryKeys": {}, 816 + "uniqueConstraints": {} 817 + }, 818 + "user": { 819 + "name": "user", 820 + "columns": { 821 + "id": { 822 + "name": "id", 823 + "type": "integer", 824 + "primaryKey": true, 825 + "notNull": true, 826 + "autoincrement": false 827 + }, 828 + "tenant_id": { 829 + "name": "tenant_id", 830 + "type": "text(256)", 831 + "primaryKey": false, 832 + "notNull": false, 833 + "autoincrement": false 834 + }, 835 + "first_name": { 836 + "name": "first_name", 837 + "type": "text", 838 + "primaryKey": false, 839 + "notNull": false, 840 + "autoincrement": false, 841 + "default": "''" 842 + }, 843 + "last_name": { 844 + "name": "last_name", 845 + "type": "text", 846 + "primaryKey": false, 847 + "notNull": false, 848 + "autoincrement": false, 849 + "default": "''" 850 + }, 851 + "photo_url": { 852 + "name": "photo_url", 853 + "type": "text", 854 + "primaryKey": false, 855 + "notNull": false, 856 + "autoincrement": false, 857 + "default": "''" 858 + }, 859 + "name": { 860 + "name": "name", 861 + "type": "text", 862 + "primaryKey": false, 863 + "notNull": false, 864 + "autoincrement": false 865 + }, 866 + "email": { 867 + "name": "email", 868 + "type": "text", 869 + "primaryKey": false, 870 + "notNull": false, 871 + "autoincrement": false, 872 + "default": "''" 873 + }, 874 + "emailVerified": { 875 + "name": "emailVerified", 876 + "type": "integer", 877 + "primaryKey": false, 878 + "notNull": false, 879 + "autoincrement": false 880 + }, 881 + "created_at": { 882 + "name": "created_at", 883 + "type": "integer", 884 + "primaryKey": false, 885 + "notNull": false, 886 + "autoincrement": false, 887 + "default": "(strftime('%s', 'now'))" 888 + }, 889 + "updated_at": { 890 + "name": "updated_at", 891 + "type": "integer", 892 + "primaryKey": false, 893 + "notNull": false, 894 + "autoincrement": false, 895 + "default": "(strftime('%s', 'now'))" 896 + } 897 + }, 898 + "indexes": { 899 + "user_tenant_id_unique": { 900 + "name": "user_tenant_id_unique", 901 + "columns": ["tenant_id"], 902 + "isUnique": true 903 + } 904 + }, 905 + "foreignKeys": {}, 906 + "compositePrimaryKeys": {}, 907 + "uniqueConstraints": {} 908 + }, 909 + "users_to_workspaces": { 910 + "name": "users_to_workspaces", 911 + "columns": { 912 + "user_id": { 913 + "name": "user_id", 914 + "type": "integer", 915 + "primaryKey": false, 916 + "notNull": true, 917 + "autoincrement": false 918 + }, 919 + "workspace_id": { 920 + "name": "workspace_id", 921 + "type": "integer", 922 + "primaryKey": false, 923 + "notNull": true, 924 + "autoincrement": false 925 + }, 926 + "role": { 927 + "name": "role", 928 + "type": "text", 929 + "primaryKey": false, 930 + "notNull": true, 931 + "autoincrement": false, 932 + "default": "'member'" 933 + }, 934 + "created_at": { 935 + "name": "created_at", 936 + "type": "integer", 937 + "primaryKey": false, 938 + "notNull": false, 939 + "autoincrement": false, 940 + "default": "(strftime('%s', 'now'))" 941 + } 942 + }, 943 + "indexes": {}, 944 + "foreignKeys": { 945 + "users_to_workspaces_user_id_user_id_fk": { 946 + "name": "users_to_workspaces_user_id_user_id_fk", 947 + "tableFrom": "users_to_workspaces", 948 + "tableTo": "user", 949 + "columnsFrom": ["user_id"], 950 + "columnsTo": ["id"], 951 + "onDelete": "no action", 952 + "onUpdate": "no action" 953 + }, 954 + "users_to_workspaces_workspace_id_workspace_id_fk": { 955 + "name": "users_to_workspaces_workspace_id_workspace_id_fk", 956 + "tableFrom": "users_to_workspaces", 957 + "tableTo": "workspace", 958 + "columnsFrom": ["workspace_id"], 959 + "columnsTo": ["id"], 960 + "onDelete": "no action", 961 + "onUpdate": "no action" 962 + } 963 + }, 964 + "compositePrimaryKeys": { 965 + "users_to_workspaces_user_id_workspace_id_pk": { 966 + "columns": ["user_id", "workspace_id"], 967 + "name": "users_to_workspaces_user_id_workspace_id_pk" 968 + } 969 + }, 970 + "uniqueConstraints": {} 971 + }, 972 + "verification_token": { 973 + "name": "verification_token", 974 + "columns": { 975 + "identifier": { 976 + "name": "identifier", 977 + "type": "text", 978 + "primaryKey": false, 979 + "notNull": true, 980 + "autoincrement": false 981 + }, 982 + "token": { 983 + "name": "token", 984 + "type": "text", 985 + "primaryKey": false, 986 + "notNull": true, 987 + "autoincrement": false 988 + }, 989 + "expires": { 990 + "name": "expires", 991 + "type": "integer", 992 + "primaryKey": false, 993 + "notNull": true, 994 + "autoincrement": false 995 + } 996 + }, 997 + "indexes": {}, 998 + "foreignKeys": {}, 999 + "compositePrimaryKeys": { 1000 + "verification_token_identifier_token_pk": { 1001 + "columns": ["identifier", "token"], 1002 + "name": "verification_token_identifier_token_pk" 1003 + } 1004 + }, 1005 + "uniqueConstraints": {} 1006 + }, 1007 + "page_subscriber": { 1008 + "name": "page_subscriber", 1009 + "columns": { 1010 + "id": { 1011 + "name": "id", 1012 + "type": "integer", 1013 + "primaryKey": true, 1014 + "notNull": true, 1015 + "autoincrement": false 1016 + }, 1017 + "email": { 1018 + "name": "email", 1019 + "type": "text", 1020 + "primaryKey": false, 1021 + "notNull": true, 1022 + "autoincrement": false 1023 + }, 1024 + "page_id": { 1025 + "name": "page_id", 1026 + "type": "integer", 1027 + "primaryKey": false, 1028 + "notNull": true, 1029 + "autoincrement": false 1030 + }, 1031 + "token": { 1032 + "name": "token", 1033 + "type": "text", 1034 + "primaryKey": false, 1035 + "notNull": false, 1036 + "autoincrement": false 1037 + }, 1038 + "accepted_at": { 1039 + "name": "accepted_at", 1040 + "type": "integer", 1041 + "primaryKey": false, 1042 + "notNull": false, 1043 + "autoincrement": false 1044 + }, 1045 + "expires_at": { 1046 + "name": "expires_at", 1047 + "type": "integer", 1048 + "primaryKey": false, 1049 + "notNull": false, 1050 + "autoincrement": false 1051 + }, 1052 + "created_at": { 1053 + "name": "created_at", 1054 + "type": "integer", 1055 + "primaryKey": false, 1056 + "notNull": false, 1057 + "autoincrement": false, 1058 + "default": "(strftime('%s', 'now'))" 1059 + }, 1060 + "updated_at": { 1061 + "name": "updated_at", 1062 + "type": "integer", 1063 + "primaryKey": false, 1064 + "notNull": false, 1065 + "autoincrement": false, 1066 + "default": "(strftime('%s', 'now'))" 1067 + } 1068 + }, 1069 + "indexes": {}, 1070 + "foreignKeys": { 1071 + "page_subscriber_page_id_page_id_fk": { 1072 + "name": "page_subscriber_page_id_page_id_fk", 1073 + "tableFrom": "page_subscriber", 1074 + "tableTo": "page", 1075 + "columnsFrom": ["page_id"], 1076 + "columnsTo": ["id"], 1077 + "onDelete": "no action", 1078 + "onUpdate": "no action" 1079 + } 1080 + }, 1081 + "compositePrimaryKeys": {}, 1082 + "uniqueConstraints": {} 1083 + }, 1084 + "workspace": { 1085 + "name": "workspace", 1086 + "columns": { 1087 + "id": { 1088 + "name": "id", 1089 + "type": "integer", 1090 + "primaryKey": true, 1091 + "notNull": true, 1092 + "autoincrement": false 1093 + }, 1094 + "slug": { 1095 + "name": "slug", 1096 + "type": "text", 1097 + "primaryKey": false, 1098 + "notNull": true, 1099 + "autoincrement": false 1100 + }, 1101 + "name": { 1102 + "name": "name", 1103 + "type": "text", 1104 + "primaryKey": false, 1105 + "notNull": false, 1106 + "autoincrement": false 1107 + }, 1108 + "stripe_id": { 1109 + "name": "stripe_id", 1110 + "type": "text(256)", 1111 + "primaryKey": false, 1112 + "notNull": false, 1113 + "autoincrement": false 1114 + }, 1115 + "subscription_id": { 1116 + "name": "subscription_id", 1117 + "type": "text", 1118 + "primaryKey": false, 1119 + "notNull": false, 1120 + "autoincrement": false 1121 + }, 1122 + "plan": { 1123 + "name": "plan", 1124 + "type": "text", 1125 + "primaryKey": false, 1126 + "notNull": false, 1127 + "autoincrement": false 1128 + }, 1129 + "ends_at": { 1130 + "name": "ends_at", 1131 + "type": "integer", 1132 + "primaryKey": false, 1133 + "notNull": false, 1134 + "autoincrement": false 1135 + }, 1136 + "paid_until": { 1137 + "name": "paid_until", 1138 + "type": "integer", 1139 + "primaryKey": false, 1140 + "notNull": false, 1141 + "autoincrement": false 1142 + }, 1143 + "created_at": { 1144 + "name": "created_at", 1145 + "type": "integer", 1146 + "primaryKey": false, 1147 + "notNull": false, 1148 + "autoincrement": false, 1149 + "default": "(strftime('%s', 'now'))" 1150 + }, 1151 + "updated_at": { 1152 + "name": "updated_at", 1153 + "type": "integer", 1154 + "primaryKey": false, 1155 + "notNull": false, 1156 + "autoincrement": false, 1157 + "default": "(strftime('%s', 'now'))" 1158 + }, 1159 + "dsn": { 1160 + "name": "dsn", 1161 + "type": "text", 1162 + "primaryKey": false, 1163 + "notNull": false, 1164 + "autoincrement": false 1165 + } 1166 + }, 1167 + "indexes": { 1168 + "workspace_slug_unique": { 1169 + "name": "workspace_slug_unique", 1170 + "columns": ["slug"], 1171 + "isUnique": true 1172 + }, 1173 + "workspace_stripe_id_unique": { 1174 + "name": "workspace_stripe_id_unique", 1175 + "columns": ["stripe_id"], 1176 + "isUnique": true 1177 + }, 1178 + "workspace_id_dsn_unique": { 1179 + "name": "workspace_id_dsn_unique", 1180 + "columns": ["id", "dsn"], 1181 + "isUnique": true 1182 + } 1183 + }, 1184 + "foreignKeys": {}, 1185 + "compositePrimaryKeys": {}, 1186 + "uniqueConstraints": {} 1187 + }, 1188 + "notification": { 1189 + "name": "notification", 1190 + "columns": { 1191 + "id": { 1192 + "name": "id", 1193 + "type": "integer", 1194 + "primaryKey": true, 1195 + "notNull": true, 1196 + "autoincrement": false 1197 + }, 1198 + "name": { 1199 + "name": "name", 1200 + "type": "text", 1201 + "primaryKey": false, 1202 + "notNull": true, 1203 + "autoincrement": false 1204 + }, 1205 + "provider": { 1206 + "name": "provider", 1207 + "type": "text", 1208 + "primaryKey": false, 1209 + "notNull": true, 1210 + "autoincrement": false 1211 + }, 1212 + "data": { 1213 + "name": "data", 1214 + "type": "text", 1215 + "primaryKey": false, 1216 + "notNull": false, 1217 + "autoincrement": false, 1218 + "default": "'{}'" 1219 + }, 1220 + "workspace_id": { 1221 + "name": "workspace_id", 1222 + "type": "integer", 1223 + "primaryKey": false, 1224 + "notNull": false, 1225 + "autoincrement": false 1226 + }, 1227 + "created_at": { 1228 + "name": "created_at", 1229 + "type": "integer", 1230 + "primaryKey": false, 1231 + "notNull": false, 1232 + "autoincrement": false, 1233 + "default": "(strftime('%s', 'now'))" 1234 + }, 1235 + "updated_at": { 1236 + "name": "updated_at", 1237 + "type": "integer", 1238 + "primaryKey": false, 1239 + "notNull": false, 1240 + "autoincrement": false, 1241 + "default": "(strftime('%s', 'now'))" 1242 + } 1243 + }, 1244 + "indexes": {}, 1245 + "foreignKeys": { 1246 + "notification_workspace_id_workspace_id_fk": { 1247 + "name": "notification_workspace_id_workspace_id_fk", 1248 + "tableFrom": "notification", 1249 + "tableTo": "workspace", 1250 + "columnsFrom": ["workspace_id"], 1251 + "columnsTo": ["id"], 1252 + "onDelete": "no action", 1253 + "onUpdate": "no action" 1254 + } 1255 + }, 1256 + "compositePrimaryKeys": {}, 1257 + "uniqueConstraints": {} 1258 + }, 1259 + "notifications_to_monitors": { 1260 + "name": "notifications_to_monitors", 1261 + "columns": { 1262 + "monitor_id": { 1263 + "name": "monitor_id", 1264 + "type": "integer", 1265 + "primaryKey": false, 1266 + "notNull": true, 1267 + "autoincrement": false 1268 + }, 1269 + "notification_id": { 1270 + "name": "notification_id", 1271 + "type": "integer", 1272 + "primaryKey": false, 1273 + "notNull": true, 1274 + "autoincrement": false 1275 + }, 1276 + "created_at": { 1277 + "name": "created_at", 1278 + "type": "integer", 1279 + "primaryKey": false, 1280 + "notNull": false, 1281 + "autoincrement": false, 1282 + "default": "(strftime('%s', 'now'))" 1283 + } 1284 + }, 1285 + "indexes": {}, 1286 + "foreignKeys": { 1287 + "notifications_to_monitors_monitor_id_monitor_id_fk": { 1288 + "name": "notifications_to_monitors_monitor_id_monitor_id_fk", 1289 + "tableFrom": "notifications_to_monitors", 1290 + "tableTo": "monitor", 1291 + "columnsFrom": ["monitor_id"], 1292 + "columnsTo": ["id"], 1293 + "onDelete": "cascade", 1294 + "onUpdate": "no action" 1295 + }, 1296 + "notifications_to_monitors_notification_id_notification_id_fk": { 1297 + "name": "notifications_to_monitors_notification_id_notification_id_fk", 1298 + "tableFrom": "notifications_to_monitors", 1299 + "tableTo": "notification", 1300 + "columnsFrom": ["notification_id"], 1301 + "columnsTo": ["id"], 1302 + "onDelete": "cascade", 1303 + "onUpdate": "no action" 1304 + } 1305 + }, 1306 + "compositePrimaryKeys": { 1307 + "notifications_to_monitors_monitor_id_notification_id_pk": { 1308 + "columns": ["monitor_id", "notification_id"], 1309 + "name": "notifications_to_monitors_monitor_id_notification_id_pk" 1310 + } 1311 + }, 1312 + "uniqueConstraints": {} 1313 + }, 1314 + "monitor_status": { 1315 + "name": "monitor_status", 1316 + "columns": { 1317 + "monitor_id": { 1318 + "name": "monitor_id", 1319 + "type": "integer", 1320 + "primaryKey": false, 1321 + "notNull": true, 1322 + "autoincrement": false 1323 + }, 1324 + "region": { 1325 + "name": "region", 1326 + "type": "text", 1327 + "primaryKey": false, 1328 + "notNull": true, 1329 + "autoincrement": false, 1330 + "default": "''" 1331 + }, 1332 + "status": { 1333 + "name": "status", 1334 + "type": "text", 1335 + "primaryKey": false, 1336 + "notNull": true, 1337 + "autoincrement": false, 1338 + "default": "'active'" 1339 + }, 1340 + "created_at": { 1341 + "name": "created_at", 1342 + "type": "integer", 1343 + "primaryKey": false, 1344 + "notNull": false, 1345 + "autoincrement": false, 1346 + "default": "(strftime('%s', 'now'))" 1347 + }, 1348 + "updated_at": { 1349 + "name": "updated_at", 1350 + "type": "integer", 1351 + "primaryKey": false, 1352 + "notNull": false, 1353 + "autoincrement": false, 1354 + "default": "(strftime('%s', 'now'))" 1355 + } 1356 + }, 1357 + "indexes": { 1358 + "monitor_status_idx": { 1359 + "name": "monitor_status_idx", 1360 + "columns": ["monitor_id", "region"], 1361 + "isUnique": false 1362 + } 1363 + }, 1364 + "foreignKeys": { 1365 + "monitor_status_monitor_id_monitor_id_fk": { 1366 + "name": "monitor_status_monitor_id_monitor_id_fk", 1367 + "tableFrom": "monitor_status", 1368 + "tableTo": "monitor", 1369 + "columnsFrom": ["monitor_id"], 1370 + "columnsTo": ["id"], 1371 + "onDelete": "cascade", 1372 + "onUpdate": "no action" 1373 + } 1374 + }, 1375 + "compositePrimaryKeys": { 1376 + "monitor_status_monitor_id_region_pk": { 1377 + "columns": ["monitor_id", "region"], 1378 + "name": "monitor_status_monitor_id_region_pk" 1379 + } 1380 + }, 1381 + "uniqueConstraints": {} 1382 + }, 1383 + "invitation": { 1384 + "name": "invitation", 1385 + "columns": { 1386 + "id": { 1387 + "name": "id", 1388 + "type": "integer", 1389 + "primaryKey": true, 1390 + "notNull": true, 1391 + "autoincrement": false 1392 + }, 1393 + "email": { 1394 + "name": "email", 1395 + "type": "text", 1396 + "primaryKey": false, 1397 + "notNull": true, 1398 + "autoincrement": false 1399 + }, 1400 + "role": { 1401 + "name": "role", 1402 + "type": "text", 1403 + "primaryKey": false, 1404 + "notNull": true, 1405 + "autoincrement": false, 1406 + "default": "'member'" 1407 + }, 1408 + "workspace_id": { 1409 + "name": "workspace_id", 1410 + "type": "integer", 1411 + "primaryKey": false, 1412 + "notNull": true, 1413 + "autoincrement": false 1414 + }, 1415 + "token": { 1416 + "name": "token", 1417 + "type": "text", 1418 + "primaryKey": false, 1419 + "notNull": true, 1420 + "autoincrement": false 1421 + }, 1422 + "expires_at": { 1423 + "name": "expires_at", 1424 + "type": "integer", 1425 + "primaryKey": false, 1426 + "notNull": true, 1427 + "autoincrement": false 1428 + }, 1429 + "created_at": { 1430 + "name": "created_at", 1431 + "type": "integer", 1432 + "primaryKey": false, 1433 + "notNull": false, 1434 + "autoincrement": false, 1435 + "default": "(strftime('%s', 'now'))" 1436 + }, 1437 + "accepted_at": { 1438 + "name": "accepted_at", 1439 + "type": "integer", 1440 + "primaryKey": false, 1441 + "notNull": false, 1442 + "autoincrement": false 1443 + } 1444 + }, 1445 + "indexes": {}, 1446 + "foreignKeys": {}, 1447 + "compositePrimaryKeys": {}, 1448 + "uniqueConstraints": {} 1449 + }, 1450 + "incident": { 1451 + "name": "incident", 1452 + "columns": { 1453 + "id": { 1454 + "name": "id", 1455 + "type": "integer", 1456 + "primaryKey": true, 1457 + "notNull": true, 1458 + "autoincrement": false 1459 + }, 1460 + "title": { 1461 + "name": "title", 1462 + "type": "text", 1463 + "primaryKey": false, 1464 + "notNull": true, 1465 + "autoincrement": false, 1466 + "default": "''" 1467 + }, 1468 + "summary": { 1469 + "name": "summary", 1470 + "type": "text", 1471 + "primaryKey": false, 1472 + "notNull": true, 1473 + "autoincrement": false, 1474 + "default": "''" 1475 + }, 1476 + "status": { 1477 + "name": "status", 1478 + "type": "text", 1479 + "primaryKey": false, 1480 + "notNull": true, 1481 + "autoincrement": false, 1482 + "default": "'triage'" 1483 + }, 1484 + "monitor_id": { 1485 + "name": "monitor_id", 1486 + "type": "integer", 1487 + "primaryKey": false, 1488 + "notNull": false, 1489 + "autoincrement": false 1490 + }, 1491 + "workspace_id": { 1492 + "name": "workspace_id", 1493 + "type": "integer", 1494 + "primaryKey": false, 1495 + "notNull": false, 1496 + "autoincrement": false 1497 + }, 1498 + "started_at": { 1499 + "name": "started_at", 1500 + "type": "integer", 1501 + "primaryKey": false, 1502 + "notNull": true, 1503 + "autoincrement": false, 1504 + "default": "(strftime('%s', 'now'))" 1505 + }, 1506 + "acknowledged_at": { 1507 + "name": "acknowledged_at", 1508 + "type": "integer", 1509 + "primaryKey": false, 1510 + "notNull": false, 1511 + "autoincrement": false 1512 + }, 1513 + "acknowledged_by": { 1514 + "name": "acknowledged_by", 1515 + "type": "integer", 1516 + "primaryKey": false, 1517 + "notNull": false, 1518 + "autoincrement": false 1519 + }, 1520 + "resolved_at": { 1521 + "name": "resolved_at", 1522 + "type": "integer", 1523 + "primaryKey": false, 1524 + "notNull": false, 1525 + "autoincrement": false 1526 + }, 1527 + "resolved_by": { 1528 + "name": "resolved_by", 1529 + "type": "integer", 1530 + "primaryKey": false, 1531 + "notNull": false, 1532 + "autoincrement": false 1533 + }, 1534 + "incident_screenshot_url": { 1535 + "name": "incident_screenshot_url", 1536 + "type": "text", 1537 + "primaryKey": false, 1538 + "notNull": false, 1539 + "autoincrement": false 1540 + }, 1541 + "recovery_screenshot_url": { 1542 + "name": "recovery_screenshot_url", 1543 + "type": "text", 1544 + "primaryKey": false, 1545 + "notNull": false, 1546 + "autoincrement": false 1547 + }, 1548 + "auto_resolved": { 1549 + "name": "auto_resolved", 1550 + "type": "integer", 1551 + "primaryKey": false, 1552 + "notNull": false, 1553 + "autoincrement": false, 1554 + "default": false 1555 + }, 1556 + "created_at": { 1557 + "name": "created_at", 1558 + "type": "integer", 1559 + "primaryKey": false, 1560 + "notNull": false, 1561 + "autoincrement": false, 1562 + "default": "(strftime('%s', 'now'))" 1563 + }, 1564 + "updated_at": { 1565 + "name": "updated_at", 1566 + "type": "integer", 1567 + "primaryKey": false, 1568 + "notNull": false, 1569 + "autoincrement": false, 1570 + "default": "(strftime('%s', 'now'))" 1571 + } 1572 + }, 1573 + "indexes": { 1574 + "incident_monitor_id_started_at_unique": { 1575 + "name": "incident_monitor_id_started_at_unique", 1576 + "columns": ["monitor_id", "started_at"], 1577 + "isUnique": true 1578 + } 1579 + }, 1580 + "foreignKeys": { 1581 + "incident_monitor_id_monitor_id_fk": { 1582 + "name": "incident_monitor_id_monitor_id_fk", 1583 + "tableFrom": "incident", 1584 + "tableTo": "monitor", 1585 + "columnsFrom": ["monitor_id"], 1586 + "columnsTo": ["id"], 1587 + "onDelete": "set default", 1588 + "onUpdate": "no action" 1589 + }, 1590 + "incident_workspace_id_workspace_id_fk": { 1591 + "name": "incident_workspace_id_workspace_id_fk", 1592 + "tableFrom": "incident", 1593 + "tableTo": "workspace", 1594 + "columnsFrom": ["workspace_id"], 1595 + "columnsTo": ["id"], 1596 + "onDelete": "no action", 1597 + "onUpdate": "no action" 1598 + }, 1599 + "incident_acknowledged_by_user_id_fk": { 1600 + "name": "incident_acknowledged_by_user_id_fk", 1601 + "tableFrom": "incident", 1602 + "tableTo": "user", 1603 + "columnsFrom": ["acknowledged_by"], 1604 + "columnsTo": ["id"], 1605 + "onDelete": "no action", 1606 + "onUpdate": "no action" 1607 + }, 1608 + "incident_resolved_by_user_id_fk": { 1609 + "name": "incident_resolved_by_user_id_fk", 1610 + "tableFrom": "incident", 1611 + "tableTo": "user", 1612 + "columnsFrom": ["resolved_by"], 1613 + "columnsTo": ["id"], 1614 + "onDelete": "no action", 1615 + "onUpdate": "no action" 1616 + } 1617 + }, 1618 + "compositePrimaryKeys": {}, 1619 + "uniqueConstraints": {} 1620 + }, 1621 + "monitor_tag": { 1622 + "name": "monitor_tag", 1623 + "columns": { 1624 + "id": { 1625 + "name": "id", 1626 + "type": "integer", 1627 + "primaryKey": true, 1628 + "notNull": true, 1629 + "autoincrement": false 1630 + }, 1631 + "workspace_id": { 1632 + "name": "workspace_id", 1633 + "type": "integer", 1634 + "primaryKey": false, 1635 + "notNull": true, 1636 + "autoincrement": false 1637 + }, 1638 + "name": { 1639 + "name": "name", 1640 + "type": "text", 1641 + "primaryKey": false, 1642 + "notNull": true, 1643 + "autoincrement": false 1644 + }, 1645 + "color": { 1646 + "name": "color", 1647 + "type": "text", 1648 + "primaryKey": false, 1649 + "notNull": true, 1650 + "autoincrement": false 1651 + }, 1652 + "created_at": { 1653 + "name": "created_at", 1654 + "type": "integer", 1655 + "primaryKey": false, 1656 + "notNull": false, 1657 + "autoincrement": false, 1658 + "default": "(strftime('%s', 'now'))" 1659 + }, 1660 + "updated_at": { 1661 + "name": "updated_at", 1662 + "type": "integer", 1663 + "primaryKey": false, 1664 + "notNull": false, 1665 + "autoincrement": false, 1666 + "default": "(strftime('%s', 'now'))" 1667 + } 1668 + }, 1669 + "indexes": {}, 1670 + "foreignKeys": { 1671 + "monitor_tag_workspace_id_workspace_id_fk": { 1672 + "name": "monitor_tag_workspace_id_workspace_id_fk", 1673 + "tableFrom": "monitor_tag", 1674 + "tableTo": "workspace", 1675 + "columnsFrom": ["workspace_id"], 1676 + "columnsTo": ["id"], 1677 + "onDelete": "cascade", 1678 + "onUpdate": "no action" 1679 + } 1680 + }, 1681 + "compositePrimaryKeys": {}, 1682 + "uniqueConstraints": {} 1683 + }, 1684 + "monitor_tag_to_monitor": { 1685 + "name": "monitor_tag_to_monitor", 1686 + "columns": { 1687 + "monitor_id": { 1688 + "name": "monitor_id", 1689 + "type": "integer", 1690 + "primaryKey": false, 1691 + "notNull": true, 1692 + "autoincrement": false 1693 + }, 1694 + "monitor_tag_id": { 1695 + "name": "monitor_tag_id", 1696 + "type": "integer", 1697 + "primaryKey": false, 1698 + "notNull": true, 1699 + "autoincrement": false 1700 + }, 1701 + "created_at": { 1702 + "name": "created_at", 1703 + "type": "integer", 1704 + "primaryKey": false, 1705 + "notNull": false, 1706 + "autoincrement": false, 1707 + "default": "(strftime('%s', 'now'))" 1708 + } 1709 + }, 1710 + "indexes": {}, 1711 + "foreignKeys": { 1712 + "monitor_tag_to_monitor_monitor_id_monitor_id_fk": { 1713 + "name": "monitor_tag_to_monitor_monitor_id_monitor_id_fk", 1714 + "tableFrom": "monitor_tag_to_monitor", 1715 + "tableTo": "monitor", 1716 + "columnsFrom": ["monitor_id"], 1717 + "columnsTo": ["id"], 1718 + "onDelete": "cascade", 1719 + "onUpdate": "no action" 1720 + }, 1721 + "monitor_tag_to_monitor_monitor_tag_id_monitor_tag_id_fk": { 1722 + "name": "monitor_tag_to_monitor_monitor_tag_id_monitor_tag_id_fk", 1723 + "tableFrom": "monitor_tag_to_monitor", 1724 + "tableTo": "monitor_tag", 1725 + "columnsFrom": ["monitor_tag_id"], 1726 + "columnsTo": ["id"], 1727 + "onDelete": "cascade", 1728 + "onUpdate": "no action" 1729 + } 1730 + }, 1731 + "compositePrimaryKeys": { 1732 + "monitor_tag_to_monitor_monitor_id_monitor_tag_id_pk": { 1733 + "columns": ["monitor_id", "monitor_tag_id"], 1734 + "name": "monitor_tag_to_monitor_monitor_id_monitor_tag_id_pk" 1735 + } 1736 + }, 1737 + "uniqueConstraints": {} 1738 + }, 1739 + "application": { 1740 + "name": "application", 1741 + "columns": { 1742 + "id": { 1743 + "name": "id", 1744 + "type": "integer", 1745 + "primaryKey": true, 1746 + "notNull": true, 1747 + "autoincrement": false 1748 + }, 1749 + "name": { 1750 + "name": "name", 1751 + "type": "text", 1752 + "primaryKey": false, 1753 + "notNull": false, 1754 + "autoincrement": false 1755 + }, 1756 + "dsn": { 1757 + "name": "dsn", 1758 + "type": "text", 1759 + "primaryKey": false, 1760 + "notNull": false, 1761 + "autoincrement": false 1762 + }, 1763 + "workspace_id": { 1764 + "name": "workspace_id", 1765 + "type": "integer", 1766 + "primaryKey": false, 1767 + "notNull": false, 1768 + "autoincrement": false 1769 + }, 1770 + "created_at": { 1771 + "name": "created_at", 1772 + "type": "integer", 1773 + "primaryKey": false, 1774 + "notNull": false, 1775 + "autoincrement": false, 1776 + "default": "(strftime('%s', 'now'))" 1777 + }, 1778 + "updated_at": { 1779 + "name": "updated_at", 1780 + "type": "integer", 1781 + "primaryKey": false, 1782 + "notNull": false, 1783 + "autoincrement": false, 1784 + "default": "(strftime('%s', 'now'))" 1785 + } 1786 + }, 1787 + "indexes": { 1788 + "application_dsn_unique": { 1789 + "name": "application_dsn_unique", 1790 + "columns": ["dsn"], 1791 + "isUnique": true 1792 + } 1793 + }, 1794 + "foreignKeys": { 1795 + "application_workspace_id_workspace_id_fk": { 1796 + "name": "application_workspace_id_workspace_id_fk", 1797 + "tableFrom": "application", 1798 + "tableTo": "workspace", 1799 + "columnsFrom": ["workspace_id"], 1800 + "columnsTo": ["id"], 1801 + "onDelete": "no action", 1802 + "onUpdate": "no action" 1803 + } 1804 + }, 1805 + "compositePrimaryKeys": {}, 1806 + "uniqueConstraints": {} 1807 + }, 1808 + "maintenance": { 1809 + "name": "maintenance", 1810 + "columns": { 1811 + "id": { 1812 + "name": "id", 1813 + "type": "integer", 1814 + "primaryKey": true, 1815 + "notNull": true, 1816 + "autoincrement": false 1817 + }, 1818 + "title": { 1819 + "name": "title", 1820 + "type": "text(256)", 1821 + "primaryKey": false, 1822 + "notNull": true, 1823 + "autoincrement": false 1824 + }, 1825 + "message": { 1826 + "name": "message", 1827 + "type": "text", 1828 + "primaryKey": false, 1829 + "notNull": true, 1830 + "autoincrement": false 1831 + }, 1832 + "from": { 1833 + "name": "from", 1834 + "type": "integer", 1835 + "primaryKey": false, 1836 + "notNull": true, 1837 + "autoincrement": false 1838 + }, 1839 + "to": { 1840 + "name": "to", 1841 + "type": "integer", 1842 + "primaryKey": false, 1843 + "notNull": true, 1844 + "autoincrement": false 1845 + }, 1846 + "workspace_id": { 1847 + "name": "workspace_id", 1848 + "type": "integer", 1849 + "primaryKey": false, 1850 + "notNull": false, 1851 + "autoincrement": false 1852 + }, 1853 + "page_id": { 1854 + "name": "page_id", 1855 + "type": "integer", 1856 + "primaryKey": false, 1857 + "notNull": false, 1858 + "autoincrement": false 1859 + }, 1860 + "created_at": { 1861 + "name": "created_at", 1862 + "type": "integer", 1863 + "primaryKey": false, 1864 + "notNull": false, 1865 + "autoincrement": false, 1866 + "default": "(strftime('%s', 'now'))" 1867 + }, 1868 + "updated_at": { 1869 + "name": "updated_at", 1870 + "type": "integer", 1871 + "primaryKey": false, 1872 + "notNull": false, 1873 + "autoincrement": false, 1874 + "default": "(strftime('%s', 'now'))" 1875 + } 1876 + }, 1877 + "indexes": {}, 1878 + "foreignKeys": { 1879 + "maintenance_workspace_id_workspace_id_fk": { 1880 + "name": "maintenance_workspace_id_workspace_id_fk", 1881 + "tableFrom": "maintenance", 1882 + "tableTo": "workspace", 1883 + "columnsFrom": ["workspace_id"], 1884 + "columnsTo": ["id"], 1885 + "onDelete": "no action", 1886 + "onUpdate": "no action" 1887 + }, 1888 + "maintenance_page_id_page_id_fk": { 1889 + "name": "maintenance_page_id_page_id_fk", 1890 + "tableFrom": "maintenance", 1891 + "tableTo": "page", 1892 + "columnsFrom": ["page_id"], 1893 + "columnsTo": ["id"], 1894 + "onDelete": "no action", 1895 + "onUpdate": "no action" 1896 + } 1897 + }, 1898 + "compositePrimaryKeys": {}, 1899 + "uniqueConstraints": {} 1900 + }, 1901 + "maintenance_to_monitor": { 1902 + "name": "maintenance_to_monitor", 1903 + "columns": { 1904 + "monitor_id": { 1905 + "name": "monitor_id", 1906 + "type": "integer", 1907 + "primaryKey": false, 1908 + "notNull": true, 1909 + "autoincrement": false 1910 + }, 1911 + "maintenance_id": { 1912 + "name": "maintenance_id", 1913 + "type": "integer", 1914 + "primaryKey": false, 1915 + "notNull": true, 1916 + "autoincrement": false 1917 + }, 1918 + "created_at": { 1919 + "name": "created_at", 1920 + "type": "integer", 1921 + "primaryKey": false, 1922 + "notNull": false, 1923 + "autoincrement": false, 1924 + "default": "(strftime('%s', 'now'))" 1925 + } 1926 + }, 1927 + "indexes": {}, 1928 + "foreignKeys": { 1929 + "maintenance_to_monitor_monitor_id_monitor_id_fk": { 1930 + "name": "maintenance_to_monitor_monitor_id_monitor_id_fk", 1931 + "tableFrom": "maintenance_to_monitor", 1932 + "tableTo": "monitor", 1933 + "columnsFrom": ["monitor_id"], 1934 + "columnsTo": ["id"], 1935 + "onDelete": "cascade", 1936 + "onUpdate": "no action" 1937 + }, 1938 + "maintenance_to_monitor_maintenance_id_maintenance_id_fk": { 1939 + "name": "maintenance_to_monitor_maintenance_id_maintenance_id_fk", 1940 + "tableFrom": "maintenance_to_monitor", 1941 + "tableTo": "maintenance", 1942 + "columnsFrom": ["maintenance_id"], 1943 + "columnsTo": ["id"], 1944 + "onDelete": "cascade", 1945 + "onUpdate": "no action" 1946 + } 1947 + }, 1948 + "compositePrimaryKeys": { 1949 + "maintenance_to_monitor_monitor_id_maintenance_id_pk": { 1950 + "columns": ["maintenance_id", "monitor_id"], 1951 + "name": "maintenance_to_monitor_monitor_id_maintenance_id_pk" 1952 + } 1953 + }, 1954 + "uniqueConstraints": {} 1955 + }, 1956 + "check": { 1957 + "name": "check", 1958 + "columns": { 1959 + "id": { 1960 + "name": "id", 1961 + "type": "integer", 1962 + "primaryKey": true, 1963 + "notNull": true, 1964 + "autoincrement": true 1965 + }, 1966 + "regions": { 1967 + "name": "regions", 1968 + "type": "text", 1969 + "primaryKey": false, 1970 + "notNull": true, 1971 + "autoincrement": false, 1972 + "default": "''" 1973 + }, 1974 + "url": { 1975 + "name": "url", 1976 + "type": "text(4096)", 1977 + "primaryKey": false, 1978 + "notNull": true, 1979 + "autoincrement": false 1980 + }, 1981 + "headers": { 1982 + "name": "headers", 1983 + "type": "text", 1984 + "primaryKey": false, 1985 + "notNull": false, 1986 + "autoincrement": false, 1987 + "default": "''" 1988 + }, 1989 + "body": { 1990 + "name": "body", 1991 + "type": "text", 1992 + "primaryKey": false, 1993 + "notNull": false, 1994 + "autoincrement": false, 1995 + "default": "''" 1996 + }, 1997 + "method": { 1998 + "name": "method", 1999 + "type": "text", 2000 + "primaryKey": false, 2001 + "notNull": false, 2002 + "autoincrement": false, 2003 + "default": "'GET'" 2004 + }, 2005 + "count_requests": { 2006 + "name": "count_requests", 2007 + "type": "integer", 2008 + "primaryKey": false, 2009 + "notNull": false, 2010 + "autoincrement": false, 2011 + "default": 1 2012 + }, 2013 + "workspace_id": { 2014 + "name": "workspace_id", 2015 + "type": "integer", 2016 + "primaryKey": false, 2017 + "notNull": false, 2018 + "autoincrement": false 2019 + }, 2020 + "created_at": { 2021 + "name": "created_at", 2022 + "type": "integer", 2023 + "primaryKey": false, 2024 + "notNull": false, 2025 + "autoincrement": false, 2026 + "default": "(strftime('%s', 'now'))" 2027 + } 2028 + }, 2029 + "indexes": {}, 2030 + "foreignKeys": { 2031 + "check_workspace_id_workspace_id_fk": { 2032 + "name": "check_workspace_id_workspace_id_fk", 2033 + "tableFrom": "check", 2034 + "tableTo": "workspace", 2035 + "columnsFrom": ["workspace_id"], 2036 + "columnsTo": ["id"], 2037 + "onDelete": "no action", 2038 + "onUpdate": "no action" 2039 + } 2040 + }, 2041 + "compositePrimaryKeys": {}, 2042 + "uniqueConstraints": {} 2043 + } 2044 + }, 2045 + "enums": {}, 2046 + "_meta": { 2047 + "schemas": {}, 2048 + "tables": {}, 2049 + "columns": {} 2050 + } 2051 + }
+7
packages/db/drizzle/meta/_journal.json
··· 232 "when": 1718027484219, 233 "tag": "0032_hot_swordsman", 234 "breakpoints": true 235 } 236 ] 237 }
··· 232 "when": 1718027484219, 233 "tag": "0032_hot_swordsman", 234 "breakpoints": true 235 + }, 236 + { 237 + "idx": 33, 238 + "version": "6", 239 + "when": 1719740057514, 240 + "tag": "0033_solid_colossus", 241 + "breakpoints": true 242 } 243 ] 244 }
+1 -1
packages/db/src/schema/monitors/constants.ts
··· 46 "other", 47 ] as const; 48 export const monitorMethods = ["GET", "POST", "HEAD"] as const; 49 - export const monitorStatus = ["active", "error"] as const; 50 export const monitorRegions = [...flyRegions] as const; 51 52 export const monitorJobTypes = ["website", "cron", "other"] as const;
··· 46 "other", 47 ] as const; 48 export const monitorMethods = ["GET", "POST", "HEAD"] as const; 49 + export const monitorStatus = ["active", "error", "degraded"] as const; 50 export const monitorRegions = [...flyRegions] as const; 51 52 export const monitorJobTypes = ["website", "cron", "other"] as const;
+11 -5
packages/db/src/schema/monitors/monitor.ts
··· 42 method: text("method", { enum: monitorMethods }).default("GET"), 43 workspaceId: integer("workspace_id").references(() => workspace.id), 44 45 assertions: text("assertions"), 46 47 public: integer("public", { mode: "boolean" }).default(false), 48 49 createdAt: integer("created_at", { mode: "timestamp" }).default( 50 - sql`(strftime('%s', 'now'))`, 51 ), 52 updatedAt: integer("updated_at", { mode: "timestamp" }).default( 53 - sql`(strftime('%s', 'now'))`, 54 ), 55 56 deletedAt: integer("deleted_at", { mode: "timestamp" }), ··· 78 .notNull() 79 .references(() => page.id, { onDelete: "cascade" }), 80 createdAt: integer("created_at", { mode: "timestamp" }).default( 81 - sql`(strftime('%s', 'now'))`, 82 ), 83 order: integer("order").default(0), 84 }, 85 (t) => ({ 86 pk: primaryKey(t.monitorId, t.pageId), 87 - }), 88 ); 89 90 export const monitorsToPagesRelation = relations( ··· 98 fields: [monitorsToPages.pageId], 99 references: [page.id], 100 }), 101 - }), 102 );
··· 42 method: text("method", { enum: monitorMethods }).default("GET"), 43 workspaceId: integer("workspace_id").references(() => workspace.id), 44 45 + // Custom timeout for this monitor 46 + timeout: integer("timeout").notNull().default(45000), // in milliseconds 47 + 48 + // Threshold for the monitor to be considered degraded 49 + degradedAfter: integer("degraded_after"), // in millisecond 50 + 51 assertions: text("assertions"), 52 53 public: integer("public", { mode: "boolean" }).default(false), 54 55 createdAt: integer("created_at", { mode: "timestamp" }).default( 56 + sql`(strftime('%s', 'now'))` 57 ), 58 updatedAt: integer("updated_at", { mode: "timestamp" }).default( 59 + sql`(strftime('%s', 'now'))` 60 ), 61 62 deletedAt: integer("deleted_at", { mode: "timestamp" }), ··· 84 .notNull() 85 .references(() => page.id, { onDelete: "cascade" }), 86 createdAt: integer("created_at", { mode: "timestamp" }).default( 87 + sql`(strftime('%s', 'now'))` 88 ), 89 order: integer("order").default(0), 90 }, 91 (t) => ({ 92 pk: primaryKey(t.monitorId, t.pageId), 93 + }) 94 ); 95 96 export const monitorsToPagesRelation = relations( ··· 104 fields: [monitorsToPages.pageId], 105 references: [page.id], 106 }), 107 + }) 108 );
+3
packages/db/src/schema/monitors/validation.ts
··· 50 periodicity: monitorPeriodicitySchema.default("10m"), 51 status: monitorStatusSchema.default("active"), 52 jobType: monitorJobTypesSchema.default("other"), 53 regions: regionsToArraySchema.default([]), 54 }).extend({ 55 headers: headersToArraySchema.default([]), ··· 76 statusAssertions: z.array(assertions.statusAssertion).optional(), 77 headerAssertions: z.array(assertions.headerAssertion).optional(), 78 textBodyAssertions: z.array(assertions.textBodyAssertion).optional(), 79 }); 80 81 export const selectMonitorToPageSchema = createSelectSchema(monitorsToPages);
··· 50 periodicity: monitorPeriodicitySchema.default("10m"), 51 status: monitorStatusSchema.default("active"), 52 jobType: monitorJobTypesSchema.default("other"), 53 + timeout: z.number().default(45), 54 regions: regionsToArraySchema.default([]), 55 }).extend({ 56 headers: headersToArraySchema.default([]), ··· 77 statusAssertions: z.array(assertions.statusAssertion).optional(), 78 headerAssertions: z.array(assertions.headerAssertion).optional(), 79 textBodyAssertions: z.array(assertions.textBodyAssertion).optional(), 80 + timeout: z.coerce.number().gte(0).lte(60000).default(45000), 81 + degradedAfter: z.coerce.number().gte(0).lte(60000).nullish(), 82 }); 83 84 export const selectMonitorToPageSchema = createSelectSchema(monitorsToPages);
+31
packages/notifications/discord/src/index.ts
··· 78 } 79 }; 80 81 export const sendTestDiscordMessage = async (webhookUrl: string) => { 82 if (!webhookUrl) { 83 return false;
··· 78 } 79 }; 80 81 + export const sendDegraded = async ({ 82 + monitor, 83 + notification, 84 + // biome-ignore lint/correctness/noUnusedVariables: <explanation> 85 + statusCode, 86 + // biome-ignore lint/correctness/noUnusedVariables: <explanation> 87 + message, 88 + // biome-ignore lint/correctness/noUnusedVariables: <explanation> 89 + incidentId, 90 + }: { 91 + monitor: Monitor; 92 + notification: Notification; 93 + statusCode?: number; 94 + message?: string; 95 + incidentId?: string; 96 + }) => { 97 + const notificationData = JSON.parse(notification.data); 98 + const { discord: webhookUrl } = notificationData; // webhook url 99 + const { name } = monitor; 100 + 101 + try { 102 + await postToWebhook( 103 + `Your monitor ${name}|${monitor.url} is degraded โš ๏ธ`, 104 + webhookUrl 105 + ); 106 + } catch (err) { 107 + console.error(err); 108 + // Do something 109 + } 110 + }; 111 + 112 export const sendTestDiscordMessage = async (webhookUrl: string) => { 113 if (!webhookUrl) { 114 return false;
+42
packages/notifications/email/src/index.ts
··· 96 console.log(`Error sending recovery email ${monitor.id}`); 97 } 98 };
··· 96 console.log(`Error sending recovery email ${monitor.id}`); 97 } 98 }; 99 + 100 + export const sendDegraded = async ({ 101 + monitor, 102 + notification, 103 + // biome-ignore lint/correctness/noUnusedVariables: <explanation> 104 + statusCode, 105 + // biome-ignore lint/correctness/noUnusedVariables: <explanation> 106 + message, 107 + }: { 108 + monitor: Monitor; 109 + notification: Notification; 110 + statusCode?: number; 111 + message?: string; 112 + }) => { 113 + // FIXME: 114 + const config = EmailConfigurationSchema.parse(JSON.parse(notification.data)); 115 + const { email } = config; 116 + 117 + const res = await fetch("https://api.resend.com/emails", { 118 + method: "POST", 119 + headers: { 120 + "Content-Type": "application/json", 121 + Authorization: `Bearer ${env.RESEND_API_KEY}`, 122 + }, 123 + body: JSON.stringify({ 124 + to: email, 125 + from: "Notifications <ping@openstatus.dev>", 126 + 127 + subject: `Your monitor ${monitor.name} is degraded โš ๏ธ`, 128 + html: `<p>Hi,<br><br>Your monitor ${monitor.name} is taking longer than expected to respond</p><p>URL : ${monitor.url}</p> <p>OpenStatus ๐Ÿ“ </p>`, 129 + }), 130 + }); 131 + 132 + if (res.ok) { 133 + const data = await res.json(); 134 + console.log(data); 135 + // return NextResponse.json(data); 136 + } 137 + if (!res.ok) { 138 + console.log(`Error sending recovery email ${monitor.id}`); 139 + } 140 + };
+48
packages/notifications/pagerduty/src/index.ts
··· 54 } 55 }; 56 57 export const sendRecovery = async ({ 58 monitor, 59 notification,
··· 54 } 55 }; 56 57 + export const sendDegraded = async ({ 58 + monitor, 59 + notification, 60 + statusCode, 61 + message, 62 + incidentId, 63 + }: { 64 + monitor: Monitor; 65 + notification: Notification; 66 + statusCode?: number; 67 + message?: string; 68 + incidentId?: string; 69 + }) => { 70 + const notificationData = PagerDutySchema.parse(JSON.parse(notification.data)); 71 + const { name } = monitor; 72 + 73 + const event = triggerEventPayloadSchema.parse({ 74 + rounting_key: notificationData.integration_keys[0].integration_key, 75 + dedup_key: `${monitor.id}}`, 76 + event_action: "trigger", 77 + payload: { 78 + summary: `${name} is degraded`, 79 + source: "Open Status", 80 + severity: "warning", 81 + timestamp: new Date().toISOString(), 82 + custom_details: { 83 + statusCode, 84 + message, 85 + }, 86 + }, 87 + }); 88 + 89 + try { 90 + for await (const integrationKey of notificationData.integration_keys) { 91 + // biome-ignore lint/correctness/noUnusedVariables: <explanation> 92 + const { integration_key, type } = integrationKey; 93 + 94 + await fetch("https://events.pagerduty.com/v2/enqueue", { 95 + method: "POST", 96 + body: JSON.stringify(event), 97 + }); 98 + } 99 + } catch (err) { 100 + console.log(err); 101 + // Do something 102 + } 103 + }; 104 + 105 export const sendRecovery = async ({ 106 monitor, 107 notification,
+49
packages/notifications/slack/src/index.ts
··· 118 } 119 }; 120 121 export const sendTestSlackMessage = async (webhookUrl: string) => { 122 try { 123 await postToWebhook(
··· 118 } 119 }; 120 121 + export const sendDegraded = async ({ 122 + monitor, 123 + notification, 124 + // biome-ignore lint/correctness/noUnusedVariables: <explanation> 125 + statusCode, 126 + // biome-ignore lint/correctness/noUnusedVariables: <explanation> 127 + message, 128 + }: { 129 + monitor: Monitor; 130 + notification: Notification; 131 + statusCode?: number; 132 + message?: string; 133 + }) => { 134 + const notificationData = JSON.parse(notification.data); 135 + const { slack: webhookUrl } = notificationData; // webhook url 136 + const { name } = monitor; 137 + 138 + try { 139 + await postToWebhook( 140 + { 141 + blocks: [ 142 + { 143 + type: "section", 144 + text: { 145 + type: "mrkdwn", 146 + text: `Your monitor <${monitor.url}/|${name}> is degraded 147 + โš ๏ธ \n\n Powered by <https://www.openstatus.dev/|OpenStatus>.`, 148 + }, 149 + accessory: { 150 + type: "button", 151 + text: { 152 + type: "plain_text", 153 + text: "Open Monitor", 154 + emoji: true, 155 + }, 156 + value: `monitor_url_${monitor.url}`, 157 + url: monitor.url, 158 + }, 159 + }, 160 + ], 161 + }, 162 + webhookUrl 163 + ); 164 + } catch (err) { 165 + console.log(err); 166 + // Do something 167 + } 168 + }; 169 + 170 export const sendTestSlackMessage = async (webhookUrl: string) => { 171 try { 172 await postToWebhook(
+44
packages/notifications/twillio-sms/src/index.ts
··· 95 // Do something 96 } 97 };
··· 95 // Do something 96 } 97 }; 98 + 99 + export const sendDegraded = async ({ 100 + monitor, 101 + notification, 102 + // biome-ignore lint/correctness/noUnusedVariables: <explanation> 103 + statusCode, 104 + // biome-ignore lint/correctness/noUnusedVariables: <explanation> 105 + message, 106 + incidentId, 107 + }: { 108 + monitor: Monitor; 109 + notification: Notification; 110 + statusCode?: number; 111 + message?: string; 112 + incidentId?: string; 113 + }) => { 114 + const notificationData = SmsConfigurationSchema.parse( 115 + JSON.parse(notification.data) 116 + ); 117 + const { name } = monitor; 118 + 119 + const body = new FormData(); 120 + body.set("To", notificationData.sms); 121 + body.set("From", "+14807252613"); 122 + body.set("Body", `Your monitor ${name} / ${monitor.url} is degraded `); 123 + 124 + try { 125 + fetch( 126 + `https://api.twilio.com/2010-04-01/Accounts/${env.TWILLIO_ACCOUNT_ID}/Messages.json`, 127 + { 128 + method: "post", 129 + body, 130 + headers: { 131 + Authorization: `Basic ${btoa( 132 + `${env.TWILLIO_ACCOUNT_ID}:${env.TWILLIO_AUTH_TOKEN}` 133 + )}`, 134 + }, 135 + } 136 + ); 137 + } catch (err) { 138 + console.log(err); 139 + // Do something 140 + } 141 + };
+13
packages/tinybird/src/audit-log/action-schema.ts
··· 14 }); 15 16 /** 17 * The schema for the monitor.failed action. 18 * It represents the event when a monitor has failed. 19 */
··· 14 }); 15 16 /** 17 + * The schema for the monitor.recovered action. 18 + * It represents the event when a monitor has recovered from a failure. 19 + */ 20 + export const monitorDegradedSchema = z.object({ 21 + action: z.literal("monitor.degraded"), 22 + metadata: z.object({ 23 + region: z.string(), 24 + statusCode: z.number(), 25 + cronTimestamp: z.number().optional(), 26 + }), 27 + }); 28 + 29 + /** 30 * The schema for the monitor.failed action. 31 * It represents the event when a monitor has failed. 32 */
+2
packages/tinybird/src/audit-log/action-validation.ts
··· 1 import { z } from "zod"; 2 3 import { 4 monitorFailedSchema, 5 monitorRecoveredSchema, 6 notificationSentSchema, ··· 21 // and made available to devs as library 22 z.discriminatedUnion("action", [ 23 monitorRecoveredSchema, 24 monitorFailedSchema, 25 notificationSentSchema, 26 ]),
··· 1 import { z } from "zod"; 2 3 import { 4 + monitorDegradedSchema, 5 monitorFailedSchema, 6 monitorRecoveredSchema, 7 notificationSentSchema, ··· 22 // and made available to devs as library 23 z.discriminatedUnion("action", [ 24 monitorRecoveredSchema, 25 + monitorDegradedSchema, 26 monitorFailedSchema, 27 notificationSentSchema, 28 ]),