#Node

洪 民憙 (Hong Minhee)'s avatar
洪 民憙 (Hong Minhee)

@hongminhee@hollo.social

Optique 0.4.0 Released!

Big update for our type-safe combinatorial parser for :

  • Labeled merge groups: organize options logically
  • Rich docs: brief, description & footer support
  • @optique/temporal: new package for date/time parsing
  • showDefault: automatic default value display

The help text has never looked this good!

.js

洪 民憙 (Hong Minhee)'s avatar
洪 民憙 (Hong Minhee)

@hongminhee@hackers.pub


We're excited to announce Optique 0.4.0, which brings significant improvements to help text organization, enhanced documentation capabilities, and introduces comprehensive Temporal API support.

Optique is a type-safe combinatorial CLI parser for TypeScript that makes building command-line interfaces intuitive and maintainable. This release focuses on making your CLI applications more user-friendly and maintainable.

Better help text organization

One of the most visible improvements in Optique 0.4.0 is the enhanced help text organization. You can now label and group your options more effectively, making complex CLIs much more approachable for users.

Labeled merge groups

The merge() combinator now accepts an optional label parameter, solving a common pain point where developers had to choose between clean code structure and organized help output:

// Before: unlabeled merged options appeared scattered
const config = merge(connectionOptions, performanceOptions);

// Now: group related options under a clear section
const config = merge(
  "Server Configuration",  // New label parameter
  connectionOptions,
  performanceOptions
);

This simple addition makes a huge difference in help text readability, especially for CLIs with many options spread across multiple reusable modules.

The resulting help output clearly organizes options under the Server Configuration section:

Demo app showcasing labeled merge groups
Usage: demo-merge.ts --host STRING --port INTEGER --timeout INTEGER --retries
       INTEGER

Server Configuration:
  --host STRING               Server hostname or IP address
  --port INTEGER              Port number for the connection
  --timeout INTEGER           Connection timeout in seconds
  --retries INTEGER           Number of retry attempts

The new group() combinator

For cases where merge() doesn't apply, the new group() combinator lets you wrap any parser with a documentation label:

// Group mutually exclusive options under a clear section
const outputFormat = group(
  "Output Format",
  or(
    map(flag("--json"), () => "json"),
    map(flag("--yaml"), () => "yaml"),
    map(flag("--xml"), () => "xml"),
  )
);

This is particularly useful for organizing mutually exclusive flags, multiple inputs, or any parser that doesn't natively support labeling. The resulting help text becomes much more scannable and user-friendly.

Here's how the grouped output format options appear in the help text:

Demo app showcasing group combinator
Usage: demo-group.ts --json
       demo-group.ts --yaml
       demo-group.ts --xml

Output Format:
  --json                      Output in JSON format
  --yaml                      Output in YAML format
  --xml                       Output in XML format

Rich documentation support

Optique 0.4.0 introduces comprehensive documentation fields that can be added directly through the run() function, eliminating the need to modify parser definitions for documentation purposes.

Brief descriptions, detailed explanations, and footers

Both @optique/core/facade and @optique/run now support brief, description, and footer options through the run() function:

import { run } from "@optique/run";
import { message } from "@optique/core/message";

const result = run(parser, {
  brief: message`A powerful data processing tool`,
  description: message`This tool provides comprehensive data processing capabilities with support for multiple formats and transformations. It can handle JSON, YAML, and CSV files with automatic format detection.`,
  footer: message`Examples:
  myapp process data.json --format yaml
  myapp validate config.toml --strict

For more information, visit https://example.com/docs`,
  help: "option"
});

These documentation fields appear in both help output and error messages (when configured), providing consistent context throughout your CLI's user experience.

The complete help output demonstrates the rich documentation features with brief description, detailed explanation, option descriptions, default values, and footer information:

A powerful data processing tool
Usage: demo-rich-docs.ts [--port INTEGER] [--format STRING] --verbose STRING

This tool provides comprehensive data processing capabilities with support for
multiple formats and transformations. It can handle JSON, YAML, and CSV files
with automatic format detection.

  --port INTEGER              Server port number [3000]
  --format STRING             Output format [json]
  --verbose STRING            Verbosity level

