@checkstack/integration-common 0.0.4 → 0.2.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 CHANGED
@@ -1,5 +1,140 @@
1
1
  # @checkstack/integration-common
2
2
 
3
+ ## 0.2.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
+ - @checkstack/signal-common@0.1.1
62
+
63
+ ## 0.1.0
64
+
65
+ ### Minor Changes
66
+
67
+ - 9faec1f: # Unified AccessRule Terminology Refactoring
68
+
69
+ This release completes a comprehensive terminology refactoring from "permission" to "accessRule" across the entire codebase, establishing a consistent and modern access control vocabulary.
70
+
71
+ ## Changes
72
+
73
+ ### Core Infrastructure (`@checkstack/common`)
74
+
75
+ - Introduced `AccessRule` interface as the primary access control type
76
+ - Added `accessPair()` helper for creating read/manage access rule pairs
77
+ - Added `access()` builder for individual access rules
78
+ - Replaced `Permission` type with `AccessRule` throughout
79
+
80
+ ### API Changes
81
+
82
+ - `env.registerPermissions()` → `env.registerAccessRules()`
83
+ - `meta.permissions` → `meta.access` in RPC contracts
84
+ - `usePermission()` → `useAccess()` in frontend hooks
85
+ - Route `permission:` field → `accessRule:` field
86
+
87
+ ### UI Changes
88
+
89
+ - "Roles & Permissions" tab → "Roles & Access Rules"
90
+ - "You don't have permission..." → "You don't have access..."
91
+ - All permission-related UI text updated
92
+
93
+ ### Documentation & Templates
94
+
95
+ - Updated 18 documentation files with AccessRule terminology
96
+ - Updated 7 scaffolding templates with `accessPair()` pattern
97
+ - All code examples use new AccessRule API
98
+
99
+ ## Migration Guide
100
+
101
+ ### Backend Plugins
102
+
103
+ ```diff
104
+ - import { permissionList } from "./permissions";
105
+ - env.registerPermissions(permissionList);
106
+ + import { accessRules } from "./access";
107
+ + env.registerAccessRules(accessRules);
108
+ ```
109
+
110
+ ### RPC Contracts
111
+
112
+ ```diff
113
+ - .meta({ userType: "user", permissions: [permissions.read.id] })
114
+ + .meta({ userType: "user", access: [access.read] })
115
+ ```
116
+
117
+ ### Frontend Hooks
118
+
119
+ ```diff
120
+ - const canRead = accessApi.usePermission(permissions.read.id);
121
+ + const canRead = accessApi.useAccess(access.read);
122
+ ```
123
+
124
+ ### Routes
125
+
126
+ ```diff
127
+ - permission: permissions.entityRead.id,
128
+ + accessRule: access.read,
129
+ ```
130
+
131
+ ### Patch Changes
132
+
133
+ - Updated dependencies [9faec1f]
134
+ - Updated dependencies [f533141]
135
+ - @checkstack/common@0.2.0
136
+ - @checkstack/signal-common@0.1.0
137
+
3
138
  ## 0.0.4
4
139
 
