Search results

0

Upyo 0.2.0 Release Notes

洪 民憙 (Hong Minhee) @hongminhee@hackers.pub

Upyo 0.2.0 has been released, introducing new features to this cross-runtime email library that supports Node.js, Deno, Bun, and edge functions. The latest version expands its capabilities with Amazon SES transport support, enabling AWS Signature v4 authentication and session-based authentication. Additionally, comprehensive OpenTelemetry integration has been added, offering distributed tracing, metrics collection, and error classification without altering existing code. The OpenTelemetry transport automatically instruments email operations, tracking delivery rates and latency, and integrates with existing OpenTelemetry infrastructure. Community feedback is encouraged to further improve Upyo, whether through testing the new Amazon SES transport, implementing OpenTelemetry, or contributing to the GitHub repository. This release enhances Upyo's utility by providing more transport options and robust observability features, making it a valuable tool for developers needing reliable email sending across various environments.

Read more →
4

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/

0
2
0

deno-vite-plugin 디버깅 1편

Lee Dogeon @moreal@hackers.pub

이 글은 Deno 런타임 환경에서 SolidStart와 `deno-vite-plugin`을 사용할 때 발생하는 라이브러리 임포트 문제를 해결하는 과정을 담고 있습니다. 특히, `jsr:@fedify/fedify` 라이브러리를 임포트할 때 `deno task build`가 실패하는 상황을 재현하고, 원인을 분석하여 임시 해결책을 제시합니다. 문제의 원인은 `deno info` 명령어가 `kind: asserted`인 모듈을 제대로 처리하지 못하는 데 있었으며, 이를 `esm`으로 취급하도록 수정하여 해결했습니다. 다만, 근본적인 해결책은 아니며, 추가적인 `npm` 관련 에러가 남아있음을 언급합니다. 이 포스팅은 Deno 생태계에서 Vite 플러그인을 사용할 때 발생할 수 있는 문제와 그 해결 과정을 보여주며, 유사한 문제를 겪는 개발자들에게 실질적인 도움을 줄 수 있습니다.

Read more →
1

It's been 30 years we have . So much in technology has changed in that time. It's kind of amazing how much the language and the broader web helped shape the world.

post on the history of Javascript really cements this. Can't believe it's been that long. 😅

deno.com/blog/history-of-javas

0
0

Announcing LogTape 1.0.0

洪 民憙 (Hong Minhee) @hongminhee@hackers.pub

LogTape 1.0.0 has been released, marking a significant milestone for this zero-dependency logging library designed for the modern JavaScript ecosystem. This release emphasizes API stability and introduces high-performance features such as non-blocking sinks for console, stream, and file logging, along with the `fromAsyncSink()` function for integrating asynchronous logging operations. New sink integrations include packages for AWS CloudWatch Logs and Windows Event Log, enhancing LogTape's versatility. The update also brings a visually appealing console logging experience with the `@logtape/pretty` package, and seamless integration with existing Winston or Pino setups through adapter packages. Key developer experience enhancements include programmatic access to log levels and improved browser compatibility. LogTape 1.0.0 streamlines logging infrastructure with a comprehensive package ecosystem, offering specialized packages for various logging needs. This release provides a stable and mature logging solution, making it easier to manage and optimize logging in JavaScript applications.

Read more →
11

LogTape 0.12.0 Release Notes

洪 民憙 (Hong Minhee) @hongminhee@hackers.pub

LogTape, a zero-dependency logging library for JavaScript and TypeScript, has released version 0.12.0 with several enhancements. The update introduces a new `trace` log level for more granular debugging and improves file sink performance through configurable buffering. A significant addition is the `@logtape/syslog` package, enabling log message transmission to syslog servers using RFC 5424. The update also includes `Logger.warning()` as an alias for `Logger.warn()` for consistency. Furthermore, all LogTape packages now share unified versioning for better compatibility. The build infrastructure has been migrated from `dnt` to `tsdown`, enhancing compatibility with modern JavaScript toolchains and improving build times. This release optimizes logging capabilities and ensures smoother integration with various JavaScript runtimes.

Read more →
9

We're migrating Hackers' Pub to a pretty unconventional tech stack, and I'm honestly excited about it!

Thanks to my friend @xiniha, we're diving into , , , , and . In a world dominated by Next.js and React, this feels refreshingly different. And yes, we're sticking with instead of Node.js too.

