@nxgt/janus-kit

中文文档
0.1.36发布于 2026/11/02MITTypeScriptES Module

@nxgt/janus wired in one call, one subpath per database — PostgreSQL through Drizzle, MongoDB — with sessions in Redis, telemetry, a health check and a close

原始使用文档
文档目录8 节
  1. Install
  2. Subpaths
  3. API
  4. The configuration
  5. Traps
  6. Documentation
  7. Type safety, counted
  8. Licence

@nxgt/janus-kit

@nxgt/janus wired in one call: users and permissions in PostgreSQL through @nxgt/janus-drizzle or in MongoDB through @nxgt/janus-mongo, sessions and one-time tokens in Redis through @nxgt/janus-redis, telemetry, a health check and a close.

import { janus, scryptHasher } from '@nxgt/janus';
import { defineModel, permissions } from '@nxgt/janus/permissions';
import { connectKit, defineConfig } from '@nxgt/janus-kit/drizzle';
import { z } from 'zod';

export const kit = await connectKit(
  defineConfig({
    postgres: { url: process.env.JANUS_DATABASE_URL! }, // Janus's own database
    redis: { url: process.env.REDIS_URL! },             // optional: sessions and tokens
    telemetry: true,                                    // optional: @nxgt/janus-telemetry
    auth: (adapters) =>
      janus({
        user: z.object({ email: z.email(), name: z.string() }),
        password: { login: 'email' },
        hasher: scryptHasher(),
        ...adapters, // { store, relations }
      }),
    access: ({ relations, auth }) =>
      permissions({
        model: defineModel({
          subjects: auth.types,
          types: {
            document: {
              related: { owners: ['user'], viewers: ['user'] },
              permits: { view: ['owners', 'viewers'] },
            },
          },
        }),
        store: relations,
      }),
  }),
);

const current = await kit.auth.authenticate(request); // null when signed out
if (current) await kit.access.can(current.user, 'view', { type: 'document', id: 'd1' });
const health = await kit.ping(); // { ok, postgres, redis } — never throws
await kit.close();

You still write janus() and permissions(), in the two functions, so every type they infer is inferred where you wrote them: kit.auth.signIn takes your login field, kit.access.can your permissions. The kit hands them the stores, opens and closes the connections, and checks at startup what would otherwise fail at the first sign-in.

0.x. A minor version may still change the surface; the changelog says how.

Install

bun add @nxgt/janus-kit @nxgt/janus @nxgt/redis zod
bun add @nxgt/janus-drizzle @nxgt/drizzle drizzle-orm   # for @nxgt/janus-kit/drizzle
bun add @nxgt/janus-mongo @nxgt/mongo mongodb           # for @nxgt/janus-kit/mongo
bun add @nxgt/janus-telemetry @nxgt/telemetry           # only for telemetry: true
bun add -d @types/bun                                   # the kit's types name Bun's RedisOptions

Required peers, whichever subpath:

  • @nxgt/janus;
  • @nxgt/redis >=0.3.1 <1, and zod 4 which it requires, even with sessions in the database: the kit's types name its connection;
  • typescript 6 or 7.

Peers of @nxgt/janus-kit/drizzle — optional in package.json, so an application on another subpath does not install them, but required by this one:

  • @nxgt/janus-drizzle: your schema file imports defineJanusTables from it to create the tables, and the kit's stores must query the same definition;
  • @nxgt/drizzle >=0.6.1 <1 and drizzle-orm 1.0 (from 1.0.0-rc.4), for PostgreSQL.

Peers of @nxgt/janus-kit/mongo, optional in the same way:

  • @nxgt/janus-mongo: syncMongoAdapter creates the collections, and the kit's stores must query the same definitions;
  • @nxgt/mongo >=0.17.0 <1 and mongodb 7.

