@checkstack/auth-frontend 0.2.0 → 0.3.0

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.
@@ -16,8 +16,7 @@ import {
16
16
  useToast,
17
17
  } from "@checkstack/ui";
18
18
  import { Plus, Edit, Trash2 } from "lucide-react";
19
- import { useApi } from "@checkstack/frontend-api";
20
- import { rpcApiRef } from "@checkstack/frontend-api";
19
+ import { usePluginClient } from "@checkstack/frontend-api";
21
20
  import { AuthApi } from "@checkstack/auth-common";
22
21
  import type { Role, AccessRuleEntry } from "../api";
23
22
  import { RoleDialog } from "./RoleDialog";
@@ -43,14 +42,51 @@ export const RolesTab: React.FC<RolesTabProps> = ({
43
42
  canDeleteRoles,
44
43
  onDataChange,
45
44
  }) => {
46
- const rpcApi = useApi(rpcApiRef);
47
- const authClient = rpcApi.forPlugin(AuthApi);
45
+ const authClient = usePluginClient(AuthApi);
48
46
  const toast = useToast();
49
47
 
50
48
  const [roleToDelete, setRoleToDelete] = useState<string>();
51
49
  const [roleDialogOpen, setRoleDialogOpen] = useState(false);
52
50
  const [editingRole, setEditingRole] = useState<Role | undefined>();
53
51
 
52
+ // Mutations
53
+ const createRoleMutation = authClient.createRole.useMutation({
54
+ onSuccess: () => {
55
+ toast.success("Role created successfully");
56
+ void onDataChange();
57
+ },
58
+ onError: (error) => {
59
+ toast.error(
60
+ error instanceof Error ? error.message : "Failed to create role"
61
+ );
62
+ },
63
+ });
64
+
65
+ const updateRoleMutation = authClient.updateRole.useMutation({
66
+ onSuccess: () => {
67
+ toast.success("Role updated successfully");
68
+ void onDataChange();
69
+ },
70
+ onError: (error) => {
71
+ toast.error(
72
+ error instanceof Error ? error.message : "Failed to update role"
73
+ );
74
+ },
75
+ });
76
+
77
+ const deleteRoleMutation = authClient.deleteRole.useMutation({
78
+ onSuccess: () => {
79
+ toast.success("Role deleted successfully");
80
+ setRoleToDelete(undefined);
81
+ void onDataChange();
82
+ },
83
+ onError: (error) => {
84
+ toast.error(
85
+ error instanceof Error ? error.message : "Failed to delete role"
86
+ );
87
+ },
88
+ });
89
+
54
90
  const handleCreateRole = () => {
55
91
  setEditingRole(undefined);
56
92
  setRoleDialogOpen(true);
@@ -67,44 +103,21 @@ export const RolesTab: React.FC<RolesTabProps> = ({
67
103
  description?: string;
68
104
  accessRules: string[];
69
105
  }) => {
70
- try {
71
- if (params.id) {
72
- await authClient.updateRole({
73
- id: params.id,
74
- name: params.name,
75
- description: params.description,
76
- accessRules: params.accessRules,
77
- });
78
- toast.success("Role updated successfully");
79
- } else {
80
- await authClient.createRole({
81
- name: params.name,
82
- description: params.description,
83
- accessRules: params.accessRules,
84
- });
85
- toast.success("Role created successfully");
86
- }
87
- await onDataChange();
88
- } catch (error: unknown) {
89
- toast.error(
90
- error instanceof Error ? error.message : "Failed to save role"
91
- );
92
- throw error;
93
- }
106
+ await (params.id ? updateRoleMutation.mutateAsync({
107
+ id: params.id,
108
+ name: params.name,
109
+ description: params.description,
110
+ accessRules: params.accessRules,
111
+ }) : createRoleMutation.mutateAsync({
112
+ name: params.name,
113
+ description: params.description,
114
+ accessRules: params.accessRules,
115
+ }));
94
116
  };
95
117
 
96
- const handleDeleteRole = async () => {
118
+ const handleDeleteRole = () => {
97
119
  if (!roleToDelete) return;
98
- try {
99
- await authClient.deleteRole(roleToDelete);
100
- toast.success("Role deleted successfully");
101
- setRoleToDelete(undefined);
102
- await onDataChange();
103
- } catch (error: unknown) {
104
- toast.error(
105
- error instanceof Error ? error.message : "Failed to delete role"
106
- );
107
- }
120
+ deleteRoleMutation.mutate(roleToDelete);
108
121
  };
109
122
 
110
123
  return (
@@ -15,8 +15,7 @@ import {
15
15
  useToast,
16
16
  } from "@checkstack/ui";
17
17
  import { Shield, RefreshCw } from "lucide-react";
18
- import { useApi } from "@checkstack/frontend-api";
19
- import { rpcApiRef } from "@checkstack/frontend-api";
18
+ import { usePluginClient } from "@checkstack/frontend-api";
20
19
  import { AuthApi } from "@checkstack/auth-common";
21
20
  import type { AuthStrategy } from "../api";
22
21
  import { AuthStrategyCard } from "./AuthStrategyCard";
@@ -34,8 +33,7 @@ export const StrategiesTab: React.FC<StrategiesTabProps> = ({
34
33
  canManageRegistration,
35
34
  onDataChange,
36
35
  }) => {
37
- const rpcApi = useApi(rpcApiRef);
38
- const authClient = rpcApi.forPlugin(AuthApi);
36
+ const authClient = usePluginClient(AuthApi);
39
37
  const toast = useToast();
40
38
 
41
39
  const [reloading, setReloading] = useState(false);
@@ -45,14 +43,9 @@ export const StrategiesTab: React.FC<StrategiesTabProps> = ({
45
43
  >({});
46
44
 
47
45
  // Registration state
48
- const [registrationSchema, setRegistrationSchema] = useState<
49
- Record<string, unknown> | undefined
50
- >();
51
46
  const [registrationSettings, setRegistrationSettings] = useState<{
52
47
  allowRegistration: boolean;
53
48
  }>({ allowRegistration: true });
54
- const [loadingRegistration, setLoadingRegistration] = useState(true);
55
- const [savingRegistration, setSavingRegistration] = useState(false);
56
49
  const [registrationValid, setRegistrationValid] = useState(true);
57
50
 
58
51
  // Initialize strategy configs when strategies change
@@ -64,104 +57,101 @@ export const StrategiesTab: React.FC<StrategiesTabProps> = ({
64
57
  setStrategyConfigs(configs);
65
58
  }, [strategies]);
66
59
 
67
- // Fetch registration data when we have access
60
+ // Query: Registration schema (admin only)
61
+ const { data: registrationSchema, isLoading: schemaLoading } =
62
+ authClient.getRegistrationSchema.useQuery(
63
+ {},
64
+ { enabled: canManageRegistration }
65
+ );
66
+
67
+ // Query: Registration status (admin only)
68
+ const { data: registrationStatus, isLoading: statusLoading } =
69
+ authClient.getRegistrationStatus.useQuery(
70
+ {},
71
+ { enabled: canManageRegistration }
72
+ );
73
+
74
+ // Sync fetched settings to local state
68
75
  useEffect(() => {
69
- if (!canManageRegistration) {
70
- setLoadingRegistration(false);
71
- return;
76
+ if (registrationStatus) {
77
+ setRegistrationSettings(registrationStatus);
72
78
  }
79
+ }, [registrationStatus]);
73
80
 
74
- const fetchRegistrationData = async () => {
75
- setLoadingRegistration(true);
76
- try {
77
- const [schema, status] = await Promise.all([
78
- authClient.getRegistrationSchema(),
79
- authClient.getRegistrationStatus(),
80
- ]);
81
- setRegistrationSchema(schema);
82
- setRegistrationSettings(status);
83
- } catch (error) {
84
- console.error("Failed to fetch registration data:", error);
85
- } finally {
86
- setLoadingRegistration(false);
87
- }
88
- };
89
- fetchRegistrationData();
90
- }, [canManageRegistration, authClient]);
81
+ const loadingRegistration = schemaLoading || statusLoading;
82
+
83
+ // Mutations
84
+ const updateStrategyMutation = authClient.updateStrategy.useMutation({
85
+ onSuccess: () => {
86
+ toast.success("Strategy updated");
87
+ void onDataChange();
88
+ },
89
+ onError: (error) => {
90
+ toast.error(
91
+ error instanceof Error ? error.message : "Failed to update strategy"
92
+ );
93
+ },
94
+ });
95
+
96
+ const setRegistrationMutation = authClient.setRegistrationStatus.useMutation({
97
+ onSuccess: () => {
98
+ toast.success("Registration settings saved");
99
+ },
100
+ onError: (error) => {
101
+ toast.error(
102
+ error instanceof Error ? error.message : "Failed to save settings"
103
+ );
104
+ },
105
+ });
106
+
107
+ const reloadAuthMutation = authClient.reloadAuth.useMutation({
108
+ onSuccess: () => {
109
+ toast.success("Authentication system reloaded");
110
+ void onDataChange();
111
+ setReloading(false);
112
+ },
113
+ onError: (error) => {
114
+ toast.error(
115
+ error instanceof Error ? error.message : "Failed to reload auth"
116
+ );
117
+ setReloading(false);
118
+ },
119
+ });
91
120
 
92
121
  const handleToggleStrategy = async (strategyId: string, enabled: boolean) => {
93
- try {
94
- await authClient.updateStrategy({ id: strategyId, enabled });
95
- await onDataChange();
96
- } catch (error: unknown) {
97
- const message =
98
- error instanceof Error ? error.message : "Failed to toggle strategy";
99
- toast.error(message);
100
- }
122
+ await updateStrategyMutation.mutateAsync({ id: strategyId, enabled });
101
123
  };
102
124
 
103
125
  const handleSaveStrategyConfig = async (
104
126
  strategyId: string,
105
127
  config: Record<string, unknown>
106
128
  ) => {
107
- try {
108
- const strategy = strategies.find((s) => s.id === strategyId);
109
- if (!strategy) {
110
- toast.error("Strategy not found");
111
- return;
112
- }
113
- setStrategyConfigs({
114
- ...strategyConfigs,
115
- [strategyId]: config,
116
- });
117
- await authClient.updateStrategy({
118
- id: strategyId,
119
- enabled: strategy.enabled,
120
- config,
121
- });
122
- toast.success(
123
- "Configuration saved successfully! Click 'Reload Authentication' to apply changes."
124
- );
125
- } catch (error: unknown) {
126
- const message =
127
- error instanceof Error
128
- ? error.message
129
- : "Failed to save strategy configuration";
130
- toast.error(message);
129
+ const strategy = strategies.find((s) => s.id === strategyId);
130
+ if (!strategy) {
131
+ toast.error("Strategy not found");
132
+ return;
131
133
  }
134
+ setStrategyConfigs({
135
+ ...strategyConfigs,
136
+ [strategyId]: config,
137
+ });
138
+ await updateStrategyMutation.mutateAsync({
139
+ id: strategyId,
140
+ enabled: strategy.enabled,
141
+ config,
142
+ });
143
+ toast.success(
144
+ "Configuration saved successfully! Click 'Reload Authentication' to apply changes."
145
+ );
132
146
  };
133
147
 
134
- const handleSaveRegistration = async () => {
135
- setSavingRegistration(true);
136
- try {
137
- await authClient.setRegistrationStatus(registrationSettings);
138
- toast.success("Registration settings saved successfully");
139
- } catch (error: unknown) {
140
- toast.error(
141
- error instanceof Error
142
- ? error.message
143
- : "Failed to save registration settings"
144
- );
145
- } finally {
146
- setSavingRegistration(false);
147
- }
148
+ const handleSaveRegistration = () => {
149
+ setRegistrationMutation.mutate(registrationSettings);
148
150
  };
149
151
 
150
- const handleReloadAuth = async () => {
152
+ const handleReloadAuth = () => {
151
153
  setReloading(true);
152
- try {
153
- await authClient.reloadAuth();
154
- toast.success("Authentication system reloaded successfully");
155
- await onDataChange();
156
- } catch (error: unknown) {
157
- toast.error(
158
- error instanceof Error
159
- ? error.message
160
- : "Failed to reload authentication"
161
- );
162
- } finally {
163
- setReloading(false);
164
- }
154
+ reloadAuthMutation.mutate({});
165
155
  };
166
156
 
167
157
  const enabledStrategies = strategies.filter((s) => s.enabled);
@@ -183,7 +173,7 @@ export const StrategiesTab: React.FC<StrategiesTabProps> = ({
183
173
  ) : registrationSchema ? (
184
174
  <div className="space-y-4">
185
175
  <DynamicForm
186
- schema={registrationSchema}
176
+ schema={registrationSchema as Record<string, unknown>}
187
177
  value={registrationSettings}
188
178
  onChange={(value) =>
189
179
  setRegistrationSettings(
@@ -193,10 +183,14 @@ export const StrategiesTab: React.FC<StrategiesTabProps> = ({
193
183
  onValidChange={setRegistrationValid}
194
184
  />
195
185
  <Button
196
- onClick={() => void handleSaveRegistration()}
197
- disabled={savingRegistration || !registrationValid}
186
+ onClick={handleSaveRegistration}
187
+ disabled={
188
+ setRegistrationMutation.isPending || !registrationValid
189
+ }
198
190
  >
199
- {savingRegistration ? "Saving..." : "Save Settings"}
191
+ {setRegistrationMutation.isPending
192
+ ? "Saving..."
193
+ : "Save Settings"}
200
194
  </Button>
201
195
  </div>
202
196
  ) : (