5
140
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@checkstack/integration-common",
3
- "version": "0.0.4",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
package/src/access.ts ADDED
@@ -0,0 +1,20 @@
1
+ import { access } from "@checkstack/common";
2
+
3
+ /**
4
+ * Access rules for the Integration plugin.
5
+ */
6
+ export const integrationAccess = {
7
+ /**
8
+ * Manage webhook integrations and view delivery logs.
9
+ */
10
+ manage: access(
11
+ "integration",
12
+ "manage",
13
+ "Manage webhook integrations and view delivery logs"
14
+ ),
15
+ };
16
+
17
+ /**
18
+ * All access rules for registration with the plugin system.
19
+ */
20
+ export const integrationAccessRules = [integrationAccess.manage];
package/src/index.ts CHANGED
@@ -48,8 +48,8 @@ export {
48
48
  // are defined in @checkstack/integration-backend/provider-types.
49
49
  // Frontend code should only use the Zod schemas above for API contracts.
50
50
 
51
- // Permissions
52
- export * from "./permissions";
51
+ // Access rules
52
+ export * from "./access";
53
53
 
54
54
  // RPC Contract
55
55
  export * from "./rpc-contract";
@@ -1,11 +1,7 @@
1
- import { oc } from "@orpc/contract";
2
1
  import { z } from "zod";
3
- import { permissions } from "./permissions";
2
+ import { integrationAccess } from "./access";
4
3
  import { pluginMetadata } from "./plugin-metadata";
5
- import {
6
- createClientDefinition,
7
- type ProcedureMetadata,
8
- } from "@checkstack/common";
4
+ import { createClientDefinition, proc } from "@checkstack/common";
9
5
  import {
10
6
  WebhookSubscriptionSchema,
11
7
  CreateSubscriptionInputSchema,
@@ -23,9 +19,6 @@ import {
23
19
  EventPayloadSchemaOutputSchema,
24
20
  } from "./schemas";
25
21
 
26
- // Base builder with full metadata support (userType + permissions)
27
- const _base = oc.$meta<ProcedureMetadata>({});
28
-
29
22
  // Integration RPC Contract
30
23
  export const integrationContract = {
31
24
  // ==========================================================================
@@ -33,11 +26,11 @@ export const integrationContract = {
33
26
  // ==========================================================================
34
27
 
35
28
  /** List all webhook subscriptions */
36
- listSubscriptions: _base
37
- .meta({
38
- userType: "authenticated",
39
- permissions: [permissions.integrationManage.id],
40
- })
29
+ listSubscriptions: proc({
30
+ operationType: "query",
31
+ userType: "authenticated",
32
+ access: [integrationAccess.manage],
33
+ })
41
34
  .input(
42
35
  z.object({
43
36
  page: z.number().min(1).default(1),
@@ -55,47 +48,47 @@ export const integrationContract = {
55
48
  ),
56
49
 
57
50
  /** Get a single subscription by ID */
58
- getSubscription: _base
59
- .meta({
60
- userType: "authenticated",
61
- permissions: [permissions.integrationManage.id],
62
- })
51
+ getSubscription: proc({
52
+ operationType: "query",
53
+ userType: "authenticated",
54
+ access: [integrationAccess.manage],
55
+ })
63
56
  .input(z.object({ id: z.string() }))
64
57
  .output(WebhookSubscriptionSchema),
65
58
 
66
59
  /** Create a new webhook subscription */
67
- createSubscription: _base
68
- .meta({
69
- userType: "authenticated",
70
- permissions: [permissions.integrationManage.id],
71
- })
60
+ createSubscription: proc({
61
+ operationType: "mutation",
62
+ userType: "authenticated",
63
+ access: [integrationAccess.manage],
64
+ })
72
65
  .input(CreateSubscriptionInputSchema)
73
66
  .output(WebhookSubscriptionSchema),
74
67
 
75
68
  /** Update an existing subscription */
76
- updateSubscription: _base
77
- .meta({
78
- userType: "authenticated",
79
- permissions: [permissions.integrationManage.id],
80
- })
69
+ updateSubscription: proc({
70
+ operationType: "mutation",
71
+ userType: "authenticated",
72
+ access: [integrationAccess.manage],
73
+ })
81
74
  .input(UpdateSubscriptionInputSchema)
82
75
  .output(WebhookSubscriptionSchema),
83
76
 
84
77
  /** Delete a subscription */
85
- deleteSubscription: _base
86
- .meta({
87
- userType: "authenticated",
88
- permissions: [permissions.integrationManage.id],
89
- })
78
+ deleteSubscription: proc({
79
+ operationType: "mutation",
80
+ userType: "authenticated",
81
+ access: [integrationAccess.manage],
82
+ })
90
83
  .input(z.object({ id: z.string() }))
91
84
  .output(z.object({ success: z.boolean() })),
92
85
 
93
86
  /** Toggle subscription enabled state */
94
- toggleSubscription: _base
95
- .meta({
96
- userType: "authenticated",
97
- permissions: [permissions.integrationManage.id],
98
- })
87
+ toggleSubscription: proc({
88
+ operationType: "mutation",
89
+ userType: "authenticated",
90
+ access: [integrationAccess.manage],
91
+ })
99
92
  .input(z.object({ id: z.string(), enabled: z.boolean() }))
100
93
  .output(z.object({ success: z.boolean() })),
101
94
 
@@ -104,19 +97,18 @@ export const integrationContract = {
104
97
  // ==========================================================================
105
98
 
106
99
  /** List all registered integration providers */
107
- listProviders: _base
108
- .meta({
109
- userType: "authenticated",
110
- permissions: [permissions.integrationManage.id],
111
- })
112
- .output(z.array(IntegrationProviderInfoSchema)),
100
+ listProviders: proc({
101
+ operationType: "query",
102
+ userType: "authenticated",
103
+ access: [integrationAccess.manage],
104
+ }).output(z.array(IntegrationProviderInfoSchema)),
113
105
 
114
106
  /** Test a provider connection with given config */
115
- testProviderConnection: _base
116
- .meta({
117
- userType: "authenticated",
118
- permissions: [permissions.integrationManage.id],
119
- })
107
+ testProviderConnection: proc({
108
+ operationType: "mutation",
109
+ userType: "authenticated",
110
+ access: [integrationAccess.manage],
111
+ })
120
112
  .input(
121
113
  z.object({
122
114
  providerId: z.string(),
@@ -131,65 +123,65 @@ export const integrationContract = {
131
123
  // ==========================================================================
132
124
 
133
125
  /** List all connections for a provider */
134
- listConnections: _base
135
- .meta({
136
- userType: "authenticated",
137
- permissions: [permissions.integrationManage.id],
138
- })
126
+ listConnections: proc({
127
+ operationType: "query",
128
+ userType: "authenticated",
129
+ access: [integrationAccess.manage],
130
+ })
139
131
  .input(z.object({ providerId: z.string() }))
140
132
  .output(z.array(ProviderConnectionRedactedSchema)),
141
133
 
142
134
  /** Get a single connection (redacted) */
143
- getConnection: _base
144
- .meta({
145
- userType: "authenticated",
146
- permissions: [permissions.integrationManage.id],
147
- })
135
+ getConnection: proc({
136
+ operationType: "query",
137
+ userType: "authenticated",
138
+ access: [integrationAccess.manage],
139
+ })
148
140
  .input(z.object({ connectionId: z.string() }))
149
141
  .output(ProviderConnectionRedactedSchema),
150
142
 
151
143
  /** Create a new provider connection */
152
- createConnection: _base
153
- .meta({
154
- userType: "authenticated",
155
- permissions: [permissions.integrationManage.id],
156
- })
144
+ createConnection: proc({
145
+ operationType: "mutation",
146
+ userType: "authenticated",
147
+ access: [integrationAccess.manage],
148
+ })
157
149
  .input(CreateConnectionInputSchema)
158
150
  .output(ProviderConnectionRedactedSchema),
159
151
 
160
152
  /** Update a provider connection */
161
- updateConnection: _base
162
- .meta({
163
- userType: "authenticated",
164
- permissions: [permissions.integrationManage.id],
165
- })
153
+ updateConnection: proc({
154
+ operationType: "mutation",
155
+ userType: "authenticated",
156
+ access: [integrationAccess.manage],
157
+ })
166
158
  .input(UpdateConnectionInputSchema)
167
159
  .output(ProviderConnectionRedactedSchema),
168
160
 
169
161
  /** Delete a provider connection */
170
- deleteConnection: _base
171
- .meta({
172
- userType: "authenticated",
173
- permissions: [permissions.integrationManage.id],
174
- })
162
+ deleteConnection: proc({
163
+ operationType: "mutation",
164
+ userType: "authenticated",
165
+ access: [integrationAccess.manage],
166
+ })
175
167
  .input(z.object({ connectionId: z.string() }))
176
168
  .output(z.object({ success: z.boolean() })),
177
169
 
178
170
  /** Test a saved connection */
179
- testConnection: _base
180
- .meta({
181
- userType: "authenticated",
182
- permissions: [permissions.integrationManage.id],
183
- })
171
+ testConnection: proc({
172
+ operationType: "mutation",
173
+ userType: "authenticated",
174
+ access: [integrationAccess.manage],
175
+ })
184
176
  .input(z.object({ connectionId: z.string() }))
185
177
  .output(TestConnectionResultSchema),
186
178
 
187
179
  /** Get dynamic options for cascading dropdowns */
188
- getConnectionOptions: _base
189
- .meta({
190
- userType: "authenticated",
191
- permissions: [permissions.integrationManage.id],
192
- })
180
+ getConnectionOptions: proc({
181
+ operationType: "mutation",
182
+ userType: "authenticated",
183
+ access: [integrationAccess.manage],
184
+ })
193
185
  .input(GetConnectionOptionsInputSchema)
194
186
  .output(z.array(ConnectionOptionSchema)),
195
187
 
@@ -198,34 +190,32 @@ export const integrationContract = {
198
190
  // ==========================================================================
199
191
 
200
192
  /** List all registered integration events */
201
- listEventTypes: _base
202
- .meta({
203
- userType: "authenticated",
204
- permissions: [permissions.integrationManage.id],
205
- })
206
- .output(z.array(IntegrationEventInfoSchema)),
193
+ listEventTypes: proc({
194
+ operationType: "query",
195
+ userType: "authenticated",
196
+ access: [integrationAccess.manage],
197
+ }).output(z.array(IntegrationEventInfoSchema)),
207
198
 
208
199
  /** Get events grouped by category */
209
- getEventsByCategory: _base
210
- .meta({
211
- userType: "authenticated",
212
- permissions: [permissions.integrationManage.id],
213
- })
214
- .output(
215
- z.array(
216
- z.object({
217
- category: z.string(),
218
- events: z.array(IntegrationEventInfoSchema),
219
- })
220
- )
221
- ),
200
+ getEventsByCategory: proc({
201
+ operationType: "query",
202
+ userType: "authenticated",
203
+ access: [integrationAccess.manage],
204
+ }).output(
205
+ z.array(
206
+ z.object({
207
+ category: z.string(),
208
+ events: z.array(IntegrationEventInfoSchema),
209
+ })
210
+ )
211
+ ),
222
212
 
223
213
  /** Get payload schema for a specific event with flattened property list for template hints */
224
- getEventPayloadSchema: _base
225
- .meta({
226
- userType: "authenticated",
227
- permissions: [permissions.integrationManage.id],
228
- })
214
+ getEventPayloadSchema: proc({
215
+ operationType: "query",
216
+ userType: "authenticated",
217
+ access: [integrationAccess.manage],
218
+ })
229
219
  .input(z.object({ eventId: z.string() }))
230
220
  .output(EventPayloadSchemaOutputSchema),
231
221
 
@@ -234,11 +224,11 @@ export const integrationContract = {
234
224
  // ==========================================================================
235
225
 
236
226
  /** Get delivery logs with filtering */
237
- getDeliveryLogs: _base
238
- .meta({
239
- userType: "authenticated",
240
- permissions: [permissions.integrationManage.id],
241
- })
227
+ getDeliveryLogs: proc({
228
+ operationType: "query",
229
+ userType: "authenticated",
230
+ access: [integrationAccess.manage],
231
+ })
242
232
  .input(DeliveryLogQueryInputSchema)
243
233
  .output(
244
234
  z.object({
@@ -248,29 +238,29 @@ export const integrationContract = {
248
238
  ),
249
239
 
250
240
  /** Get a single delivery log entry */
251
- getDeliveryLog: _base
252
- .meta({
253
- userType: "authenticated",
254
- permissions: [permissions.integrationManage.id],
255
- })
241
+ getDeliveryLog: proc({
242
+ operationType: "query",
243
+ userType: "authenticated",
244
+ access: [integrationAccess.manage],
245
+ })
256
246
  .input(z.object({ id: z.string() }))
257
247
  .output(DeliveryLogSchema),
258
248
 
259
249
  /** Retry a failed delivery */
260
- retryDelivery: _base
261
- .meta({
262
- userType: "authenticated",
263
- permissions: [permissions.integrationManage.id],
264
- })
250
+ retryDelivery: proc({
251
+ operationType: "mutation",
252
+ userType: "authenticated",
253
+ access: [integrationAccess.manage],
254
+ })
265
255
  .input(z.object({ logId: z.string() }))
266
256
  .output(z.object({ success: z.boolean(), message: z.string().optional() })),
267
257
 
268
258
  /** Get delivery statistics for dashboard */
269
- getDeliveryStats: _base
270
- .meta({
271
- userType: "authenticated",
272
- permissions: [permissions.integrationManage.id],
273
- })
259
+ getDeliveryStats: proc({
260
+ operationType: "query",
261
+ userType: "authenticated",
262
+ access: [integrationAccess.manage],
263
+ })
274
264
  .input(
275
265
  z.object({
276
266
  /** Time range in hours (default: 24) */
@@ -1,12 +0,0 @@
1
- import { createPermission } from "@checkstack/common";
2
-
3
- export const permissions = {
4
- /** Manage webhook integrations and view delivery logs */
5
- integrationManage: createPermission(
6
- "integration",
7
- "manage",
8
- "Manage webhook integrations and view delivery logs"
9
- ),
10
- };
11
-
12
- export const permissionList = Object.values(permissions);