Examples:
  myapp process data.json --format yaml
  myapp validate config.toml --strict

For more information, visit https://example.com/docs

These documentation fields appear in both help output and error messages (when configured), providing consistent context throughout your CLI's user experience.

Display default values

A frequently requested feature is now available: showing default values directly in help text. Enable this with the new showDefault option when using withDefault():

const parser = object({
  port: withDefault(
    option("--port", integer(), { description: message`Server port number` }),
    3000,
  ),
  format: withDefault(
    option("--format", string(), { description: message`Output format` }),
    "json",
  ),
});

run(parser, { showDefault: true });

// Or with custom formatting:
run(parser, {
  showDefault: {
    prefix: " (default: ",
    suffix: ")"
  }  // Shows: --port (default: 3000)
});

Default values are automatically dimmed when colors are enabled, making them visually distinct while remaining readable.

The help output shows default values clearly marked next to each option:

Usage: demo-defaults.ts [--port INTEGER] [--format STRING]

  --port INTEGER              Server port number [3000]
  --format STRING             Output format [json]

Temporal API support

Optique 0.4.0 introduces a new package, @optique/temporal, providing comprehensive support for the modern Temporal API. This brings type-safe parsing for dates, times, durations, and time zones:

import { instant, duration, zonedDateTime } from "@optique/temporal";
import { option } from "@optique/core/parser";

const parser = object({
  // Parse ISO 8601 timestamps
  timestamp: option("--at", instant()),

  // Parse durations like "PT30M" or "P1DT2H"
  timeout: option("--timeout", duration()),

  // Parse zoned datetime with timezone info
  meeting: option("--meeting", zonedDateTime()),
});

The temporal parsers return native Temporal objects with full functionality:

const result = parse(timestampArg, ["2023-12-25T10:30:00Z"]);
if (result.success) {
  const instant = result.value;
  console.log(`UTC: ${instant.toString()}`);
  console.log(`Seoul: ${instant.toZonedDateTimeISO("Asia/Seoul")}`);
}

Install the new package with:

npm add @optique/temporal

Improved type inference

The merge() combinator now supports up to 10 parsers (previously 5), and the tuple() parser has improved type inference using TypeScript's const type parameter. These enhancements enable more complex CLI structures while maintaining perfect type safety.

Breaking changes

While we've maintained backward compatibility for most APIs, there are a few changes to be aware of:

  • The Parser.getDocFragments() method now uses DocState<TState> instead of direct state values (only affects custom parser implementations)
  • The merge() combinator now enforces stricter type constraints at compile time, rejecting non-object-producing parsers

Learn more

For a complete list of changes, bug fixes, and improvements, see the full changelog.

Check out the updated documentation:

Installation

Upgrade to Optique 0.4.0:

npm update @optique/core @optique/run
# or
deno add jsr:@optique/core@^0.4.0 jsr:@optique/run@^0.4.0

Add temporal support (optional):

npm add @optique/temporal
# or
deno add jsr:@optique/temporal

We hope these improvements make building CLI applications with Optique even more enjoyable. As always, we welcome your feedback and contributions on GitHub.

洪 民憙 (Hong Minhee)'s avatar
洪 民憙 (Hong Minhee)

@hongminhee@hollo.social

Optique 0.4.0 Released!

Big update for our type-safe combinatorial parser for :

  • Labeled merge groups: organize options logically
  • Rich docs: brief, description & footer support
  • @optique/temporal: new package for date/time parsing
  • showDefault: automatic default value display

The help text has never looked this good!

.js

洪 民憙 (Hong Minhee)'s avatar
洪 民憙 (Hong Minhee)

@hongminhee@hackers.pub


We're excited to announce Optique 0.4.0, which brings significant improvements to help text organization, enhanced documentation capabilities, and introduces comprehensive Temporal API support.

Optique is a type-safe combinatorial CLI parser for TypeScript that makes building command-line interfaces intuitive and maintainable. This release focuses on making your CLI applications more user-friendly and maintainable.

Better help text organization

One of the most visible improvements in Optique 0.4.0 is the enhanced help text organization. You can now label and group your options more effectively, making complex CLIs much more approachable for users.

Labeled merge groups

