Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion apps/website/docs/api-reference/commandkit/classes/kv.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import MemberDescription from '@site/src/components/MemberDescription';

## KV

<GenerationInfo sourceFile="packages/commandkit/src/kv/kv.ts" sourceLine="42" packageName="commandkit" />
<GenerationInfo sourceFile="packages/commandkit/src/kv/kv.ts" sourceLine="47" packageName="commandkit" />

A key-value store implementation using SQLite

Expand Down Expand Up @@ -56,6 +56,7 @@ class KV implements Disposable, AsyncDisposable {
get(key: string) => T | undefined;
set(key: string, value: any) => void;
setex(key: string, value: any, ttl: number) => void;
math(key: string, operator: KvMathOperator, value: number | bigint) => number | bigint;
expire(key: string, ttl: number) => boolean;
ttl(key: string) => number;
delete(key: string) => void;
Expand Down Expand Up @@ -186,6 +187,34 @@ kv.setex('temp:data', { cached: true, timestamp: Date.now() }, 5 * 60 * 1000);
// Use dot notation with expiration
kv.setex('user:123.temp_settings', { theme: 'light' }, 30 * 60 * 1000);
```
### math

<MemberInfo kind="method" type={`(key: string, operator: <a href='/docs/next/api-reference/commandkit/types/kv-math-operator#kvmathoperator'>KvMathOperator</a>, value: number | bigint) => number | bigint`} />

Performs mathematical operations on numeric values in the KV store



*Example*

```typescript
// Initialize a counter
kv.set('counter', 10);

// Increment by 5
const result1 = kv.math('counter', '+', 5); // 15

// Multiply by 2
const result2 = kv.math('counter', '*', 2); // 30

// Use with bigint
kv.set('big_counter', BigInt(1000));
const result3 = kv.math('big_counter', '+', BigInt(500)); // 1500n

// Use with dot notation
kv.set('user:123', { score: 100, level: 5 });
const result4 = kv.math('user:123.score', '+', 50); // 150
```
### expire

<MemberInfo kind="method" type={`(key: string, ttl: number) => boolean`} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import MemberDescription from '@site/src/components/MemberDescription';

## openKV

<GenerationInfo sourceFile="packages/commandkit/src/kv/kv.ts" sourceLine="620" packageName="commandkit" />
<GenerationInfo sourceFile="packages/commandkit/src/kv/kv.ts" sourceLine="731" packageName="commandkit" />

Opens a new KV instance

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import MemberDescription from '@site/src/components/MemberDescription';

## KvOptions

<GenerationInfo sourceFile="packages/commandkit/src/kv/kv.ts" sourceLine="10" packageName="commandkit" />
<GenerationInfo sourceFile="packages/commandkit/src/kv/kv.ts" sourceLine="15" packageName="commandkit" />

Configuration options for the KV store

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
title: "KvMathOperator"
isDefaultIndex: false
generated: true
---

import MemberInfo from '@site/src/components/MemberInfo';
import GenerationInfo from '@site/src/components/GenerationInfo';
import MemberDescription from '@site/src/components/MemberDescription';

<!-- This file was generated from the CommandKit source. Do not modify. Instead, re-run the "docgen" script -->


## KvMathOperator

<GenerationInfo sourceFile="packages/commandkit/src/kv/kv.ts" sourceLine="10" packageName="commandkit" />

Mathematical operators supported by the KV math method

```ts title="Signature"
type KvMathOperator = '+' | '-' | '*' | '/' | '^' | '%'
```
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ The CommandKit Key-Value (KV) store provides a simple, persistent storage soluti
## Quick Start

```typescript
import { KV } from '@commandkit/kv';
import { KV } from 'commandkit/kv';

// Create a new KV store
const kv = new KV('data.db');
Expand Down Expand Up @@ -65,7 +65,7 @@ The KV store supports storing and retrieving the following data types:
The KV store is included with CommandKit. No additional installation is required.

```bash
npm install @commandkit/kv
npm install commandkit/kv
```

## Next Steps
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ This guide covers the fundamental operations of the CommandKit KV store, includi
## Creating a KV Store

```typescript
import { KV, openKV } from '@commandkit/kv';
import { KV, openKV } from 'commandkit/kv';

// Create with custom database file
const kv = new KV('my-bot-data.db');
Expand Down
40 changes: 22 additions & 18 deletions apps/website/ignore_build.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,37 @@ const { execSync } = require('child_process');

// Check if there are changes in the website directory
function hasWebsiteChanges() {
try {
// Get the list of changed files in the current commit compared to the base branch
const baseBranch = process.env.BASE_BRANCH || 'main';
const changedFiles = execSync(`git diff --name-only origin/${baseBranch}...HEAD`, { encoding: 'utf8' });
try {
// Get the list of changed files in the current commit compared to the base branch
const baseBranch = process.env.BASE_BRANCH || 'main';
const changedFiles = execSync(
`git diff --name-only origin/${baseBranch}...HEAD`,
{ encoding: 'utf8' },
);

// Check if any of the changed files are in the website directory
const websiteChanges = changedFiles
.split('\n')
.filter(file => file.trim() && file.startsWith('apps/website/'));
// Check if any of the changed files are in the website directory
const websiteChanges = changedFiles
.split('\n')
.filter((file) => file.trim() && file.startsWith('apps/website/'));

return websiteChanges.length > 0;
} catch (error) {
// If we can't determine changes, allow the build to proceed
console.log('Could not determine changes, allowing build to proceed');
return true;
}
return websiteChanges.length > 0;
} catch (error) {
// If we can't determine changes, allow the build to proceed
console.log('Could not determine changes, allowing build to proceed');
return true;
}
}

// Ignore build if:
// 1. Branch is owned by renovate, OR
// 2. No changes in website directory
const shouldIgnore = process.env.BRANCH?.includes('renovate') || !hasWebsiteChanges();
const shouldIgnore =
process.env.BRANCH?.includes('renovate') || !hasWebsiteChanges();

process.exitCode = shouldIgnore ? 0 : 1;

if (shouldIgnore) {
console.log('Build ignored: No relevant changes detected');
console.log('Build ignored: No relevant changes detected');
} else {
console.log('Build proceeding: Website changes detected');
}
console.log('Build proceeding: Website changes detected');
}
3 changes: 2 additions & 1 deletion apps/website/src/plugins/llms-txt.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ module.exports = function (context) {
entry.name.endsWith('.md')
) {
const content = await fs.promises.readFile(fullPath, 'utf8');
const { data: frontmatter, content: markdownContent } = matter(content);
const { data: frontmatter, content: markdownContent } =
matter(content);

// Get relative path from guide directory
const relativePath = path
Expand Down
2 changes: 1 addition & 1 deletion packages/commandkit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@
"picocolors": "^1.1.1",
"rfdc": "^1.3.1",
"rimraf": "^6.0.0",
"tsdown": "^0.13.0",
"tsdown": "^0.13.1",
"use-macro": "^1.1.0"
},
"devDependencies": {
Expand Down
111 changes: 111 additions & 0 deletions packages/commandkit/src/kv/kv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ import { getNestedValue, setNestedValue } from './dotprops';

export type { SerializedValue } from './serde';

/**
* Mathematical operators supported by the KV math method
*/
export type KvMathOperator = '+' | '-' | '*' | '/' | '^' | '%';

/**
* Configuration options for the KV store
*/
Expand Down Expand Up @@ -309,6 +314,112 @@ export class KV implements Disposable, AsyncDisposable {
}
}

/**
* Performs mathematical operations on numeric values in the KV store
*
* @param key - The key to perform math operation on (supports dot notation for nested properties)
* @param operator - The mathematical operator to apply
* @param value - The value to use in the operation
* @returns The updated value after the mathematical operation
* @throws Error if the existing value is not numeric or if the operation is invalid
*
* @example
* ```typescript
* // Initialize a counter
* kv.set('counter', 10);
*
* // Increment by 5
* const result1 = kv.math('counter', '+', 5); // 15
*
* // Multiply by 2
* const result2 = kv.math('counter', '*', 2); // 30
*
* // Use with bigint
* kv.set('big_counter', BigInt(1000));
* const result3 = kv.math('big_counter', '+', BigInt(500)); // 1500n
*
* // Use with dot notation
* kv.set('user:123', { score: 100, level: 5 });
* const result4 = kv.math('user:123.score', '+', 50); // 150
* ```
*/
public math(
key: string,
operator: KvMathOperator,
value: number | bigint,
): number | bigint {
const existingValue = this.get(key);

if (existingValue === undefined) {
throw new Error(`Key '${key}' does not exist`);
}

if (
typeof existingValue !== 'number' &&
typeof existingValue !== 'bigint'
) {
throw new Error(
`Value at key '${key}' is not numeric. Expected number or bigint, got ${typeof existingValue}`,
);
}

// Handle mixed number/bigint operations by converting to bigint
const isBigIntOperation =
typeof existingValue === 'bigint' || typeof value === 'bigint';

const existing = isBigIntOperation
? typeof existingValue === 'bigint'
? existingValue
: BigInt(existingValue)
: (existingValue as number);
const operand = isBigIntOperation
? typeof value === 'bigint'
? value
: BigInt(value)
: (value as number);

let result: number | bigint;

switch (operator) {
case '+':
result = (existing as any) + (operand as any);
break;
case '-':
result = (existing as any) - (operand as any);
break;
case '*':
result = (existing as any) * (operand as any);
break;
case '/':
if (operand === 0 || operand === 0n) {
throw new Error('Division by zero');
}
result = (existing as any) / (operand as any);
break;
case '^':
if (isBigIntOperation && operand < 0n) {
throw new Error(
'Exponentiation with negative exponent is not supported for bigint',
);
}
result = (existing as any) ** (operand as any);
break;
case '%':
if (operand === 0 || operand === 0n) {
throw new Error('Modulo by zero');
}
result = (existing as any) % (operand as any);
break;
default:
throw new Error(`Invalid operator: ${operator}`);
}

// Update the value in the store
this.set(key, result);

return result;
}

/**
* Sets expiration for an existing key
*
Expand Down
4 changes: 2 additions & 2 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.