This file provides guidance for coding agents and human contributors working in
the @tsmx/mongoose-encrypted-string repository.
A minimal Mongoose plugin that adds a transparent EncryptedString schema type.
Encryption/decryption is delegated entirely to @tsmx/string-crypto.
- Language: Plain JavaScript (CommonJS, no TypeScript, no build step)
- Single source file:
mongoose-encrypted-string.js(~41 lines) - Test directory:
test/
npm testnpm run test-coveragenpx jest test/encryptedstring-aes-gcm.test.js
npx jest test/encryptedstring-aes-cbc.test.js
npx jest test/encryptedstring.test.jsnpx jest -t "tests a successful document creation"npx eslint .npx eslint . --fix- CommonJS only. Use
require()andmodule.exports. Do not use ES moduleimport/exportsyntax anywhere in this project.
- Indentation: 4 spaces (no tabs).
switchcase bodies are indented 1 level inside theswitch. - Quotes: Single quotes for all strings.
- Semicolons: Required at the end of every statement.
- No Prettier — all formatting rules come from ESLint.
- Use
constfor imports and values that are never reassigned. - Use
letfor variables that may be reassigned. - Avoid
varin new source code. Test files historically usevarfor top-level mutable setup variables (mongoServer, model variables), butconst/letis preferred going forward.
- Classes: PascalCase — e.g.
EncryptedString - Functions and variables: camelCase — e.g.
registerEncryptedString,testKey - Constants: camelCase (not
SCREAMING_SNAKE_CASE) — e.g.allowedAlgorithms - Unused parameters: Prefix with
_to silence theno-unused-varswarning — e.g.function handler(_req, res) {}
- Export only what consumers need. The library currently exports a single named function; do not add a default export.
- The
EncryptedStringclass is intentionally not exported; it is only accessible after registration viamongoose.Schema.Types.EncryptedString.
- Use ES6
classsyntax extending a base class where appropriate. - Static class fields are acceptable for shared mutable state:
static options = { key: null };
- Throw
Errorinstances with descriptive messages using template literals:throw new Error(`Invalid algorithm '${algorithm}'. Allowed: ${allowedAlgorithms.join(', ')}`);
- Do not silently swallow errors. Let errors from underlying libraries (e.g.
@tsmx/string-crypto, Mongoose) propagate naturally unless there is a specific reason to catch and re-throw.
- Use
async/awaitconsistently. Do not use raw.then()/.catch()Promise chains unless interoperating with a callback-only API.
- Jest
^29withtestEnvironment: 'node'. - Each test suite that requires MongoDB spins up an in-memory server via
mongodb-memory-server.
- Test files live in
test/and are namedencryptedstring*.test.js.
describeblocks name the suite:'EncryptedString tests','AES-256-GCM tests', etc.itdescriptions start with"tests":it('tests a successful document creation', async () => { ... }); it('tests that an error is thrown for an invalid algorithm', () => { ... });
describe('suite name', () => {
const testKey = '...'; // immutable constants at top
var mongoServer = null; // mutable lifecycle vars
var Person = null;
beforeAll(async () => { /* start mongo, register plugin */ });
afterAll(async () => { /* stop mongo */ });
beforeEach(async () => { /* reset collection */ });
afterEach(async () => { /* cleanup */ });
it('tests ...', async () => {
// arrange
// act
// expect
});
});- Use Jest's built-in
expectAPI. - Verify thrown errors with
expect(() => fn()).toThrow()orexpect(() => fn()).toThrow('message substring').
registerEncryptedString(mongoose, key, algorithm?)is the sole public API. It validates the algorithm, stores key/algorithm on the staticEncryptedString.optionsobject, and attachesEncryptedStringtomongoose.Schema.Types.- Supported algorithms:
'aes-256-gcm'(default) and'aes-256-cbc'. - The key must be a 32-byte hex string (64 hex characters) or a 32-character UTF-8 string — see README for details.
- Encryption/decryption uses
passNull: true, meaningnullvalues pass through without being encrypted/decrypted.
GitHub Actions workflows are in .github/workflows/:
git-build.yml— runsnpm teston Node 18, 20, and 22 for every push.npm-publish.yml— manually triggered; runs tests then publishes to npm.
All tests must pass on Node 18, 20, and 22 before any change is considered complete.