{"_id":"@pixygon/knowledge-server","name":"@pixygon/knowledge-server","description":"Storage + extraction + chunking + semantic search engine for any text knowledge. Used by @pixygon/chatbot-server for RAG; can also back a wiki/codex search layer.","dist-tags":{"latest":"0.1.3"},"versions":{"0.1.0":{"name":"@pixygon/knowledge-server","version":"0.1.0","_id":"@pixygon/knowledge-server@0.1.0","maintainers":[{"name":"imakestupidgames","email":"anders@pixygon.io"}],"dist":{"shasum":"522a5e3f2a697a77e92e0291c772a0c328695b1f","unpackedSize":38421,"fileCount":4,"integrity":"sha512-Vp1tli6WbSuI6ffHZhb4RIIcAikL6DeVVK39VWX0/h0C2yEku8Wi3x9GseyaAol0Xx5bnF/Uf8e8Onwo9KIvyQ==","tarball":"https://ppm.pixygon.io/@pixygon/knowledge-server/-/knowledge-server-0.1.0.tgz"},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"d464e7f9801bea6a4501e3ce8940969ee349f0a4","scripts":{"build":"tsup src/index.ts --format esm --dts --clean --target node22 --tsconfig tsconfig.json","typecheck":"tsc --noEmit"},"_npmUser":{"name":"imakestupidgames","email":"anders@pixygon.io"},"_npmVersion":"11.16.0","description":"Storage + extraction + chunking + semantic search engine for any text knowledge. Used by @pixygon/chatbot-server for RAG; can also back a wiki/codex search layer.","directories":{},"_nodeVersion":"26.2.0","dependencies":{"zod":"^3.23.0","xlsx":"^0.18.5","jsdom":"^25.0.0","multer":"^1.4.5-lts.1","mammoth":"^1.8.0","pdf-parse":"^1.1.1","@mozilla/readability":"^0.5.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","express":"^5.1.0","mongoose":"^8.15.0","typescript":"^5.7.0","@types/node":"^22.10.0","@types/jsdom":"^21.1.7","@types/multer":"^1.4.12","@types/pdf-parse":"^1.1.4"},"peerDependencies":{"express":"^5.0.0","mongoose":"^8.0.0"},"_npmOperationalInternal":{"tmp":"tmp/knowledge-server_0.1.0_1781696813928_0.20408978931832267","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@pixygon/knowledge-server","version":"0.1.1","_id":"@pixygon/knowledge-server@0.1.1","maintainers":[{"name":"imakestupidgames","email":"anders@pixygon.io"}],"dist":{"shasum":"7af79f8f69a4f86a062b2fee81fec52283aa3cf4","unpackedSize":38439,"fileCount":4,"integrity":"sha512-V6DgqOC5Dl5TAFYWrKxQNanM3g0ngMCO1h2KKVHEqgVTg43th6QZOFlAYL/shMb7DyN+5muJgSJ+wrsqMtvg8A==","tarball":"https://ppm.pixygon.io/@pixygon/knowledge-server/-/knowledge-server-0.1.1.tgz"},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"d464e7f9801bea6a4501e3ce8940969ee349f0a4","scripts":{"build":"tsup src/index.ts --format esm --dts --clean --target node22 --tsconfig tsconfig.json","typecheck":"tsc --noEmit"},"_npmUser":{"name":"imakestupidgames","email":"anders@pixygon.io"},"_npmVersion":"11.16.0","description":"Storage + extraction + chunking + semantic search engine for any text knowledge. Used by @pixygon/chatbot-server for RAG; can also back a wiki/codex search layer.","directories":{},"_nodeVersion":"26.2.0","dependencies":{"zod":"^3.23.0","xlsx":"^0.18.5","jsdom":"^25.0.0","multer":"^1.4.5-lts.1","mammoth":"^1.8.0","pdf-parse":"^1.1.1","@mozilla/readability":"^0.5.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","express":"^5.1.0","mongoose":"^8.15.0","typescript":"^5.7.0","@types/node":"^22.10.0","@types/jsdom":"^21.1.7","@types/multer":"^1.4.12","@types/pdf-parse":"^1.1.4"},"peerDependencies":{"express":"^5.0.0","mongoose":"^8.0.0"},"_npmOperationalInternal":{"tmp":"tmp/knowledge-server_0.1.1_1781699377725_0.6011166695360373","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@pixygon/knowledge-server","version":"0.1.2","_id":"@pixygon/knowledge-server@0.1.2","maintainers":[{"name":"imakestupidgames","email":"anders@pixygon.io"}],"dist":{"shasum":"d861cb0749b256ad007b8c21aa7785b4ea5ae844","unpackedSize":38456,"fileCount":4,"integrity":"sha512-or1+yR9wiL3W90fHYZ5t+vj3M/9Tko+zkHoFwjl/iDMnZgwyClw9e86QDZjBr0imKlzdpKllPt/gzmKlwLAShg==","tarball":"https://ppm.pixygon.io/@pixygon/knowledge-server/-/knowledge-server-0.1.2.tgz"},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"d464e7f9801bea6a4501e3ce8940969ee349f0a4","scripts":{"build":"tsup src/index.ts --format esm --dts --clean --target node22 --tsconfig tsconfig.json","typecheck":"tsc --noEmit"},"_npmUser":{"name":"imakestupidgames","email":"anders@pixygon.io"},"_npmVersion":"11.16.0","description":"Storage + extraction + chunking + semantic search engine for any text knowledge. Used by @pixygon/chatbot-server for RAG; can also back a wiki/codex search layer.","directories":{},"_nodeVersion":"26.2.0","dependencies":{"zod":"^3.23.0","xlsx":"^0.18.5","jsdom":"^25.0.0","multer":"^1.4.5-lts.1","mammoth":"^1.8.0","pdf-parse":"^1.1.1","@mozilla/readability":"^0.5.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","express":"^5.1.0","mongoose":"^8.15.0","typescript":"^5.7.0","@types/node":"^22.10.0","@types/jsdom":"^21.1.7","@types/multer":"^1.4.12","@types/pdf-parse":"^1.1.4"},"peerDependencies":{"express":">=4.18.0 <6.0.0","mongoose":">=6.8.0 <9.0.0"},"_npmOperationalInternal":{"tmp":"tmp/knowledge-server_0.1.2_1781699396783_0.3484965142658496","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"name":"@pixygon/knowledge-server","version":"0.1.3","description":"Storage + extraction + chunking + semantic search engine for any text knowledge. Used by @pixygon/chatbot-server for RAG; can also back a wiki/codex search layer.","type":"module","main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"publishConfig":{"access":"public"},"scripts":{"build":"tsup src/index.ts --format esm --dts --clean --target node22 --tsconfig tsconfig.json","typecheck":"tsc --noEmit"},"peerDependencies":{"express":">=4.18.0 <6.0.0","mongoose":">=6.8.0 <9.0.0"},"dependencies":{"@mozilla/readability":"^0.6.0","jsdom":"^25.0.0","mammoth":"^1.8.0","multer":"^2.2.0","pdf-parse":"^1.1.1","xlsx":"https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz","zod":"^3.23.0"},"devDependencies":{"@types/jsdom":"^21.1.7","@types/multer":"^1.4.12","@types/node":"^22.10.0","@types/pdf-parse":"^1.1.4","express":"^5.1.0","mongoose":"^8.15.0","tsup":"^8.5.0","typescript":"^5.7.0"},"gitHead":"49e6fae00189c9e7bf4a7a3078d4c5d575e44196","_id":"@pixygon/knowledge-server@0.1.3","_nodeVersion":"26.2.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-Pkfag+5XD6dQCn2Swn4wYrEbbyLqIvDdmjXW5h1Q33F4C9mK7n1sq2z+QxldEBccyh9/HoDWimhkSzR19kiy2A==","shasum":"490605041f639eb378d395d008f8aa956ad89c81","unpackedSize":38494,"fileCount":4,"tarball":"https://ppm.pixygon.io/@pixygon/knowledge-server/-/knowledge-server-0.1.3.tgz"},"_npmUser":{"name":"imakestupidgames","email":"anders@pixygon.io"},"directories":{},"maintainers":[{"name":"imakestupidgames","email":"anders@pixygon.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/knowledge-server_0.1.3_1785705489844_0.700596759142263"},"_hasShrinkwrap":false}},"time":{"0.1.0":"2026-06-17T11:46:54.077Z","modified":"2026-09-30T23:30:49.286Z","created":"2026-06-17T11:46:54.077Z","0.1.1":"2026-06-17T12:29:37.874Z","0.1.2":"2026-06-17T12:29:56.931Z","0.1.3":"2026-08-02T21:18:10.015Z"},"readme":"# @pixygon/knowledge-server\n\nStorage + extraction + chunking + semantic search for any text knowledge.\n\n```\n+--------------------+      +-------------------------+\n|  Host Express app  |----->|     engine.router       |\n|  (your auth here)  |      +-------------------------+\n+--------------------+               |\n                                     v\n  KnowledgeDocument · KnowledgeChunk · extractors · embedder · search\n```\n\nUsed by:\n\n- `@pixygon/chatbot-server` — calls `engine.search()` from the RAG pipeline\n- (planned) Codex / wiki — calls `engine.upsertExternal()` on entry save to keep an embedding index in sync with the rich domain model\n\n---\n\n## What it does\n\n- **Documents.** Operator pastes text, uploads PDF/DOCX/XLSX/CSV/TXT/MD, points at a URL (scraped once + embedded), or points at a URL marked _live_ (re-fetched at query time).\n- **Extraction.** `pdf-parse`, `mammoth`, `xlsx`, `@mozilla/readability` + `jsdom` cover the common ingest paths.\n- **Chunking.** Paragraph-aware splitter producing ~2 KB chunks with 400-char overlap.\n- **Embedding.** Whatever AI client the host passes — text in, vector out.\n- **Search.** Cosine-similarity top-K over the embedding index, namespace-scoped.\n- **Namespaces.** Multiple knowledge silos per tenant (`chatbot`, `codex`, `wiki`, `help-center`, …) — search defaults to one namespace at a time, but cross-namespace queries are explicit.\n- **External refs.** A knowledge document can be linked back to a host-domain entity (a codex `LoreEntity`, an LMS `Lesson`, etc.). `engine.upsertExternal()` keeps the index in sync as the host model changes.\n\n---\n\n## Install\n\n```bash\nnpm install @pixygon/knowledge-server\n```\n\nPeer expectations:\n\n- `express` ≥ 5\n- `mongoose` ≥ 8\n- Node ≥ 22\n\n---\n\n## Usage\n\n```ts\nimport mongoose from \"mongoose\";\nimport { createKnowledge } from \"@pixygon/knowledge-server\";\n\n// Any object matching { embed(text), chat?({ messages, system }) } works.\n// `@pixygon/chatbot-server`'s `createAiClient` returns this shape.\nconst ai = {\n  async embed(text: string) {\n    const e = await myEmbeddingClient.embed(text);\n    return { embedding: e.vector, tokens: e.tokens };\n  },\n  async chat({ messages, system }: any) {\n    const r = await myChatClient.chat({ messages, system });\n    return { content: r.text };\n  },\n};\n\nconst knowledge = createKnowledge({\n  mongoose,\n  ai,\n  tenantField: \"tenantId\",\n  tenantRefName: \"Tenant\",\n  defaultNamespace: \"default\",\n  plugins: [\n    (schema, label) => schema.plugin(tenantScopedPlugin, { tenantField: \"tenantId\", label }),\n    (schema, label) => schema.plugin(auditLogPlugin, { entityType: label }),\n  ],\n});\n\n// Mount the default HTTP router under whatever path the host owns.\napp.use(\"/v1/tenants/:tenantId\", verifyToken, tenantAccess, knowledge.router);\n\n// Programmatic search — used by RAG pipelines, codex search, etc.\nconst hits = await knowledge.search({\n  tenantId, query: \"fall protection rules\", namespace: \"chatbot\", k: 5,\n});\n\n// Codex-style external sync. Idempotent — upsert by (namespace, externalRef).\nawait knowledge.upsertExternal({\n  tenantId,\n  namespace: \"codex\",\n  externalModelName: \"LoreEntity\",\n  externalId: loreEntity._id,\n  title: loreEntity.name,\n  content: loreEntity.description,\n  source: `codex/${loreEntity.slug}`,\n  tags: loreEntity.tags,\n});\n```\n\n---\n\n## HTTP surface\n\nDefault router (`engine.router`):\n\n```\nGET    /knowledge                  ?namespace=&sourceType=\nGET    /knowledge/search           ?q=&namespace=&k=\nGET    /knowledge/:id\nPOST   /knowledge                  text       { title, content, source?, namespace?, tags? }\nPOST   /knowledge/upload           multipart  file, title?, namespace?, tags?\nPOST   /knowledge/from-url         json       { url, title?, namespace?, extractInstruction?, isLive?, liveDescription?, tags? }\nPUT    /knowledge/:id              { title?, content?, source?, tags?, namespace? }\nDELETE /knowledge/:id\n```\n\n---\n\n## Companion package\n\n`@pixygon/knowledge-react` ships the operator UI (list, tabbed upload dialog, RTK Query hooks) — see its README for the React wire-up.\n\n## License\n\nMIT.\n","readmeFilename":"README.md"}