The @nxgt/* floors are tested, not claimed: in the Floors job, on every CI run, the kit's mongo specs and its typecheck run on @nxgt/mongo 0.17.0, and its whole suite and typecheck on @nxgt/redis 0.3.1, @nxgt/drizzle 0.6.1 and @nxgt/telemetry 0.2.1.

@nxgt/janus-telemetry is an optional peer, loaded only when telemetry is true; it requires @nxgt/telemetry >=0.2.1 <1 as its own peer. @nxgt/janus-redis is a dependency: your code never imports it.

It runs on Bun only: the kit opens PostgreSQL over Bun's SQL and Redis over Bun's RedisClient. It needs PostgreSQL 15 or later, or MongoDB as a replica set, and Redis 7.0 or later. Like @nxgt/janus, it expects "moduleResolution": "bundler".

Subpaths

One kit, one subpath per database. The package has no root entry, so the import names the database: import … from '@nxgt/janus-kit' fails with TS2307. Redis, telemetry, ping and close are the same whichever subpath you use.

SubpathDatabaseThe database keyWhat connectKit checks
@nxgt/janus-kit/drizzlePostgreSQL, through @nxgt/janus-drizzlepostgresJanus's five tables exist
@nxgt/janus-kit/mongoMongoDB, through @nxgt/janus-mongomongoJanus's four collections and their indexes exist; any other difference is a warning

On MongoDB, the example above changes in its first lines only:

import { connectKit, defineConfig } from '@nxgt/janus-kit/mongo';

export const kit = await connectKit(
  defineConfig({
    mongo: { url: process.env.JANUS_MONGO_URL! }, // mongodb://…/janus — the path names the database
    redis: { url: process.env.REDIS_URL! },
    auth: (adapters) => janus({ /* … */ ...adapters }),
  }),
);
kit.db; // the Db; (await kit.ping()).mongo

API

Both subpaths export the same names; they differ in the database key and what db is.

ExportWhat it is
defineConfig(config)Checks the configuration and answers it, frozen. It connects to nothing and reads no environment variable. What is wrong throws a TypeError here, where the application starts.
connectKit(config)Checks the configuration again, opens the database and Redis, checks Janus's tables or collections, builds auth and access, and answers the kit. Fails with an Error naming what to do — a TypeError for a URL it cannot read — after closing what it opened.
KitWhat connectKit answers: auth; access when configured; db, the Drizzle instance or the MongoDB Db; redis, the connection or undefined; ping(options?); close(); and [Symbol.asyncDispose].
KitConfig, RedisConfig, and PostgresConfig from /drizzle or MongoConfig from /mongoThe configuration's types.
Adapters, AccessWiringWhat auth and access are given: { store, relations }, and { relations, auth }.
Health, PingResultWhat ping answers: { ok, postgres, redis? } or { ok, mongo, redis? }, each { ok: true, latencyMs } or { ok: false, error }.

The configuration

Key
postgresrequired on /drizzle{ url } of Janus's database, a postgres:// or postgresql:// URL, which the kit opens and closes; or { db }, a Drizzle instance you opened, never closed by the kit. tables: what your schema file exports, when the tables are in a PostgreSQL schema of their own.
mongorequired on /mongo{ url, clientOptions? } of Janus's database, a mongodb:// or mongodb+srv:// URL whose path names the database, which the kit opens with serverSelectionTimeoutMS: 5_000 and closes; or { db }, a Db you opened, never closed by the kit.
redisoptional{ url, prefix?, clientOptions? }, which the kit opens with enableOfflineQueue: false and closes; or { connection, prefix? }, which it never closes. Absent, sessions and tokens stay in the database.
telemetryoptionaltrue wraps auth with instrumentJanus and access with instrumentPermissions.
authrequired(adapters) => janus({ …, ...adapters }).
accessoptional({ relations, auth }) => permissions({ model, store: relations }). Absent, the kit has no access, and kit.access does not compile.

adapters is { store, relations }: users from the database, sessions and tokens from Redis when it is wired, and the relation store, so deleting a user deletes every tuple naming them. The configuration guide has each key in detail.

