AI 资讯
Node.js Moves to One Major Release Per Year, Starting with Node 27
Node.js will change its release schedule starting with version 27 in October 2026, moving from two major releases per year to one. All releases will become Long-Term Support (LTS), removing the distinction between odd and even versions. An Alpha channel for early testing will also be introduced. This decision addresses maintenance challenges and aims to align with user needs. By Daniel Curtis
AI 资讯
How to Integrate the OpenAI API into a Production Express App
Last year I helped a startup integrate the OpenAI API into their product. It was a chat feature — users could ask questions about their data and get natural language answers. The integration took about a day. Three days after launch, the founder messaged me: "Hey, something's wrong. Our AWS bill just showed an unexpected charge." It was $340. For three days. They had 60 users. The issue wasn't a bug — it was that production API usage looks nothing like a tutorial. The tutorial shows you openai.chat.completions.create() and returns a response. The tutorial doesn't show you what happens when users send 500-token messages, when they open 15 browser tabs each maintaining their own chat context, or when one user fires requests 30 times per minute because they think it's broken. This guide covers what the tutorials skip: rate limiting, token counting, cost guards, streaming, error handling with retries, and model selection. These aren't optional additions — they're what separates a demo from a production feature. Why Production Is Different Here's the gap between tutorial code and production code, stated plainly: Concern Tutorial Code Production Code Cost control Not mentioned Token counting, spending limits, model selection by task Rate limiting Not mentioned Per-user and per-IP limits to prevent abuse Error handling try/catch that logs to console Typed errors, retries with backoff, user-facing messages Response delivery Wait for full completion, return at once Streaming via SSE — response appears as it generates Context management Each request is independent Conversation history managed, truncated at token limit Secrets management API key hardcoded or in .env (no rotation) Rotation strategy, usage monitoring, per-feature keys Let's build a production-grade Express API that addresses all of this. We'll go layer by layer. The Architecture ┌─────────────────────────────────────────────────────────┐ │ CLIENT (Browser / Mobile) │ │ POST /api/chat { messages: [...] } │ │ GET
AI 资讯
I built a tool that gives Claude Code permanent memory of your codebase
The problem Every time I started a session with Claude Code I had to re-explain my entire project. What framework I use. How my folders are structured. What naming conventions I follow. What decisions I have already made. Every. Single. Session. It was slowing me down and I knew there had to be a better way. What I built I built stackbrief. One command scans your repo and opens a local visual dashboard showing your full codebase intelligence. npx stackbrief scan It opens a dashboard at localhost:3000 showing: Interactive code map of your architecture Dependency version comparison against npm Convention detection (naming, async patterns, error handling) Context health score MCP server so Claude Code pulls context automatically How it works stackbrief reads every file in your project and builds a structured understanding of it. It detects your framework, architecture pattern, modules, dependencies, and coding conventions. It then writes a CLAUDE.md file to your project and starts an MCP server on port 3001. Claude Code picks this up automatically before every session. No more explaining your project from scratch. AI chat that actually knows your code The dashboard has an Ask your codebase section. Unlike generic AI chat, this assistant has read every file in your project. Ask it about your own architecture and get answers specific to your code. Works with Ollama (free, fully local), Claude, OpenAI, or any OpenAI-compatible provider including Groq, Mistral, and local runners like LM Studio and AnythingLLM. Zero config, fully local No cloud. No telemetry. No account required. Everything runs on your machine. npx stackbrief scan That is it. The dashboard opens automatically. Try it GitHub: https://github.com/ragavtech/stackbrief Built with Node.js and TypeScript. Open source, MIT license. Would love to hear what you think.
AI 资讯
LLM integration with OpenAI Responses API
Large language models (LLMs) understand and generate text from prompts. OpenAI exposes models through the Responses API . The official openai npm package is the practical way to call it from Node.js. This post covers common patterns beyond a single prompt string. Prerequisites OpenAI account Generated API key Enabled billing Node.js version 26 openai package installed ( npm i openai ) For Markdown output: marked , dompurify , and jsdom ( npm i marked dompurify jsdom ) Client setup Create a client with your API key (read from the environment in production). import OpenAI from ' openai ' ; const client = new OpenAI ({ apiKey : process . env . OPENAI_API_KEY }); The same SDK can target other hosts that implement a compatible API by setting baseURL and apiKey : const client = new OpenAI ({ apiKey : process . env . LLM_API_KEY , baseURL : ' https://your-gateway.example/v1 ' , }); Azure OpenAI uses AzureOpenAI instead. Many third-party gateways support Chat Completions only; the examples below use client.responses.* , so confirm your provider supports the Responses API (especially for tools like web search). Basic integration Pass a string as input and read output_text from the response. const response = await client . responses . create ({ model : ' gpt-5.5 ' , input : ' Write a one-sentence bedtime story about a unicorn. ' , }); console . log ( response . output_text ); System prompt Use top-level instructions for stable behavior (tone, format, role). They take precedence over casual wording in the user message. const response = await client . responses . create ({ model : ' gpt-5.5 ' , instructions : ' Reply in one short sentence. Use plain language. ' , input : ' Explain what an LLM is. ' , }); console . log ( response . output_text ); Few-shot prompting Pass prior turns as an input array with user and assistant roles, then the new user message. Keep task rules in instructions . const response = await client . responses . create ({ model : ' gpt-5.5 ' , instructions :
AI 资讯
DaloyJS Is the Latest Modern Enterprise TypeScript Framework, and It Has Your Back on Security
I want to tell you something that took me years to learn, so you can learn it on a Tuesday afternoon instead of during a production incident: most developers who build REST APIs do not actually know all the security protections their API needs. I did not know them when I started. I learned them slowly, usually right after something broke. I am a Filipino fullstack developer, about ten years in, now based in Norway. I built DaloyJS ( @daloyjs/core ) partly so that newer developers do not have to learn security the painful way I did. This post is a gentle walk through the problem and how DaloyJS helps. No gatekeeping, I promise. First, what even is a "security protection"? When your API is on the internet, anyone can send it anything. Most people are nice. Some are not, and a few are running automated tools that poke at every API they can find. So your server needs some basic defenses. Here are a few, in plain words: Body-size limit: stop someone from sending a giant 2GB request that fills up your server's memory and crashes it. Timeouts: if a request takes forever, give up on it so it does not clog everything. Prototype-pollution protection: block a sneaky trick where a special key in the JSON ( __proto__ ) can mess with your whole app. Header safety: reject weird characters in headers so attackers cannot inject their own. Path-traversal protection: stop a path like ../../etc/passwd from reading files it should not. Hiding error details in production: do not show strangers your stack traces and internal info. Rate limiting: stop one person from hammering your API thousands of times a second. Secure headers and CORS: tell browsers how to safely talk to your API. You do not need to memorize all of these today. The point I want you to take away is simpler: this list exists, it is longer than most people think, and nobody hands it to you when you write your first endpoint. Why this is a trap, especially with AI tools Here is the part that matters most for you right now,
AI 资讯
Error: Cannot Set Headers After They Are Sent to the Client
Error: Cannot Set Headers After They Are Sent to the Client If you've built APIs with Express for any length of time, you've probably seen this error: Error [ ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client Or: Cannot set headers after they are sent to the client The frustrating part is that the application often works for some requests and fails only under specific conditions. This error is almost always caused by sending multiple responses for the same request. Let's break down why it happens and how to prevent it in production code. Problem Consider this Express route: app . get ( " /users/:id " , ( req , res ) => { if ( ! req . params . id ) { res . status ( 400 ). json ({ error : " User ID required " }); } res . json ({ id : req . params . id }); }); Looks harmless. But if the first response is sent, Express continues executing the remaining code. Result: Error [ ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client The server attempts to send two responses for a single request. HTTP doesn't allow that. Why It Happens A request can only receive one response. Once Express sends: res . send (); or res . json (); or res . redirect (); or res . end (); the HTTP headers are already transmitted. Any attempt to modify headers or send another response will trigger the error. In production systems, this usually happens because of: Missing return statements Multiple async operations Duplicate error handling Middleware issues Promise and callback mixing Race conditions Example Missing Return Statement This is the most common cause. app . get ( " /profile " , ( req , res ) => { if ( ! req . user ) { res . status ( 401 ). json ({ error : " Unauthorized " }); } res . json ( req . user ); }); If req.user is missing: res . status ( 401 ). json (...) runs first. Then: res . json ( req . user ) runs immediately afterward. Two responses. One request. Crash. Correct Version app . get ( " /profile " , ( req , res ) => { if ( ! req
AI 资讯
How I Built a Live Football Platform That Doesn't Fall Apart Under Load
A walkthrough of the architecture decisions behind Flacron Gamezone a production full-stack app built with Next.js, Express, PostgreSQL, and Redis. When a client approached me to build a live football match discovery platform, the requirements sounded straightforward on the surface: show live scores, let users subscribe, handle authentication. But the moment you start thinking about how those pieces connect in production, straightforward gets complicated fast. This is the story of how I designed the backend for Flacron Gamezone — what decisions I made, why I made them, and what broke along the way. Table of Contents The Problem With "Just Building It" The Architecture: Four Distinct Layers Why This Matters to a Client The Bug That Taught Me Something Real The Full Stack at a Glance What I'd Do Differently The Problem With "Just Building It" The easiest version of this app is a single Express file: one route handler that queries the database, formats the data, and sends a response. I've seen this pattern in tutorials everywhere. It works for demos. It falls apart in production. The problems are predictable: you can't test business logic without hitting the database, a change in one feature quietly breaks another, and the moment a second developer joins the codebase, nobody knows where anything lives. I wanted to build something I could actually be proud to show an employer or a client. That meant committing to a proper layered architecture from day one, even on a project this size. The Architecture: Four Distinct Layers The entire Express backend is organized into four layers. Each layer has one job and talks only to the layer directly below it. Route → Controller → Service → Repository Here's what each one actually does. Routes are just maps. They declare that POST /api/v1/subscriptions exists, attach the auth middleware, and hand off to the controller. No logic lives here. Controllers handle the HTTP boundary. They extract data from req.body or req.params , call th
AI 资讯
Claude vs Gemini Across 4 Security Domains: A Dead Heat — and the Hardening 63% of AI Code Skips
The interesting result isn't who won. It's that across four security domains, Claude and Gemini missed the same hardening steps — and if you've shipped AI-generated auth middleware this year, your code almost certainly has the same gaps, and your review didn't catch them either. For the record, the scoreboard: one Gemini win, two ties, one split — a statistical dead heat. That's the last time the winner matters in this article. Here's the number that should bother you more than any leaderboard: across 700 AI-generated functions scored by the rules I'm about to use, 63% shipped a vulnerability . So "which model writes more secure code?" is mostly the wrong question — I've run that leaderboard myself and argued it's the wrong frame. But people keep asking it, so I ran it properly — on the ESLint security plugins I wrote specifically to catch these bugs, each mapped to a CWE — to show you what actually matters. The setup Four domains, four of my plugins. For each, the same feature-only prompt (no "make it secure" hint — that's how people actually use these tools), generated once by Gemini 2.5 Flash via the Gemini CLI and once by Claude Sonnet 4.6 via the Claude CLI , then linted with the domain's plugin on recommended . Method honesty: this is Gemini Flash vs Claude Sonnet — the comparable price/latency tier each vendor's CLI defaults to (Pro and Opus are a separate bracket; more on that below). It compares CLI tooling, system prompt included, not raw models under controlled decoding. n=1 per domain — but I re-ran the JWT round, and both models landed on 5 findings again with the same core misses, so treat these as directional with stable failure modes, not ±0 gospel. The scorecard Domain Prompt Plugin Gemini Claude NestJS service users + auth + admin nestjs-security 2 6 JWT auth login + verify middleware jwt 5 5 MongoDB data layer Mongoose model + search mongodb-security 8 8 General API (injection) import + search + reset secure-coding 9 13* One Gemini win, two dead h
AI 资讯
The Bug That Passes Every Toolchain Check: Circular Dependencies in JavaScript
A circular dependency is one of the few bugs that passes every check your toolchain runs. TypeScript compiles it cleanly. The tests pass. The build succeeds. The app ships. And somewhere deep in your import graph, a developer is staring at a TypeError: X is not a constructor that disappears the moment they add a console.log . Here are the three patterns that create them, what Node.js, webpack, Rollup, and esbuild actually do with them — they don't solve the problem, they each make a different tradeoff — and how to stop them from forming. What a circular dependency actually is A circular dependency exists when module A imports from module B, which imports — directly or transitively — from module A. // user.service.ts import { formatUser } from ' ./user.utils ' ; // user.utils.ts import { UserService } from ' ./user.service ' ; // ← closes the loop Neither developer planned this. user.service.ts needed a formatter. user.utils.ts needed the service type for a helper added three sprints later. Nobody saw the cycle form — they just saw two reasonable imports. This is how every circular dependency is born: through incremental, individually sensible decisions. The 3 patterns that create them 1. Barrel files ( index.ts re-exports) Barrel files are the biggest source of accidental cycles in TypeScript projects. // features/user/index.ts — re-exports everything in the feature export { UserService } from ' ./user.service ' ; export { UserRepository } from ' ./user.repository ' ; export { UserController } from ' ./user.controller ' ; export { formatUser , validateUser } from ' ./user.utils ' ; Now every file in the user feature imports from ../user (the barrel) for cleaner paths. And any utility the barrel re-exports cannot safely import anything else from the barrel without creating a cycle. // user.utils.ts import { UserService } from ' ../user ' ; // ← imports the barrel // The barrel re-exports user.utils → user.utils imports the barrel → cycle Teams adopt barrel files for
AI 资讯
You Have a Free AI Model Sitting in Chrome Right Now
Hello, I'm Maneshwar. I'm building git-lrc, a Micro AI code reviewer that runs on every commit. It is free and source-available on Github. Star git-lrc to help devs discover the project. Do give it a try and share your feedback for improving the project. You might not have noticed, but Chrome quietly started shipping a local AI model called Gemini Nano bundled right into the browser. No API keys. No cloud round-trips. No per-token cost. It just runs on your machine. The interface to talk to it is called the Prompt API , and it landed in Chrome 138. I spent some time going through the full API surface and built a playground that lets you experiment with every feature session management, streaming, structured output, multimodal input, response prefixing, and more in one page. This post walks you through all of it. Why does this matter? On-device AI flips the usual tradeoffs: Free at runtime — the model runs on the user's hardware, not your servers Private by default — no data leaves the device once the model is downloaded Works offline — after the initial download, no network required Low latency — no round-trip to a data centre The catch is that Gemini Nano is a small model. It's great for classification, summarization, Q&A on focused content, and structured extraction. It won't replace GPT-4 for complex reasoning. Think of it as a smart, free, always-available layer you can add on top of your existing product. Enabling the API The Prompt API isn't on by default in all Chrome builds. Enable two flags: Step 1 — Go to chrome://flags/#optimization-guide-on-device-model and set it to Enabled BypassPerfRequirement . Step 2 — Go to chrome://flags/#prompt-api-for-gemini-nano and enable both the base API and the multimodal option. Relaunch Chrome. Then visit chrome://on-device-internals to check the model download status. First use will trigger a download — Gemini Nano is a few gigabytes. The Playground I put together a single-file HTML playground that covers the entire API
AI 资讯
Stop Using LLMs to Audit Other LLMs: You Are Bricking Your Production Latency
Look at your modern Agentic AI stack. An agent wants to execute a tool, trigger a deployment, access a database, or call an external API. Because nobody fully trusts a probabilistic black box, many teams now use a second probabilistic black box to validate the first one. Think about what is actually happening. You are running hundreds of billions of parameters, consuming tokens, burning GPU resources, and adding hundreds or thousands of milliseconds of latency just to answer a simple operational question: PASS HOLD RED Or in plain English: Continue Verify Stop For many production systems, that's the only decision that matters. Yet we often spend orders of magnitude more compute determining whether an action should execute than executing the action itself. That feels dangerously close to architectural bankruptcy. The Illusion of Prompt-Based Safety We've all done it. You create a prompt: "You are a security validator. If the action appears unsafe, return RED." Then reality arrives. Prompt injections appear. Edge cases appear. Different model versions behave differently. The same input occasionally produces different outputs. And your cloud bill keeps growing. At some point, a difficult architectural question emerges: Can a probabilistic system reliably govern another probabilistic system? Many teams assume the answer is yes. I'm not convinced. The Problem Isn't Intelligence This is where I think the industry may be looking at the problem incorrectly. The challenge is not intelligence. The challenge is governance. LLMs are exceptional at: Reasoning Summarization Code generation Natural language interaction But governance is a different problem. Governance is not asking: "What is the best answer?" Governance is asking: "Should this action be allowed to proceed?" Those are fundamentally different questions. A Different Architecture While exploring this problem, we ended up building a separate deterministic governance layer internally. Instead of generating text, it perf
AI 资讯
Environment Variables in Node.js: The Complete Guide (2026)
Environment Variables in Node.js: The Complete Guide (2026) Environment variables are the standard way to configure apps across environments. Here's how to use them correctly. What and Why What: Key-value pairs set outside your application code Where: OS environment, .env files, CI/CD config, container orchestration Why: → Separate config from code (12-Factor App methodology) → Same code runs everywhere (dev, staging, production) → Secrets never committed to git → Easy to change behavior without redeploying Reading Env Vars in Node.js // Method 1: process.env (built-in, always available) const port = process . env . PORT || 3000 ; const dbUrl = process . env . DATABASE_URL ; const apiKey = process . env . API_KEY ; // ⚠️ process.env values are ALWAYS strings! const timeout = parseInt ( process . env . TIMEOUT , 10 ) || 5000 ; const debug = process . env . DEBUG === ' true ' ; const maxRetries = Number ( process . env . MAX_RETRIES || ' 3 ' ); // Method 2: dotenv (most popular approach) // npm install dotenv import ' dotenv/config ' ; // Loads .env into process.env automatically // Now process.env has all your .env variables! // Or explicit load: import dotenv from ' dotenv ' ; dotenv . config ({ path : ' .env.local ' }); // Custom file path // Method 3: env-cmd (for package.json scripts) // "dev": "env-cmd -f .env.dev node server.js" // "prod": "env-cmd -f .env.prod node server.js" // Method 4: tenv / enve (type-safe alternatives) import { env } from ' tenv ' ; const port = env . number ( ' PORT ' , 3000 ); // Type-safe with default const dbUrl = env . string ( ' DATABASE_URL ' ); // Required, throws if missing const debug = env . bool ( ' DEBUG ' , false ); // Boolean parsing The .env File Ecosystem # .env (committed to git with defaults) NODE_ENV = development PORT = 3000 LOG_LEVEL = debug # .env.local (NOT committed! Gitignored) # Contains local overrides and secrets DATABASE_URL = postgresql://localhost/myapp_dev API_KEY = sk_test_local_key JWT_SECRET = local-de
AI 资讯
We Replaced Jest With node:test in 12 Services — Here's What Broke and What Didn't
After months of using Jest for unit testing, we decided to take the plunge and migrate to the built-in node:test runner. The results were surprising, with some features working seamlessly and others requiring significant rework. In this post, we'll share our journey and the lessons we learned along the way. Introduction to node:test The node:test runner is a built-in testing framework that comes with Node.js. It's designed to be fast, efficient, and easy to use. Here's an example of a simple test using node:test: import { test } from ' node:test ' ; import { Command } from ' @aws-sdk/client-lambda ' ; test ( ' Lambda client test ' , async ( t ) => { const lambdaClient = new Command (); const response = await lambdaClient (); t . equal . responseStatusCode , 200 ; }); Warning: When using node:test, make sure to handle errors properly, as unhandled errors can cause the test runner to crash. Migrating from Jest to node:test Migrating from Jest to node:test requires some changes to your test code. One of the main differences is the way you handle ES modules. In Jest, you can use the jest.config.js file to configure how ES modules are handled. In node:test, you need to use the --test-type option to specify the type of test you're running. Here's an example of how to migrate a Jest test to node:test: // jest.test.js import { lambdaClient } from ' ../lambdaClient ' ; describe ( ' Lambda client test ' , () => { it ( ' should return 200 ' , async () => { const response = await lambdaClient (); expect ( response . statusCode ). toBe ( 200 ); }); }); // node-test.test.js import { test } from ' node:test ' ; import { lambdaClient } from ' ../lambdaClient ' ; test ( ' Lambda client test ' , async ( t ) => { const response = await lambdaClient (); t . equal ( response . statusCode , 200 ); }); Tip: Use the --coverage option to generate code coverage reports for your tests. Overcoming Incompatibilities and Limitations One of the main limitations of node:test is that it does not su
AI 资讯
Why I built tmpdrop: a self-hosted, expiring file drop
I had a screenshot to send. Nothing secret — a stack trace from a side project — but it had an internal hostname, a file path with my username, and a chunk of a config file in the terminal behind it. The fast move is to drag it onto a free image host and paste the link. I sat there with my cursor over the upload button and couldn't do it. Because I know what happens next. That image lives on someone else's infrastructure, indefinitely, behind a URL I don't control, and I have no idea who else can reach it. For a throwaway screenshot, that's a permanent record I never agreed to. So I closed the tab and built a thing instead. It's called tmpdrop , and it's ~500 lines of Node. The threat model The problem with public file hosts isn't that they're evil. It's the gap between what you intend ("share this once, with one person") and what the platform delivers ("store this forever, serve it to anyone who finds the link"). A few specific things go wrong: Retention. "Temporary" hosts keep your files long after you've forgotten them. There's no expiry you can trust, and deletion is usually best-effort. Predictable URLs. Plenty of hosts use sequential or short IDs. Scrapers walk the keyspace and hoover up everything. Your "private" link was never private. Stored XSS via uploads. If a host serves an uploaded .html or .svg file inline with a permissive content type, an attacker can ship JavaScript that runs in your browser, in the host's origin. Your file host becomes an XSS delivery service. Abuse vectors. No rate limit means the box is a free CDN for whatever someone wants to dump on it — malware, spam payloads, the works. So the design goal wasn't "another uploader." It was: close each of those gaps, then stop. What I built tmpdrop is a single Fastify server backed by SQLite. The whole defensive surface is small enough to hold in your head: Unguessable URLs. Slugs are 9 random bytes, base64url-encoded — 72 bits of entropy. You cannot enumerate them. A TTL reaper. Every upload
AI 资讯
How I scraped the CQC Care Register without hitting the API auth wall
The Care Quality Commission regulates 56,000+ healthcare and social care locations in England — care homes, GP surgeries, hospitals, dental practices, home care agencies. If you work in care sector tech, you've probably needed this data at some point. There's a CQC REST API, and I was planning to wrap it. Then I hit the auth wall. The API is now authenticated CQC migrated their API to api.service.cqc.org.uk and added bearer token authentication. You need to register at their developer portal, create an application, and include an Authorization: Bearer <token> header on every request. That's not a dealbreaker for enterprise use cases, but it creates friction for a data product — it means requiring users to register with CQC before they can run your actor. I checked the old API base ( api.cqc.org.uk/public/v1 ) as a fallback. HTTP 403. Fully blocked. The open-data file rescue CQC publishes a monthly open-data file called HSCA_Active_Locations.ods . It's a 23 MB OpenDocument Spreadsheet with every active regulated location in England — all 56,000 of them. Free, no auth, Open Government Licence. The URL is date-stamped and changes each month, but the transparency page always links to the current version. The approach: scrape the transparency page to find the current ODS URL, download the file, parse it, filter rows, push results. No API. No auth wall. The ODS parsing challenge ODS files ( .ods ) are ZIP archives containing XML. The standard tool for parsing them in Node.js is SheetJS ( xlsx package, v0.18.5 — the last Apache 2.0 release). The first surprise: the workbook has three sheets — README , HSCA_Active_Locations , and Dual_Registration_Locations . SheetJS defaults to the first sheet, which is the README with 34 rows. I added logic to find the sheet with the most rows. for ( const name of workbook . SheetNames ) { const probe = XLSX . utils . sheet_to_json ( sheet , { header : 1 }); if ( probe . length > bestCount ) { bestCount = probe . length ; bestSheet = shee