The merge() combinator now accepts an optional label parameter, solving a common pain point where developers had to choose between clean code structure and organized help output:

// Before: unlabeled merged options appeared scattered
const config = merge(connectionOptions, performanceOptions);

// Now: group related options under a clear section
const config = merge(
  "Server Configuration",  // New label parameter
  connectionOptions,
  performanceOptions
);

This simple addition makes a huge difference in help text readability, especially for CLIs with many options spread across multiple reusable modules.

The resulting help output clearly organizes options under the Server Configuration section:

Demo app showcasing labeled merge groups
Usage: demo-merge.ts --host STRING --port INTEGER --timeout INTEGER --retries
       INTEGER

Server Configuration:
  --host STRING               Server hostname or IP address
  --port INTEGER              Port number for the connection
  --timeout INTEGER           Connection timeout in seconds
  --retries INTEGER           Number of retry attempts

The new group() combinator

For cases where merge() doesn't apply, the new group() combinator lets you wrap any parser with a documentation label:

// Group mutually exclusive options under a clear section
const outputFormat = group(
  "Output Format",
  or(
    map(flag("--json"), () => "json"),
    map(flag("--yaml"), () => "yaml"),
    map(flag("--xml"), () => "xml"),
  )
);

This is particularly useful for organizing mutually exclusive flags, multiple inputs, or any parser that doesn't natively support labeling. The resulting help text becomes much more scannable and user-friendly.

Here's how the grouped output format options appear in the help text:

Demo app showcasing group combinator
Usage: demo-group.ts --json
       demo-group.ts --yaml
       demo-group.ts --xml

Output Format:
  --json                      Output in JSON format
  --yaml                      Output in YAML format
  --xml                       Output in XML format

Rich documentation support

Optique 0.4.0 introduces comprehensive documentation fields that can be added directly through the run() function, eliminating the need to modify parser definitions for documentation purposes.

Brief descriptions, detailed explanations, and footers

Both @optique/core/facade and @optique/run now support brief, description, and footer options through the run() function:

import { run } from "@optique/run";
import { message } from "@optique/core/message";

const result = run(parser, {
  brief: message`A powerful data processing tool`,
  description: message`This tool provides comprehensive data processing capabilities with support for multiple formats and transformations. It can handle JSON, YAML, and CSV files with automatic format detection.`,
  footer: message`Examples:
  myapp process data.json --format yaml
  myapp validate config.toml --strict

For more information, visit https://example.com/docs`,
  help: "option"
});

These documentation fields appear in both help output and error messages (when configured), providing consistent context throughout your CLI's user experience.

The complete help output demonstrates the rich documentation features with brief description, detailed explanation, option descriptions, default values, and footer information:

A powerful data processing tool
Usage: demo-rich-docs.ts [--port INTEGER] [--format STRING] --verbose STRING

This tool provides comprehensive data processing capabilities with support for
multiple formats and transformations. It can handle JSON, YAML, and CSV files
with automatic format detection.

  --port INTEGER              Server port number [3000]
  --format STRING             Output format [json]
  --verbose STRING            Verbosity level

Examples:
  myapp process data.json --format yaml
  myapp validate config.toml --strict

For more information, visit https://example.com/docs

These documentation fields appear in both help output and error messages (when configured), providing consistent context throughout your CLI's user experience.

Display default values

A frequently requested feature is now available: showing default values directly in help text. Enable this with the new showDefault option when using withDefault():

const parser = object({
  port: withDefault(
    option("--port", integer(), { description: message`Server port number` }),
    3000,
  ),
  format: withDefault(
    option("--format", string(), { description: message`Output format` }),
    "json",
  ),
});

run(parser, { showDefault: true });

// Or with custom formatting:
run(parser, {
  showDefault: {
    prefix: " (default: ",
    suffix: ")"
  }  // Shows: --port (default: 3000)
});

Default values are automatically dimmed when colors are enabled, making them visually distinct while remaining readable.

The help output shows default values clearly marked next to each option:

Usage: demo-defaults.ts [--port INTEGER] [--format STRING]

  --port INTEGER              Server port number [3000]
  --format STRING             Output format [json]

Temporal API support

Optique 0.4.0 introduces a new package, @optique/temporal, providing comprehensive support for the modern Temporal API. This brings type-safe parsing for dates, times, durations, and time zones:

