@checkstack/integration-frontend 0.2.19 → 0.2.21

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,48 @@
1
1
  # @checkstack/integration-frontend
2
2
 
3
+ ## 0.2.21
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [26d8bae]
8
+ - @checkstack/ui@1.3.0
9
+
10
+ ## 0.2.20
11
+
12
+ ### Patch Changes
13
+
14
+ - d1a2796: Enforce stricter code quality standards and eliminate AI slop anti-patterns.
15
+
16
+ **New utility**
17
+
18
+ - `extractErrorMessage(error, fallback?)` in `@checkstack/common` for consistent error extraction
19
+
20
+ **ESLint rules**
21
+
22
+ - `react-hooks/rules-of-hooks` and `exhaustive-deps` for hook correctness
23
+ - `no-console` in frontend packages — forces `toast` over silent `console.error`
24
+ - `no-restricted-syntax` banning `instanceof Error` — forces `extractErrorMessage`
25
+ - Custom `no-eslint-disable-any` rule preventing `@typescript-eslint/no-explicit-any` circumvention
26
+
27
+ **Refactoring**
28
+
29
+ - Replace 141 `instanceof Error` boilerplate patterns across the codebase
30
+ - Replace swallowed `console.error` with user-visible `toast.error()` feedback
31
+ - Remove 15 redundant `as` type casts in IntegrationsPage and ProviderConnectionsPage
32
+ - Consolidate 3 identical callback handlers into `handleDialogClose`
33
+ - Fix conditional React hook call in `FormField.tsx`
34
+ - Fix unstable useMemo deps in `Dashboard.tsx`
35
+ - Replace `useEffect`→`setState` with derived `useMemo` in `RegisterPage.tsx`
36
+ - Rewrite `keystore.test.ts` with typed `DrizzleMockChain` (eliminating 7 `any` suppressions)
37
+ - Delete obvious comments in `encryption.ts` and Teams `provider.ts`
38
+
39
+ - Updated dependencies [d1a2796]
40
+ - @checkstack/common@0.6.5
41
+ - @checkstack/ui@1.2.1
42
+ - @checkstack/frontend-api@0.3.9
43
+ - @checkstack/integration-common@0.2.8
44
+ - @checkstack/signal-frontend@0.0.15
45
+
3
46
  ## 0.2.19
4
47
 
5
48
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@checkstack/integration-frontend",
3
- "version": "0.2.19",
3
+ "version": "0.2.21",
4
4
  "type": "module",
5
5
  "main": "src/index.tsx",
6
6
  "checkstack": {
@@ -12,11 +12,11 @@
12
12
  "lint:code": "eslint . --max-warnings 0"
13
13
  },
14
14
  "dependencies": {
15
- "@checkstack/integration-common": "0.2.7",
16
- "@checkstack/frontend-api": "0.3.8",
17
- "@checkstack/signal-frontend": "0.0.14",
18
- "@checkstack/common": "0.6.4",
19
- "@checkstack/ui": "1.1.3",
15
+ "@checkstack/integration-common": "0.2.8",
16
+ "@checkstack/frontend-api": "0.3.9",
17
+ "@checkstack/signal-frontend": "0.0.15",
18
+ "@checkstack/common": "0.6.5",
19
+ "@checkstack/ui": "1.2.1",
20
20
  "react": "^18.2.0",
21
21
  "react-router-dom": "^6.22.0",
22
22
  "lucide-react": "^0.344.0"
@@ -24,7 +24,7 @@
24
24
  "devDependencies": {
25
25
  "typescript": "^5.0.0",
26
26
  "@types/react": "^18.2.0",
27
- "@checkstack/tsconfig": "0.0.4",
27
+ "@checkstack/tsconfig": "0.0.5",
28
28
  "@checkstack/scripts": "0.1.2"
29
29
  }
30
30
  }
