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

@teo_dev/keen-sdk-types

v1.0.11

Published

Unified type definitions for Keen Engine SDK modules

Readme

@teo_dev/keen-sdk-types

Unified TypeScript type definitions for all Keen Engine SDK modules.

Installation

npm install @teo_dev/keen-sdk-types

Included SDKs

| Module | Type File | Description | |---|---|---| | system/files | SDK_Files.d.ts | File management, processing, and factory | | system/chat | SDK_Chat.d.ts | Real-time chat output and sub-agent streaming | | system/log | SDK_Logs.d.ts | Logging (error, warning, info, debug) | | system/flow | SDK_Flow.d.ts | Flow pipeline execution | | system/agent | SDK_Agent.d.ts | Agent response history and prompt injection | | system/session | SDK_Session.d.ts | Session key/value storage | | system/tools | SDK_Tools.d.ts | Utility helpers like UUIDs and timestamps | | system/database | SDK_Database.d.ts | Database operations (sessions, agents, messages) |

Usage

Once installed, import directly from the system modules inside your sandbox:

Files

The Files SDK exposes three entry points:

  • FilesManager — upload, search, get/update/delete file records
  • FilesProcessor — format-specific operations (pdf.*, excel.*, word.*, text.*)
  • FilesFactory — wrap raw FileData into typed file instances (FilePDF, FileMSExcel, FileMSWord, ...)

Most operations are also available directly on file instances (e.g. file.styleRange(...)).

Upload, search, copy, delete

import { FilesManager, FilesProcessor } from 'system/files';

// Upload from a Buffer (Node) — `expiresIn` removes the file after the duration
const file = await FilesManager.uploadBuffer(buffer, 'report.pdf', {
    expiresIn: { minutes: 30 }
});

// Or from base64
const fromBase64 = await FilesManager.createFromBase64({
    originalName: 'notes.txt',
    data: 'SGVsbG8sIHRoaXMgaXMgbXkgZmlsZQ==',
});

// Lookup by id, search, copy, delete
const fetched = await FilesManager.getFileById(file.data.id);
const matches = await FilesManager.searchFiles({ mimeType: 'application/pdf' });
const copy    = await fetched.copy({ expiresIn: { minutes: 5 } });
await copy.delete();

Wrap raw FileData with FilesFactory

When you already have a raw FileData record (from getFileByIdRaw, a search result, or persisted state) and want a typed instance with operation methods, use FilesFactory.create. The correct subclass is chosen automatically from the MIME type.

import { FilesManager, FilesFactory, FileMSExcel } from 'system/files';

// Pull the plain record (no methods, just data)
const raw = await FilesManager.getFileByIdRaw('616372e7-dcfe-4b56-9acb-b8036d684389');

// Wrap it into a typed file instance
const file = FilesFactory.create(raw);

// Narrow + use Excel-specific operations
if (file instanceof FileMSExcel) {
    const range = await file.readRange({ sheet: 'Sheet1', range: 'A1:C10' });
    await file.styleRange({
        sheet: 'Sheet1',
        range: 'A1:C1',
        style: { font: { bold: true }, border: { bottom: { style: 'thin' } } },
    });
}

PDF

const pdf = await FilesManager.getFileById('f7730e41-1aa7-4f50-8d71-a603d87ea0f5');

// Read
const info = await pdf.getInfo();                         // page count, metadata, bookmarks
const text = await pdf.getText({ pages: [1, 2, 3] });     // extract specific pages

// Create new files
const pages  = await pdf.extractPages({ pageRanges: [{ startPage: 1, endPage: 10 }] });
const images = await pdf.extractImages({ format: 'jpeg' });
const rendered = await pdf.pagesToImages({ format: 'jpeg' });

// Update in place
await pdf.addPageNumbers({ startAt: 1, format: 'Page {page} of {total}', fontSize: 11 });
await pdf.compress({ imageDpi: 72 });

// Async variant for long-running ops — returns a processing id to poll
const job = await pdf.extractPagesAsync({}, { expiresIn: { minutes: 5 } });
const status = await FilesProcessor.getFPOperation(job.fileProcessingId);

Excel

// Create a workbook with named sheets
const wb = await FilesProcessor.excel.createWorkbook(
    { name: 'Report', sheets: ['Summary', 'Data'] },
    { expiresIn: { minutes: 30 } }
);