import { instant, duration, zonedDateTime } from "@optique/temporal";
import { option } from "@optique/core/parser";

const parser = object({
  // Parse ISO 8601 timestamps
  timestamp: option("--at", instant()),

  // Parse durations like "PT30M" or "P1DT2H"
  timeout: option("--timeout", duration()),

  // Parse zoned datetime with timezone info
  meeting: option("--meeting", zonedDateTime()),
});

The temporal parsers return native Temporal objects with full functionality:

const result = parse(timestampArg, ["2023-12-25T10:30:00Z"]);
if (result.success) {
  const instant = result.value;
  console.log(`UTC: ${instant.toString()}`);
  console.log(`Seoul: ${instant.toZonedDateTimeISO("Asia/Seoul")}`);
}

Install the new package with:

npm add @optique/temporal

Improved type inference

The merge() combinator now supports up to 10 parsers (previously 5), and the tuple() parser has improved type inference using TypeScript's const type parameter. These enhancements enable more complex CLI structures while maintaining perfect type safety.

Breaking changes

While we've maintained backward compatibility for most APIs, there are a few changes to be aware of:

  • The Parser.getDocFragments() method now uses DocState<TState> instead of direct state values (only affects custom parser implementations)
  • The merge() combinator now enforces stricter type constraints at compile time, rejecting non-object-producing parsers

Learn more

For a complete list of changes, bug fixes, and improvements, see the full changelog.

Check out the updated documentation:

Installation

Upgrade to Optique 0.4.0:

npm update @optique/core @optique/run
# or
deno add jsr:@optique/core@^0.4.0 jsr:@optique/run@^0.4.0

Add temporal support (optional):

npm add @optique/temporal
# or
deno add jsr:@optique/temporal

We hope these improvements make building CLI applications with Optique even more enjoyable. As always, we welcome your feedback and contributions on GitHub.

洪 民憙 (Hong Minhee)'s avatar
洪 民憙 (Hong Minhee)

@hongminhee@hollo.social

Optique 0.4.0 Released!

Big update for our type-safe combinatorial parser for :

  • Labeled merge groups: organize options logically
  • Rich docs: brief, description & footer support
  • @optique/temporal: new package for date/time parsing
  • showDefault: automatic default value display

The help text has never looked this good!

.js

洪 民憙 (Hong Minhee)'s avatar
洪 民憙 (Hong Minhee)

@hongminhee@hackers.pub


We're excited to announce Optique 0.4.0, which brings significant improvements to help text organization, enhanced documentation capabilities, and introduces comprehensive Temporal API support.

Optique is a type-safe combinatorial CLI parser for TypeScript that makes building command-line interfaces intuitive and maintainable. This release focuses on making your CLI applications more user-friendly and maintainable.

Better help text organization

One of the most visible improvements in Optique 0.4.0 is the enhanced help text organization. You can now label and group your options more effectively, making complex CLIs much more approachable for users.

Labeled merge groups

The merge() combinator now accepts an optional label parameter, solving a common pain point where developers had to choose between clean code structure and organized help output:

// Before: unlabeled merged options appeared scattered
const config = merge(connectionOptions, performanceOptions);

// Now: group related options under a clear section
const config = merge(
  "Server Configuration",  // New label parameter
  connectionOptions,
  performanceOptions
);

This simple addition makes a huge difference in help text readability, especially for CLIs with many options spread across multiple reusable modules.

The resulting help output clearly organizes options under the Server Configuration section:

Demo app showcasing labeled merge groups
Usage: demo-merge.ts --host STRING --port INTEGER --timeout INTEGER --retries
       INTEGER

Server Configuration:
  --host STRING               Server hostname or IP address
  --port INTEGER              Port number for the connection
  --timeout INTEGER           Connection timeout in seconds
  --retries INTEGER           Number of retry attempts

The new group() combinator

For cases where merge() doesn't apply, the new group() combinator lets you wrap any parser with a documentation label:

// Group mutually exclusive options under a clear section
const outputFormat = group(
  "Output Format",
  or(
    map(flag("--json"), () => "json"),
    map(flag("--yaml"), () => "yaml"),
    map(flag("--xml"), () => "xml"),
  )
);

