今日已更新 222 条资讯 | 累计 40667 条内容
关于我们

标签:#node

找到 235 篇相关文章

AI 资讯

Your MCP tool takes three minutes. Now what?

I maintain an MCP server that generates music. One call takes anywhere from 40 seconds to three minutes, because there is a model rendering audio on the other end. That does not fit the shape MCP tools are usually written in: call it, get an answer, move on. Everything about the transport assumes the answer is close by. It is worth writing down what actually breaks when it isn't, because "my tool is slow" turns out to be three separate problems wearing one coat. What breaks The obvious first version is a single tool that kicks off the job and awaits the result. server . registerTool ( ' generate_music ' , { /* ... */ }, async ( args ) => { const task = await lacuna . music . generations . create ( args ) const done = await waitUntilReady ( task . id ) // three minutes later return { content : [{ type : ' text ' , text : JSON . stringify ( done ) }] } }) 1. You do not own the timeout. The MCP client does. Claude Desktop, Claude Code, Cursor and the rest each pick their own tool-call deadline, and none of them ask you what yours is. A tool that usually returns in 90 seconds and occasionally takes 200 will work on your machine and fail on someone else's, which is the worst possible failure distribution to debug. 2. If you hand the polling to the model, the model quits. The obvious fix is to return a pending task immediately and expose a get_generation tool so the agent can check on it. The agent will check on it. Twice. Maybe three times. Then it decides the job is wedged and tells the user "this seems to be taking a while, would you like me to keep checking?" — which is a reasonable thing for a helpful assistant to say and a terrible thing for a job that had 40 seconds left. You have converted a slow tool into an unreliable one. 3. Polling burns the context window. Every poll puts a full task object back in the transcript. Twenty polls of a JSON blob is real budget, spent entirely on the word pending . Three tools instead of one What ended up working is splitting the

2026-08-04 原文 →
AI 资讯

Mendapi 0.5.5: the one bug we shipped on purpose, now fixed

The 0.5.4 release notes carried an unusual section: Known issue shipped with 0.5.4 . We had spent that whole release fixing the first minute of using the CLI — twelve corrections to help text, exit codes, path handling, and MCP behaviour — and in the middle of it we found one more that did not make the cut. mendapi scan -h did not print help. It ran a scan. Every other subcommand normalized -h to --help before dispatching. scan did not, so the short flag fell through to the scanner, which happily ignored an unrecognized argument and started working. Nobody loses data over this. But it is exactly the kind of thing that makes a first-time user close the terminal, and we had just shipped a release about first impressions. We wrote it down rather than quietly patching over it, because a tool whose entire premise is upstream changes should be visible before they surprise you does not get to hide its own. What 0.5.5 does One change. -h is normalized to --help before any subcommand spawns, so all nine subcommands behave identically: $ npx mendapi@0.5.5 scan -h Usage: mendapi scan --repo <path> --provider <name> --change-id <id> --out <file.json> --json --quiet --include-prereleases The regression gate that covers this now asserts on all nine subcommands, plus a negative control that fails if the assertion ever becomes vacuously true. That second part matters more than the fix: a test that passes because it stopped testing anything is worse than no test. Also in this release The MCP registry entry has been refreshed. com.mendapi/mendapi now carries an icon set and a website URL alongside the package metadata, so clients that render a server picker have something to render. Nothing else changed. scan , fix , deps , review , and pr still run entirely on your machine. No network primitives exist in those files at all, and the build fails if any appear. Install npx mendapi@latest scan Or wire it into an agent: claude mcp add mendapi \ -- npx mendapi mcp Requires Node.js 22.13 o

2026-08-04 原文 →
AI 资讯

Node Date 的 epoch 毫秒坑 + 用 MCP 把转换塞进 AI 流

