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

标签:#node

找到 104 篇相关文章

AI 资讯

I built a JS image compressor that actually handles iPhone HEIC photos

If you've ever built a file upload feature, you've probably hit this: a user uploads a photo from their iPhone, and your app breaks. No preview, no compression, just a silent failure — because the file is .heic and browsers can't read it. HEIC is Apple's default photo format since iOS 11. Every iPhone photo taken today is HEIC. And virtually every JS image compression library just ignores the problem. I spent a weekend building PixSqueeze to fix that. The problem with HEIC in the browser Browsers use the <canvas> API to compress images. You draw the image onto a canvas, call canvas.toBlob() , and get a compressed file back. Clean, client-side, zero server cost. The problem: canvas.drawImage() only works if the browser can decode the image first. And no major browser can decode HEIC natively — not Chrome, not Firefox, not even Safari on macOS (Safari on iOS can, but that doesn't help your web app). So when a user picks a HEIC file, your image element fires onerror , your canvas stays blank, and your compression pipeline silently does nothing. The solution: server-side conversion, then client-side compression PixSqueeze handles this in two stages: Stage 1 — Server converts the format HEIC (and TIFF, camera RAW) files get sent to a small Express server. The server uses heic-convert running in a dedicated worker thread to convert to JPEG. Worker threads matter here — HEIC decoding is CPU-intensive WASM work, and running it on the main event loop would block every other request. Stage 2 — Client compresses the result The converted JPEG comes back to the browser, where the normal canvas-based compression pipeline takes over. Quality, resize, watermark hooks — all the usual options. The detection is important too. You can't just check file.type — iOS often sets HEIC files with an empty MIME type. PixSqueeze checks the ISO Base Media File Format magic bytes directly: async function isHeicFile ( file ) { const buffer = await file . slice ( 0 , 12 ). arrayBuffer (); const byt

2026-06-09 原文 →
AI 资讯

I Got Tired of Repeating Validation Logic in Every Node.js Project — So I Built Zero Validation

How I Published My Own Validation Package on npm As developers, we've all done this: if ( ! email ) { throw new Error ( " Email is required " ); } if ( typeof email !== " string " ) { throw new Error ( " Email must be a string " ); } if ( ! email . includes ( " @ " )) { throw new Error ( " Invalid email " ); } Now imagine doing this for: User Registration Login APIs Product Creation Payment Requests Admin Panels Microservices The validation code starts growing faster than the actual business logic. The Problem In many Node.js projects, validation ends up being: Repetitive Hard to maintain Inconsistent across APIs Difficult to scale Every endpoint contains similar checks: if ( ! name ) ... if ( ! email ) ... if ( ! password ) ... if ( password . length < 8 ) ... As projects grow, these validations become scattered throughout the codebase. Existing Solutions There are already some excellent validation libraries available: Zod Joi Yup Express Validator I've used many of them and they're great. But for some smaller projects and APIs, I wanted something: Lightweight Easy to understand Minimal setup Zero configuration TypeScript friendly That's what led me to build Zero Validation . Introducing Zero Validation Zero Validation is a lightweight schema validation package for Node.js and TypeScript applications. The goal is simple: Define your validation schema once and validate data consistently everywhere. Installation npm install zero-validation Basic Example import { z } from " zero-validation " ; const userSchema = z . object ({ name : z . string (), email : z . email (), age : z . number (), }); const result = userSchema . parse ({ name : " John " , email : " john@example.com " , age : 25 , }); console . log ( result ); Handling Validation Errors const result = userSchema . safeParse ( data ); if ( ! result . success ) { console . log ( result . errors ); } Instead of crashing your application, you can safely inspect validation errors and return meaningful API responses

2026-06-09 原文 →
AI 资讯

Building a production TypeScript CLI in 2026: oclif vs commander vs custom.

Building a production TypeScript CLI in 2026: oclif vs commander vs custom. I shipped my first Node CLI in 2019 with a 12-line arg slicer and process.argv . It worked until it needed a second command and then collapsed into spaghetti. The other extreme is grabbing a full framework for a tool that runs one command. In 2026 there are three reasonable paths between those extremes, and each one wins on a specific slice of the problem. This post covers @oclif/core v4, commander v14, and a zero-dependency parser that fits in 30 lines. Same "greet" command in all three. Same distribution steps at the end. Honest tradeoffs throughout. TL;DR oclif v4 commander v14 zero-dep npm install size ~8 MB ~220 kB 0 B Type inference on flags Full, generated Good, manual Manual Plugin ecosystem Yes (Heroku, Salesforce) No No Learning curve High (day 1) Low (hour 1) None Best for Multi-team, multi-command CLIs Most real-world tools One-shot scripts 1. The decision: framework vs no framework Reach for a framework when the tool needs subcommands, a plugin system, or auto-generated help text. The second engineer who touches the CLI should be able to find where things live without reading your code twice. Build your own when the tool does one thing, ships as a one-file script, or lives inside a monorepo where pulling in 8 MB of transitive deps is not welcome. A zero-dep parser also removes the surface area for supply-chain incidents, a real concern on tools that run in CI. Commander sits in the middle: a 220 kB install that covers most real tools without the scaffolding overhead of oclif. 2. Project skeleton Every path shares the same bin setup. Start with a package.json that declares the executable: { "name" : "greet-cli" , "version" : "1.0.0" , "bin" : { "greet" : "./dist/cli.js" }, "scripts" : { "build" : "tsc" , "dev" : "tsx src/cli.ts" }, "type" : "module" } The tsconfig.json for a CLI targets the Node release line you plan to support. Node 24 LTS handles ESM natively, so use "module":

2026-06-09 原文 →
AI 资讯

LLM integration with OpenRouter

OpenRouter is a unified API gateway to hundreds of language models from providers such as OpenAI, Anthropic, Google, and Meta. You use one API key and one billing surface, and swap models by changing a provider/model slug. OpenRouter exposes a Chat Completions -compatible HTTP API. This post shows three Node.js integration paths: the official @openrouter/sdk , the openai package with baseURL , and the Vercel AI SDK with @openrouter/ai-sdk-provider . For deeper patterns on each stack, see the Chat Completions API , OpenAI Responses API (OpenAI direct only), and Vercel AI SDK posts. Prerequisites OpenRouter account API key Credits or billing enabled as needed Node.js version 26 Install packages for the path you use: @openrouter/sdk ( npm i @openrouter/sdk ) openai ( npm i openai ) ai and @openrouter/ai-sdk-provider ( npm i ai @openrouter/ai-sdk-provider ) Configuration Read credentials from the environment in production. Variable Purpose OPENROUTER_API_KEY Bearer token from OpenRouter settings OPENROUTER_MODEL Default model slug, for example openai/gpt-5.5 OPENROUTER_SITE_URL Optional site URL sent as HTTP-Referer for rankings on openrouter.ai OPENROUTER_SITE_TITLE Optional app name sent as X-OpenRouter-Title Model IDs use the provider/model format, for example openai/gpt-5.5 , anthropic/claude-opus-4.8 , or google/gemini-3.1-flash-lite . Browse the full catalog at openrouter.ai/models . The examples below use openai/gpt-5.5 , matching the model in the other LLM posts in this series. Override it with OPENROUTER_MODEL when you want a different model. @openrouter/sdk OpenRouter's official TypeScript SDK is type-safe and generated from the OpenAPI spec. Client setup import { OpenRouter } from ' @openrouter/sdk ' ; const client = new OpenRouter ({ apiKey : process . env . OPENROUTER_API_KEY , httpReferer : process . env . OPENROUTER_SITE_URL , appTitle : process . env . OPENROUTER_SITE_TITLE , }); Basic integration const response = await client . chat . send ({ chatReques

2026-06-08 原文 →
AI 资讯

The Anti-Bot Detection Checklist I Use Before Every Scraping Project

The Anti-Bot Detection Checklist I Use Before Every Scraping Project Every scraping project I take on starts with this checklist. Not because I'm paranoid — but because I've learned the hard way that production scrapers fail silently. They return 200 OK with garbage data, or they get rate-limited so gradually you don't notice for days. This is the systematic approach I've refined over 50+ scraping projects. Pre-Scraping: Know Your Target 1. Identify the CDN and Protection Stack Before writing a single line of code, check what you're up against: # Check CDN and headers curl -I https://target-site.com # Look for these common protection headers: # X-Engine: akamai-html-protection # X-Served-By: DataDome # cf-ray: Cloudflare # X-Bot-Status: blocked Common protection platforms: Cloudflare → Look for cf-ray and __cfduid cookies DataDome → Look for datadome in headers or scripts PerimeterX → Look for _pxff cookies Akamai → Look for akamai-html-protection headers 2. Check Robots.txt Respectfully curl https://target-site.com/robots.txt | grep -v "^#" Don't take this as gospel — but it's a good signal. If they explicitly disallow your use case, that's a flag. 3. Map the Site's JavaScript Rendering Some sites are fully static (fast, easy). Others render everything with JavaScript (need Playwright/Puppeteer). Check: // Quick check - fetch raw HTML vs rendered content // If they differ significantly, you need JS rendering const https = require ( ' https ' ); const html = await fetch ( ' https://target.com ' ). then ( r => r . text ()); const hasAngularVueReact = /ng-app|vue|react|__NEXT_DATA__/i . test ( html ); console . log ( ' Needs JS rendering: ' , hasAngularVueReact ); Code-Time: Defensive Patterns 4. Rotate User Agents const USER_AGENTS = [ ' Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 Chrome/120 Safari ' , ' Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120 Edge/120 ' , ' Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chro

2026-06-08 原文 →
AI 资讯

Fix: babel-plugin-transform-flow-strip-types broken in Babel 7 and 8

The original babel-plugin-transform-flow-strip-types hasn't been updated in 9 years and breaks silently in Babel 7 and 8 environments. The fix I published a maintained fork that works as a drop-in replacement: npm install --save-dev babel-plugin-transform-flow-strip-types-maintained Then update your .babelrc: { "plugins": ["transform-flow-strip-types-maintained"] } That's it. No other changes needed. What's fixed Babel 7 and 8 peer dependency conflicts Missing syntax plugin declaration Deprecated visitor patterns allowDeclareFields support Automated migration If you want to update your entire project automatically: npx flow-strip-migrate . This updates your package.json and babel config in one command. More info: https://flowstrip.netlify.app npm: https://www.npmjs.com/package/babel-plugin-transform-flow-strip-types-maintained

2026-06-07 原文 →
AI 资讯

Why DaloyJS Is the Best Backend (or BFF) for Your Electron App

If you've ever built an Electron app that needs a backend, you know the problem. You want something lightweight, something that runs on Node, something where you don't spend three hours configuring Swagger, and something that doesn't make you feel like you're setting up a microservices architecture just to expose two endpoints to your own desktop UI. I've shipped Electron apps with Express. I've tried Fastify. Both work, but they leave you doing a lot of plumbing yourself. Then I found DaloyJS , and honestly, it clicked. The Electron Backend Problem Here's the thing about Electron: your renderer process is basically a browser, and your main process is a Node.js server. When you need data from external APIs, or you need a clean layer between your UI and your business logic, you want a BFF, a Backend for Frontend. A thin server that composes upstream calls, holds the session, and returns exactly the shape your UI needs. DaloyJS was built for this role. The docs even say so plainly: typed upstream client, fetchGuard for safe egress, session handling, and edge runtime support. That combination is exactly the BFF toolkit. Contract-First Means Less Glue The killer feature for desktop apps is contract-first routing. You define a route once, and DaloyJS gives you validation, OpenAPI 3.1 docs, and a typed in-process client all from the same source. No stale spec files. No writing types by hand. Here's what a basic Electron BFF route looks like: import { z } from " zod " ; import { App , requestId , secureHeaders , rateLimit } from " @daloyjs/core " ; import { serve } from " @daloyjs/core/node " ; const app = new App ({ bodyLimitBytes : 1 << 20 , requestTimeoutMs : 5 _000 , docs : true , // auto-mounts /docs and /openapi.json }); app . use ( requestId ()); app . use ( secureHeaders ()); app . use ( rateLimit ({ windowMs : 60 _000 , max : 120 })); app . route ({ method : " GET " , path : " /settings/:userId " , operationId : " getUserSettings " , request : { params : z . objec

2026-06-05 原文 →
AI 资讯

Stop Hardcoding 301s: How I Built a Redirect Engine That Doesn't Break at 2 A.M.

Marketing wants an A/B landing page by Friday. Product wants to gracefully deprecate a legacy API without breaking old mobile clients. Growth wants ten thousand short links, and Ops does not want ten thousand Nginx edits. At some point, a single return 301 in your CDN stops being a configuration problem and becomes a routing product . Someone has to answer, on every HTTP request: Given this host, path, query, and method—where does this visitor go, and with which status code? I built that answer as a pipeline at LinkShift . Not a pile of special cases, but a fixed sequence of steps that runs the exact same way for real visitors and for the tools you use to test rules before rollout. Here is how I designed a deterministic redirect engine, the pipeline that powers it, and the edge cases that kept me up at night so they don't have to keep you up. Why "Usually Works" Is Not Enough A redirect engine fails quietly. The browser follows a broken 302 and nobody files a ticket. The damage shows up days later in analytics: wrong campaign, wrong locale, or an infinite loop that only appears when two rules on the same host point at each other. What I wanted early on was boring, bulletproof reliability: Same inputs → same decision. Two engineers simulating the same request against the same rule set should get the same target URL. Same resolution logic everywhere. Matching and destination resolution must not diverge between the "Test Rule" button in the dashboard and an actual click on a custom domain. Guards before cleverness. Rate limits and access checks run before anyone evaluates a ternary conditional in a destination string. Expressiveness is easy. Ordering is what saves you in production. The Pipeline, Told as a Story Picture a request hitting a hostname. Before the engine asks "which rule wins?", the request walks through a strict corridor of gates. Only then does it enter the rule loop. Gate 1: The Host Has to Exist If the hostname does not resolve to a domain or LinkShift

2026-06-04 原文 →
AI 资讯

Serverless Framework Deployment: Unleash the Power of AWS Lambda

Let me tell you exactly what happened the first time I tried to set up Lambda manually. Four hours. IAM trust policies I didn't fully understand, ARNs copy-pasted into the wrong fields, an API Gateway that was technically configured but somehow not routing anything correctly, and a deploy that failed with an error message pointing me nowhere useful. I hadn't written a single line of actual business logic yet. That's when someone on my team mentioned the Serverless Framework. My first reaction was honestly skepticism — another abstraction layer sounded like another thing to learn and eventually fight with. I was wrong about that. This isn't a "look how clean this tool is" post. It's more like: here's what I actually did to get a Postgres-backed CRUD API running on Lambda, step by step, including the parts that tripped me up. What the Framework Is Actually Doing Under the Hood Worth knowing before you start: the Serverless Framework isn't magic. It's generating CloudFormation templates and submitting them to AWS on your behalf. Your Lambda functions, API Gateway routes, CloudWatch log groups — all of it gets provisioned from a single config file. It works with other providers too, but the AWS integration is where it really earns its keep. The console clicking and manual ARN-wiring that burns time at the start of every serverless project? Gone. Same deploy workflow whether you're building a REST API, an event processor, or a cron job. Once you've done it once, the second project takes a fraction of the time. What You're Building Four live endpoints backed by PostgreSQL. A Users table. Create, read, update, delete — nothing exotic, but a real enough foundation that you can extend it into something actual once this guide is done. You'll need an AWS account, the AWS CLI installed, and the Serverless Framework installed before starting. That's it. Step 1: Sort Out Your AWS Credentials Run this to create both config files in one go: bash cat << EOF > ~/.aws/credentials [def

2026-06-04 原文 →
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

2026-06-03 原文 →
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

2026-06-03 原文 →
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.

2026-06-02 原文 →
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 :

2026-06-01 原文 →
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,

2026-06-01 原文 →
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

2026-06-01 原文 →
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

2026-05-31 原文 →
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

2026-05-31 原文 →
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

2026-05-31 原文 →
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

2026-05-31 原文 →
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

2026-05-30 原文 →