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

@x12i/memorix-writer

v1.34.0

Published

Descriptor-driven write layer for Memorix entity/event records and content objects

Downloads

3,985

Readme

@x12i/memorix-writer

Descriptor-driven write layer for Memorix. Turns Catalox write descriptors, entity descriptors, validated input, and optional Markdown/text content into Memorix records and external content object pointers.

Shared MongoDB naming rules: docs/MEMORIX-DATABASE-CONVENTIONS.md.

Architecture

  • Cataloxmemorix-write-descriptors, memorix-object-type-descriptors. Catalog metadata lives in MongoDB (memorix-catalox via @x12i/catalox/mongo). Firestore is not used for Memorix Catalox.
  • MongoDB — built-in MemorixDataTier + collection-name CRUD (no separate @x12i/memorix package)
  • @x12i/memorix-descriptors — shared catalog ids and descriptor validation (aligned with retrieval)
  • @x12i/helpers — GCS/S3 content uploads (contentWriters.gcs / contentWriters.s3)
  • @x12i/memorix-retrieval (optional) — returnMode: "retrievalItem"

Quick start

Set MONGO_URI and provide a Catalox client. Database names, entity vs event routing, and collection resolution are handled internally.

MONGO_URI=mongodb://localhost:27017
import {
  createMemorixWriterFromEnv,
  writeMemorixRecord,
} from "@x12i/memorix-writer";

const writer = await createMemorixWriterFromEnv({
  catalox: boundCatalox, // must implement getCatalogItem(appId, catalogId, itemId)
  contentWriters: {
    gcs: myGcsUploader, // uploadObject({ key, body, contentType })
  },
});

const result = await writeMemorixRecord(writer, {
  writeDescriptorId: "asset-analysis-write",
  entityId: "10.150.68.31",
  input: { riskLevel: "HIGH", summary: "..." },
  metadata: { source: { uri: "file://scan.json" } },
  tags: ["risk", "source-scan"],
  narratives: {
    "high-risk": { detectedBy: "risk-worker" },
  },
  content: {
    fields: {
      investigationReport: { body: "# Report\n...", format: "markdown" },
    },
  },
});

await writer.close?.();

Lazy connect (same env, no upfront await):

import { createMemorixWriter, writeMemorixRecord } from "@x12i/memorix-writer";

const writer = createMemorixWriter({ catalox: boundCatalox });
// connects to Mongo on first write using MONGO_URI

Advanced (optional)

Override defaults only when you need to:

| Option | Purpose | |--------|---------| | MEMORIX_ENTITIES_DB / MEMORIX_EVENTS_DB | Non-default database names | | MEMORIX_ENTITIES_COLLECTION_* / MEMORIX_EVENTS_COLLECTION_* | Per-type collection overrides | | memorix | Inject a pre-configured MemorixDataTier instead of built-in Mongo connect | | mongo | Reuse an existing MongoClient | | processEnv | Custom env object (default: process.env) |

Collection resolution

