npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@mnemora/testkit

v1.2.0

Published

adapter(MemoryStore/VectorStore/EventStore の実装)が満たすべき適合テスト一式(conformance suite)。

Readme

@mnemora/testkit

adapter(MemoryStore / VectorStore / EventStore / OutboxStore / TenantSettingsStore の実装)が満たすべき適合テスト一式(conformance suite)と、 決定的な擬似 LLMProvider / EmbeddingProvider。

インストール

pnpm add -D @mnemora/testkit @mnemora/core vitest
# または
npm i -D @mnemora/testkit @mnemora/core vitest

@mnemora/testkit は vitest に依存している(describe/it/expect を内部で呼ぶ)ため、 vitest から実行するコードとして使う。テスト対象の adapter を書く側の devDependency として入れる。

vitest は peerDependencies である(ADR 0066)——このパッケージは vitest を同梱せず、 **使う側が入れた vitest をそのまま使う。**そうしないと、使う側の vitest と このパッケージが引き込む vitest の2つが node_modules に並び、describe の実体が 食い違って「テストが1本も見つからない」形の壊れ方をしうる。

前提

  • Node.js >= 22
  • ESM のみ("type": "module")。CommonJS からは Node 22.12 以降の require(esm) で読み込める(TypeScript は module/moduleResolution を nodenext にし、TypeScript 5.8 以降を使うこと。 5.7 以前の nodenext と、どの版の node16 も TS1479 になる。node10 は TypeScript 5.x なら パッケージの入口の型を解決できるが、exports を読まないので @mnemora/testkit/fixtures のような subpath は解決できず、TypeScript 6 で非推奨・7 で廃止された。2026-09-27 に TypeScript 5.0〜7.0 で実測)
  • 呼び出し側が vitest を使っていること(describeXxxConformance は 内部で describe/it/expect を呼ぶ)

動く最小の例(実際に vitest で実行して確認済み)

**adapter 作者は、自分の実装を conformance suite に食わせるだけで、テナント分離・ append-only・並び順・外部キー相当の契約などを検査できる。**以下は EventStore を 自作した場合の例(describeEventStoreConformance を使う。他に describeMemoryStoreConformance / describeVectorStoreConformance / describeLexicalStoreConformance / describeRelationStoreConformance / describeOutboxStoreConformance / describeTenantSettingsStoreConformance / describeEmbeddingProviderConformance / describeLLMProviderConformance がある)。

// my-event-store.test.ts
import { randomUUID } from "node:crypto";
import type {
  Ctx,
  EventFilter,
  EventId,
  EventStore,
  MemoryEvent,
  NewMemoryEvent,
} from "@mnemora/core";
import { assertWellFormedCtx } from "@mnemora/core";
import { describeEventStoreConformance } from "@mnemora/testkit";

// 適合テストは「memoryId が実在の Memory を指しているか」(外部キー相当)と、その Memory が
// ctx のテナントのものか(ADR 0436)も検査する。ここでは実際の MemoryStore を持たない最小の例なので、
// prepareMemoryId が登録した id だけを、登録したテナントの Memory として「実在する」ことにする素朴な実装にしてある。
const knownMemoryIds = new Map<string, string>(); // memoryId -> tenantId

class MyEventStore implements EventStore {
  private rows: MemoryEvent[] = [];

  async append(ctx: Ctx, event: NewMemoryEvent): Promise<MemoryEvent> {
    // 孤立サロゲート・NUL を含む識別子は入口で断る(適合テストが検査する約束。ADR 0423)。
    assertWellFormedCtx(ctx);
    // 実在しない Memory も、別のテナントの Memory も、同じ例外で断る(行は書かない)。
    if (event.memoryId !== null && knownMemoryIds.get(event.memoryId) !== ctx.tenantId) {
      throw new Error(`MyEventStore: memory not found for tenant: ${event.memoryId}`);
    }
    // structuredClone で複製して持つ——受け取った入力(meta の配列・オブジェクト)を
    // 呼び手が後から書き換えても、store の中身は変わらない(適合テストが検査する約束)。
    const row: MemoryEvent = structuredClone({
      id: randomUUID(),
      at: event.at ?? new Date(),
      ...event,
    });
    this.rows.push(row);
    return structuredClone(row);
  }

  async get(ctx: Ctx, id: EventId): Promise<MemoryEvent | null> {
    assertWellFormedCtx(ctx);
    const row = this.rows.find((row) => row.tenantId === ctx.tenantId && row.id === id);
    // 返す値も複製する——呼び手が受け取った値を書き換えても、次の get は影響を受けない。
    return row ? structuredClone(row) : null;
  }

