An opinionated library and command-line utility for configuration CouchDB endpoints, databases, and design documents.
Kivik uses Nano to connect to CouchDB.
This package has nothing to do with the Go kivik CouchDB library. I just also happen to own a Kivik couch.
Kivik's opinionated nature lies in its expectation of a directory structure where it will find all of the CouchDB configuration you'd like to test and deploy. This repository contains an example directory structure which contains all possible kinds of configuration, as explained below:
./kivirc.(json|yaml|yml)
: The Kivik RC File../$DB/
: Subdirectories (that haven't been excluded) are treated as CouchDB databases with the name$DB
../$DB/validate.js
: A module that returns a function that validates data against the database../$DB/fixtures/*.json
: Test fixtures for ths database. Not deployed by default, but can be configured to do so for testing../$DB/indexes/*.json
: Query indexes for use by the Mango JSON query server./$DB/design/$DDOC/
: Design document configuration. The design document specified in this directory will be deployed to CouchDB with the id_design/$DDOC
. See thetest
design document for a demonstration of how a design document is laid out.
Configuration options can be specified in an RC file, found at ./kivikrc.json
, ./kivikrc.yml
, or ./kivikrc.yaml
. The shape of a Kivik RC file is defined in src/context/rc.ts
, and I've pasted the relevant parts below. An example of sorts can be found at kivikrc.json
. At this moment, deploying Kivik configuration to an external CouchDB endpoint requires adding at least one object to the deployments
RC file property.
NEW Use the subdirectory
option to specify which subdirectory of the directory containing the Kivik RC file contains the database configuration. This is really handy when testing monorepos.
The RC file is read whether using Kivik on the command line or programmatically.
/** Kivik RC file configuration. */
export interface Rc {
/**
* Object containing deployment configurations. Adding at least one is
* required to be able to deploy Kivik configuration elsewhere.
*/
deployments?: Record<string, Deployment>;
/** Subdirectories of the root directory which do not contain database configuration. Default: `["node_modules"]` */
excludeDirectories?: string[];
/** JavaScript files to ignore when processing design documents. Default: `["*.spec.*", "*.test.*"]` */
excludeDesign?: string[];
/** Subdirectory of the directory containing the RC file where the database configuration can be found. */
subdirectory?: string;
}
/**
* Configuration for deploying design documents to a CouchDB endpoint.
*/
export interface Deployment {
/** CouchDB endpoint URL. Required. */
url: string;
/**
* Authentication credentials. If left unset, Kivik will attempt to deploy
* anonymously.
*/
auth?: {
/** CouchDB username */
user: string;
/** `user`'s password */
password: string;
};
/** Suffix to append to the end of each database name. Default: `undefined` */
suffix?: string;
/** Whether or not to deploy fixtures along with the design documents. */
fixtures?: boolean;
/** List of databases to deploy. By default, all databases are deployed. */
dbs?: string[];
}
--color
: Colorize output. Use--no-color
(or set theNO_COLOR
environment variable) to skip colorization. Default:true
.--logLevel
: Log level for the standard log output. Your options are:error
: When things don't work as expectedsuccess
: When things do work as expectedwarn
: Something interesting is about to happen, or something didn't work as expected but it isn't a big dealinfo
: Everything Kivik is doingcouch
: Forkivik dev
, output the CouchDB logs
--logTimestamp
: Add a timestamp to log output.--quiet
: Silence output.
$ kivik validate db path/to/file.json
$ kivik validate db https://example.com/file.json
import { createKivik, Database } from "kivik";
const database = "db";
const document = {
_id: "something",
};
const kivik = await createKivik("path/to/directory", "validate");
const kivikdb = kivik.databases.get(database) as Database;
const response = kivikdb.validate(document);
if (response.valid) {
console.log("yay!");
}
await kivik.close();
Validates a file against a database's validation function that you provide.
To provide a validation function, have $DB/validate.js
export it. The function's return value must be shaped like this:
export type ValidateResponse =
| boolean
| {
/** Is the document valid? */
valid: boolean;
/** Validation errors. */
errors?: any;
};
(errors
is passed through JSON.stringify
in log output.)
When a database has a validation function, its fixtures will be validated against it. Invalid fixtures will not be deployed. If a database does not have a validation function, all fixtures are considered valid and will be deployed. If you try to validate a document against a database on the command line, you'll get an error.
The example directory contains a validation function that uses Ajv to validate data against a JSON Schema.
$ kivik fixtures
import { createKivik } from "kivik";
const kivik = await createKivik("path/to/dir", "fixtures");
const errors = kivik.validateFixtures();
Returns a report of fixtures that do not validate against their database's validate function.
Deploys Kivik configuration to a CouchDB endpoint. If, in your RC file, you have the following:
{
"deployments": {
"production": {
"url": "http://production:5984/",
"auth": {
"user": "admin",
"password": "donttellanyone"
}
}
}
}
you can deploy Kivik configuration to the production server like so:
$ kivik deploy production
import { createKivik } from "kivik";
const kivik = await createKivik("path/to/dir", "deploy");
await kivik.deploy("production");
await kivik.close();
Run kivik deploy
with the --watch
flag to deploy subsequent changes you make to your Kivik files.
import { localhost as localNano } from "@crkn-rcdr/nano";
import { createKivik } from "kivik";
const client = localNano(5984, { user: "admin", password: "admin" });
const kivik = await createKivik("kivikrc/directory");
const testDeploy = kivik.testDeployer(client);
// handler is a couchdb-nano `DocumentScope` object
// supplying a suffix allows you to deploy multiple tests at once without conflict
const handler = await testDeploy("db-name", "unique-testing-suffix");
$ git clone https://github.com/crkn-rcdr/kivik
$ cd kivik
$ docker pull couchdb:3.1
$ pnpm install
$ pnpm test