Skip to content

Commit de99172

Browse files
Split server into middleware's and add request validation (#43)
Signed-off-by: Kristina Fefelova <[email protected]>
1 parent fc4d912 commit de99172

34 files changed

+1720
-745
lines changed

.version

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.1.167
1+
0.1.168

bun.lock

+13-10
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"eslint-plugin-prettier": "^5.2.6",
1313
"prettier": "^3.5.3",
1414
"turbo": "^2.5.0",
15-
"typescript-eslint": "^8.29.1",
15+
"typescript-eslint": "^8.30.1",
1616
},
1717
},
1818
"packages/client-query": {
@@ -109,6 +109,7 @@
109109
"@hcengineering/core": "^0.7.28",
110110
"@hcengineering/platform": "^0.7.28",
111111
"@hcengineering/server-token": "^0.7.28",
112+
"zod": "^3.24.2",
112113
},
113114
"devDependencies": {
114115
"@types/bun": "^1.1.14",
@@ -304,21 +305,21 @@
304305

305306
"@types/ws": ["@types/[email protected]", "", { "dependencies": { "@types/node": "*" } }, "sha512-8svvI3hMyvN0kKCJMvTJP/x6Y/EoQbepff882wL+Sn5QsXb3etnamgrJq4isrBxSJj5L2AuXcI0+bgkoAXGUJw=="],
306307

307-
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.29.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.29.1", "@typescript-eslint/type-utils": "8.29.1", "@typescript-eslint/utils": "8.29.1", "@typescript-eslint/visitor-keys": "8.29.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-ba0rr4Wfvg23vERs3eB+P3lfj2E+2g3lhWcCVukUuhtcdUx5lSIFZlGFEBHKr+3zizDa/TvZTptdNHVZWAkSBg=="],
308+
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.30.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.30.1", "@typescript-eslint/type-utils": "8.30.1", "@typescript-eslint/utils": "8.30.1", "@typescript-eslint/visitor-keys": "8.30.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-v+VWphxMjn+1t48/jO4t950D6KR8JaJuNXzi33Ve6P8sEmPr5k6CEXjdGwT6+LodVnEa91EQCtwjWNUCPweo+Q=="],
308309

309-
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.29.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.29.1", "@typescript-eslint/types": "8.29.1", "@typescript-eslint/typescript-estree": "8.29.1", "@typescript-eslint/visitor-keys": "8.29.1", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-zczrHVEqEaTwh12gWBIJWj8nx+ayDcCJs06yoNMY0kwjMWDM6+kppljY+BxWI06d2Ja+h4+WdufDcwMnnMEWmg=="],
310+
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.30.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.30.1", "@typescript-eslint/types": "8.30.1", "@typescript-eslint/typescript-estree": "8.30.1", "@typescript-eslint/visitor-keys": "8.30.1", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-H+vqmWwT5xoNrXqWs/fesmssOW70gxFlgcMlYcBaWNPIEWDgLa4W9nkSPmhuOgLnXq9QYgkZ31fhDyLhleCsAg=="],
310311

311-
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.29.1", "", { "dependencies": { "@typescript-eslint/types": "8.29.1", "@typescript-eslint/visitor-keys": "8.29.1" } }, "sha512-2nggXGX5F3YrsGN08pw4XpMLO1Rgtnn4AzTegC2MDesv6q3QaTU5yU7IbS1tf1IwCR0Hv/1EFygLn9ms6LIpDA=="],
312+
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.30.1", "", { "dependencies": { "@typescript-eslint/types": "8.30.1", "@typescript-eslint/visitor-keys": "8.30.1" } }, "sha512-+C0B6ChFXZkuaNDl73FJxRYT0G7ufVPOSQkqkpM/U198wUwUFOtgo1k/QzFh1KjpBitaK7R1tgjVz6o9HmsRPg=="],
312313

