@classytic/mongokit

中文文档
3.46.0发布于 2026/11/08MITTypeScriptES Module零依赖近 30 天下载 2843

生产级MongoDB寄存器 - 智能发卡,事件和插件. 建于@classytic/repo-core上.

中文使用文档
文档目录33 节
  1. 安装
  2. 快速启动
  3. 为什么是Mongokit?
  4. 核心 API
  5. 常见食谱
  6. 多十年读写
  7. 软删除和硬删除
  8. 倾斜
  9. 交易
  10. 时限和关切 queryDefaults (中文(简体) )
  11. 加入范围
  12. 批量读取( E) getByIds (中文(简体) )
  13. 读取模型( E) bulkUpsert , (中文(简体) ), @classytic/mongokit/read-m…
  14. 活性扫荡 iterate (中文(简体) )
  15. 改变流
  16. 查询解析器
  17. 前缀搜索( 搜索- as- you- type, 有索引)
  18. 内建插件
  19. 事件和中间软件
  20. 类型脚本
  21. 输入您的 Mongoose 模型—— 绝不铸造 as never
  22. 子路径导入
  23. 高级文档
  24. 测试
  25. 测试机率—— @classytic/mongokit/testkit
  26. 运行于本地或云 DB
  27. 测试索引
  28. 帮助者
  29. 查询计划门
  30. 内核配合—— @classytic/mongokit/kernel-conformance
  31. 硬化准备: tenantUniques
  32. 许可证
  33. 商标

@ 经典/ mongokit

npm version License: MIT Sponsor

Mongoose apps的生产准备寄存层: 租户安全 CRUD, 软删除, pagination, hooks, retries, dealers, change streams, 和插件.

蒙戈克特就是建立在这个基础上的 @classytic/repo-core 执行共享 StandardRepo<TDoc> 合同,因此控制器代码可以瞄准一个存储器接口跨越MongoDB和SQLite.

安装

npm install @classytic/mongokit @classytic/repo-core mongoose

所需经费:

  • 节点.js >=22
  • 乌鸦 >=9.4.1
  • @classytic/repo-core >=0.19.0
  • mongodb-memory-server >=10.4.3 —— 说 选项,仅需要 @classytic/mongokit/testkit 子路径( 被宣布为可选对等点, 所以它是 从来没有为不使用它的消费者安装)

快速启动

使用 createRepository(model, config) 为了共同的道路。 它为您按安全顺序绘制插件 .

import { createRepository } from '@classytic/mongokit';
import UserModel from './models/User.js';

const userRepo = createRepository<UserDoc>(UserModel, {
  tenant: { tenantField: 'organizationId' },
  softDelete: true,
  timestamps: true,
  batch: true,
});

const user = await userRepo.create(
  { name: 'Ada', email: '[email protected]' },
  { organizationId },
);

const page = await userRepo.getAll({
  page: 1,
  limit: 20,
  filters: { status: 'active' },
  organizationId,
});

await userRepo.update(user._id, { name: 'Ada Lovelace' }, { organizationId });
await userRepo.delete(user._id, { organizationId });

对于手动插件控制,请直接使用构造器:

import {
  Repository,
  methodRegistryPlugin,
  multiTenantPlugin,
  softDeletePlugin,
  timestampPlugin,
} from '@classytic/mongokit';

const userRepo = new Repository(UserModel, [
  methodRegistryPlugin(),
  multiTenantPlugin({ tenantField: 'organizationId' }),
  softDeletePlugin(),
  timestampPlugin(),
]);

为什么是Mongokit?

  • 房客安全: 房客过滤器在司机打电话前由政策钩注入.
  • 软删除 : 默认软删除方式 restore, (中文(简体) ), getDeletedTTL的支持 和硬去除的逃生舱.
  • 铺设 : 为不安全的密钥集查询提供索引警告.
  • 钩和中间器皿: 决定性 before:*, (中文(简体) ), after:*, (中文(简体) ), error:* 钩子外加包装式中件.
  • 检索和取消: retryPolicy 财务报告和审定财务报表 AbortSignal 整个存储器表面的支持.
  • 交易 : 用于单repo和跨repo MongoDB交易的辅助API.
  • 更改流 : 便携式 watch() API过蒙戈变流.
  • 跨吻合同: 可转让到 StandardRepo<TDoc> 从 @classytic/repo-core。 。 。 .

核心 API

读取:

await repo.getById(id, options);
await repo.getByQuery({ email }, options);
await repo.getOne({ slug }, options);
await repo.findAll({ status: 'active' }, options);
await repo.getAll({ page: 1, limit: 20, filters });
await repo.count(filters, options);
await repo.exists(filters, options);
await repo.distinct('status', filters, options);

写作:

await repo.create(data, options);
await repo.createMany(rows, options);
await repo.update(id, patch, options);
await repo.updateMany(filter, patch, options);
await repo.delete(id, options);
await repo.deleteMany(filter, options);
await repo.findOneAndUpdate(filter, update, options);

语义学小姐跟随 MinimalRepo 合同:

  • getById, (中文(简体) ), update,以及 delete 返回时 null 关于小姐.
  • 无效的对象Id形状输入返回 null 而不是冲浪出一只绵羊 CastError。 。 。 .
  • 过 { throwOnNotFound: true } 选择404式错误.

常见食谱

多十年读写

const repo = createRepository(OrderModel, {
  tenant: { tenantField: 'organizationId', required: true },
});

await repo.create({ total: 120 }, { organizationId });
await repo.findAll({ status: 'paid' }, { organizationId });

若为 required: true 无法解决租户的问题,在任何司机打电话前,电话无法拨打.

软删除和硬删除

const repo = createRepository(UserModel, {
  softDelete: { deletedField: 'deletedAt' },
});

await repo.delete(userId);                    // soft delete
await repo.restore(userId);                   // plugin method
await repo.delete(userId, { mode: 'hard' });  // physical delete

硬删除仍然运行着租户,审计,缓存和验证钩.

倾斜

const offsetPage = await repo.getAll({
  mode: 'offset',
  page: 1,
  limit: 25,
  sort: { createdAt: -1 },
});

const first = await repo.getAll({
  mode: 'keyset',
  limit: 25,
  sort: { createdAt: -1 },
});

const next = await repo.getAll({
  mode: 'keyset',
  limit: 25,
  sort: { createdAt: -1 },
  after: first.next,
});

每一类都有一个独特的 _id 断线器和 hasNext 来源于限制+1获取。 偏移页面 报告 { total, totalIsEstimate, countedAt } 每栏下 countStrategy (单位:千美元)exact, (中文(简体) ), capped, (中文(简体) ), estimated, (中文(简体) ), none, (中文(简体) ), cached页:1 skip 过去 maxOffset (违约10万)以下列方式被拒绝: mongokit.pagination.offset_too_deep。光标绑定在它的收藏、过滤器上(租户) 和整理:在其他地方重放 repo.cursor.scope_mismatch (对等核心) CURSOR_ERROR_CODES页:1 cursorSecret 所以篡改也被发现了.

// Boot: the deployment's list policy.
configurePaginationDefaults({ defaultCountStrategy: 'capped', cursorSecret, maxOffset: 50_000 });

交易

import { withTransaction } from '@classytic/mongokit';

await withTransaction(mongoose.connection, async (session) => {
  const order = await orderRepo.create(orderData, { session, organizationId });
  await ledgerRepo.create({ orderId: order._id, amount: order.total }, { session, organizationId });
});

单还原便利:

await orderRepo.withTransaction(async (txRepo) => {
  return txRepo.create(orderData, { organizationId });
});

要连载作家,写作必须改变. 将字段设置到它已经拥有的值的更新是无可操作的:它不需要写入锁,所以两个交易在同一瞬间完成,从不冲突. 写有变化的东西( 例如) Name $inc: { writes: 1 } 在大门或租赁行.

时限和关切queryDefaults(中文(简体) )

// Boot: every command is bounded by a server-side maxTimeMS; the boot check fails without it.
// Do not pass `timeoutMS` to mongoose.connect(): the MongoDB driver ignores it since 7.8 (CVE-2026-119179).
await mongoose.connect(uri);
configureQueryDefaults({ maxTimeMS: 5_000, writeConcern: { w: 'majority' } });
configureAggregateDefaults({ maxTimeMs: 15_000 });
assertQueryDefaultsConfigured();

// Per repository, and per call (per call always wins):
const repo = new Repository(Order, plugins, {}, { queryDefaults: { comment: 'orders' } });
await repo.findAll(filter, { maxTimeMS: 500 });

加入范围