Some might call it contrarian, but I like to think of it as exploring what's possible beyond the mainstream. Sometimes the road less traveled leads to interesting places.

7
4
1

I think I've fully adopted to writing scripts in with . 😅 It can be so immensely convenient.

You can bundle hack something fairly quickly. With dependencies pinned. And most of all, still have some level of security.

Can't say the same of all my other language scripts. 🫠

0

Hello @hongminhee洪 民憙 (Hong Minhee)

since multiple hours I was sleepless cause I wondered about how to store anything ActivityPub in

I think, I will finish this crazy code somewhen in the next days :) Would you be interested in such a thing?

If:
Tried to solve the following fully ActivityPub conformant, meaning e.g.
- multiple actors can do an action on multiple objects and it needs to be fully versioned cause Undo or Undo/Undo …
- so anything is RFC 6902 <-> kv where anything is ulid and the "version" for the object is the ulid of an Update/Undo etc.
- JSON Patch acknowledges the limits (e.g. size of kv values), any property is stored versioned
- strongly avoiding duplicates;
the "text properties" like contentMap are stored as cid and similar beneath each other by a numeric nilsimsa hash (though /me bad at math)
- we can query all relationships and
- additionally "where", "when", "what" questions are answered by geohash, ulid ranges or a specific hierarchic hash of as:- and our subtypes

0
1

Ditch the DIY Drama: Why Use Fedify Instead of Building ActivityPub from Scratch?

洪 民憙 (Hong Minhee) @hongminhee@hackers.pub

So, you're captivated by the fediverse—the decentralized social web powered by protocols like ActivityPub. Maybe you're dreaming of building the next great federated app, a unique space connected to Mastodon, Lemmy, Pixelfed, and more. The temptation to dive deep and implement ActivityPub yourself, from the ground up, is strong. Total control, right? Understanding every byte? Sounds cool!

But hold on a sec. Before you embark on that epic quest, let's talk reality. Implementing ActivityPub correctly isn't just one task; it's like juggling several complex standards while riding a unicycle… blindfolded. It’s hard.

That's where Fedify comes in. It's a TypeScript framework designed to handle the gnarliest parts of ActivityPub development, letting you focus on what makes your app special, not reinventing the federation wheel.

This post will break down the common headaches of DIY ActivityPub implementation and show how Fedify acts as the super-powered pain reliever, starting with the very foundation of how data is represented.

Challenge #1: Data Modeling—Speaking ActivityStreams & JSON-LD Fluently

At its core, ActivityPub relies on the ActivityStreams 2.0 vocabulary to describe actions and objects, and it uses JSON-LD as the syntax to encode this vocabulary. While powerful, this combination introduces significant complexity right from the start.

First, understanding and correctly using the vast ActivityStreams vocabulary itself is a hurdle. You need to model everything—posts (Note, Article), profiles (Person, Organization), actions (Create, Follow, Like, Announce)—using the precise terms and properties defined in the specification. Manual JSON construction is tedious and prone to errors.

Second, JSON-LD, the encoding layer, has specific rules that make direct JSON manipulation surprisingly tricky:

  • Missing vs. Empty Array: In JSON-LD, a property being absent is often semantically identical to it being present with an empty array. Your application logic needs to treat these cases equally when checking for values. For example, these two Note objects mean the same thing regarding the name property:
    // No name property
    {
      "@context": "https://www.w3.org/ns/activitystreams",
      "type": "Note",
      "content": ""
    }
    // Equivalent to:
    {
      "@context": "https://www.w3.org/ns/activitystreams",
      "type": "Note",
      "name": [],
      "content": ""
    }
  • Single Value vs. Array: Similarly, a property holding a single value directly is often equivalent to it holding a single-element array containing that value. Your code must anticipate both representations for the same meaning, like for the content property here:
    // Single value
    {
      "@context": "https://www.w3.org/ns/activitystreams",
      "type": "Note",
      "content": "Hello"
    }
    // Equivalent to:
    {
      "@context": "https://www.w3.org/ns/activitystreams",
      "type": "Note",
      "content": ["Hello"]
    }
  • Object Reference vs. Embedded Object: Properties can contain either the full JSON-LD object embedded directly or just a URI string referencing that object. Your application needs to be prepared to fetch the object's data if only a URI is given (a process called dereferencing). These two Announce activities are semantically equivalent (assuming the URIs resolve correctly):
    {
      "@context": "https://www.w3.org/ns/activitystreams",
      "type": "Announce",
      // Embedded objects:
      "actor": {
        "type": "Person",
        "id": "http://sally.example.org/",
        "name": "Sally"
      },
      "object": {
        "type": "Arrive",
        "id": "https://sally.example.com/arrive",
        /* ... */
      }
    }
    // Equivalent to:
    {
      "@context":
      "https://www.w3.org/ns/activitystreams",
      "type": "Announce",
      // URI references:
      "actor": "http://sally.example.org/",
      "object": "https://sally.example.com/arrive"
    }