@@ -24,7 +24,7 @@ import {
24
24
  type LucideIconName,
25
25
  } from "@checkstack/ui";
26
26
  import { usePluginClient } from "@checkstack/frontend-api";
27
- import { resolveRoute } from "@checkstack/common";
27
+ import { resolveRoute, extractErrorMessage } from "@checkstack/common";
28
28
  import {
29
29
  IntegrationApi,
30
30
  integrationRoutes,
@@ -111,11 +111,7 @@ export const SubscriptionDialog = ({
111
111
  setSaving(false);
112
112
  },
113
113
  onError: (error) => {
114
- toast.error(
115
- error instanceof Error
116
- ? error.message
117
- : "Failed to create subscription",
118
- );
114
+ toast.error(extractErrorMessage(error, "Failed to create subscription"));
119
115
  setSaving(false);
120
116
  },
121
117
  });
@@ -128,11 +124,7 @@ export const SubscriptionDialog = ({
128
124
  setSaving(false);
129
125
  },
130
126
  onError: (error) => {
131
- toast.error(
132
- error instanceof Error
133
- ? error.message
134
- : "Failed to update subscription",
135
- );
127
+ toast.error(extractErrorMessage(error, "Failed to update subscription"));
136
128
  setSaving(false);
137
129
  },
138
130
  });
@@ -144,11 +136,7 @@ export const SubscriptionDialog = ({
144
136
  onOpenChange(false);
145
137
  },
146
138
  onError: (error) => {
147
- toast.error(
148
- error instanceof Error
149
- ? error.message
150
- : "Failed to delete subscription",
151
- );
139
+ toast.error(extractErrorMessage(error, "Failed to delete subscription"));
152
140
  },
153
141
  });
154
142
 
@@ -303,11 +291,7 @@ export const SubscriptionDialog = ({
303
291
  value: opt.value,
304
292
  label: opt.label,
305
293
  }));
306
- } catch (error) {
307
- console.error(
308
- `Failed to fetch options for ${resolverName}:`,
309
- error,
310
- );
294
+ } catch {
311
295
  return [];
312
296
  }
313
297
  };
@@ -320,7 +304,7 @@ export const SubscriptionDialog = ({
320
304
  formValues: Record<string, unknown>,
321
305
  ) => Promise<{ value: string; label: string }[]>
322
306
  >;
323
- // Note: getOptionsMutation intentionally omitted - mutation objects change on every render
307
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- getOptionsMutation is a TanStack mutation object that changes identity every render; including it would destroy the Proxy on each render, breaking in-flight requests
324
308
  }, [selectedProvider, selectedConnectionId]);
325
309
 
326
310
  return (
@@ -90,8 +90,7 @@ export const DeliveryLogsPage = () => {
90
90
  toast.error(result.message ?? "Failed to retry delivery");
91
91
  }
92
92
  },
