Skip to content

Commit

Permalink
Publishes hyper-express-session 1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
kartikk221 committed Oct 13, 2021
1 parent 87999dc commit ed56586
Show file tree
Hide file tree
Showing 10 changed files with 813 additions and 28 deletions.
1 change: 1 addition & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
docs/
64 changes: 64 additions & 0 deletions docs/Examples.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Examples & Snippets
Below are various examples and snippets that make use of `SessionEngine` and `Session` components.

#### Example: Initializing & Binding A Session Engine With Redis Store Implementation
```javascript
const SessionEngine = require('hyper-express-session');
const TestEngine = new session_engine({
duration: 1000 * 60 * 45, // Default duration is 45 Minutes
cookie: {
name: 'example_sess',
path: '/',
httpOnly: true,
secure: true,
sameSite: 'strict',
secret: 'SomeSuperSecretForSigningCookies'
}
});

// Bind session engine handlers for storing sessions in Redis store
TestEngine.use('read', async (session) => {
const data = await redis.get('session:' + session.id);
if(typeof data == 'string') return JSON.parse(data);
});

TestEngine.use('touch', async (session) => {
return await redis.pexpireat('session:' + session.id, session.expires_at);
});

TestEngine.use('write', async (session) => {
const key = 'session:' + session.id;

// We use redis pipeline to perform two operations in one go
return await redis.pipeline()
.set(key, JSON.stringify(session.get()))
.pexpireat(key, session.expires_at)
.exec();
});

TestEngine.on('destroy', async (session) => {
return await redis.del('session:' + session.id);
});

// Use middleware from TestEngine in a HyperExpress webserver instance
webserver.use(TestEngine.middleware);
```

#### Example: Initiating and storing visits in a session
```js
// Assume a SessionEngine instance has already been setup for this route
webserver.get('/dashboard/news', async (request, response) => {
// Initiate a session asynchronously
await request.session.start();

// Read session for visits property and iterate
let visits = request.session.get('visits');
if (visits == undefined){
request.session.set('visits', 1); // Initiate visits property in session
} else {
request.session.set('visits', visits + 1); // Iterate visists by 1
}

return response.html(news_html);
});
```
49 changes: 49 additions & 0 deletions docs/Session.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
## Session
Below is a breakdown of the `session` object made available through the `request.session` property in route/middleware handler(s).

#### Session Properties
| Property | Type | Description |
| :-------- | :------- | :------------------------- |
| `id` | `Number` | Raw session id for current request. |
| `signed_id` | `Number` | Signed session id for current request. |
| `ready` | `Boolean` | Specifies whether session has been started. |
| `stored` | `Boolean` | Specifies whether session is already stored in database. |
| `duration` | `Number` | Duration in **milliseconds** of current session. |
| `expires_at` | `Number` | Expiry timestamp in **milliseconds** of current session. |

#### Session Methods
Methods that return `Session` are chainable to allow for cleaner code.

* `generate_id()`: Asynchronously generates and returns a new session id from `'id'` session engine event.
* **Returns** `Promise`->`String`
* `set_id(String: session_id)`: Overwrites/Sets session id for current request session.
* **Returns** `Session`
* **Note** this method is not recommended in conjunction with user input as it performs no verification.
* `set_signed_id(String: signed_id, String: secret)`: Overwrites/Sets session id for current request session.
* **Returns** `Session`
* **Note** this method is **recommended** over `set_id` as it will first unsign/verify the provided signed id and then update the state of current session.
* `secret` is **optional** as this method uses the underlying `SessionEngine.cookie.secret` by default.
* `set_duration(Number: duration)`: Sets a custom session lifetime duration for current session.
* **Returns** `Session`
* **Note** this method stores the custom duration value as a part of the session data in a prefix called `__cust_dur`.
* `start()`: Starts session on incoming request and loads session data from storage source.
* **Returns** `Promise`.
* `roll()`: Rolls current session's id by migrating current session data to a new session id.
* **Returns** `Promise` -> `Boolean`
* `touch()`: Updates current session's expiry timestamp in storage.
* **Returns** `Promise`
* **Note** This method is automatically called at the end of each request when `automatic_touch` is enabled in `SessionEngine` options.
* `destroy()`: Destroys current session from storage and set's cookie header to delete session cookie.
* **Returns** `Promise`
* `set(String: name, Any: value)`: Sets session data value. You set multiple values by passing an `Object` parameter.
* **Returns** `Promise`
* **Single Example:** `session.set('id', 'some_id')`
* **Multiple Example:** `session.set({ id: 'some_id', email: 'some_email' })`
* `reset(Object: data)`: Replaces existing session data values with values from the provided `data` object.
* **Returns** `Promise`
* `get(String: name)`: Returns session data value for specified name. You may **omit** `name` to get **all** session data values.
* **Returns** `Any`, `Object`, `undefined`
* **Get One Example**: `session.get('email');` will return the session data value for `email` or `undefined` if it is not set.
* **Get All Example**: `session.get()` will return all session data values in an `Object`.
* `delete(String: name)`: Deletes session data value at specified name. You may **omit** `name` to delete **all** session data values.
* **Returns** `Promise`
54 changes: 54 additions & 0 deletions docs/SessionEngine.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# SessionEngine
Below is a breakdown of the `SessionEngine` object class generated while creating a new session engine instance. A single session engine can be shared across multiple `HyperExpress.Server` instances.

