Documentation

Guides for protecting production JavaScript

Reference guides for release workflows, command-line usage, cross-file protections, and the desktop app.

Inside The Docs

Practical guides, not placeholder pages.

How-to guides Start with release sequencing and command-line usage, then move into feature-specific references.
Advanced protection Browse cross-file controls like Replace Globals and Protect Members when a build spans multiple scripts.

Deploying JSO AI Phase 1

Hand-off document for whoever flips Phase 1 on. The code is in production today as preview-mode stubs; this page lists everything that has to happen outside the source tree to switch real LLM responses on. The site is engineered so this is the only ritual — no further C# changes are required.

Pre-flip state (what's already shipped)

  • Four endpoints: /v1/ai/preset-suggest.ashx, /v1/ai/compat-check.ashx, /v1/ai/explain-error.ashx, /v1/ai/usage.ashx. All POST-only, 405 elsewhere. Wire envelope locked by ai-wire-format.schema.json and the polyglot smoke harness (8/8 mock + 4/4 live).
  • Auth: AIService.ResolveAccountId(base64ApiKey, base64ApiPwd) validates the standard JSO API key + password pair against JSODB.APIKey. Same credential shape as HttpApi.ashx.
  • Quota enforcement: AIService.CheckQuota reads AIDisable, walks vw_AIMonthlyUsage, applies the in-code Tier caps in action / token / cost priority order.
  • Usage read: AIService.GetMonthlyUsage shared by the endpoint, the dashboard widget, and the Prometheus exporter (jso-ai-quota-exporter.js).
  • LLM client: LlmProviderClient.SendChat dispatches to real Anthropic Messages or OpenAI Chat Completions clients. Account-level BYO keys are preferred; site-wide provider config is the fallback.
  • Browser previews: PresetAssistant, CompatCheck, ExplainError — mirror the rule-based engines client-side, run without auth.
  • Dashboard widget: /dashboard/AIUsage.aspx with schema, subscription, BYO-key, and usage states; /dashboard/AIOrder.aspx honors the managed-billing flag; and /dashboard/AISettings.aspx stores encrypted account-level OpenAI or Claude keys.
  • Stripe wiring: /v1/ai/checkout-create.ashx (Stripe Checkout Sessions), /v1/ai/stripe-webhook.ashx (HMAC-SHA256-verified event receiver, routes checkout.session.completed + customer.subscription.* events into AISubscription and captures the Customer ID), and /v1/ai/portal-create.ashx (Stripe Customer Portal sessions for self-service subscription management: payment method updates, invoices, cancel). All three use the same dual auth (APIKey body field OR dashboard session cookie); webhook is idempotent via a Stripe event-ID ledger; all rate-limited per-IP.
  • Admin: /jsomanage/AISubscriptions.aspx for support to create subscriptions manually for the early-access cohort before Stripe pricing is fully provisioned.
  • Health: /v1/health.ashx surfaces ai.globallyEnabled + ai.provider so external monitors detect the go-live moment without an API key.
  • Regression coverage: npm run verify:ai-live (in packages/jso-protector) runs a 7-case live POST harness covering preset-suggest, compat-check, explain-error, usage, checkout-create (auth-fail path), stripe-webhook (405), and the per-IP rate limiter.

Deploy-time steps

1. Provision the AI schema

Run App_Data/CreateAITables.sql against the production database. The script is idempotent (uses IF NOT EXISTS guards) so re-running is safe. Creates:

  • AISubscription — one row per active AI tier subscription.
  • AIUsage — per-action audit row, written by AIService.RecordSuccess.
  • AIDisable — account-level kill switch (one row = AI off for that account, with a Reason string).
  • AIAccountKey — encrypted account-level OpenAI or Claude key for BYO-key calls.
  • vw_AIMonthlyUsage — aggregated view over AIUsage grouped by AccountID + first-of-month.

Verify: hit /dashboard/AIUsage.aspx as any logged-in user. Banner should switch from "AI schema not yet provisioned" to "no active subscription" (the schema-present-no-subscription state).

2. Configure the LLM provider

Add to Web.config <appSettings>:

<add key="JSOAI.Provider"  value="claude" />
<add key="JSOAI.ClaudeApiKey" value="sk-ant-..." />
<!-- Optional: model override; defaults to claude-sonnet-4-5 (AIService.DEFAULT_CLAUDE_MODEL). -->
<add key="JSOAI.ClaudeModel" value="claude-sonnet-4-5" />

For OpenAI:

<add key="JSOAI.Provider"   value="openai" />
<add key="JSOAI.OpenAIApiKey" value="sk-..." />
<!-- Optional: defaults to gpt-5 (AIService.DEFAULT_OPENAI_MODEL). -->
<add key="JSOAI.OpenAIModel"  value="gpt-5" />

If you want to test the wiring without a site-wide API key, leave JSOAI.Provider on preview (or remove the provider key entirely). The endpoints stay up; they just keep returning the rule-based preview envelopes. Individual dashboard accounts can also save encrypted OpenAI or Claude keys at /dashboard/AISettings.aspx.

3. Flip the global enable flag

In AIService.cs there is a single IsGloballyEnabled property. Today it returns false via the JSOAI.Enabled appSetting (default off). Add:

<add key="JSOAI.Enabled" value="true" />

This flag controls the site-wide managed AI path. Accounts with an encrypted BYO provider key can still run live AI when managed AI is globally disabled, so use AIDisable or remove the account provider key when the goal is to stop a specific account. Accounts with no provider key fall back to preview behavior.

4. Configure Stripe billing

The handlers /v1/ai/checkout-create.ashx and /v1/ai/stripe-webhook.ashx ship as Phase 1 code, but checkout must stay disabled until Stripe products, prices, and webhook verification are ready. Keep this setting false until the billing surface is live:

<add key="JSOAI.ManagedBillingEnabled" value="false" />

When managed billing is enabled, the handlers use the existing site-wide Stripe settings by default:

<add key="StripeSecureKey" value="sk_live_..." />
<add key="StripeWebhookKey" value="whsec_..." />

Optional AI-specific overrides are also supported:

<add key="StripeApiKey"              value="sk_live_..." />
<add key="StripeAiBasicPriceId"      value="price_..." />
<add key="StripeAiCorporatePriceId"  value="price_..." />
<add key="StripeAiEnterprisePriceId" value="price_..." />
<add key="StripeAiWebhookSecret"     value="whsec_..." />

In the Stripe dashboard:

  1. Either let checkout-create.ashx find or create the three recurring Prices automatically by lookup key, or create Products/Prices manually (JSO AI Basic / Corporate / Enterprise) at $19, $79, $299 per month and copy each Price ID into the optional appSetting above.
  2. Configure a webhook endpoint at https://www.javascriptobfuscator.com/v1/ai/stripe-webhook.ashx. Subscribe to checkout.session.completed, customer.subscription.created, customer.subscription.updated, customer.subscription.deleted. Use StripeAiWebhookSecret if you want an AI-specific secret; otherwise the handler falls back to StripeWebhookKey.

If managed billing is disabled, checkout-create.ashx returns managed_billing_disabled in a normal JSON response and the dashboard order page points users to BYO-key setup or support. If managed billing is enabled but no Stripe secret key is available, the endpoint returns checkout_not_configured. When Stripe is configured, checkout can create the missing AI Prices on first use.

5. (Optional) Seed early-access subscriptions

While Stripe billing is being provisioned, the early-access cohort gets manual subscriptions via /jsomanage/AISubscriptions.aspx (admin only). Direct SQL works too:

INSERT INTO AISubscription (AccountID, Tier, MonthlyActionsCap, MonthlyTokensCap, MonthlyCostCapCents)
VALUES (12345, 'Corporate', 500, 2000000, 30000);

6. Confirm via the config-check page

Admin-only at /jsomanage/AIConfigCheck.aspx — live mirror of this checklist. Reads every appSetting the AI / Stripe surface consumes and reports which are wired (secrets masked). One green pill = "all required appSettings configured" before you flip the global flag.

7. Run the live smoke

cd packages/jso-protector
JSO_BASE_URL=https://www.javascriptobfuscator.com npm run verify:ai-live

Expected: 7/7 PASS (preset-suggest, compat-check, explain-error, checkout-create auth-fail, stripe-webhook 405, usage, rate-limit). The 429 case is localhost-guarded and SKIPs on prod targets so we don't burn a real visitor's rate-limit bucket. If any endpoint fails, the harness message includes the upstream provider error or HTTP status — debug from there. The smoke harness uses "x" as the APIKey, so passing is "wire format intact"; confirm "real LLM calls work" by hitting the endpoint with a real Corporate APIKey and observing actionsUsed tick up.

Rollback plan

Three independent kill switches in order of severity:

  1. Remove the API key from Web.config and disable any account BYO keys that should not run. Endpoints fall back to the preview envelope when no live provider key is available. Customers still get useful (rule-based) responses; no quota is consumed. Recovery time: 1 minute.
  2. Set JSOAI.Enabled=false. This disables the site-wide managed provider path. BYO-key accounts can still run live AI unless their account key is removed or disabled. Recovery time: 1 minute.
  3. Insert into AIDisable for specific accounts. Surgical: leaves AI on for everyone else while taking it off for one or more accounts. INSERT INTO AIDisable (AccountID, Reason, DisabledUtc) VALUES (...).

The dashboard widget and the Prometheus exporter both pick up the rollback automatically — no separate UI revert needed.

Observability after the flip

  • The dashboard widget at /dashboard/AIUsage.aspx shows live counters and the green/amber/red threshold gradient.
  • The Prometheus exporter at /download/jso-ai-quota-exporter.js exposes per-account counters that customers can pipe into their own stacks. Internally, point one instance at a service account and dashboard the global numbers in our Grafana.
  • The RecordFailure path in AIService writes a QuotaRejections increment to AIUsage. Spike alert at >50/min suggests a Stripe webhook regression or a quota arithmetic bug.
  • RSS feed + /changelog.aspx — customers and watchers see every shipped change. Drop a CHANGELOG entry when you flip the flag so subscribers know they can start using AI.

What's not in Phase 1

  • Stripe pricing setup — the webhook handler (/v1/ai/stripe-webhook.ashx) and the checkout-session creator (/v1/ai/checkout-create.ashx) both ship in Phase 1. The checkout path reuses StripeSecureKey and auto-creates missing AI monthly Prices by lookup key unless explicit StripeAi<Tier>PriceId overrides are configured. Configure the webhook in Stripe to point at https://www.javascriptobfuscator.com/v1/ai/stripe-webhook.ashx; use StripeAiWebhookSecret or the existing StripeWebhookKey.
  • Resistance Score (Phase 2, 2026-Q4). Separate concept; separate Phase. See the blog post.
  • Deobfuscation benchmark (Phase 3, 2027-Q1). Quarterly publication, includes our own output.
One-page summary for the deployer: run the SQL script → enable BYO account keys or configure a site-wide provider → keep JSOAI.ManagedBillingEnabled=false until Stripe products and webhooks are ready → run npm run verify:ai-live. 7/7 PASS means the live surface is wired. Rollback is one config/account edit away (remove provider key, flip managed provider off, or insert per-account AIDisable). Every link in the chain — APIKey resolution, quota enforcement, LLM call, usage write, dashboard widget, Prometheus exporter, schema validator, checkout gating, webhook reconciliation, success-banner UX, public release-notes RSS — is production code today.