@checkstack/notification-backend 0.0.4 → 0.1.1

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,97 @@
1
1
  # @checkstack/notification-backend
2
2
 
3
+ ## 0.1.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [9a27800]
8
+ - @checkstack/queue-api@0.0.6
9
+ - @checkstack/backend-api@0.3.1
10
+ - @checkstack/auth-backend@0.2.1
11
+
12
+ ## 0.1.0
13
+
14
+ ### Minor Changes
15
+
16
+ - 9faec1f: # Unified AccessRule Terminology Refactoring
17
+
18
+ This release completes a comprehensive terminology refactoring from "permission" to "accessRule" across the entire codebase, establishing a consistent and modern access control vocabulary.
19
+
20
+ ## Changes
21
+
22
+ ### Core Infrastructure (`@checkstack/common`)
23
+
24
+ - Introduced `AccessRule` interface as the primary access control type
25
+ - Added `accessPair()` helper for creating read/manage access rule pairs
26
+ - Added `access()` builder for individual access rules
27
+ - Replaced `Permission` type with `AccessRule` throughout
28
+
29
+ ### API Changes
30
+
31
+ - `env.registerPermissions()` → `env.registerAccessRules()`
32
+ - `meta.permissions` → `meta.access` in RPC contracts
33
+ - `usePermission()` → `useAccess()` in frontend hooks
34
+ - Route `permission:` field → `accessRule:` field
35
+
36
+ ### UI Changes
37
+
38
+ - "Roles & Permissions" tab → "Roles & Access Rules"
39
+ - "You don't have permission..." → "You don't have access..."
40
+ - All permission-related UI text updated
41
+
42
+ ### Documentation & Templates
43
+
44
+ - Updated 18 documentation files with AccessRule terminology
45
+ - Updated 7 scaffolding templates with `accessPair()` pattern
46
+ - All code examples use new AccessRule API
47
+
48
+ ## Migration Guide
49
+
50
+ ### Backend Plugins
51
+
52
+ ```diff
53
+ - import { permissionList } from "./permissions";
54
+ - env.registerPermissions(permissionList);
55
+ + import { accessRules } from "./access";
56
+ + env.registerAccessRules(accessRules);
57
+ ```
58
+
59
+ ### RPC Contracts
60
+
61
+ ```diff
62
+ - .meta({ userType: "user", permissions: [permissions.read.id] })
63
+ + .meta({ userType: "user", access: [access.read] })
64
+ ```
65
+
66
+ ### Frontend Hooks
67
+
68
+ ```diff
69
+ - const canRead = accessApi.usePermission(permissions.read.id);
70
+ + const canRead = accessApi.useAccess(access.read);
71
+ ```
72
+
73
+ ### Routes
74
+
75
+ ```diff
76
+ - permission: permissions.entityRead.id,
77
+ + accessRule: access.read,
78
+ ```
79
+
80
+ ### Patch Changes
81
+
82
+ - Updated dependencies [9faec1f]
83
+ - Updated dependencies [827b286]
84
+ - Updated dependencies [95eeec7]
85
+ - Updated dependencies [f533141]
86
+ - Updated dependencies [aa4a8ab]
87
+ - @checkstack/auth-backend@0.2.0
88
+ - @checkstack/auth-common@0.2.0
89
+ - @checkstack/backend-api@0.3.0
90
+ - @checkstack/common@0.2.0
91
+ - @checkstack/notification-common@0.1.0
92
+ - @checkstack/signal-common@0.1.0
93
+ - @checkstack/queue-api@0.0.5
94
+
3
95
  ## 0.0.4
4
96
 