#### SessionEngine Constructor Options
* `duration`[`Number`]: Specifies the lifetime of sessions in **milliseconds**.
* **Default:** `1000 * 60 * 30` (30 Minutes)
* `automatic_touch`[`Boolean`]: Specifies whether active sessions should be `touched` regardless of data changes upon each request.
* **Default:** `true`
* `cookie`[`Object`]: Specifies session cookie options.
* `name`[`String`]: Cookie Name
* `domain`[`String`]: Cookie Domain
* `path`[`String`]: Cookie Path
* `secure`[`Boolean`]: Adds Secure Flag
* `httpOnly`[`Boolean`]: Adds httpOnly Flag
* `sameSite`[`Boolean`, `'none'`, `'lax'`, `'strict'`]: Cookie Same-Site Preference
* `secret`[`String`]: Specifies secret value used to sign/authenticate session cookies.
* **Note!** a strong and unique string is required for `cookie.secret`.

### SessionEngine Instance Properties
| Property | Type | Description |
| :-------- | :------- | :------------------------- |
| `middleware` | `Function` | Middleware handler to be used with `HyperExpress.use()`. |

#### SessionEngine Methods
* `use(String: type, Function: handler)`: Binds a handler for specified operation `type`.
* **Note** you must use your own storage implementation in combination with available operations below.
* **Supported Operations:**
* [`read`]: Must read and return session data as an `Object` from your storage.
* **Parameters**: `(Session: session) => {}`.
* **Expects** A `Promise` which then resolves to an `Object` or `undefined` type.
* **Required**
* [`touch`]: Must update session expiry timestamp in your storage.
* **Parameters**: `(Session: session) => {}`.
* **Expects** A `Promise` which is then resolved to `Any` type.
* **Required**
* [`write`]: Must write session data and update expiry timestamp to your storage.
* **Parameters**: `(Session: session) => {}`.
* You can use `session.stored` to determine if you need to `INSERT` or `UPDATE` for SQL based implementations.
* **Expects** A `Promise` which then resolves to `Any` type.
* **Required**
* [`destroy`]: Must destroy session from your storage.
* **Parameters**: `(Session: session) => {}`.
* **Expects** A `Promise` which then resolves to `Any` type.
* **Required**
* [`id`]: Must return a promise that generates and resolves a cryptographically random id.
* **Parameters**: `() => {}`.
* **Expects** A `Promise` which then resolves to `String` type.
* **Optional**
* [`cleanup`]: Must clean up expired sessions from your storage.
* **Parameters**: `() => {}`.
* **Expects** A `Promise` which then resolves to `Any` type.
* **Optional**
* See [`> [Session]`](./Session.md) for working with the `session` parameter.
* `cleanup()`: Triggers `cleanup` operation handler to delete expired sessions from storage.
2 changes: 2 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
const SessionEngine = require('./src/components/SessionEngine.js');
module.exports = SessionEngine;
49 changes: 49 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

59 changes: 31 additions & 28 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,30 +1,33 @@
{
"name": "hyper-express-session",
"version": "1.0.0",
"description": "High performance middleware that implements cookie sessions into the HyperExpress webserver.",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/kartikk221/hyper-express-session.git"
},
"keywords": [
"high",
"performance",
"cookie",
"session",
"flexible",
"redis",
"sql",
"compatible",
"node"
],
"author": "kartikk221",
"license": "MIT",
"bugs": {
"url": "https://github.com/kartikk221/hyper-express-session/issues"
},
"homepage": "https://github.com/kartikk221/hyper-express-session#readme"
"name": "hyper-express-session",
"version": "1.0.0",
"description": "High performance middleware that implements cookie based web sessions into the HyperExpress webserver.",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/kartikk221/hyper-express-session.git"
},
"keywords": [
"high",
"performance",
"cookie",
"session",
"flexible",
"redis",
"sql",
"compatible",
"node"
],
"author": "kartikk221",
"license": "MIT",
"bugs": {
"url": "https://github.com/kartikk221/hyper-express-session/issues"
},
"homepage": "https://github.com/kartikk221/hyper-express-session#readme",
"dependencies": {
"uid-safe": "^2.1.5"
}
}
Loading

0 comments on commit ed56586

Please sign in to comment.