AI 资讯
A test said the server started. I deleted the server. It still passed.
Here is a test from a real, well run Node project: test ( ' server starts ' , async ( t ) => { const app = build () await app . listen ({ port : 0 }) t . assert . ok ( true , ' server started ' ) }) It reads fine in review. It runs green. Now delete the body of build() so the server never comes up. The test is still green, because the only thing it asserts is true . In the same file two more of these caught the error in a catch and asserted true there too, so even the failure path was green. That is not a made up example. I found it in fastify at a pinned commit and opened a PR to fix it. More on that at the end. A whole class of tests cannot fail Once you start looking, the pattern turns up in a few shapes: A literal: assert.ok(true) , expect(1).toBe(1) , a snapshot of a constant. An assertion parked in a catch the happy path never reaches, so nothing is checked when the code works and nothing is checked when it breaks. A status list that accepts both outcomes: assert.ok([200, 500].includes(res.status)) . Each one runs, counts toward coverage and guards nothing. Coverage is the trap. The line executed, so the tool that counts executed lines is happy. Whether the line would go red on a regression is a different question. It is the one that matters. Why review misses it A reviewer reading the diff sees a test called server starts , an await listen and a green tick. The name states intent. The assertion is what actually runs, yet ok(true) does not look like a problem until you stop and ask what would ever turn this test red. A missing check does not show up in a diff the way a wrong line does. Finding them I wrote a small scanner for this. No account, no config file, no network call: npx margyn-scan /path/to/repo One of its checks is cannot-fail : tests whose assertions hold whatever the code does. It also flags tests that assert nothing at all, files the build reads that git never committed, gates declared in package.json that no workflow invokes and linter exclusion
AI 资讯
Simple Hosted Metrics Dashboard API Explained (for Small Node.js SaaS with Postgres)
Choice Setup burden Incident evidence Best fit Hosted metrics API Low Good if event context is preserved Small teams with an on-call rotation Postgres plus a custom dashboard Medium Excellent for joining metrics to business records Low-volume systems with strong SQL skills Self-hosted metrics stack High Configurable, but operationally demanding Teams that already run observability infrastructure Short answer: start with a hosted metrics dashboard API, send a small set of custom application metrics from Node.js, and retain reconstruction fields in Postgres. Choose the custom Postgres path when joins are the investigation, or self-hosting when data control outweighs maintenance. That recommendation has a catch. A chart can show when enrollment failures rose, but it cannot explain which course, release, region, or feature state produced them unless those dimensions were recorded at write time. For an edtech SaaS, the real deliverable isn't a pretty dashboard. It is enough evidence to replay the story of a customer incident without guessing. How can Node.js send custom app metrics to a hosted dashboard API? Capture the dimensions an investigator can act on: metric name, timestamp, deployment identifier, region, tenant or school identifier, operation, outcome, and a bounded error class. Keep direct student data out of labels. A useful event might say that lesson_publish failed validation in the EU region on deployment 7f3c2a1 ; it should not contain a learner's name, email, answer, or free-form support message. Small is good. Stop there. Start with service-level signals tied to customer work: request count, failure count, latency distribution, queue depth, and the age of the oldest queued job. Add business-flow counters such as course publication attempts only when they answer a concrete incident question. Don't export every database column as a label. High-cardinality dimensions make charts harder to read, alerts harder to tune, and the ingestion boundary harder to reas
AI 资讯
Prompt Caching at the Edge: Using CloudFront Functions and Lambda to Speed Up Claude Calls
LLM APIs like Claude feel snappy—until latency spikes hit your users. By caching prompt‑response pairs right at the edge, you can cut round‑trip time to milliseconds. This post shows you how to make that happen with CloudFront Functions and a Lambda origin. Why Prompt Caching Matters for LLM‑Powered Apps When a user types a question, your front‑end sends the text to an LLM (large language model) API, waits for the model to generate a reply, and then shows the answer. The user experience is dominated by two things: Network latency – the time it takes for the request to travel from the user’s browser to the API endpoint and back. Model compute time – how long the LLM needs to think. Even if the model itself is fast, the network hop to the provider’s data center can add 100 ms – 300 ms, and sometimes more during traffic spikes. For a chat UI that refreshes every few seconds, those extra milliseconds feel like a noticeable lag. Prompt caching means storing the exact prompt (the user’s message) together with the response (the model’s answer) in a fast lookup table. If the same prompt arrives again within a short window, you can return the cached answer instantly, without touching the LLM provider at all. In plain English: Think of the cache as a “sticky note” on the receptionist’s desk. If someone asks the same question twice, the receptionist can hand them the note instead of calling the manager again. Freshness vs. Speed LLM responses are not immutable—new data, temperature settings, or model updates can change the answer. A short time‑to‑live (TTL) of a few minutes gives you a good trade‑off: most users repeat recent prompts, but you still get new answers after a reasonable window. Setting Up a CloudFront Distribution with an Edge Key‑Value Store The big picture Edge KV store – a tiny key‑value database that lives on every CloudFront edge node. CloudFront Function – a lightweight JavaScript snippet (max 2 MB) that runs on every request before it reaches the origin. It
AI 资讯
Frame-accurate FFmpeg trimming without re-encoding the whole file
TL;DR -c copy can only cut on keyframes, so your 12.4s trim starts wherever the last keyframe was. We'll build a smart-trim script that probes keyframe positions with ffprobe , re-encodes only the head and tail fragments, stream copies everything between them, and concatenates the three. Frame accurate output, encoding cost proportional to two GOPs instead of the whole file. Tested with FFmpeg 9.0 "Lei" (released 2026-08-04) and Node 22.x. The JS is ESM, so put "type": "module" in your package.json before running any of it. Everything here also works on FFmpeg 7.x and 8.x; nothing we use is new. The problem, in two commands 🎬 # fast, and wrong ffmpeg -ss 12.4 -i input.mp4 -t 20 -c copy fast.mp4 ffprobe -v error -show_entries format = start_time,duration -of default = nw = 1 fast.mp4 # start_time=0.000000 # duration=20.388000 <- we asked for 20, starting at 12.4 The clip is long by the distance from our requested start back to the previous keyframe, and every frame in it is shifted earlier than the user asked for. Stream copy moves compressed packets without decoding them. Most frames in a compressed stream only describe the difference from their neighbors, so the only place you can start is a keyframe. FFmpeg snaps back to the nearest preceding one, and your clip starts early. # accurate, and slow on a long source ffmpeg -ss 12.4 -i input.mp4 -t 20 -c :v libx264 -crf 20 -c :a aac slow.mp4 We want the accuracy of the second and roughly the cost of the first. 1. Look at your keyframes first Before writing any code, find out how bad the problem is for your content: ffprobe -v error -select_streams v:0 \ -show_entries packet = pts_time,flags \ -of csv = print_section = 0 input.mp4 | grep 'K' | head -20 0.000000,K__ 2.002000,K__ 4.004000,K__ 6.006000,K__ Two second GOPs here, so worst-case error is about two seconds. Screen recorders and some camera output emit keyframes on scene change only, and there the gaps can be 30 seconds or more. That distribution is the real spe
AI 资讯
Past the README Demo: Conversations, Healthcare Data, Agents, and CI Checks
"Extract a name and email from this sentence" is the easy 10% of structured output. The other 90% is everything that doesn't fit in one prompt, one turn, or one model call. Here are five things shapecraft handles once you're past the basics. 1. Collecting data across a whole conversation A single message rarely has everything you need. Someone books an appointment over three or four back-and-forth messages, not one. turnaround mode lets the conversation run naturally and validates the whole transcript once, at the end, against one schema: import { generate , openai } from " @aviasole/shapecraft " ; const result = await generate ( model , BookingSchema , conversationHistory , { turnaround : true , }); No manual "do I have everything yet?" tracking, no partial-state bugs, just one validated object once the conversation is actually complete. 2. Extracting from clinical notes into real FHIR shapes Healthcare data has a standard (FHIR R4) and it's not optional if you're integrating with anything real. Built-in presets mean you're not hand-writing a Patient or Observation schema from scratch: import { generate , openai } from " @aviasole/shapecraft/fhir " ; import { PatientSchema } from " @aviasole/shapecraft/fhir " ; const patient = await generate ( openai ({ model : " gpt-4o-mini " }), PatientSchema , clinicalNote ); Same retry/validation guarantees as any other schema, just pre-built to match a spec you'd otherwise have to implement yourself. 3. An agent that checks real data before answering "Is this order still on hold?" isn't answerable from the prompt alone, it needs an actual lookup. generateWithTools() lets the model call your functions, see the results, and then produce a validated final answer: import { generateWithTools } from " @aviasole/shapecraft " ; const result = await generateWithTools ( model , [ lookupOrder ], AnswerSchema , userQuestion ); The tool call's arguments are validated before your function ever runs, and the final answer goes through the sam
AI 资讯
Fintech Shipment Fan-Out: SaaS Retention Cleanup and the Node.js Cron-Queue Boundary
Short answer: use a scheduled cleanup endpoint when one indexed, bounded pass can finish predictably; use a queue when cleanup must be divided into independently retriable batches. For a fintech SaaS that fans out shipment updates to many subscribers, latency and cost should be judged at the system boundary: a cheap cleanup run is not a good bargain if it contends with delivery or leaves retention evidence incomplete. The first design decision is to keep shipment fan-out separate from retention work. A shipment update has a latency-sensitive path. Expired subscriptions, old delivery attempts, and temporary fan-out records usually have a policy-driven path. They may share a database, but they should not share an unbounded transaction or an execution budget. This distinction matters more than the spelling of a cron expression. It also gives the team a useful test: can the cleanup be repeated safely while the shipment update path continues to make progress? How should a Node.js SaaS choose a cron or queue for scheduled cleanup? Measure the worst case first. Count eligible records by tenant, check the relevant index, estimate lock pressure, and measure a bounded pass while the database is serving normal shipment traffic. The median duration is not the decision variable; the tail is. A scheduled data cleanup is a good fit for one HTTP-triggered run when its cutoff, tenant scope, batch size, and completion state can be recorded and the run has room to finish before its execution limit. The cutoff should be computed by the application and persisted with the run. A schedule has jitter, and a paused schedule may not replay every missed invocation. “Delete records older than the cutoff captured at run start” is therefore more auditable than silently recalculating the boundary for every page. The query should also exclude legal holds, active disputes, and any retention exception required by the business policy. Keep it bounded. The boundary is operational. When a tenant can mo
AI 资讯
RFLCT: Bringing Runtime Type Metadata to TypeScript 7
If you've built large-scale applications in TypeScript, chances are you've used a Dependency Injection (DI) container. As the creator of InversifyJS, I've spent years thinking deeply about inversion of control, decoupling, and how to make enterprise patterns feel natural in TypeScript. But for all those years, there has been a glaring elephant in the room: our heavy reliance on experimentalDecorators and emitDecoratorMetadata . These compiler flags have served us well, but they are exactly that— experimental . They tie us to legacy decorator implementations, require specific compiler configurations, and often feel like a magic black box that doesn't perfectly align with modern build pipelines. I've spent a lot of time recently thinking about how we could finally drop these flags entirely while keeping the developer experience pristine. With the release of TypeScript 7, I'm thrilled to introduce the solution: 🪞 RFLCT . What is RFLCT? RFLCT is an ahead-of-time (AOT) reflect metadata injector for TypeScript 7. It injects design:symbols and design:arguments directly at build time. Zero decorators. Zero emitDecoratorMetadata . It integrates seamlessly with virtually any build tool (Vite, Rollup, webpack, esbuild) via unplugin , or you can use the built-in CLI using the TypeScript 7 API for standalone tsgo projects. Let's look at how it actually feels to write code with RFLCT. The Magic: Before and After With RFLCT, you annotate the types you want to expose to your runtime metadata using a special Reflect<T> wrapper type. What you write: import { Reflect , resolve } from " rflct " ; interface Shape { sides : number ; } class Polygon { constructor ( public shape : Reflect < Shape > , public label : Reflect < string , { optional : true } > ) {} } // resolve<T>() → the runtime identity of T (Symbol for interfaces, class for classes) container . bind ( resolve < Shape > ()). to ( Polygon ); What RFLCT compiles it to: Notice how the interfaces are safely converted into global
AI 资讯
From SOLID to Composition, Dependency Injection, and IoC: How Angular, Spring, and Node.js Differ
When learning Angular, Spring, and Node.js, I often came across terms like SOLID, Dependency Injection (DI), Inversion of Control (IoC), IoC Container, and Composition . At first, these concepts can feel like they are all the same thing. They are not. The key realization is: SOLID is about how we design software. Composition is about how we build larger systems from smaller pieces. Dependency Injection is a technique for providing those pieces. IoC containers automate that process. Understanding this relationship makes Angular, Spring, and Node.js architectures much easier to reason about. 1. SOLID Is a Design Principle, Not a Framework Feature SOLID is a collection of software design principles. For example, Single Responsibility Principle (SRP) says that a component should have a focused responsibility. Instead of having one class responsible for HTTP handling, database access, validation, email, and payment processing, we can separate those responsibilities: Controller ↓ Service ↓ Repository ↓ Database Each part has a focused job. Similarly, the Open/Closed Principle (OCP) encourages us to design components that can be extended without constantly modifying their existing implementation. These principles don't require Angular, Spring, or an IoC container. You can follow SOLID in plain JavaScript. 2. Composition Is the Bigger Idea Composition means: Build a larger behavior by combining smaller, focused pieces. This works in both functional and object-oriented programming. In functional programming: function A ↓ function B ↓ function C A larger function can be created by composing smaller functions. In object-oriented programming: OrderService │ ├── PaymentService └── EmailService OrderService is composed using other objects. The important relationship is often: HAS-A rather than IS-A For example: OrderService HAS-A PaymentService rather than: OrderService IS-A PaymentService This is one reason composition is often preferred over deep inheritance hierarchies. 3. Dep
AI 资讯
I built an RPG that teaches Claude Code by making you actually use it
Most tool documentation teaches by just telling you things. You read a page about /model , or hooks, or subagents, nod along, and forget it by the time you'd actually need it. I wanted something closer to how people actually learn a CLI, by using it, with something checking whether you did the thing right or not. So I built claude-quest , a text RPG that runs entirely inside a real claude session and teaches the Claude Code CLI zero to hero. the idea isn't new, I borrowed it This is basically GameShell 's philosophy applied to Claude Code. GameShell teaches Unix shell commands by dropping you into a real shell wrapped in a themed fake filesystem, and grading your progress by checking real shell/filesystem state instead of asking you to self report or answer a quiz question. claude-quest does the same thing, except the "filesystem" is a real Claude Code environment. missions live in real sandbox directories, and progress is checked by inspecting what you actually did, config files you wrote, hooks that fired, tool calls that happened. what it actually looks like There's no separate app, no fancy terminal UI, none of that. You say "let's play claude quest" inside a normal claude session, and Claude itself becomes the game master. It reads real output from the engine and narrates on top of it, something like this: > lets play claude quest **The Gatehall** You've just been let through the outer gate. The tower keeps no secrets from those who bother to read the walls... **Mission: First Contact** (Tier 1, Artifact) Create a CLAUDE.md file in this sandbox recording how to run the project's tests. Let me know when you're done and I'll check it. > done CLAUDE.md records how to run the tests. Claude Code will know next time. MISSION_STATUS: complete **What you actually learned:** Claude Code reads a file named CLAUDE.md in your project root automatically, at the start of every session... that's it, that's the whole interface. it's just a chat, with real commands running unde
AI 资讯
How to Combine Claude’s Function Calling with SNS FIFO for Reliable, Ordered AI Notifications
LLMs can now call tools, but turning their output into a trustworthy event stream is still a puzzle. We wire Claude’s function‑calling to an SNS FIFO topic, giving you ordered, deduplicated notifications that downstream Lambda functions can consume with zero‑loss guarantees. Why SNS FIFO Is a Good Fit for LLM‑Generated Events When an LLM decides to “publishAlert”, you usually want the alert to be processed exactly in the order it was generated . Imagine a fire‑alarm system that first warns about a smoke detector, then follows up with a sprinkler‑activation command. If those two messages arrive swapped, you could end up turning on sprinklers before the fire is even confirmed. FIFO stands for First‑In‑First‑Out . An SNS FIFO topic guarantees that messages sharing the same MessageGroupId are delivered to subscribers in the exact order they were published. This is different from the default “standard” SNS topics, which deliver messages quickly but without ordering guarantees. In plain English: SNS FIFO is like a single‑lane road with a traffic light that lets cars (messages) pass one after another, never overtaking. Key terms (first use) Term Meaning Function calling A feature where the LLM can invoke a pre‑defined tool (a piece of code) instead of just returning text. FIFO topic An SNS topic that preserves the order of messages that belong to the same logical group. MessageGroupId An identifier that tells SNS which messages belong together for ordering. MessageDeduplicationId A token that prevents the same message from being delivered twice within a 5‑minute window. Lambda A serverless compute service that runs code in response to events (like an SNS message). Because the LLM can generate many alerts rapidly, using a FIFO topic means you can treat the AI as a deterministic producer rather than a chaotic chatterbox. The downstream Lambda sees the alerts in the same sequence the model emitted them. Setting Up Claude’s Function Calls to Publish to SNS Before you can send
AI 资讯
The n8n Community Node You Need Might Already Exist
You know that moment when you're building an n8n workflow and realize: “Wait… does n8n already have a node for this?” Maybe you need a specific AI provider. Or a browser automation tool. Or some obscure database. Or a service that isn't part of n8n's core integrations. The first instinct is usually to reach for the HTTP Request node. But before writing API calls yourself, there's another possibility: Someone may have already built the node. That's one of the reasons I created Awesome n8n Community Nodes . The n8n ecosystem is bigger than it looks One of the best things about n8n is that it isn't limited to its built-in integrations. Developers can create community nodes and publish them as npm packages, extending n8n with new services, triggers, actions, AI capabilities, utilities, and more. The ecosystem has grown significantly. One existing ecosystem tracker had already indexed thousands of community nodes, showing just how quickly the space is expanding. That's great for n8n users. But it creates a new problem: Discovery. Having thousands of nodes is useful only if you can actually find the one you need. So I built a directory I created: Awesome n8n Community Nodes 🔗 https://github.com/bhavyshekhaliya/awesome-n8n-community-nodes It's an open-source, curated directory for discovering community-built n8n integrations and utilities. Instead of organizing everything as one massive list, I grouped nodes around what you're actually trying to automate. 🤖 AI, Agents & Search Looking for AI, LLM, search, agent, or AI-media capabilities? There's a dedicated section for that. 🌐 Browser, Web & Scraping Need browser automation, crawling, scraping, or web extraction? You'll find those together. 💬 Communication & Messaging WhatsApp, email, chat, notifications, and other communication-related nodes have their own category. 🗄️ Data, Storage & Observability Database, storage, infrastructure, monitoring, and data-related integrations live here. 📄 Documents, Media & Productivity For
AI 资讯
Node.js API Key Text Classification: JSON Validation Before Multi-Provider Gateway Failover
Short answer: For private knowledge-base tagging, compare a multi-provider LLM gateway by valid, policy-compliant classifications per unit of spend, not by the cheapest advertised token rate. One API key reduces credential and adapter work, but JSON mode is only a transport promise; your Node.js boundary still needs to parse, validate, reject, and selectively retry every answer. The decision rule is blunt: keep the gateway only if the same frozen evaluation set produces acceptable labels and schema-valid JSON across the model routes you will actually enable. Otherwise, use direct provider adapters and accept the extra config. What changed the gateway choice? A private developer-tools knowledge base sounds like a small classification job. Give each document one primary tag, a confidence value, and a short reason. The awkward part is that a syntactically valid object can still be wrong: confidence may be a string, a tag may fall outside the approved taxonomy, or the model may classify instructions embedded in a document instead of classifying the document itself. JSON mode doesn't settle any of those cases. So I would benchmark the boundary, not the demo. The fixture set should contain ordinary docs, empty bodies, ambiguous release notes, code-heavy pages, and text that tries to redirect the classifier. Freeze the prompt, taxonomy, expected acceptance rules, and model identifiers for each run. Then record parse success, schema success, allowed-tag success, agreement with reviewed labels, latency, and total billed usage. I'm not sure which route wins on a particular corpus; nobody can know without those reviewed labels and current billing data. Your mileage may vary. This is where “cheapest routing” gets slippery. A low-cost response that fails validation and consumes a retry isn't cheap. A fallback that returns valid JSON but changes the label is not recovery either — it is an observable classification decision that needs its own test. Short version: benchmark accepte
AI 资讯
40001 is not a query error
The PostgreSQL manual is unusually direct about this: When an application receives this error message, it should abort the current transaction and retry the whole transaction from the beginning. "The whole transaction" is doing a lot of work in that sentence, and it is the part that gets dropped. TypeORM issue #9806 — "Auto Retry options on error in transactions (e.g. Deadlock)" — has been open since February 2023. Thirty 👍, six comments, no implementation. Meanwhile typeorm-transactional , at 188,000 downloads a week, ships @Transactional() with isolation levels and seven propagation modes and no retry at all. So the ecosystem's actual answer to "how do I use SERIALIZABLE in Node" is: don't. Use READ COMMITTED , don't think about write skew, and hope. I spent a while building the thing that issue asks for. The short version of what I found: the feature as literally requested cannot be built correctly , and the reason is more interesting than the feature. The implementation everyone reaches for first Wrap the query. It's the obvious move — the error came from a query, so retry the query: async function withRetry < T > ( fn : () => Promise < T > , attempts = 3 ): Promise < T > { for ( let i = 1 ; ; i ++ ) { try { return await fn (); } catch ( e ) { if ( i >= attempts || ! isSerializationFailure ( e )) throw e ; await sleep ( 50 * i ); } } } await dataSource . transaction ( ' SERIALIZABLE ' , async ( em ) => { const from = await em . findOneOrFail ( Account , { where : { id : fromId } }); const to = await em . findOneOrFail ( Account , { where : { id : toId } }); await withRetry (() => em . decrement ( Account , { id : fromId }, ' balance ' , amt )); // ← here await withRetry (() => em . increment ( Account , { id : toId }, ' balance ' , amt )); // ← and here }); This does nothing. Worse than nothing — it turns one clear error into a confusing one. When PostgreSQL raises 40001 , it does not fail that statement . It aborts the entire transaction . The connection is now
AI 资讯
App Health Endpoint Design: 3 Probes That Keep Logging and Metrics Useful
Short answer: for a Node.js app in Docker or Kubernetes, give startup, readiness, and liveness probes separate meanings, keep routine health traffic out of application logging, and measure state transitions instead of counting every successful check. For a property-management API rolling out a new pricing rule, this preserves useful metrics: whether an instance can calculate rent correctly and accept traffic, without turning each kubelet poll into noise. Which health signal should control each container decision? Start with the decision, not the endpoint name. Signal Question it answers Include Exclude Action Startup Has initialization completed? Configuration parsing, pricing-rule compilation, required local warm-up Long-term dependency health Allow the process more time before other probes apply Readiness Can this instance safely receive a new pricing request now? Ability to serve the active rule version and any required dependency state Optional analytics and background exports Remove the pod from Service endpoints Liveness Is the process stuck beyond local recovery? Event-loop progress or another narrow process invariant Database, cache, and third-party availability Restart the container This split is the main noise filter. A downstream dependency becoming unavailable can make a pod unready, but restarting the same healthy process usually doesn't repair that dependency. If the dependency is placed in liveness anyway, every pod can restart together. The health response has then amplified one problem into two: lost capacity plus a restart storm. The pricing rollout makes readiness more demanding than “the port is open.” Imagine rule version rent-2026-08 is enabled for one building cohort. A newly started instance has loaded configuration but hasn't compiled that version yet. It is alive. It isn't ready. Its startup check should hold back liveness and readiness until initialization finishes; afterward, readiness should stay false until the active rule can be evalua
AI 资讯
52 Days, 2,340 Rows, Every Cost Logged as Zero: The Stop Hook Trap
Going from a $700/month student side hustle to a real business in six months came down to one thing: I stopped instructing Claude and started letting it run the whole environment autonomously. That environment then spent 52 days writing 2,340 log rows where every single cost was zero — and it never once complained. Why This Setup Works Most people who start with Claude Code use it as a convenient chat AI. But once monthly revenue crosses a certain threshold, your thinking shifts. Instead of "issuing instructions and getting output," you move to "letting the whole environment run itself." Here's the concrete difference. In the first mode, you type a prompt every time and get a result back. In the second, hooks fire while you sleep, scripts execute, and logs accumulate. In my case, there are a dozen-odd jobs running on a schedule via launchd, and a Claude Code Stop hook that fires at the end of every session. I wake up to yesterday's brief sitting on my Desktop, and a record in ~/.claude/metrics/costs.jsonl of how many tokens each session consumed — that was the ideal, anyway. Why track cost at all? Claude Code's MAX plan is a flat monthly fee, but there's an intuitive ceiling where "using too much effectively chokes next month's capacity." Without visibility into which session used which model and how much, you're running autonomous agents with zero cost awareness. The more convenient an autonomous environment gets, the more it silently eats. That's why measurement comes first. The Stop hook is the mechanism that handles this measurement. When a Claude Code session ends (when the user runs /exit , or on timeout), it runs the commands registered in the Stop section of settings.json . Put a cost-aggregation script there and you get a "session ends = automatically recorded" pipeline. No more hand-typing costs into a spreadsheet. "It's running" and "it's running correctly" are different things — any engineer knows the feeling. Logs streaming out with all-zero contents is
AI 资讯
Node.js Express vs. Python FastAPI: Which Should You Choose in 2026?
Node.js Express vs. Python FastAPI: The Definitive Guide for Choosing Your Next Backend Choosing a backend framework used to be simple. If you liked JavaScript, you built with Express. If you liked Python, you went with Flask or Django. But the landscape has fundamentally shifted. With the explosion of AI, machine learning, and strict type safety, Python FastAPI has emerged as a powerhouse alternative to the traditional JavaScript runtime. Meanwhile, Node.js Express remains the unopinionated king of the enterprise web. If you are starting a new project today, which one should you choose? Let’s break down the technical trade-offs, developer experience, and code structures of both frameworks. 🚀 The Core Philosophy Node.js Express: The Minimalist Canvas Express is a minimalist, unopinionated framework. It doesn't care how you structure your folders, how you validate data, or how you handle errors. It gives you a robust set of HTTP tools and steps out of your way. The Catch: You have to build or install your own solutions for data validation, ORM mapping, and API documentation. Python FastAPI: The Automated Powerhouse FastAPI is built on modern Python 3.8+ features like type hints and asynchronous ASGI (asyncio). It is highly opinionated about data handling, leveraging Pydantic to automate input validation and schema serialization. The Catch: It forces you into a specific way of handling data types from day one, which can feel restrictive if you prefer absolute freedom. 📊 Feature Breakdown Feature Node.js Express Python FastAPI Language JavaScript / TypeScript Python Data Validation Manual / Third-Party (Zod, Joi) Native via Pydantic API Docs Manual Setup (Swagger UI plugin) Automatic (Interactive Swagger UI & ReDoc) Best For Real-time I/O, WebSockets, Full-stack JS AI/ML APIs, Data pipelines, Type-safe apps 🛠️ Code Comparison: Creating a Validated POST Route Let’s look at how both frameworks handle a common task: creating a POST endpoint that accepts an item, validates
开发者
JWT Authentication in Node.js: A Practical Guide (with Express)
Ever logged into an app, closed the tab, come back, and you're still logged in — no password needed? That's almost always JWT doing its job behind the scenes. JWT (JSON Web Token) is one of the most common ways to handle authentication in modern backends. But a lot of developers use it without really understanding what's happening — and that's exactly where security bugs sneak in. Let's fix that. By the end of this post you'll know what a JWT actually is, how to use it in a Node.js + Express app, and the mistakes that quietly break real apps. What is a JWT, really? A JWT is just a string with three parts , separated by dots: xxxxx.yyyyy.zzzzz │ │ │ header payload signature Header — says which algorithm signed the token (e.g. HS256 ). Payload — the actual data (like userId , role , and an expiry time). This is not encrypted — it's just Base64-encoded. Anyone can read it. Signature — a cryptographic stamp created using a secret only your server knows. This is what stops people from faking tokens. Want to see this for yourself? Paste any token into a free JWT decoder and you'll instantly see the header and payload. Notice you can read everything without the secret — that's the key lesson: never put passwords or sensitive data in a JWT payload. Creating a token (login) Install the library: npm install jsonwebtoken When a user logs in successfully, sign a token: import jwt from ' jsonwebtoken ' // On successful login: const token = jwt . sign ( { userId : user . _id , role : user . role }, // payload process . env . JWT_SECRET , // secret (keep it in .env!) { expiresIn : ' 7d ' } // auto-expiry ) res . json ({ token }) Three things to notice: Keep the payload small — just an id and role, not the whole user object. The secret lives in an environment variable, never hardcoded. Always set expiresIn . A token that never expires is a token that can be stolen forever. Verifying a token (protecting routes) Now create a middleware that checks the token on every protected request
AI 资讯
Why Fixed-Window Rate Limiters Fail (And How to Fix Them with Math)
If you’ve ever built an Express API, you’ve probably reached for standard rate-limiting middleware to protect your login or payment endpoints from DDoS and brute-force attacks. Under the hood, most simple limiters use a Fixed-Window Counter . It’s easy to write: count incoming requests, and once the minute rolls over, reset the counter to zero. However, from a security and algorithmic standpoint, Fixed-Window counters have a massive blind spot. The Boundary Vulnerability (The 2-Second Spike) Imagine your endpoint allows a maximum of 100 requests per minute , resetting every full minute on the clock ( :00 ). Here is how an attacker bypasses that limit without breaking your rules: At 12:00:59 , the attacker fires 100 requests. (Allowed: 100/100 used). At 12:01:00 , the clock resets your counter back to 0. At 12:01:01 , the attacker fires another 100 requests. (Allowed: 100/100 used). To your server code, everything looks fine. But in reality, 200 requests slammed your backend within a 2-second window. In FinTech or authentication systems, that burst is more than enough to overwhelm payment gateways or run a successful credential-stuffing attack. The Algorithmic Fix: Sliding Window Counter To stop boundary spikes, we need a continuously sliding window rather than a rigid clock reset. Attempt 1: The Sliding Window Log (High Memory) You store a timestamps array (a Deque) for every user request and drop timestamps older than 60 seconds. While accurate, storing every single request timestamp takes $O(N)$ space. If your API receives millions of requests, your server memory dies instantly. Attempt 2: Sliding Window Counter (Optimal O(1) Math) Instead of keeping thousands of timestamps, we track only two integers : the request count of the previous window and the count of the current window . When a request arrives, we calculate an estimated request count by weighting the previous window based on how much time has passed in the current window: Estimated Requests = Current Cou
AI 资讯
Next step to client-side storage
Next step to client-side storage In my past one blog, I wrote about how I improve the performance of the application using the local storage. And the problem local storage solves. But now I face another problem about the client storage. My project is simply about order management software for the rental clothing industry. In the rental clothing industry, Showrooms or small shops have a big problem. The problem starts when one order has a single or multiple items that are booked in a particular time range. Now, a second order wants the same item in between that particular time range. If, by mistake, the second order books that item, then the problem starts. The item is booked two times in that particular time range. That is called double booking of the item. This mistake is created by the use of traditional register booking. Now, when I need to store the items data, that is a small amount of data, so I simply use the local storage. But now I need another and a big storage for storing order details. I build two features: first one is for showing all the orders and second one is for showing the full order. To implement those features and to maintain the user experience, I decide to store a small amount of data about the order on the client side. First, I decide to store data in local storage. But to store data in the local storage is not a good option because the local storage is used for storing small details about the application, and storing order details in the local storage compromises the performance of the application. Now I want a new storage option for storing order details. And again I find out, and that is the IndexedDB. To integrate IndexedDB in my application, I want to learn about that storage. I search multiple videos about IndexedDB, but no one is teaching me properly. After finding hundreds of tutorials, I finally found one tutorial that is teaching properly how to integrate IndexedDB in the application. Now I want to share that learning with you. To i
AI 资讯
Redora 0.3.1 — Redis for NestJS
There are already good Redis tools for NestJS. Most of them mainly help you connect NestJS to Redis and use the Redis client. That's useful, but as a project grows, you often need to build more things around Redis yourself: caching, TTL, cache invalidation, locks, rate limiting, sessions, monitoring, and more. That's why I built Redora. Redora adds a higher-level layer for using Redis in NestJS. Today it includes: Redis service Cache service Cache decorators "remember()" caching TTL and expiration policies Cache tags and eviction Distributed locks Redis diagnostics Logger and observability _The idea is simple: Redis gives you the primitives. Redora gives you the architecture._ What I'm working on next I want Redora to cover more of the common things developers use Redis for: Session management Rate limiting for OTP, login, and APIs Distributed locks Message queues Redis for AI applications Redis and Valkey support More monitoring and telemetry Redora is still early and I'm building it in public. 📦 "npm i redora" 🌐 https://redora-sdk.com If you use NestJS and Redis, try it and let me know what you think. I'd really like to hear what works, what's missing, and what you would change.