// Read / write
const range = await wb.readRange({ sheet: 'Summary', range: 'A1:C10' });
const cell  = await wb.readCell({ sheet: 'Summary', cell: 'B2' });

await wb.updateRange({
    sheet: 'Summary',
    range: 'A1:C2',
    values: [['Header A', 'Header B', 'Header C'], [1, 2, 3]],
});
await wb.updateCell({ sheet: 'Summary', cell: 'D2', value: 'note' });

// Sheet management
await wb.addSheet({ name: 'Notes' });
await wb.copySheet({ sheet: 'Summary', name: 'Summary_Backup' });
await wb.deleteSheet({ sheet: 'Notes' });

// Row / column manipulation
await wb.insertRow({ sheet: 'Summary', row: 3, count: 2 });
await wb.deleteRow({ sheet: 'Summary', row: 5 });
await wb.insertColumn({ sheet: 'Summary', column: 'B' });
await wb.deleteColumn({ sheet: 'Summary', column: 'D' });

// Style cells — font, fill, alignment, number format, borders, protection.
// Properties merge with existing styles; only what you pass is changed.
await wb.styleRange({
    sheet: 'Summary',
    range: 'A1:C1',
    style: {
        font:      { bold: true, color: '#FFFFFF', size: 14 },
        fill:      { color: '#003366' },                                     // pattern defaults to solid
        alignment: { horizontal: 'center', vertical: 'center' },
        border:    { bottom: { style: 'medium', color: '#000000' } },
        numberFormat: '0.00',
    },
});

// Merge / unmerge cells. Only the top-left value/format survives a merge.
// Unmerge fails if the range doesn't match an existing merge exactly.
await wb.mergeCells({ sheet: 'Summary', range: 'A1:C1' });
await wb.unmergeCells({ sheet: 'Summary', range: 'A1:C1' });

// Workbook info
const meta = await wb.getInfo();   // sheets, dimensions, named ranges, document properties

Word

// Create a document, optionally pre-seeded with paragraphs
const doc = await FilesProcessor.word.createDocument(
    { name: 'agreement', paragraphs: ['First paragraph.', 'Second paragraph.'] },
    { expiresIn: { minutes: 30 } }
);

// Read
const text = await doc.getText({ header: true, footer: true });
const info = await doc.getInfo();   // word/paragraph/table counts, headings, hasMacros, etc.

// Replace literal text across body, tables, headers and footers
await doc.replaceText({ find: 'TODO', replace: 'Done', caseSensitive: true });

// Export to PDF — returns a new FilePDF
const pdf = await doc.exportToPdf({ name: 'agreement.pdf' });

// Render a template with variables. Templates support a full template language
// (see the wordRenderTemplateParams JSDoc for the complete syntax reference):
//
//   • Inline:      {{ user.name }}, {{ items|length }}
//   • Conditional: {%if isActive %} ... {% endif %}      (or {%p if %} for paragraph removal)
//   • Loops:       {%p for item in items %} ... {%p endfor %}
//   • Table rows:  {%tr for row in rows %} ... {%tr endfor %}
//   • Filters:     {{ value | upper }}, comparisons, expressions
const filled = await doc.renderTemplate({
    name: 'invoice-2026-04',
    variables: {
        clientName: 'Acme Corp',
        showSection: true,
        rows: [
            { num: 1, item: 'Consulting', amount: 1200 },
            { num: 2, item: 'Hosting',    amount:  300 },
        ],
    },
});

Text

// Create a plain text file (defaults to "text.txt" if no name given)
const note = await FilesProcessor.text.createTextFile(
    { name: 'notes', content: 'First line.\n' },
    { expiresIn: { minutes: 30 } }
);

// Read
const info    = await note.getInfo();      // { lines, chars, bytes, words }
const content = await note.getContent();   // full UTF-8 string

// Update — full replacement
await note.updateContent({ content: 'Replaced content.\n' });

// Append — no automatic newline is inserted between old and new content
await note.appendContent({ content: 'Second line.\n' });

// Replace literal text (all occurrences, no regex)
await note.replaceText({ find: 'Second', replace: 'Last', caseSensitive: true });

Chat

import Chat from 'system/chat';