Attempting to manually handle all these vocabulary rules and JSON-LD variations consistently across your application inevitably leads to verbose, complex, and fragile code, ripe for subtle bugs that break federation.

Fedify tackles this entire data modeling challenge with its comprehensive, type-safe Activity Vocabulary API. It provides TypeScript classes for ActivityStreams types and common extensions, giving you autocompletion and compile-time safety. Crucially, these classes internally manage all the tricky JSON-LD nuances. Fedify's property accessors present a consistent interface—non-functional properties (like tags) always return arrays, functional properties (like content) always return single values or null. It handles object references versus embedded objects seamlessly through dereferencing accessors (like activity.getActor()) which automatically fetch remote objects via URI when needed—a feature known as property hydration. With Fedify, you work with a clean, predictable TypeScript API, letting the framework handle the messy details of AS vocabulary and JSON-LD encoding.

Challenge #2: Discovery & Identity—Finding Your Actors

Once you can model data, you need to make your actors discoverable. This primarily involves the WebFinger protocol (RFC 7033). You'd need to build a server endpoint at /.well-known/webfinger capable of parsing resource queries (like acct: URIs), validating the requested domain against your server, and responding with a precisely formatted JSON Resource Descriptor (JRD). This JRD must include specific links, like a self link pointing to the actor's ActivityPub ID using the correct media type. Getting any part of this wrong can make your actors invisible.

Fedify simplifies this significantly. It automatically handles WebFinger requests based on the actor information you provide through its setActorDispatcher() method. Fedify generates the correct JRD response. If you need more advanced control, like mapping user-facing handles to internal identifiers, you can easily register mapHandle() or mapAlias() callbacks. You focus on defining your actors; Fedify handles making them discoverable.

// Example: Define how to find actors
federation.setActorDispatcher(
  "/users/{username}",
  async (ctx, username) => { /* ... */ }
);
// Now GET /.well-known/webfinger?resource=acct:username@your.domain just works!

Challenge #3: Core ActivityPub Mechanics—Handling Requests and Collections

Serving actor profiles requires careful content negotiation. A request for an actor's ID needs JSON-LD for machine clients (Accept: application/activity+json) but HTML for browsers (Accept: text/html). Handling incoming activities at the inbox endpoint involves validating POST requests, verifying cryptographic signatures, parsing the payload, preventing duplicates (idempotency), and routing based on activity type. Implementing collections (outbox, followers, etc.) with correct pagination adds another layer.

Fedify streamlines all of this. Its core request handler (via Federation.fetch() or framework adapters like @fedify/express) manages content negotiation. You define actors with setActorDispatcher() and web pages with your framework (Hono, Express, SvelteKit, etc.)—Fedify routes appropriately. For the inbox, setInboxListeners() lets you define handlers per activity type (e.g., .on(Follow, ...)), while Fedify automatically handles validation, signature verification, parsing, and idempotency checks using its KV Store. Collection implementation is simplified via dispatchers (e.g., setFollowersDispatcher()); you provide logic to fetch a page of data, and Fedify constructs the correct Collection or CollectionPage with pagination.

// Define inbox handlers
federation.setInboxListeners("/inbox", "/users/{handle}/inbox")
  .on(Follow, async (ctx, follow) => { /* Handle follow */ })
  .on(Undo, async (ctx, undo) => { /* Handle undo */ });

// Define followers collection logic
federation.setFollowersDispatcher(
  "/users/{handle}/followers",
  async (ctx, handle, cursor) => { /* ... */ }
);

Challenge #4: Reliable Delivery & Asynchronous Processing—Sending Activities Robustly

Sending an activity requires more than a simple POST. Networks fail, servers go down. You need robust failure handling and retry logic (ideally with backoff). Processing incoming activities synchronously can block your server. Efficiently broadcasting to many followers (fan-out) requires background processing and using shared inboxes where possible.

