├── .env ├── .eslintignore ├── .eslintrc ├── .github └── workflows │ └── npm-ci.yml ├── .gitignore ├── .npmignore ├── .npmrc ├── .prettierrc ├── .vscode ├── launch.json └── settings.json ├── LICENSE ├── README.md ├── coverage-badge.svg ├── docker ├── README.md ├── docker-compose.6.yml └── docker-compose.7.yml ├── docs ├── .nojekyll ├── assets │ ├── highlight.css │ ├── main.js │ ├── navigation.js │ ├── search.js │ └── style.css ├── coverage │ ├── coverage-summary.json │ ├── lcov-report │ │ ├── base.css │ │ ├── block-navigation.js │ │ ├── favicon.png │ │ ├── index.html │ │ ├── index.ts.html │ │ ├── mongodb-session.ts.html │ │ ├── mongoose-session.ts.html │ │ ├── prettify.css │ │ ├── prettify.js │ │ ├── sort-arrow-sprite.png │ │ ├── sorter.js │ │ └── type.ts.html │ └── lcov.info ├── functions │ ├── sessionDeserializer.html │ └── sessionSerializer.html ├── index.html ├── modules.html └── types │ └── SerializedSession.html ├── jest.config.ts ├── jest.setup.js ├── package.json ├── pnpm-lock.yaml ├── renovate.json ├── src ├── index.ts ├── mongodb-session.ts ├── mongoose-session.ts └── type.ts ├── test ├── mongodb-session.test.ts └── mongoose-session.test.ts └── tsconfig.json /.env: -------------------------------------------------------------------------------- 1 | DEBUG=false 2 | 3 | # Mongo 4 | MONGO_DB=wenex 5 | 6 | MONGO_USER=root 7 | MONGO_PASS=password123 8 | MONGO_HOST=mongodb-primary:27017,mongodb-secondary:27018 9 | MONGO_QUERY="replicaSet=rs0&authSource=admin" 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | docs 3 | coverage 4 | node_modules 5 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "plugins": ["@typescript-eslint"], 5 | "extends": [ 6 | "prettier", 7 | "eslint:recommended", 8 | "plugin:prettier/recommended", 9 | "plugin:@typescript-eslint/eslint-recommended", 10 | "plugin:@typescript-eslint/recommended" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /.github/workflows/npm-ci.yml: -------------------------------------------------------------------------------- 1 | name: Build, Test and Publish 2 | on: 3 | release: 4 | types: [created] 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v4 10 | # Setup .npmrc file to publish to npm 11 | - uses: actions/setup-node@v4 12 | with: 13 | node-version: '20.x' 14 | registry-url: 'https://registry.npmjs.org' 15 | - run: npm install -g pnpm 16 | - run: pnpm install --frozen-lockfile 17 | # - run: npm test 18 | - run: npm run build --if-present 19 | - run: npm publish 20 | env: 21 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | index.d.ts 2 | index.js 3 | index.js.map 4 | mongodb-session.d.ts 5 | mongodb-session.js 6 | mongodb-session.js.map 7 | mongoose-session.d.ts 8 | mongoose-session.js 9 | mongoose-session.js.map 10 | type.d.ts 11 | type.js 12 | type.js.map 13 | 14 | # Logs 15 | logs 16 | *.log 17 | npm-debug.log* 18 | yarn-debug.log* 19 | yarn-error.log* 20 | lerna-debug.log* 21 | .pnpm-debug.log* 22 | 23 | # Diagnostic reports (https://nodejs.org/api/report.html) 24 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 25 | 26 | # Runtime data 27 | pids 28 | *.pid 29 | *.seed 30 | *.pid.lock 31 | 32 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 33 | .grunt 34 | 35 | # Bower dependency directory (https://bower.io/) 36 | bower_components 37 | 38 | # node-waf configuration 39 | .lock-wscript 40 | 41 | # Compiled binary addons (https://nodejs.org/api/addons.html) 42 | build/Release 43 | 44 | # Dependency directories 45 | node_modules/ 46 | jspm_packages/ 47 | 48 | # Snowpack dependency directory (https://snowpack.dev/) 49 | web_modules/ 50 | 51 | # TypeScript cache 52 | *.tsbuildinfo 53 | 54 | # Optional npm cache directory 55 | .npm 56 | 57 | # Optional eslint cache 58 | .eslintcache 59 | 60 | # Optional stylelint cache 61 | .stylelintcache 62 | 63 | # Microbundle cache 64 | .rpt2_cache/ 65 | .rts2_cache_cjs/ 66 | .rts2_cache_es/ 67 | .rts2_cache_umd/ 68 | 69 | # Optional REPL history 70 | .node_repl_history 71 | 72 | # Output of 'npm pack' 73 | *.tgz 74 | 75 | # Yarn Integrity file 76 | .yarn-integrity 77 | 78 | # dotenv environment variable files 79 | .env.development.local 80 | .env.test.local 81 | .env.production.local 82 | .env.local 83 | 84 | # parcel-bundler cache (https://parceljs.org/) 85 | .cache 86 | .parcel-cache 87 | 88 | # Next.js build output 89 | .next 90 | out 91 | 92 | # Nuxt.js build / generate output 93 | .nuxt 94 | dist 95 | 96 | # Gatsby files 97 | .cache/ 98 | # Comment in the public line in if your project uses Gatsby and not Next.js 99 | # https://nextjs.org/blog/next-9-1#public-directory-support 100 | # public 101 | 102 | # vuepress build output 103 | .vuepress/dist 104 | 105 | # vuepress v2.x temp and cache directory 106 | .temp 107 | .cache 108 | 109 | # Docusaurus cache and generated files 110 | .docusaurus 111 | 112 | # Serverless directories 113 | .serverless/ 114 | 115 | # FuseBox cache 116 | .fusebox/ 117 | 118 | # DynamoDB Local files 119 | .dynamodb/ 120 | 121 | # TernJS port file 122 | .tern-port 123 | 124 | # Stores VSCode versions used for testing VSCode extensions 125 | .vscode-test 126 | 127 | # yarn v2 128 | .yarn/cache 129 | .yarn/unplugged 130 | .yarn/build-state.yml 131 | .yarn/install-state.gz 132 | .pnp.* 133 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | docs 3 | .vscode 4 | coverage 5 | 6 | tslint.json 7 | tsconfig.json 8 | jest.config.ts 9 | .prettierrc.js 10 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmjs.org/ 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all", 4 | "printWidth": 90, 5 | "tabWidth": 2 6 | } 7 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "attach", 10 | "name": "Attach", 11 | "restart": true, 12 | "port": 9229, 13 | "skipFiles": ["/**"] 14 | }, 15 | { 16 | "type": "node", 17 | "request": "launch", 18 | "name": "Jest watch current file", 19 | "program": "${workspaceFolder}/node_modules/jest/bin/jest", 20 | "args": [ 21 | "${fileBasename}", 22 | "--verbose", 23 | "-i", 24 | "--no-cache", 25 | "--watchAll" 26 | ], 27 | "console": "integratedTerminal", 28 | "internalConsoleOptions": "neverOpen" 29 | }, 30 | { 31 | "type": "node", 32 | "request": "launch", 33 | "name": "Jest e2e watch current file", 34 | "program": "${workspaceFolder}/node_modules/jest/bin/jest", 35 | "args": [ 36 | "${fileBasename}", 37 | "--verbose", 38 | "-i", 39 | "--no-cache", 40 | "--watchAll", 41 | "--config", 42 | "${workspaceFolder}/test/jest-e2e.json" 43 | ], 44 | "console": "integratedTerminal", 45 | "internalConsoleOptions": "neverOpen" 46 | } 47 | ] 48 | } 49 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.codeActionsOnSave": { 3 | "source.fixAll.eslint": "explicit" 4 | }, 5 | "cSpell.words": ["Vahid"] 6 | } 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Vahid V. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MongoDB Session Serializer/Deserializer 2 | 3 | [![npm](https://img.shields.io/npm/v/mongodb-session-serializer)](https://www.npmjs.com/package/mongodb-session-serializer) 4 | ![npm](https://img.shields.io/npm/dm/mongodb-session-serializer) 5 | [![Coverage](https://raw.githubusercontent.com/vhidvz/mongodb-session-serializer/main/coverage-badge.svg)](https://htmlpreview.github.io/?https://github.com/vhidvz/mongodb-session-serializer/blob/main/docs/coverage/lcov-report/index.html) 6 | [![GitHub](https://img.shields.io/github/license/vhidvz/mongodb-session-serializer?style=flat)](https://github.com/vhidvz/mongodb-session-serializer/blob/main/LICENSE) 7 | [![documentation](https://img.shields.io/badge/documentation-click_to_read-c27cf4)](https://vhidvz.github.io/mongodb-session-serializer/) 8 | [![Build, Test and Publish](https://github.com/vhidvz/mongodb-session-serializer/actions/workflows/npm-ci.yml/badge.svg)](https://github.com/vhidvz/mongodb-session-serializer/actions/workflows/npm-ci.yml) 9 | 10 | This package helps you serialize a MongoDB session and use it in a microservices environment on the same MongoDB infrastructure to have ACID at the database level. 11 | 12 | - Support for multi-database transactions on the same MongoDB infrastructure 13 | 14 | ## Quick Start Guide 15 | 16 | | # | Driver | MongoDB | | 17 | | - | ---------------------- | ------- | ---- | 18 | | 1 | 5.x ( `mongoose` 7.x ) | 6.x | OK | 19 | | 2 | 6.x ( `mongoose` 8.x ) | 7.x | OK | 20 | 21 | ### Installation 22 | 23 | ```sh 24 | npm install --save mongodb mongodb-session-serializer 25 | ``` 26 | 27 | ### Serializing 28 | 29 | ```ts 30 | import { MongoClient, ReadPreference, TransactionOptions } from 'mongodb'; 31 | import { sessionSerializer } from 'mongodb-session-serializer'; 32 | 33 | export const transactionOptions: TransactionOptions = { 34 | readPreference: ReadPreference.primary, 35 | readConcern: { level: 'snapshot' }, 36 | writeConcern: { w: 'majority' }, 37 | 38 | maxCommitTimeMS: 15 * 60 * 1000, // 15 mins 39 | }; 40 | 41 | // Connection URL - https://github.com/vhidvz/mongo-rs 42 | const url = 43 | 'mongodb://root:password123@mongodb-primary:27017,mongodb-secondary-1:27018,mongodb-secondary-2:27019,mongodb-arbiter:27020/?replicaSet=rs0'; 44 | const client = new MongoClient(url); 45 | 46 | await client.connect(); 47 | 48 | const session = await client.startSession(); 49 | 50 | try { 51 | session.startTransaction(transactionOptions); 52 | 53 | // do anything you want... 54 | 55 | const serializedSession = sessionSerializer(session); 56 | // send the serialized session to another microservice 57 | } catch { 58 | await session.abortTransaction(); 59 | } 60 | ``` 61 | 62 | ### Deserializing 63 | 64 | ```ts 65 | import { MongoClient, ReadPreference, TransactionOptions } from 'mongodb'; 66 | import { sessionDeserializer } from 'mongodb-session-serializer'; 67 | 68 | export const transactionOptions: TransactionOptions = { 69 | readPreference: ReadPreference.primary, 70 | readConcern: { level: 'snapshot' }, 71 | writeConcern: { w: 'majority' }, 72 | 73 | maxCommitTimeMS: 15 * 60 * 1000, // 15 mins 74 | }; 75 | 76 | // Connection URL - https://github.com/vhidvz/mongo-rs 77 | const url = 78 | 'mongodb://root:password123@mongodb-primary:27017,mongodb-secondary-1:27018,mongodb-secondary-2:27019,mongodb-arbiter:27020/?replicaSet=rs0'; 79 | const client = new MongoClient(url); 80 | 81 | await client.connect(); 82 | 83 | const session = sessionDeserializer(client, /* serialized session */); 84 | 85 | try { 86 | session.startTransaction(transactionOptions); 87 | 88 | // do anything you want... 89 | 90 | await session.commitTransaction(); 91 | } catch { 92 | await session.abortTransaction(); 93 | } finally { 94 | await session.endSession(); 95 | } 96 | ``` 97 | 98 | ## License 99 | 100 | [MIT](https://github.com/vhidvz/mongodb-session-serializer/blob/main/LICENSE) 101 | -------------------------------------------------------------------------------- /coverage-badge.svg: -------------------------------------------------------------------------------- 1 | Coverage: 100%Coverage100% -------------------------------------------------------------------------------- /docker/README.md: -------------------------------------------------------------------------------- 1 | # Mongo-RS 2 | 3 | Mongo replication set with two nodes, run and start with docker-compose: 4 | 5 | ```sh 6 | docker-compose -f docker-compose.(6|7).yml up -d 7 | ``` 8 | 9 | > NOTE: It will take time to initiate for first time 10 | 11 | Add these lines to `/etc/hosts`: 12 | 13 | ```sh 14 | 127.0.0.1 mongodb-primary 15 | 127.0.0.1 mongodb-secondary 16 | ``` 17 | 18 | ## Connection URI 19 | 20 | `mongodb://root:password123@mongodb-primary:27017,mongodb-secondary:27018/?replicaSet=rs0&authSource=admin` 21 | 22 | ### Reference 23 | 24 | - [https://github.com/bitnami/containers/tree/main/bitnami/mongodb](https://github.com/bitnami/containers/tree/main/bitnami/mongodb) 25 | -------------------------------------------------------------------------------- /docker/docker-compose.6.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | services: 4 | mongodb-primary: 5 | image: bitnami/mongodb:6.0 6 | container_name: mongodb-primary 7 | ports: 8 | - 27017:27017 9 | environment: 10 | - MONGODB_ADVERTISED_HOSTNAME=mongodb-primary 11 | - MONGODB_REPLICA_SET_MODE=primary 12 | - MONGODB_ROOT_PASSWORD=password123 13 | - MONGODB_REPLICA_SET_NAME=rs0 14 | - MONGODB_REPLICA_SET_KEY=replicasetkey123 15 | - BITNAMI_DEBUG=true 16 | networks: 17 | - localnet 18 | 19 | mongodb-secondary: 20 | image: bitnami/mongodb:6.0 21 | container_name: mongodb-secondary 22 | ports: 23 | - 27018:27017 24 | environment: 25 | - MONGODB_ADVERTISED_HOSTNAME=mongodb-secondary 26 | - MONGODB_REPLICA_SET_MODE=secondary 27 | - MONGODB_INITIAL_PRIMARY_HOST=mongodb-primary 28 | - MONGODB_INITIAL_PRIMARY_PORT_NUMBER=27017 29 | - MONGODB_INITIAL_PRIMARY_ROOT_PASSWORD=password123 30 | - MONGODB_REPLICA_SET_NAME=rs0 31 | - MONGODB_REPLICA_SET_KEY=replicasetkey123 32 | depends_on: 33 | - mongodb-primary 34 | networks: 35 | - localnet 36 | 37 | mongodb-arbiter: 38 | image: bitnami/mongodb:6.0 39 | container_name: mongodb-arbiter 40 | ports: 41 | - 27019:27017 42 | environment: 43 | - MONGODB_ADVERTISED_HOSTNAME=mongodb-arbiter 44 | - MONGODB_REPLICA_SET_MODE=arbiter 45 | - MONGODB_INITIAL_PRIMARY_HOST=mongodb-primary 46 | - MONGODB_INITIAL_PRIMARY_PORT_NUMBER=27017 47 | - MONGODB_INITIAL_PRIMARY_ROOT_PASSWORD=password123 48 | - MONGODB_REPLICA_SET_NAME=rs0 49 | - MONGODB_REPLICA_SET_KEY=replicasetkey123 50 | depends_on: 51 | - mongodb-primary 52 | networks: 53 | - localnet 54 | 55 | networks: 56 | localnet: 57 | driver: bridge 58 | -------------------------------------------------------------------------------- /docker/docker-compose.7.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | services: 4 | mongodb-primary: 5 | image: bitnami/mongodb:7.0 6 | container_name: mongodb-primary 7 | ports: 8 | - 27017:27017 9 | environment: 10 | - MONGODB_ADVERTISED_HOSTNAME=mongodb-primary 11 | - MONGODB_REPLICA_SET_MODE=primary 12 | - MONGODB_ROOT_PASSWORD=password123 13 | - MONGODB_REPLICA_SET_NAME=rs0 14 | - MONGODB_REPLICA_SET_KEY=replicasetkey123 15 | - BITNAMI_DEBUG=true 16 | networks: 17 | - localnet 18 | 19 | mongodb-secondary: 20 | image: bitnami/mongodb:7.0 21 | container_name: mongodb-secondary 22 | ports: 23 | - 27018:27017 24 | environment: 25 | - MONGODB_ADVERTISED_HOSTNAME=mongodb-secondary 26 | - MONGODB_REPLICA_SET_MODE=secondary 27 | - MONGODB_INITIAL_PRIMARY_HOST=mongodb-primary 28 | - MONGODB_INITIAL_PRIMARY_PORT_NUMBER=27017 29 | - MONGODB_INITIAL_PRIMARY_ROOT_PASSWORD=password123 30 | - MONGODB_REPLICA_SET_NAME=rs0 31 | - MONGODB_REPLICA_SET_KEY=replicasetkey123 32 | depends_on: 33 | - mongodb-primary 34 | networks: 35 | - localnet 36 | 37 | mongodb-arbiter: 38 | image: bitnami/mongodb:7.0 39 | container_name: mongodb-arbiter 40 | ports: 41 | - 27019:27017 42 | environment: 43 | - MONGODB_ADVERTISED_HOSTNAME=mongodb-arbiter 44 | - MONGODB_REPLICA_SET_MODE=arbiter 45 | - MONGODB_INITIAL_PRIMARY_HOST=mongodb-primary 46 | - MONGODB_INITIAL_PRIMARY_PORT_NUMBER=27017 47 | - MONGODB_INITIAL_PRIMARY_ROOT_PASSWORD=password123 48 | - MONGODB_REPLICA_SET_NAME=rs0 49 | - MONGODB_REPLICA_SET_KEY=replicasetkey123 50 | depends_on: 51 | - mongodb-primary 52 | networks: 53 | - localnet 54 | 55 | networks: 56 | localnet: 57 | driver: bridge 58 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- 1 | TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. -------------------------------------------------------------------------------- /docs/assets/highlight.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --light-hl-0: #795E26; 3 | --dark-hl-0: #DCDCAA; 4 | --light-hl-1: #000000; 5 | --dark-hl-1: #D4D4D4; 6 | --light-hl-2: #A31515; 7 | --dark-hl-2: #CE9178; 8 | --light-hl-3: #0000FF; 9 | --dark-hl-3: #569CD6; 10 | --light-hl-4: #AF00DB; 11 | --dark-hl-4: #C586C0; 12 | --light-hl-5: #001080; 13 | --dark-hl-5: #9CDCFE; 14 | --light-hl-6: #0070C1; 15 | --dark-hl-6: #4FC1FF; 16 | --light-hl-7: #267F99; 17 | --dark-hl-7: #4EC9B0; 18 | --light-hl-8: #098658; 19 | --dark-hl-8: #B5CEA8; 20 | --light-hl-9: #008000; 21 | --dark-hl-9: #6A9955; 22 | --light-code-background: #FFFFFF; 23 | --dark-code-background: #1E1E1E; 24 | } 25 | 26 | @media (prefers-color-scheme: light) { :root { 27 | --hl-0: var(--light-hl-0); 28 | --hl-1: var(--light-hl-1); 29 | --hl-2: var(--light-hl-2); 30 | --hl-3: var(--light-hl-3); 31 | --hl-4: var(--light-hl-4); 32 | --hl-5: var(--light-hl-5); 33 | --hl-6: var(--light-hl-6); 34 | --hl-7: var(--light-hl-7); 35 | --hl-8: var(--light-hl-8); 36 | --hl-9: var(--light-hl-9); 37 | --code-background: var(--light-code-background); 38 | } } 39 | 40 | @media (prefers-color-scheme: dark) { :root { 41 | --hl-0: var(--dark-hl-0); 42 | --hl-1: var(--dark-hl-1); 43 | --hl-2: var(--dark-hl-2); 44 | --hl-3: var(--dark-hl-3); 45 | --hl-4: var(--dark-hl-4); 46 | --hl-5: var(--dark-hl-5); 47 | --hl-6: var(--dark-hl-6); 48 | --hl-7: var(--dark-hl-7); 49 | --hl-8: var(--dark-hl-8); 50 | --hl-9: var(--dark-hl-9); 51 | --code-background: var(--dark-code-background); 52 | } } 53 | 54 | :root[data-theme='light'] { 55 | --hl-0: var(--light-hl-0); 56 | --hl-1: var(--light-hl-1); 57 | --hl-2: var(--light-hl-2); 58 | --hl-3: var(--light-hl-3); 59 | --hl-4: var(--light-hl-4); 60 | --hl-5: var(--light-hl-5); 61 | --hl-6: var(--light-hl-6); 62 | --hl-7: var(--light-hl-7); 63 | --hl-8: var(--light-hl-8); 64 | --hl-9: var(--light-hl-9); 65 | --code-background: var(--light-code-background); 66 | } 67 | 68 | :root[data-theme='dark'] { 69 | --hl-0: var(--dark-hl-0); 70 | --hl-1: var(--dark-hl-1); 71 | --hl-2: var(--dark-hl-2); 72 | --hl-3: var(--dark-hl-3); 73 | --hl-4: var(--dark-hl-4); 74 | --hl-5: var(--dark-hl-5); 75 | --hl-6: var(--dark-hl-6); 76 | --hl-7: var(--dark-hl-7); 77 | --hl-8: var(--dark-hl-8); 78 | --hl-9: var(--dark-hl-9); 79 | --code-background: var(--dark-code-background); 80 | } 81 | 82 | .hl-0 { color: var(--hl-0); } 83 | .hl-1 { color: var(--hl-1); } 84 | .hl-2 { color: var(--hl-2); } 85 | .hl-3 { color: var(--hl-3); } 86 | .hl-4 { color: var(--hl-4); } 87 | .hl-5 { color: var(--hl-5); } 88 | .hl-6 { color: var(--hl-6); } 89 | .hl-7 { color: var(--hl-7); } 90 | .hl-8 { color: var(--hl-8); } 91 | .hl-9 { color: var(--hl-9); } 92 | pre, code { background: var(--code-background); } 93 | -------------------------------------------------------------------------------- /docs/assets/navigation.js: -------------------------------------------------------------------------------- 1 | window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAA4uuVipJrShRslIKTi3KTMzJrEpNCU4tLs7Mz1PSUSpILMkASpVUFqQW62Mo0Msoyc0BqsrOzEtRsjIysDQ3NDWq1YGbWAxR5pJaDNNZhDAzrTQvuQQoW6yPRRmqyWYmmIYGE2NkMG4DYwHRmLm1+QAAAA==" -------------------------------------------------------------------------------- /docs/assets/search.js: -------------------------------------------------------------------------------- 1 | window.searchData = "data:application/octet-stream;base64,H4sIAAAAAAAAA5WUy26DMBBF/2W6tQg2dqqw7qbrSN0gFKHgqFZ5CZO+EP/ewQQcGhOFDdIw5947npi0UJdfGsKohQ9VpBBuOYEiySWEoKXWqiz2slZJpn5lDQTOdYad07k4NtjSmxvGe2/yDMFjlmhsIgwdWTZ/kfoB+2vqbgDzd89UsCllmivdD05TRvNTSb256d8fX4hgO3kfDr3HQ4ZPE3vlS6BKalk0zjFtKPWZ3ZpK1+R5Bn8w0rvMuJC89qzeugNP6TEBDJffELbwKWuzjBCYF3g7NDgpmaX9dR3GQvsyz3vL+NJ7k8emrHtiQDY+kMgnVHjc53FMolFhGuaFwShW1IXRGcawYi6MzbAAq8CFBTOMY8VdGJ9hAivhwoTBzMZwVY1MX4fN4dnHC9fC4bLOYPwpWwjw0XV2eX3V+/bXxQq4FfAFwfRVpnr8vKyeWT1b1BtVOvsTsA7UOtD7Dm69b/X+gv7/loSVCJcEl12pSmaqQCaKu+4PepZ4eUEFAAA="; -------------------------------------------------------------------------------- /docs/coverage/coverage-summary.json: -------------------------------------------------------------------------------- 1 | {"total": {"lines":{"total":66,"covered":66,"skipped":0,"pct":100},"statements":{"total":66,"covered":66,"skipped":0,"pct":100},"functions":{"total":6,"covered":6,"skipped":0,"pct":100},"branches":{"total":10,"covered":10,"skipped":0,"pct":100},"branchesTrue":{"total":0,"covered":0,"skipped":0,"pct":"Unknown"}} 2 | ,"/home/vahid/WorkSpace/github/mongodb-session-serializer/src/index.ts": {"lines":{"total":2,"covered":2,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":2,"covered":2,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} 3 | ,"/home/vahid/WorkSpace/github/mongodb-session-serializer/src/mongodb-session.ts": {"lines":{"total":30,"covered":30,"skipped":0,"pct":100},"functions":{"total":3,"covered":3,"skipped":0,"pct":100},"statements":{"total":30,"covered":30,"skipped":0,"pct":100},"branches":{"total":5,"covered":5,"skipped":0,"pct":100}} 4 | ,"/home/vahid/WorkSpace/github/mongodb-session-serializer/src/mongoose-session.ts": {"lines":{"total":33,"covered":33,"skipped":0,"pct":100},"functions":{"total":3,"covered":3,"skipped":0,"pct":100},"statements":{"total":33,"covered":33,"skipped":0,"pct":100},"branches":{"total":5,"covered":5,"skipped":0,"pct":100}} 5 | ,"/home/vahid/WorkSpace/github/mongodb-session-serializer/src/type.ts": {"lines":{"total":1,"covered":1,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":1,"covered":1,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} 6 | } 7 | -------------------------------------------------------------------------------- /docs/coverage/lcov-report/base.css: -------------------------------------------------------------------------------- 1 | body, html { 2 | margin:0; padding: 0; 3 | height: 100%; 4 | } 5 | body { 6 | font-family: Helvetica Neue, Helvetica, Arial; 7 | font-size: 14px; 8 | color:#333; 9 | } 10 | .small { font-size: 12px; } 11 | *, *:after, *:before { 12 | -webkit-box-sizing:border-box; 13 | -moz-box-sizing:border-box; 14 | box-sizing:border-box; 15 | } 16 | h1 { font-size: 20px; margin: 0;} 17 | h2 { font-size: 14px; } 18 | pre { 19 | font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; 20 | margin: 0; 21 | padding: 0; 22 | -moz-tab-size: 2; 23 | -o-tab-size: 2; 24 | tab-size: 2; 25 | } 26 | a { color:#0074D9; text-decoration:none; } 27 | a:hover { text-decoration:underline; } 28 | .strong { font-weight: bold; } 29 | .space-top1 { padding: 10px 0 0 0; } 30 | .pad2y { padding: 20px 0; } 31 | .pad1y { padding: 10px 0; } 32 | .pad2x { padding: 0 20px; } 33 | .pad2 { padding: 20px; } 34 | .pad1 { padding: 10px; } 35 | .space-left2 { padding-left:55px; } 36 | .space-right2 { padding-right:20px; } 37 | .center { text-align:center; } 38 | .clearfix { display:block; } 39 | .clearfix:after { 40 | content:''; 41 | display:block; 42 | height:0; 43 | clear:both; 44 | visibility:hidden; 45 | } 46 | .fl { float: left; } 47 | @media only screen and (max-width:640px) { 48 | .col3 { width:100%; max-width:100%; } 49 | .hide-mobile { display:none!important; } 50 | } 51 | 52 | .quiet { 53 | color: #7f7f7f; 54 | color: rgba(0,0,0,0.5); 55 | } 56 | .quiet a { opacity: 0.7; } 57 | 58 | .fraction { 59 | font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; 60 | font-size: 10px; 61 | color: #555; 62 | background: #E8E8E8; 63 | padding: 4px 5px; 64 | border-radius: 3px; 65 | vertical-align: middle; 66 | } 67 | 68 | div.path a:link, div.path a:visited { color: #333; } 69 | table.coverage { 70 | border-collapse: collapse; 71 | margin: 10px 0 0 0; 72 | padding: 0; 73 | } 74 | 75 | table.coverage td { 76 | margin: 0; 77 | padding: 0; 78 | vertical-align: top; 79 | } 80 | table.coverage td.line-count { 81 | text-align: right; 82 | padding: 0 5px 0 20px; 83 | } 84 | table.coverage td.line-coverage { 85 | text-align: right; 86 | padding-right: 10px; 87 | min-width:20px; 88 | } 89 | 90 | table.coverage td span.cline-any { 91 | display: inline-block; 92 | padding: 0 5px; 93 | width: 100%; 94 | } 95 | .missing-if-branch { 96 | display: inline-block; 97 | margin-right: 5px; 98 | border-radius: 3px; 99 | position: relative; 100 | padding: 0 4px; 101 | background: #333; 102 | color: yellow; 103 | } 104 | 105 | .skip-if-branch { 106 | display: none; 107 | margin-right: 10px; 108 | position: relative; 109 | padding: 0 4px; 110 | background: #ccc; 111 | color: white; 112 | } 113 | .missing-if-branch .typ, .skip-if-branch .typ { 114 | color: inherit !important; 115 | } 116 | .coverage-summary { 117 | border-collapse: collapse; 118 | width: 100%; 119 | } 120 | .coverage-summary tr { border-bottom: 1px solid #bbb; } 121 | .keyline-all { border: 1px solid #ddd; } 122 | .coverage-summary td, .coverage-summary th { padding: 10px; } 123 | .coverage-summary tbody { border: 1px solid #bbb; } 124 | .coverage-summary td { border-right: 1px solid #bbb; } 125 | .coverage-summary td:last-child { border-right: none; } 126 | .coverage-summary th { 127 | text-align: left; 128 | font-weight: normal; 129 | white-space: nowrap; 130 | } 131 | .coverage-summary th.file { border-right: none !important; } 132 | .coverage-summary th.pct { } 133 | .coverage-summary th.pic, 134 | .coverage-summary th.abs, 135 | .coverage-summary td.pct, 136 | .coverage-summary td.abs { text-align: right; } 137 | .coverage-summary td.file { white-space: nowrap; } 138 | .coverage-summary td.pic { min-width: 120px !important; } 139 | .coverage-summary tfoot td { } 140 | 141 | .coverage-summary .sorter { 142 | height: 10px; 143 | width: 7px; 144 | display: inline-block; 145 | margin-left: 0.5em; 146 | background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; 147 | } 148 | .coverage-summary .sorted .sorter { 149 | background-position: 0 -20px; 150 | } 151 | .coverage-summary .sorted-desc .sorter { 152 | background-position: 0 -10px; 153 | } 154 | .status-line { height: 10px; } 155 | /* yellow */ 156 | .cbranch-no { background: yellow !important; color: #111; } 157 | /* dark red */ 158 | .red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } 159 | .low .chart { border:1px solid #C21F39 } 160 | .highlighted, 161 | .highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ 162 | background: #C21F39 !important; 163 | } 164 | /* medium red */ 165 | .cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } 166 | /* light red */ 167 | .low, .cline-no { background:#FCE1E5 } 168 | /* light green */ 169 | .high, .cline-yes { background:rgb(230,245,208) } 170 | /* medium green */ 171 | .cstat-yes { background:rgb(161,215,106) } 172 | /* dark green */ 173 | .status-line.high, .high .cover-fill { background:rgb(77,146,33) } 174 | .high .chart { border:1px solid rgb(77,146,33) } 175 | /* dark yellow (gold) */ 176 | .status-line.medium, .medium .cover-fill { background: #f9cd0b; } 177 | .medium .chart { border:1px solid #f9cd0b; } 178 | /* light yellow */ 179 | .medium { background: #fff4c2; } 180 | 181 | .cstat-skip { background: #ddd; color: #111; } 182 | .fstat-skip { background: #ddd; color: #111 !important; } 183 | .cbranch-skip { background: #ddd !important; color: #111; } 184 | 185 | span.cline-neutral { background: #eaeaea; } 186 | 187 | .coverage-summary td.empty { 188 | opacity: .5; 189 | padding-top: 4px; 190 | padding-bottom: 4px; 191 | line-height: 1; 192 | color: #888; 193 | } 194 | 195 | .cover-fill, .cover-empty { 196 | display:inline-block; 197 | height: 12px; 198 | } 199 | .chart { 200 | line-height: 0; 201 | } 202 | .cover-empty { 203 | background: white; 204 | } 205 | .cover-full { 206 | border-right: none !important; 207 | } 208 | pre.prettyprint { 209 | border: none !important; 210 | padding: 0 !important; 211 | margin: 0 !important; 212 | } 213 | .com { color: #999 !important; } 214 | .ignore-none { color: #999; font-weight: normal; } 215 | 216 | .wrapper { 217 | min-height: 100%; 218 | height: auto !important; 219 | height: 100%; 220 | margin: 0 auto -48px; 221 | } 222 | .footer, .push { 223 | height: 48px; 224 | } 225 | -------------------------------------------------------------------------------- /docs/coverage/lcov-report/block-navigation.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | var jumpToCode = (function init() { 3 | // Classes of code we would like to highlight in the file view 4 | var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; 5 | 6 | // Elements to highlight in the file listing view 7 | var fileListingElements = ['td.pct.low']; 8 | 9 | // We don't want to select elements that are direct descendants of another match 10 | var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` 11 | 12 | // Selecter that finds elements on the page to which we can jump 13 | var selector = 14 | fileListingElements.join(', ') + 15 | ', ' + 16 | notSelector + 17 | missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` 18 | 19 | // The NodeList of matching elements 20 | var missingCoverageElements = document.querySelectorAll(selector); 21 | 22 | var currentIndex; 23 | 24 | function toggleClass(index) { 25 | missingCoverageElements 26 | .item(currentIndex) 27 | .classList.remove('highlighted'); 28 | missingCoverageElements.item(index).classList.add('highlighted'); 29 | } 30 | 31 | function makeCurrent(index) { 32 | toggleClass(index); 33 | currentIndex = index; 34 | missingCoverageElements.item(index).scrollIntoView({ 35 | behavior: 'smooth', 36 | block: 'center', 37 | inline: 'center' 38 | }); 39 | } 40 | 41 | function goToPrevious() { 42 | var nextIndex = 0; 43 | if (typeof currentIndex !== 'number' || currentIndex === 0) { 44 | nextIndex = missingCoverageElements.length - 1; 45 | } else if (missingCoverageElements.length > 1) { 46 | nextIndex = currentIndex - 1; 47 | } 48 | 49 | makeCurrent(nextIndex); 50 | } 51 | 52 | function goToNext() { 53 | var nextIndex = 0; 54 | 55 | if ( 56 | typeof currentIndex === 'number' && 57 | currentIndex < missingCoverageElements.length - 1 58 | ) { 59 | nextIndex = currentIndex + 1; 60 | } 61 | 62 | makeCurrent(nextIndex); 63 | } 64 | 65 | return function jump(event) { 66 | if ( 67 | document.getElementById('fileSearch') === document.activeElement && 68 | document.activeElement != null 69 | ) { 70 | // if we're currently focused on the search input, we don't want to navigate 71 | return; 72 | } 73 | 74 | switch (event.which) { 75 | case 78: // n 76 | case 74: // j 77 | goToNext(); 78 | break; 79 | case 66: // b 80 | case 75: // k 81 | case 80: // p 82 | goToPrevious(); 83 | break; 84 | } 85 | }; 86 | })(); 87 | window.addEventListener('keydown', jumpToCode); 88 | -------------------------------------------------------------------------------- /docs/coverage/lcov-report/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vhidvz/mongodb-session-serializer/1532571d93287fdfb70238295208c3180497650c/docs/coverage/lcov-report/favicon.png -------------------------------------------------------------------------------- /docs/coverage/lcov-report/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Code coverage report for All files 7 | 8 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 20 |
21 |
22 |