Writes target memorix-entities, memorix-events, or memorix-knowledge based on the write descriptor (target.kind, defaulting from the descriptor's identity.idField config). Database names follow Memorix Database Conventions (MEMORIX_ENTITIES_DB, MEMORIX_EVENTS_DB, MEMORIX_KNOWLEDGE_DB, …).

Identity model

Every record this package writes uses the memorix-record.2.0 envelope — a nested identity object, not flat top-level id fields:

{
  "identity": {
    "recordId": "rec_...",
    "target": "entity",
    "targetId": "10.150.68.31",
    "objectType": "assets",
    "contentType": "analysis",
    "version": "memorix-record.2.0"
  },
  "lifecycle": { "createdAt": "...", "modifiedAt": "...", "status": "active" },
  "concept": { "kind": "assets", "name": "10.150.68.31" },
  "data": { "...": "..." }
}

entityId / eventId / knowledgeId are request-time parameter names on writeMemorixRecord — pass exactly one to say which target and which id value you're writing:

| Target | Request field | Written to | |--------|----------------|------------| | entity | entityId | identity.target: "entity", identity.targetId | | event | eventId | identity.target: "event", identity.targetId | | knowledge | knowledgeId | identity.target: "knowledge", identity.targetId |

They are never stored as flat root fields, and there is no client-facing idField concept — clients read/write identity via the identity object (and, for narrative/search context, the concept object). This package will not add a flat-id or idField public API even on request, since it would break the memorix-record.2.0 contract for every downstream consumer. See MEMORIX-DATABASE-CONVENTIONS.md for the full shape and rationale.

Internally, @x12i/memorix-writer tolerates reading older, pre-2.0 records that only have a flat entityId/eventId (see docs/GRAPH-RUNS.md § Identity resolution) so graph-run tracking keeps working during a tenant's migration window. That fallback is read-only, internal, and not exported — it does not change what gets written, and it is not something applications should rely on or target.

Collection name resolution order:

  1. Explicit override (API/code parameter)
  2. Write descriptor target.targetCollection
  3. Entity descriptor content type collection
  4. MEMORIX_ENTITIES_COLLECTION_* / MEMORIX_EVENTS_COLLECTION_* env vars
  5. Write descriptor target.targetCollectionCandidates
  6. Content-type slice {collectionPrefix}-{postfix} (e.g. assets-analysis)
  7. Built-in defaults for known entityType values
  8. Heuristic (<entityType> or <entityType>-events)
  9. Verify the collection exists in the target database (skipped for dryRun / validateOnly)

For content-type slices, step 6 runs before canonical entity defaults so assets + analysis still resolves to assets-analysis unless overridden explicitly.

Generic Annotations

writeMemorixRecord and writeMemorixRecords expose generic annotation hooks that work across entity, event, and knowledge targets:

| Request field | Written shape | |---------------|---------------| | metadata | _memorix.metadata | | tags | _memorix.tags | | narratives | narratives.{key} |

Narrative keys use the same top-level narratives.{key} shape consumed by @x12i/memorix-retrieval helpers such as fetchMemorixNarrativeRecords. This is only a generic tag/write primitive; applications still own narrative detection, descriptor design, and domain-specific relation names.

Operations

| Operation | Default | Notes | |-----------|---------|--------| | add | yes | Always inserts a new record | | upsert | descriptor-gated | Requires conflict.matchBy | | patch | descriptor-gated | Updates writable fields on existing row | | replace | descriptor-gated | Full replace |

Catalox seeds

Catalog metadata for this package (write descriptors, entity descriptors) is managed in MongoDB — the memorix-catalox database. The manifest below is the source of truth for what gets applied there.

Validate the write descriptor seed:

npm run catalox:seed:write-descriptors:validate

Apply the manifest to Mongo memorix-catalox (uses MONGO_URI + MEMORIX_CATALOX_DB) — this is the normal way to publish or update descriptors:

npm run catalox:seed:write-descriptors:apply

Seed file: catalox-seeds/memorix-write-descriptors.manifest.json

Shipped write descriptors include asset-analysis-write (entity) and corpus helpers content-documents-snapshot-write / content-documents-chunk-write (knowledge target). Record builders: @x12i/memorix-corpus.

Acceptance criteria

| ID | Status | |----|--------| | AC-1 | Generic descriptor-driven write | | AC-2 | Prefix/postfix collection resolution | | AC-3 | Identity: exactly one of entityId / eventId / knowledgeId, written to identity.targetId | | AC-4 | Default operation add | | AC-5 | Upsert only when allowed | | AC-6 | Patch only when allowed | | AC-7 | Writable field allowlist / unknown fields | | AC-8 | Required fields | | AC-9 | Content body → object storage + pointer | | AC-10 | Existing content pointer | | AC-11 | Content maxBytes | | AC-12 | No secrets in descriptors | | AC-13 | Idempotency | | AC-14 | dryRun | | AC-15 | validateOnly | | AC-16 | Retrieval delegated when configured | | AC-17 | Generic metadata, tags, narrative tags, and knowledge writes |

Graph-run tracking (_graphRuns) — MRX-FRS-001

System-only APIs for Exellix jobs graph execution tracking. Domain writeMemorixRecord rejects _graphRuns in input.

import {
  markGraphRunStarted,
  markGraphRunFailed,
  writeGraphRunResult,
  clearGraphRun,
  ensureGraphRunIndexes,
} from "@x12i/memorix-writer";

| API | Purpose | |-----|---------| | markGraphRunStarted | Stamp in_progress (idempotent per jobRunId) | | markGraphRunFailed | Terminal failure stamp | | writeGraphRunResult | Upsert result doc + stamp source done (best-effort compensation) | | clearGraphRun | Force re-run via $unset | | ensureGraphRunIndexes | Opt-in planning-query indexes |

Full contract: docs/GRAPH-RUNS.md.

Job-type run tracking (_jobTypeRuns) — MRX-CR-003

Parallel stamp APIs keyed by jobTypeId (shared GraphRunEntry shape). Domain writes reject _jobTypeRuns in input.

import {
  markJobTypeRunStarted,
  markJobTypeRunCompleted,
  markJobTypeRunFailed,
  ensureJobTypeRunIndexes,
} from "@x12i/memorix-writer";

Full contract: docs/JOB-TYPE-RUNS.md.

Entity collection bootstrap — MRX-CR-005

import { initializeEntityCollections } from "@x12i/memorix-writer";

await initializeEntityCollections(client, "assets", {
  contentTypes: ["core", "inferences"],
  graphRunIndexes: true,
  jobTypeRunIndexes: true,
});

Idempotent: creates missing collections and ensures standard indexes (idx_updatedAt, idx_graphRuns, optional idx_jobTypeRuns, etc.).

Development

npm run build
npm test

Mongo collection I/O is built in (insertMemorixCollectionDocument, etc. under src/mongo/).

Publish

npm run build
npm publish --access public

Or from the x12i workspace root: ./scripts/publish-memorix-packages.sh