Fedify addresses reliability and scalability using its MessageQueue abstraction. When configured (highly recommended), Context.sendActivity() enqueues delivery tasks. Background workers handle sending with automatic retries based on configurable policies (like outboxRetryPolicy). Fedify supports various queue backends (Deno KV, Redis, PostgreSQL, AMQP). For high-traffic fan-out, Fedify uses an optimized two-stage mechanism to distribute the load efficiently.

// Configure Fedify with a persistent queue (e.g., Deno KV)
const federation = createFederation({
  queue: new DenoKvMessageQueue(/* ... */),
  // ...
});
// Sending is now reliable and non-blocking
await ctx.sendActivity({ handle: "myUser" }, recipient, someActivity);

Challenge #5: Security—Avoiding Common Pitfalls

Securing an ActivityPub server is critical. You need to implement HTTP Signatures (draft-cavage-http-signatures-12) for server-to-server authentication—a complex process. You might also need Linked Data Signatures (LDS) or Object Integrity Proofs (OIP) based on FEP-8b32 for data integrity and compatibility. Managing cryptographic keys securely is essential. Lastly, fetching remote resources risks Server-Side Request Forgery (SSRF) if not validated properly.

Fedify is designed with security in mind. It automatically handles the creation and verification of HTTP Signatures, LDS, and OIP, provided you supply keys via setKeyPairsDispatcher(). It includes key management utilities. Crucially, Fedify's default document loader includes built-in SSRF protection, blocking requests to private IPs unless explicitly allowed.

Challenge #6: Interoperability & Maintenance—Playing Nicely with Others

The fediverse is diverse. Different servers have quirks. Ensuring compatibility requires testing and adaptation. Standards evolve with new Federation Enhancement Proposals (FEPs). You also need protocols like NodeInfo to advertise server capabilities.

Fedify aims for broad interoperability and is actively maintained. It includes features like ActivityTransformers to smooth over implementation differences. NodeInfo support is built-in via setNodeInfoDispatcher().

Challenge #7: Developer Experience—Actually Building Your App

Beyond the protocol, building any server involves setup, testing, and debugging. With federation, debugging becomes harder—was the message malformed? Was the signature wrong? Is the remote server down? Is it a compatibility quirk? Good tooling is essential.

Fedify enhances the developer experience significantly. Being built with TypeScript, it offers excellent type safety and editor auto-completion. The fedify CLI is a powerful companion designed to streamline common development tasks.

You can quickly scaffold a new project tailored to your chosen runtime and web framework using fedify init.

For debugging interactions and verifying data, fedify lookup is invaluable. It lets you inspect how any remote actor or object appears from the outside by performing WebFinger discovery and fetching the object's data. Fedify then displays the parsed object structure and properties directly in your terminal. For example, running:

$ fedify lookup @fedify-example@fedify-blog.deno.dev

Will first show progress messages and then output the structured representation of the actor, similar to this:

// Output of fedify lookup command (shows parsed object structure)
Person {
  id: URL "https://fedify-blog.deno.dev/users/fedify-example",
  name: "Fedify Example Blog",
  published: 2024-03-03T13:18:11.857Z, // Simplified timestamp
  summary: "This blog is powered by Fedify, a fediverse server framework.",
  url: URL "https://fedify-blog.deno.dev/",
  preferredUsername: "fedify-example",
  publicKey: CryptographicKey {
    id: URL "https://fedify-blog.deno.dev/users/fedify-example#main-key",
    owner: URL "https://fedify-blog.deno.dev/users/fedify-example",
    publicKey: CryptoKey { /* ... CryptoKey details ... */ }
  },
  // ... other properties like inbox, outbox, followers, endpoints ...
}

This allows you to easily check how data is structured or troubleshoot why an interaction might be failing by seeing the actual properties Fedify parsed.

Testing outgoing activities from your application during development is made much easier with fedify inbox. Running the command starts a temporary local server that acts as a publicly accessible inbox, displaying key information about the temporary actor it creates for receiving messages:

$ fedify inbox
✔ The ephemeral ActivityPub server is up and running: https://<unique_id>.lhr.life/
✔ Sent follow request to @<some_test_account>@activitypub.academy.
╭───────────────┬─────────────────────────────────────────╮
│ Actor handle: │ i@<unique_id>.lhr.life                  │
├───────────────┼─────────────────────────────────────────┤
│   Actor URI:  │ https://<unique_id>.lhr.life/i          │
├───────────────┼─────────────────────────────────────────┤
│  Actor inbox: │ https://<unique_id>.lhr.life/i/inbox    │
├───────────────┼─────────────────────────────────────────┤
│ Shared inbox: │ https://<unique_id>.lhr.life/inbox      │
╰───────────────┴─────────────────────────────────────────╯

Web interface available at: http://localhost:8000/

You then configure your developing application to send an activity to the Actor inbox or Shared inbox URI provided. When an activity arrives, fedify inbox only prints a summary table to your console indicating that a request was received:

╭────────────────┬─────────────────────────────────────╮
│     Request #: │ 2                                   │
├────────────────┼─────────────────────────────────────┤
│ Activity type: │ Follow                              │
├────────────────┼─────────────────────────────────────┤
│  HTTP request: │ POST /i/inbox                       │
├────────────────┼─────────────────────────────────────┤
│ HTTP response: │ 202                                 │
├────────────────┼─────────────────────────────────────┤
│       Details  │ https://<unique_id>.lhr.life/r/2    │
╰────────────────┴─────────────────────────────────────╯

Crucially, the detailed information about the received request—including the full headers (like Signature), the request body (the Activity JSON), and the signature verification status—is only available in the web interface provided by fedify inbox. This web UI allows you to thoroughly inspect incoming activities during development.

Screenshot of the Fedify Inbox web interface showing received activities and their details.
The Fedify Inbox web UI is where you view detailed activity information.

When you need to test interactions with the live fediverse from your local machine beyond just sending, fedify tunnel can securely expose your entire local development server temporarily. This suite of tools significantly eases the process of building and debugging federated applications.

Conclusion: Build Features, Not Plumbing

Implementing the ActivityPub suite of protocols from scratch is an incredibly complex and time-consuming undertaking. It involves deep dives into multiple technical specifications, cryptographic signing, security hardening, and navigating the nuances of a diverse ecosystem. While educational, it dramatically slows down the process of building the actual, unique features of your federated application.

Fedify offers a well-architected, secure, and type-safe foundation, handling the intricacies of federation for you—data modeling, discovery, core mechanics, delivery, security, and interoperability. It lets you focus on your application's unique value and user experience. Stop wrestling with low-level protocol details and start building your vision for the fediverse faster and more reliably. Give Fedify a try!

Getting started is straightforward. First, install the Fedify CLI using your preferred method. Once installed, create a new project template by running fedify init your-project-name.

Check out the Fedify tutorials and Fedify manual to learn more. Happy federating!

Read more →
13
0
3
1
0

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:

• Type-safe objects for Activity Vocabulary (including some vendor-specific extensions)
client and server
• HTTP Signatures
• Middleware for handling webhooks
protocol
.js, , and support
• CLI toolchain for testing and debugging

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

fedify.dev/

0
0
0

deno-task-hooks: Git 훅을 Deno 태스크로 쉽게 관리하기

洪 民憙 (Hong Minhee) @hongminhee@hackers.pub

안녕하세요! 오늘은 제가 개발한 deno-task-hooks 패키지를 소개해 드리려고 합니다. 이 도구는 Deno 태스크를 Git 훅으로 사용할 수 있게 해주는 간단하면서도 유용한 패키지입니다.

어떤 문제를 해결하나요?

Git을 사용하는 개발 팀에서는 코드 품질 유지를 위해 커밋이나 푸시 전에 린트, 테스트 등의 검증 작업을 실행하는 것이 일반적입니다. 이러한 작업은 Git 훅을 통해 자동화할 수 있지만, 기존 방식에는 몇 가지 문제가 있었습니다:

  • Git 훅 스크립트를 팀원들과 공유하기 어려움 (.git 디렉토리는 보통 버전 관리에서 제외됨)
  • 각 개발자가 로컬에서 훅을 직접 설정해야 하는 번거로움
  • 훅 스크립트의 일관성 유지가 어려움

deno-task-hooks는 이러한 문제를 해결하기 위해 Deno의 태스크 러너를 활용합니다. Deno 태스크는 deno.json 파일에 정의되어 버전 관리가 가능하므로, 팀 전체가 동일한 Git 훅을 쉽게 공유할 수 있습니다.