5
97
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@checkstack/notification-backend",
3
- "version": "0.0.4",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "checkstack": {
package/src/index.ts CHANGED
@@ -8,11 +8,15 @@ import {
8
8
  type NotificationStrategyRegistry,
9
9
  } from "@checkstack/backend-api";
10
10
  import {
11
- permissionList,
11
+ notificationAccessRules,
12
12
  pluginMetadata,
13
13
  notificationContract,
14
14
  } from "@checkstack/notification-common";
15
- import type { PluginMetadata } from "@checkstack/common";
15
+ import {
16
+ access,
17
+ type PluginMetadata,
18
+ type AccessRule,
19
+ } from "@checkstack/common";
16
20
  import { eq } from "drizzle-orm";
17
21
 
18
22
  import * as schema from "./schema";
@@ -49,9 +53,8 @@ export const notificationStrategyExtensionPoint =
49
53
  * Create a new notification strategy registry instance.
50
54
  */
51
55
  function createNotificationStrategyRegistry(): NotificationStrategyRegistry & {
52
- getNewPermissions: () => Array<{
53
- id: string;
54
- description: string;
56
+ getNewAccessRules: () => Array<{
57
+ accessRule: AccessRule;
55
58
  ownerPluginId: string;
56
59
  }>;
57
60
  } {
@@ -59,9 +62,8 @@ function createNotificationStrategyRegistry(): NotificationStrategyRegistry & {
59
62
  string,
60
63
  RegisteredNotificationStrategy<unknown, unknown, unknown>
61
64
  >();
62
- const newPermissions: Array<{
63
- id: string;
64
- description: string;
65
+ const newAccessRules: Array<{
66
+ accessRule: AccessRule;
65
67
  ownerPluginId: string;
66
68
  }> = [];
67
69
 
@@ -71,7 +73,7 @@ function createNotificationStrategyRegistry(): NotificationStrategyRegistry & {
71
73
  metadata: PluginMetadata
72
74
  ): void {
73
75
  const qualifiedId = `${metadata.pluginId}.${strategy.id}`;
74
- const permissionId = `${metadata.pluginId}.strategy.${strategy.id}.use`;
76
+ const accessRuleId = `${metadata.pluginId}.strategy.${strategy.id}.use`;
75
77
 
76
78
  // Cast to unknown for storage - registry stores heterogeneous strategies
77
79
  const registered: RegisteredNotificationStrategy<
@@ -82,15 +84,18 @@ function createNotificationStrategyRegistry(): NotificationStrategyRegistry & {
82
84
  ...(strategy as NotificationStrategy<unknown, unknown, unknown>),
83
85
  qualifiedId,
84
86
  ownerPluginId: metadata.pluginId,
85
- permissionId,
87
+ accessRuleId,
86
88
  };
87
89
 
88
90
  strategies.set(qualifiedId, registered);
89
91
 
90
- // Track new permission for later registration
91
- newPermissions.push({
92
- id: permissionId,
93
- description: `Use ${strategy.displayName} notification channel`,
92
+ // Track new access rule for later registration
93
+ newAccessRules.push({
94
+ accessRule: access(
95
+ `strategy.${strategy.id}`,
96
+ "manage",
97
+ `Use ${strategy.displayName} notification channel`
98
+ ),
94
99
  ownerPluginId: metadata.pluginId,
95
100
  });
96
101
  },
@@ -110,15 +115,15 @@ function createNotificationStrategyRegistry(): NotificationStrategyRegistry & {
110
115
  },
111
116
 
112
117
  getStrategiesForUser(
113
- userPermissions: Set<string>
118
+ userAccessRules: Set<string>
114
119
  ): RegisteredNotificationStrategy<unknown, unknown, unknown>[] {
115
120
  return [...strategies.values()].filter((s) =>
116
- userPermissions.has(s.permissionId)
121
+ userAccessRules.has(s.accessRuleId)
117
122
  );
118
123
  },
119
124
 
120
- getNewPermissions() {
121
- return newPermissions;
125
+ getNewAccessRules() {
126
+ return newAccessRules;
122
127
  },
123
128
  };
124
129
  }
@@ -134,8 +139,8 @@ export default createBackendPlugin({
134
139
  // Create the strategy registry
135
140
  const strategyRegistry = createNotificationStrategyRegistry();
136
141
 
137
- // Register static permissions
138
- env.registerPermissions(permissionList);
142
+ // Register static access rules
143
+ env.registerAccessRules(notificationAccessRules);
139
144
 
140
145
  // Register the extension point
141
146
  env.registerExtensionPoint(notificationStrategyExtensionPoint, {
@@ -214,32 +219,26 @@ export default createBackendPlugin({
214
219
  .join(", ")}`
215
220
  );
216
221
 
217
- // Emit dynamic permissions for strategies
218
- const newPermissions = strategyRegistry.getNewPermissions();
219
- if (newPermissions.length > 0) {
222
+ // Emit dynamic access rules for strategies
223
+ const newAccessRules = strategyRegistry.getNewAccessRules();
224
+ if (newAccessRules.length > 0) {
220
225
  logger.debug(
221
- `🔐 Registering ${newPermissions.length} dynamic strategy permissions`
226
+ `🔐 Registering ${newAccessRules.length} dynamic strategy access rules`
222
227
  );
223
228
 
224
- // Group permissions by owner plugin and emit hooks
225
- const byPlugin = new Map<
226
- string,
227
- Array<{ id: string; description: string }>
228
- >();
229
- for (const perm of newPermissions) {
230
- const existing = byPlugin.get(perm.ownerPluginId) ?? [];
231
- existing.push({ id: perm.id, description: perm.description });
232
- byPlugin.set(perm.ownerPluginId, existing);
229
+ // Group access rules by owner plugin and emit hooks
230
+ const byPlugin = new Map<string, AccessRule[]>();
231
+ for (const item of newAccessRules) {
232
+ const existing = byPlugin.get(item.ownerPluginId) ?? [];
233
+ existing.push(item.accessRule);
234
+ byPlugin.set(item.ownerPluginId, existing);
233
235
  }
234
236
 
235
- // Emit permissions registered hook for each plugin's permissions
236
- for (const [ownerPluginId, permissions] of byPlugin) {
237
- await emitHook(coreHooks.permissionsRegistered, {
237
+ // Emit access rules registered hook for each plugin's rules
238
+ for (const [ownerPluginId, accessRules] of byPlugin) {
239
+ await emitHook(coreHooks.accessRulesRegistered, {
238
240
  pluginId: ownerPluginId,
239
- permissions: permissions.map((p) => ({
240
- id: p.id,
241
- description: p.description,
242
- })),
241
+ accessRules,
243
242
  });
244
243
  }
245
244
  }
package/src/router.ts CHANGED
@@ -85,8 +85,8 @@ function resolveContact({
85
85
  /**
86
86
  * Creates the notification router using contract-based implementation.
87
87
  *
88
- * Auth and permissions are automatically enforced via autoAuthMiddleware
89
- * based on the contract's meta.userType and meta.permissions.
88
+ * Auth and access rules are automatically enforced via autoAuthMiddleware
89
+ * based on the contract's meta.userType and meta.access.
90
90
  */
91
91
  export const createNotificationRouter = (
92
92
  database: NodePgDatabase<typeof schema>,
@@ -260,7 +260,7 @@ export const createNotificationRouter = (
260
260
  return os.router({
261
261
  // ==========================================================================
262
262
  // USER NOTIFICATION ENDPOINTS
263
- // Contract meta: userType: "user", permissions: [notificationRead]
263
+ // Contract meta: userType: "user", accessRules: [notificationRead]
264
264
  // ==========================================================================
265
265
 
266
266
  getNotifications: os.getNotifications.handler(
@@ -364,7 +364,7 @@ export const createNotificationRouter = (
364
364
 
365
365
  // ==========================================================================
366
366
  // ADMIN SETTINGS ENDPOINTS
367
- // Contract meta: userType: "user", permissions: [notificationAdmin]
367
+ // Contract meta: userType: "user", accessRules: [notificationAdmin]
368
368
  // ==========================================================================
369
369
 
370
370
  getRetentionSchema: os.getRetentionSchema.handler(() => {
@@ -85,7 +85,7 @@ function createMockRegistry(): NotificationStrategyRegistry & {
85
85
  id: "smtp",
86
86
  qualifiedId: "test-plugin.smtp",
87
87
  ownerPluginId: "test-plugin",
88
- permissionId: "test-plugin.strategy.smtp.use",
88
+ accessRuleId: "test-plugin.strategy.smtp.use",
89
89
  displayName: "SMTP Email",
90
90
  description: "Send emails via SMTP",
91
91
  contactResolution: { type: "auth-email" },
@@ -97,7 +97,7 @@ function createMockRegistry(): NotificationStrategyRegistry & {
97
97
  id: "sms",
98
98
  qualifiedId: "test-plugin.sms",
99
99
  ownerPluginId: "test-plugin",
100
- permissionId: "test-plugin.strategy.sms.use",
100
+ accessRuleId: "test-plugin.strategy.sms.use",
101
101
  displayName: "SMS",
102
102
  description: "Send SMS messages",
103
103
  contactResolution: { type: "user-config", field: "phoneNumber" },