AI 资讯
Kenapa Banyak Frontend Developer Memakai Next.js untuk Pekerjaan, tapi Vue.js untuk Personal Project?
Artikel ini juga tersedia dalam bahasa Inggris Pendahuluan Beberapa waktu terakhir saya sering berdiskusi dengan beberapa frontend developer mengenai framework yang mereka gunakan. Pertanyaan saya sebenarnya sederhana. "Kalau membuat frontend web, biasanya pakai framework apa?" Hampir semuanya memberikan jawaban yang kurang lebih sama. "Tergantung kebutuhan." Dan saya setuju. Tidak ada framework yang selalu menjadi pilihan terbaik untuk semua kondisi. Namun, setelah pembahasannya berlanjut, mereka mulai menceritakan pengalaman dan preferensinya masing-masing. Nah... Di sinilah saya mulai menemukan pola yang menarik. Dari beberapa developer yang saya ajak berdiskusi, cukup banyak yang mengatakan bahwa mereka lebih sering menggunakan Next.js / React untuk pekerjaan, sedangkan Vue.js lebih sering digunakan untuk personal project. Padahal saya tidak pernah bertanya, "Kalau kerja pakai apa?" atau "Kalau project pribadi pakai apa?" Penjelasan itu muncul begitu saja ketika mereka mulai menjelaskan alasan di balik framework yang mereka pilih. Awalnya saya mengira itu hanya kebetulan. Tapi setelah mendengar pola yang sama dari beberapa orang... Saya jadi penasaran. Kenapa banyak developer yang sudah menguasai keduanya justru memilih memisahkan penggunaannya? (・_・;) Disclaimer Tulisan ini bukan hasil survei atau penelitian resmi. Ini hanyalah pola yang saya temui dari beberapa frontend developer yang sempat saya ajak berdiskusi. Pembahasan Vue.js Kalau melihat ekosistem frontend saat ini, Vue.js jelas bukan framework yang kecil. Komunitasnya besar. Dokumentasinya bagus. Ekosistemnya juga sudah cukup matang. Namun memang harus diakui, jika dibandingkan dengan React dan Next.js, komunitasnya memang masih lebih kecil. Lalu muncul pertanyaan. Kalau begitu... Kenapa masih banyak yang memilih Vue.js untuk personal project? Dari beberapa jawaban yang saya dengar, ternyata alasan utamanya bukan karena performa. Bukan juga karena framework lain kurang bagus. Melainkan karena pengalama
AI 资讯
React development and clean architecture
Hot take 👀 The hardest part of React isn't hooks. It's knowing how to structure an app so it stays maintainable as it grows. Clean architecture beats clever code every time. What's been the biggest challenge in your React projects?
AI 资讯
The Architectural Trap: Accessing CONST Attributes Across a Series of Classes
When building scalable systems, we often need a collection of classes to expose a fixed, read-only configuration value. Whether it is a unique API_ENDPOINT, a DATABASE_TABLE name, or a specific PERMISSIONS_MASK, handling constants across a series of classes looks simple on day one but can quickly turn into an architectural nightmare. Setting the Foundation: How to Make It In modern object-oriented programming, the standard way to declare a constant on a class is by leveraging the static readonly modifiers. This ensures the attribute belongs to the class itself, rather than an instance, and cannot be mutated at runtime. TypeScript class BillingService { static readonly SERVICE_TYPE = "BILLING"; } class InventoryService { static readonly SERVICE_TYPE = "INVENTORY"; } This works perfectly when you know exactly which class you are dealing with at compile time. You simply call BillingService.SERVICE_TYPE and move on. The Architectural Breakdown: What Will Be the Problems The clean code facade breaks the moment you attempt to handle these classes dynamically. In production environments, you rarely hardcode class names; instead, you process them as an array or a series of registry keys. Loss of Type Safety: If you pass a series of these classes into a processing function, standard type systems will treat them as generic constructor functions, wiping out access to the static property unless you resort to unsafe type casting. Polymorphism Failure: Subclasses do not inherently enforce or override static properties cleanly through standard interfaces. You cannot enforce a static readonly property on an interface, meaning a developer could easily forget to define the constant on a new service class, causing silent runtime failures. Instance vs. Class Metadata Confusion: If your architecture receives an instance of the class rather than the class definition itself, accessing the static attribute requires jumping through hoops like instance.constructor.SERVICE_TYPE, which breaks
AI 资讯
I'm not an engineer. I built a prompt-structuring tool anyway, using Claude Code — here's what actually went wrong
I'm not an engineer. I built a prompt-structuring tool anyway, using Claude Code — here's what actually went wrong 🤔 The problem I don't write code. I'm not an engineer, day to day — but I use AI chatbots constantly, and I kept running into the same annoying pattern. I'd type something lazy into ChatGPT or Claude — half a sentence, no context, whatever came to mind first — and get back a mediocre answer. Then, later, I'd realize: if I'd just written a slightly better prompt, I probably would've gotten a much better answer on the first try. Instead I'd burned a chunk of my monthly quota (sometimes on a paid plan) on something forgettable. I figured other people had to be doing the same thing. So I built something for it. 💡 What I built It's called Deep Prompt Studio . You paste in a rough, unpolished prompt — the kind you'd type without thinking too hard — and it hands back a detailed version that pulls in whichever pieces actually matter for that request: role, task, constraints, output format, and more. It's not tuned for one specific chatbot; it's meant to work well whether you're pasting the result into ChatGPT, Claude, Gemini, or something else. https://deep-prompt-studio.vercel.app 🛠 Tech stack Next.js (App Router, Turbopack) + TypeScript Tailwind CSS Anthropic Claude API for the actual prompt enhancement Stripe for payments Upstash Redis for storage Deployed on Vercel ⚙️ How it works Tone selector — Default, Professional, Casual & friendly, Concise, Direct Target-model optimization — Generic, ChatGPT, Claude, Gemini, Midjourney Snippets — save reusable context/tone/role info and toggle them on or off per enhance (free: up to 3, Pro: unlimited) Variable fill-in — template placeholders like {{product name}} you can reuse Refine mode — if your prompt is too vague, it asks a couple of follow-up questions before enhancing, instead of guessing Template gallery — writing, coding, business, learning, SEO, customer support Library — saved enhanced prompts (Pro) Free ti
AI 资讯
How We Built 非标准文本翻译与含义确认: A Context-Aware Book Translation Pipeline with Python and LLMs
Tackling idioms, cultural references, and ambiguous phrases in AI-powered book translation. At LectuLibre, we’ve been working on an AI-powered book translation service. One of the toughest challenges we ran into wasn’t the straightforward sentences — it was the non-standard text: idioms, metaphors, cultural references, and ambiguous phrases that machine translation consistently butchers. We needed a way to not only translate these correctly but also let users verify and edit the translations, because in literary works, getting them wrong breaks the entire reading experience. That’s how we built our 非标准文本翻译与含义确认 (non‑standard text translation and meaning confirmation) feature. It’s a pipeline that detects tricky sentences, proposes a contextual translation with a full meaning explanation, and gives users a final say. Here’s the engineering story, warts and all. The Problem Standard LLM translation does an impressive job on factual, literal text. But when a book says “it’s raining cats and dogs” it could be rendered as “raining animals” in the target language, which is either brilliant or absurd depending on context. Idioms often carry cultural weight that a simple word‑for‑word translation misplaces. Additionally, metaphors and ambiguous phrases can have multiple valid interpretations. For a translator, understanding the intent behind the phrase is half the work. We wanted a system that: Automatically identifies sentences containing non‑standard language. Generates a translation that preserves the original meaning rather than just the literal words. Provides a plain‑language explanation of what the phrase actually means (e.g., “This is an English idiom meaning it’s raining heavily”), so the user can judge the translation’s accuracy. Allows the user to confirm, edit, or retranslate those segments. A book can easily run to hundreds of thousands of words, so cost and speed were critical. We couldn’t just throw everything at a single high‑end LLM and call it a day. Our A
AI 资讯
I Built 31 Developer Tools Into a Single 133 KB HTML File — No Dependencies, No Backend
As a developer, I regularly find myself searching for small online utilities. Format some JSON. Decode a JWT. Test a regex. Generate a UUID. Convert a timestamp. Format an SQL query. Calculate a CIDR subnet. None of these tasks individually justify installing another application. But over time, I ended up with a collection of bookmarks to different websites, each solving one small problem. There was also another issue: privacy. Sometimes the data I'm working with isn't something I necessarily want to paste into an unknown third-party website. So I decided to build an alternative. The constraint: one HTML file I wanted the entire application to exist as a single file. No backend. No npm install. No CDN dependencies. No external API calls. No account. No telemetry. You download the HTML file, open it in a modern browser, and everything runs locally. The final file ended up at approximately 133 KB and contains 31 developer tools. What's inside? The tools are organized into six categories. Encode / Decode JSON Formatter & Validator Base64 Encode / Decode URL Encode / Decode HTML Escape / Unescape JWT Decoder Number Base Converter Generators UUID Generator Password Generator with entropy estimation Hash Generator Slug Generator Lorem Ipsum Generator Random Data Generator Converters Timestamp Converter CSV ↔ JSON JSON ↔ YAML CSS Unit Converter Case Converter Cron Expression Parser CSS Tools Color Picker & Converter Gradient Generator Box Shadow Generator Border Radius Generator CSS Filter Generator Text Tools Regex Tester Markdown Preview Text Diff Character Counter Text Sort & Dedupe String Inspector SQL Formatter Network Tools IPv4 Address and CIDR/Subnet Calculator Everything happens inside the browser. Making a single HTML file feel like an application I didn't want the result to feel like 31 unrelated forms dumped onto one page. So I added some application-level functionality. There's a Ctrl+K / Cmd+K command palette for quickly jumping between tools. The sidebar org
AI 资讯
Every AI-built site looks the same, so I built a skill that locks taste before any code is written
I build a lot of side projects with AI coding tools. Mostly Claude Code. A few months ago I noticed something that kept bugging me. Every site I shipped looked the same. Same indigo gradient. Same default font. Same rounded cards with the same soft shadow. Then I started noticing it on other people's projects too. Demo days, launch posts, screenshots on social media. The indigo gradient is everywhere. It is basically a uniform at this point. This is not really the AI's fault. When you do not give a model a design direction, it picks the average of the internet. And the average of the internet is a Tailwind starter template with an indigo gradient and Inter. The model is doing exactly what it was trained to do. The problem is that nobody told it what you actually want. So I built tastemaker. It is a skill for Claude Code, and it also works with Cursor, Windsurf, and Codex. The idea is simple: lock the design system before the AI writes a single line of UI. Full disclosure before we go further: I built this. I am a solo builder. It is free and open source under the MIT license. I am posting it here because I want honest feedback, not because I have anything to sell you. There is nothing to buy. Taste first, code second A skill is just a folder of instructions the AI reads before it starts working. tastemaker forces a design decision step at the beginning, with real constraints, instead of letting the model improvise the look as it goes. When you start a UI project with it installed, this is what gets locked before any code exists: A palette. 5 presets, each matched to a mood. Not random hex codes. Combinations that were picked to work together. Fonts. 24 curated Google Font pairings. A display font and a body font that actually belong on the same page. Real assets. Illustrator-grade illustrations, recolored to your palette. No gray placeholder boxes. No generic stock photo energy. A logo. A constructed geometric mark, plus a full favicon set, so the tab icon is not th
AI 资讯
We made our security auditor buyable by AI agents (x402, one serverless function)
Last night we made our Supabase security auditor buyable by AI agents. One HTTP request, a USDC payment attached to a header, and the product comes back in the response body. No checkout page, no account, no human. Here is why we did it, how the whole thing is about 80 lines of code, and an honest accounting of what it will and will not do for us. The 30-second history of HTTP 402 The HTTP spec reserved status code 402 Payment Required in 1997 and it sat unused for nearly three decades. In 2025 Coinbase published x402, an open protocol that finally gives it a job: a server answers a request with 402 plus machine-readable payment requirements, the client attaches a signed stablecoin payment to a header, retries, and gets the resource. Settlement happens on-chain (USDC on Base) in one round trip. Visa's Intelligent Commerce integrated it this spring. It is not a concept; it is running infrastructure. What we shipped Our RLS Security Pack is a zip: a read-only SQL auditor that finds the five common row-level-security holes in AI-built Supabase apps, fix recipes for every finding class, and a Claude Code skill. Humans buy it on Gumroad. Now an agent can buy it like this: # ask for the product curl -i https://ticassociation.com/api/agent/rls-pack # the server answers 402 with the exact terms: # {"x402Version":1,"accepts":[{"scheme":"exact","network":"base", # "asset":"...USDC...","payTo":"0x...","maxAmountRequired":"...", ...}]} # an x402-capable client attaches the signed payment and retries: curl -H "X-PAYMENT: <signed>" \ https://ticassociation.com/api/agent/rls-pack -o pack.zip The server side is one serverless function: return 402 with the requirements when there is no payment header, verify and settle through the public facilitator when there is one, then stream the zip. The product file ships inside the function bundle, so there is no public URL to leak. The whole thing took an evening, and most of that was reading the spec. Why a tiny company bothered Three hones
AI 资讯
I Got Tired of AI Quiz Tools Making Up Facts That Weren't In My Notes, So I Built One That Can't
Two nights before a chemistry final, I pasted my notes into an AI quiz generator to test myself. One question asked about a reaction I never studied. I got it wrong, looked it up afterward, and it wasn't in my notes at all. The tool had just made it up. I went looking for a better one and hit the same wall three more times with three different tools. Paste your notes, get a quiz, and somewhere in the output is a question built on a fact your source material never mentioned. Nobody flags it. You just find out when you're wrong about something you were sure you'd studied. The failure mode makes sense once you think about how these tools are built. Most of them prompt an LLM with something like "generate 10 quiz questions from this text" and print whatever comes back. The model is good at sounding right. It is not naturally good at staying inside the boundary of what you actually gave it, and a prompt that says "don't hallucinate" is a request, not a constraint. The model can ignore it and you'd never know from the output alone. So I built QuizPaste around a different idea: don't ask the model to be honest, check it. When it generates a question, it has to also point at the sentence in your source text the question came from. Before that question ever gets shown to you, the code tries to actually locate that sentence in your original text. If it can't find it (wrong wording, a made-up detail, or the line just isn't there), the question gets thrown out silently and never reaches you. You only ever see questions the tool can prove came from your own material. Open any question and you can see the exact line highlighted. Using it is the boring part, on purpose. Paste lecture notes or a block of text, or grab a YouTube video's transcript (open the video, three dots, "Show transcript," copy the panel text, paste it in). There's no scraping involved, so it doesn't break when YouTube changes something on their end. You get a practice quiz plus flashcards in about five seconds
AI 资讯
When Green Browser Tests Lie: Environment Drift, CI Noise, and Hidden Runtime Failures
A browser test can be green and still be wrong. It can pass because a mock returned an outdated response. It can fail because staging enabled a feature flag that no one documented. It can become flaky after a React upgrade even though the user-facing behavior looks unchanged. And when the same failure appears only in a minified build, the stack trace may be so unhelpful that the team blames the test before investigating the application. These problems look unrelated, but they usually share one root cause: the test is running against a different system than the one the team thinks it is testing . The difference may be configuration, data, rendering behavior, build output, infrastructure, or timing. Reliable browser testing therefore requires more than stable selectors. It requires evidence that the environment, application state, and execution path are what you expect. Feature flags create multiple versions of the same application Feature flags are useful because they let teams release functionality gradually. They are also one of the easiest ways to create staging-only failures. A test written against the default interface may encounter a completely different component tree when a flag is enabled. A button can move into a menu, a form can become a wizard, or an API request can be delayed until the user completes an additional step. The difficult part is that the URL may remain identical. From the test runner's perspective, it is visiting the same page. From the application's perspective, it is executing a different product variant. A useful starting point is this breakdown of why browser tests fail only in staging when feature flags change runtime UI state . For important workflows, record the active flag state with every run. Do not limit the log to a generic environment name such as staging . Capture the actual configuration that influenced the UI. A failed run should answer questions such as: Which flags were active? Which account or cohort received them? Did the
AI 资讯
How to Test AI-Powered Web Apps Without Treating the Model Like a Normal API
AI-powered web applications look familiar on the surface. They have text boxes, buttons, menus, loading indicators, and API calls. That makes it tempting to test them like any other web application: submit an input, wait for a response, and compare the output with an expected string. That approach breaks quickly. Model output is variable. Safety behavior depends on context. A response can be semantically correct but displayed in the wrong conversation. An agent can produce a convincing final message after calling the wrong tool. A prompt-injection defense can block obvious attacks while failing when malicious instructions arrive through a webpage, document, image, or previous message. Testing these applications requires two kinds of evidence at the same time: Deterministic product evidence: the UI, state, permissions, tool calls, and workflow behaved correctly. Probabilistic model evidence: the output stayed within an acceptable range across repeated and adversarial inputs. Prompt injection is a workflow problem Prompt injection testing is often reduced to pasting “ignore previous instructions” into a chat box. That is a useful smoke test, but it does not represent how browser-based agents encounter untrusted content. An agent may read instructions from: A webpage. A support ticket. A PDF. A hidden DOM node. An email. A retrieved knowledge-base entry. A tool response. A previous conversation turn. The guide on testing prompt injection defenses in AI-powered browser workflows provides a good foundation. The test should verify more than the final sentence. It should inspect whether the agent: Treated external content as data rather than authority. Attempted a prohibited tool call. Exposed secrets in an intermediate step. Navigated to an unapproved domain. Changed its goal after reading untrusted content. Requested confirmation before a sensitive action. Preserved the original user instruction. A safe final answer does not prove that the workflow was safe. The agent ma
AI 资讯
Polling, SSE, or WebSockets for Mobile Upload Status?
After the browser transfers a file, the server may still scan, transcode, extract metadata, or generate previews. The interface needs status updates, but the most fashionable real-time transport is not automatically the most reliable choice for an event guest on a mobile browser. Start with the update contract Define states and transitions before choosing transport: accepted -> queued -> processing -> ready accepted -> rejected processing -> processing_error Every status response should include a monotonically increasing version or timestamp. The client can ignore events older than the state it already knows. Polling is a strong baseline HTTP polling works through proxies, resumes naturally after a page wake, and is easy to cache and rate-limit. Use adaptive intervals: one second just after acceptance, then back off to several seconds when processing takes longer. const delay = Math . min ( 8000 , 1000 * 2 ** slowChecks ); Add jitter when many guests finish at the same time. Stop when the state is terminal, the page is gone, or a server-provided retry time says to wait longer. SSE fits one-way progress Server-Sent Events are attractive when the server only pushes status. The browser reconnects with a last-event ID, and the wire format is simple. But mobile networks and some intermediaries silently kill idle connections. Send occasional heartbeats and treat reconnection as normal. The reconnect handler must fetch current state because events may have been missed beyond the server replay window. Do not keep one SSE stream per file. Subscribe by guest session or album and filter authorized upload IDs on the server. WebSockets add more responsibility WebSockets make sense when the client also sends frequent commands over the same channel or when a host moderation console needs many rapid updates. For a guest waiting on two files, they add connection authentication, heartbeat, reconnect, replay, and load-balancer complexity without much user benefit. Never rely on the so
AI 资讯
Designing Upload Expiration as a Recoverable State
Signed upload sessions expire. Event contribution windows close. Storage reservations are reclaimed. These are normal lifecycle events, but many interfaces reduce all of them to “Upload failed.” A better protocol makes expiration explicit and recoverable where policy allows it. Distinguish three clocks An upload workflow usually has at least three deadlines: the event contribution window; the server-side upload intent expiry; the short-lived storage credential expiry. They should not share one timestamp. The event may accept contributions until midnight while a credential lasts five minutes and an intent can be renewed for an hour. Return the clocks in the session response with server time: { "serverNow" : "2026-07-17T18:00:00Z" , "eventClosesAt" : "2026-07-18T00:00:00Z" , "intentExpiresAt" : "2026-07-17T19:00:00Z" , "credentialExpiresAt" : "2026-07-17T18:05:00Z" } The client can display useful warnings without trusting its own clock for authorization. Model expiration by state A credential expiring during transfer is different from an intent expiring before completion. Use stable reasons: credential_expired -> request renewal intent_expired -> reconcile committed parts, then renew or restart event_closed -> stop new work, preserve local recovery guidance Do not automatically restart from byte zero. First ask the control plane which parts were committed and whether the original object key remains valid. Renew narrowly A renewal endpoint should accept the upload ID and prove continuity with the guest session. It rechecks event state, file policy, rate limits, and committed size. The response returns a new credential for the same object. Do not let the browser extend an intent indefinitely. Define a maximum session age and a bounded number of renewals. Long uploads may receive a larger initial policy based on file size and observed throughput. Handle the closing boundary fairly Decide what happens to an upload already transferring when the event window closes. Reasona
AI 资讯
Network Performance for Web Teams: DNS, TLS, HTTP, CDN, and Cache Rules
A PageSpeed Insights run flags a high Time to First Byte. The ticket lands on the theme backlog. Hosting gets upgraded. A CDN is added. The next lab run still shows a slow first byte on the same priority URL. In our experience the miss is often earlier in the path: DNS, TLS, HTTP version, connection reuse, edge routing, or cache policy. Theme and plugin work still matter, but they sit after the network and delivery stack has done its job. If first byte is already late, paint and interactivity inherit that delay. What follows walks that request in order for teams who need to reduce TTFB before another theme rewrite. We stay on the network and delivery layers. For WordPress cases where code on the stack beats a bigger hosting plan, see Why Your WordPress Site Is Slow (It Is Not Always Hosting) . For LCP levers once first byte is under control, see A Quick Way to Fix LCP: Four Changes That Cut Time to Paint . What TTFB includes when you measure first byte in lab tools Time to First Byte (TTFB) measures how long the browser waits from the start of the navigation request until the first byte of the response arrives. In PageSpeed Insights and Lighthouse, it appears as a diagnostic timing. In WebPageTest and similar waterfall tools, you can split the same wait into DNS, TCP connect, TLS, and waiting (server or edge processing). That split is what makes network work actionable for delivery teams. TTFB is not a Core Web Vital , but it feeds Largest Contentful Paint and overall load feel. A page that spends 800 ms waiting for first byte has already used a large share of a mobile LCP budget before the hero image or heading can paint. Field data from Chrome UX Report may show Time to First Byte as a supporting metric. Lab tools remain the fastest way to prove a DNS or CDN change after a release, because you control the URL, location, and cache state of the run. When you read TTFB in a report, ask which hop dominated. Resolver delay looks different from a cold TLS handshake. A c
AI 资讯
Memory-Safe Media Preflight in Mobile Browsers
Client-side media preflight can improve an upload experience, but it can also crash the page before the network request begins. A twelve-megapixel JPEG may be only four megabytes on disk and tens of megabytes after decoding. Creating several full-size canvases at once is enough to exhaust memory on older phones. Preflight is policy, not editing Decide what the browser must prove before transfer. Useful checks include file count, compressed byte size, declared type, readable dimensions, and a conservative duration limit for video. Avoid mandatory re-encoding unless the product truly needs it. Every transformation adds CPU time, memory pressure, battery use, and another failure mode. Process one file at a time A file picker may return twenty items. Do not decode all of them to build previews. Maintain a queue with one active decode on constrained devices and at most two on stronger ones. for ( const file of files ) { const result = await inspect ( file ); renderResult ( result ); await yieldToMainThread (); } The UI can list filenames immediately while dimensions and thumbnails arrive progressively. Prefer metadata over full pixels Use createImageBitmap with resize hints when supported. It can decode away from the main rendering path and avoid a full-resolution canvas for a small preview. const bitmap = await createImageBitmap ( file , { resizeWidth : 640 , resizeQuality : ' medium ' }); Always close bitmaps after drawing. Revoke object URLs when the component unmounts. Small leaks become large when guests select and remove files repeatedly. Handle orientation and color carefully Modern browsers generally honor EXIF orientation when decoding, but behavior differs across APIs and older engines. Test portrait photographs from real iOS and Android devices. Do not strip metadata silently if the original is supposed to remain untouched; upload the source file and treat the preview as disposable UI. Color differences between the preview and exported original are usually les
AI 资讯
Resumable Browser Uploads for Crowded Event Networks
Event uploads fail differently from normal office uploads. A wedding guest may move between venue Wi-Fi and mobile data, lock the phone while a video is transferring, or close the browser as soon as the progress bar reaches 100%. Hundreds of devices can share one access point, and users rarely wait around to diagnose an error. The usual POST request plus optimistic success toast is not enough. A reliable browser flow needs a small protocol that distinguishes local preparation, network transfer, server acceptance, media processing, and final availability. This article describes a platform-neutral design for that protocol. The five states users actually experience Model each file as a durable state machine: selected -> preparing -> transferring -> accepted -> processing -> ready Add terminal or recoverable branches: preparing -> rejected_local transferring -> paused | retryable_error | expired accepted -> processing_error processing -> ready | processing_error The key distinction is between transferring and accepted . The browser may have sent every byte while the server has not yet committed the upload. Showing “done” at that boundary creates the most frustrating failure: the guest deletes the original, but the organizer never receives it. Give every file a client-generated identity Create an upload ID before the first network request. A UUID is sufficient when combined with the event identifier: const uploadId = crypto . randomUUID (); const uploadIntent = { uploadId , eventId , name : file . name , size : file . size , type : file . type , lastModified : file . lastModified , }; Send that identity when creating the server-side upload session. If the browser retries after a timeout, the server returns the existing session instead of creating a duplicate. This is idempotency at the workflow level. A guest can tap “retry” without having to understand whether the first request reached the server. Separate the control plane from file bytes Use a small JSON API for sessi
AI 资讯
Model experiments became an architectural stress test
I've been tuning Codenames AI , a small web game where an LLM plays Codenames with you. Clue generation is tightly constrained: one word, a count, optional intended targets, JSON on the wire, then deterministic validation before anything reaches the board. As the project started attracting regular players, I wanted to improve the gameplay experience without blowing out costs. Moving one model generation from gpt-4o-mini to gpt-5-mini was my first instinct. The default reasoning setting made responses an order of magnitude slower for this workload. Minimal reasoning looked like the obvious compromise: newer model, responsive gameplay. I expected to compare clue quality, latency, and cost while the surrounding prompt, validator, and consumer contracts stayed put. That last part was wrong. The experiment stopped behaving like an A/B test What showed up was structural, and it showed up in places that had been stable for months. Validation failures started rising. Retries started rising. Entire candidate batches started failing before the game ever saw a clue. The sharpest signal came from a clue-selection path that had run untouched for months, and it hard-failed for the first time. They weren't latency regressions so much as architectural ones. It is easy to read that as "minimal reasoning made the model worse." More often, the failures were exposing gaps in contracts that had looked fine under the previous model. What each failure actually invalidated Eventually every failure traced back to one of three layers: Prompt contracts ask for exactly count targets and, in batch mode, several distinct candidates. Deterministic validators reject target/count mismatches and filter invalid candidates before anything downstream runs. Downstream consumers only see survivors. Empty batches retry with rejection feedback, then fall back if needed. Those layers share one job: enforce the same invariants. The failures below cut across all three rather than mapping one to one. Side comm
AI 资讯
Amazon fixing bug that billed some AWS customers billions of dollars
Some Amazon customers logged on Friday to a surprise bill estimate claiming that they owed the tech and cloud giant billions in fees.
AI 资讯
Cursor Keeps Skipping Rate Limits on Login Routes (CWE-307)
TL;DR I checked 50 AI-generated login endpoints. Zero had rate limiting. Attackers can brute-force credentials at full speed against these routes. Adding a rate limiter takes four lines and one npm install. I asked Cursor to build a login route for a side project last month. Email, password, JWT back on success. It worked first try, passed my manual tests, and I moved on to the next feature. Three weeks later I ran a load test against it out of curiosity and hit the endpoint two thousand times in under a minute. Not one request got throttled. That's when I started pulling apart every AI-generated auth route I could find, mine and other people's open source side projects, and the pattern held everywhere I looked. The models write correct authentication logic and completely skip rate limiting, because rate limiting isn't part of "does this login work," it's part of "does this login survive contact with an attacker." The vulnerable code (CWE-307) Here's roughly what Cursor and Claude Code hand you when you ask for a login route: // ❌ No rate limiting - CWE-307: Improper Restriction of Excessive Authentication Attempts app . post ( ' /api/login ' , async ( req , res ) => { const { email , password } = req . body ; const user = await User . findOne ({ email }); if ( ! user || ! ( await bcrypt . compare ( password , user . passwordHash ))) { return res . status ( 401 ). json ({ error : ' Invalid credentials ' }); } const token = jwt . sign ({ id : user . id }, process . env . JWT_SECRET , { expiresIn : ' 1h ' }); res . json ({ token }); }); Password hashing is fine. JWT signing is fine. But nothing stops a script from hitting this route as fast as the network allows. No lockout, no delay, no cap on attempts per IP or per account. A credential-stuffing list with ten thousand leaked passwords runs against this endpoint in seconds. Why this keeps happening Rate limiting lives outside the function the model was asked to write. The prompt is "build a login endpoint," and it re
AI 资讯
How to Scrape Airbnb Listings and Prices in 2026 (No Code Required)
Heads-up: this post references a tool I built. It's a genuinely useful walkthrough either way — the technique applies to any Airbnb scraping project. If you've ever tried to scrape Airbnb, you already know the two walls you hit: the pages are rendered by JavaScript, and Airbnb aggressively blocks datacenter IPs. Below is the reliable way to get clean Airbnb data in 2026 — listing prices, ratings, coordinates, and discounts — without running a headless browser or babysitting proxies. The key insight: Airbnb ships its data in the HTML You don't need to render the page. Every Airbnb search response embeds the full result set as JSON inside a <script id="data-deferred-state-0"> tag. Parse that and you get structured data straight away — no DOM scraping, no selectors that break on the next redesign. The path to the results is: niobeClientData[*][1].data.presentation.staysSearch.results ├── searchResults[] // ~18 listings per page └── paginationInfo.pageCursors[] // all page cursors, upfront Each listing carries a base64-encoded ID in demandStayListing.id (decode it, take the segment after the last colon, and you have the numeric listing ID for airbnb.com/rooms/<id> ), a price line with discounts, avgRatingLocalized ("4.95 (123)"), and GPS coordinates. The two gotchas Datacenter IPs get blocked. You need residential proxies. If a response comes back without the data-deferred-state marker, you've been served a bot check — rotate to a fresh IP and retry. ~270 result cap per search. Airbnb won't paginate past ~15 pages. To cover a whole market, split into narrower searches (by price band or neighborhood) and dedupe by listing ID. The no-code way If you'd rather not maintain proxy pools and parsers, I published an Airbnb Scraper on Apify that does exactly the above. Paste a location or a full Airbnb search URL (every filter is honored), and get flat JSON/CSV back. curl -X POST "https://api.apify.com/v2/acts/ethanteague~airbnb-scraper/run-sync-get-dataset-items?token=YOUR_TOKE