어떻게 작동하나요?

deno-task-hooks의 작동 방식은 간단합니다:

  1. deno.json 파일에 Git 훅으로 사용할 Deno 태스크를 정의합니다.
  2. hooks:install 태스크를 실행하면, 정의된 태스크들이 자동으로 .git/hooks/ 디렉토리에 설치됩니다.
  3. 이후 Git 작업 시 해당 훅이 트리거되면 연결된 Deno 태스크가 실행됩니다.

설치 및 사용 방법

1. hooks:install 태스크 추가하기

먼저 deno.json 파일에 hooks:install 태스크를 추가합니다:

{
  "tasks": {
    "hooks:install": "deno run --allow-read=deno.json,.git/hooks/ --allow-write=.git/hooks/ jsr:@hongminhee/deno-task-hooks"
  }
}

2. Git 훅 정의하기

Git 훅은 hooks: 접두사 다음에 훅 이름(케밥 케이스)을 붙여 정의합니다. 예를 들어, pre-commit 훅을 정의하려면:

{
  "tasks": {
    "hooks:pre-commit": "deno check *.ts && deno lint"
  }
}

3. 훅 설치하기

다음 명령어를 실행하여 정의된 훅을 설치합니다:

deno task hooks:install

이제 Git 커밋을 실행할 때마다 pre-commit 훅이 자동으로 실행되어 TypeScript 파일을 검사하고 린트 검사를 수행합니다.

지원되는 Git 훅 종류

deno-task-hooks는 다음과 같은 모든 Git 훅 타입을 지원합니다:

  • applypatch-msg
  • commit-msg
  • fsmonitor-watchman
  • post-update
  • pre-applypatch
  • pre-commit
  • pre-merge-commit
  • pre-push
  • pre-rebase
  • pre-receive
  • prepare-commit-msg
  • push-to-checkout
  • sendemail-validate
  • update

이점

deno-task-hooks를 사용하면 다음과 같은 이점이 있습니다:

  1. 간편한 공유: Git 훅을 deno.json 파일에 정의하여 팀 전체가 동일한 훅을 사용할 수 있습니다.
  2. 설정 용이성: 새 팀원은 저장소를 클론한 후 한 번의 명령어로 모든 훅을 설치할 수 있습니다.
  3. 유지 관리 용이성: 훅 스크립트를 중앙에서 관리하므로 변경 사항을 쉽게 추적하고 적용할 수 있습니다.
  4. Deno의 안전성: Deno의 권한 모델을 활용하여 훅 스크립트의 보안을 강화할 수 있습니다.

마치며

deno-task-hooks는 작은 패키지이지만, Git과 Deno를 함께 사용하는 팀의 개발 경험을 크게 향상시킬 수 있습니다. 코드 품질 유지와 개발 워크플로우 자동화를 위해 한번 사용해 보세요!

패키지는 JSR에서 다운로드할 수 있으며, GitHub에서 소스 코드를 확인할 수 있습니다.

피드백과 기여는 언제나 환영합니다! 😊

Read more →
0
0

Looking for CMS advice

Hey Web devs!

Do you have any suggestions, tips, opinions, dos, don’ts about headless CMSes?

I have a growing list of small/mid non-profits and collectives asking for my help to (re)make their website. I totally want to help, but I don’t have much time, especially considering that they generally have little or no funding—I would most definitely point them to @VillageOneCoopVillage One Cooperative, otherwise.

Therefore, I want a super simple and replicable solution where I can copy-paste most of the code, while providing them with a stable, fast, and modern solution. I had a look at the Headless CMS section in the Jamstack website, but I need opinions from people who actually used some of that software already.

Needs

  • I want to code and configure everything using @eleventyEleventy 🎈 v3.0.0
  • Admin interface () for the client to add pages and write posts
  • Static website in the front-end
  • Simple and reliable CI/CD
  • No/minimal maintenance after the first setup
  • Self-hostable (I was taking this for granted so much that I forgot to write it)
  • If it requires forge integration, it should support

Nice to have

  • Possibly using , not
  • Allowing the client to customize a bit their website through the admin interface, with a GUI
  • CMS app packaged on @yunohostYunoHost :neopossum_box:
  • No CMS vendor lock-in
  • I’d love to write as little JavaScript as possible

Absolutely not

Please, boost this and ask around! Links to videos, tutorials, and resources are welcome.