  async list(ctx: Ctx, filter: EventFilter): Promise<MemoryEvent[]> {
    assertWellFormedCtx(ctx);
    return this.rows
      .filter((row) => row.tenantId === ctx.tenantId)
      .filter((row) => filter.kind === undefined || row.kind === filter.kind)
      .filter((row) => filter.memoryId === undefined || row.memoryId === filter.memoryId)
      .filter((row) => filter.since === undefined || row.at >= filter.since)
      .filter((row) => filter.until === undefined || row.at <= filter.until)
      .sort((a, b) => a.at.getTime() - b.at.getTime())
      .slice(0, filter.limit);
  }
}

describeEventStoreConformance({
  name: "my-event-store",
  createStore: () => new MyEventStore(),
  prepareMemoryId: async (ctx) => {
    const id = randomUUID();
    knownMemoryIds.set(id, ctx.tenantId);
    return id;
  },
});
npx vitest run my-event-store.test.ts

決定的な擬似 provider

LLMProvider / EmbeddingProvider の本物(@mnemora/openai)を CI で叩けない(API キーが無い)場合に備えて、決定的な擬似実装を export している。

import { DeterministicLLMProvider, DeterministicEmbeddingProvider } from "@mnemora/testkit";

const llmProvider = new DeterministicLLMProvider();
const embeddingProvider = new DeterministicEmbeddingProvider(); // 既定で 8次元

**⚠ これは本物の LLM・埋め込みモデルを模したものではない。**文字コードや文字列長から 機械的に出力を作るだけで、意味的な類似度・言語理解は一切表現しない。配線・契約・ 適合テストのための stubであり、想起の質を測る物差しにはならない (recorded 層・openai 層との違いは ADR 0051 を参照)。

ほかに export しているもの(約束は各 TSDoc)

  • 記録を再生する provider(ADR 0051): RecordedLLMProvider・RecordedEmbeddingProvider はカセット(Cassette)に記録した実 API の応答を再生する。 **記録に無い入力は例外にする。**録る側は CassetteRecorder と、実 provider を包む RecordingLLMProvider・RecordingEmbeddingProvider。カセットの形の検査は assertCassette (CASSETTE_FORMAT_VERSION)、鍵は llmCassetteKey・embeddingCassetteKey。 壊れたカセットは読んだ時点で落ちる(成分が有限でない・embedding.space.dimensions が正の整数でない・鍵が text/prompt から導いた値と一致しない。 ADR 0452)。CassetteRecorder は、違う埋め込み空間・モデル名の2回目以降の記録を断る。 RecordingEmbeddingProvider は、delegate の壊れた戻り(次元違い・有限でない成分)を記録せずに落ち、同じ入力の並列の呼びでも delegate を1回だけ呼ぶ。
  • 種カセットから返す provider: SeededLLMProvider・SeededEmbeddingProvider。種に在る入力は種から返し、 種に無い入力だけ実 provider(delegate)へ流す(Recorded* とは逆の規律)。種のモデル名・埋め込み空間が expectedModel・expectedSpace(必須)と食い違えば構築時に落ちる(埋め込みは delegate.space とも照合する。ADR 0452)。
  • テストデータのひな型: buildNewMemoryFixture・buildNewObservationFixture・buildNewMemoryEventFixture・ buildProvenanceFixture。⚠ 実時計で recall() を通すなら、recordedAt(必要なら decayFloorAt)を明示して 渡すこと(既定値のままだと減衰の床を越えて0件になる。buildNewMemoryFixture の TSDoc)。
  • 適合スイートの各 options の型(MemoryStoreConformanceOptions など)は、対応する describe*Conformance の引数。

@mnemora/testkit/fixtures(インメモリの store。適合スイートの入力にしない)

@mnemora/testkit/fixtures は、InMemoryMemoryStore・InMemoryVectorStore・InMemoryLexicalStore・ InMemoryRelationStore・InMemoryEventStore・InMemoryOutboxStore・InMemoryTenantSettingsStore を export する別の入口である。 DB 無しで createRuntime を組み立てて、本物の provider を通しで動かすためにある。

⛔ これを describe*Conformance の createStore に渡してはいけない——自分の adapter を1文字も測らないまま 緑になる(そのため @mnemora/testkit の入口からは export していない)。Postgres が拒む入力を同じく拒むが、 例外の顔は違う(packages/postgres/README.md「例外の見分け方」)。揃えてあるものと揃えていないものの一覧は src/fixtures.ts の冒頭にある。

もっと詳しく

  • docs/architecture.md §5 — 各 interface の契約
  • ADR 0051 — provider の3層 (deterministic / recorded / openai)の使い分け
  • ADR 0047 — 擬似実装の外部キー相当の扱い
  • リポジトリ: https://github.com/takecchi/mnemora