@manojkmfsi/monodog 1.1.21 → 1.1.23

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,17 @@
1
1
  # @manojkmfsi/monoapp
2
2
 
3
+ ## 1.1.23
4
+
5
+ ### Patch Changes
6
+
7
+ - [`b90aa90`](https://github.com/manojkmfsi/monodog/commit/b90aa90bfbf516128af033c883a21ca4d09f713d) - dcdsdsvdvdvxvcxvxvx
8
+
9
+ ## 1.1.22
10
+
11
+ ### Patch Changes
12
+
13
+ - [`6015ae6`](https://github.com/manojkmfsi/monodog/commit/6015ae608b6b89061ab5cc1dd633d974d2a5ac27) - ddfdfdfdvdvcv
14
+
3
15
  ## 1.1.21
4
16
 
5
17
  ### Patch Changes
@@ -0,0 +1,311 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getPublishPackages = getPublishPackages;
4
+ exports.getPublishChangesets = getPublishChangesets;
5
+ exports.previewPublish = previewPublish;
6
+ exports.createChangeset = createChangeset;
7
+ exports.checkPublishStatus = checkPublishStatus;
8
+ exports.triggerPublish = triggerPublish;
9
+ const logger_1 = require("../middleware/logger");
10
+ const auth_middleware_1 = require("../middleware/auth-middleware");
11
+ const changeset_service_1 = require("../services/changeset-service");
12
+ /**
13
+ * Get all workspace packages
14
+ */
15
+ async function getPublishPackages(req, res) {
16
+ try {
17
+ const rootPath = req.app.locals.rootPath;
18
+ const packages = await (0, changeset_service_1.getWorkspacePackages)(rootPath);
19
+ // Filter out private packages for UI display
20
+ const publicPackages = packages.filter((pkg) => !pkg.private);
21
+ res.json({
22
+ success: true,
23
+ packages: publicPackages,
24
+ total: publicPackages.length,
25
+ });
26
+ }
27
+ catch (error) {
28
+ logger_1.AppLogger.error(`Failed to fetch packages: ${error}`);
29
+ res.status(500).json({
30
+ success: false,
31
+ error: 'Failed to fetch packages',
32
+ message: error instanceof Error ? error.message : 'Unknown error',
33
+ });
34
+ }
35
+ }
36
+ /**
37
+ * Get existing unpublished changesets
38
+ */
39
+ async function getPublishChangesets(req, res) {
40
+ try {
41
+ const rootPath = req.app.locals.rootPath;
42
+ const changesets = await (0, changeset_service_1.getExistingChangesets)(rootPath);
43
+ res.json({
44
+ success: true,
45
+ changesets,
46
+ total: changesets.length,
47
+ });
48
+ }
49
+ catch (error) {
50
+ logger_1.AppLogger.error(`Failed to fetch changesets: ${error}`);
51
+ res.status(500).json({
52
+ success: false,
53
+ error: 'Failed to fetch changesets',
54
+ });
55
+ }
56
+ }
57
+ /**
58
+ * Preview publish plan (calculate new versions, affected packages)
59
+ */
60
+ async function previewPublish(req, res) {
61
+ try {
62
+ const { packages: selectedPackageNames, bumps } = req.body;
63
+ if (!selectedPackageNames || !Array.isArray(selectedPackageNames)) {
64
+ res.status(400).json({
65
+ success: false,
66
+ error: 'Invalid request',
67
+ message: 'packages array is required',
68
+ });
69
+ return;
70
+ }
71
+ const rootPath = req.app.locals.rootPath;
72
+ const allPackages = await (0, changeset_service_1.getWorkspacePackages)(rootPath);
73
+ // Filter selected packages
74
+ const selectedPackages = allPackages.filter((pkg) => selectedPackageNames.includes(pkg.name));
75
+ // Calculate new versions
76
+ const newVersions = (0, changeset_service_1.calculateNewVersions)(selectedPackages, bumps || []);
77
+ // Check if working tree is clean
78
+ const isClean = true; //await isWorkingTreeClean(rootPath);
79
+ // Get existing changesets
80
+ const changesets = await (0, changeset_service_1.getExistingChangesets)(rootPath);
81
+ // Perform validation checks
82
+ const errors = [];
83
+ const warnings = [];
84
+ // Get authenticated user
85
+ const session = (0, auth_middleware_1.getSessionFromRequest)(req);
86
+ const authUser = req.user;
87
+ const userPermission = req.permission.permission || 'read';
88
+ // Check 1: Working tree clean
89
+ const workingTreeClean = isClean;
90
+ if (!workingTreeClean) {
91
+ errors.push('Working tree has uncommitted changes');
92
+ }
93
+ // Check 2: User permissions
94
+ const permissionHierarchy = {
95
+ admin: 4,
96
+ maintain: 3,
97
+ write: 2,
98
+ read: 1,
99
+ none: 0,
100
+ };
101
+ const userLevel = permissionHierarchy[userPermission] || 0;
102
+ const requiredLevel = permissionHierarchy['write'] || 0;
103
+ const permissions = userLevel >= requiredLevel;
104
+ if (!permissions) {
105
+ errors.push(`Insufficient permissions. Required: write, Got: ${userPermission}`);
106
+ }
107
+ // Check 3: CI passing (simplified - always true for now)
108
+ const ciPassing = true;
109
+ // Check 4: Version available on npm (simplified - always true for now)
110
+ const versionAvailable = true;
111
+ logger_1.AppLogger.info(`Publishing preview for user: ${authUser?.login} (permission: ${userPermission})`);
112
+ const isValid = errors.length === 0;
113
+ res.json({
114
+ success: true,
115
+ isValid,
116
+ errors,
117
+ warnings,
118
+ checks: {
119
+ permissions,
120
+ workingTreeClean,
121
+ ciPassing,
122
+ versionAvailable,
123
+ },
124
+ preview: {
125
+ packages: newVersions,
126
+ workingTreeClean: isClean,
127
+ existingChangesets: changesets.length,
128
+ affectedPackages: newVersions.length,
129
+ },
130
+ });
131
+ }
132
+ catch (error) {
133
+ logger_1.AppLogger.error(`Failed to preview publish: ${error}`);
134
+ res.status(500).json({
135
+ success: false,
136
+ error: 'Failed to preview publish',
137
+ message: error instanceof Error ? error.message : 'Unknown error',
138
+ });
139
+ }
140
+ }
141
+ /**
142
+ * Create a new changeset
143
+ */
144
+ async function createChangeset(req, res) {
145
+ try {
146
+ const { packages: selectedPackageNames, bumps, summary } = req.body;
147
+ const authUser = req.user;
148
+ const userPermission = req.permission.permission || 'read';
149
+ if (!selectedPackageNames || !Array.isArray(selectedPackageNames)) {
150
+ res.status(400).json({
151
+ success: false,
152
+ error: 'Invalid request',
153
+ message: 'packages array is required',
154
+ });
155
+ return;
156
+ }
157
+ if (!summary || typeof summary !== 'string' || summary.length < 10) {
158
+ res.status(400).json({
159
+ success: false,
160
+ error: 'Invalid summary',
161
+ message: 'Summary must be at least 10 characters',
162
+ });
163
+ return;
164
+ }
165
+ // Check permissions
166
+ const permissionHierarchy = {
167
+ admin: 4,
168
+ maintain: 3,
169
+ write: 2,
170
+ read: 1,
171
+ none: 0,
172
+ };
173
+ const userLevel = permissionHierarchy[userPermission] || 0;
174
+ const requiredLevel = permissionHierarchy['write'] || 0;
175
+ if (userLevel < requiredLevel) {
176
+ logger_1.AppLogger.warn(`User ${authUser?.login} attempted to create changeset without write permission`);
177
+ res.status(403).json({
178
+ success: false,
179
+ error: 'Forbidden',
180
+ message: `This action requires write permission. You have: ${userPermission}`,
181
+ });
182
+ return;
183
+ }
184
+ const rootPath = req.app.locals.rootPath;
185
+ logger_1.AppLogger.info(`Creating changeset for user: ${authUser?.login} (permission: ${userPermission})`);
186
+ // Generate the changeset
187
+ const result = await (0, changeset_service_1.generateChangeset)(rootPath, selectedPackageNames, bumps || [], summary, authUser?.login);
188
+ if (!result.success) {
189
+ res.status(400).json({
190
+ success: false,
191
+ error: 'Failed to create changeset',
192
+ message: result.message,
193
+ });
194
+ return;
195
+ }
196
+ res.json({
197
+ success: true,
198
+ changeset: result.changeset,
199
+ message: 'Changeset created successfully',
200
+ });
201
+ }
202
+ catch (error) {
203
+ logger_1.AppLogger.error(`Failed to create changeset: ${error}`);
204
+ res.status(500).json({
205
+ success: false,
206
+ error: 'Failed to create changeset',
207
+ message: error instanceof Error ? error.message : 'Unknown error',
208
+ });
209
+ }
210
+ }
211
+ /**
212
+ * Check publish readiness
213
+ */
214
+ async function checkPublishStatus(req, res) {
215
+ try {
216
+ const rootPath = req.app.locals.rootPath;
217
+ // Check if working tree is clean
218
+ const isClean = true; //await isWorkingTreeClean(rootPath);
219
+ // Get existing changesets
220
+ const changesets = await (0, changeset_service_1.getExistingChangesets)(rootPath);
221
+ res.json({
222
+ success: true,
223
+ status: {
224
+ workingTreeClean: isClean,
225
+ hasChangesets: changesets.length > 0,
226
+ changesetCount: changesets.length,
227
+ readyToPublish: isClean && changesets.length > 0,
228
+ },
229
+ });
230
+ }
231
+ catch (error) {
232
+ logger_1.AppLogger.error(`Failed to check publish status: ${error}`);
233
+ res.status(500).json({
234
+ success: false,
235
+ error: 'Failed to check publish status',
236
+ });
237
+ }
238
+ }
239
+ /**
240
+ * Trigger publishing workflow
241
+ */
242
+ async function triggerPublish(req, res) {
243
+ try {
244
+ const rootPath = req.app.locals.rootPath;
245
+ const authUser = req.user;
246
+ const userPermission = req.permission.permission || 'read';
247
+ // Check permissions
248
+ const permissionHierarchy = {
249
+ admin: 4,
250
+ maintain: 3,
251
+ write: 2,
252
+ read: 1,
253
+ none: 0,
254
+ };
255
+ const userLevel = permissionHierarchy[userPermission] || 0;
256
+ const requiredLevel = permissionHierarchy['maintain'] || 0;
257
+ if (userLevel < requiredLevel) {
258
+ logger_1.AppLogger.warn(`User ${authUser?.login} attempted to trigger publish without maintain permission`);
259
+ res.status(403).json({
260
+ success: false,
261
+ error: 'Forbidden',
262
+ message: `This action requires maintain permission. You have: ${userPermission}`,
263
+ });
264
+ return;
265
+ }
266
+ // Check if working tree is clean
267
+ const isClean = true; //await isWorkingTreeClean(rootPath);
268
+ if (!isClean) {
269
+ res.status(400).json({
270
+ success: false,
271
+ error: 'Working tree not clean',
272
+ message: 'Please commit or stash all changes before publishing',
273
+ });
274
+ return;
275
+ }
276
+ // Check if changesets exist
277
+ const changesets = await (0, changeset_service_1.getExistingChangesets)(rootPath);
278
+ if (changesets.length === 0) {
279
+ res.status(400).json({
280
+ success: false,
281
+ error: 'No changesets found',
282
+ message: 'Create changesets before publishing',
283
+ });
284
+ return;
285
+ }
286
+ logger_1.AppLogger.info(`Triggering publish for user: ${authUser?.login} (permission: ${userPermission})`);
287
+ // Trigger publish pipeline with user context
288
+ const result = await (0, changeset_service_1.triggerPublishPipeline)(rootPath, authUser?.login);
289
+ if (!result.success) {
290
+ res.status(500).json({
291
+ success: false,
292
+ error: 'Failed to trigger publish pipeline',
293
+ message: result.message,
294
+ });
295
+ return;
296
+ }
297
+ res.json({
298
+ success: true,
299
+ message: 'Publishing workflow initiated',
300
+ result: result.result,
301
+ });
302
+ }
303
+ catch (error) {
304
+ logger_1.AppLogger.error(`Failed to trigger publish: ${error}`);
305
+ res.status(500).json({
306
+ success: false,
307
+ error: 'Failed to trigger publish',
308
+ message: error instanceof Error ? error.message : 'Unknown error',
309
+ });
310
+ }
311
+ }
@@ -90,9 +90,30 @@ function authenticationMiddleware(req, res, next) {
90
90
  });
91
91
  return;
92
92
  }