313-
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.29.1", "", { "dependencies": { "@typescript-eslint/typescript-estree": "8.29.1", "@typescript-eslint/utils": "8.29.1", "debug": "^4.3.4", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-DkDUSDwZVCYN71xA4wzySqqcZsHKic53A4BLqmrWFFpOpNSoxX233lwGu/2135ymTCR04PoKiEEEvN1gFYg4Tw=="],
314+
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.30.1", "", { "dependencies": { "@typescript-eslint/typescript-estree": "8.30.1", "@typescript-eslint/utils": "8.30.1", "debug": "^4.3.4", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-64uBF76bfQiJyHgZISC7vcNz3adqQKIccVoKubyQcOnNcdJBvYOILV1v22Qhsw3tw3VQu5ll8ND6hycgAR5fEA=="],
314315

315-
"@typescript-eslint/types": ["@typescript-eslint/types@8.29.1", "", {}, "sha512-VT7T1PuJF1hpYC3AGm2rCgJBjHL3nc+A/bhOp9sGMKfi5v0WufsX/sHCFBfNTx2F+zA6qBc/PD0/kLRLjdt8mQ=="],
316+
"@typescript-eslint/types": ["@typescript-eslint/types@8.30.1", "", {}, "sha512-81KawPfkuulyWo5QdyG/LOKbspyyiW+p4vpn4bYO7DM/hZImlVnFwrpCTnmNMOt8CvLRr5ojI9nU1Ekpw4RcEw=="],
316317

317-
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.29.1", "", { "dependencies": { "@typescript-eslint/types": "8.29.1", "@typescript-eslint/visitor-keys": "8.29.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-l1enRoSaUkQxOQnbi0KPUtqeZkSiFlqrx9/3ns2rEDhGKfTa+88RmXqedC1zmVTOWrLc2e6DEJrTA51C9iLH5g=="],
318+
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.30.1", "", { "dependencies": { "@typescript-eslint/types": "8.30.1", "@typescript-eslint/visitor-keys": "8.30.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-kQQnxymiUy9tTb1F2uep9W6aBiYODgq5EMSk6Nxh4Z+BDUoYUSa029ISs5zTzKBFnexQEh71KqwjKnRz58lusQ=="],
318319

319-
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.29.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "8.29.1", "@typescript-eslint/types": "8.29.1", "@typescript-eslint/typescript-estree": "8.29.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-QAkFEbytSaB8wnmB+DflhUPz6CLbFWE2SnSCrRMEa+KnXIzDYbpsn++1HGvnfAsUY44doDXmvRkO5shlM/3UfA=="],
320+
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.30.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "8.30.1", "@typescript-eslint/types": "8.30.1", "@typescript-eslint/typescript-estree": "8.30.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-T/8q4R9En2tcEsWPQgB5BQ0XJVOtfARcUvOa8yJP3fh9M/mXraLxZrkCfGb6ChrO/V3W+Xbd04RacUEqk1CFEQ=="],
320321

321-
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.29.1", "", { "dependencies": { "@typescript-eslint/types": "8.29.1", "eslint-visitor-keys": "^4.2.0" } }, "sha512-RGLh5CRaUEf02viP5c1Vh1cMGffQscyHe7HPAzGpfmfflFg1wUz2rYxd+OZqwpeypYvZ8UxSxuIpF++fmOzEcg=="],
322+
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.30.1", "", { "dependencies": { "@typescript-eslint/types": "8.30.1", "eslint-visitor-keys": "^4.2.0" } }, "sha512-aEhgas7aJ6vZnNFC7K4/vMGDGyOiqWcYZPpIWrTKuTAlsvDNKy2GFDqh9smL+iq069ZvR0YzEeq0B8NJlLzjFA=="],
322323

