@checkstack/maintenance-common 0.0.2

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 ADDED
@@ -0,0 +1,66 @@
1
+ # @checkstack/maintenance-common
2
+
3
+ ## 0.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - d20d274: Initial release of all @checkstack packages. Rebranded from Checkmate to Checkstack with new npm organization @checkstack and domain checkstack.dev.
8
+ - Updated dependencies [d20d274]
9
+ - @checkstack/common@0.0.2
10
+ - @checkstack/frontend-api@0.0.2
11
+ - @checkstack/signal-common@0.0.2
12
+
13
+ ## 0.1.2
14
+
15
+ ### Patch Changes
16
+
17
+ - Updated dependencies [a65e002]
18
+ - Updated dependencies [ae33df2]
19
+ - Updated dependencies [32ea706]
20
+ - @checkstack/common@0.2.0
21
+ - @checkstack/frontend-api@0.1.0
22
+ - @checkstack/signal-common@0.1.1
23
+
24
+ ## 0.1.1
25
+
26
+ ### Patch Changes
27
+
28
+ - Updated dependencies [0f8cc7d]
29
+ - @checkstack/frontend-api@0.0.3
30
+
31
+ ## 0.1.0
32
+
33
+ ### Minor Changes
34
+
35
+ - eff5b4e: Add standalone maintenance scheduling plugin
36
+
37
+ - New `@checkstack/maintenance-common` package with Zod schemas, permissions, oRPC contract, and extension slots
38
+ - New `@checkstack/maintenance-backend` package with Drizzle schema, service, and oRPC router
39
+ - New `@checkstack/maintenance-frontend` package with admin page and system detail panel
40
+ - Shared `DateTimePicker` component added to `@checkstack/ui`
41
+ - Database migrations for maintenances, maintenance_systems, and maintenance_updates tables
42
+
43
+ - 4dd644d: Enable external application (API key) access to management endpoints
44
+
45
+ Changed `userType: "user"` to `userType: "authenticated"` for 52 endpoints across 5 packages, allowing external applications (service accounts with API keys) to call these endpoints programmatically while maintaining RBAC permission checks:
46
+
47
+ - **incident-common**: createIncident, updateIncident, addUpdate, resolveIncident, deleteIncident
48
+ - **maintenance-common**: createMaintenance, updateMaintenance, addUpdate, closeMaintenance, deleteMaintenance
49
+ - **catalog-common**: System CRUD, Group CRUD, addSystemToGroup, removeSystemFromGroup
50
+ - **healthcheck-common**: Configuration management, system associations, retention config, detailed history
51
+ - **integration-common**: Subscription management, connection management, event discovery, delivery logs
52
+
53
+ This enables automation use cases such as:
54
+
55
+ - Creating incidents from external monitoring systems (Prometheus, Grafana)
56
+ - Scheduling maintenances from CI/CD pipelines
57
+ - Managing catalog systems from infrastructure-as-code tools
58
+ - Configuring health checks from deployment scripts
59
+
60
+ ### Patch Changes
61
+
62
+ - Updated dependencies [ffc28f6]
63
+ - Updated dependencies [b55fae6]
64
+ - @checkstack/common@0.1.0
65
+ - @checkstack/signal-common@0.1.0
66
+ - @checkstack/frontend-api@0.0.2
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@checkstack/maintenance-common",
3
+ "version": "0.0.2",
4
+ "type": "module",
5
+ "exports": {
6
+ ".": {
7
+ "import": "./src/index.ts"
8
+ }
9
+ },
10
+ "dependencies": {
11
+ "@checkstack/common": "workspace:*",
12
+ "@checkstack/frontend-api": "workspace:*",
13
+ "@checkstack/signal-common": "workspace:*",
14
+ "@orpc/contract": "^1.13.2",
15
+ "zod": "^4.2.1"
16
+ },
17
+ "devDependencies": {
18
+ "typescript": "^5.7.2",
19
+ "@checkstack/tsconfig": "workspace:*",
20
+ "@checkstack/scripts": "workspace:*"
21
+ },
22
+ "scripts": {
23
+ "typecheck": "tsc --noEmit",
24
+ "lint": "bun run lint:code",
25
+ "lint:code": "eslint . --max-warnings 0"
26
+ }
27
+ }
package/src/index.ts ADDED
@@ -0,0 +1,47 @@
1
+ export { permissions, permissionList } from "./permissions";
2
+ export {
3
+ maintenanceContract,
4
+ MaintenanceApi,
5
+ type MaintenanceContract,
6
+ } from "./rpc-contract";
7
+ export {
8
+ MaintenanceStatusEnum,
9
+ MaintenanceSchema,
10
+ MaintenanceWithSystemsSchema,
11
+ MaintenanceUpdateSchema,
12
+ MaintenanceDetailSchema,
13
+ CreateMaintenanceInputSchema,
14
+ UpdateMaintenanceInputSchema,
15
+ AddMaintenanceUpdateInputSchema,
16
+ type MaintenanceStatus,
17
+ type Maintenance,
18
+ type MaintenanceWithSystems,
19
+ type MaintenanceUpdate,
20
+ type MaintenanceDetail,
21
+ type CreateMaintenanceInput,
22
+ type UpdateMaintenanceInput,
23
+ type AddMaintenanceUpdateInput,
24
+ } from "./schemas";
25
+ export { MaintenanceDetailsSlot, MaintenanceStatusSlot } from "./slots";
26
+ export * from "./plugin-metadata";
27
+ export { maintenanceRoutes } from "./routes";
28
+
29
+ // =============================================================================
30
+ // REALTIME SIGNALS
31
+ // =============================================================================
32
+
33
+ import { createSignal } from "@checkstack/signal-common";
34
+ import { z } from "zod";
35
+
36
+ /**
37
+ * Broadcast when a maintenance is created, updated, or closed.
38
+ * Frontend components listening to this signal can refetch state for affected systems.
39
+ */
40
+ export const MAINTENANCE_UPDATED = createSignal(
41
+ "maintenance.updated",
42
+ z.object({
43
+ maintenanceId: z.string(),
44
+ systemIds: z.array(z.string()),
45
+ action: z.enum(["created", "updated", "closed"]),
46
+ })
47
+ );
@@ -0,0 +1,19 @@
1
+ import { createPermission, type Permission } from "@checkstack/common";
2
+
3
+ export const permissions = {
4
+ /** Read access to maintenances - granted to all authenticated users by default */
5
+ maintenanceRead: createPermission(
6
+ "maintenance",
7
+ "read",
8
+ "View planned maintenances",
9
+ { isAuthenticatedDefault: true, isPublicDefault: true }
10
+ ),
11
+ /** Manage maintenances - create, edit, delete, and add updates */
12
+ maintenanceManage: createPermission(
13
+ "maintenance",
14
+ "manage",
15
+ "Manage planned maintenances"
16
+ ),
17
+ } as const satisfies Record<string, Permission>;
18
+
19
+ export const permissionList = Object.values(permissions);
@@ -0,0 +1,9 @@
1
+ import { definePluginMetadata } from "@checkstack/common";
2
+
3
+ /**
4
+ * Plugin metadata for the maintenance plugin.
5
+ * Exported from the common package so both backend and frontend can reference it.
6
+ */
7
+ export const pluginMetadata = definePluginMetadata({
8
+ pluginId: "maintenance",
9
+ });
package/src/routes.ts ADDED
@@ -0,0 +1,31 @@
1
+ import { createRoutes } from "@checkstack/common";
2
+
3
+ /**
4
+ * Route definitions for the maintenance plugin.
5
+ * Import and use these routes in both frontend plugins and for link generation.
6
+ *
7
+ * @example Frontend plugin usage
8
+ * ```tsx
9
+ * import { maintenanceRoutes } from "@checkstack/maintenance-common";
10
+ *
11
+ * createFrontendPlugin({
12
+ * routes: [
13
+ * { route: maintenanceRoutes.routes.config, element: <ConfigPage /> },
14
+ * ],
15
+ * });
16
+ * ```
17
+ *
18
+ * @example Link generation
19
+ * ```tsx
20
+ * import { maintenanceRoutes } from "@checkstack/maintenance-common";
21
+ * import { usePluginRoute } from "@checkstack/frontend-api";
22
+ *
23
+ * const getRoute = usePluginRoute();
24
+ * <Link to={getRoute(maintenanceRoutes.routes.config)}>Maintenances</Link>
25
+ * ```
26
+ */
27
+ export const maintenanceRoutes = createRoutes("maintenance", {
28
+ config: "/config",
29
+ systemHistory: "/system/:systemId/history",
30
+ detail: "/:maintenanceId",
31
+ });
@@ -0,0 +1,110 @@
1
+ import { oc } from "@orpc/contract";
2
+ import { z } from "zod";
3
+ import {
4
+ createClientDefinition,
5
+ type ProcedureMetadata,
6
+ } from "@checkstack/common";
7
+ import { permissions } from "./permissions";
8
+ import { pluginMetadata } from "./plugin-metadata";
9
+ import {
10
+ MaintenanceWithSystemsSchema,
11
+ MaintenanceDetailSchema,
12
+ MaintenanceUpdateSchema,
13
+ CreateMaintenanceInputSchema,
14
+ UpdateMaintenanceInputSchema,
15
+ AddMaintenanceUpdateInputSchema,
16
+ MaintenanceStatusEnum,
17
+ } from "./schemas";
18
+
19
+ const _base = oc.$meta<ProcedureMetadata>({});
20
+
21
+ export const maintenanceContract = {
22
+ /** List all maintenances with optional status filter */
23
+ listMaintenances: _base
24
+ .meta({
25
+ userType: "public",
26
+ permissions: [permissions.maintenanceRead.id],
27
+ })
28
+ .input(
29
+ z
30
+ .object({
31
+ status: MaintenanceStatusEnum.optional(),
32
+ systemId: z.string().optional(),
33
+ })
34
+ .optional()
35
+ )
36
+ .output(z.array(MaintenanceWithSystemsSchema)),
37
+
38
+ /** Get a single maintenance with all details */
39
+ getMaintenance: _base
40
+ .meta({
41
+ userType: "public",
42
+ permissions: [permissions.maintenanceRead.id],
43
+ })
44
+ .input(z.object({ id: z.string() }))
45
+ .output(MaintenanceDetailSchema.nullable()),
46
+
47
+ /** Get active or upcoming maintenances for a specific system */
48
+ getMaintenancesForSystem: _base
49
+ .meta({
50
+ userType: "public",
51
+ permissions: [permissions.maintenanceRead.id],
52
+ })
53
+ .input(z.object({ systemId: z.string() }))
54
+ .output(z.array(MaintenanceWithSystemsSchema)),
55
+
56
+ /** Create a new maintenance */
57
+ createMaintenance: _base
58
+ .meta({
59
+ userType: "authenticated",
60
+ permissions: [permissions.maintenanceManage.id],
61
+ })
62
+ .input(CreateMaintenanceInputSchema)
63
+ .output(MaintenanceWithSystemsSchema),
64
+
65
+ /** Update an existing maintenance */
66
+ updateMaintenance: _base
67
+ .meta({
68
+ userType: "authenticated",
69
+ permissions: [permissions.maintenanceManage.id],
70
+ })
71
+ .input(UpdateMaintenanceInputSchema)
72
+ .output(MaintenanceWithSystemsSchema),
73
+
74
+ /** Add a status update to a maintenance */
75
+ addUpdate: _base
76
+ .meta({
77
+ userType: "authenticated",
78
+ permissions: [permissions.maintenanceManage.id],
79
+ })
80
+ .input(AddMaintenanceUpdateInputSchema)
81
+ .output(MaintenanceUpdateSchema),
82
+
83
+ /** Close a maintenance early (sets status to completed) */
84
+ closeMaintenance: _base
85
+ .meta({
86
+ userType: "authenticated",
87
+ permissions: [permissions.maintenanceManage.id],
88
+ })
89
+ .input(z.object({ id: z.string(), message: z.string().optional() }))
90
+ .output(MaintenanceWithSystemsSchema),
91
+
92
+ /** Delete a maintenance */
93
+ deleteMaintenance: _base
94
+ .meta({
95
+ userType: "authenticated",
96
+ permissions: [permissions.maintenanceManage.id],
97
+ })
98
+ .input(z.object({ id: z.string() }))
99
+ .output(z.object({ success: z.boolean() })),
100
+ };
101
+
102
+ // Export contract type
103
+ export type MaintenanceContract = typeof maintenanceContract;
104
+
105
+ // Export client definition for type-safe forPlugin usage
106
+ // Use: const client = rpcApi.forPlugin(MaintenanceApi);
107
+ export const MaintenanceApi = createClientDefinition(
108
+ maintenanceContract,
109
+ pluginMetadata
110
+ );
package/src/schemas.ts ADDED
@@ -0,0 +1,96 @@
1
+ import { z } from "zod";
2
+
3
+ /**
4
+ * Maintenance status enum values
5
+ */
6
+ export const MaintenanceStatusEnum = z.enum([
7
+ "scheduled",
8
+ "in_progress",
9
+ "completed",
10
+ "cancelled",
11
+ ]);
12
+ export type MaintenanceStatus = z.infer<typeof MaintenanceStatusEnum>;
13
+
14
+ /**
15
+ * Core maintenance entity schema
16
+ */
17
+ export const MaintenanceSchema = z.object({
18
+ id: z.string(),
19
+ title: z.string(),
20
+ description: z.string().optional(),
21
+ status: MaintenanceStatusEnum,
22
+ startAt: z.date(),
23
+ endAt: z.date(),
24
+ createdAt: z.date(),
25
+ updatedAt: z.date(),
26
+ });
27
+ export type Maintenance = z.infer<typeof MaintenanceSchema>;
28
+
29
+ /**
30
+ * Maintenance with related systems
31
+ */
32
+ export const MaintenanceWithSystemsSchema = MaintenanceSchema.extend({
33
+ systemIds: z.array(z.string()),
34
+ });
35
+ export type MaintenanceWithSystems = z.infer<
36
+ typeof MaintenanceWithSystemsSchema
37
+ >;
38
+
39
+ /**
40
+ * Maintenance update schema - status updates posted to a maintenance
41
+ */
42
+ export const MaintenanceUpdateSchema = z.object({
43
+ id: z.string(),
44
+ maintenanceId: z.string(),
45
+ message: z.string(),
46
+ statusChange: MaintenanceStatusEnum.optional(),
47
+ createdAt: z.date(),
48
+ createdBy: z.string().optional(),
49
+ });
50
+ export type MaintenanceUpdate = z.infer<typeof MaintenanceUpdateSchema>;
51
+
52
+ /**
53
+ * Full maintenance detail with systems and updates
54
+ */
55
+ export const MaintenanceDetailSchema = MaintenanceWithSystemsSchema.extend({
56
+ updates: z.array(MaintenanceUpdateSchema),
57
+ });
58
+ export type MaintenanceDetail = z.infer<typeof MaintenanceDetailSchema>;
59
+
60
+ // Input schemas for mutations
61
+ export const CreateMaintenanceInputSchema = z
62
+ .object({
63
+ title: z.string().min(1, "Title is required"),
64
+ description: z.string().optional(),
65
+ startAt: z.date(),
66
+ endAt: z.date(),
67
+ systemIds: z.array(z.string()).min(1, "At least one system is required"),
68
+ })
69
+ .refine((data) => data.endAt > data.startAt, {
70
+ message: "End date must be after start date",
71
+ path: ["endAt"],
72
+ });
73
+ export type CreateMaintenanceInput = z.infer<
74
+ typeof CreateMaintenanceInputSchema
75
+ >;
76
+
77
+ export const UpdateMaintenanceInputSchema = z.object({
78
+ id: z.string(),
79
+ title: z.string().min(1).optional(),
80
+ description: z.string().nullable().optional(),
81
+ startAt: z.date().optional(),
82
+ endAt: z.date().optional(),
83
+ systemIds: z.array(z.string()).min(1).optional(),
84
+ });
85
+ export type UpdateMaintenanceInput = z.infer<
86
+ typeof UpdateMaintenanceInputSchema
87
+ >;
88
+
89
+ export const AddMaintenanceUpdateInputSchema = z.object({
90
+ maintenanceId: z.string(),
91
+ message: z.string().min(1, "Message is required"),
92
+ statusChange: MaintenanceStatusEnum.optional(),
93
+ });
94
+ export type AddMaintenanceUpdateInput = z.infer<
95
+ typeof AddMaintenanceUpdateInputSchema
96
+ >;
package/src/slots.ts ADDED
@@ -0,0 +1,18 @@
1
+ import { createSlot } from "@checkstack/frontend-api";
2
+ import type { MaintenanceWithSystems } from "./schemas";
3
+
4
+ /**
5
+ * Slot for extending maintenance detail views.
6
+ * Plugins can add additional content or actions to maintenance details.
7
+ */
8
+ export const MaintenanceDetailsSlot = createSlot<{
9
+ maintenance: MaintenanceWithSystems;
10
+ }>("plugin.maintenance.details");
11
+
12
+ /**
13
+ * Slot for adding custom status indicators to maintenances.
14
+ * Can be used to show external integrations, alerts, etc.
15
+ */
16
+ export const MaintenanceStatusSlot = createSlot<{
17
+ maintenance: MaintenanceWithSystems;
18
+ }>("plugin.maintenance.status");
package/tsconfig.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "extends": "@checkstack/tsconfig/common.json",
3
+ "include": [
4
+ "src"
5
+ ]
6
+ }