Traps

  • Janus's tables come from your migrations. connectKit checks that all five exist and refuses to start otherwise, naming them. Create them with drizzle-kit, from defineJanusTables(), as @nxgt/janus-drizzle's guide shows.
  • In a PostgreSQL schema of their own, pass postgres.tables. Without it, the kit looks for, and the stores query, users in the connection's search_path: public, where your application may have a users of its own.
  • Janus's collections come from syncMongoAdapter, a deployment step. connectKit compares them with @nxgt/janus-mongo's definitions, writing nothing. A missing collection or index refuses to start: MongoDB would create a missing collection on the first write without the unique index on logins. A validator, an option or an index's options that differ only warn (JANUS_KIT_COLLECTIONS_DRIFTED), so a rollback still starts.
  • kit.auth.collectExpired() answers UNSUPPORTED on /mongo: a TTL index removes lapsed sessions and tokens there. Schedule it on PostgreSQL only, where it deletes both.
  • A MongoDB URL without a database in its path uses test, the driver's default. Name Janus's database in the URL: mongodb://…/janus.
  • A MongoDB that does not answer fails after 5 seconds, measured: the kit's serverSelectionTimeoutMS, where the driver's own is 30. A request during a replica-set election can fail rather than wait; pass clientOptions: { serverSelectionTimeoutMS } to wait longer.
  • A Redis that is down at startup takes about 31 seconds to fail, measured: Bun's client retries its first connection. At run time the kit's enableOfflineQueue: false makes an outage fail at once.
  • What you hand in, you close. A db or a connection from the configuration is left open by kit.close().
  • @nxgt/mongo shares one client per URL, as @nxgt/redis does below: connecting to Janus's MongoDB URL elsewhere with other options is refused.
  • @nxgt/redis shares one client per URL. If your application connects to the same Redis URL with other options, connectRedis refuses the second. Give Janus its own URL, another database number for instance, or pass { connection }.

Documentation

  • Guides: every key of the configuration, the health check, and closing
  • Troubleshooting: look up the error message you see
  • Roadmap: what is next, and what is not planned

Type safety, counted

Sixteen plausible mistakes are refused by the compiler, each with a @ts-expect-error case: ten in test/types/kit.ts, over PostgreSQL,

  • kit.access on a kit configured without access;
  • a user type auth does not have;
  • a permission the model does not have;
  • both postgres.url and postgres.db;
  • both redis.url and redis.connection;
  • redis.clientOptions beside a connection already open;
  • postgres.schema instead of the tables built in it;
  • a configuration without auth;
  • postgres with neither url nor db;
  • telemetry as a string, as an environment variable reads;

and six in test/types/mongo.ts, over MongoDB:

  • kit.access on a kit configured without access;
  • ping()'s postgres on a MongoDB kit, which answers mongo;
  • both mongo.url and mongo.db;
  • mongo.clientOptions beside a Db whose client is already open;
  • the postgres key given to the MongoDB kit;
  • mongo with neither url nor db.

Licence

MIT

版本与发布记录

@nxgt/janus-kit 共发布 37 个版本,首次发布于 2026/09/26;过去 12 个月发布了 37 个版本。

版本发布日期距今
0.1.36latest2026/11/021 天前
0.1.352026/11/021 天前
0.1.342026/10/304 天前
0.1.332026/10/277 天前
0.1.322026/10/277 天前
0.1.312026/10/277 天前

关于 @nxgt/janus-kit 的常见问题

@nxgt/janus-kit 是什么?

@nxgt/janus连接在一个调用中,每个数据库有一个子路径——PostgreSQL通过Drizzle, MongoDB——在Redis中有会话,遥测,健康检查和关闭

如何安装 @nxgt/janus-kit?

在项目目录运行 npm install @nxgt/janus-kit,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:typescript(^6.0.3 || ^7.0.0)、@nxgt/janus(^0.36.0)、@nxgt/redis(>=0.3.1 <1)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@nxgt/janus-kit 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@nxgt/janus-kit 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@nxgt/janus-kit 可以商用吗?

@nxgt/janus-kit 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@nxgt/janus-kit 还在维护吗?

最新版本 0.1.36 发布于 2026/11/02(1 天前);至今共发布 37 个版本,其中过去 12 个月发布了 37 个;首次发布于 2026/09/26。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。