@checkstack/auth-common 0.1.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.
- package/CHANGELOG.md +133 -0
- package/package.json +1 -1
- package/src/access.ts +91 -0
- package/src/index.ts +1 -1
- package/src/rpc-contract.ts +282 -268
- package/src/permissions.ts +0 -58
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,138 @@
|
|
|
1
1
|
# @checkstack/auth-common
|
|
2
2
|
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 7a23261: ## TanStack Query Integration
|
|
8
|
+
|
|
9
|
+
Migrated all frontend components to use `usePluginClient` hook with TanStack Query integration, replacing the legacy `forPlugin()` pattern.
|
|
10
|
+
|
|
11
|
+
### New Features
|
|
12
|
+
|
|
13
|
+
- **`usePluginClient` hook**: Provides type-safe access to plugin APIs with `.useQuery()` and `.useMutation()` methods
|
|
14
|
+
- **Automatic request deduplication**: Multiple components requesting the same data share a single network request
|
|
15
|
+
- **Built-in caching**: Configurable stale time and cache duration per query
|
|
16
|
+
- **Loading/error states**: TanStack Query provides `isLoading`, `error`, `isRefetching` states automatically
|
|
17
|
+
- **Background refetching**: Stale data is automatically refreshed when components mount
|
|
18
|
+
|
|
19
|
+
### Contract Changes
|
|
20
|
+
|
|
21
|
+
All RPC contracts now require `operationType: "query"` or `operationType: "mutation"` metadata:
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
const getItems = proc()
|
|
25
|
+
.meta({ operationType: "query", access: [access.read] })
|
|
26
|
+
.output(z.array(itemSchema))
|
|
27
|
+
.query();
|
|
28
|
+
|
|
29
|
+
const createItem = proc()
|
|
30
|
+
.meta({ operationType: "mutation", access: [access.manage] })
|
|
31
|
+
.input(createItemSchema)
|
|
32
|
+
.output(itemSchema)
|
|
33
|
+
.mutation();
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Migration
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
// Before (forPlugin pattern)
|
|
40
|
+
const api = useApi(myPluginApiRef);
|
|
41
|
+
const [items, setItems] = useState<Item[]>([]);
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
api.getItems().then(setItems);
|
|
44
|
+
}, [api]);
|
|
45
|
+
|
|
46
|
+
// After (usePluginClient pattern)
|
|
47
|
+
const client = usePluginClient(MyPluginApi);
|
|
48
|
+
const { data: items, isLoading } = client.getItems.useQuery({});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Bug Fixes
|
|
52
|
+
|
|
53
|
+
- Fixed `rpc.test.ts` test setup for middleware type inference
|
|
54
|
+
- Fixed `SearchDialog` to use `setQuery` instead of deprecated `search` method
|
|
55
|
+
- Fixed null→undefined warnings in notification and queue frontends
|
|
56
|
+
|
|
57
|
+
### Patch Changes
|
|
58
|
+
|
|
59
|
+
- Updated dependencies [7a23261]
|
|
60
|
+
- @checkstack/common@0.3.0
|
|
61
|
+
|
|
62
|
+
## 0.2.0
|
|
63
|
+
|
|
64
|
+
### Minor Changes
|
|
65
|
+
|
|
66
|
+
- 9faec1f: # Unified AccessRule Terminology Refactoring
|
|
67
|
+
|
|
68
|
+
This release completes a comprehensive terminology refactoring from "permission" to "accessRule" across the entire codebase, establishing a consistent and modern access control vocabulary.
|
|
69
|
+
|
|
70
|
+
## Changes
|
|
71
|
+
|
|
72
|
+
### Core Infrastructure (`@checkstack/common`)
|
|
73
|
+
|
|
74
|
+
- Introduced `AccessRule` interface as the primary access control type
|
|
75
|
+
- Added `accessPair()` helper for creating read/manage access rule pairs
|
|
76
|
+
- Added `access()` builder for individual access rules
|
|
77
|
+
- Replaced `Permission` type with `AccessRule` throughout
|
|
78
|
+
|
|
79
|
+
### API Changes
|
|
80
|
+
|
|
81
|
+
- `env.registerPermissions()` → `env.registerAccessRules()`
|
|
82
|
+
- `meta.permissions` → `meta.access` in RPC contracts
|
|
83
|
+
- `usePermission()` → `useAccess()` in frontend hooks
|
|
84
|
+
- Route `permission:` field → `accessRule:` field
|
|
85
|
+
|
|
86
|
+
### UI Changes
|
|
87
|
+
|
|
88
|
+
- "Roles & Permissions" tab → "Roles & Access Rules"
|
|
89
|
+
- "You don't have permission..." → "You don't have access..."
|
|
90
|
+
- All permission-related UI text updated
|
|
91
|
+
|
|
92
|
+
### Documentation & Templates
|
|
93
|
+
|
|
94
|
+
- Updated 18 documentation files with AccessRule terminology
|
|
95
|
+
- Updated 7 scaffolding templates with `accessPair()` pattern
|
|
96
|
+
- All code examples use new AccessRule API
|
|
97
|
+
|
|
98
|
+
## Migration Guide
|
|
99
|
+
|
|
100
|
+
### Backend Plugins
|
|
101
|
+
|
|
102
|
+
```diff
|
|
103
|
+
- import { permissionList } from "./permissions";
|
|
104
|
+
- env.registerPermissions(permissionList);
|
|
105
|
+
+ import { accessRules } from "./access";
|
|
106
|
+
+ env.registerAccessRules(accessRules);
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### RPC Contracts
|
|
110
|
+
|
|
111
|
+
```diff
|
|
112
|
+
- .meta({ userType: "user", permissions: [permissions.read.id] })
|
|
113
|
+
+ .meta({ userType: "user", access: [access.read] })
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Frontend Hooks
|
|
117
|
+
|
|
118
|
+
```diff
|
|
119
|
+
- const canRead = accessApi.usePermission(permissions.read.id);
|
|
120
|
+
+ const canRead = accessApi.useAccess(access.read);
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Routes
|
|
124
|
+
|
|
125
|
+
```diff
|
|
126
|
+
- permission: permissions.entityRead.id,
|
|
127
|
+
+ accessRule: access.read,
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Patch Changes
|
|
131
|
+
|
|
132
|
+
- Updated dependencies [9faec1f]
|
|
133
|
+
- Updated dependencies [f533141]
|
|
134
|
+
- @checkstack/common@0.2.0
|
|
135
|
+
|
|
3
136
|
## 0.1.0
|
|
4
137
|
|
|
5
138
|
### Minor Changes
|
package/package.json
CHANGED
package/src/access.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { access, accessPair, type AccessRule } from "@checkstack/common";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Access rules for the Auth plugin.
|
|
5
|
+
*
|
|
6
|
+
* Auth has fine-grained access rules for different operations
|
|
7
|
+
* on users, roles, teams, strategies, etc.
|
|
8
|
+
*/
|
|
9
|
+
export const authAccess = {
|
|
10
|
+
/**
|
|
11
|
+
* User management access rules.
|
|
12
|
+
*/
|
|
13
|
+
users: {
|
|
14
|
+
read: access("users", "read", "List all users"),
|
|
15
|
+
create: access(
|
|
16
|
+
"users.create",
|
|
17
|
+
"manage",
|
|
18
|
+
"Create new users (credential strategy)"
|
|
19
|
+
),
|
|
20
|
+
manage: access("users", "manage", "Delete users"),
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Role management access rules.
|
|
25
|
+
*/
|
|
26
|
+
roles: {
|
|
27
|
+
read: access("roles", "read", "Read and list roles"),
|
|
28
|
+
create: access("roles.create", "manage", "Create new roles"),
|
|
29
|
+
update: access(
|
|
30
|
+
"roles.update",
|
|
31
|
+
"manage",
|
|
32
|
+
"Update role names and access rules"
|
|
33
|
+
),
|
|
34
|
+
delete: access("roles.delete", "manage", "Delete roles"),
|
|
35
|
+
manage: access("roles", "manage", "Assign roles to users"),
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Authentication strategy management.
|
|
40
|
+
*/
|
|
41
|
+
strategies: access(
|
|
42
|
+
"strategies",
|
|
43
|
+
"manage",
|
|
44
|
+
"Manage authentication strategies and settings"
|
|
45
|
+
),
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Registration settings management.
|
|
49
|
+
*/
|
|
50
|
+
registration: access(
|
|
51
|
+
"registration",
|
|
52
|
+
"manage",
|
|
53
|
+
"Manage user registration settings"
|
|
54
|
+
),
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* External application management.
|
|
58
|
+
*/
|
|
59
|
+
applications: access(
|
|
60
|
+
"applications",
|
|
61
|
+
"manage",
|
|
62
|
+
"Create, update, delete, and view external applications"
|
|
63
|
+
),
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Team management access rules.
|
|
67
|
+
*/
|
|
68
|
+
teams: accessPair("teams", {
|
|
69
|
+
read: "View teams and team memberships",
|
|
70
|
+
manage: "Create, delete, and manage all teams and resource access",
|
|
71
|
+
}),
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* All access rules for registration with the plugin system.
|
|
76
|
+
*/
|
|
77
|
+
export const authAccessRules: AccessRule[] = [
|
|
78
|
+
authAccess.users.read,
|
|
79
|
+
authAccess.users.create,
|
|
80
|
+
authAccess.users.manage,
|
|
81
|
+
authAccess.roles.read,
|
|
82
|
+
authAccess.roles.create,
|
|
83
|
+
authAccess.roles.update,
|
|
84
|
+
authAccess.roles.delete,
|
|
85
|
+
authAccess.roles.manage,
|
|
86
|
+
authAccess.strategies,
|
|
87
|
+
authAccess.registration,
|
|
88
|
+
authAccess.applications,
|
|
89
|
+
authAccess.teams.read,
|
|
90
|
+
authAccess.teams.manage,
|
|
91
|
+
];
|
package/src/index.ts
CHANGED
package/src/rpc-contract.ts
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
import { oc } from "@orpc/contract";
|
|
2
1
|
import {
|
|
3
2
|
createClientDefinition,
|
|
4
|
-
|
|
3
|
+
proc,
|
|
5
4
|
lucideIconSchema,
|
|
6
5
|
} from "@checkstack/common";
|
|
7
6
|
import { z } from "zod";
|
|
8
|
-
import {
|
|
7
|
+
import { authAccess } from "./access";
|
|
9
8
|
import { pluginMetadata } from "./plugin-metadata";
|
|
10
9
|
|
|
11
|
-
// Base builder with full metadata support
|
|
12
|
-
const _base = oc.$meta<ProcedureMetadata>({});
|
|
13
|
-
|
|
14
10
|
// Zod schemas for return types
|
|
15
11
|
const UserDtoSchema = z.object({
|
|
16
12
|
id: z.string(),
|
|
@@ -23,12 +19,12 @@ const RoleDtoSchema = z.object({
|
|
|
23
19
|
id: z.string(),
|
|
24
20
|
name: z.string(),
|
|
25
21
|
description: z.string().optional().nullable(),
|
|
26
|
-
|
|
22
|
+
accessRules: z.array(z.string()),
|
|
27
23
|
isSystem: z.boolean().optional(),
|
|
28
|
-
isAssignable: z.boolean().optional(),
|
|
24
|
+
isAssignable: z.boolean().optional(),
|
|
29
25
|
});
|
|
30
26
|
|
|
31
|
-
const
|
|
27
|
+
const AccessRuleDtoSchema = z.object({
|
|
32
28
|
id: z.string(),
|
|
33
29
|
description: z.string().optional(),
|
|
34
30
|
});
|
|
@@ -40,9 +36,9 @@ const StrategyDtoSchema = z.object({
|
|
|
40
36
|
icon: lucideIconSchema.optional(),
|
|
41
37
|
enabled: z.boolean(),
|
|
42
38
|
configVersion: z.number(),
|
|
43
|
-
configSchema: z.record(z.string(), z.unknown()),
|
|
44
|
-
config: z.record(z.string(), z.unknown()).optional(),
|
|
45
|
-
adminInstructions: z.string().optional(),
|
|
39
|
+
configSchema: z.record(z.string(), z.unknown()),
|
|
40
|
+
config: z.record(z.string(), z.unknown()).optional(),
|
|
41
|
+
adminInstructions: z.string().optional(),
|
|
46
42
|
});
|
|
47
43
|
|
|
48
44
|
const EnabledStrategyDtoSchema = z.object({
|
|
@@ -58,32 +54,25 @@ const RegistrationStatusSchema = z.object({
|
|
|
58
54
|
allowRegistration: z.boolean(),
|
|
59
55
|
});
|
|
60
56
|
|
|
61
|
-
//
|
|
62
|
-
// SERVICE-TO-SERVICE SCHEMAS (for auth provider plugins like LDAP)
|
|
63
|
-
// ==========================================================================
|
|
64
|
-
|
|
57
|
+
// Service-to-service schemas
|
|
65
58
|
const FindUserByEmailInputSchema = z.object({
|
|
66
59
|
email: z.string().email(),
|
|
67
60
|
});
|
|
68
61
|
|
|
69
|
-
const FindUserByEmailOutputSchema = z
|
|
70
|
-
.object({
|
|
71
|
-
id: z.string(),
|
|
72
|
-
})
|
|
73
|
-
.optional();
|
|
62
|
+
const FindUserByEmailOutputSchema = z.object({ id: z.string() }).optional();
|
|
74
63
|
|
|
75
64
|
const UpsertExternalUserInputSchema = z.object({
|
|
76
65
|
email: z.string().email(),
|
|
77
66
|
name: z.string(),
|
|
78
|
-
providerId: z.string(),
|
|
79
|
-
accountId: z.string(),
|
|
80
|
-
password: z.string(),
|
|
81
|
-
autoUpdateUser: z.boolean().optional(),
|
|
67
|
+
providerId: z.string(),
|
|
68
|
+
accountId: z.string(),
|
|
69
|
+
password: z.string(),
|
|
70
|
+
autoUpdateUser: z.boolean().optional(),
|
|
82
71
|
});
|
|
83
72
|
|
|
84
73
|
const UpsertExternalUserOutputSchema = z.object({
|
|
85
74
|
userId: z.string(),
|
|
86
|
-
created: z.boolean(),
|
|
75
|
+
created: z.boolean(),
|
|
87
76
|
});
|
|
88
77
|
|
|
89
78
|
const CreateSessionInputSchema = z.object({
|
|
@@ -95,7 +84,7 @@ const CreateSessionInputSchema = z.object({
|
|
|
95
84
|
const CreateCredentialUserInputSchema = z.object({
|
|
96
85
|
email: z.string().email(),
|
|
97
86
|
name: z.string().min(1),
|
|
98
|
-
password: z.string(),
|
|
87
|
+
password: z.string(),
|
|
99
88
|
});
|
|
100
89
|
|
|
101
90
|
const CreateCredentialUserOutputSchema = z.object({
|
|
@@ -106,103 +95,132 @@ const CreateCredentialUserOutputSchema = z.object({
|
|
|
106
95
|
export const authContract = {
|
|
107
96
|
// ==========================================================================
|
|
108
97
|
// ANONYMOUS ENDPOINTS (userType: "anonymous")
|
|
109
|
-
// These can be called without authentication (login/registration pages)
|
|
110
98
|
// ==========================================================================
|
|
111
99
|
|
|
112
|
-
getEnabledStrategies:
|
|
113
|
-
|
|
114
|
-
|
|
100
|
+
getEnabledStrategies: proc({
|
|
101
|
+
operationType: "query",
|
|
102
|
+
userType: "anonymous",
|
|
103
|
+
access: [],
|
|
104
|
+
}).output(z.array(EnabledStrategyDtoSchema)),
|
|
115
105
|
|
|
116
|
-
getRegistrationStatus:
|
|
117
|
-
|
|
118
|
-
|
|
106
|
+
getRegistrationStatus: proc({
|
|
107
|
+
operationType: "query",
|
|
108
|
+
userType: "anonymous",
|
|
109
|
+
access: [],
|
|
110
|
+
}).output(RegistrationStatusSchema),
|
|
119
111
|
|
|
120
112
|
// ==========================================================================
|
|
121
|
-
// AUTHENTICATED ENDPOINTS (userType: "authenticated"
|
|
113
|
+
// AUTHENTICATED ENDPOINTS (userType: "authenticated")
|
|
122
114
|
// ==========================================================================
|
|
123
115
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
116
|
+
accessRules: proc({
|
|
117
|
+
operationType: "query",
|
|
118
|
+
userType: "authenticated",
|
|
119
|
+
access: [],
|
|
120
|
+
}).output(z.object({ accessRules: z.array(z.string()) })),
|
|
127
121
|
|
|
128
122
|
// ==========================================================================
|
|
129
|
-
// USER MANAGEMENT (userType: "user" with
|
|
123
|
+
// USER MANAGEMENT (userType: "user" with access)
|
|
130
124
|
// ==========================================================================
|
|
131
125
|
|
|
132
|
-
getUsers:
|
|
133
|
-
|
|
134
|
-
|
|
126
|
+
getUsers: proc({
|
|
127
|
+
operationType: "query",
|
|
128
|
+
userType: "user",
|
|
129
|
+
access: [authAccess.users.read],
|
|
130
|
+
}).output(z.array(UserDtoSchema)),
|
|
135
131
|
|
|
136
|
-
deleteUser:
|
|
137
|
-
|
|
132
|
+
deleteUser: proc({
|
|
133
|
+
operationType: "mutation",
|
|
134
|
+
userType: "user",
|
|
135
|
+
access: [authAccess.users.manage],
|
|
136
|
+
})
|
|
138
137
|
.input(z.string())
|
|
139
138
|
.output(z.void()),
|
|
140
139
|
|
|
141
|
-
createCredentialUser:
|
|
142
|
-
|
|
140
|
+
createCredentialUser: proc({
|
|
141
|
+
operationType: "mutation",
|
|
142
|
+
userType: "user",
|
|
143
|
+
access: [authAccess.users.create],
|
|
144
|
+
})
|
|
143
145
|
.input(CreateCredentialUserInputSchema)
|
|
144
146
|
.output(CreateCredentialUserOutputSchema),
|
|
145
147
|
|
|
146
|
-
updateUserRoles:
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
})
|
|
153
|
-
)
|
|
148
|
+
updateUserRoles: proc({
|
|
149
|
+
operationType: "mutation",
|
|
150
|
+
userType: "user",
|
|
151
|
+
access: [authAccess.users.manage],
|
|
152
|
+
})
|
|
153
|
+
.input(z.object({ userId: z.string(), roles: z.array(z.string()) }))
|
|
154
154
|
.output(z.void()),
|
|
155
155
|
|
|
156
156
|
// ==========================================================================
|
|
157
|
-
// ROLE MANAGEMENT (userType: "user" with
|
|
157
|
+
// ROLE MANAGEMENT (userType: "user" with access)
|
|
158
158
|
// ==========================================================================
|
|
159
159
|
|
|
160
|
-
getRoles:
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
160
|
+
getRoles: proc({
|
|
161
|
+
operationType: "query",
|
|
162
|
+
userType: "user",
|
|
163
|
+
access: [authAccess.roles.read],
|
|
164
|
+
}).output(z.array(RoleDtoSchema)),
|
|
165
|
+
|
|
166
|
+
getAccessRules: proc({
|
|
167
|
+
operationType: "query",
|
|
168
|
+
userType: "user",
|
|
169
|
+
access: [authAccess.roles.read],
|
|
170
|
+
}).output(z.array(AccessRuleDtoSchema)),
|
|
171
|
+
|
|
172
|
+
createRole: proc({
|
|
173
|
+
operationType: "mutation",
|
|
174
|
+
userType: "user",
|
|
175
|
+
access: [authAccess.roles.create],
|
|
176
|
+
})
|
|
170
177
|
.input(
|
|
171
178
|
z.object({
|
|
172
179
|
name: z.string(),
|
|
173
180
|
description: z.string().optional(),
|
|
174
|
-
|
|
181
|
+
accessRules: z.array(z.string()),
|
|
175
182
|
})
|
|
176
183
|
)
|
|
177
184
|
.output(z.void()),
|
|
178
185
|
|
|
179
|
-
updateRole:
|
|
180
|
-
|
|
186
|
+
updateRole: proc({
|
|
187
|
+
operationType: "mutation",
|
|
188
|
+
userType: "user",
|
|
189
|
+
access: [authAccess.roles.update],
|
|
190
|
+
})
|
|
181
191
|
.input(
|
|
182
192
|
z.object({
|
|
183
193
|
id: z.string(),
|
|
184
194
|
name: z.string().optional(),
|
|
185
195
|
description: z.string().optional(),
|
|
186
|
-
|
|
196
|
+
accessRules: z.array(z.string()),
|
|
187
197
|
})
|
|
188
198
|
)
|
|
189
199
|
.output(z.void()),
|
|
190
200
|
|
|
191
|
-
deleteRole:
|
|
192
|
-
|
|
201
|
+
deleteRole: proc({
|
|
202
|
+
operationType: "mutation",
|
|
203
|
+
userType: "user",
|
|
204
|
+
access: [authAccess.roles.delete],
|
|
205
|
+
})
|
|
193
206
|
.input(z.string())
|
|
194
207
|
.output(z.void()),
|
|
195
208
|
|
|
196
209
|
// ==========================================================================
|
|
197
|
-
// STRATEGY MANAGEMENT (userType: "user" with
|
|
210
|
+
// STRATEGY MANAGEMENT (userType: "user" with access)
|
|
198
211
|
// ==========================================================================
|
|
199
212
|
|
|
200
|
-
getStrategies:
|
|
201
|
-
|
|
202
|
-
|
|
213
|
+
getStrategies: proc({
|
|
214
|
+
operationType: "query",
|
|
215
|
+
userType: "user",
|
|
216
|
+
access: [authAccess.strategies],
|
|
217
|
+
}).output(z.array(StrategyDtoSchema)),
|
|
203
218
|
|
|
204
|
-
updateStrategy:
|
|
205
|
-
|
|
219
|
+
updateStrategy: proc({
|
|
220
|
+
operationType: "mutation",
|
|
221
|
+
userType: "user",
|
|
222
|
+
access: [authAccess.strategies],
|
|
223
|
+
})
|
|
206
224
|
.input(
|
|
207
225
|
z.object({
|
|
208
226
|
id: z.string(),
|
|
@@ -212,26 +230,27 @@ export const authContract = {
|
|
|
212
230
|
)
|
|
213
231
|
.output(z.object({ success: z.boolean() })),
|
|
214
232
|
|
|
215
|
-
reloadAuth:
|
|
216
|
-
|
|
217
|
-
|
|
233
|
+
reloadAuth: proc({
|
|
234
|
+
operationType: "mutation",
|
|
235
|
+
userType: "user",
|
|
236
|
+
access: [authAccess.strategies],
|
|
237
|
+
}).output(z.object({ success: z.boolean() })),
|
|
218
238
|
|
|
219
239
|
// ==========================================================================
|
|
220
|
-
// REGISTRATION MANAGEMENT (userType: "user" with
|
|
240
|
+
// REGISTRATION MANAGEMENT (userType: "user" with access)
|
|
221
241
|
// ==========================================================================
|
|
222
242
|
|
|
223
|
-
getRegistrationSchema:
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
})
|
|
243
|
+
getRegistrationSchema: proc({
|
|
244
|
+
operationType: "query",
|
|
245
|
+
userType: "user",
|
|
246
|
+
access: [authAccess.registration],
|
|
247
|
+
}).output(z.record(z.string(), z.unknown())),
|
|
248
|
+
|
|
249
|
+
setRegistrationStatus: proc({
|
|
250
|
+
operationType: "mutation",
|
|
251
|
+
userType: "user",
|
|
252
|
+
access: [authAccess.registration],
|
|
253
|
+
})
|
|
235
254
|
.input(RegistrationStatusSchema)
|
|
236
255
|
.output(z.object({ success: z.boolean() })),
|
|
237
256
|
|
|
@@ -239,48 +258,41 @@ export const authContract = {
|
|
|
239
258
|
// INTERNAL SERVICE ENDPOINTS (userType: "service")
|
|
240
259
|
// ==========================================================================
|
|
241
260
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
.meta({ userType: "service" })
|
|
248
|
-
.output(z.array(z.string())),
|
|
261
|
+
getAnonymousAccessRules: proc({
|
|
262
|
+
operationType: "query",
|
|
263
|
+
userType: "service",
|
|
264
|
+
access: [],
|
|
265
|
+
}).output(z.array(z.string())),
|
|
249
266
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
.meta({ userType: "service" })
|
|
267
|
+
findUserByEmail: proc({
|
|
268
|
+
operationType: "query",
|
|
269
|
+
userType: "service",
|
|
270
|
+
access: [],
|
|
271
|
+
})
|
|
256
272
|
.input(FindUserByEmailInputSchema)
|
|
257
273
|
.output(FindUserByEmailOutputSchema),
|
|
258
274
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
upsertExternalUser: _base
|
|
265
|
-
.meta({ userType: "service" })
|
|
275
|
+
upsertExternalUser: proc({
|
|
276
|
+
operationType: "mutation",
|
|
277
|
+
userType: "service",
|
|
278
|
+
access: [],
|
|
279
|
+
})
|
|
266
280
|
.input(UpsertExternalUserInputSchema)
|
|
267
281
|
.output(UpsertExternalUserOutputSchema),
|
|
268
282
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
.meta({ userType: "service" })
|
|
283
|
+
createSession: proc({
|
|
284
|
+
operationType: "mutation",
|
|
285
|
+
userType: "service",
|
|
286
|
+
access: [],
|
|
287
|
+
})
|
|
275
288
|
.input(CreateSessionInputSchema)
|
|
276
289
|
.output(z.object({ sessionId: z.string() })),
|
|
277
290
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
.meta({ userType: "service" })
|
|
291
|
+
getUserById: proc({
|
|
292
|
+
operationType: "query",
|
|
293
|
+
userType: "service",
|
|
294
|
+
access: [],
|
|
295
|
+
})
|
|
284
296
|
.input(z.object({ userId: z.string() }))
|
|
285
297
|
.output(
|
|
286
298
|
z
|
|
@@ -292,49 +304,46 @@ export const authContract = {
|
|
|
292
304
|
.optional()
|
|
293
305
|
),
|
|
294
306
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
.meta({ userType: "service" })
|
|
307
|
+
filterUsersByAccessRule: proc({
|
|
308
|
+
operationType: "query",
|
|
309
|
+
userType: "service",
|
|
310
|
+
access: [],
|
|
311
|
+
})
|
|
301
312
|
.input(
|
|
302
313
|
z.object({
|
|
303
314
|
userIds: z.array(z.string()),
|
|
304
|
-
|
|
315
|
+
accessRule: z.string(),
|
|
305
316
|
})
|
|
306
317
|
)
|
|
307
|
-
.output(z.array(z.string())),
|
|
318
|
+
.output(z.array(z.string())),
|
|
308
319
|
|
|
309
320
|
// ==========================================================================
|
|
310
|
-
// APPLICATION MANAGEMENT (userType: "user" with
|
|
311
|
-
// External API applications (API keys) with RBAC integration
|
|
321
|
+
// APPLICATION MANAGEMENT (userType: "user" with access)
|
|
312
322
|
// ==========================================================================
|
|
313
323
|
|
|
314
|
-
getApplications:
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
.
|
|
320
|
-
z.
|
|
321
|
-
z.
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
),
|
|
324
|
+
getApplications: proc({
|
|
325
|
+
operationType: "query",
|
|
326
|
+
userType: "user",
|
|
327
|
+
access: [authAccess.applications],
|
|
328
|
+
}).output(
|
|
329
|
+
z.array(
|
|
330
|
+
z.object({
|
|
331
|
+
id: z.string(),
|
|
332
|
+
name: z.string(),
|
|
333
|
+
description: z.string().optional().nullable(),
|
|
334
|
+
roles: z.array(z.string()),
|
|
335
|
+
createdById: z.string(),
|
|
336
|
+
createdAt: z.coerce.date(),
|
|
337
|
+
lastUsedAt: z.coerce.date().optional().nullable(),
|
|
338
|
+
})
|
|
339
|
+
)
|
|
340
|
+
),
|
|
332
341
|
|
|
333
|
-
createApplication:
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
342
|
+
createApplication: proc({
|
|
343
|
+
operationType: "mutation",
|
|
344
|
+
userType: "user",
|
|
345
|
+
access: [authAccess.applications],
|
|
346
|
+
})
|
|
338
347
|
.input(
|
|
339
348
|
z.object({
|
|
340
349
|
name: z.string().min(1).max(100),
|
|
@@ -351,15 +360,15 @@ export const authContract = {
|
|
|
351
360
|
createdById: z.string(),
|
|
352
361
|
createdAt: z.coerce.date(),
|
|
353
362
|
}),
|
|
354
|
-
secret: z.string(),
|
|
363
|
+
secret: z.string(),
|
|
355
364
|
})
|
|
356
365
|
),
|
|
357
366
|
|
|
358
|
-
updateApplication:
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
367
|
+
updateApplication: proc({
|
|
368
|
+
operationType: "mutation",
|
|
369
|
+
userType: "user",
|
|
370
|
+
access: [authAccess.applications],
|
|
371
|
+
})
|
|
363
372
|
.input(
|
|
364
373
|
z.object({
|
|
365
374
|
id: z.string(),
|
|
@@ -370,50 +379,47 @@ export const authContract = {
|
|
|
370
379
|
)
|
|
371
380
|
.output(z.void()),
|
|
372
381
|
|
|
373
|
-
deleteApplication:
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
382
|
+
deleteApplication: proc({
|
|
383
|
+
operationType: "mutation",
|
|
384
|
+
userType: "user",
|
|
385
|
+
access: [authAccess.applications],
|
|
386
|
+
})
|
|
378
387
|
.input(z.string())
|
|
379
388
|
.output(z.void()),
|
|
380
389
|
|
|
381
|
-
regenerateApplicationSecret:
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
390
|
+
regenerateApplicationSecret: proc({
|
|
391
|
+
operationType: "mutation",
|
|
392
|
+
userType: "user",
|
|
393
|
+
access: [authAccess.applications],
|
|
394
|
+
})
|
|
386
395
|
.input(z.string())
|
|
387
|
-
.output(z.object({ secret: z.string() })),
|
|
396
|
+
.output(z.object({ secret: z.string() })),
|
|
388
397
|
|
|
389
398
|
// ==========================================================================
|
|
390
|
-
// TEAM MANAGEMENT (userType: "authenticated" with
|
|
391
|
-
// Resource-level access control via teams
|
|
392
|
-
// Both users and applications can manage teams with proper permissions
|
|
399
|
+
// TEAM MANAGEMENT (userType: "authenticated" with access)
|
|
393
400
|
// ==========================================================================
|
|
394
401
|
|
|
395
|
-
getTeams:
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
.
|
|
401
|
-
z.
|
|
402
|
-
z.
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
),
|
|
402
|
+
getTeams: proc({
|
|
403
|
+
operationType: "query",
|
|
404
|
+
userType: "authenticated",
|
|
405
|
+
access: [authAccess.teams.read],
|
|
406
|
+
}).output(
|
|
407
|
+
z.array(
|
|
408
|
+
z.object({
|
|
409
|
+
id: z.string(),
|
|
410
|
+
name: z.string(),
|
|
411
|
+
description: z.string().optional().nullable(),
|
|
412
|
+
memberCount: z.number(),
|
|
413
|
+
isManager: z.boolean(),
|
|
414
|
+
})
|
|
415
|
+
)
|
|
416
|
+
),
|
|
411
417
|
|
|
412
|
-
getTeam:
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
418
|
+
getTeam: proc({
|
|
419
|
+
operationType: "query",
|
|
420
|
+
userType: "authenticated",
|
|
421
|
+
access: [authAccess.teams.read],
|
|
422
|
+
})
|
|
417
423
|
.input(z.object({ teamId: z.string() }))
|
|
418
424
|
.output(
|
|
419
425
|
z
|
|
@@ -431,11 +437,11 @@ export const authContract = {
|
|
|
431
437
|
.optional()
|
|
432
438
|
),
|
|
433
439
|
|
|
434
|
-
createTeam:
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
440
|
+
createTeam: proc({
|
|
441
|
+
operationType: "mutation",
|
|
442
|
+
userType: "authenticated",
|
|
443
|
+
access: [authAccess.teams.manage],
|
|
444
|
+
})
|
|
439
445
|
.input(
|
|
440
446
|
z.object({
|
|
441
447
|
name: z.string().min(1).max(100),
|
|
@@ -444,11 +450,11 @@ export const authContract = {
|
|
|
444
450
|
)
|
|
445
451
|
.output(z.object({ id: z.string() })),
|
|
446
452
|
|
|
447
|
-
updateTeam:
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
453
|
+
updateTeam: proc({
|
|
454
|
+
operationType: "mutation",
|
|
455
|
+
userType: "authenticated",
|
|
456
|
+
access: [authAccess.teams.read],
|
|
457
|
+
})
|
|
452
458
|
.input(
|
|
453
459
|
z.object({
|
|
454
460
|
id: z.string(),
|
|
@@ -458,51 +464,51 @@ export const authContract = {
|
|
|
458
464
|
)
|
|
459
465
|
.output(z.void()),
|
|
460
466
|
|
|
461
|
-
deleteTeam:
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
467
|
+
deleteTeam: proc({
|
|
468
|
+
operationType: "mutation",
|
|
469
|
+
userType: "authenticated",
|
|
470
|
+
access: [authAccess.teams.manage],
|
|
471
|
+
})
|
|
466
472
|
.input(z.string())
|
|
467
473
|
.output(z.void()),
|
|
468
474
|
|
|
469
|
-
addUserToTeam:
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
475
|
+
addUserToTeam: proc({
|
|
476
|
+
operationType: "mutation",
|
|
477
|
+
userType: "authenticated",
|
|
478
|
+
access: [authAccess.teams.read],
|
|
479
|
+
})
|
|
474
480
|
.input(z.object({ teamId: z.string(), userId: z.string() }))
|
|
475
481
|
.output(z.void()),
|
|
476
482
|
|
|
477
|
-
removeUserFromTeam:
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
483
|
+
removeUserFromTeam: proc({
|
|
484
|
+
operationType: "mutation",
|
|
485
|
+
userType: "authenticated",
|
|
486
|
+
access: [authAccess.teams.read],
|
|
487
|
+
})
|
|
482
488
|
.input(z.object({ teamId: z.string(), userId: z.string() }))
|
|
483
489
|
.output(z.void()),
|
|
484
490
|
|
|
485
|
-
addTeamManager:
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
491
|
+
addTeamManager: proc({
|
|
492
|
+
operationType: "mutation",
|
|
493
|
+
userType: "authenticated",
|
|
494
|
+
access: [authAccess.teams.manage],
|
|
495
|
+
})
|
|
490
496
|
.input(z.object({ teamId: z.string(), userId: z.string() }))
|
|
491
497
|
.output(z.void()),
|
|
492
498
|
|
|
493
|
-
removeTeamManager:
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
499
|
+
removeTeamManager: proc({
|
|
500
|
+
operationType: "mutation",
|
|
501
|
+
userType: "authenticated",
|
|
502
|
+
access: [authAccess.teams.manage],
|
|
503
|
+
})
|
|
498
504
|
.input(z.object({ teamId: z.string(), userId: z.string() }))
|
|
499
505
|
.output(z.void()),
|
|
500
506
|
|
|
501
|
-
getResourceTeamAccess:
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
507
|
+
getResourceTeamAccess: proc({
|
|
508
|
+
operationType: "query",
|
|
509
|
+
userType: "authenticated",
|
|
510
|
+
access: [authAccess.teams.read],
|
|
511
|
+
})
|
|
506
512
|
.input(z.object({ resourceType: z.string(), resourceId: z.string() }))
|
|
507
513
|
.output(
|
|
508
514
|
z.array(
|
|
@@ -515,11 +521,11 @@ export const authContract = {
|
|
|
515
521
|
)
|
|
516
522
|
),
|
|
517
523
|
|
|
518
|
-
setResourceTeamAccess:
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
524
|
+
setResourceTeamAccess: proc({
|
|
525
|
+
operationType: "mutation",
|
|
526
|
+
userType: "authenticated",
|
|
527
|
+
access: [authAccess.teams.manage],
|
|
528
|
+
})
|
|
523
529
|
.input(
|
|
524
530
|
z.object({
|
|
525
531
|
resourceType: z.string(),
|
|
@@ -531,11 +537,11 @@ export const authContract = {
|
|
|
531
537
|
)
|
|
532
538
|
.output(z.void()),
|
|
533
539
|
|
|
534
|
-
removeResourceTeamAccess:
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
540
|
+
removeResourceTeamAccess: proc({
|
|
541
|
+
operationType: "mutation",
|
|
542
|
+
userType: "authenticated",
|
|
543
|
+
access: [authAccess.teams.manage],
|
|
544
|
+
})
|
|
539
545
|
.input(
|
|
540
546
|
z.object({
|
|
541
547
|
resourceType: z.string(),
|
|
@@ -545,20 +551,19 @@ export const authContract = {
|
|
|
545
551
|
)
|
|
546
552
|
.output(z.void()),
|
|
547
553
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
})
|
|
554
|
+
getResourceAccessSettings: proc({
|
|
555
|
+
operationType: "query",
|
|
556
|
+
userType: "authenticated",
|
|
557
|
+
access: [authAccess.teams.read],
|
|
558
|
+
})
|
|
554
559
|
.input(z.object({ resourceType: z.string(), resourceId: z.string() }))
|
|
555
560
|
.output(z.object({ teamOnly: z.boolean() })),
|
|
556
561
|
|
|
557
|
-
setResourceAccessSettings:
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
+
setResourceAccessSettings: proc({
|
|
563
|
+
operationType: "mutation",
|
|
564
|
+
userType: "authenticated",
|
|
565
|
+
access: [authAccess.teams.manage],
|
|
566
|
+
})
|
|
562
567
|
.input(
|
|
563
568
|
z.object({
|
|
564
569
|
resourceType: z.string(),
|
|
@@ -572,8 +577,11 @@ export const authContract = {
|
|
|
572
577
|
// S2S ENDPOINTS FOR TEAM ACCESS (userType: "service")
|
|
573
578
|
// ==========================================================================
|
|
574
579
|
|
|
575
|
-
checkResourceTeamAccess:
|
|
576
|
-
|
|
580
|
+
checkResourceTeamAccess: proc({
|
|
581
|
+
operationType: "query",
|
|
582
|
+
userType: "service",
|
|
583
|
+
access: [],
|
|
584
|
+
})
|
|
577
585
|
.input(
|
|
578
586
|
z.object({
|
|
579
587
|
userId: z.string(),
|
|
@@ -581,13 +589,16 @@ export const authContract = {
|
|
|
581
589
|
resourceType: z.string(),
|
|
582
590
|
resourceId: z.string(),
|
|
583
591
|
action: z.enum(["read", "manage"]),
|
|
584
|
-
|
|
592
|
+
hasGlobalAccess: z.boolean(),
|
|
585
593
|
})
|
|
586
594
|
)
|
|
587
595
|
.output(z.object({ hasAccess: z.boolean() })),
|
|
588
596
|
|
|
589
|
-
getAccessibleResourceIds:
|
|
590
|
-
|
|
597
|
+
getAccessibleResourceIds: proc({
|
|
598
|
+
operationType: "query",
|
|
599
|
+
userType: "service",
|
|
600
|
+
access: [],
|
|
601
|
+
})
|
|
591
602
|
.input(
|
|
592
603
|
z.object({
|
|
593
604
|
userId: z.string(),
|
|
@@ -595,13 +606,16 @@ export const authContract = {
|
|
|
595
606
|
resourceType: z.string(),
|
|
596
607
|
resourceIds: z.array(z.string()),
|
|
597
608
|
action: z.enum(["read", "manage"]),
|
|
598
|
-
|
|
609
|
+
hasGlobalAccess: z.boolean(),
|
|
599
610
|
})
|
|
600
611
|
)
|
|
601
612
|
.output(z.array(z.string())),
|
|
602
613
|
|
|
603
|
-
deleteResourceGrants:
|
|
604
|
-
|
|
614
|
+
deleteResourceGrants: proc({
|
|
615
|
+
operationType: "mutation",
|
|
616
|
+
userType: "service",
|
|
617
|
+
access: [],
|
|
618
|
+
})
|
|
605
619
|
.input(z.object({ resourceType: z.string(), resourceId: z.string() }))
|
|
606
620
|
.output(z.void()),
|
|
607
621
|
};
|
package/src/permissions.ts
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import type { Permission } from "@checkstack/common";
|
|
2
|
-
|
|
3
|
-
export const permissions = {
|
|
4
|
-
usersRead: {
|
|
5
|
-
id: "users.read",
|
|
6
|
-
description: "List all users",
|
|
7
|
-
},
|
|
8
|
-
usersCreate: {
|
|
9
|
-
id: "users.create",
|
|
10
|
-
description: "Create new users (credential strategy)",
|
|
11
|
-
},
|
|
12
|
-
usersManage: {
|
|
13
|
-
id: "users.manage",
|
|
14
|
-
description: "Delete users",
|
|
15
|
-
},
|
|
16
|
-
rolesRead: {
|
|
17
|
-
id: "roles.read",
|
|
18
|
-
description: "Read and list roles",
|
|
19
|
-
},
|
|
20
|
-
rolesCreate: {
|
|
21
|
-
id: "roles.create",
|
|
22
|
-
description: "Create new roles",
|
|
23
|
-
},
|
|
24
|
-
rolesUpdate: {
|
|
25
|
-
id: "roles.update",
|
|
26
|
-
description: "Update role names and permissions",
|
|
27
|
-
},
|
|
28
|
-
rolesDelete: {
|
|
29
|
-
id: "roles.delete",
|
|
30
|
-
description: "Delete roles",
|
|
31
|
-
},
|
|
32
|
-
rolesManage: {
|
|
33
|
-
id: "roles.manage",
|
|
34
|
-
description: "Assign roles to users",
|
|
35
|
-
},
|
|
36
|
-
strategiesManage: {
|
|
37
|
-
id: "strategies.manage",
|
|
38
|
-
description: "Manage authentication strategies and settings",
|
|
39
|
-
},
|
|
40
|
-
registrationManage: {
|
|
41
|
-
id: "registration.manage",
|
|
42
|
-
description: "Manage user registration settings",
|
|
43
|
-
},
|
|
44
|
-
applicationsManage: {
|
|
45
|
-
id: "applications.manage",
|
|
46
|
-
description: "Create, update, delete, and view external applications",
|
|
47
|
-
},
|
|
48
|
-
teamsRead: {
|
|
49
|
-
id: "teams.read",
|
|
50
|
-
description: "View teams and team memberships",
|
|
51
|
-
},
|
|
52
|
-
teamsManage: {
|
|
53
|
-
id: "teams.manage",
|
|
54
|
-
description: "Create, delete, and manage all teams and resource access",
|
|
55
|
-
},
|
|
56
|
-
} satisfies Record<string, Permission>;
|
|
57
|
-
|
|
58
|
-
export const permissionList = Object.values(permissions);
|