323324
"acorn": ["[email protected]", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg=="],
324325

@@ -572,7 +573,7 @@
572573

573574
"typescript": ["[email protected]", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="],
574575

575-
"typescript-eslint": ["typescript-eslint@8.29.1", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.29.1", "@typescript-eslint/parser": "8.29.1", "@typescript-eslint/utils": "8.29.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-f8cDkvndhbQMPcysk6CUSGBWV+g1utqdn71P5YKwMumVMOG/5k7cHq0KyG4O52nB0oKS4aN2Tp5+wB4APJGC+w=="],
576+
"typescript-eslint": ["typescript-eslint@8.30.1", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.30.1", "@typescript-eslint/parser": "8.30.1", "@typescript-eslint/utils": "8.30.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-D7lC0kcehVH7Mb26MRQi64LMyRJsj3dToJxM1+JVTl53DQSV5/7oUGWQLcKl1C1KnoVHxMMU2FNQMffr7F3Row=="],
576577

577578
"undici-types": ["[email protected]", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="],
578579

@@ -588,6 +589,8 @@
588589

589590
"yocto-queue": ["[email protected]", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
590591

592+
"zod": ["[email protected]", "", {}, "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ=="],
593+
591594
"@eslint-community/eslint-utils/eslint-visitor-keys": ["[email protected]", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
592595

593596
"@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/[email protected]", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="],

package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
"workspaces": ["packages/*"],
44
"scripts": {
55
"publish": "sh scripts/publish.sh",
6+
"publish:beta": "sh scripts/publish.sh beta",
67
"build": "turbo run build",
78
"lint": "turbo run lint",
89
"format": "turbo run format",
9-
"check": "bun run format && bun run lint",
10+
"reformat": "turbo run format && turbo run lint -- --fix",
1011
"format:check": "prettier --check \"**/*.ts\""
1112
},
1213
"devDependencies": {
@@ -17,7 +18,7 @@
1718
"eslint-config-prettier": "^9.1.0",
1819
"eslint-plugin-prettier": "^5.2.6",
1920
"prettier": "^3.5.3",
20-
"typescript-eslint": "^8.29.1",
21+
"typescript-eslint": "^8.30.1",
2122
"turbo": "^2.5.0"
2223
},
2324
"packageManager": "[email protected]"

packages/cockroach/src/adapter.ts

+8-3
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,13 @@ export class CockroachAdapter implements DbAdapter {
156156
return await this.message.findThread(thread)
157157
}
158158

159-
async addCollaborators(card: CardID, cardType: CardType, collaborators: AccountID[], date?: Date): Promise<void> {
160-
await this.notification.addCollaborators(card, cardType, collaborators, date)
159+
async addCollaborators(
160+
card: CardID,
161+
cardType: CardType,
162+
collaborators: AccountID[],
163+
date?: Date
164+
): Promise<AccountID[]> {
165+
return await this.notification.addCollaborators(card, cardType, collaborators, date)
161166
}
162167

163168
async removeCollaborators(card: CardID, collaborators: AccountID[]): Promise<void> {
@@ -184,7 +189,7 @@ export class CockroachAdapter implements DbAdapter {
184189
await this.notification.removeContext(context, account)
185190
}
186191

187-
async findContexts(params: FindNotificationContextParams): Promise<NotificationContext[]> {
192+
async findNotificationContexts(params: FindNotificationContextParams): Promise<NotificationContext[]> {
188193
return await this.notification.findContexts(params)
189194
}
190195

packages/cockroach/src/db/label.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ import {
2424
} from '@hcengineering/communication-types'
2525

2626
import { BaseDb } from './base'
27-
import { type LabelDb, TableName } from './schema.ts'
28-
import { toLabel } from './mapping.ts'
27+
import { type LabelDb, TableName } from './schema'
28+
import { toLabel } from './mapping'
2929

3030
export class LabelsDb extends BaseDb {
3131
async createLabel(

packages/cockroach/src/db/notification.ts

+10-4
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,13 @@ import { getCondition } from './utils'
3535
import { toCollaborator, toNotification, toNotificationContext } from './mapping'
3636

3737
export class NotificationsDb extends BaseDb {
38-
async addCollaborators(card: CardID, cardType: CardType, collaborators: AccountID[], date?: Date): Promise<void> {
39-
if (collaborators.length === 0) return
38+
async addCollaborators(
39+
card: CardID,
40+
cardType: CardType,
41+
collaborators: AccountID[],
42+
date?: Date
43+
): Promise<AccountID[]> {
44+
if (collaborators.length === 0) return []
4045
const values: any[] = []
4146

4247
const sqlValues = collaborators
@@ -47,9 +52,10 @@ export class NotificationsDb extends BaseDb {
4752
})
4853
.join(', ')
4954

50-
const sql = `INSERT INTO ${TableName.Collaborators} (workspace_id, card_id, account, date, card_type) VALUES ${sqlValues} ON CONFLICT DO NOTHING`
55+
const sql = `INSERT INTO ${TableName.Collaborators} (workspace_id, card_id, account, date, card_type) VALUES ${sqlValues} ON CONFLICT DO NOTHING RETURNING account`
5156

52-
await this.execute(sql, values, 'insert collaborators')
57+
const result = await this.execute(sql, values, 'insert collaborators')
58+
return result.map((it: any) => it.account)
5359
}
5460

5561
async removeCollaborators(card: CardID, collaborators: AccountID[]): Promise<void> {

packages/cockroach/src/init.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ let isInitialized = false
2121

2222
export async function initSchema(sql: postgres.Sql) {
2323
if (isInitialized) return
24+
const start = performance.now()
2425
console.log('🗃️ Initializing schema...')
2526
await sql.unsafe('CREATE SCHEMA IF NOT EXISTS communication;')
2627
await sql.unsafe(`CREATE TABLE IF NOT EXISTS ${migrationsTableName}
@@ -50,7 +51,9 @@ export async function initSchema(sql: postgres.Sql) {
5051
}
5152
}
5253
isInitialized = true
53-
console.log('🎉 All migrations complete')
54+
const end = performance.now()
55+
const resTime = (end - start) / 1000
56+
console.log(`🎉 All migrations complete in ${resTime.toFixed(2)} sec`)
5457
}
5558

5659
function getMigrations(): [string, string][] {

packages/query/src/notification-contexts/query.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
6464
order: params.order ?? defaultQueryParams.order
6565
}
6666
const limit = params.limit != null ? params.limit + 1 : undefined
67-
const findParams = {
67+
const findParams: FindNotificationContextParams = {
6868
...this.params,
69-
sort: this.params.order ?? defaultQueryParams.order,
69+
order: this.params.order ?? defaultQueryParams.order,
7070
limit
7171
}
7272

packages/query/src/notifications/query.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,11 @@ export class NotificationQuery implements PagedQuery<Notification, FindNotificat
4848
initialResult?: QueryResult<Notification>
4949
) {
5050
const limit = this.params.limit ?? defaultQueryParams.limit
51-
const findParams = { ...this.params, sort: this.params.order ?? defaultQueryParams.order, limit: limit + 1 }
51+
const findParams: FindNotificationsParams = {
52+
...this.params,
53+
order: this.params.order ?? defaultQueryParams.order,
54+
limit: limit + 1
55+
}
5256

5357
if (initialResult !== undefined) {
5458
this.result = initialResult

packages/sdk-types/src/db.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ export interface DbAdapter {
8888
findMessagesGroups(params: FindMessagesGroupsParams): Promise<MessagesGroup[]>
8989
findThread(thread: CardID): Promise<Thread | undefined>
9090

91-
addCollaborators(card: CardID, cardType: CardType, collaborators: AccountID[], date?: Date): Promise<void>
91+
addCollaborators(card: CardID, cardType: CardType, collaborators: AccountID[], date?: Date): Promise<AccountID[]>
9292
removeCollaborators(card: CardID, collaborators: AccountID[]): Promise<void>
9393
getCollaboratorsCursor(card: CardID, date: Date, size?: number): AsyncIterable<Collaborator[]>
9494

@@ -101,7 +101,7 @@ export interface DbAdapter {
101101
updateContext(context: ContextID, account: AccountID, lastUpdate?: Date, lastView?: Date): Promise<void>
102102
removeContext(context: ContextID, account: AccountID): Promise<void>
103103

104-
findContexts(params: FindNotificationContextParams): Promise<NotificationContext[]>
104+
findNotificationContexts(params: FindNotificationContextParams): Promise<NotificationContext[]>
105105
findNotifications(params: FindNotificationsParams): Promise<Notification[]>
106106

107107
createLabel(label: LabelID, card: CardID, cardType: CardType, account: AccountID, created: Date): Promise<void>

packages/sdk-types/src/serverApi.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -29,30 +29,30 @@ import type { Account } from '@hcengineering/core'
2929

3030
import type { EventResult, RequestEvent } from './event'
3131

32-
export interface ConnectionInfo {
32+
export interface SessionData {
3333
sessionId?: string
3434
account: Account
3535
}
3636

3737
export interface ServerApi {
38-
findMessages(info: ConnectionInfo, params: FindMessagesParams, queryId?: number | string): Promise<Message[]>
39-
findMessagesGroups(info: ConnectionInfo, params: FindMessagesGroupsParams): Promise<MessagesGroup[]>
38+
findMessages(session: SessionData, params: FindMessagesParams, queryId?: number | string): Promise<Message[]>
39+
findMessagesGroups(session: SessionData, params: FindMessagesGroupsParams): Promise<MessagesGroup[]>
4040
findNotificationContexts(
41-
info: ConnectionInfo,
41+
session: SessionData,
4242
params: FindNotificationContextParams,
4343
queryId?: number | string
4444
): Promise<NotificationContext[]>
4545
findNotifications(
46-
info: ConnectionInfo,
46+
session: SessionData,
4747
params: FindNotificationsParams,
4848
queryId?: number | string
4949
): Promise<Notification[]>
5050

51-
findLabels(info: ConnectionInfo, params: FindLabelsParams): Promise<Label[]>
51+
findLabels(session: SessionData, params: FindLabelsParams): Promise<Label[]>
5252

53-
event(info: ConnectionInfo, event: RequestEvent): Promise<EventResult>
53+
event(session: SessionData, event: RequestEvent): Promise<EventResult>
5454

55-
unsubscribeQuery(info: ConnectionInfo, id: number): Promise<void>
55+
unsubscribeQuery(session: SessionData, id: number): Promise<void>
5656

5757
closeSession(sessionId: string): Promise<void>
5858
close(): Promise<void>

packages/server/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
"@hcengineering/communication-types": "workspace:*",
3030
"@hcengineering/core": "^0.7.28",
3131
"@hcengineering/server-token": "^0.7.28",
32-
"@hcengineering/platform": "^0.7.28"
32+
"@hcengineering/platform": "^0.7.28",
33+
"zod": "^3.24.2"
3334
},
3435
"peerDependencies": {
3536
"typescript": "^5.6.3"

packages/server/src/error.ts

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//
2+
// Copyright © 2025 Hardcore Engineering Inc.
3+
//
4+
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License. You may
6+
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
//
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
16+
export class ApiError extends Error {
17+
public code: number
18+
public message: string
19+
20+
private constructor(code: number, message: string) {
21+
super(message)
22+
this.code = code
23+
this.message = message
24+
Object.setPrototypeOf(this, ApiError.prototype)
25+
}
26+
27+
static badRequest(message: string): ApiError {
28+
return new ApiError(400, `Bad Request: ${message}`)
29+
}
30+
31+
static forbidden(message: string): ApiError {
32+
return new ApiError(403, `Forbidden: ${message}`)
33+
}
34+
}

0 commit comments

Comments
 (0)