Node Date 的 epoch 毫秒坑 + 用 MCP 把转换塞进 AI 流 作者是 Node.js / JS 时间 方向的开发者。这篇不是广告,是踩坑记录 + 顺手做的工具。 背景 做 Node.js / JS 时间 时,时间戳转换是最常被低估的雷区。16 个时间戳工具(Unix 转换/时区/ISO8601/Cron/Duration…) 已覆盖日常;但每个语言/框架的坑都不一样,所以又补了 30 个语言/框架时间戳页(python/javascript/java/sql/…),每页含 6 个真实坑。 我踩过的坑(举几个) 秒 vs 毫秒:前端 Date.now() 是毫秒,后端常存秒,混用差 1000 倍。 时区不是字符串:存 UTC、展示本地,别把本地时间当 UTC 落库。 2038 问题:32 位系统 time_t 在 2038-01-19 溢出,老系统要提前查。 夏令时:一年有两次重复/缺失的本地时间,跨区调度尤其坑。 我顺手做的东西 转换速查页: https://gotimestamp.com/timestamp/nodejs 相关语言页: https://gotimestamp.com/timestamp/javascript 开源 MCP: https://github.com/caresotin/tsforge-mcp —— 把时间戳转换/校验直接接进 LLM 工作流,不用手算。 小结 时间戳没那么简单,但工具到位就省心。上面都是免费、开源、可直接用的,希望对同样踩坑的人有帮助。

2026-08-04 原文 →
AI 资讯

Semantic Search Embeddings vs Keyword Search for a SaaS Help Center

Bottom line: for a beginner ask-your-docs feature in a SaaS help center, I would start with embeddings-based semantic retrieval over document chunks, retain keyword search as a fallback, and add reranking only after I can measure weak top results. It is the least complicated architecture that handles the natural-language questions support teams actually receive while still giving an operator clear levers for relevance, cost, and SLOs. I learned to treat retrieval as a production dependency after a token bill landed at $8,742 for a help-center experiment I had estimated at under $1,000. The expensive part wasn't one dramatic model call; it was sending whole articles, navigation chrome, and duplicate chunks to the answering model for every vaguely phrased question. That mistake changed my order of operations: retrieve a small, attributable set first, inspect it, then generate. A chat model is a poor index. Small index. Big difference. How should a SaaS help center use semantic search, embeddings, and keyword search? Semantic search turns both a question and each document chunk into vectors, then retrieves chunks that are close in that vector space. For an ask-your-docs semantic search feature, that means a customer asking "Why can't I invite another teammate?" can reach a passage titled "Adding users to a workspace" even when the words do not line up. Keyword search remains useful for exact error identifiers, product SKUs, and freshly published terms, but by itself it is a thin answer to the way people phrase support questions. My beginner architecture is deliberately boring: export approved help-center content, strip templates and repeated navigation, split the remaining text into stable chunks, attach the page URL and heading as metadata, create embeddings, and put the vectors in a managed vector database. At question time, retrieve a modest candidate set, optionally rerank it, and pass only the best cited chunks to the chat model. Node.js can own the ingestion job

2026-08-03 原文 →
AI 资讯

Node.js Runs TypeScript Now: Field Notes on Native Type Stripping

Headline: Node.js executes TypeScript files directly — node script.ts works with no loader, no ts-node, and no build step — by stripping type annotations at load time. Type stripping is on by default since Node.js 23.6 and ships in the 22.18 LTS release, but it only covers erasable syntax: I enforce that with TypeScript 5.8's erasableSyntaxOnly flag, moved type checking to tsc --noEmit in CI, and left my decorator-heavy NestJS services on their existing build. Key takeaways Node.js runs .ts files natively by replacing type annotations with whitespace, a mechanism called type stripping. It is enabled by default since Node.js 23.6 and in the 22.18 LTS release; on Node 22.6–22.17 it sits behind --experimental-strip-types . Type stripping handles only erasable syntax. enum , namespace with runtime code, and constructor parameter properties need the separate --experimental-transform-types flag. Node.js never type-checks and never reads tsconfig.json . The type checker is still tsc --noEmit , run in CI or a pre-commit hook. TypeScript 5.8's erasableSyntaxOnly compiler option turns every non-erasable construct into a compile error, which guarantees a file Node.js can run. Relative imports must spell out the .ts extension, and Node.js refuses to strip types inside node_modules — published packages still ship JavaScript. Can Node.js run TypeScript without a build step? Yes, for most application code. Node.js 22.6 introduced type stripping behind the --experimental-strip-types flag, Node.js 23.6 turned it on by default, and the 22.18 release brought the default-on behavior to the LTS line. On Node.js 24 — the current LTS and my daily runtime — node script.ts simply executes. // hello.ts const greet = ( name : string ): string => `Hello, ${ name } ` ; console . log ( greet ( ' Node 24 ' )); console . log ( process . features . typescript ); // 'strip' The mechanism matters. In strip mode Node.js replaces every type annotation with whitespace instead of compiling the file, so l

