Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .release-please-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"packages/read-pkg": "2.0.0",
"packages/openapi-express-viewer": "4.1.0",
"packages/openapi-helpers": "5.1.0",
"packages/openapi-typed-request-handler": "0.1.0",
"packages/semantic-conventions": "1.0.0",
"packages/tracing": "1.0.0",
"packages/tracing-utils": "1.0.0",
Expand Down
4 changes: 4 additions & 0 deletions .vscode/project.code-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@
"name": "openapi-helpers",
"path": "../packages/openapi-helpers",
},
{
"name": "openapi-typed-request-handler",
"path": "../packages/openapi-typed-request-handler",
},
{
"name": "semantic-conventions",
"path": "../packages/semantic-conventions",
Expand Down
8 changes: 1 addition & 7 deletions packages/openapi-helpers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@
"types": "./dist/requestSender/requestSender.d.ts",
"default": "./dist/requestSender/requestSender.js"
},
"./typedRequestHandler": {
"types": "./dist/typedRequestHandler/typedRequestHandler.d.ts",
"default": "./dist/typedRequestHandler/typedRequestHandler.js"
},
"./generators": {
"types": "./dist/generator/index.d.ts",
"default": "./dist/generator/index.js"
Expand All @@ -28,9 +24,7 @@
"prepack": "turbo run build",
"check-dist": "publint && attw --profile node16 --pack .",
"knip": "knip --directory ../.. --workspace packages/openapi-helpers",
"api:check": "pnpm run handler:api:check && pnpm run sender:api:check && pnpm run generators:api:check",
"handler:api": "api-extractor run --local --verbose --config ./api-extractor.handler.json",
"handler:api:check": "api-extractor run --verbose --config ./api-extractor.handler.json",
"api:check": "pnpm run sender:api:check && pnpm run generators:api:check",
"sender:api": "api-extractor run --local --verbose --config ./api-extractor.sender.json",
"sender:api:check": "api-extractor run --verbose --config ./api-extractor.sender.json",
"generators:api": "api-extractor run --local --verbose --config ./api-extractor.generators.json",
Expand Down
3 changes: 0 additions & 3 deletions packages/openapi-helpers/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
{
"extends": "@map-colonies/tsconfig/tsconfig-library",
"compilerOptions": {
"lib": ["ESNext"]
},
"include": ["src", "tests"],
"exclude": ["dist", "node_modules"]
}
29 changes: 29 additions & 0 deletions packages/openapi-typed-request-handler/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# openapi-typed-request-handler

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# openapi-typed-request-handler
# @map-colonies/openapi-typed-request-handler

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But in other packages it's like I did it

@ronenkapelian ronenkapelian Jun 10, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the real name of the package.so let fix it here as suggested.


Express request handler type utilities for building type-safe APIs based on OpenAPI specifications.

## Installation

```bash
npm install @map-colonies/openapi-typed-request-handler
```

## Usage

```typescript
import { TypedRequestHandlers } from '@map-colonies/openapi-typed-request-handler';
import type { paths, operations } from './types.d.ts';

// Initialize the TypedRequestHandlers with the paths and operations types
type MyHandlers = TypedRequestHandlers<paths, operations>;

export const getUser: MyHandlers['getUserById'] = (req, res) => {
const id = req.params.id; // Autocomplete!
res.status(200).json({ id, name: 'John' }); // Type-safe response body!
};

// Or using method/path mapping
export const getResource: MyHandlers['GET /resource'] = (req, res) => {
res.status(200).json({ id: 1, name: 'name' });
};
```
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
"extends": "../../api-extractor.json",
"mainEntryPointFilePath": "dist/typedRequestHandler/typedRequestHandler.d.ts",
"mainEntryPointFilePath": "dist/index.d.ts",
"apiReport": {
"enabled": true,
"reportFileName": "handler.<unscopedPackageName>"
"reportFileName": "openapi-typed-request-handler.api.md"
}
}
4 changes: 4 additions & 0 deletions packages/openapi-typed-request-handler/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import baseConfig from '@map-colonies/eslint-config/ts-base';
import { defineConfig } from 'eslint/config';

export default defineConfig(baseConfig, { ignores: ['vitest.config.ts'] });
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
## API Report File for "@map-colonies/openapi-typed-request-handler"

> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).

```ts

import type { OptionalKeys } from 'ts-essentials';
import type { RequestHandler } from 'express';

// Warning: (ae-forgotten-export) The symbol "PathsTemplate" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "OperationsTemplate" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "OperationHandlers" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "PathHandlers" needs to be exported by the entry point index.d.ts
//
// @public
export type TypedRequestHandlers<Paths extends PathsTemplate, Operations extends OperationsTemplate> = OperationHandlers<Operations> & PathHandlers<Paths>;

// (No @packageDocumentation comment for this package)

```
54 changes: 54 additions & 0 deletions packages/openapi-typed-request-handler/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"name": "@map-colonies/openapi-typed-request-handler",
"version": "0.1.0",
"description": "Express request handler type utilities for OpenAPI-defined APIs",
"type": "commonjs",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
},
"scripts": {
"test": "vitest run",
"lint": "eslint .",
"lint:fix": "eslint --fix .",
"prebuild": "pnpm run clean",
"build": "tsc --project tsconfig.build.json",
"clean": "rimraf dist",
"prepack": "turbo run build",
"check-dist": "publint && attw --profile node16 --pack .",
"knip": "knip --directory ../.. --workspace packages/openapi-typed-request-handler",
"api:check": "api-extractor run --verbose --config ./api-extractor.json",
"api": "api-extractor run --local --verbose --config ./api-extractor.json"
},
"repository": "github:MapColonies/infra-packages",
"files": [
"dist/**/*"
],
"publishConfig": {
"access": "public"
},
"engines": {
"node": ">=24"
},
"dependencies": {
"ts-essentials": "^10.1.1"
},
"peerDependencies": {
"@types/express": "^4.17.21",
"openapi-typescript": "^7.4.1"
},
"devDependencies": {
"@map-colonies/eslint-config": "workspace:^",
"@map-colonies/tsconfig": "workspace:^",
"@types/node": "catalog:",
"express": "5.2.1",
"eslint": "catalog:",
"rimraf": "catalog:",
"typescript": "catalog:",
"vitest-config": "workspace:^",
"vitest": "catalog:",
"@microsoft/api-extractor": "catalog:"
}
}
26 changes: 26 additions & 0 deletions packages/openapi-typed-request-handler/src/common/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
type HasContent<T> = [T] extends [{ content: any }] ? T['content']['application/json'] : never;

export type Methods = 'get' | 'post' | 'put' | 'delete' | 'patch' | 'head' | 'options' | 'trace';

export type OperationsTemplate = Record<string, any>;

export type PathsTemplate = Record<
string,
{
parameters: {
query?: any;
header?: any;
path?: any;
cookie?: any;
};
} & {
[key in Methods]?: OperationsTemplate;
}
>;

export type ResponseObjectToFlat<T> = [T] extends [{ responses: any }]
? {
[res in keyof T['responses']]: { status: res; body: HasContent<T['responses'][res]> };
}[keyof T['responses']]
: never;
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
*/
import type { RequestHandler } from 'express';
import type { OptionalKeys } from 'ts-essentials';
import type { ResponseObjectToFlat } from '../requestSender/types';
import type { OperationsTemplate, PathsTemplate } from '../common/types';
import type { OperationsTemplate, PathsTemplate, ResponseObjectToFlat } from './common/types';

// The types only work with any, so we need to disable the eslint rule
// It doesn't affect the resulting types as its only used for the condition
Expand Down
Loading
Loading