All files

23 |
24 | 25 |
26 | 100% 27 | Statements 28 | 66/66 29 |
30 | 31 | 32 |
33 | 100% 34 | Branches 35 | 10/10 36 |
37 | 38 | 39 |
40 | 100% 41 | Functions 42 | 6/6 43 |
44 | 45 | 46 |
47 | 100% 48 | Lines 49 | 66/66 50 |
51 | 52 | 53 |
54 |

55 | Press n or j to go to the next uncovered block, b, p or k for the previous block. 56 |

57 | 63 |
64 |
65 |
66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 |
FileStatementsBranchesFunctionsLines
index.ts 84 |
85 |
100%2/2100%0/0100%0/0100%2/2
mongodb-session.ts 99 |
100 |
100%30/30100%5/5100%3/3100%30/30
mongoose-session.ts 114 |
115 |
100%33/33100%5/5100%3/3100%33/33
type.ts 129 |
130 |
100%1/1100%0/0100%0/0100%1/1
143 |
144 |
145 |
146 | 151 | 152 | 157 | 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /docs/coverage/lcov-report/index.ts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Code coverage report for index.ts 7 | 8 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 20 |
21 |
22 |

All files index.ts

23 |
24 | 25 |
26 | 100% 27 | Statements 28 | 2/2 29 |
30 | 31 | 32 |
33 | 100% 34 | Branches 35 | 0/0 36 |
37 | 38 | 39 |
40 | 100% 41 | Functions 42 | 0/0 43 |
44 | 45 | 46 |
47 | 100% 48 | Lines 49 | 2/2 50 |
51 | 52 | 53 |
54 |