This is particularly useful for organizing mutually exclusive flags, multiple inputs, or any parser that doesn't natively support labeling. The resulting help text becomes much more scannable and user-friendly.

Here's how the grouped output format options appear in the help text:

Demo app showcasing group combinator
Usage: demo-group.ts --json
       demo-group.ts --yaml
       demo-group.ts --xml

Output Format:
  --json                      Output in JSON format
  --yaml                      Output in YAML format
  --xml                       Output in XML format

Rich documentation support

Optique 0.4.0 introduces comprehensive documentation fields that can be added directly through the run() function, eliminating the need to modify parser definitions for documentation purposes.

Brief descriptions, detailed explanations, and footers

Both @optique/core/facade and @optique/run now support brief, description, and footer options through the run() function:

import { run } from "@optique/run";
import { message } from "@optique/core/message";

const result = run(parser, {
  brief: message`A powerful data processing tool`,
  description: message`This tool provides comprehensive data processing capabilities with support for multiple formats and transformations. It can handle JSON, YAML, and CSV files with automatic format detection.`,
  footer: message`Examples:
  myapp process data.json --format yaml
  myapp validate config.toml --strict

For more information, visit https://example.com/docs`,
  help: "option"
});

These documentation fields appear in both help output and error messages (when configured), providing consistent context throughout your CLI's user experience.

The complete help output demonstrates the rich documentation features with brief description, detailed explanation, option descriptions, default values, and footer information:

A powerful data processing tool
Usage: demo-rich-docs.ts [--port INTEGER] [--format STRING] --verbose STRING

This tool provides comprehensive data processing capabilities with support for
multiple formats and transformations. It can handle JSON, YAML, and CSV files
with automatic format detection.

  --port INTEGER              Server port number [3000]
  --format STRING             Output format [json]
  --verbose STRING            Verbosity level

Examples:
  myapp process data.json --format yaml
  myapp validate config.toml --strict

For more information, visit https://example.com/docs

These documentation fields appear in both help output and error messages (when configured), providing consistent context throughout your CLI's user experience.

Display default values

A frequently requested feature is now available: showing default values directly in help text. Enable this with the new showDefault option when using withDefault():

const parser = object({
  port: withDefault(
    option("--port", integer(), { description: message`Server port number` }),
    3000,
  ),
  format: withDefault(
    option("--format", string(), { description: message`Output format` }),
    "json",
  ),
});

run(parser, { showDefault: true });

// Or with custom formatting:
run(parser, {
  showDefault: {
    prefix: " (default: ",
    suffix: ")"
  }  // Shows: --port (default: 3000)
});

Default values are automatically dimmed when colors are enabled, making them visually distinct while remaining readable.

The help output shows default values clearly marked next to each option:

Usage: demo-defaults.ts [--port INTEGER] [--format STRING]

  --port INTEGER              Server port number [3000]
  --format STRING             Output format [json]

Temporal API support

Optique 0.4.0 introduces a new package, @optique/temporal, providing comprehensive support for the modern Temporal API. This brings type-safe parsing for dates, times, durations, and time zones:

import { instant, duration, zonedDateTime } from "@optique/temporal";
import { option } from "@optique/core/parser";

const parser = object({
  // Parse ISO 8601 timestamps
  timestamp: option("--at", instant()),

  // Parse durations like "PT30M" or "P1DT2H"
  timeout: option("--timeout", duration()),

  // Parse zoned datetime with timezone info
  meeting: option("--meeting", zonedDateTime()),
});

The temporal parsers return native Temporal objects with full functionality:

const result = parse(timestampArg, ["2023-12-25T10:30:00Z"]);
if (result.success) {
  const instant = result.value;
  console.log(`UTC: ${instant.toString()}`);
  console.log(`Seoul: ${instant.toZonedDateTimeISO("Asia/Seoul")}`);
}

Install the new package with:

npm add @optique/temporal

Improved type inference

The merge() combinator now supports up to 10 parsers (previously 5), and the tuple() parser has improved type inference using TypeScript's const type parameter. These enhancements enable more complex CLI structures while maintaining perfect type safety.

Breaking changes