People whose perspective I would really value: @zachleatZach Leatherman :11ty: @harryfkHarry Keller @deno_landDeno @jaredwhiteJared “Indie Social Web” White @vanillawebThat HTML Blog & The Spicy Web @stefanStefan Bohacek @mxbckMax Böck @WeirdWriterThe Fediverse Twink @deadsuperheroSean Tilley (Sorry if I am spamming you!)

0
0
0

has an incredibly mature governance model which lacks completely. Its trajectory is completely determined by the VC-backed company behind it.

I feel like this fact is often overlooked in debates whether to choose one or the other.

github.com/nodejs/TSC

0
0

Hi everyone, I am now looking for full-time work! If you have a remote Software Engineer position available and work with web tech ( / / / / , etc), (or / ), , or / then please reach out! I love building tools to solve problems and delight users.

For examples of my previous work, links to my projects, and my resume, please see my website: jakehamilton.dev

Boosts very much appreciated!

0
0
0
0
0
0
0
0
0
0
0
0

🎉 Announcing BotKit 0.1.0: A new framework for creating ActivityPub bots!

We're thrilled to announce the initial release of , a framework that makes creating standalone bots simpler than ever before. With BotKit, you can create a complete fediverse bot in just a single TypeScript file!

Key features:

Getting started is as simple as:

deno add jsr:@fedify/botkit@^0.1.0

Here's a quick example of a weather bot:

const kv = await Deno.openKv();

const bot = createBot<void>({
  username: "weatherbot",
  name: "Seoul Weather Bot",
  summary: text`I post daily weather updates for Seoul!`,
  kv: new DenoKvStore(kv),
  queue: new DenoKvMessageQueue(kv),
});

// Reply to mentions
bot.onMention = async (session, message) => {
  await message.reply(text`Current temperature in Seoul is 18°C!`);
};

// Post scheduled updates
const session = bot.getSession("https://weather.example.com");
setInterval(async () => {
  await session.publish(
    text`Seoul Weather Update 🌡️
    Current: 18°C
    Humidity: 65%
    Forecast: Clear skies ☀️`
  );
}, 1000 * 60 * 60); // Hourly updates

While BotKit currently supports , we're working on bringing Node.js and Bun support in future releases.

Ready to create your first fediverse bot? Check out our docs at https://botkit.fedify.dev/ to get started! 🚀

0
0
0
0

Are you interested in creating bots for the ? Meet , a framework that makes bot development easier than ever!

Key Features:

True Independence

  • Create standalone bots
  • No need for a Mastodon or Misskey account
  • Free from platform-specific limitations

Simple and Intuitive API

  • Create a complete bot in a single TypeScript file
  • Intuitive event handlers for mentions, follows, and messages
  • Rich text formatting with Markdown support

Modern Deployment

  • Deploy on Deno Deploy, Fly.io, Railway, or any virtual server
  • Minimal dependencies
  • Designed for modern cloud platforms

Enterprise-Ready Foundation

  • Built on Fedify, a rock-solid ActivityPub framework
  • Seamless federation with Mastodon, Misskey, and other platforms
  • Robust compatibility across the fediverse

Developer Experience

  • Full TypeScript support with great IDE integration
  • Comprehensive documentation
  • Built-in testing utilities

Here's a quick example of how simple it is to create a bot:

import { createBot, mention, text } from "@fedify/botkit";

const bot = createBot<void>({
  username: "greetbot",
  name: "Greet Bot",
  summary: text`A friendly bot that greets people!`,
  // ... configuration ...
});

// Respond to mentions
bot.onMention = async (session, message) => {
  await message.reply(text`Hi, ${message.actor}! Thanks for saying hello!`);
};

export default bot;

Getting Started:

  1. Install
  2. Run: deno add jsr:@fedify/botkit@^0.1.0-dev
  3. Create your bot with just a few lines of code

Check out our documentation at https://botkit.fedify.dev/ to learn more!

0
0
0
0
0
0
0

:botkit: Introducing : A framework for creating truly standalone bots!

Unlike traditional Mastodon bots, BotKit lets you build fully independent bots that aren't constrained by platform limits. Create your entire bot in a single TypeScript file using our simple, expressive API.

Currently -only, with Node.js & Bun support planned. Built on the robust @fedifyFedify: an ActivityPub server framework foundation.

https://botkit.fedify.dev/

0
1
0