93
- // Attach session to request
93
+ // Attach session and user info to request
94
94
  req.session = session;
95
- logger_1.AppLogger.debug(`Authenticated request from user: ${session.user.login}`);
95
+ req.user = {
96
+ login: session.user.login,
97
+ id: session.user.id,
98
+ };
99
+ // Attach permission from session (if available)
100
+ if (session.permission) {
101
+ req.permission = session.permission;
102
+ }
103
+ else {
104
+ // Default to 'read' if no permission fetched
105
+ req.permission = {
106
+ permission: 'read',
107
+ role: 'Denied',
108
+ userId: session.user.id,
109
+ username: session.user.login,
110
+ owner: '',
111
+ repo: '',
112
+ cachedAt: Date.now(),
113
+ ttl: 0,
114
+ };
115
+ }
116
+ logger_1.AppLogger.debug(`Authenticated request from user: ${session.user.login} with permission: ${req.permission?.permission || 'unknown'}`);
96
117
  next();
97
118
  }
98
119
  /**
@@ -124,10 +145,12 @@ function repositoryPermissionMiddleware(requiredPermission) {
124
145
  read: 1,
125
146
  none: 0,
126
147
  };
127
- const userLevel = permissionHierarchy[permission.permission] || 0;
148
+ // Handle both string and object formats for permission
149
+ const userPermissionString = typeof permission === 'string' ? permission : (permission.permission || 'none');
150
+ const userLevel = permissionHierarchy[userPermissionString] || 0;
128
151
  const requiredLevel = permissionHierarchy[requiredPermission] || 0;
129
152
  if (userLevel < requiredLevel) {
130
- logger_1.AppLogger.warn(`User ${session.user.login} lacks permission for action requiring ${requiredPermission}`);
153
+ logger_1.AppLogger.warn(`User ${session.user.login} lacks permission for action requiring ${requiredPermission} (has ${userPermissionString})`);
131
154
  res.status(403).json({
132
155
  error: 'Forbidden',
133
156
  message: `This action requires ${requiredPermission} permission`,
@@ -20,6 +20,7 @@ const health_routes_1 = __importDefault(require("../routes/health-routes"));
20
20
  const config_routes_1 = __importDefault(require("../routes/config-routes"));
21
21
  const auth_routes_1 = __importDefault(require("../routes/auth-routes"));
22
22
  const permission_routes_1 = __importDefault(require("../routes/permission-routes"));
23
+ const publish_routes_1 = __importDefault(require("../routes/publish-routes"));
23
24
  const constants_1 = require("../constants");
24
25
  const auth_middleware_1 = require("./auth-middleware");
25
26
  const permission_service_1 = require("../services/permission-service");
@@ -64,6 +65,7 @@ function createApp(rootPath) {
64
65
  app.use('/api/commits/', commit_routes_1.default);
65
66
  app.use('/api/health/', health_routes_1.default);
66
67
  app.use('/api/config/', config_routes_1.default);
68
+ app.use('/api/publish', publish_routes_1.default);
67
69
  // 404 handler
68
70
  app.use('*', error_handler_1.notFoundHandler);
69
71
  // Global error handler (must be last)
@@ -109,6 +111,13 @@ function startServer(rootPath) {
109
111
  // Config endpoints
110
112
  'PUT /api/config/files/:id',
111
113
  'GET /api/config/files',
114
+ // Publish endpoints
115
+ 'GET /api/publish/packages',
116
+ 'GET /api/publish/changesets',
117
+ 'GET /api/publish/status',
118
+ 'POST /api/publish/preview',
119
+ 'POST /api/publish/changesets',
120
+ 'POST /api/publish/trigger',
112
121
  ],
113
122
  });
114
123
  });
@@ -7,7 +7,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  const express_1 = require("express");
8
8
  const github_oauth_service_1 = require("../services/github-oauth-service");
9
9
  const auth_middleware_1 = require("../middleware/auth-middleware");
10
+ const permission_service_1 = require("../services/permission-service");
10
11
  const logger_1 = require("../middleware/logger");
12
+ const utilities_1 = require("../utils/utilities");
11
13
  const router = (0, express_1.Router)();
12
14
  // OAuth configuration (should come from environment variables)
13
15
  // const GITHUB_CLIENT_ID = process.env.GITHUB_CLIENT_ID || '';
@@ -138,13 +140,34 @@ router.get('/callback', async (req, res) => {
138
140
  // Get user information
139
141
  logger_1.AppLogger.debug('Retrieving authenticated user information');
140
142
  const user = await (0, github_oauth_service_1.getAuthenticatedUser)(tokenResponse.access_token);
141
- // Create session
143
+ // Fetch user's repository permission
144
+ let permission = null;
145
+ try {
146
+ logger_1.AppLogger.debug(`Fetching repository permission for user ${user.login}`);
147
+ // Extract repository info from git remote
148
+ const repoInfo = await (0, utilities_1.getRepositoryInfoFromGit)();
149
+ if (!repoInfo) {
150
+ logger_1.AppLogger.warn('Could not extract repository info from git remote - permission fetch skipped');
151
+ }
152
+ else {
153
+ const { owner, repo } = repoInfo;
154
+ permission = await (0, permission_service_1.getUserRepositoryPermission)(tokenResponse.access_token, user.id, user.login, owner, repo);
155
+ logger_1.AppLogger.info(`User ${user.login} has ${permission.permission} permission on ${owner}/${repo}`);
156
+ }
157
+ }
158
+ catch (permError) {
159
+ logger_1.AppLogger.error(`Failed to fetch repository permission: ${permError}`);
160
+ // Continue without permission - will be checked on protected routes
161
+ permission = null;
162
+ }
163
+ // Create session with permission
142
164
  const session = {
143
165
  accessToken: tokenResponse.access_token,
144
166
  expiresIn: 3600, // 1 hour default
145
167
  expiresAt: Date.now() + 24 * 60 * 60 * 1000, // 24 hours
146
168
  user,
147
169
  scopes: tokenResponse.scope.split(','),
170
+ permission, // Include fetched permission in session
148
171
  };
149
172
  // Store session and get token
150
173
  const sessionToken = (0, auth_middleware_1.storeSession)(session);
@@ -152,7 +175,7 @@ router.get('/callback', async (req, res) => {
152
175
  const redirectUrl = getRedirectUrl(state) || '/';
153
176
  // Clear state
154
177
  clearState(state);
155
- logger_1.AppLogger.info(`User authenticated: ${user.login}`);
178
+ logger_1.AppLogger.info(`User authenticated: ${user.login} with permission: ${permission?.permission || 'unknown'}`);
156
179
  res.json({
157
180
  success: true,
158
181
  message: 'Authentication successful',
@@ -164,6 +187,10 @@ router.get('/callback', async (req, res) => {
164
187
  name: user.name,
165
188
  avatar_url: user.avatar_url,
166
189
  },
190
+ permission: permission ? {
191
+ level: permission.permission,
192
+ role: permission.role,
193
+ } : null,
167
194
  });
168
195
  }
169
196
  catch (error) {
@@ -203,6 +230,7 @@ router.get('/me', auth_middleware_1.authenticationMiddleware, (req, res) => {
203
230
  },
204
231
  scopes: session.scopes,
205
232
  expiresAt: session.expiresAt,
233
+ permission: session.permission || null,
206
234
  });
207
235
  }
208
236
  catch (error) {
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const express_1 = __importDefault(require("express"));
7
+ const publish_controller_1 = require("../controllers/publish-controller");
8
+ const auth_middleware_1 = require("../middleware/auth-middleware");
9
+ const publishRouter = express_1.default.Router();
10
+ /**
11
+ * GET /api/publish/packages
12
+ * Get all workspace packages for publishing
13
+ * Requires: read permission
14
+ */
15
+ publishRouter.get('/packages', auth_middleware_1.authenticationMiddleware, publish_controller_1.getPublishPackages);
16
+ /**
17
+ * GET /api/publish/changesets
18
+ * Get existing unpublished changesets
19
+ * Requires: read permission
20
+ */
21
+ publishRouter.get('/changesets', auth_middleware_1.authenticationMiddleware, publish_controller_1.getPublishChangesets);
22
+ /**
23
+ * POST /api/publish/preview
24
+ * Preview the publish plan (calculate new versions, affected packages)
25
+ * Requires: read permission
26
+ */
27
+ publishRouter.post('/preview', auth_middleware_1.authenticationMiddleware, publish_controller_1.previewPublish);
28
+ /**
29
+ * POST /api/publish/changesets
30
+ * Create a new changeset for the selected packages
31
+ * Requires: write permission
32
+ */
33
+ publishRouter.post('/changesets', auth_middleware_1.authenticationMiddleware, (0, auth_middleware_1.repositoryPermissionMiddleware)('write'), publish_controller_1.createChangeset);
34
+ /**
35
+ * GET /api/publish/status
36
+ * Check publish readiness (working tree, changesets, etc.)
37
+ * Requires: read permission
38
+ */
39
+ publishRouter.get('/status', auth_middleware_1.authenticationMiddleware, publish_controller_1.checkPublishStatus);
40
+ /**
41
+ * POST /api/publish/trigger
42
+ * Trigger the publishing workflow
43
+ * Requires: maintain permission
44
+ */
45
+ publishRouter.post('/trigger', auth_middleware_1.authenticationMiddleware, (0, auth_middleware_1.repositoryPermissionMiddleware)('maintain'), publish_controller_1.triggerPublish);
46
+ exports.default = publishRouter;