While we've maintained backward compatibility for most APIs, there are a few changes to be aware of:

  • The Parser.getDocFragments() method now uses DocState<TState> instead of direct state values (only affects custom parser implementations)
  • The merge() combinator now enforces stricter type constraints at compile time, rejecting non-object-producing parsers

Learn more

For a complete list of changes, bug fixes, and improvements, see the full changelog.

Check out the updated documentation:

Installation

Upgrade to Optique 0.4.0:

npm update @optique/core @optique/run
# or
deno add jsr:@optique/core@^0.4.0 jsr:@optique/run@^0.4.0

Add temporal support (optional):

npm add @optique/temporal
# or
deno add jsr:@optique/temporal

We hope these improvements make building CLI applications with Optique even more enjoyable. As always, we welcome your feedback and contributions on GitHub.

BotKit by Fedify :botkit:'s avatar
BotKit by Fedify :botkit:

@botkit@hollo.social

We're excited to announce the release of BotKit 0.3.0! This release marks a significant milestone as now supports .js alongside , making it accessible to a wider audience. The minimum required Node.js version is 22.0.0. This dual-runtime support means you can now choose your preferred runtime while building with the same powerful BotKit APIs.

One of the most requested features has landed: poll support! You can now create interactive polls in your messages, allowing followers to vote on questions with single or multiple-choice options. Polls are represented as ActivityPub Question objects with proper expiration times, and your bot can react to votes through the new onVote event handler. This feature enhances engagement possibilities and brings BotKit to feature parity with major platforms like Mastodon and Misskey.

// Create a poll with multiple choices
await session.publish(text`What's your favorite programming language?`, {
  class: Question,
  poll: {
    multiple: true,  // Allow multiple selections
    options: ["JavaScript", "TypeScript", "Python", "Rust"],
    endTime: Temporal.Now.instant().add({ hours: 24 }),
  },
});

// Handle votes
bot.onVote = async (session, vote) => {
  console.log(`${vote.actor} voted for "${vote.option}"`);
};

The web frontend has been enhanced with a new followers page, thanks to the contribution from Hyeonseo Kim (@gaebalgom)! The /followers route now displays a paginated list of your bot's followers, and the follower count on the main profile page is now clickable, providing better visibility into your bot's audience. This improvement makes the web interface more complete and user-friendly.

For developers looking for alternative storage backends, we've introduced the SqliteRepository through the new @fedify/botkit-sqlite package. This provides a production-ready SQLite-based storage solution with ACID compliance, write-ahead logging (WAL) for optimal performance, and proper indexing. Additionally, the new @fedify/botkit/repository module offers MemoryCachedRepository for adding an in-memory cache layer on top of any repository implementation, improving read performance for frequently accessed data.

This release also includes an important security update: we've upgraded to 1.8.8, ensuring your bots stay secure and compatible with the latest ActivityPub standards. The repository pattern has been expanded with new interfaces and types like RepositoryGetMessagesOptions, RepositoryGetFollowersOptions, and proper support for polls storage through the KvStoreRepositoryPrefixes.polls option, providing more flexibility for custom implementations.

BotKit by Fedify :botkit:'s avatar
BotKit by Fedify :botkit:

@botkit@hollo.social

We're excited to announce the release of BotKit 0.3.0! This release marks a significant milestone as now supports .js alongside , making it accessible to a wider audience. The minimum required Node.js version is 22.0.0. This dual-runtime support means you can now choose your preferred runtime while building with the same powerful BotKit APIs.

One of the most requested features has landed: poll support! You can now create interactive polls in your messages, allowing followers to vote on questions with single or multiple-choice options. Polls are represented as ActivityPub Question objects with proper expiration times, and your bot can react to votes through the new onVote event handler. This feature enhances engagement possibilities and brings BotKit to feature parity with major platforms like Mastodon and Misskey.

// Create a poll with multiple choices
await session.publish(text`What's your favorite programming language?`, {
  class: Question,
  poll: {
    multiple: true,  // Allow multiple selections
    options: ["JavaScript", "TypeScript", "Python", "Rust"],
    endTime: Temporal.Now.instant().add({ hours: 24 }),
  },
});

// Handle votes
bot.onVote = async (session, vote) => {
  console.log(`${vote.actor} voted for "${vote.option}"`);
};