93
- onError: (error) => {
94
- console.error("Failed to retry delivery:", error);
93
+ onError: () => {
95
94
  toast.error("Failed to retry delivery");
96
95
  },
97
96
  onSettled: () => {
@@ -26,7 +26,7 @@ import {
26
26
  type LucideIconName,
27
27
  } from "@checkstack/ui";
28
28
  import { usePluginClient } from "@checkstack/frontend-api";
29
- import { resolveRoute } from "@checkstack/common";
29
+ import { resolveRoute, extractErrorMessage} from "@checkstack/common";
30
30
  import {
31
31
  IntegrationApi,
32
32
  integrationRoutes,
@@ -67,9 +67,7 @@ export const IntegrationsPage = () => {
67
67
  },
68
68
  onError: (error) => {
69
69
  toast.error(
70
- error instanceof Error
71
- ? error.message
72
- : "Failed to toggle subscription",
70
+ extractErrorMessage(error, "Failed to toggle subscription"),
73
71
  );
74
72
  },
75
73
  });
@@ -91,28 +89,14 @@ export const IntegrationsPage = () => {
91
89
  const getProviderInfo = (
92
90
  providerId: string,
93
91
  ): IntegrationProviderInfo | undefined => {
94
- return (providers as IntegrationProviderInfo[]).find(
95
- (p) => p.qualifiedId === providerId,
96
- );
92
+ return providers.find((p) => p.qualifiedId === providerId);
97
93
  };
98
94
 
99
95
  const handleToggle = (id: string, enabled: boolean) => {
100
96
  toggleMutation.mutate({ id, enabled });
101
97
  };
102
98
 
103
- const handleCreated = () => {
104
- void refetchSubs();
105
- setDialogOpen(false);
106
- setSelectedSubscription(undefined);
107
- };
108
-
109
- const handleUpdated = () => {
110
- void refetchSubs();
111
- setDialogOpen(false);
112
- setSelectedSubscription(undefined);
113
- };
114
-
115
- const handleDeleted = () => {
99
+ const handleDialogClose = () => {
116
100
  void refetchSubs();
117
101
  setDialogOpen(false);
118
102
  setSelectedSubscription(undefined);
@@ -239,8 +223,8 @@ export const IntegrationsPage = () => {
239
223
  <div className="p-2 rounded-lg bg-muted">
240
224
  <DynamicIcon
241
225
  name={
242
- (provider?.icon ??
243
- "Webhook") as LucideIconName
226
+ (provider?.icon as LucideIconName | undefined) ??
227
+ "Webhook"
244
228
  }
245
229
  className="h-5 w-5 text-muted-foreground"
246
230
  />
@@ -305,14 +289,14 @@ export const IntegrationsPage = () => {
305
289
  description="Providers handle the delivery of events to external systems"
306
290
  />
307
291
  <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
308
- {(providers as IntegrationProviderInfo[]).map((provider) => (
292
+ {providers.map((provider) => (
309
293
  <Card key={provider.qualifiedId}>
310
294
  <CardContent className="p-4">
311
295
  <div className="flex items-center justify-between">
312
296
  <div className="flex items-center gap-3">
313
297
  <div className="p-2 rounded-lg bg-muted">
314
298
  <DynamicIcon
315
- name={(provider.icon ?? "Webhook") as LucideIconName}
299
+ name={(provider.icon as LucideIconName | undefined) ?? "Webhook"}
316
300
  className="h-6 w-6"
317
301
  />
318
302
  </div>
@@ -341,7 +325,7 @@ export const IntegrationsPage = () => {
341
325
  </CardContent>
342
326
  </Card>
343
327
  ))}
344
- {(providers as IntegrationProviderInfo[]).length === 0 && (
328
+ {providers.length === 0 && (
345
329
  <Card className="col-span-full">
346
330
  <CardContent className="p-4">
347
331
  <div className="text-center text-muted-foreground py-4">
@@ -361,11 +345,11 @@ export const IntegrationsPage = () => {
361
345
  setDialogOpen(open);
362
346
  if (!open) setSelectedSubscription(undefined);
363
347
  }}
364
- providers={providers as IntegrationProviderInfo[]}
348
+ providers={providers}
365
349
  subscription={selectedSubscription}
366
- onCreated={handleCreated}
367
- onUpdated={handleUpdated}
368
- onDeleted={handleDeleted}
350
+ onCreated={handleDialogClose}
351
+ onUpdated={handleDialogClose}
352
+ onDeleted={handleDialogClose}
369
353
  />
370
354
  </PageLayout>
371
355
  );
@@ -45,11 +45,10 @@ import {
45
45
  type LucideIconName,
46
46
  } from "@checkstack/ui";
47
47
  import { usePluginClient } from "@checkstack/frontend-api";
48
- import { resolveRoute } from "@checkstack/common";
48
+ import { resolveRoute, extractErrorMessage } from "@checkstack/common";
49
49
  import {
50
50
  IntegrationApi,
51
51
  integrationRoutes,
52
- type IntegrationProviderInfo,
53
52
  type ProviderConnectionRedacted,
54
53
  } from "@checkstack/integration-common";
55
54
 
@@ -95,9 +94,7 @@ export const ProviderConnectionsPage = () => {
95
94
  );
96
95
 
97
96
  const loading = providersLoading || connectionsLoading;
98
- const provider = (providers as IntegrationProviderInfo[]).find(
99
- (p) => p.qualifiedId === providerId,
100
- );
97
+ const provider = providers.find((p) => p.qualifiedId === providerId);
101
98
 
102
99
  // Mutations
103
100
  const createMutation = client.createConnection.useMutation({
@@ -110,9 +107,7 @@ export const ProviderConnectionsPage = () => {
110
107
  setSaving(false);
111
108
  },
112
109
  onError: (error) => {
113
- toast.error(
114
- error instanceof Error ? error.message : "Failed to create connection",
115
- );
110
+ toast.error(extractErrorMessage(error, "Failed to create connection"));
116
111
  setSaving(false);
117
112
  },
118
113
  });
@@ -126,9 +121,7 @@ export const ProviderConnectionsPage = () => {
126
121
  setSaving(false);
127
122
  },
128
123
  onError: (error) => {
129
- toast.error(
130
- error instanceof Error ? error.message : "Failed to update connection",
131
- );
124
+ toast.error(extractErrorMessage(error, "Failed to update connection"));
132
125
  setSaving(false);
133
126
  },
134
127
  });
@@ -141,9 +134,7 @@ export const ProviderConnectionsPage = () => {
141
134
  toast.success("Connection deleted");
142
135
  },
143
136
  onError: (error) => {
144
- toast.error(
145
- error instanceof Error ? error.message : "Failed to delete connection",
146
- );
137
+ toast.error(extractErrorMessage(error, "Failed to delete connection"));
147
138
  },
148
139
  });
149
140
 
@@ -165,9 +156,7 @@ export const ProviderConnectionsPage = () => {
165
156
  ...prev,
166
157
  [variables.connectionId]: { success: false, message: "Test failed" },
167
158
  }));
168
- toast.error(
169
- error instanceof Error ? error.message : "Connection test failed",
170
- );
159
+ toast.error(extractErrorMessage(error, "Connection test failed"));
171
160
  setTestingId(undefined);
172
161
  },
173
162
  });
@@ -275,11 +264,13 @@ export const ProviderConnectionsPage = () => {
275
264
  </div>
276
265
  }
277
266
  >
278
- {(connections as ProviderConnectionRedacted[]).length === 0 ? (
267
+ {connections.length === 0 ? (
279
268
  <EmptyState
280
269
  icon={
281
270
  <DynamicIcon
282
- name={(provider?.icon ?? "Settings2") as LucideIconName}
271
+ name={
272
+ (provider?.icon as LucideIconName | undefined) ?? "Settings2"
273
+ }
283
274
  className="h-12 w-12"
284
275
  />
285
276
  }
@@ -296,7 +287,9 @@ export const ProviderConnectionsPage = () => {
296
287
  <CardHeader>
297
288
  <CardTitle className="flex items-center gap-2">
298
289
  <DynamicIcon
299
- name={(provider?.icon ?? "Settings2") as LucideIconName}
290
+ name={
291
+ (provider?.icon as LucideIconName | undefined) ?? "Settings2"
292
+ }
300
293
  className="h-5 w-5"
301
294
  />
302
295
  Connections
@@ -313,7 +306,7 @@ export const ProviderConnectionsPage = () => {
313
306
  </TableRow>
314
307
  </TableHeader>
315
308
  <TableBody>
316
- {(connections as ProviderConnectionRedacted[]).map((conn) => {
309
+ {connections.map((conn) => {
317
310
  const testResult = testResults[conn.id];
318
311
  const isTesting = testingId === conn.id;
319
312