A 类 $lookup 编号 : $unionWith 编号 : $graphLookup 在自己的仓库下读取已合并的收藏 租户和软删除范围。 拿着 from 从 Model.collection.name: 没有模型拥有的名称丢出 mongokit.join.unknown_collection,没有寄存器支配丢弃 mongokit.join.ungoverned_collection (列出一个全公司在 unscopedJoins) (中文(简体) ).

批量读取( E)getByIds(中文(简体) )

const byId = await repo.getByIds(ids, { select: 'name sku' });              // Map, chunked $in
const rows = await repo.getByIds(ids, { preserveOrder: true, chunkSize: 5_000 }); // aligned, undefined = miss

读取模型( E)bulkUpsert, (中文(简体) ), @classytic/mongokit/read-model(中文(简体) )

const res = await totals.bulkUpsert(rows, { key: ['period', 'rate'], inc: ['tax'], organizationId });
// res.results[i].outcome: 'inserted' | 'updated' | 'unchanged' | 'failed' (+ code). Needs MongoDB 8.0.

import { applyIncrements, rebuildInto, reconcile } from '@classytic/mongokit/read-model';
await applyIncrements(totals, grains, { session, ledger, organizationId }); // inside the posting transaction
await rebuildInto(facts, totals, { pipeline, on: ['organizationId', 'period', 'rate'], scope: { organizationId } });
const { drift } = await reconcile(facts, totals, { pipeline, on, measures: ['tax'], scope: { organizationId } });

活性扫荡iterate(中文(简体) )

for await (const { docs, checkpoint } of repo.iterate(filter, { batchSize: 1_000, after: saved, organizationId })) {
  await process(docs);
  await saveCheckpoint(checkpoint); // resume later with { after: checkpoint }
}

改变流

const ac = new AbortController();

for await (const change of repo.watch({ status: 'pending' }, {
  signal: ac.signal,
  organizationId,
} as { signal: AbortSignal; organizationId: string })) {
  if (change.operation === 'create') enqueue(change.doc);
}

watch() 与其它读取的一样是插件路由的,所以在蒙戈变流管打开之前,会应用租户和软去除过滤器.

查询解析器

import { QueryParser } from '@classytic/mongokit';

const parser = new QueryParser({
  schema: InvoiceModel.schema,
  allowedFilterFields: ['status', 'total', 'customerId'],
  allowedSortFields: ['createdAt', 'total'],
  searchMode: 'auto',
});

const parsed = parser.parse(req.query); // throws HttpError(400) on invalid/blocked input
const result = await invoiceRepo.getAll(parsed);

支持常见的 URL 运算符, 如 _gt, (中文(简体) ), _gte, (中文(简体) ), _lt, (中文(简体) ), _lte, (中文(简体) ), _in, (中文(简体) ), _nin, (中文(简体) ), _regex地理过滤器 聚居物 以及有知觉的强迫.

解析器是 默认关闭失败 (单位:千美元)invalidInput: 'throw': 被封锁 运算符、不允许的字段、错误的值和病理正则输入 提高HTTP 400 (code: 'INVALID_QUERY_INPUT'而不是沉默无声 驳回请求 仅限 过滤器会将查询扩展至每个 租户范围记录。 文-语义输入( E)search, (中文(简体) ), like编号 :contains(中文(简体) ) 总是逃避而不是拒绝,所以 ?search=c++ 从来没有400s。 已经信任 迁移/匹配工具可以选择使用遗留的警告和滴放行为 invalidInput: 'drop'。 。 。 .

前缀搜索( 搜索- as- you- type, 有索引)

searchMode: 'prefix' 找到每个查询词开始一个字的文档 searchFields (单位:千美元)moh ali 找到"Mohammed Al-Ali",由多键索引提供 而不是一个无忧无虑的Regex扫描。 寄存器会写一个普通的单词 键入 searchKeysField (默认) _searchKeys在每一个写道上. 规范化:小写,有二甲酸盐脱落的NFKD,阿拉伯折叠 (删除了tashkeel/tatweel, أ إ آ → ا, (中文(简体) ), ى → ي, (中文(简体) ), ة → ه),拆分开 白相间/平相.

import { rebuildSearchKeys, searchKeysIndex, searchKeysPath } from '@classytic/mongokit';

schema.add({ _searchKeys: searchKeysPath() }); // string[], select: false
// Serves getAll({ search }) prefix search.
schema.index(searchKeysIndex().fields, searchKeysIndex().options);

const repo = new Repository(Person, [], {}, { searchMode: 'prefix', searchFields: ['name', 'email'] });
await rebuildSearchKeys(repo, { onlyMissing: true }); // backfill rows written before
await repo.getAll({ search: 'moh', page: 1 }); // composes with filters, tenant scope, keyset/offset, counts

客户用同样的规则从无鼠标的子路径突出: import { findSearchMatches } from '@classytic/mongokit/search'写着: 绕过寄存器( raw) Model.updateOne,更好的奥思的适配器)写出 键为 buildSearchKeys(doc, fields)。 。 。 .