2026-08-02 原文 →
AI 资讯

Converting a JavaScript-Rendered Web Page to PDF

If you've ever tried to turn a modern web page into a PDF programmatically, you've probably hit the wall: the file comes out blank, half-empty, or frozen on a loading spinner. The page looks perfect in the browser, so what gives? The answer is timing. Most PDF approaches grab the HTML before the JavaScript has rendered the content. On a server-rendered page that's fine — the markup is already there. On a React/Vue/Angular app, the server sends an near-empty shell and the browser builds the DOM afterward. Capture too early and you save the shell. Here's how to do it properly. Why the naive approaches fail wkhtmltopdf is the classic Google answer. It's fast and it's been around forever, but it uses an ancient WebKit build with effectively no modern JavaScript support. For a static page it's fine. For anything client-rendered, it captures the empty state. Browser window.print() / Ctrl+P works because it is a real browser — but it's manual, single-page, and impossible to automate cleanly at scale. Hitting the raw HTML with an HTTP client (axios/fetch then pipe to a PDF lib) has the same fatal flaw as wkhtmltopdf : no JS execution, no rendered content. What you actually need is a real browser engine that runs the page's JavaScript, waits for it to settle, and then prints. That's Puppeteer. The Puppeteer approach Puppeteer drives a headless Chromium. It executes the page exactly like a normal Chrome tab, so whatever renders on screen is what you capture. const puppeteer = require ( ' puppeteer ' ); async function pageToPdf ( url , outPath ) { const browser = await puppeteer . launch ({ args : [ ' --no-sandbox ' , ' --disable-setuid-sandbox ' ], // needed in most containers }); const page = await browser . newPage (); await page . goto ( url , { waitUntil : ' networkidle0 ' , timeout : 60000 }); await page . pdf ({ path : outPath , format : ' A4 ' , printBackground : true , // otherwise CSS backgrounds/colors are dropped margin : { top : ' 20px ' , bottom : ' 20px ' , left

2026-08-01 原文 →
AI 资讯

qm multiplayer AI agent tutorial: Cut Latency 20% with Node.js

This article was originally published on BuildZn . Everyone talks about multi-agent systems but few show you how to actually coordinate them without a ton of boilerplate and deadlocks. I spent weeks trying to get agents to talk, especially when building something like FarahGPT's multi-agent trading system, often hitting insane latency. Turns out, qm can drastically simplify this, and this qm multiplayer AI agent tutorial will show you how to cut task completion times by 20% using a specific Node.js workflow. Why Multi-Agent Systems Aren't Just Hype Anymore (and qm Helps) Single LLM calls hit a wall, fast. You get generic answers, struggle with complex, multi-step tasks, and prompt engineering becomes a full-time job. I've built 9-agent YouTube automation pipelines and an AI gold trading system that needed to analyze market data, news sentiment, and historical trends concurrently. Trying to jam all that into one prompt for a single agent? Forget about it. You need a collaborative AI agent architecture . That's where multi-agent systems shine. You break down complex problems into smaller, manageable tasks, assign them to specialized agents, and have them work together. Think of it like a dev team: one person focuses on backend, another on frontend, another on CI/CD. This is how you handle real-world complexity, and it's how I scaled FarahGPT to 5,100+ users. The challenge? Orchestration. How do these agents communicate? Who manages their state? How do you ensure they don't step on each other's toes or get stuck waiting for slow upstream tasks? This is exactly where qm , a lightweight agent harness, becomes a game-changer for building AI teams. It gives you the primitives to define agents, tasks, and workflows without drowning in custom event loops. The Core Concept: Task Delegation in qm Most qm examples show simple agent interactions. Agent A asks Agent B. Done. But what if Agent A needs to delegate a task that itself needs parallel sub-tasks, and then aggregate the

2026-08-01 原文 →
AI 资讯

How to structure a Chrome Extension with Manifest V3 (the right way)

If you've tried building a Chrome extension recently, you've probably hit Manifest V3 and spent an hour just figuring out why your background page stopped working. MV3 replaced background pages with service workers, changed how content scripts communicate, and made permissions stricter. The official docs are... not great. So here's the structure that actually works. The folder structure chrome-extension/ ├── manifest.json ├── popup/ │ ├── popup.html │ ├── popup.css │ └── popup.js ├── options/ │ ├── options.html │ └── options.js ├── content/ │ └── content.js ├── background/ │ └── service-worker.js ├── utils/ │ └── storage.js └── icons/ The manifest.json (MV3) The biggest MV3 gotcha: background scripts are now service workers. { "manifest_version": 3, "name": "Your Extension", "version": "1.0.0", "permissions": ["storage", "activeTab", "scripting"], "action": { "default_popup": "popup/popup.html" }, "background": { "service_worker": "background/service-worker.js" }, "content_scripts": [ { "matches": [""], "js": ["content/content.js"] } ] } Communicating between popup and content script This trips up almost everyone. The popup can't directly access the page DOM — it has to message the content script. // popup.js const [tab] = await chrome.tabs.query({ active: true, currentWindow: true }); await chrome.tabs.sendMessage(tab.id, { type: 'RUN_ACTION' }); // content.js chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { if (message.type === 'RUN_ACTION') { // do something on the page sendResponse({ success: true }); } return true; // keeps the channel open for async response }); The return true at the end is critical — without it, async responses silently fail. Storage that syncs across devices Use chrome.storage.sync instead of localStorage. Here's a utility wrapper that makes it clean to use anywhere: const Storage = { async get(key) { return new Promise((resolve) => { chrome.storage.sync.get([key], (result) => resolve(result[key])); }); }, async set

2026-08-01 原文 →
AI 资讯

Installing Ghost Blogging Platform on Ubuntu 24.04

Ghost is an open-source publishing platform with built-in newsletters, memberships, subscriptions, ActivityPub federation, and Tinybird-powered web analytics. This guide covers two install paths on Ubuntu 24.04: Ghost-CLI for a traditional host install, and Docker Compose for a containerized deployment with analytics. Prerequisites: an Ubuntu 24.04 server, non-root sudo user, a domain A record (e.g. ghost.example.com ). Option A: Install with Ghost-CLI Install Node.js Ghost requires Node v22 LTS — check compatible versions before installing elsewhere. $ curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh $ sudo -E bash nodesource_setup.sh $ sudo apt install -y nodejs $ node -v Install and Configure MySQL $ sudo apt install -y mysql-server $ mysql --version $ sudo mysql_secure_installation Walk through the prompts: enable password validation ( y ), pick strong policy ( 2 ), remove anonymous users ( y ), restrict root to localhost ( y ), drop the test database ( y ), reload privileges ( y ). $ sudo mysql mysql > CREATE DATABASE ghost_db ; mysql > CREATE USER 'ghostuser' @ 'localhost' IDENTIFIED BY 'Your_password2!' ; mysql > GRANT ALL PRIVILEGES ON ghost_db . * TO 'ghostuser' @ 'localhost' ; mysql > FLUSH PRIVILEGES ; mysql > EXIT ; Install Nginx $ sudo apt install -y nginx $ sudo ufw allow 'Nginx Full' $ sudo systemctl status nginx Install Ghost $ sudo npm install ghost-cli@latest -g $ sudo mkdir -p /var/www/html/ghost $ sudo chown $USER : $USER /var/www/html/ghost $ sudo chmod 775 /var/www/html/ghost $ cd /var/www/html/ghost $ ghost install The installer prompts for: Blog URL : https://ghost.example.com MySQL hostname : localhost MySQL username/password/database : from the setup above Set up Nginx? : y Set up SSL? : y (installs acme.sh ) Email for SSL : your address Set up Systemd? : y Start Ghost? : y Manage the Config $ nano /var/www/html/ghost/config.production.json $ cd /var/www/html/ghost $ ghost restart Or via systemd (replace ghost-example

2026-07-31 原文 →
AI 资讯

Telechat: self-host Claude AI across Telegram/WhatsApp/Slack with one npm install

Built something the r/selfhosted crowd might appreciate: Telechat — a self-hosted Claude AI bot that connects to Telegram, WhatsApp, Slack, and web chat from a single process. Why self-hosted matters here Anthropic launched Claude Code Channels recently — Claude on Telegram/Discord, managed by Anthropic. It works great, but every message goes through their cloud. Telechat takes the opposite approach: Runs on your machine (laptop, VPS, RPi, NAS — anything that runs Node.js or Python) Messages flow: phone → your server → Anthropic API → back to phone No relay server, no telemetry, no analytics SQLite for conversation history, stored locally The only external call is to Anthropic's chat-completions API for inference Your messages, your hardware, your data. Install # npm npm install -g telechatai && telechat init # pip pip install telechatai && telechat init # Docker docker run -v ~/.telechat:/config telechatai/telechat telechat init walks you through an interactive setup — API key, bot tokens for whichever platforms you want, model preferences, budget limits. What it does Multi-platform — Telegram, WhatsApp, Slack, Web Chat. All running simultaneously from one process. Smart model routing — Routes queries to the cheapest Claude model that handles them. Saves ~60% on API costs vs always using Sonnet. Budget caps — Per-user daily and monthly limits. Set $5/day and forget about it. Persistent memory — SQLite-backed. Context carries across conversations. Desktop Bridge — If you run Claude Code on your desktop and it needs approval for a destructive action, you get a push notification on your phone. Approve/deny remotely. Media support — Send images for analysis, generate images if you have DALL-E configured. Resource usage Light. Single process, ~50MB RSS idle, spikes briefly during inference calls. SQLite means no database server. The bottleneck is always the Anthropic API latency, not local compute. Self-hosting tips Run behind a reverse proxy (Caddy/nginx) for HTTPS if

2026-07-31 原文 →
AI 资讯

Protect your application from npm supply chain attacks with tinyNpm!

tinyNpm is a vs code extension that helps protect you from supply chain attacks, stale packages, and bloated code! I had been using package.json version keepers for quite some time but after the big supply chain attack i thought they would be the perfect place to add in some security. The idea is just to provide the latest package number x days old. This will help prevent most of the danger in supply in chain attacks. It will also remove the ^ if you have it so you can better control what version of a package your application is using. To be more security focused it gives general hints in the hover menu to help keep an eye on the packages you have installed. These hints include warnings for staleness, high dependency count, and number of downloads. Since all of this is something you can get through the npm api, I called it tinyNpm You can download it on the marketplace

2026-07-31 原文 →
AI 资讯

Multipart upload of large AI-generated images to S3-compatible object storage

If you just want the recommendation: for the ordinary AI-generated image an inference job hands back — a 2 to 8 MB PNG — do one plain object PUT into your S3-compatible storage and stop there, because multipart upload only earns its complexity when a single artifact is big enough that losing a transfer halfway through costs you real money to redo, which for my team starts somewhere north of 100 MB. Everything below is about that threshold, and about the operations bill you pick up the moment you cross it. I run the platform roadmap for a team that renders a few hundred thousand images a month, and I count pages before I count features, so read the rest with that bias in mind. Should I use multipart upload for large AI-generated images, or a single object PUT? Multipart solves two narrow problems: a payload too awkward for one HTTP round trip, and a transfer you refuse to restart from byte zero. A 6 MB PNG has neither problem. The shape of the flow is always the same wherever you run it. You start a multipart upload and get back an upload id, you push each part under that id, you collect the returned ETag and part number for every one of them, and you send the finished list back in a complete call that stitches the object together server-side. Parts have to be at least 5 MiB on Amazon S3 and on every S3-compatible store I've tested against, with the final part exempt, which already tells you the feature was designed for objects measured in hundreds of megabytes rather than for a batch of thumbnails. Where it genuinely pays off in an image pipeline is the long tail: a 4-gigapixel tiled upscale, a nightly ZIP export of a customer's whole render history, a raw latent archive somebody in research wants kept for a year. Those are the jobs where a dropped connection at 80% is a real incident and not a shrug. For everything else, one put is one line of code and one thing to monitor. There's a second cost that people underrate, and it's the one I'd argue about in a design re

2026-07-31 原文 →
AI 资讯

How to store AI-generated images per user in object storage and delete the old ones

Use one key prefix per user, delete from the application every key you can name, and leave lifecycle rules to sweep the old temporary images nobody will ever ask for again. That's the whole design, and I've watched teams get it wrong in the same two ways for years: they either try to make the storage layer clever enough to know what a user is, or they hand the entire deletion problem to a lifecycle policy and then wonder why an account-deletion request took nine days to actually remove anything. I design data layers for a living, so I'm going to be blunt about the durability and consistency side of this rather than the upload-a-file-in-five-minutes side. Why the key layout matters more than the backend you pick Object storage has no folders. There's a flat keyspace and a delimiter convention, and every "folder" you see in a console is the UI grouping keys that share a prefix — which is good news, because it means the layout is yours to design and costs nothing to enforce. The layout I keep landing on is users/{userId}/generations/{yyyy-mm}/{uuid}.png , with a sibling users/{userId}/scratch/ prefix for renders that only exist so the browser can show a preview. Four properties come out of that shape, and they're the reason I don't get creative here. Listing a tenant's images is a single prefix query rather than a metadata scan, which matters because object stores generally don't let you search metadata server-side — you filter by prefix or you keep an index in your own database. Deleting an account becomes "enumerate one prefix, delete what's under it," so the compliance clock is something you control. The month segment keeps any single listing page from growing without bound, and it gives you a cheap way to write an age-based rule later. And the opaque UUID means the key never leaks a filename, a prompt, or an email address into a URL that might end up in a log or a referrer header. One thing I'd push back on if I saw it in review: don't put the user's email or usern

2026-07-30 原文 →
AI 资讯

I tried to compile TypeScript into a native binary with scriptc

TL;DR: I tried to compile the TypeScript 6 compiler into a native binary with scriptc , and I failed — it got 90% of the way there and then hit an internal compiler error it couldn't get past, so there is no native tsc at the end of this story. But it's a failure worth having: I learned exactly where a week-old TypeScript-to-native compiler runs out of road, and I got some interesting numbers along the way. So when scriptc was released to the public a few days ago, I knew exactly how my week was going to end. If you haven't seen it yet, scriptc is a compiler that takes TypeScript — plain, ordinary TypeScript, no special dialect, no annotations — and turns it into a small, fast native binary. No Node.js. No V8. No JavaScript engine shipped alongside your code. A "hello world" comes out at around 320KB and starts in a few milliseconds. The pitch is bold: what compiles behaves byte-for-byte like Node . It does this with a three-tier model — most code lowers straight to native, anything too dynamic can opt into an embedded engine with a --dynamic flag, and the truly impossible fails at build time with a precise diagnostic instead of a surprise. It's experimental. It's early. It's exactly the kind of thing I can't leave alone. And almost immediately, a mischievous thought showed up: could I compile TypeScript itself? Not a toy. Not a fibonacci function. The actual compiler — tsc — the thing that has type-checked basically every line of TypeScript I've ever written. If scriptc can turn that into a native binary, it can turn anything into a native binary. It felt like the ultimate stress test, and I wanted to see it either fly or fall over. Why 6, and not 7? Here's where the timing gets interesting. If you've been following the TypeScript roadmap, you know the ground just shifted. TypeScript 6.0 shipped as the final JavaScript-based release of the compiler, and TypeScript 7 is the ground-up rewrite in Go — the "native" port the team has been building in the open. So we now

2026-07-30 原文 →
AI 资讯

I Built a Blood Donation Management System with the MERN Stack

Every year, thousands of people struggle to find blood donors during emergencies. I wanted to build something that could simplify that process while improving my full-stack development skills. So I built a Blood Donation Management System using the MERN Stack. The goal was simple: create a platform where donors, recipients, and volunteers can connect efficiently through a modern web application. In this article, I'll share the architecture, key features, and the lessons I learned while building it. Tech Stack : Frontend React.js React Router Tailwind CSS Axios Backend Node.js Express.js Database MongoDB Mongoose Authentication JWT bcrypt Deployment Vercel (Frontend) Render (Backend) The Problem Finding blood donors during emergencies is often difficult because information is scattered across social media and messaging apps. I wanted to build a centralized platform where users could: Register as blood donors Search donors by blood group and location Request blood Manage donation information Keep donor data organized 🏗️Project Architecture Client (React) │ REST API │ Node.js + Express │ ├── Authentication ├── Donor Management ├── Blood Requests ├── User Dashboard └── Admin Panel │ MongoDB Keeping the frontend and backend separated made the project easier to maintain and scale. Key Features Secure user authentication Role-based dashboard Blood donor registration Search donors by blood group Blood request management Responsive UI Protected routes RESTful API Project Structure client/ ├── components/ ├── pages/ ├── hooks/ ├── layouts/ └── routes/ server/ ├── controllers/ ├── middleware/ ├── models/ ├── routes/ ├── utils/ └── config/ Organizing the project into separate folders helped keep the codebase clean and easier to extend. Authentication Flow Authentication was implemented using JWT and bcrypt. The basic flow looks like this: Register ↓ Password Hashing ↓ MongoDB ↓ Login ↓ JWT Token ↓ Protected Routes This keeps user data secure while allowing authenticated access

2026-07-30 原文 →
开发者

Top 5 Node.js ORMs Every Developer Should Know in 2026

Working with databases is a big part of backend development, and choosing the right ORM can save you hours of work. Here are five of the most popular Node.js ORMs, along with their strengths and weaknesses, to help you pick the right one for your next project. 1. Prisma A modern, type-safe ORM built for TypeScript with an excellent developer experience. Pros • Great TypeScript support • Easy migrations • Excellent DX • Large community Cons • Less flexible for advanced SQL • Requires client generation Drizzle ORM A lightweight, SQL-first ORM focused on performance and simplicity. Pros • Very fast • Full TypeScript support • SQL-first approach • Lightweight Cons • Smaller ecosystem • Better if you know SQL 3. TypeORM A mature ORM with broad database support, widely used in enterprise and legacy projects. Pros • Rich feature set • Supports many databases • Strong relationship support Cons • More complex API • Slower development than newer ORMs 4. MikroORM A powerful TypeScript ORM designed for large and complex applications. Pros • Excellent relationship handling • High flexibility • Strong TypeScript integration Cons • Steeper learning curve • Smaller community 5. Sequelize One of the oldest and most established ORMs in the Node.js ecosystem. Pros • Battle-tested • Supports many databases • Large legacy adoption Cons • TypeScript support is weaker • Feels outdated compared to modern ORMs Which ORM do you use the most? 👇

2026-07-29 原文 →
AI 资讯

Building TypeScript-Native Observability: Async Context and Execution Flow

A useful agent trace is not a list of timestamps. It is a causal tree. When a TypeScript agent retrieves documents in parallel, calls a model, retries a tool, and falls back to cached data, each operation needs a trace ID, its own span ID, and the correct parent span. Without those relationships, completion order is easily mistaken for execution structure. This article builds a small Node.js tracer to demonstrate the core mechanics: immutable async context, parent-child spans, reliable finalization, and a pluggable sink. It is intentionally smaller than a production observability library, but the design avoids several common mistakes found in minimal examples. Completion Order Is Not Causality Imagine three tools running in parallel: 80 ms search_tickets completes 100 ms load_account completes 120 ms search_docs completes Those timestamps describe completion order. The execution tree describes why the operations existed: research_agent └─ parallel_retrieval ├─ search_docs ├─ search_tickets └─ load_account Both views are useful, but only the tree preserves the relationship between the agent decision and its child tools. The normal JavaScript call stack cannot serve as that tree. Async work may resume later, execute concurrently, or outlive the function that scheduled it. Tracing therefore needs an explicit logical context. The Context We Need Each asynchronous branch needs two values: type TraceContext = { traceId : string ; parentSpanId : string | null ; }; When a new span starts, it reads the current context, records parentSpanId , creates its own spanId , and runs child work inside a new context whose parent is that span. In Node.js, AsyncLocalStorage provides the propagation primitive. It carries a value through normal asynchronous resources without adding trace parameters to every application function. Do not mutate one shared context object. Parallel siblings would race to replace the current span. Create a new context value for every nested span instead. Defin

2026-07-29 原文 →
AI 资讯

JWT Authentication in Node.js - A Complete Beginner Guide With Code

When I first tried to understand JWT authentication, every article I found either assumed I already knew what a token was or buried the actual implementation under three pages of theory before showing a single line of code. This guide skips that. We are going to build a working JWT authentication system in Node.js from scratch, understand what is actually happening at each step and end up with something you can use as the foundation for any project that needs user login. By the end of this article you will have a complete auth flow - user registration, login, protected routes and token verification - with code you actually understand rather than code you copied and hoped for the best. What JWT Actually Is Before We Touch Any Code JWT stands for JSON Web Token. It is a way of proving to a server that you are who you claim to be without the server needing to check a database on every single request. Here is the practical version. When a user logs in successfully, your server creates a token - a long string that contains encoded information about that user. The server sends that token to the client. The client stores it and sends it back with every subsequent request. The server reads the token, verifies it is legitimate and knows who is making the request without querying the database again. The token has three parts separated by dots. Header.payload.signature The header says which algorithm was used. The payload contains the data you encoded - typically the user ID and role. The signature is a cryptographic proof that the token was created by your server and has not been tampered with. The signature is what makes JWTs trustworthy. Anyone can decode the header and payload - they are just base64 encoded, not encrypted. But nobody can fake a valid signature without your secret key. This means you can trust the contents of a token if the signature is valid. Project Setup Create a new directory and initialize the project. mkdir jwt-auth-demo cd jwt-auth-demo npm init -y I

2026-07-28 原文 →
AI 资讯

Private avatars in a Node.js SaaS: which object storage, and how to sign downloads

Use a private bucket with short-lived presigned URLs when an avatar belongs to exactly one user, and reach for a public CDN-backed bucket only when the images are genuinely public and you'd rather pay for cache hits than for signatures. For a Node.js SaaS that is the entire decision, and everything after it is plumbing: which S3-compatible provider you point at, how long a signature should live, and what happens to the stored object on the day a user deletes their account. Avatars are small. That removes half the hard problems. The half that's left is the half I get paged for, because an avatar key is written by an untrusted client, read on nearly every page render, cached in three places you don't control, and referenced from a database row that has its own opinion about which object is current. So the questions I ask a storage vendor aren't about upload throughput. They're about whether a partial write can ever be visible to a reader, what the durability number is actually measuring, and how I reconcile the bucket with my user table after a failed deploy. I've never watched a team lose avatar bytes. I've watched several lose track of which bytes were current, which is the same outage with a friendlier root-cause section. How should a Node.js SaaS store private user avatars in object storage? Three moves, in this order. Create one private bucket for the whole tenant base, write each avatar under a key that carries a random component, and mint a presigned GET at display time instead of persisting any URL. Store the key in your database, on the user row, and nothing else, because keys are stable and signatures expire — a URL you saved last Tuesday is a support ticket waiting to happen. Serving the image then costs you one signing call per render, which you can cache in Redis for slightly less than the signature's own lifetime. That random component does more work than it looks like it does. Overwriting a fixed path like users/8821/avatar.png puts you in a read-modify

2026-07-28 原文 →
AI 资讯

Picking a text-to-image API for a SaaS app: REST, pricing, and safety

If you just want the recommendation: call a plain REST image generation endpoint from your Node.js backend, keep the prompt-in / image-out path as dumb as you can stand, and add a chat model on top only when you actually need policy checks or structured prompts. For a first text-to-image feature inside a SaaS app, that is the entire architecture worth building. I've shipped that feature twice. Both times the generation call was the boring part. What ate the calendar was everything around it: deciding whether the output was safe to show a paying customer, reading the licence terms closely enough to know we could put generated art in a customer's exported PDF, storing the result somewhere that wasn't the provider's temporary URL, and — the part I got wrong, which I'll come back to — making retries safe. I run a one-person company, so I optimise for the number of moving parts I have to keep in my head at 2am, and a text-to-image feature that pulls in three new vendors is a feature I'll quietly regret. Your priorities may be different if you have an infra team. What should I look for in a text-to-image API for a SaaS app? Four things, in the order they'll actually hurt you. Model availability in your regions comes first. If you sell into both the US and the EU, check that the model you pick is served in both, because "we support Europe" sometimes means the marketing site and not the inference region. Ask for it in writing if the answer matters to your DPA. Commercial use terms come second, and they're the ones nobody reads until legal asks. Most of the big image models now permit commercial use of outputs, but the details differ on who owns the output, whether you can train on it, and what happens with likenesses and trademarks. Read the actual terms page for the model, not the aggregator's summary of it — aggregators route to several vendors and the upstream licence is what governs your PDF. Then pricing shape. Per-image billing is easy to model in a spreadsheet; per-s

2026-07-28 原文 →