diff --git a/libs/adapters/src/express/command.ts b/libs/adapters/src/express/command.ts index 2c784791c04..1b6b305bc6c 100644 --- a/libs/adapters/src/express/command.ts +++ b/libs/adapters/src/express/command.ts @@ -1,5 +1,5 @@ import { command, type CommandMetadata, type User } from '@hicommonwealth/core'; -import type { Request, RequestHandler, Response } from 'express'; +import type { NextFunction, Request, RequestHandler, Response } from 'express'; import { z, ZodSchema } from 'zod'; /** @@ -21,10 +21,15 @@ export const expressCommand = } >, res: Response | undefined>, + next: NextFunction, ) => { - const results = await command(md, req.params.id, req.body, { - user: req.user as User, - address_id: req.body.address_id, - }); - return res.json(results); + try { + const results = await command(md, req.params.id, req.body, { + user: req.user as User, + address_id: req.body.address_id, + }); + return res.json(results); + } catch (error) { + next(error); + } }; diff --git a/libs/adapters/src/express/middleware.ts b/libs/adapters/src/express/middleware.ts index 3a15eeaca5c..1ef762069bb 100644 --- a/libs/adapters/src/express/middleware.ts +++ b/libs/adapters/src/express/middleware.ts @@ -1,6 +1,10 @@ -import { INVALID_INPUT_ERROR, stats } from '@hicommonwealth/core'; +import { + INVALID_ACTOR_ERROR, + INVALID_INPUT_ERROR, + stats, +} from '@hicommonwealth/core'; import { NextFunction, Request, Response } from 'express'; -import { BadRequest, InternalServerError } from './http'; +import { BadRequest, InternalServerError, Unauthorized } from './http'; /** * Captures traffic and latency @@ -19,7 +23,7 @@ export const statsMiddleware = ( stats().histogram(`cw.path.latency`, latency, { path }); }); } catch (err: unknown) { - console.error(err); + console.error(err); // don't use logger port here } next(); }; @@ -33,7 +37,7 @@ export const errorMiddleware = ( res: Response, next: NextFunction, ): void => { - console.error(error); + console.error(error); // don't use logger port here if (res.headersSent) return next(error); let response = InternalServerError( @@ -44,8 +48,18 @@ export const errorMiddleware = ( switch (name) { case INVALID_INPUT_ERROR: response = BadRequest(message, 'details' in error && error.details); + break; + + case INVALID_ACTOR_ERROR: + response = Unauthorized(message); + break; + + default: + response = InternalServerError( + message, + process.env.NODE_ENV !== 'production' ? stack : undefined, + ); } - response = InternalServerError(message, stack); } res.status(response.status).send(response); }; diff --git a/libs/adapters/src/express/query.ts b/libs/adapters/src/express/query.ts index 88866556a6e..e40e562e3bd 100644 --- a/libs/adapters/src/express/query.ts +++ b/libs/adapters/src/express/query.ts @@ -1,5 +1,5 @@ import { query, type QueryMetadata, type User } from '@hicommonwealth/core'; -import type { Request, RequestHandler, Response } from 'express'; +import type { NextFunction, Request, RequestHandler, Response } from 'express'; import { z, ZodSchema } from 'zod'; /** @@ -12,13 +12,18 @@ export const expressQuery = async ( req: Request>, T, Partial>>, res: Response, + next: NextFunction, ) => { - const results = await query( - md, - { ...req.body, ...req.params } as z.infer

, - { - user: req.user as User, - }, - ); - return res.json(results); + try { + const results = await query( + md, + { ...req.body, ...req.params } as z.infer

, + { + user: req.user as User, + }, + ); + return res.json(results); + } catch (error) { + next(error); + } }; diff --git a/libs/core/src/framework/query.ts b/libs/core/src/framework/query.ts index 60953017f69..c8d36f2a152 100644 --- a/libs/core/src/framework/query.ts +++ b/libs/core/src/framework/query.ts @@ -16,7 +16,10 @@ export const query = async ( actor: Actor, ): Promise => { try { - const context: QueryContext

= { actor, payload: schema.parse(payload) }; + const validated = Object.fromEntries( + Object.entries(schema.parse(payload)).filter(([, v]) => v !== undefined), + ); + const context: QueryContext

= { actor, payload: validated }; for (const fn of auth) { await fn(context); } diff --git a/libs/model/src/comment/CreateComment.command.ts b/libs/model/src/comment/CreateComment.command.ts index 8ea0df5cce1..82526202a29 100644 --- a/libs/model/src/comment/CreateComment.command.ts +++ b/libs/model/src/comment/CreateComment.command.ts @@ -1,7 +1,7 @@ import { type CommandMetadata } from '@hicommonwealth/core'; import { z } from 'zod'; import { models } from '../database'; -import { MustNotExist } from '../middleware/invariants'; +import { mustNotExist } from '../middleware/guards'; import type { CommentAttributes } from '../models'; const schema = z.object({ @@ -15,7 +15,7 @@ export const CreateComment: CommandMetadata = body: async ({ id, payload }) => { const comment = await models.Comment.findOne({ where: { id } }); - MustNotExist('Comment', comment); + mustNotExist('Comment', comment); //await models.Comment.create(payload) return payload as Partial; diff --git a/libs/model/src/community/CreateCommunity.command.ts b/libs/model/src/community/CreateCommunity.command.ts index 2f6f802323d..1d507e05170 100644 --- a/libs/model/src/community/CreateCommunity.command.ts +++ b/libs/model/src/community/CreateCommunity.command.ts @@ -6,7 +6,7 @@ import { } from '@hicommonwealth/core'; import { z } from 'zod'; import { models } from '../database'; -import { MustNotExist } from '../middleware/invariants'; +import { mustNotExist } from '../middleware/guards'; import type { CommunityAttributes } from '../models'; import { checkIconSize } from '../utils/checkIconSize'; import { ALL_COMMUNITIES } from '../utils/constants'; @@ -65,7 +65,7 @@ export const CreateCommunity: CommandMetadata< body: async ({ id, payload }) => { const community = await models.Community.findOne({ where: { id } }); - MustNotExist('Community', community); + mustNotExist('Community', community); //await models.Community.create(payload) return payload as Partial; diff --git a/libs/model/src/community/SetCommunityNamespace.command.ts b/libs/model/src/community/SetCommunityNamespace.command.ts index a885bce87f8..12bbd80bd47 100644 --- a/libs/model/src/community/SetCommunityNamespace.command.ts +++ b/libs/model/src/community/SetCommunityNamespace.command.ts @@ -2,7 +2,7 @@ import type { CommandMetadata } from '@hicommonwealth/core'; import { z } from 'zod'; import { models } from '../database'; import { isCommunityAdmin } from '../middleware'; -import { MustExist } from '../middleware/invariants'; +import { mustExist } from '../middleware/guards'; import type { CommunityAttributes } from '../models'; export const schema = z.object({ @@ -20,7 +20,7 @@ export const SetCommunityNamespace: CommandMetadata< body: async ({ id, payload }) => { const community = await models.Community.findOne({ where: { id } }); - if (!MustExist('Community', community)) return; + if (!mustExist('Community', community)) return; // TODO: validate contract // call protocol api and resolve if tbc should be a singleton diff --git a/libs/model/src/community/SetCommunityStake.command.ts b/libs/model/src/community/SetCommunityStake.command.ts index 75b1d3d32ee..97de8910aa5 100644 --- a/libs/model/src/community/SetCommunityStake.command.ts +++ b/libs/model/src/community/SetCommunityStake.command.ts @@ -2,7 +2,7 @@ import { CommandMetadata, InvalidState } from '@hicommonwealth/core'; import { z } from 'zod'; import { models } from '../database'; import { isCommunityAdmin } from '../middleware'; -import { MustExist } from '../middleware/invariants'; +import { mustExist } from '../middleware/guards'; import { CommunityAttributes } from '../models'; import { validateCommunityStakeConfig } from '../services/commonProtocol/communityStakeConfigValidator'; @@ -38,7 +38,7 @@ export const SetCommunityStake: CommandMetadata< }); // !domain logic - invariants on loaded state & payload - if (!MustExist('Community', community)) return; + if (!mustExist('Community', community)) return; if ( community.CommunityStakes && community.CommunityStakes.find((s) => s.stake_id === payload.stake_id) diff --git a/libs/model/src/middleware/invariants.ts b/libs/model/src/middleware/guards.ts similarity index 65% rename from libs/model/src/middleware/invariants.ts rename to libs/model/src/middleware/guards.ts index 8c5e2a73290..252a73e66fb 100644 --- a/libs/model/src/middleware/invariants.ts +++ b/libs/model/src/middleware/guards.ts @@ -1,10 +1,10 @@ import { InvalidState } from '@hicommonwealth/core'; -export const MustExist = (subject: string, state?: T | null): state is T => { +export const mustExist = (subject: string, state?: T | null): state is T => { if (!state) throw new InvalidState(`${subject} must exist`, state); return true; }; -export const MustNotExist = (subject: string, state?: T | null) => { +export const mustNotExist = (subject: string, state?: T | null) => { if (state) throw new InvalidState(`${subject} must not exist`, state); }; diff --git a/libs/model/src/reaction/CreateReaction.command.ts b/libs/model/src/reaction/CreateReaction.command.ts index 00c2701d2d3..9b6538854bb 100644 --- a/libs/model/src/reaction/CreateReaction.command.ts +++ b/libs/model/src/reaction/CreateReaction.command.ts @@ -1,7 +1,7 @@ import { type CommandMetadata } from '@hicommonwealth/core'; import { z } from 'zod'; import { models } from '../database'; -import { MustNotExist } from '../middleware/invariants'; +import { mustNotExist } from '../middleware/guards'; import type { ReactionAttributes } from '../models'; export const schema = z.object({ @@ -17,7 +17,7 @@ export const CreateReaction: CommandMetadata< body: async ({ id, payload }) => { const reaction = await models.Reaction.findOne({ where: { id } }); - MustNotExist('Reaction', reaction); + mustNotExist('Reaction', reaction); //await models.Reaction.create(payload) return payload as Partial; diff --git a/libs/model/src/thread/CreateThread.command.ts b/libs/model/src/thread/CreateThread.command.ts index 7a286f5e4b6..d462272ba8f 100644 --- a/libs/model/src/thread/CreateThread.command.ts +++ b/libs/model/src/thread/CreateThread.command.ts @@ -1,7 +1,7 @@ import { type CommandMetadata } from '@hicommonwealth/core'; import { z } from 'zod'; import { models } from '../database'; -import { MustNotExist } from '../middleware/invariants'; +import { mustNotExist } from '../middleware/guards'; import type { ThreadAttributes } from '../models'; export const schema = z.object({ @@ -14,7 +14,7 @@ export const CreateThread: CommandMetadata = { body: async ({ id, payload }) => { const thread = await models.Thread.findOne({ where: { id } }); - MustNotExist('Thread', thread); + mustNotExist('Thread', thread); //await models.Thread.create(payload) return payload as Partial; diff --git a/libs/model/src/user/CreateUser.command.ts b/libs/model/src/user/CreateUser.command.ts index 9cccc5ece29..7e9857f4771 100644 --- a/libs/model/src/user/CreateUser.command.ts +++ b/libs/model/src/user/CreateUser.command.ts @@ -1,7 +1,7 @@ import { type CommandMetadata } from '@hicommonwealth/core'; import { z } from 'zod'; import { models } from '../database'; -import { MustNotExist } from '../middleware/invariants'; +import { mustNotExist } from '../middleware/guards'; import type { UserAttributes } from '../models'; export const schema = z.object({ @@ -14,7 +14,7 @@ export const CreateUser: CommandMetadata = { body: async ({ id, payload }) => { const user = await models.User.findOne({ where: { id } }); - MustNotExist('User', user); + mustNotExist('User', user); //await models.User.create(payload) return payload as Partial; diff --git a/packages/commonwealth/server/routes/ddd/community.ts b/packages/commonwealth/server/routes/ddd/community.ts index e6e0767dfb2..92f55a0b860 100644 --- a/packages/commonwealth/server/routes/ddd/community.ts +++ b/packages/commonwealth/server/routes/ddd/community.ts @@ -5,13 +5,6 @@ import passport from 'passport'; const router = Router(); -//router.put('/:id', expressCommand(Community.CreateCommunity)); - -//router.post( -// '/set-community-namespace/:id', -// expressCommand(Community.SetCommunityNamespace), -//); - router.get( '/:community_id/stake/:stake_id?', passport.authenticate('jwt', { session: false }), diff --git a/packages/commonwealth/server/routes/ddd/index.ts b/packages/commonwealth/server/routes/ddd/index.ts index 7a71d8f4dd2..25d3fb2e0a0 100644 --- a/packages/commonwealth/server/routes/ddd/index.ts +++ b/packages/commonwealth/server/routes/ddd/index.ts @@ -1,4 +1,4 @@ -import { statsMiddleware } from '@hicommonwealth/adapters'; +import { errorMiddleware, statsMiddleware } from '@hicommonwealth/adapters'; import { Router } from 'express'; import community from './community'; @@ -6,5 +6,6 @@ const router = Router(); // sub-routes router.use('/community', statsMiddleware, community); +router.use(errorMiddleware); export default router; diff --git a/packages/commonwealth/server/routing/router.ts b/packages/commonwealth/server/routing/router.ts index 335542d1075..6844189f35c 100644 --- a/packages/commonwealth/server/routing/router.ts +++ b/packages/commonwealth/server/routing/router.ts @@ -1285,11 +1285,11 @@ function setupRouter( ); app.use(endpoint, router); + // ddd-routes - app.use('/', ddd); + app.use('/ddd', ddd); + app.use(methodNotAllowedMiddleware()); - // catch-all and format errors - TODO: fix unit tests - // app.use(errorMiddleware); } export default setupRouter;