内建插件

插件目的
methodRegistryPlugin安全添加插件分配方法
multiTenantPlugin租户范围界定和租户盖章
softDeletePlugin软删除、 恢复、 删除列表查询、 TTL
timestampPlugincreatedAt 编号 : updatedAt 管理层
searchKeysPlugin每个书写上的前缀搜索密钥( 自动安装于 searchMode: 'prefix'(中文(简体) )
batchOperationsPluginbulkWrite 和批量帮助者
cachePlugin可插取读取缓存
auditLogPlugin 编号 : auditTrailPlugin审计线索—— auditTrailPlugin({ mode: 'transactional' }) 给出内部为原子的会话连接条目 withTransaction (遵守级别);默认 'best-effort' 模式是防火和遗忘的可观察性。 打电话 ensureAuditTrailReady() 因此,在第一次交易中不会发生收藏/索引创建
observabilityPlugin量子钩点
cascadePluginHook 路由级联删除
customIdPlugin前缀或相继的公共身份证
fieldFilterPlugin了解作用的外地可见度
validationChainPlugin分层同步和同步验证
mongoOperationsPluginHook- routed Mongo 更新助手
aggregateHelpersPlugin常见的聚合助手
subdocumentPluginNested 阵列文档助手
changeLogPlugin持久每个文件的改变种子(@classytic/repo-core/sync用于离线第一拉出/推出和复制品

只导入您使用的插件 .

事件和中间软件

每个操作都发出钩子:

repo.on('before:delete', (context) => {
  if (!context.user) throw new Error('unauthorized');
});

repo.on('after:create', ({ context, result }) => {
  audit.info({ model: context.model, id: result._id });
});

Middleward 包裹成功操作执行 :

repo.useMiddleware(async ({ operation, next }) => {
  const start = performance.now();
  try {
    return await next();
  } finally {
    metrics.record(operation, performance.now() - start);
  }
});

使用 before:* 安全政策的钩子。 使用中间软件来进行人机组学,如定时,追踪,以及输入/输出成型等.

类型脚本

import type {
  Repository,
  RepositoryContext,
  SoftDeleteMethods,
  BatchOperationsMethods,
} from '@classytic/mongokit';

type UserRepo = Repository<UserDoc> &
  SoftDeleteMethods<UserDoc> &
  BatchOperationsMethods;

输入您的 Mongoose 模型—— 绝不铸造 as never

以医生类型宣布型号 Model<UserDoc> 直接流入 Repository<UserDoc> 财务报告和审定财务报表 createMongooseAdapter 没有铸造物:

// ✅ Typed — flows cleanly into Repository + the arc adapter
export type UserDoc = InferSchemaType<typeof UserSchema> & { _id: Types.ObjectId };
export const UserModel = model<UserDoc>('User', UserSchema);
export const userRepo = new Repository<UserDoc>(UserModel, [/* plugins */]);

// ❌ Untyped — the inferred doc type diverges from `UserDoc`, and
//    `mongoose.Model<T>` is INVARIANT in T, so it won't unify. The
//    tempting "fix" is `as never` — don't; type the model instead.
export const UserModel = model('User', UserSchema);          // Model<inferred>
new Repository<UserDoc>(UserModel as never, []);             // ⛔ cast smell

出品人并不是蒙哥基打字漏洞——是未打字模型的症状. 一个通用的 model<Doc>(...) 调用网站将其删除 (单位:千美元)Repository, (中文(简体) ), createMongooseAdapter,以及任意 RepositoryLike<Doc> 网站).

特征- 检测可移植行为 :

if (repo.capabilities.changeStreams) {
  // repo.watch is available
}

子路径导入

import { parseGeoFilter } from '@classytic/mongokit/query/primitives/geo';
import { coerceFieldValue } from '@classytic/mongokit/query/primitives/coercion';
import { extractSchemaIndexes } from '@classytic/mongokit/query/primitives/indexes';

可选桥梁 :

import { createBetterAuthOverlay } from '@classytic/mongokit/better-auth';

高级文档

GitHub 寄存器包括以下更深入的指南:

  • 增强安全性
  • 查找和汇总模式
  • 类型架构
  • 贡献工作流程
  • 释放检查

见 docs/ 这些长式引用的目录.

测试

npm test
npm run typecheck
npm run build

测试套房使用 mongodb-memory-server 默认。 设定 MONGODB_URI 以对抗外部蒙戈DB部署.

测试机率—— @classytic/mongokit/testkit

装有电池的吊带 用来测试你的储物库 旋转平面 MongoDB( 独立的, 或用于交易的单节点复制件), 打开一个 单独 连接,并给你一个活的mongokit Repository 在一个电话.

mongodb-memory-server 是一个 选项对等点 ——在使用试样时安装;它从来不是生产依赖性,是动态导入的,因此它从不输入您的应用包:

npm i -D mongodb-memory-server
import { createTestRepository } from '@classytic/mongokit/testkit';

const t = await createTestRepository({
  name: 'Order',
  schema: orderSchema,
  config: { softDelete: true, timestamps: true }, // full CreateRepositoryConfig
});

await t.repository.create({ total: 10 });
await t.clear();   // empty the collection between tests
await t.close();   // close connection + stop server (idempotent)

运行于本地或云 DB

传出 a uri (或设置) MONGODB_URI和 没有启动模拟服务器 测试 kit 连接到你真正的数据库和 close()编号 :stop() 所以它不会放弃它:

const t = await createTestRepository({
  name: 'Order', schema: orderSchema,
  uri: process.env.ATLAS_TEST_URI ?? 'mongodb://localhost:27017/myapp-test',
});
# or for the whole suite, no code change:
MONGODB_URI="mongodb+srv://…/myapp-test" vitest run

⚠️ clear() 虚空 每个收藏 在连接。 在真正的数据库中,总是指向 专用测试 DB 从不生产.

测试索引

createTestRepository 运行 model.init(),因此所宣布的指数是真正构建的——独特的约束性执行(E11000),TTL,复合物,文本,和地理学索引都真实表现在记忆服务器上. 使用已曝光内容 model 用于运行时间索引工作:

await t.model.syncIndexes();
await t.model.collection.indexes();          // inspect
await t.model.collection.dropIndex('tag_1'); // drop

Atlas $search 编号 : $vectorSearch 索引只使用阿特拉斯系统,在任何非阿特拉斯服务器上都不存在 uri 在真正的Atlas测试集群.

帮助者

帮助使用
createTestRepository服务器 + 连接 + 直播 Repository 在一个电话中
createTestConnection孤立连接 + clear() 编号 : close()
withMongoMemory(fn)设 设 — 运行 — 拆 (finally(中文(简体) )
createMongoMemory原始服务器寿命周期( n)uri + 键 stop(中文(简体) )
mongoMemoryBackend()(单位:千美元) TestBackend 连接 @classytic/arc-testkit

都接受,我们接受 { replset?, dbName?, uri? }。 。 。 .

查询计划门

import { assertQueryPlan } from '@classytic/mongokit/testkit';
// The connection must be opened with { monitorCommands: true }.
await assertQueryPlan(() => repo.getAll({ filters: { status: 'open' }, sort: { at: -1 } }), {
  connection, minDocs: 1_000, leadingKeys: ['status', 'at'],   // fails on COLLSCAN / unindexed SORT
});

默认读取有门; 通过 commands: ['findAndModify', 'update', 'delete'] 写得也一样. explainCommands(run, { connection, commands?, collections?, verbosity? }) 返回每个字的原始解释 命令 run 为插件构建的查询,例如: leasePlugin 索赔:

import { explainCommands } from '@classytic/mongokit/testkit';
const { explains } = await explainCommands(() => jobs.lease({ leaseFor: 30_000, leasedBy }), {
  connection, commands: ['findAndModify'], collections: ['jobs'],
});
explains[0].explain.executionStats; // what the claim examined

内核配合—— @classytic/mongokit/kernel-conformance

一个 可执行合同套件 用于构建于 defineModels()内核 按描述 ^ 捆绑 → 校验 → 服务 → 关闭寿命周期电线进行自身测试 目录; 传送它符合.

它声称普通内核测试没有做到的: defineX(shape) 没有登记,那 bind 准确登记SUPPLIED连接上申报的模型,不执行索引 I/O,第二个捆绑扔 ModelCollisionError,即提供主机的事件运输 从来没有关闭 当一个内部创建的 close() 有天分,没有遗产 createX编号 :destroy编号 :dispose 表面幸存,一个失败的索引同步REJECS 而不是被吞没.

试跑者注射,从未导入 ——mongokit不需依赖(甚至不需依赖) 在vitest上可选的对等点),套房运行在任何暴露的跑道下无修改 describe编号 :it请求是内部的,所以没有 expect 需要执行.

import mongoose from 'mongoose';
import { describe, it } from 'vitest';
import { describeKernelConformance } from '@classytic/mongokit/kernel-conformance';
import * as kernel from '../../src/index.js';

describeKernelConformance({
  name: 'party',
  runner: { describe, it },
  // A FACTORY — purity is only observable if the suite can call defineX itself.
  blueprint: () => kernel.defineParty({ multiTenant: false, autoIndex: false }),
  // Never connected: every check is registry-level, so no server is needed.
  connect: async () => mongoose.createConnection(),
  bind: (bp, conn, ctx) => bp.bind(conn, { eventTransport: ctx.transport }),
  expectedModelNames: ['Party'],
  moduleExports: kernel,
  // Opt-outs are explicit, typed, and REQUIRE a reason; each one still emits a
  // visible `[SKIPPED] <id> — <reason>` test. A silent skip is the bug this suite exists
  // to prevent.
  skip: [{ check: 'bind-verifies-requirements', reason: '…' }],
});

硬化准备: tenantUniques

MongoDB 拒绝 shardCollection 任何独一无二的指数都缺少这个键作为它的 前缀,所以一个全球独有的索引使得一个收藏被租户无法硬化. 供应 tenantUniques 启用 unique-indexes-tenant-prefixed: 套房将内核绑起 租借权,阅读每个注册的计划指数,并要求每个独特的指数与 租户田地,或 allowGlobal 说明理由和处理时间 部署被硬化或被分解为舱(shard-key-prefix, (中文(简体) ), identity-registry, (中文(简体) ), pod-local 或者说 drop) (中文(简体) ). 当没有检查过独特的指数时,它也失败了 allowGlobal 输入.

tenantUniques: {
  tenantField: 'organizationId',
  bindScoped: (conn) => kernel.defineParty({ tenant: { enabled: true }, autoIndex: false }).bind(conn, runtime),
  allowGlobal: [{ index: 'party_site_slug', reason: 'public slug, no tenant', t2: 'identity-registry' }],
},

检查 ID 导出为 KERNEL_CONFORMANCE_CHECKS 联合国 const tu,所以 skip 是输入的 union —— 错误的 id 是编译错误,而不是无效的跳过.

许可证

麻省理工学院

商标

密码是麻省理工学院许可的. "classytic","arc",并标志为: 经典专卖局长 并且现在 没有 根据麻省理工学院颁发的许可证——见 贸易商。 。 。 . 叉子必须更名;许可证覆盖了代码,而不是品牌.

版本与发布记录

@classytic/mongokit 共发布 97 个版本,首次发布于 2025/11/09;过去 12 个月发布了 95 个版本。

版本发布日期距今
3.46.0latest2026/11/081 天前
3.45.02026/11/063 天前
3.44.02026/11/036 天前
3.43.12026/10/2119 天前
3.43.02026/10/1723 天前
3.42.02026/10/1426 天前

关于 @classytic/mongokit 的常见问题

@classytic/mongokit 是什么?

生产级MongoDB寄存器 - 智能发卡,事件和插件. 建于@classytic/repo-core上.

如何安装 @classytic/mongokit?

在项目目录运行 npm install @classytic/mongokit,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:mongoose(>=9.12.0)、@classytic/repo-core(>=0.38.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@classytic/mongokit 支持 TypeScript 吗?

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

@classytic/mongokit 支持 ESM 还是 CommonJS?

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

@classytic/mongokit 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@classytic/mongokit 可以商用吗?

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

@classytic/mongokit 的下载量有多少?

根据 npm 官方下载统计,@classytic/mongokit 在 2026/10/10 – 2026/11/08 这 30 天内被下载 2,843 次,日均约 95 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@classytic/mongokit 还在维护吗?

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