@checkstack/maintenance-common 0.3.2 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # @checkstack/maintenance-common
2
2
 
3
+ ## 0.4.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 8a87cd4: Updated access rules to use new `accessPair` interface
8
+
9
+ Migrated to the new `accessPair` interface with per-level options objects for cleaner access rule definitions.
10
+
11
+ - Updated dependencies [8a87cd4]
12
+ - @checkstack/common@0.5.0
13
+ - @checkstack/frontend-api@0.3.2
14
+ - @checkstack/signal-common@0.1.3
15
+
16
+ ## 0.4.0
17
+
18
+ ### Minor Changes
19
+
20
+ - 18fa8e3: Add notification suppression toggle for maintenance windows
21
+
22
+ **New Feature:** When creating or editing a maintenance window, you can now enable "Suppress health notifications" to prevent health status change notifications from being sent for affected systems while the maintenance is active (in_progress status). This is useful for planned downtime where health alerts are expected and would otherwise create noise.
23
+
24
+ **Changes:**
25
+
26
+ - Added `suppressNotifications` field to maintenance schema
27
+ - Added new service-to-service API `hasActiveMaintenanceWithSuppression`
28
+ - Healthcheck queue executor now checks for suppression before sending notifications
29
+ - MaintenanceEditor UI includes new toggle checkbox
30
+
31
+ **Bug Fix:** Fixed migration system to correctly set PostgreSQL search_path when running plugin migrations. Previously, migrations could fail with "relation does not exist" errors because the schema context wasn't properly set.
32
+
3
33
  ## 0.3.2
4
34
 
5
35
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@checkstack/maintenance-common",
3
- "version": "0.3.2",
3
+ "version": "0.4.1",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
package/src/access.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { access, accessPair } from "@checkstack/common";
1
+ import { accessPair } from "@checkstack/common";
2
2
 
3
3
  /**
4
4
  * Access rules for the Maintenance plugin.
@@ -8,34 +8,26 @@ export const maintenanceAccess = {
8
8
  * Maintenance access with both read and manage levels.
9
9
  * Read is public by default.
10
10
  * Uses system-level instance access for team-based filtering.
11
+ *
12
+ * Bulk endpoints should use the same access rule with instanceAccess
13
+ * override at the contract level.
11
14
  */
12
15
  maintenance: accessPair(
13
16
  "maintenance",
14
17
  {
15
- read: "View planned maintenances",
16
- manage:
17
- "Manage planned maintenances - create, edit, delete, and add updates",
18
+ read: {
19
+ description: "View planned maintenances",
20
+ isDefault: true,
21
+ isPublic: true,
22
+ },
23
+ manage: {
24
+ description:
25
+ "Manage planned maintenances - create, edit, delete, and add updates",
26
+ },
18
27
  },
19
28
  {
20
29
  idParam: "systemId",
21
- readIsDefault: true,
22
- readIsPublic: true,
23
- }
24
- ),
25
-
26
- /**
27
- * Bulk maintenance access for viewing maintenances for multiple systems.
28
- * Uses recordKey for filtering the output record by accessible system IDs.
29
- */
30
- bulkMaintenance: access(
31
- "maintenance.maintenance",
32
- "read",
33
- "View planned maintenances",
34
- {
35
- recordKey: "maintenances",
36
- isDefault: true,
37
- isPublic: true,
38
- }
30
+ },
39
31
  ),
40
32
  };
41
33
 
@@ -25,7 +25,7 @@ export const maintenanceContract = {
25
25
  status: MaintenanceStatusEnum.optional(),
26
26
  systemId: z.string().optional(),
27
27
  })
28
- .optional()
28
+ .optional(),
29
29
  )
30
30
  .output(z.object({ maintenances: z.array(MaintenanceWithSystemsSchema) })),
31
31
 
@@ -53,16 +53,17 @@ export const maintenanceContract = {
53
53
  getBulkMaintenancesForSystems: proc({
54
54
  operationType: "query",
55
55
  userType: "public",
56
- access: [maintenanceAccess.bulkMaintenance],
56
+ access: [maintenanceAccess.maintenance.read],
57
+ instanceAccess: { recordKey: "maintenances" },
57
58
  })
58
59
  .input(z.object({ systemIds: z.array(z.string()) }))
59
60
  .output(
60
61
  z.object({
61
62
  maintenances: z.record(
62
63
  z.string(),
63
- z.array(MaintenanceWithSystemsSchema)
64
+ z.array(MaintenanceWithSystemsSchema),
64
65
  ),
65
- })
66
+ }),
66
67
  ),
67
68
 
68
69
  /** Create a new maintenance */
@@ -109,6 +110,18 @@ export const maintenanceContract = {
109
110
  })
110
111
  .input(z.object({ id: z.string() }))
111
112
  .output(z.object({ success: z.boolean() })),
113
+
114
+ /** Check if a system has active maintenance with notification suppression enabled.
115
+ * Used by healthcheck to skip notifications during expected downtime.
116
+ * Service-to-service endpoint (not exposed to users).
117
+ */
118
+ hasActiveMaintenanceWithSuppression: proc({
119
+ operationType: "query",
120
+ userType: "service",
121
+ access: [],
122
+ })
123
+ .input(z.object({ systemId: z.string() }))
124
+ .output(z.object({ suppressed: z.boolean() })),
112
125
  };
113
126
 
114
127
  // Export contract type
@@ -118,5 +131,5 @@ export type MaintenanceContract = typeof maintenanceContract;
118
131
  // Use: const client = rpcApi.forPlugin(MaintenanceApi);
119
132
  export const MaintenanceApi = createClientDefinition(
120
133
  maintenanceContract,
121
- pluginMetadata
134
+ pluginMetadata,
122
135
  );
package/src/schemas.ts CHANGED
@@ -18,6 +18,7 @@ export const MaintenanceSchema = z.object({
18
18
  id: z.string(),
19
19
  title: z.string(),
20
20
  description: z.string().optional(),
21
+ suppressNotifications: z.boolean(),
21
22
  status: MaintenanceStatusEnum,
22
23
  startAt: z.date(),
23
24
  endAt: z.date(),
@@ -62,6 +63,7 @@ export const CreateMaintenanceInputSchema = z
62
63
  .object({
63
64
  title: z.string().min(1, "Title is required"),
64
65
  description: z.string().optional(),
66
+ suppressNotifications: z.boolean().optional().default(false),
65
67
  startAt: z.date(),
66
68
  endAt: z.date(),
67
69
  systemIds: z.array(z.string()).min(1, "At least one system is required"),
@@ -78,6 +80,7 @@ export const UpdateMaintenanceInputSchema = z.object({
78
80
  id: z.string(),
79
81
  title: z.string().min(1).optional(),
80
82
  description: z.string().nullable().optional(),
83
+ suppressNotifications: z.boolean().optional(),
81
84
  startAt: z.date().optional(),
82
85
  endAt: z.date().optional(),
83
86
  systemIds: z.array(z.string()).min(1).optional(),