https://github.com/jaredwray/tensile
A Modern Enterprise Auth Framework
https://github.com/jaredwray/tensile
Last synced: 9 months ago
JSON representation
A Modern Enterprise Auth Framework
- Host: GitHub
- URL: https://github.com/jaredwray/tensile
- Owner: jaredwray
- License: mit
- Created: 2024-03-13T18:15:10.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2025-02-10T17:14:24.000Z (11 months ago)
- Last Synced: 2025-02-15T09:08:14.979Z (11 months ago)
- Language: TypeScript
- Homepage: https://tensile.dev
- Size: 59.6 KB
- Stars: 2
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README

[](https://codecov.io/gh/jaredwray/tensile)
[](https://github.com/jaredwray/tensile/actions/workflows/tests.yaml)
[](https://github.com/jaredwray/tensile/blob/master/LICENSE)
[](https://npmjs.com/package/tensile)
[](https://npmjs.com/package/tensile)
# Fastify Plugin for Modern API Development
Tensile is a [fastify](https://fastify.dev) plugin that enables the standard features you need to build a modern REST api service. 🎉
🚨 WARNING: This is a work in progress and is not ready for use yet. Please use when we hit 1.0.0!
## Features
* Caching: Layer 1 / Layer 2 caching built in via [Cacheable](https://cacheable.org)
* Rate Limiting: Prevent abuse with request rate controls.
* CORS: Enable cross-origin resource sharing for API clients.
* Helmet: Harden API security with HTTP headers.
* Swagger/OpenAPI: Auto-generate API documentation and interactive testing interfaces.
* Logging: Preset logging via pino-pretty for easy debugging.
* Maintained on a regular basis!
## Installation
```bash
npm install tensile
```
# Usage
```javascript
import fastify from 'fastify';
import tensile from 'tensile';
const app = fastify();
app.register(tensile);
```
This will add all the features above with the following pre-configured options:
* Caching: Enabled with a default TTL of 60 seconds.
* Rate Limiting: Enabled with a default limit of 500 requests per minute.
* CORS: Enabled with default options.
* Helmet: Enabled with default options.
* Swagger/OpenAPI: Enabled with `/openapi.json` and a default client at path of `/`.
For more advanced usage you can initialize Tensile with options and then update the options for each feature using the properties:
# Caching
Caching is provided by [Cacheable](https://cacheable.org) and is enabled by default with a TTL of 60 seconds. You can update the options by setting the `cache` property in the `tensileOptions` object:
```javascript
const tensileOptions = {
cache: {
ttl: 120
}
};
app.register(tensile, tensileOptions);
```
if you want to disable caching, you can set the `cache` property to `false`:
```javascript
const tensileOptions = {
cache: false
};
app.register(tensile, tensileOptions);
```
The options are based on `CachableOptions` from [Cacheable](https://cacheable.org) and are passed directly to the `Cacheable` instance:
```typescript
export type CacheableOptions = {
/**
* The primary store for the cacheable instance
*/
primary?: Keyv | KeyvStoreAdapter;
/**
* The secondary store for the cacheable instance
*/
secondary?: Keyv | KeyvStoreAdapter;
/**
* Whether to enable statistics for the cacheable instance
*/
stats?: boolean;
/**
* Whether the secondary store is non-blocking mode. It is set to false by default.
* If it is set to true then the secondary store will not block the primary store.
*/
nonBlocking?: boolean;
/**
* The time-to-live for the cacheable instance and will be used as the default value.
* can be a number in milliseconds or a human-readable format such as `1s` for 1 second or `1h` for 1 hour
* or undefined if there is no time-to-live.
*/
ttl?: number | string;
/**
* The namespace for the cacheable instance. It can be a string or a function that returns a string.
*/
namespace?: string | (() => string);
};
```
To use the cache in your routes, you can use the `cache` property on the `fastify` instance:
```javascript
import fastify from 'fastify';
import tensile from 'tensile';
const app = fastify();
app.register(tensile);
app.get('/cache-example/:id', async (request, reply) => {
const { id } = request.params;
const cacheKey = `cache-example-${id}`;
const cachedValue = app.cache.get(cacheKey);
if (cachedValue) {
return cachedValue;
}
const newValue = `New value for ${id}`;
app.cache.set(cacheKey, newValue);
return newValue;
});
```
# Rate Limiting
Rate limiting is based on `@fastify/rate-limit` is enabled by default with the following settings:
* `limit`: 100 requests per minute
* `timeWindow`: 60000 milliseconds (1 minute)
```javascript
const tensileOptions = {
rateLimit: {
limit: 200,
timeWindow: 60000
}
};
```
You can disable rate limiting by setting the `rateLimit` property to `false`:
```javascript
const tensileOptions = {
rateLimit: false
};
```
To read more about the options for rate limiting, please see the [@fastify/rate-limit documentation](https://github.com/fastify/fastify-rate-limit?tab=readme-ov-file#options).
# CORS
CORS is based on [@fastify/cors] and enabled by default with the following settings for a public API service:
* `origin`: `*` which allows all origins
* `methods`: GET, POST, PUT, DELETE, OPTIONS, PATCH
* `allowedHeaders`: 'Content-Type', 'Authorization', 'Accept', 'X-Requested-With'
* `exposedHeaders`: 'X-RateLimit-Limit', 'X-RateLimit-Remaining', 'X-RateLimit-Reset'
* `maxAge`: 86400 which will cache the preflight request for 1 day
Here is an example to set the CORS options:
```javascript
import fastify from 'fastify';
import tensile from 'tensile';
const app = fastify();
const tensileOptions = {
cors: {
origin: 'https://example.com',
methods: ['GET', 'POST'],
allowedHeaders: ['Content-Type', 'Authorization'],
}
};
app.register(tensile, tensileOptions);
```
# Helmet
Helmet is based on [@fastify-helmet](https://github.com/fastify/fastify-helmet) and is enabled with the default settings provided. You can update the options by setting the `helmet` property in the `tensileOptions` object:
```javascript
import fastify from 'fastify';
import tensile from 'tensile';
const app = fastify();
const tensileOptions = {
helmet: {
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'"],
objectSrc: ["'none'"],
upgradeInsecureRequests: true,
},
},
},
};
app.register(tensile, tensileOptions);
```
# Swagger/OpenAPI
Swagger/OpenAPI is based on [@fastify/swagger](https://github.com/fastify/fastify-swagger) and is enabled with the following settings:
* `routePrefix`: `/`
* `openApi`: We use the latest version of OpenAPI (3.0.3) instead of swagger
* `title`: We get this fron `package.json` and cache it in memory for performance
* `description`: We get this fron `package.json` and cache it in memory for performance
* `version`: We get this fron `package.json` and cache it in memory for performance
You can update the options by setting the `swagger` property in the `tensileOptions` object:
```javascript
import fastify from 'fastify';
import tensile from 'tensile';
const app = fastify();
const tensileOptions = {
docs: {
routePrefix: '/docs',
openApi: {
info: {
title: 'My API',
description: 'API documentation for my API',
version: '1.0.0',
},
servers: [
{
url: 'http://localhost:3000',
description: 'Development server',
},
],
},
},
};
```
# Logging
Logging is based on [pino-pretty](https://github.com/pinojs/pino-pretty) and is enabled with the default settings provided. You can update the options by setting the `logging` property in the `tensileOptions` object:
```javascript
import fastify from 'fastify';
import tensile from 'tensile';
const app = fastify();
const tensileOptions = {
logging: {
prettyPrint: {
colorize: true,
translateTime: 'SYS:standard',
},
},
};
app.register(tensile, tensileOptions);
```
# Contributing and Code of Conduct
Please see [CONTRIBUTING](CONTRIBUTING.md) for details. Please see [CODE_OF_CONDUCT](CODE_OF_CONDUCT.md) for details.
# License
[MIT & © Jared Wray](LICENSE)