This is a viewer only at the moment see the article on how this works.
To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk
This is a preview from the server running through my markdig pipeline
Monday, 01 June 2026
La rilevazione del bot non dovrebbe fermarsi a permettere/block. Questo post mostra come il risultato della classificazione di StyloBotM SK2 diventi la logica dell'applicazione nel TypeScript : middleware del server per Express e FastifyMSC4 helpers dei template per le barre di comandosMST5 NunjucksMSL6 e EJSMLS7 e componenti web del browserMSSK8 così che l'interfaccia utente possa modellare l'esperienza invece di infilare la frizione dopo il fattoMSS9
L'informazione figura nella parte dispositiva.
@stylobot/coree@stylobot/nodeI pacchetti npm verranno pubblicati tra poco. I frammenti sotto descrivono la superficie che esponeranno.
StyloBot Release Series
- Comportamento, Non identità: perché StyloBot modella i clienti comportamentalmente
- Comportamento-Aware ASP.NET UI: il server- la superficie restituita per le applicazioni .NET
- Trovare e riparare la crescita senza limiti nei servizi NET Long-Running .: la disciplina di affidabilità che mantiene il motore noioso nella produzione.
- Comportamento-Conoscere l'interfaccia grafica del tipoScript: questo articolo
- L'architettura della Sidecar: come il motore di rilevazione si collega a stack non -.NET
- Imparare a diventare più veloce: il sistema di apprendimento adattativo, quattroM SK2 memoria a livello di livello+, e la cassa del verdetto
- Provare a fare ciò che non si ferma.: la disciplina di verificazioneM SK1 un file BDF guida la regressione , carico, e calibrazione
- StyloExtract - un convertitore locale di HTML per Markdown: l'HTML→Layere Markdown che si combina con il rilevatore , il walkeder bug lucidVIEW catturatoM SK3 e la catena di cibo per cani che lo rende onesto
Il motore di rilevamento del StyloBot' è scritto in ASP.NET CoreM SK2 un sistema ad alta performance - con eccellenti primitivi asincentiMSC4 sotto-- millisecondi di latenza del percorso MNK6 e 20 anni di pedigree produttivo dietro di essoMRK8 Il TypeScript SDK è la superficie che porta il motoreMST9 la fuoriuscita in NodeMst10js applicazioni e browser senza bisogno di sapere nulla su ciò che è successo sotto l'aspetto SST11 (La latenza di percorso \MST13\ viene dal sistema di apprendimento adattabile coperto Imparare a diventare più veloce: una volta che l'impronta digitale è stata vista con abbastanza sicurezza, il cache del verdetto supera la catena di rilevamento completa e risponde in microsecondi .)
La maggior parte della rilevazione dei robot disponibile nell'ecosistema di TypeScript ti dà una delle due cose: un'impronta digitale del browser che ti dice se il cliente Sembra automatizzato, o un regex sull'User-String Agent che cattura solo i bot che si annuncianoM SK2
Nessuno dei due è utile nella stratagemma dell'applicazione.
Si trattava di un sistema che si basava su una serie di fattori, come il tempo, l'energia e la capacità. funziona nel browser e non ha una visuale dei titoli di richiesta, impronte digitali TLSM SK1 comportamento della sessione, o reputazione IP . Un Chromium senza testa e un Googlebot sembrano identici a luiMSC4 Pacchetti di compatibilità Pure UA Mスク5is-bot, isbot) cattura solo quello che si opta per essere catturatoM SK1 Network-Producti di strata (Cloudflare Bot Management+, DataDome+) blocca al limite ma non può personalizzarlo nella strata dell'applicazione+M SK6 Avete imparato che una richiesta è stata bloccata=, mai che una domanda che ha raggiunto la vostra app abbia avuto una probabilità di bot e una fascia di rischio medio=M SK9 così la vostra pagina di pagamento avrebbe potuto mostrare un passo di frizione e le vostre analisi l'avrebbero potuto escludere+MSC10 tutto senza un codice d'errore*.
Quello che StyloBot dà alla vostra applicazione TypeScript è un verdetto: un risultato digitato con un punteggio di probabilità continua del bot, una classifica M SK2AiBot, Scraper, GoodBot, MaliciousBot, ...), una fascia di rischioM SK2 un'azione consigliata, e un punteggio per la minacciaMSC4 Quello che fate con quel giudizio dipende da voi.
Questo articolo passa attraverso un esempio di storefront e mostra come quel giudizio diventi il comportamento dell'applicazione a ogni strato: middleware del server, helpers dei templateM SK2 e componenti del browserMSC3
Prima di ogni altra cosa, questo è ciò che arriva:
// @stylobot/core
interface Verdict {
isBot: boolean;
botProbability: number; // 0.0–1.0 - not binary, a continuous score
confidence: number; // certainty in that score
botType: BotType | null; // 'AiBot' | 'Scraper' | 'GoodBot' | 'MaliciousBot' | ...
botName: string | null; // 'GPTBot', 'Googlebot', 'curl/8.9.1', ...
riskBand: RiskBand; // 'VeryLow' | 'Low' | 'Elevated' | 'Medium' | 'High' | 'VeryHigh'
recommendedAction: RecommendedAction; // 'Allow' | 'Throttle' | 'Challenge' | 'Block'
threatScore: number; // elevated when CVE probes or credential stuffing detected
threatBand: ThreatBand; // 'None' | 'Low' | 'Elevated' | 'High' | 'Critical'
}
Un punto di fine del checkout può gonfiare. Medium Rischio invece di bloccarlo. Un API può escludere AiBot traffic from rate-limit quotas without counting it against real users Elevated Rischio senza toccare l'esperienza per Low Visitori a rischio. Niente di questo è possibile se il risultato della rilevazione è un boolean alla strata di rete.
Bande di rischio in ordine: VeryLow, Low, Elevated, Medium, High, VeryHigh, Verified.
npm install @stylobot/core @stylobot/node
# only needed for grpc mode
npm install @grpc/grpc-js @grpc/proto-loader
@stylobot/core Ha zero dipendenze del tempo di esecuzione. contiene le definizioni di tipo, il cliente RESTM SK2 il parsatore di header , e MSC4 opzionealmenteMST5 il client gRPCMSV6 Funziona in NodeMSL7 DenoMsl8 e Bun senza modificazioniMSR9
@stylobot/node fornisce Express middleware, un plugin Fastify, utilità per l'aiuto di schemiM SK2 e l'injectore del verdetto . dipende da @stylobot/core e niente altro al runtime.
Il middleware ha tre modi. Tutti i tre producono lo stesso. req.stylobot forma. Quella che usate dipende da dove funziona la vostra detezione dell'infrastruttura
graph LR
classDef input fill:none,stroke:#3b82f6,stroke-width:2px
classDef good fill:none,stroke:#22c55e,stroke-width:2px
classDef async fill:none,stroke:#a855f7,stroke-width:2px
subgraph H ["headers mode - zero added latency"]
GW[Gateway / Caddy / YARP]:::input -->|"X-StyloBot-* headers"| A[Express / Fastify]:::good
end
subgraph G ["grpc mode - HTTP/2, no JSON overhead"]
B[Express / Fastify]:::good -->|"gRPC Detect RPC"| SC[StyloBot Sidecar :5090]:::async
end
subgraph R ["api mode - REST, full signal set"]
C[Express / Fastify]:::good -->|"POST /api/v1/detect"| SC2[StyloBot Sidecar :5091]:::async
end
headers Mode: la detezione è andata in arrivo alla porta ; il middleware legge i titoli inseriti senza chiamare la rete МSK2 Questo è il modello di produzione quando una porta Caddy o YARP si trova davanti a noi
grpc Mode: il middleware chiama la sidecar direttamente su HTTP/2. La latenza più bassaM SK2 non c'è JSON overhead @grpc/grpc-js. L'interfaccia del gRPC e i dettagli di deployment della sidecar sono in articolo sull'architettura della carrozza laterale.
api ModeLe chiamate : POST /api/v1/detect su HTTP/1.1. Ritorna anche reasons (perM SK1contributioni dei rilevatori) e signals (lo stato completo della lavagna) che gli altri modi omitanoM SK2
Il middleware continua a fallire quando si apre. Se l'autostrana è inaccessibile o non funziona. req.stylobot è stabilito ad un verdetto vuoto permisivo e la richiesta continua.
Express:
import express from 'express';
import { styloBotMiddleware } from '@stylobot/node';
const app = express();
app.use(styloBotMiddleware({ mode: 'headers' }));
// or:
app.use(styloBotMiddleware({ mode: 'grpc', endpoint: 'localhost:5090', timeout: 100 }));
Fastify:
import Fastify from 'fastify';
import { styloBotPlugin } from '@stylobot/node';
const fastify = Fastify();
await fastify.register(styloBotPlugin, { mode: 'headers' });
Add a type declaration if you want typed access on Fastify requests:
// types.d.ts
import type { StyloBotResult } from '@stylobot/node';
declare module 'fastify' {
interface FastifyRequest { stylobot: StyloBotResult; }
}
Lo stesso campione di magazzino di Article ASP.NET, la pagina del prodottoM SK1 il pagamento, l'inscrittaMST3 il newsletterM ST4 ma in TypeScriptMst5 Il risultato della rilevazione è lo stessoMSST6 quello che cambia è come la superficie lo esponeMSS7
I tiratori di prezzi iniziano qui. Vogliono i nomi dei prodotti, i prezziM SK2 e i livelli di quotaMSC3 Vogliate il catalogo indicebile da motori di ricerca ed utile per gli umani senza dare i segnali commerciali a una raccolta sistematica .
Scenario: un scafo di prezzo colpisce /products/:id. Non vede un codice di sconto, nessun aggiungimentoM SK2a- bottone di carto , e nessun segnale d'acquisto che valga la pena di agire suMSC5
L'operatore del percorso:
app.get('/products/:id', (req, res) => {
const { verdict } = req.stylobot;
const product = getProduct(req.params.id);
res.render('product', {
product,
sbVerdict: verdict,
showDiscount: verdict.riskBand === 'VeryLow' || verdict.riskBand === 'Low',
showBuyButton: !verdict.isBot,
showCartWarning: verdict.recommendedAction === 'Challenge',
isSearchBot: verdict.botType === 'SearchEngine' || verdict.botType === 'VerifiedBot',
});
});
La template (Handlebars):
{{! verified crawlers get structured metadata instead of commercial UI }}
{{#if isSearchBot}}
<meta name="description" content="{{product.name}} -{{product.category}}." />
<p>{{product.description}}</p>
{{else}}
{{! discount only for low-risk human visitors }}
{{#if showDiscount}}
<div class="alert alert-success">
Member price: use code <strong>LOYAL10</strong> for 10% off.
</div>
{{/if}}
{{! add-to-cart only for non-bot traffic }}
{{#if showBuyButton}}
<form method="post" action="/cart/add">
<input type="hidden" name="productId" value="{{product.id}}" />
{{#if showCartWarning}}
<p class="text-warning">Additional verification may be required at checkout.</p>
{{/if}}
<button type="submit" class="btn btn-primary">Add to Cart</button>
</form>
{{else}}
<p class="text-muted">Purchase available to human visitors.</p>
{{/if}}
{{/if}}
Tre modelli in uso qui. Differenzazione Crawler: SearchEngine e VerifiedBot ottenere metadati strutturati senza segnali commerciali, che è quello di cui hanno veramente bisogno. Targeting discountM SK2 un codice di lealtà mostrato solo a basso livelloMSC3 il traffico a rischio è meno probabile di finire su un forum per i voucher . Frizione progressivaMST5 Challenge è un avvertimento, non è un blocco. Le sessioni sospette possono ancora comprarsi
Automatizzazione della frode, testatori di carte, voucher bruteM SK2 forscheriMSC3 e retreazioni scritte tutte convergono al checkout . L'obiettivo è la difesa in profondità senza CAPTCHAMST5la prima esperienza per tuttiMst6
Scenario: un voucher-test bot colpisce /checkout. Vede un mortoM SK1 messaggio finale, invia una vasca da miele - modulo completatoMSC4 e riceve una conferma silenziosa senza incoraggiamento a riprovare.
flowchart TD
classDef input fill:none,stroke:#3b82f6,stroke-width:2px
classDef good fill:none,stroke:#22c55e,stroke-width:2px
classDef problem fill:none,stroke:#ef4444,stroke-width:2px
A([Visitor reaches /checkout]):::input --> B{bot?}
B -->|yes| C[Dead-end message - no form]:::problem
B -->|no| D{risk band}
D -->|Low| E[Express checkout CTA]:::good
D -->|Elevated| F[Standard checkout CTA]:::good
D -->|High+| G[Phone number - no online path]:::problem
E & F --> H[POST /checkout/order]
H --> I{honeypot triggered?}
I -->|yes| J[Silent fake confirmation]:::problem
I -->|no| K[Process real order]:::good
La strada:
app.get('/checkout', (req, res) => {
const { verdict } = req.stylobot;
res.render('checkout', {
sbVerdict: verdict,
showForm: !verdict.isBot,
showExpress: verdict.riskBand === 'VeryLow' || verdict.riskBand === 'Low',
showStandard: ['VeryLow','Low','Elevated'].includes(verdict.riskBand),
showPhone: ['High','VeryHigh'].includes(verdict.riskBand),
});
});
app.post('/checkout/order', (req, res) => {
// honeypot fields are invisible to humans; bots fill everything
if (req.body.hp_name || req.body.hp_email) {
return res.redirect('/checkout/confirmed'); // silent fake - no retry incentive
}
return processRealOrder(req, res);
});
La template:
{{#if showForm}}
<form method="post" action="/checkout/order">
{{! invisible honeypot trap - humans leave blank, bots fill everything }}
<div style="position:absolute;left:-9999px;opacity:0" aria-hidden="true">
<input type="text" name="hp_name" tabindex="-1" autocomplete="off" />
<input type="email" name="hp_email" tabindex="-1" autocomplete="off" />
</div>
{{#if showExpress}}
<button type="submit" name="express" value="true" class="btn btn-success btn-lg">
Express Checkout
</button>
{{/if}}
{{#if showStandard}}
<button type="submit" class="btn btn-primary">Proceed to Payment</button>
{{/if}}
{{#if showPhone}}
<p>Please call us to complete your order: <strong>0800 123 456</strong></p>
{{/if}}
</form>
{{else}}
<p class="text-muted">Checkout is available to human visitors only.</p>
{{/if}}
La discardazione del vaso di miele è la tecnica chiave qui. Il feedback sull'errore insegna agli attacchi a ripetere; una falsa conferma silenziosa spreca il loro tempo , e la pagina di conferma sembra identica se l'ordine era reale o discardatoM SK3 Il checkout Express come beneficio di fiducia MSC4 non è un predefinitoMST5 significa che solo le sessioni che lo hanno guadagnato ottengono il percorso più breveM ST6 Nella produzioneMst7 il fattore del vaso <div> un wrapper in una maniglia condivisa ({{> honeypot}}) invece di ripetere il blocco dello stile inline su ogni forma protetta.
L'ingresso è affidabile-territorio di affichageM SK1 Il commercio-l'affetto è diverso dal checkout : un falso positivo al checkout può perdere una venditaMSC4 un affidabile mancanteMST5 l'attacco di affari perde un accountMst6 L'applicazione può essere più rigorosaMSSK7
Scenario: credenzale- battito dello script /login. Vede un messaggio di dissuasione , riempie il vaso con il miele, e viene spinto verso /login/denied prima di qualsiasi authenticazione funziona.
app.get('/login', (req, res) => {
const { verdict } = req.stylobot;
res.render('login', {
sbVerdict: verdict,
showWarning: verdict.isBot,
showRisk: ['High','VeryHigh'].includes(verdict.riskBand),
});
});
app.post('/login', async (req, res) => {
if (req.body.hp_user || req.body.hp_pass) {
return res.redirect('/login/denied');
}
if (req.stylobot.verdict.isBot) {
return res.redirect('/login/denied');
}
return authenticate(req, res);
});
{{#if showRisk}}
<div class="alert alert-danger">
High-risk signals detected. Login attempts are logged.
</div>
{{/if}}
{{#if showWarning}}
<div class="alert alert-warning">
Automated login attempts are detected and blocked.
</div>
{{/if}}
<form method="post" action="/login">
<div style="position:absolute;left:-9999px;opacity:0" aria-hidden="true">
<input type="text" name="hp_user" tabindex="-1" autocomplete="off" />
<input type="password" name="hp_pass" tabindex="-1" autocomplete="off" />
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" id="email" name="email" autocomplete="email" />
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" id="password" name="password" autocomplete="current-password" />
</div>
<button type="submit" class="btn btn-primary">Sign In</button>
</form>
Il bot vede il contenitore prima di presentarlo. Se lo presenta comunqueM SK1 il vaso d'almonde lo cattura. Se in qualche modo evita il vaso di almonde , verdict.isBot è il server finale-controllo laterale prima che una logica di autenticazione funzioni. Tre stratiM SK2 tutti piccoli .
I crawler artificiali sono un problema diverso. Non stanno cercando di brutalizzare- forzare le account o i prezzi delle raccolteM SK2 stanno ingaggiando contenuti per la formazione dei modelli . Sono spesso onesti riguardo all'identitàMSC4 il che significa che la risposta giusta è commerciale piuttosto che avversariaMST5
scenario: GPTBot colpisce /newsletter. Vede un messaggio di licenzione dei dati invece che un'affidazione di sottoscrizione. La sua ricevuta è discesa silenziosamenteM SK2
app.get('/newsletter', (req, res) => {
const { verdict } = req.stylobot;
res.render('newsletter', {
sbVerdict: verdict,
isHuman: !verdict.isBot,
isAiBot: verdict.botType === 'AiBot',
isOtherBot: verdict.isBot && verdict.botType !== 'AiBot',
});
});
app.post('/newsletter/subscribe', (req, res) => {
if (req.body.hp_email2 || req.stylobot.verdict.isBot) {
return res.redirect('/newsletter/thanks'); // silent discard
}
mailingList.subscribe(req.body.email);
return res.redirect('/newsletter/thanks');
});
{{#if isHuman}}
<p>Get exclusive deals delivered to your inbox. Unsubscribe any time.</p>
{{/if}}
{{#if isAiBot}}
<div class="alert alert-info">
This subscription endpoint is for human readers.
For data licensing enquiries, <a href="/contact">contact us directly</a>.
</div>
{{/if}}
{{#if isOtherBot}}
<div class="alert alert-warning">
Automated subscription attempts are discarded.
</div>
{{/if}}
<form method="post" action="/newsletter/subscribe">
<div style="position:absolute;left:-9999px;opacity:0" aria-hidden="true">
<input type="email" name="hp_email2" tabindex="-1" autocomplete="off" />
</div>
<div class="form-group">
<input type="email" name="email" placeholder="[email protected]" autocomplete="email" />
</div>
<button type="submit" class="btn btn-success">Subscribe</button>
</form>
AiBot Non è solo un'altra etichetta ostile.
sbVerdictInjector va avanti dopo il middleware di rilevazione e mette il verdetto. res.locals:
import { sbVerdictInjector } from '@stylobot/node';
app.use(styloBotMiddleware({ mode: 'headers' }));
app.use(sbVerdictInjector({ mode: 'gateway' }));
// or for direct sidecar calls (REST port, not the gRPC port):
app.use(sbVerdictInjector({ mode: 'sidecar', endpoint: 'http://localhost:5091' }));
res.locals.sbVerdict è disponibile in ogni modello. res.locals.sbVerdictScript è un'inline. <script> tag che stabilisce window.__sb per i componenti del browser.
Definire RISK_ORDER una volta nella scala di moduli ( i Nunjucks e gli assistenti EJS sotto usano la stessa mappa):
import type { Verdict, RiskBand } from '@stylobot/core';
const RISK_ORDER: Record<string, number> = {
Unknown: 0, VeryLow: 1, Low: 2, Elevated: 3, Medium: 4, High: 5, VeryHigh: 6, Verified: 7,
};
// register on your Handlebars engine instance
hbs.engine({
helpers: {
// {{#sbGate sbVerdict "Low"}}...{{else}}...{{/sbGate}}
sbGate(verdict: Verdict | null, maxRisk: string, options: any) {
if (!verdict) return options.fn(this);
return RISK_ORDER[verdict.riskBand] <= RISK_ORDER[maxRisk]
? options.fn(this)
: options.inverse(this);
},
// {{#sbIsBot sbVerdict}}...{{else}}...{{/sbIsBot}}
sbIsBot(verdict: Verdict | null, options: any) {
return verdict?.isBot ? options.fn(this) : options.inverse(this);
},
// {{#sbBotType sbVerdict "AiBot"}}...{{/sbBotType}}
sbBotType(verdict: Verdict | null, type: string, options: any) {
return verdict?.botType === type ? options.fn(this) : options.inverse(this);
},
// {{#sbMinRisk sbVerdict "High"}}...{{/sbMinRisk}}
sbMinRisk(verdict: Verdict | null, minRisk: string, options: any) {
if (!verdict) return options.inverse(this);
return RISK_ORDER[verdict.riskBand] >= RISK_ORDER[minRisk]
? options.fn(this)
: options.inverse(this);
},
},
});
Nelle schemi:
{{#sbGate sbVerdict "Low"}}
<a href="/checkout/express" class="btn btn-success">Express Checkout</a>
{{else}}
<a href="/checkout" class="btn btn-secondary">Checkout</a>
{{/sbGate}}
{{#sbBotType sbVerdict "AiBot"}}
<div class="alert alert-info">AI crawler detected. Data licensing info above.</div>
{{/sbBotType}}
{{#sbMinRisk sbVerdict "High"}}
<div class="alert alert-danger">High-risk session. Some features restricted.</div>
{{/sbMinRisk}}
import nunjucks from 'nunjucks';
// RISK_ORDER - same map defined in the Handlebars section above
class SbGateExtension {
tags = ['sbgate'];
parse(parser: any, nodes: any, lexer: any) {
const tok = parser.nextToken();
const args = parser.parseSignature(null, true);
parser.advanceAfterBlockEnd(tok.value);
const body = parser.parseUntilBlocks('else', 'endsbgate');
let elseBody = null;
if (parser.skipSymbol('else')) {
parser.skip(lexer.TOKEN_BLOCK_END);
elseBody = parser.parseUntilBlocks('endsbgate');
}
parser.advanceAfterBlockEnd();
return new nodes.CallExtension(this, 'run', args, [body, elseBody]);
}
run(context: any, maxRisk: string, body: any, elseBody: any) {
const v = context.ctx.sbVerdict;
const fits = !v || RISK_ORDER[v.riskBand] <= RISK_ORDER[maxRisk];
return fits ? body() : (elseBody?.() ?? '');
}
}
env.addExtension('SbGateExtension', new SbGateExtension());
{% sbgate "Low" %}
<a href="/checkout/express">Express checkout</a>
{% else %}
<a href="/checkout">Checkout</a>
{% endsbgate %}
EJS non ha degli aiuti a blocchi, ma le funzioni locali coprono la maggior parte dei casi in modo pulito:
// RISK_ORDER - same map defined in the Handlebars section above
app.use((req, res, next) => {
const v = res.locals.sbVerdict ?? null;
res.locals.sbBelowRisk = (max: string) =>
!v || RISK_ORDER[v.riskBand] <= RISK_ORDER[max];
res.locals.sbAboveRisk = (min: string) =>
v && RISK_ORDER[v.riskBand] >= RISK_ORDER[min];
res.locals.sbIsBot = () => v?.isBot ?? false;
res.locals.sbBotIs = (type: string) => v?.botType === type;
next();
});
<% if (sbBelowRisk('Low')) { %>
<a href="/checkout/express" class="btn btn-success">Express Checkout</a>
<% } else { %>
<a href="/checkout" class="btn btn-secondary">Checkout</a>
<% } %>
<% if (sbBotIs('AiBot')) { %>
<div class="alert alert-info">AI crawler. Data licensing enquiries via /contact.</div>
<% } %>
Aggiungere {{{sbVerdictScript}}} alla vostra testa di layout. Rende come:
<script>window.__sb = {"isBot":false,"botProbability":0.12,"riskBand":"Low","recommendedAction":"Allow",...}</script>
Poi caricate il pacchetto di elementi:
<head>
{{{sbVerdictScript}}}
<script type="module" src="/js/sb-elements.js"></script>
</head>
<sb-gate>: mostrare o nascondere il contenuto secondo la fascia di rischio<!-- only shown when riskBand <= 'low' -->
<sb-gate max-risk="low">
<a href="/checkout/express" class="btn btn-success">Express Checkout</a>
</sb-gate>
<!-- only shown when riskBand >= 'elevated' -->
<sb-gate min-risk="elevated">
<div class="alert alert-warning">Unusual activity detected on your session.</div>
</sb-gate>
<sb-adapt>: scegliere il primo caso corrispondente<sb-adapt>
<sb-case max-risk="low">
Standard checkout - enter your card details below.
</sb-case>
<sb-case max-risk="medium">
Additional verification is required before we can process your order.
</sb-case>
<sb-case>
Automated checkout access is not permitted.
</sb-case>
</sb-adapt>
<sb-adapt> Prende il primo. <sb-case> I quali max-risk Si adatta e nasconde il resto. Il finale <sb-case> Non c'è. max-risk è il taglio-toccoM SK1 Entrambi <sb-gate> e <sb-adapt> Ascoltate. sb:verdict evento e ri-evalutare se il verdetto cambia dopo la prima pitturaM SK1
<sb-widget>: server-fragmenti liquidi consegnati<sb-gate> nasconde il cliente del contenuto-lato. Se avete bisogno di un bot per ricevere un diverso marchoM SK2 non un marcho nascosto , dovete rendere il frammento sul server con il contesto di rilevazione disponibile alla templateMSC4
<sb-widget> legge il foglio Liquido da un'inline. <template> element, batchi tutte le richieste di widget sulla pagina in una singola ronda -trip, e si sostituisce con il HTML riferitoM SK3
<sb-widget data-sb-widget="checkout-cta">
<template>
{% if recommendedAction == 'Block' %}
<p class="text-danger">Automated checkout is blocked.</p>
{% elsif botType == 'AiBot' %}
<p>AI crawlers cannot complete purchases. <a href="/contact">Data licensing enquiries</a>.</p>
{% elsif isBot %}
<p class="text-muted">Checkout is available to human visitors.</p>
{% else %}
<a href="/checkout/express" class="btn btn-success">Express Checkout</a>
{% endif %}
</template>
</sb-widget>
Variabili del template: isBot, botProbability, confidence, botType, botName, riskBand, recommendedAction, threatScore, threatBand. In più qualsiasi vars Si passa dal server-side quando si chiama. RenderWidget direttamente.
Tutti. <sb-widget> Elementi che si collegano nello stesso ticolo di microtask sono battuti in una sola richiesta. Una pagina con cinque widget fa una volta rotonda
sequenceDiagram
participant B as Browser
participant C as Coordinator
participant S as /_stylobot/partials/render
participant L as Fluid / Liquid
B->>C: sb-widget#checkout-cta registers
B->>C: sb-widget#promo-banner registers
B->>C: sb-widget#nav-links registers
Note over C: queueMicrotask - one batch
C->>S: POST { widgets: { checkout-cta: "...", promo-banner: "...", nav-links: "..." } }
S->>L: render each template with verdict context
L-->>S: rendered HTML fragments
S-->>C: <div data-sb-widget="checkout-cta">...</div> ...
C-->>B: each sb-widget replaced in DOM
| Componente | ||
|---|---|---|
styloBotMiddleware |
Express | Attaches req.stylobot attraverso i titoli / gRPC / REST |
styloBotPlugin |
Fastify | Lo stesso, come plugin Fastify con decorateRequest |
sbVerdictInjector |
Express | Populazioni res.locals.sbVerdict e sbVerdictScript |
| Aiuti alla barra di comandos | Template del server | sbGate, sbIsBot, sbBotType, sbMinRisk Aiutatori di blocco |
| Espansione di Nunjucks | Immagini del server | {% sbgate "Low" %}...{% endsbgate %} |
| Locali EJS | Servetori templates | sbBelowRisk(), sbAboveRisk(), sbIsBot(), sbBotIs() |
<sb-gate> |
Browser | mostrare/ nascondere il contenuto secondo la banda di rischioM SK3 ascolta per sb:verdict |
<sb-adapt> |
Browser | Prendete il primo caso corrispondente da una lista SSK2 |
<sb-widget> |
Browser | Server di attivazione- Fragmento liquido consegnatoM SK3 battuto per taglio SSK4 |
StyloBotGrpcClient |
Node / Bun |
Il prossimo nella serie di release: L'architettura della Sidecar, come il motore di rilevazione si collega a non--. stacks NETM SK2 Go SDK, la plugin Caddy , e l'interfaccia gRPC che lo collega insiemeMSC5
Se siete arrivati qui dal lato .NET, Comportamento-Aware ASP.NET UI copre gli stessi schemi frontali con tag helper e filtri di azione; il ritocco di affidabilità che mantiene la memoria del motore- stabile sotto un traffico sostenuto è in Trovare e riparare la crescita senza limiti nei servizi NET Long-Running .. Motore viventeM SK1 Armatura dashboard, e controlli commerciali a stylobot.net.
© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.