The web frontend has been enhanced with a new followers page, thanks to the contribution from Hyeonseo Kim (@gaebalgom)! The /followers route now displays a paginated list of your bot's followers, and the follower count on the main profile page is now clickable, providing better visibility into your bot's audience. This improvement makes the web interface more complete and user-friendly.

For developers looking for alternative storage backends, we've introduced the SqliteRepository through the new @fedify/botkit-sqlite package. This provides a production-ready SQLite-based storage solution with ACID compliance, write-ahead logging (WAL) for optimal performance, and proper indexing. Additionally, the new @fedify/botkit/repository module offers MemoryCachedRepository for adding an in-memory cache layer on top of any repository implementation, improving read performance for frequently accessed data.

This release also includes an important security update: we've upgraded to 1.8.8, ensuring your bots stay secure and compatible with the latest ActivityPub standards. The repository pattern has been expanded with new interfaces and types like RepositoryGetMessagesOptions, RepositoryGetFollowersOptions, and proper support for polls storage through the KvStoreRepositoryPrefixes.polls option, providing more flexibility for custom implementations.

BotKit by Fedify :botkit:'s avatar
BotKit by Fedify :botkit:

@botkit@hollo.social

We're excited to announce the release of BotKit 0.3.0! This release marks a significant milestone as now supports .js alongside , making it accessible to a wider audience. The minimum required Node.js version is 22.0.0. This dual-runtime support means you can now choose your preferred runtime while building with the same powerful BotKit APIs.

One of the most requested features has landed: poll support! You can now create interactive polls in your messages, allowing followers to vote on questions with single or multiple-choice options. Polls are represented as ActivityPub Question objects with proper expiration times, and your bot can react to votes through the new onVote event handler. This feature enhances engagement possibilities and brings BotKit to feature parity with major platforms like Mastodon and Misskey.

// Create a poll with multiple choices
await session.publish(text`What's your favorite programming language?`, {
  class: Question,
  poll: {
    multiple: true,  // Allow multiple selections
    options: ["JavaScript", "TypeScript", "Python", "Rust"],
    endTime: Temporal.Now.instant().add({ hours: 24 }),
  },
});

// Handle votes
bot.onVote = async (session, vote) => {
  console.log(`${vote.actor} voted for "${vote.option}"`);
};

The web frontend has been enhanced with a new followers page, thanks to the contribution from Hyeonseo Kim (@gaebalgom)! The /followers route now displays a paginated list of your bot's followers, and the follower count on the main profile page is now clickable, providing better visibility into your bot's audience. This improvement makes the web interface more complete and user-friendly.

For developers looking for alternative storage backends, we've introduced the SqliteRepository through the new @fedify/botkit-sqlite package. This provides a production-ready SQLite-based storage solution with ACID compliance, write-ahead logging (WAL) for optimal performance, and proper indexing. Additionally, the new @fedify/botkit/repository module offers MemoryCachedRepository for adding an in-memory cache layer on top of any repository implementation, improving read performance for frequently accessed data.

This release also includes an important security update: we've upgraded to 1.8.8, ensuring your bots stay secure and compatible with the latest ActivityPub standards. The repository pattern has been expanded with new interfaces and types like RepositoryGetMessagesOptions, RepositoryGetFollowersOptions, and proper support for polls storage through the KvStoreRepositoryPrefixes.polls option, providing more flexibility for custom implementations.

Fedify: ActivityPub server framework's avatar
Fedify: ActivityPub server framework

@fedify@hollo.social

Fedify is an server framework in & . It aims to eliminate the complexity and redundant boilerplate code when building a federated server app, so that you can focus on your business logic and user experience.

The key features it provides currently are:

If you're curious, take a look at the website! There's comprehensive docs, a demo, a tutorial, example code, and more:

https://fedify.dev/

洪 民憙 (Hong Minhee)'s avatar
洪 民憙 (Hong Minhee)

@hongminhee@hollo.social

Introducing !

A simple, cross-runtime email library that works seamlessly on , .js, , and edge functions. Zero dependencies, unified API, and excellent testability with built-in mock transport.

Switch between , , without changing your code. Available on & !

https://upyo.org/