55 | Press n or j to go to the next uncovered block, b, p or k for the previous block. 56 |

57 | 63 |
64 |
65 |

66 | 
1 67 | 2 68 | 31x 69 | 1x 70 |  
export * from './type';
71 | export * from './mongodb-session';
72 |  
73 | 74 |
75 |
76 | 81 | 82 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /docs/coverage/lcov-report/mongodb-session.ts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Code coverage report for mongodb-session.ts 7 | 8 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 20 |
21 |
22 |

All files mongodb-session.ts

23 |
24 | 25 |
26 | 100% 27 | Statements 28 | 30/30 29 |
30 | 31 | 32 |
33 | 100% 34 | Branches 35 | 5/5 36 |
37 | 38 | 39 |
40 | 100% 41 | Functions 42 | 3/3 43 |
44 | 45 | 46 |
47 | 100% 48 | Lines 49 | 30/30 50 |
51 | 52 | 53 |
54 |

55 | Press n or j to go to the next uncovered block, b, p or k for the previous block. 56 |

57 | 63 |
64 |
65 |

 66 | 
1 67 | 2 68 | 3 69 | 4 70 | 5 71 | 6 72 | 7 73 | 8 74 | 9 75 | 10 76 | 11 77 | 12 78 | 13 79 | 14 80 | 15 81 | 16 82 | 17 83 | 18 84 | 19 85 | 20 86 | 21 87 | 22 88 | 23 89 | 24 90 | 25 91 | 26 92 | 27 93 | 28 94 | 29 95 | 30 96 | 311x 97 | 1x 98 | 1x 99 | 1x 100 | 1x 101 | 1x 102 | 1x 103 | 1x 104 | 1x 105 | 2x 106 | 2x 107 | 2x 108 | 2x 109 | 2x 110 | 1x 111 | 1x 112 | 1x 113 | 1x 114 | 1x 115 | 1x 116 | 1x 117 | 1x 118 | 1x 119 | 1x 120 | 1x 121 | 1x 122 | 1x 123 | 1x 124 | 1x 125 | 1x 126 |  
import {
127 |   ServerSessionPool,
128 |   ServerSession,
129 |   ClientSession as SessionClient,
130 | } from 'mongodb/lib/sessions';
131 | import { Binary, ClientSession, ClientSessionOptions, MongoClient } from 'mongodb';
132 |  
133 | import { SerializedSession } from './type';
134 |  
135 | export function sessionSerializer(session: ClientSession): SerializedSession {
136 |   // eslint-disable-next-line @typescript-eslint/no-unused-vars
137 |   const { id } = session.id ?? { id: { toString: (_) => '', sub_type: -1 } };
138 |   return { id: id.toString('hex'), type: id.sub_type };
139 | }
140 |  
141 | export function sessionDeserializer(
142 |   client: MongoClient,
143 |   session: SerializedSession,
144 |   options?: ClientSessionOptions,
145 | ): ClientSession {
146 |   const sessionPool = new ServerSessionPool(client);
147 |  
148 |   const { id, type } = session;
149 |   const serverSession = new ServerSession();
150 |   serverSession.id = { id: Binary.createFromHexString(id, type) };
151 |  
152 |   sessionPool.sessions.push(serverSession);
153 |  
154 |   return new SessionClient(client, sessionPool, { ...options, explicit: true });
155 | }
156 |  
157 | 158 |
159 |
160 | 165 | 166 | 171 | 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /docs/coverage/lcov-report/mongoose-session.ts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Code coverage report for mongoose-session.ts 7 | 8 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 20 |
21 |
22 |

