Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
6b6addc
chore: adds prettier (#3)
TENSIILE Mar 18, 2026
5c0fef4
chore: adds eslint (#3)
TENSIILE Mar 18, 2026
5e78f49
chore: adds cspell config (#3)
TENSIILE Mar 18, 2026
64b0269
chore: installs dev packages (#3)
TENSIILE Mar 18, 2026
5643251
chore: adds husky (#3)
TENSIILE Mar 18, 2026
e11ed04
adds a word to the cspell dictionary (#3)
TENSIILE Mar 18, 2026
5d7fe06
feat: adds an API for integration with Express (#3)
TENSIILE Mar 18, 2026
21b3d99
Merge pull request #4 from TENSIILE/feature/saborter-initialization
TENSIILE Mar 18, 2026
3a1c867
fix: corrects the branch name for CI (#5)
TENSIILE Mar 18, 2026
e7feee5
changes the hook to a pre-push (#5)
TENSIILE Mar 18, 2026
90def8f
feat: adds a demo that runs in development mode (#5)
TENSIILE Mar 18, 2026
1f8facd
updates logo (#5)
TENSIILE Mar 19, 2026
04919f5
chore: adds import/no-unresolved setting (#5)
TENSIILE Mar 19, 2026
7b1f45a
feat: improves the API for working with saborter.server (#5)
TENSIILE Mar 19, 2026
2494ef7
chore: adds typing to process.env (#5)
TENSIILE Mar 19, 2026
1bb36b3
installs a saborter package (#5)
TENSIILE Mar 19, 2026
37f7828
feat: extends the Express query interface (#5)
TENSIILE Mar 19, 2026
fe39d95
feat: adds a demo server for testing (#5)
TENSIILE Mar 19, 2026
74294ce
Merge pull request #5 from TENSIILE/feature/demo
TENSIILE Mar 19, 2026
ff2f2a1
refactor: removes the old version of the code (#6)
TENSIILE Mar 24, 2026
99dbdc4
feat: adds a utility for obtaining request ID (#6)
TENSIILE Mar 24, 2026
c1de2cd
chore: adds a dot-notation rule (#6)
TENSIILE Mar 24, 2026
dc0fdb2
feat: adds request cancellation implementation for Express (#6)
TENSIILE Mar 24, 2026
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
53 changes: 53 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"root": true,
"env": { "browser": true, "es2020": true, "jest": true },
"extends": ["eslint:recommended", "airbnb", "plugin:import/typescript", "plugin:prettier/recommended"],
"parser": "@typescript-eslint/parser",
"ignorePatterns": [
"**/dist/",
"**/node_modules/",
"**/*.json",
"**/*.html",
"/**/coverage/",
"**/integrations/**/",
"./vite.config.js"
],
"plugins": ["@typescript-eslint", "prettier"],
"rules": {
"no-continue": "off",
"quotes": "off",
"import/prefer-default-export": ["off"],
"class-methods-use-this": ["off"],
"func-names": ["off"],
"no-plusplus": ["off"],
"prefer-spread": ["off"],
"consistent-return": ["off"],
"newline-before-return": "warn",
"default-case": ["off"],
"comma-dangle": ["off"],
"import/extensions": ["off"],
"max-len": ["off"],
"no-console": ["warn", { "allow": ["warn", "error"] }],
"@typescript-eslint/lines-between-class-members": ["off", {}],
"import/no-extraneous-dependencies": ["off"],
"@typescript-eslint/no-unused-vars": ["off", {}],
"no-unused-vars": ["off"],
"import/no-unresolved": "off",
"dot-notation": "off",
"prettier/prettier": [
"error",
{
"arrowParens": "always",
"endOfLine": "auto"
}
]
},
"overrides": [
{
"files": ["*.ts", "*.tsx"],
"rules": {
"no-undef": "off"
}
}
]
}
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ name: CI
on:
pull_request:
branches:
- main
- master
- develop
- 'release/v*.*.*'
push:
branches:
- main
- master
- develop
- 'release/v*.*.*'

Expand Down
3 changes: 3 additions & 0 deletions .husky/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
npm run format
npm run verify
npx lint-staged
4 changes: 4 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
dist
coverage
**/.git
**/node_modules
13 changes: 13 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"semi": true,
"tabWidth": 2,
"printWidth": 120,
"singleQuote": true,
"endOfLine": "lf",
"trailingComma": "none",
"jsxSingleQuote": true,
"bracketSpacing": true,
"useTabs": false,
"jsxBracketSameLine": false,
"arrowParens": "always"
}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<img src="https://img.shields.io/badge/repository-github-color" /></a>
</p>

**Saborter Server** – A lightweight [Node.js](https://nodejs.org/en) library that automatically cancels server-side operations when the client aborts a request. Built on the standard [AbortController API](https://developer.mozilla.org/en-US/docs/Web/API/AbortController), it seamlessly with [Express](https://expressjs.com/) framework and allows you to stop unnecessary database queries, file writes, or external API calls, saving server resources and improving scalability. Fully tree‑shakeable – only the code you actually use ends up in your bundle.
**Saborter Server** a lightweight [Node.js](https://nodejs.org/en) library that automatically cancels server-side operations when the client aborts a request. Built on the standard [AbortController API](https://developer.mozilla.org/en-US/docs/Web/API/AbortController), it seamlessly with [Express](https://expressjs.com/) framework and allows you to stop unnecessary database queries, file writes, or external API calls, saving server resources and improving scalability. Fully tree‑shakeable – only the code you actually use ends up in your bundle.

## 📚 Documentation

Expand Down
Binary file modified assets/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 36 additions & 0 deletions cspell.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"version": "0.2",
"language": "en,ru",
"words": ["Saborter", "saborter", "Laptev", "Vladislav", "tgz", "Сalls", "Interruptible"],
"flagWords": [],
"ignorePaths": [
"node_modules/**",
"dist/**",
"build/**",
".git/**",
"coverage/**",
"*.log",
"package-lock.json",
"./**/*.test.ts",
"./cspell.json",
"./integrations"
],
"dictionaries": ["typescript", "node", "softwareTerms", "en_US", "ru_RU"],
"useGitignore": true,
"patterns": [
{
"name": "markdown-links",
"pattern": "\\(.*\\)",
"description": "Ignore URLs in Markdown"
},
{
"name": "html-entities",
"pattern": "&\\w+;",
"description": "Ignore HTML entities"
}
],
"ignoreRegExpList": ["/\\[.*\\]\\(.*\\)/g", "/&[a-z]+;/g", "/0x[a-fA-F0-9]+/g", "/\\$[^{][\\w.]+/g"],
"caseSensitive": false,
"allowCompoundWords": true,
"minWordLength": 3
}
55 changes: 55 additions & 0 deletions demo/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import express from 'express';
import cors from 'cors';
import { isAbortError } from 'saborter/lib';
import { initRequestInterrupts } from '../src/express';

const app = express();
const port = process.env['PORT'] || 3000;

initRequestInterrupts(app, { endpointName: '/api/abort' });

app.use(cors());
app.use(express.json());

const longRunningOperation = async (signal?: AbortSignal | null) => {
return new Promise((resolve, reject) => {
// eslint-disable-next-line no-console
console.log('Work...');
const timeout = setTimeout(() => {
// eslint-disable-next-line no-console
console.log('Done!');
resolve({ done: true });
}, 30_000);

signal?.addEventListener(
'abort',
() => {
clearTimeout(timeout);
const error = new Error('Operation cancelled');
error.name = 'AbortError';

reject(error);
},
{ once: true }
);
});
};

app.get('/', async (req, res) => {
try {
const result = await longRunningOperation(req.signal);

res.json(result);
} catch (error) {
if (isAbortError(error)) {
return res.status(499).send();
}

res.status(500).send();
}
});

app.listen(port, () => {
// eslint-disable-next-line no-console
console.log(`Server running at http://localhost:${port}`);
});
Loading
Loading