洪 民憙 (Hong Minhee)'s avatar
洪 民憙 (Hong Minhee)

@hongminhee@hollo.social

Introducing !

A simple, cross-runtime email library that works seamlessly on , .js, , and edge functions. Zero dependencies, unified API, and excellent testability with built-in mock transport.

Switch between , , without changing your code. Available on & !

https://upyo.org/

洪 民憙 (Hong Minhee)'s avatar
洪 民憙 (Hong Minhee)

@hongminhee@hollo.social

Introducing !

A simple, cross-runtime email library that works seamlessly on , .js, , and edge functions. Zero dependencies, unified API, and excellent testability with built-in mock transport.

Switch between , , without changing your code. Available on & !

https://upyo.org/

洪 民憙 (Hong Minhee)'s avatar
洪 民憙 (Hong Minhee)

@hongminhee@hollo.social

Introducing !

A simple, cross-runtime email library that works seamlessly on , .js, , and edge functions. Zero dependencies, unified API, and excellent testability with built-in mock transport.

Switch between , , without changing your code. Available on & !

https://upyo.org/

洪 民憙 (Hong Minhee)'s avatar
洪 民憙 (Hong Minhee)

@hongminhee@hollo.social

Introducing !

A simple, cross-runtime email library that works seamlessly on , .js, , and edge functions. Zero dependencies, unified API, and excellent testability with built-in mock transport.

Switch between , , without changing your code. Available on & !

https://upyo.org/

yamanoku's avatar
yamanoku

@yamanoku@hollo.yamanoku.net

a11y MCP を作成して登壇までした話 .js - Qiita

https://qiita.com/shiminori0612/items/dc9c162ed214a4a0fab2

BotKit by Fedify :botkit:'s avatar
BotKit by Fedify :botkit:

@botkit@hollo.social

We're pleased to announce that .js support has been merged and will be available in 0.3.0.

Now you can build your bots with both and Node.js, giving you more flexibility in choosing your preferred runtime environment.

Stay tuned for BotKit 0.3.0!

BotKit by Fedify :botkit:'s avatar
BotKit by Fedify :botkit:

@botkit@hollo.social

We're pleased to announce that .js support has been merged and will be available in 0.3.0.

Now you can build your bots with both and Node.js, giving you more flexibility in choosing your preferred runtime environment.

Stay tuned for BotKit 0.3.0!

BotKit by Fedify :botkit:'s avatar
BotKit by Fedify :botkit:

@botkit@hollo.social

We're pleased to announce that .js support has been merged and will be available in 0.3.0.

Now you can build your bots with both and Node.js, giving you more flexibility in choosing your preferred runtime environment.

Stay tuned for BotKit 0.3.0!

洪 民憙 (Hong Minhee)'s avatar
洪 民憙 (Hong Minhee)

@hongminhee@hollo.social

Anyone here have experience using @vitest with @deno_land, or setting up a unit test suite that works on , .js, and ?

洪 民憙 (Hong Minhee)'s avatar
洪 民憙 (Hong Minhee)

@hongminhee@hollo.social

Anyone here have experience using @vitest with @deno_land, or setting up a unit test suite that works on , .js, and ?

洪 民憙 (Hong Minhee)'s avatar
洪 民憙 (Hong Minhee)

@hongminhee@hollo.social

Anyone here have experience using @vitest with @deno_land, or setting up a unit test suite that works on , .js, and ?

Deno's avatar
Deno

@deno_land@fosstodon.org

Programming should be simple

Deno's avatar
Deno

@deno_land@fosstodon.org

4 years after Deno 1.0, the next generation of JavaScript is ready for production at scale.

Deno 2 is out today
🐢 Fully backwards compatible with Node and npm
📦 Package management and node_modules and package.json
📅 Long term support

deno.com/2

Fedify: ActivityPub server framework's avatar
Fedify: ActivityPub server framework

@fedify@hollo.social

Fedify is an server framework in & . It aims to eliminate the complexity and redundant boilerplate code when building a federated server app, so that you can focus on your business logic and user experience.

The key features it provides currently are:

If you're curious, take a look at the website! There's comprehensive docs, a demo, a tutorial, example code, and more:

https://fedify.dev/