All files mongoose-session.ts

23 |
24 | 25 |
26 | 100% 27 | Statements 28 | 33/33 29 |
30 | 31 | 32 |
33 | 100% 34 | Branches 35 | 5/5 36 |
37 | 38 | 39 |
40 | 100% 41 | Functions 42 | 3/3 43 |
44 | 45 | 46 |
47 | 100% 48 | Lines 49 | 33/33 50 |
51 | 52 | 53 |
54 |

55 | Press n or j to go to the next uncovered block, b, p or k for the previous block. 56 |

57 | 63 |
64 |
65 |

 66 | 
1 67 | 2 68 | 3 69 | 4 70 | 5 71 | 6 72 | 7 73 | 8 74 | 9 75 | 10 76 | 11 77 | 12 78 | 13 79 | 14 80 | 15 81 | 16 82 | 17 83 | 18 84 | 19 85 | 20 86 | 21 87 | 22 88 | 23 89 | 24 90 | 25 91 | 26 92 | 27 93 | 28 94 | 29 95 | 30 96 | 31 97 | 32 98 | 33 99 | 341x 100 | 1x 101 | 1x 102 | 1x 103 | 1x 104 | 1x 105 | 1x 106 | 1x 107 | 1x 108 | 1x 109 | 1x 110 | 1x 111 | 2x 112 | 2x 113 | 2x 114 | 2x 115 | 2x 116 | 1x 117 | 1x 118 | 1x 119 | 1x 120 | 1x 121 | 1x 122 | 1x 123 | 1x 124 | 1x 125 | 1x 126 | 1x 127 | 1x 128 | 1x 129 | 1x 130 | 1x 131 | 1x 132 |  
import {
133 |   ServerSessionPool,
134 |   ServerSession,
135 |   ClientSession as SessionClient,
136 | } from 'mongodb/lib/sessions';
137 | import { ClientSession, ClientSessionOptions, Connection } from 'mongoose';
138 | import { Binary } from 'mongodb';
139 |  
140 | import { SerializedSession } from './type';
141 |  
142 | export * from './type';
143 |  
144 | export function sessionSerializer(session: ClientSession): SerializedSession {
145 |   // eslint-disable-next-line @typescript-eslint/no-unused-vars
146 |   const { id } = session.id ?? { id: { toString: (_) => '', sub_type: -1 } };
147 |   return { id: id.toString('hex'), type: id.sub_type };
148 | }
149 |  
150 | export function sessionDeserializer(
151 |   client: Connection,
152 |   session: SerializedSession,
153 |   options?: ClientSessionOptions,
154 | ): ClientSession {
155 |   const sessionPool = new ServerSessionPool(client);
156 |  
157 |   const { id, type } = session;
158 |   const serverSession = new ServerSession();
159 |   serverSession.id = { id: Binary.createFromHexString(id, type) };
160 |  
161 |   sessionPool.sessions.push(serverSession);
162 |  
163 |   return new SessionClient(client, sessionPool, options);
164 | }
165 |  
166 | 167 |
168 |
169 | 174 | 175 | 180 | 181 | 182 | 183 | 184 | -------------------------------------------------------------------------------- /docs/coverage/lcov-report/prettify.css: -------------------------------------------------------------------------------- 1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} 2 | -------------------------------------------------------------------------------- /docs/coverage/lcov-report/prettify.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); 3 | -------------------------------------------------------------------------------- /docs/coverage/lcov-report/sort-arrow-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vhidvz/mongodb-session-serializer/1532571d93287fdfb70238295208c3180497650c/docs/coverage/lcov-report/sort-arrow-sprite.png -------------------------------------------------------------------------------- /docs/coverage/lcov-report/sorter.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | var addSorting = (function() { 3 | 'use strict'; 4 | var cols, 5 | currentSort = { 6 | index: 0, 7 | desc: false 8 | }; 9 | 10 | // returns the summary table element 11 | function getTable() { 12 | return document.querySelector('.coverage-summary'); 13 | } 14 | // returns the thead element of the summary table 15 | function getTableHeader() { 16 | return getTable().querySelector('thead tr'); 17 | } 18 | // returns the tbody element of the summary table 19 | function getTableBody() { 20 | return getTable().querySelector('tbody'); 21 | } 22 | // returns the th element for nth column 23 | function getNthColumn(n) { 24 | return getTableHeader().querySelectorAll('th')[n]; 25 | } 26 | 27 | function onFilterInput() { 28 | const searchValue = document.getElementById('fileSearch').value; 29 | const rows = document.getElementsByTagName('tbody')[0].children; 30 | for (let i = 0; i < rows.length; i++) { 31 | const row = rows[i]; 32 | if ( 33 | row.textContent 34 | .toLowerCase() 35 | .includes(searchValue.toLowerCase()) 36 | ) { 37 | row.style.display = ''; 38 | } else { 39 | row.style.display = 'none'; 40 | } 41 | } 42 | } 43 | 44 | // loads the search box 45 | function addSearchBox() { 46 | var template = document.getElementById('filterTemplate'); 47 | var templateClone = template.content.cloneNode(true); 48 | templateClone.getElementById('fileSearch').oninput = onFilterInput; 49 | template.parentElement.appendChild(templateClone); 50 | } 51 | 52 | // loads all columns 53 | function loadColumns() { 54 | var colNodes = getTableHeader().querySelectorAll('th'), 55 | colNode, 56 | cols = [], 57 | col, 58 | i; 59 | 60 | for (i = 0; i < colNodes.length; i += 1) { 61 | colNode = colNodes[i]; 62 | col = { 63 | key: colNode.getAttribute('data-col'), 64 | sortable: !colNode.getAttribute('data-nosort'), 65 | type: colNode.getAttribute('data-type') || 'string' 66 | }; 67 | cols.push(col); 68 | if (col.sortable) { 69 | col.defaultDescSort = col.type === 'number'; 70 | colNode.innerHTML = 71 | colNode.innerHTML + ''; 72 | } 73 | } 74 | return cols; 75 | } 76 | // attaches a data attribute to every tr element with an object 77 | // of data values keyed by column name 78 | function loadRowData(tableRow) { 79 | var tableCols = tableRow.querySelectorAll('td'), 80 | colNode, 81 | col, 82 | data = {}, 83 | i, 84 | val; 85 | for (i = 0; i < tableCols.length; i += 1) { 86 | colNode = tableCols[i]; 87 | col = cols[i]; 88 | val = colNode.getAttribute('data-value'); 89 | if (col.type === 'number') { 90 | val = Number(val); 91 | } 92 | data[col.key] = val; 93 | } 94 | return data; 95 | } 96 | // loads all row data 97 | function loadData() { 98 | var rows = getTableBody().querySelectorAll('tr'), 99 | i; 100 | 101 | for (i = 0; i < rows.length; i += 1) { 102 | rows[i].data = loadRowData(rows[i]); 103 | } 104 | } 105 | // sorts the table using the data for the ith column 106 | function sortByIndex(index, desc) { 107 | var key = cols[index].key, 108 | sorter = function(a, b) { 109 | a = a.data[key]; 110 | b = b.data[key]; 111 | return a < b ? -1 : a > b ? 1 : 0; 112 | }, 113 | finalSorter = sorter, 114 | tableBody = document.querySelector('.coverage-summary tbody'), 115 | rowNodes = tableBody.querySelectorAll('tr'), 116 | rows = [], 117 | i; 118 | 119 | if (desc) { 120 | finalSorter = function(a, b) { 121 | return -1 * sorter(a, b); 122 | }; 123 | } 124 | 125 | for (i = 0; i < rowNodes.length; i += 1) { 126 | rows.push(rowNodes[i]); 127 | tableBody.removeChild(rowNodes[i]); 128 | } 129 | 130 | rows.sort(finalSorter); 131 | 132 | for (i = 0; i < rows.length; i += 1) { 133 | tableBody.appendChild(rows[i]); 134 | } 135 | } 136 | // removes sort indicators for current column being sorted 137 | function removeSortIndicators() { 138 | var col = getNthColumn(currentSort.index), 139 | cls = col.className; 140 | 141 | cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); 142 | col.className = cls; 143 | } 144 | // adds sort indicators for current column being sorted 145 | function addSortIndicators() { 146 | getNthColumn(currentSort.index).className += currentSort.desc 147 | ? ' sorted-desc' 148 | : ' sorted'; 149 | } 150 | // adds event listeners for all sorter widgets 151 | function enableUI() { 152 | var i, 153 | el, 154 | ithSorter = function ithSorter(i) { 155 | var col = cols[i]; 156 | 157 | return function() { 158 | var desc = col.defaultDescSort; 159 | 160 | if (currentSort.index === i) { 161 | desc = !currentSort.desc; 162 | } 163 | sortByIndex(i, desc); 164 | removeSortIndicators(); 165 | currentSort.index = i; 166 | currentSort.desc = desc; 167 | addSortIndicators(); 168 | }; 169 | }; 170 | for (i = 0; i < cols.length; i += 1) { 171 | if (cols[i].sortable) { 172 | // add the click event handler on the th so users 173 | // dont have to click on those tiny arrows 174 | el = getNthColumn(i).querySelector('.sorter').parentElement; 175 | if (el.addEventListener) { 176 | el.addEventListener('click', ithSorter(i)); 177 | } else { 178 | el.attachEvent('onclick', ithSorter(i)); 179 | } 180 | } 181 | } 182 | } 183 | // adds sorting functionality to the UI 184 | return function() { 185 | if (!getTable()) { 186 | return; 187 | } 188 | cols = loadColumns(); 189 | loadData(); 190 | addSearchBox(); 191 | addSortIndicators(); 192 | enableUI(); 193 | }; 194 | })(); 195 | 196 | window.addEventListener('load', addSorting); 197 | -------------------------------------------------------------------------------- /docs/coverage/lcov-report/type.ts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Code coverage report for type.ts 7 | 8 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 20 |
21 |
22 |

All files type.ts

23 |
24 | 25 |
26 | 100% 27 | Statements 28 | 1/1 29 |
30 | 31 | 32 |
33 | 100% 34 | Branches 35 | 0/0 36 |
37 | 38 | 39 |
40 | 100% 41 | Functions 42 | 0/0 43 |
44 | 45 | 46 |
47 | 100% 48 | Lines 49 | 1/1 50 |
51 | 52 | 53 |
54 |

55 | Press n or j to go to the next uncovered block, b, p or k for the previous block. 56 |

57 | 63 |
64 |
65 |

66 | 
1 67 | 21x 68 |  
export type SerializedSession = { id: string; type: number };
69 |  
70 | 71 |
72 |
73 | 78 | 79 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /docs/coverage/lcov.info: -------------------------------------------------------------------------------- 1 | TN: 2 | SF:src/index.ts 3 | FNF:0 4 | FNH:0 5 | DA:1,1 6 | DA:2,1 7 | LF:2 8 | LH:2 9 | BRF:0 10 | BRH:0 11 | end_of_record 12 | TN: 13 | SF:src/mongodb-session.ts 14 | FN:10,sessionSerializer 15 | FN:12,toString 16 | FN:16,sessionDeserializer 17 | FNF:3 18 | FNH:3 19 | FNDA:2,sessionSerializer 20 | FNDA:1,toString 21 | FNDA:1,sessionDeserializer 22 | DA:1,1 23 | DA:2,1 24 | DA:3,1 25 | DA:4,1 26 | DA:5,1 27 | DA:6,1 28 | DA:7,1 29 | DA:8,1 30 | DA:9,1 31 | DA:10,2 32 | DA:11,2 33 | DA:12,2 34 | DA:13,2 35 | DA:14,2 36 | DA:15,1 37 | DA:16,1 38 | DA:17,1 39 | DA:18,1 40 | DA:19,1 41 | DA:20,1 42 | DA:21,1 43 | DA:22,1 44 | DA:23,1 45 | DA:24,1 46 | DA:25,1 47 | DA:26,1 48 | DA:27,1 49 | DA:28,1 50 | DA:29,1 51 | DA:30,1 52 | LF:30 53 | LH:30 54 | BRDA:10,0,0,2 55 | BRDA:12,1,0,1 56 | BRDA:12,2,0,1 57 | BRDA:12,3,0,1 58 | BRDA:16,4,0,1 59 | BRF:5 60 | BRH:5 61 | end_of_record 62 | TN: 63 | SF:src/mongoose-session.ts 64 | FN:13,sessionSerializer 65 | FN:15,toString 66 | FN:19,sessionDeserializer 67 | FNF:3 68 | FNH:3 69 | FNDA:2,sessionSerializer 70 | FNDA:1,toString 71 | FNDA:1,sessionDeserializer 72 | DA:1,1 73 | DA:2,1 74 | DA:3,1 75 | DA:4,1 76 | DA:5,1 77 | DA:6,1 78 | DA:7,1 79 | DA:8,1 80 | DA:9,1 81 | DA:10,1 82 | DA:11,1 83 | DA:12,1 84 | DA:13,2 85 | DA:14,2 86 | DA:15,2 87 | DA:16,2 88 | DA:17,2 89 | DA:18,1 90 | DA:19,1 91 | DA:20,1 92 | DA:21,1 93 | DA:22,1 94 | DA:23,1 95 | DA:24,1 96 | DA:25,1 97 | DA:26,1 98 | DA:27,1 99 | DA:28,1 100 | DA:29,1 101 | DA:30,1 102 | DA:31,1 103 | DA:32,1 104 | DA:33,1 105 | LF:33 106 | LH:33 107 | BRDA:13,0,0,2 108 | BRDA:15,1,0,1 109 | BRDA:15,2,0,1 110 | BRDA:15,3,0,1 111 | BRDA:19,4,0,1 112 | BRF:5 113 | BRH:5 114 | end_of_record 115 | TN: 116 | SF:src/type.ts 117 | FNF:0 118 | FNH:0 119 | DA:1,1 120 | LF:1 121 | LH:1 122 | BRF:0 123 | BRH:0 124 | end_of_record 125 | -------------------------------------------------------------------------------- /docs/functions/sessionDeserializer.html: -------------------------------------------------------------------------------- 1 | sessionDeserializer | mongodb-session-serializer
2 |
3 | 10 |
11 |
12 |
13 |
14 | 17 |

Function sessionDeserializer

18 |
19 |
    20 | 21 |
  • 22 |
    23 |

    Parameters

    24 |
      25 |
    • 26 |
      client: MongoClient
    • 27 |
    • 28 |
      session: SerializedSession
    • 29 |
    • 30 |
      Optional options: ClientSessionOptions
    31 |

    Returns ClientSession

34 |
35 | 49 |
55 |
56 |

Generated using TypeDoc

57 |
-------------------------------------------------------------------------------- /docs/functions/sessionSerializer.html: -------------------------------------------------------------------------------- 1 | sessionSerializer | mongodb-session-serializer
2 |
3 | 10 |
11 |
12 |
13 |
14 | 17 |

Function sessionSerializer

18 |
19 |
30 |
31 | 45 |
51 |
52 |

Generated using TypeDoc

53 |
-------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | mongodb-session-serializer
2 |
3 | 10 |
11 |
12 |
13 |
14 |

mongodb-session-serializer

15 |

MongoDB Session Serializer/Deserializer

npm 16 | npm 17 | Coverage 18 | GitHub 19 | documentation 20 | Build, Test and Publish

21 |

This package helps you serialize a MongoDB session and use it in a microservices environment on the same MongoDB infrastructure to have ACID at the database level.

22 |
    23 |
  • Support for multi-database transactions on the same MongoDB infrastructure
  • 24 |
25 |

Quick Start Guide

26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 |
#NodeJS DriverMongoDB CommunityTest
15.x.x6.xOK
26.x.x7.xOK
47 |

Installation

npm install --save mongodb mongodb-session-serializer
48 | 
49 |

Serializing

import { MongoClient, ReadPreference, TransactionOptions } from 'mongodb';
import { sessionSerializer } from 'mongodb-session-serializer';

export const transactionOptions: TransactionOptions = {
readPreference: ReadPreference.primary,
readConcern: { level: 'snapshot' },
writeConcern: { w: 'majority' },

maxCommitTimeMS: 15 * 60 * 1000, // 15 mins
};

// Connection URL - https://github.com/vhidvz/mongo-rs
const url =
'mongodb://root:password123@mongodb-primary:27017,mongodb-secondary-1:27018,mongodb-secondary-2:27019,mongodb-arbiter:27020/?replicaSet=rs0';
const client = new MongoClient(url);

await client.connect();

const session = await client.startSession();

try {
session.startTransaction(transactionOptions);

// do anything you want...

const serializedSession = sessionSerializer(session);
// send the serialized session to another microservice
} catch {
await session.abortTransaction();
} 50 |
51 |

Deserializing

import { MongoClient, ReadPreference, TransactionOptions } from 'mongodb';
import { sessionDeserializer } from 'mongodb-session-serializer';

export const transactionOptions: TransactionOptions = {
readPreference: ReadPreference.primary,
readConcern: { level: 'snapshot' },
writeConcern: { w: 'majority' },

maxCommitTimeMS: 15 * 60 * 1000, // 15 mins
};

// Connection URL - https://github.com/vhidvz/mongo-rs
const url =
'mongodb://root:password123@mongodb-primary:27017,mongodb-secondary-1:27018,mongodb-secondary-2:27019,mongodb-arbiter:27020/?replicaSet=rs0';
const client = new MongoClient(url);

await client.connect();

const session = sessionDeserializer(client, /* serialized session */);

try {
session.startTransaction(transactionOptions);

// do anything you want...

await session.commitTransaction();
} catch {
await session.abortTransaction();
} finally {
await session.endSession();
} 52 |
53 |

License

MIT

54 |
55 |
56 | 86 |
92 |
93 |

Generated using TypeDoc

94 |
-------------------------------------------------------------------------------- /docs/modules.html: -------------------------------------------------------------------------------- 1 | mongodb-session-serializer
2 |
3 | 10 |
11 |
12 |
13 |
14 |

mongodb-session-serializer

15 |
16 |
17 |

Index

18 |
19 |

Type Aliases

20 |
22 |
23 |

Functions

24 |
27 |
28 | 42 |
48 |
49 |

Generated using TypeDoc

50 |
-------------------------------------------------------------------------------- /docs/types/SerializedSession.html: -------------------------------------------------------------------------------- 1 | SerializedSession | mongodb-session-serializer
2 |
3 | 10 |
11 |
12 |
13 |
14 | 17 |

Type alias SerializedSession

18 |
SerializedSession: {
    id: string;
    type: number;
}
19 |
20 |

Type declaration

21 |
    22 |
  • 23 |
    id: string
  • 24 |
  • 25 |
    type: number
28 |
29 | 43 |
49 |
50 |

Generated using TypeDoc

51 |
-------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | collectCoverage: true, 3 | coverageDirectory: 'docs/coverage', 4 | coveragePathIgnorePatterns: ['/node_modules/'], 5 | coverageProvider: 'v8', 6 | preset: 'ts-jest', 7 | roots: ['/test'], 8 | testEnvironment: 'node', 9 | setupFilesAfterEnv: ['./jest.setup.js'], 10 | coverageReporters: ['json-summary', 'text', 'lcov'], 11 | watchman: true, 12 | }; 13 | -------------------------------------------------------------------------------- /jest.setup.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | /* eslint-disable @typescript-eslint/no-var-requires */ 3 | 4 | require('dotenv').config(); 5 | jest.setTimeout(60 * 60 * 1000); 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mongodb-session-serializer", 3 | "version": "2.1.1", 4 | "description": "MongoDB Session Serializer/Deserializer", 5 | "main": "index.js", 6 | "types": "index.d.ts", 7 | "scripts": { 8 | "debug": "jest --watch", 9 | "prebuild": "rimraf dist", 10 | "doc": "typedoc --out docs src/", 11 | "build": "tsc -p ./tsconfig.json", 12 | "clean": "rm -rf ./dist && rm -rf ./coverage", 13 | "lint": "eslint . '*/**/*.{js,ts}' --quiet --fix", 14 | "format": "prettier --write \"(src|test)/**/*.(ts|js)\"", 15 | "start": "node -r tsconfig-paths/register -r ts-node/register src/index.ts", 16 | "start:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register src/index.ts", 17 | "test": "jest && make-coverage-badge --report-path docs/coverage/coverage-summary.json --output-path coverage-badge.svg" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/vhidvz/mongodb-session-serializer.git" 22 | }, 23 | "author": "Vahid V. ", 24 | "license": "MIT", 25 | "bugs": { 26 | "url": "https://github.com/vhidvz/mongodb-session-serializer/issues" 27 | }, 28 | "keywords": [ 29 | "mongodb-session", 30 | "mongoose-session", 31 | "session-serializer", 32 | "mongodb-serializer", 33 | "mongoose-serializer", 34 | "mongodb-session-serializer", 35 | "mongoose-session-serializer" 36 | ], 37 | "homepage": "https://github.com/vhidvz/mongodb-session-serializer#readme", 38 | "peerDependencies": { 39 | "mongodb": "^5.x || ^6.x", 40 | "mongoose": "^7.x || ^8.x" 41 | }, 42 | "peerDependenciesMeta": { 43 | "mongoose": { 44 | "optional": true 45 | } 46 | }, 47 | "devDependencies": { 48 | "@types/jest": "^29.5.5", 49 | "@types/node": "^20.12.12", 50 | "@typescript-eslint/eslint-plugin": "^6.7.3", 51 | "@typescript-eslint/parser": "^6.7.3", 52 | "dotenv": "^16.4.5", 53 | "eslint": "^8.50.0", 54 | "eslint-config-prettier": "^9.0.0", 55 | "eslint-plugin-prettier": "^5.0.0", 56 | "jest": "^29.7.0", 57 | "jshint": "^2.13.6", 58 | "make-coverage-badge": "^1.2.0", 59 | "prettier": "^3.0.3", 60 | "rimraf": "^5.0.7", 61 | "ts-jest": "^29.1.2", 62 | "ts-node": "^10.9.2", 63 | "tsconfig-paths": "^4.2.0", 64 | "typedoc": "^0.25.13", 65 | "typescript": "^5.4.5" 66 | }, 67 | "publishConfig": { 68 | "access": "public", 69 | "registry": "https://registry.npmjs.org/" 70 | }, 71 | "files": [ 72 | "index.d.ts", 73 | "index.js", 74 | "index.js.map", 75 | "mongodb-session.d.ts", 76 | "mongodb-session.js", 77 | "mongodb-session.js.map", 78 | "mongoose-session.d.ts", 79 | "mongoose-session.js", 80 | "mongoose-session.js.map", 81 | "type.d.ts", 82 | "type.js", 83 | "type.js.map" 84 | ] 85 | } 86 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './type'; 2 | export * from './mongodb-session'; 3 | -------------------------------------------------------------------------------- /src/mongodb-session.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ServerSessionPool, 3 | ServerSession, 4 | ClientSession as SessionClient, 5 | } from 'mongodb/lib/sessions'; 6 | import { Binary, ClientSession, ClientSessionOptions, MongoClient } from 'mongodb'; 7 | 8 | import { SerializedSession } from './type'; 9 | 10 | export function sessionSerializer(session: ClientSession): SerializedSession { 11 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 12 | const { id } = session.id ?? { id: { toString: (_) => '', sub_type: -1 } }; 13 | return { id: id.toString('hex'), type: id.sub_type }; 14 | } 15 | 16 | export function sessionDeserializer( 17 | client: MongoClient, 18 | session: SerializedSession, 19 | options?: ClientSessionOptions, 20 | ): ClientSession { 21 | const sessionPool = new ServerSessionPool(client); 22 | 23 | const { id, type } = session; 24 | const serverSession = new ServerSession(); 25 | serverSession.id = { id: Binary.createFromHexString(id, type) }; 26 | 27 | sessionPool.sessions.push(serverSession); 28 | 29 | return new SessionClient(client, sessionPool, { ...options, explicit: true }); 30 | } 31 | -------------------------------------------------------------------------------- /src/mongoose-session.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ServerSessionPool, 3 | ServerSession, 4 | ClientSession as SessionClient, 5 | } from 'mongodb/lib/sessions'; 6 | import { ClientSession, ClientSessionOptions, Connection } from 'mongoose'; 7 | import { Binary } from 'mongodb'; 8 | 9 | import { SerializedSession } from './type'; 10 | 11 | export * from './type'; 12 | 13 | export function sessionSerializer(session: ClientSession): SerializedSession { 14 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 15 | const { id } = session.id ?? { id: { toString: (_) => '', sub_type: -1 } }; 16 | return { id: id.toString('hex'), type: id.sub_type }; 17 | } 18 | 19 | export function sessionDeserializer( 20 | client: Connection, 21 | session: SerializedSession, 22 | options?: ClientSessionOptions, 23 | ): ClientSession { 24 | const sessionPool = new ServerSessionPool(client); 25 | 26 | const { id, type } = session; 27 | const serverSession = new ServerSession(); 28 | serverSession.id = { id: Binary.createFromHexString(id, type) }; 29 | 30 | sessionPool.sessions.push(serverSession); 31 | 32 | return new SessionClient(client, sessionPool, { ...options, explicit: true }); 33 | } 34 | -------------------------------------------------------------------------------- /src/type.ts: -------------------------------------------------------------------------------- 1 | export type SerializedSession = { id: string; type: number }; 2 | -------------------------------------------------------------------------------- /test/mongodb-session.test.ts: -------------------------------------------------------------------------------- 1 | import { sessionSerializer, sessionDeserializer, SerializedSession } from '../src'; 2 | import { ClientSession, MongoClient } from 'mongodb'; 3 | 4 | const MONGO_CONFIG = () => { 5 | const host = process.env.MONGO_HOST; 6 | 7 | const username = process.env.MONGO_USER || null; 8 | const password = process.env.MONGO_PASS || null; 9 | const database = process.env.MONGO_DB || 'develop'; 10 | 11 | const query = process.env.MONGO_QUERY || 'authSource=admin'; 12 | 13 | return `mongodb://${username}:${password}@${host}/${database}?${query}`; 14 | }; 15 | 16 | describe('test mongodb session serializer', () => { 17 | let client: MongoClient; 18 | let session: ClientSession; 19 | let serializedSession: SerializedSession; 20 | 21 | it('should create client', async () => { 22 | client = new MongoClient(MONGO_CONFIG()); 23 | 24 | expect(async () => await client.connect()).not.toThrow(); 25 | }); 26 | 27 | it('should create session id', async () => { 28 | session = client.startSession(); 29 | 30 | expect(session?.id).toBeDefined(); 31 | }); 32 | 33 | it('should serialize a session', async () => { 34 | serializedSession = sessionSerializer(session); 35 | 36 | expect(serializedSession).toBeDefined(); 37 | 38 | expect(sessionSerializer({} as ClientSession)).toStrictEqual({ id: '', type: -1 }); 39 | }); 40 | 41 | it('should deserialized a serialized session', async () => { 42 | session = sessionDeserializer(client, serializedSession); 43 | 44 | expect(session).toBeDefined(); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /test/mongoose-session.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | SerializedSession, 3 | sessionDeserializer, 4 | sessionSerializer, 5 | } from '../src/mongoose-session'; 6 | import { ClientSession, Connection, createConnection } from 'mongoose'; 7 | 8 | const MONGO_CONFIG = () => { 9 | const host = process.env.MONGO_HOST; 10 | 11 | const username = process.env.MONGO_USER || null; 12 | const password = process.env.MONGO_PASS || null; 13 | const database = process.env.MONGO_DB || 'develop'; 14 | 15 | const query = process.env.MONGO_QUERY || 'authSource=admin'; 16 | 17 | return `mongodb://${username}:${password}@${host}/${database}?${query}`; 18 | }; 19 | 20 | describe('test mongodb session serializer', () => { 21 | let client: Connection; 22 | let session: ClientSession; 23 | let serializedSession: SerializedSession; 24 | 25 | it('should create client', async () => { 26 | client = createConnection(MONGO_CONFIG()); 27 | 28 | expect(client).toBeDefined(); 29 | }); 30 | 31 | it('should create session id', async () => { 32 | session = await client.startSession(); 33 | 34 | expect(session?.id).toBeDefined(); 35 | }); 36 | 37 | it('should serialize a session', async () => { 38 | serializedSession = sessionSerializer(session); 39 | 40 | expect(serializedSession).toBeDefined(); 41 | 42 | expect(sessionSerializer({} as ClientSession)).toStrictEqual({ id: '', type: -1 }); 43 | }); 44 | 45 | it('should deserialized a serialized session', async () => { 46 | session = sessionDeserializer(client, serializedSession); 47 | 48 | expect(session).toBeDefined(); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES6", 4 | "allowJs": true, 5 | "sourceMap": true, 6 | "baseUrl": "./src", 7 | "declaration": true, 8 | "module": "CommonJS", 9 | "skipLibCheck": true, 10 | "noImplicitAny": false, 11 | "esModuleInterop": true, 12 | "moduleResolution": "Node", 13 | "emitDecoratorMetadata": true, 14 | "experimentalDecorators": true, 15 | "types": ["node", "jest"], 16 | "removeComments": false, 17 | "outDir": "./", 18 | "strict": true 19 | }, 20 | "include": ["src/**/*"], 21 | "exclude": ["./docs", "./node_modules"] 22 | } 23 | --------------------------------------------------------------------------------