Chat.writeOut('Hello from the agent!');
Chat.writeThinking('Processing your request...');
Chat.writeError('Something went wrong');

// Sub-agent streaming
Chat.writeAgentStart(mainSessionId, subSessionId, 'DataAgent');
Chat.writeAgentStream(subSessionId, 'partial response...');
Chat.writeAgentEnd(subSessionId, 'completed');
Chat.writeFiles([{ id: 'file-1', originalName: 'report.pdf', mimeType: 'application/pdf', size: 1024 }]);

Log

import Log from 'system/log';

Log.info('Processing started');
Log.warning('Rate limit approaching');
Log.error('Connection failed');
Log.debug('Payload received: ...');

Flow

import Flow from 'system/flow';

const result = await Flow.run('Main-Start', { key: 'value' });

if ('error' in result) {
    Chat.writeError(result.message);
} else {
    Chat.writeOut(JSON.stringify(result)); // dictionary returned from pipeline
}

Agent

import Agent from 'system/agent';

const lastResponse = Agent.getAgentLastResponse('WriterAgent');

const promptResult = Agent.setAgentPrompt('WriterAgent', {
    sessionID: 'session-123',
    prompt: 'Summarize the uploaded files.',
    role: 'user'
});

if (promptResult?.error) {
    Chat.writeError(promptResult.message);
}

Session

import Session from 'system/session';

// Built-in keys available by default: "sessionID", "email", "userID", "requestID"
const sessionId = Session.getSessionValue('sessionID');
const email = Session.getSessionValue('email');
const userId = Session.getSessionValue('userID');
const requestId = Session.getSessionValue('requestID');

// You can also store and retrieve custom values
Session.setSessionValue('draftMode', true);

if (Session.hasSessionKey('draftMode')) {
    Chat.writeOut(JSON.stringify(Session.getSessionValue('draftMode')));
}

Chat.writeOut(JSON.stringify(Session.getSessionSize()));

Database

import Database from 'system/database';
import Chat from 'system/chat';
import Session from 'system/session';

const sessionId = Session.getSessionValue('sessionID') as string;

// Session
let session = await Database.Session.get(sessionId);

if (!session) {
    session = await Database.Session.create({ sessionId });
    Chat.writeOut('Session created.');
}

Chat.writeOut(JSON.stringify(session));

// Agent
// We can extract the actual agent/nodeId from this response
const agents = await Database.Agent.getBySession(sessionId);
const nodeId = agents[0]?.nodeId;
Chat.writeOut(JSON.stringify(agents));

// Message
const created = await Database.Message.create({
    sessionId,
    nodeId,
    role: 'user',
    content: 'Summarize the project status.',
    systemCall: 0,
    systemResponse: 0,
    prePrompt: 0,
    skipOtherReason: 0,
    filePaths: [{ path: '/tmp/report.pdf' }],
    specialRules: [{ type: 'custom', results: 'Return 3 bullets only.' }]
});

const messages = await Database.Message.get(sessionId, nodeId);
Chat.writeOut(JSON.stringify(messages));

const updated = await Database.Message.update(created.id, {
    content: 'Summarize in valid JSON.',
    specialRules: [{ type: 'custom', results: 'Output must be JSON.' }]
});

Chat.writeOut(JSON.stringify(updated));

Tools

import Tools from 'system/tools';

const requestId = Tools.generateUUID();
const startedAt = Tools.getTimestamp();

Project Structure

keen-sdk-types/
├── package.json
├── index.d.ts              <- references all SDK type files
└── types/
    ├── SDK_Files.d.ts      <- system/files
    ├── SDK_Chat.d.ts       <- system/chat
    ├── SDK_Logs.d.ts       <- system/log
    ├── SDK_Flow.d.ts       <- system/flow
    ├── SDK_Agent.d.ts      <- system/agent
    ├── SDK_Session.d.ts    <- system/session
    ├── SDK_Tools.d.ts      <- system/tools
    └── SDK_Database.d.ts   <- system/database

Adding a New SDK

  1. Create a new type file in types/ (e.g. SDK_Storage.d.ts)
  2. Add a /// <reference path="./types/SDK_Storage.d.ts" /> line in index.d.ts
  3. Bump the version and publish

Publishing

npm login
npm publish --access public