toiljs 0.0.101 → 0.0.103

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,36 +1,81 @@
1
1
  # The modern stack: what toil gives you that others do not
2
2
 
3
- Most frameworks give you a way to write code and then send you shopping: a database, an auth provider, email, a rate limiter, analytics, a realtime service, a job runner, all wired together and kept in sync by you. toil owns those parts instead: built in, and on from the first line. This page is the catalog of what ships; for how the edge and distribution actually work, see [How toil works](./how-it-works.md) and [How toil is distributed](./distributed.md).
3
+ Most frameworks give you a way to write code and then send you shopping: a database, an auth provider, email, a rate limiter, analytics, a realtime service, a job runner, each its own account, bill, and SDK, all wired together and kept in sync by you. toil owns those parts instead. They ship in one framework, they are toil's own (nothing third-party sits on your critical path), and they are on from the first line with zero configuration. This page is the full catalog.
4
4
 
5
- ## What is built in
5
+ The point is not that toil bundles a lot. It is that the good version is the default version: a solo builder gets the same baseline as a funded team, without assembling or babysitting ten vendors. For how the edge and worldwide distribution actually work, see [How toil works](./how-it-works.md) and [How toil is distributed](./distributed.md).
6
+
7
+ ## The backend, built in
8
+
9
+ Your TypeScript backend declares what it needs with a decorator or a one-line config flag. toil provides the machinery.
6
10
 
7
11
  | Feature | What it is | Why it matters |
8
12
  | --- | --- | --- |
9
- | Edge compute over HTTP/3 | Frontend and backend both run on servers in many cities, over HTTP/3 with automatic fallback to HTTP/2 or HTTP/1.1. | Code runs next to the user, so there is no slow round trip to one origin. |
10
- | [ToilDB](../database/README.md) | A global database with no connection string and seven families (documents, unique, counter, events, capacity, membership, view). | Distributes writes, not just reads, so a thousand servers can write at once without a single-region bottleneck (trade: eventual consistency). |
11
- | [Post-quantum auth](../auth/README.md) | Password login via `server: { auth: true }`; the password becomes an ML-DSA-44 key in the browser and the server stores only the public key. | The password never crosses the wire in a replayable form, so a breached server yields no usable passwords, and there is no identity vendor to rent. |
12
- | Automatic SRI | A SHA-384 fingerprint on every local script, preload, and stylesheet, plus an import map covering the whole module graph. | Tampered assets simply do not run, even if a CDN or cache hop is compromised. |
13
- | [Email](../services/email.md) | `EmailService.send(...)` or a reusable `EmailTemplate` with `{{placeholder}}` bodies, through a provider you configure once. | Verification codes, resets, and receipts are one call: validated, per-tenant capped, and off the worker while the provider replies. |
13
+ | [Post-quantum auth](../auth/README.md) | Password login via `server: { auth: true }`. The password is stretched (OPRF + Argon2id) into an ML-DSA-44 keypair in the browser; only the public key is sent; login runs ML-KEM-768 mutual auth so the client also verifies the server. | Real post-quantum cryptography (the NIST-standardized algorithms), in about one line. The password never reaches the server in a usable form, so a breached server yields nothing replayable, and there is no identity vendor to rent. |
14
+ | [ToilDB](../database/README.md) | A global database with no connection string and seven purpose-built families. Its differentiator is distributed writes: every key has one home region that orders its writes, while data replicates outward for fast local reads. | Distributes writes, not just reads, so a thousand servers can write at once with no single-region bottleneck. This is the hard part almost nobody does (trade: eventual consistency, a far read can lag a few ms). |
15
+ | [Email](../services/email.md) | `EmailService.send(...)`, or a reusable `EmailTemplate` with `{{placeholder}}` bodies, through a provider you configure once. | Verification codes, resets, and receipts are one validated, per-tenant-capped call, off the worker while the provider replies. |
14
16
  | [Rate limiting](../services/ratelimit.md) | `@ratelimit` on a route, counted at the edge in an exact cross-worker limiter keyed on the caller's network address. | Over-limit clients are rejected before your code runs, blunting brute-force and spam. |
15
- | [Analytics and time series](../services/analytics.md) | The `Analytics` global reads your site's own counters: `self()` for a snapshot, `series(metric, range)` for a graph. | A real usage dashboard with no extra code and no analytics vendor, correct across every edge location. |
16
- | [Realtime streaming](../realtime/README.md) | A `@stream` class with `@connect`/`@message`/`@close`/`@disconnect` hooks, opened from React with `useChannel`; WebTransport in production, WebSocket in dev. | A resident instance stays alive per connection and remembers state next to the user (chat, presence, progress). |
17
- | [Daemons and @derive](../background/README.md) | `@daemon` runs one global background worker on a schedule (interval or cron) with lease-based failover; `@derive` re-runs when its source data changes to refresh a View. | Nightly jobs and rollups run once globally, with no cron server, queue, or leader election to run yourself. |
18
- | [Owned globals](../services/README.md) | No-import cookies (read/set, sign or encrypt), crypto (hash, HMAC, AES, random), time (the edge clock), and environment/secrets. | Your request's small dependencies live in one system, and your compiled program carries no credential. |
19
- | [Toolchain](../cli/README.md) | `toiljs create` scaffolding, a shared ESLint config, Prettier plus a decorator-aware plugin, an editor plugin, one CLI, and `toiljs doctor --fix`. | Set up for you and wired by types, so a server change is a compile error at your desk, not a production bug. |
20
- | LLM-friendly docs | A machine-readable `llms.txt` plus a generated `.toil/docs/` folder and pointer files (`CLAUDE.md`, `AGENTS.md`, editor rules), refreshed on every build. | An assistant reads your current conventions instead of guessing from stale training. |
17
+ | [Analytics](../services/analytics.md) | The `Analytics` global reads your site's own counters: `self()` for a snapshot, `series(metric, range)` for a graph. | A real usage dashboard with no extra code and no analytics vendor. |
18
+ | [Realtime streaming](../realtime/README.md) | A `@stream` class with `@connect` / `@message` / `@close` / `@disconnect` hooks, opened from React with `useChannel`. WebTransport (over QUIC) in production, WebSocket in dev. | A resident instance stays alive per connection and remembers state next to the user: chat, presence, live progress. |
19
+ | [Background jobs (`@daemon`)](../background/daemons.md) | One global background worker on a schedule (interval or cron), with lease-based failover so exactly one instance runs worldwide. | Nightly jobs run once globally, with no cron server, queue, or leader election to run yourself. |
20
+ | [Scheduled jobs (`@scheduled`)](../background/daemons.md) | A method that fires on an interval or cron expression, driven by the same lease so it runs once across the fleet. | Recurring work (cleanup, digests, syncs) without standing up a scheduler. |
21
+ | [Materialized views (`@derive`)](../background/derive.md) | A function that re-runs when its source data changes and writes the result into a View family. | Rollups and denormalized read models stay fresh automatically, so reads are cheap without a hand-rolled pipeline. |
22
+ | [Sessions and cookies](../services/cookies.md) | No-import cookie read/set, signed or encrypted, plus the session layer that backs `@auth`. | Login state and small per-user data without a session store to provision. |
23
+ | [Environment and secrets](../services/environment.md) | A per-tenant environment store for config and secrets, read at the edge, never baked into the shipped WASM. | Your compiled program carries no credential; secrets live in one place, disjoint from public config. |
24
+
25
+ ### The seven ToilDB families
26
+
27
+ One database, seven shapes, each tuned to its access pattern rather than bent out of a single table model.
21
28
 
22
- ## Built in versus assemble it yourself
29
+ | Family | For |
30
+ | --- | --- |
31
+ | [Documents](../database/documents.md) | General structured records. |
32
+ | [Unique](../database/unique.md) | Uniqueness constraints (one email, one handle). |
33
+ | [Counter](../database/counters.md) | High-throughput increments (views, likes, quotas). |
34
+ | [Events](../database/events.md) | Append-only logs and feeds. |
35
+ | [Membership](../database/membership.md) | Set membership and relationships (who is in what). |
36
+ | [Capacity](../database/capacity.md) | Bounded resources and seat/slot allocation. |
37
+ | [View](../database/views.md) | Read models materialized by `@derive`. |
38
+
39
+ ## The frontend, built in
40
+
41
+ The React client is Vite-fast and typed end to end. The pieces that usually take a build config, a fetch layer, and an SEO plugin are already wired.
42
+
43
+ | Feature | What it is | Why it matters |
44
+ | --- | --- | --- |
45
+ | [File routing](../frontend/routing.md) | Routes are files under `client/routes/`. The tree is your URL map. | No router config to hand-maintain; add a file, get a route. |
46
+ | [Loaders with revalidation](../frontend/data-fetching.md) | A route `loader` fetches its data before render and revalidates on demand. | Data arrives with the page, not after a client-side waterfall. |
47
+ | [Two rendering paths](../frontend/rendering.md) | Build-time prerender for SEO by default, plus opt-in edge SSR with `export const ssr = true`, both hydrated with `hydrateRoot`. | Static-fast pages where you can, live server rendering where you need it, one codebase. |
48
+ | [Typed `Server` client](../frontend/data-fetching.md) | A generated client (`Server.REST.*`, `Server.Stream.*`, `Server.<service>`) so the browser calls the backend with end-to-end types. | No hand-written fetch and no drift: rename a field on the server and the frontend stops compiling until you fix it. |
49
+ | [Image with LQIP](../frontend/images.md) | A built-in `Image` component with blur / low-quality placeholders and reserved aspect ratio. | Fast, layout-stable images with no CLS and no separate image service. |
50
+ | [Metadata and SEO](../frontend/metadata.md) | Per-route title, description, canonical, and Open Graph (including `og:image`), baked into the served HTML head. | Correct SEO and share cards in view-source, not assembled by JavaScript after load. |
51
+ | [Page search](../frontend/search.md) | A static index of each route's title, description, keywords, and Open Graph, generated at build. | In-app search with no search vendor (see the caveat below). |
52
+ | [SHA-384 SRI](../concepts/security.md) | Subresource Integrity plus importmap integrity on every shipped script, preload, and stylesheet, across the whole module graph. | A tampered asset simply does not run, even if a CDN or cache hop is compromised. |
53
+
54
+ ## Owned, not rented
55
+
56
+ Everything above is toil's own code on your critical path, not a black box you cannot inspect, patch, or secure. That is the difference the table below draws.
23
57
 
24
58
  | Capability | toil (built in, zero setup) | Typical stack (you assemble it) |
25
59
  | --- | --- | --- |
26
- | Edge and transport | Frontend and backend worldwide over HTTP/3 | A separate edge product, often reads-only |
27
60
  | Database | ToilDB: global, distributed writes, seven families | A managed database, usually single-region for writes |
28
61
  | Auth | Post-quantum login; the server holds no password | A rented identity provider or hand-rolled hashing |
29
62
  | Email, rate limiting, analytics | Built-in primitives, one call each | A separate SDK or vendor per capability |
30
- | Realtime and background | `@stream`, `@daemon`, `@derive` | A realtime service plus a cron server, queue, and leader election |
31
- | Asset integrity and toolchain | Automatic SRI, ESLint/Prettier/editor plugins, one CLI | Manual or skipped; configured and maintained by you |
63
+ | Realtime and background | `@stream`, `@daemon`, `@scheduled`, `@derive` | A realtime service plus a cron server, queue, and leader election |
64
+ | Sessions, secrets, cookies | Owned globals, no store to provision | A session store and a secrets manager to run |
65
+ | Frontend integrity and SEO | Automatic SHA-384 SRI, Image/LQIP, metadata, page search | Plugins and services bolted on per concern |
32
66
  | Critical-path ownership | The core is toil's own | A mix of vendors you cannot inspect or fix |
33
67
 
68
+ Honest boundary: "owned" means the core of a working app is toil's, not that outside services are banned. Call a payment provider or another API and you still can.
69
+
70
+ ## The honest caveats
71
+
72
+ toil grades itself on honesty, so read these before you count on anything.
73
+
74
+ - **Distributed writes are built, live multi-cell is config-gated.** The home-region model and its core logic are real and tested, but live multi-region deployment (WAN routing, the ScyllaDB backing) is opt-in, not on by default. The local dev database is a single in-process store. toil is built to distribute writes worldwide; not every app is running a live global write cluster today.
75
+ - **Analytics is a dev stub locally.** It is real on the edge; the local dev server returns sample data.
76
+ - **Auth secrets ship as dev placeholders.** The session HMAC, OPRF seed, and ML-KEM key are clearly-insecure placeholders so `toiljs dev` just works. A real deployment must set its own (per-tenant auto-generation at domain registration is the plan).
77
+ - **Page search indexes static metadata only.** Routes whose metadata comes from a dynamic `generateMetadata` are not in the index.
78
+
34
79
  ## Why it is all a default
35
80
 
36
- None of this is an upgrade you unlock later. toil grades itself against [RSG](./design-principles.md) (Resilience and Scale Grade), whose one rule is that your grade is your weakest axis, never the average, so these batteries exist to keep any single axis from quietly capping the whole. Where the honest trade fits your project (ToilDB is not general SQL, the server language is a strict TypeScript subset, the catalog is younger than long-established platforms), the built-in stack is the whole point; [Why toil](./why-toil.md) says where it does not.
81
+ None of this is an upgrade you unlock later. toil grades itself against [RSG](./design-principles.md) (Resilience and Scale Grade), whose one rule is that your grade is your weakest axis, never the average, so these batteries exist to keep any single axis from quietly capping the whole. Where the honest trade fits your project (ToilDB is not general SQL, the server language is a strict TypeScript subset, the catalog is younger than long-established platforms), the built-in stack is the whole point. [Why toil](./why-toil.md) says where it does not.
@@ -1,48 +1,64 @@
1
1
  # toil versus other stacks
2
2
 
3
- An honest look at where each stack you already use hits a ceiling, and why toil bets on a different shape. Each of these tools is genuinely good at what it was built for, so the goal is not to crown a winner but to show *where* each one typically caps.
3
+ An honest, axis-by-axis look at where toil trades differently from the stacks you already use. Every tool below is genuinely good at what it was built for, so the goal is not to crown a winner but to be concrete about what you gain and what you give up. toil is also younger than all of them, and that shows up in a few rows.
4
4
 
5
- We grade with the [RSG rubric](./design-principles.md), whose rule is that a system's grade is its **weakest** axis, never the average. So the useful question is not "what is it great at?" but "what quietly caps it?" For most stacks the answer is the same axis: the **data path** (how and where writes happen), sometimes joined by **dependencies** (how much of the critical path you rent versus own).
5
+ The short story: toil trades a large, mature ecosystem for one owned framework that distributes writes and ships the fast, safe defaults for free. Whether that trade fits your project is the honest question this page tries to answer.
6
6
 
7
- RSG is toil's own internal rubric, not an external standard, and every stack below can be configured many ways. The caps described are the *typical* production shape, not a claim that they are unavoidable.
7
+ ## The comparison at a glance
8
8
 
9
- ## Where each stack caps
9
+ | Axis | A typical modern stack | toil |
10
+ | --- | --- | --- |
11
+ | Pieces on the critical path | A dozen rented vendors (host, functions, database, auth, email, queue, cache, analytics, realtime), each its own account, bill, and SDK | One framework you write in; the core services are toil's own, so nothing third-party sits on the critical path |
12
+ | Where writes land | One primary region: reads go global, writes crawl back to that box | Every key has one home region that orders its writes, while data replicates outward for fast local reads (built to distribute; live multi-cell is configuration-gated) |
13
+ | Server runtime | A Node process, container, or VM per app | A small sandboxed WebAssembly module; one edge box safely runs many apps (multi-tenant), which is what makes running near everyone affordable |
14
+ | Client-to-server calls | Hand-written fetch/REST, types drift until something breaks in production | A generated, fully typed `Server` client with no raw fetch: change a field on the server and the frontend stops compiling until you fix it |
15
+ | Auth | Bolt on a provider or roll your own | Post-quantum login (ML-DSA + ML-KEM) built in, enabled in about one line |
16
+ | Getting to production | Assemble CDN, cache, regions, hardened auth, and CI yourself | Zero config: the good version is the default version |
17
+ | Toolchain | A decade of bundler configs, transpiler shims, CommonJS-versus-ESM interop, and `node_modules` churn | Built on modern web tech (React + Vite client, one CLI), far less legacy to fight |
18
+ | Database | Mature SQL: joins, ad-hoc queries, huge tooling | Seven purpose-built families (Documents, Unique, Counter, Events, Membership, Capacity, View): fast and distributed, but not relational |
19
+ | Package ecosystem | The full npm and Node universe | A strict TypeScript subset with built-in globals; no arbitrary npm packages or Node APIs on the server |
20
+ | Integration catalog | Large, mature, well documented | Smaller and younger |
21
+ | Single-region app | Dead simple, nothing to distribute | Distribution you may not need |
10
22
 
11
- | Stack | Great at | Typical binding axis | Why it caps there |
12
- | --- | --- | --- | --- |
13
- | **Next.js / Vercel** | DX, React, global edge reads | data path | Global reads, single-region writes: a sudden write-heavy spike concentrates on one DB box that edge caches and read replicas cannot relieve, while serverless cold starts add latency and per-invocation billing climbs exactly when load peaks |
14
- | **Rails / Django** | Maturity, batteries included | topology / availability / data | Centralized single-region monolith: one place to be near, one place to fail, and one primary every write must reach |
15
- | **Serverless functions** (Lambda, Cloud Functions) | Elastic stateless compute | data path | Distributes compute, not state; the central DB stays the write bottleneck, and a cold-start burst adds latency and cost right when traffic surges |
16
- | **Edge runtimes** (Workers, Deno Deploy) | Code at the edge, near users | data path | Distributes compute beautifully, but the DB you attach is usually single-region (Durable Objects / D1 excepted, below) |
17
- | **BaaS** (Supabase, Firebase) | Fastest to start | dependencies + data path | You rent a managed service you cannot inspect or fix, and writes resolve against a primary |
18
- | **toil** | Owned stack, distributed writes | aims for no single binder | Every key has one home region that serializes its writes; auth, DB, email, and jobs are owned, so the usual caps are designed out (latency and client axes are still yours to earn) |
23
+ The top rows lean toil's way, the bottom rows lean the incumbents' way, and that split is the whole story. toil is designed to win the structural axes (one owned stack, distributed writes, a multi-tenant sandbox, end-to-end types, built-in modern auth) and it concedes the ecosystem axes (SQL, the Node universe, catalog size) that maturity buys.
19
24
 
20
- ## One line each
25
+ ## Where each stack fits
21
26
 
22
- - **Next.js / Vercel:** superb reads and DX, but a sudden spike (a viral launch, a flash sale, a timed drop where everyone writes in the same second) lands as a thundering herd on the one write region, so latency, timeouts, and per-invocation cost climb together while edge caching helps only the reads.
23
- - **Rails / Django:** mature and productive, capped by its single-region shape; you can add replicas and standbys to climb, but distributed *writes* are not in the default model.
24
- - **Serverless functions:** great elastic compute, but it is stateless compute in front of a central database, so a write burst still bottlenecks on that store and each cold invocation bills separately.
25
- - **Edge runtimes:** the closest in spirit to toil's compute model, yet edge compute in front of a central database is just a faster front door to the same bottleneck.
26
- - **Cloudflare Durable Objects / D1:** the closest mainstream analog to toil's idea, and credit is due. A Durable Object gives one object a single-writer home that serializes its writes, the same shape as ToilDB's per-key home. The difference is packaging: with the edge-runtime approach you assemble the pieces yourself (runtime, object or DB product, auth, email), whereas toil ships distributed writes, the seven database families, auth, email, streaming, and jobs as one integrated owned stack. Which you prefer is a genuine trade-off.
27
- - **BaaS (Supabase, Firebase):** fastest to start, but the convenience is a managed service on your critical path, and writes still resolve against a primary, so it is **dependency-bound and data-bound**.
27
+ **Next.js / Vercel.** Superb React DX and global edge reads. The ceiling is the write path: pages cache worldwide, but a write (a comment, an order, a flash-sale click) still resolves against one primary region, and serverless cold starts add latency and per-invocation cost exactly when a spike hits. toil keeps a React-first client and moves the write to a home region near the data.
28
28
 
29
- ## Being honest about toil's own limits
29
+ **Rails / Django.** Mature, productive, batteries included, an enormous ecosystem and a deep hiring pool. If you are happy in one region this is a great and boring choice. The default shape is a single-region monolith with one primary that every write must reach; you can add replicas and standbys to climb, but distributed writes are not in the model.
30
30
 
31
- RSG grades toil by the same weakest-link rule, and some axes are not handed to you for free:
31
+ **Serverless functions (Lambda, Cloud Functions).** Elastic, stateless compute that scales to zero. But it is stateless compute in front of a central database, so a write burst still bottlenecks on that store, and each cold invocation bills and lags on its own.
32
32
 
33
- - **Younger, smaller ecosystem.** Fewer integrations, tutorials, and hosting options than the mature stacks above. If your project is defined by a large existing integration catalog, that gap is real today.
34
- - **The server language is a TypeScript subset.** toilscript compiles a strict subset of TypeScript to WebAssembly: no arbitrary npm packages or Node APIs on the server, built-in globals instead. That is the price of the small, fast, safe sandbox.
35
- - **ToilDB is not SQL.** It is seven purpose-built families, not a relational engine, so heavy ad-hoc joins and existing SQL schemas are not its shape (see the [database overview](../database/README.md)).
36
- - **Some axes you still earn.** RSG measures delivered latency, program performance, and client performance from *your* code. toil removes the structural caps, but it cannot make slow application code fast or a bloated client light.
33
+ **Edge runtimes (Workers, Deno Deploy).** The closest in spirit to toil's compute model: your code runs near users. The catch is that the database you attach is usually single-region, so edge compute becomes a faster front door to the same central write bottleneck.
34
+
35
+ Cloudflare Durable Objects and D1 are the closest mainstream analog to toil's idea, and credit is due: a Durable Object gives one object a single-writer home that orders its writes, the same shape as ToilDB's per-key home. The difference is packaging. With the edge-runtime approach you assemble the pieces yourself (runtime, object or database product, auth, email, realtime); toil ships distributed writes, the seven database families, auth, email, streaming, and background jobs as one owned stack. Which you prefer is a real trade-off.
36
+
37
+ **Backend-as-a-service (Supabase, Firebase).** The fastest thing to start with, and often the right call for a prototype. The convenience is a managed service on your critical path that you cannot inspect or patch, and writes still resolve against a primary.
38
+
39
+ ## Where the incumbents still win
40
+
41
+ toil does not win every axis, and some gaps are real today. Be honest about them:
42
+
43
+ - **Mature ecosystems.** More tutorials, more answered questions, more hosting options, and more people who already know the tool.
44
+ - **SQL and joins.** If your data is relational and you live in ad-hoc queries and joins, a SQL database is the right tool. ToilDB is seven purpose-built families, not a relational engine (see the [database overview](../database/README.md)).
45
+ - **The Node package universe.** The toil server is a strict TypeScript subset compiled to WebAssembly: no arbitrary npm packages or Node APIs, built-in globals instead. That is the price of the small, fast, multi-tenant sandbox.
46
+ - **Bigger integration catalogs.** toil is younger, so the catalog of ready-made integrations is smaller. If your project is defined by a large existing integration catalog, that gap matters.
47
+ - **Single-region simplicity.** If one region already fits your users, toil's distribution is effort you do not need.
48
+
49
+ None of these are permanent, and the right tool is the one that fits the job in front of you.
37
50
 
38
51
  ## toil's bet
39
52
 
40
- Every stack above is capped in almost the same place: the write path is one box in one region, or the critical path leans on a service you rent. toil's bet is to refuse both at once, own the whole stack and distribute the writes, so the axes that usually cap a "global" system are designed out and the only limits left are the ones your own code sets.
53
+ Most stacks cap in nearly the same place: the write path is one box in one region, or the critical path leans on services you rent and cannot fix. toil's bet is to refuse both at once, own the whole stack and distribute the writes, so the structural caps are designed out and the limits left are the ones your own code sets.
54
+
55
+ Keep the mechanism honest. The home-region model and its core logic are real and tested, but live multi-region deployment (the WAN routing and the ScyllaDB backing) is configuration-gated rather than on by default, and the local dev database is a single in-process store. Compute works the same way: your code runs at the edge on every request, while the regional, continental, and global-daemon tiers are opt-in. So the accurate claim is "toil is built to distribute writes worldwide, and the mechanism is real," not "every app is already running a live global write cluster today."
41
56
 
42
- Whether that bet fits *your* project is the honest checklist in [Why toil](./why-toil.md).
57
+ Whether that trade fits your project is the checklist in [Why toil](./why-toil.md).
43
58
 
44
59
  ## Related
45
60
 
46
61
  - [Why toil? Who is it for?](./why-toil.md): the problem toil solves and the honest cases where you should not use it.
62
+ - [The modern stack](./modern-stack.md): the full, verified catalog of what is built in.
47
63
  - [How toil is distributed](./distributed.md): the mechanism behind distributed writes (every key's single home region).
48
- - [Why toil is built this way (the RSG bar)](./design-principles.md): the weakest-link rubric this comparison uses.
64
+ - [Why toil is built this way](./design-principles.md): the bar toil grades itself against.
@@ -2,27 +2,35 @@
2
2
 
3
3
  toil is a full-stack framework: you write a React frontend and a TypeScript backend in one project, and toil runs both (plus a database) close to every user, worldwide.
4
4
 
5
- The thesis in one line: toil is the modern full-stack tech a developer would actually want, AAA-grade from the very first line, and hyper-scalable at the same time. Even a simple pizza site gets top-tier infrastructure with zero setup. Distributed writes are one pillar of that. The modern stack that just works is the heart.
5
+ The thesis in one line: toil is the modern full-stack tech a developer would actually want, AAA-grade from the very first line, and hyper-scalable at the same time. Even a simple pizza site gets top-tier infrastructure with zero setup. Distributed writes are one pillar of that; the modern stack that just works is the heart.
6
6
 
7
7
  ## The problem with today's stacks
8
8
 
9
- Two problems, really.
9
+ Shipping a good app today means fighting your own infrastructure. Five ways it fights back.
10
10
 
11
- **Read-global, write-central.** Your pages load fast from caches worldwide. But a *write* (a comment, a like, an order) usually travels to one database in one region. A user in Sydney writing to a database in Virginia pays for the round trip. That single region is also a single point of failure.
11
+ **Reads go global, writes go to one region.** Your pages load fast from caches worldwide, but a *write* (a comment, a like, an order) crawls back to a single database in a single region. A user in Sydney writing to Virginia pays for the whole round trip, and that one region is a single point of failure for everyone.
12
12
 
13
- **The ten-vendor tax.** A typical production stack is stitched from rented services: a frontend host, serverless functions, a managed database, auth, email, a queue, a cache, analytics, realtime. Each is its own account, bill, SDK, and failure mode. You did not set out to be a systems integrator, but the stack hands you the job.
13
+ **You became a systems integrator by accident.** A production stack is a dozen rented services stitched together: a frontend host, serverless functions, a managed database, auth, email, a queue, a cache, analytics, realtime. Each is its own account, bill, SDK, and outage. And every one on your *critical path* (what must work for a request to succeed) is a black box you cannot inspect, patch, or secure: when it is slow you are slow, when it is breached part of you is breached.
14
14
 
15
- And every third-party service on your **critical path** (what must work for a request to succeed) is a black box you cannot inspect, patch, or fully secure. When it is slow, you are slow. When it is breached, part of you is breached.
15
+ **It runs on yesterday's tooling.** The typical stack sits on a decade of accumulated legacy: bundler configs, transpiler shims, CommonJS-versus-ESM interop, framework churn, and a `node_modules` folder heavier than the app itself. You fight the toolchain and chase version bumps instead of building. The modern web platform moved on; the stack did not.
16
16
 
17
- The result: a solo builder and a funded startup hit the *same* wall. Good, safe, fast infrastructure means assembling and babysitting a lot of parts, so most people settle for less.
17
+ **Overhead at every layer.** Heavy runtimes, slow builds, serverless cold starts, oversized JavaScript shipped to the browser, and a network hop between every service. Each layer piles on latency and cost that the user feels and you debug.
18
+
19
+ **Fast and safe are opt-in, never the default.** Good performance and real security are things you assemble by hand: a CDN here, a cache there, careful data fetching, region tuning, hardened auth, current cryptography. Miss a piece and you are slow or exposed. The good version is always the extra work, so most people ship the lesser one.
20
+
21
+ The result: a solo builder and a funded startup hit the *same* wall. Top-tier infrastructure means assembling and babysitting a lot of parts, so most settle for less.
18
22
 
19
23
  ## What toil does instead
20
24
 
21
- Close the gap, own the pieces, and make the good version the *default* version. Four pillars.
25
+ Every design decision in toil serves one goal: AAA-grade infrastructure as the *default*, not the thing you assemble by hand. All of it in one framework, not ten rented vendors. Zero configuration, and no distributed-systems or networking expertise required. It just works out of the box, quantum-proof login included, on a stack built for modern tech instead of a decade of legacy tooling.
26
+
27
+ Four pillars.
22
28
 
23
29
  ### 1. AAA-grade from the first line
24
30
 
25
- Top-tier infrastructure on day one, on the smallest project, with zero setup: edge compute (your code runs near users worldwide), one-line post-quantum login, automatic tamper-proofing of your app's code, HTTP/3, and a global database already there.
31
+ Top-tier infrastructure on day one, on the smallest project, with zero setup: edge compute (your code runs near users worldwide), a global database already there, automatic tamper-proofing of every shipped asset (SHA-384 Subresource Integrity), and quantum-proof login in about one line.
32
+
33
+ That login is real post-quantum cryptography. Your password is stretched into a signing key on your device and never reaches the server in a usable form, and the handshake uses ML-DSA and ML-KEM, the NIST-standardized algorithms meant to survive a quantum computer. Most stacks bolt current crypto on by hand, if at all; here it is the default.
26
34
 
27
35
  A pizza site and a planet-scale app start from the same baseline. "AAA-grade" is the actual bar toil grades itself against; see [design principles](./design-principles.md).
28
36
 
@@ -56,15 +64,15 @@ Honest boundary: "owned" means the *core* of a working app is toil's, not that o
56
64
 
57
65
  ### 3. A modern DX that just works
58
66
 
59
- TypeScript end to end, one repo, one deploy, wired by types: change a field on the server and the frontend stops compiling until you fix it (a compile error at your desk, not a production bug).
67
+ Built on today's web platform, not a decade of accumulated legacy: TypeScript end to end, one repo, one deploy, wired by types. Change a field on the server and the frontend stops compiling until you fix it (a compile error at your desk, not a production bug).
60
68
 
61
69
  The toolchain is set up for you: ESLint, Prettier (with a plugin for toil's decorators), an editor plugin, one CLI, and a `doctor` that fixes common problems in place. The docs are even LLM-friendly, so an AI assistant reads your current conventions instead of guessing. More in [The modern stack](./modern-stack.md).
62
70
 
63
- ### 4. Hyper-scalable and distributed (one pillar, not the whole story)
71
+ ### 4. Hyper-scalable and distributed
64
72
 
65
- Your backend compiles to a tiny sandboxed **WebAssembly** module (a compact, locked-down binary that runs at near-native speed), so one edge box safely runs many apps, which makes running near everyone affordable.
73
+ Your backend compiles to a tiny sandboxed **WebAssembly** module (a compact, locked-down binary that runs at near-native speed), modern tech rather than a heavyweight legacy runtime, so one edge box safely runs many apps and running near everyone stays affordable.
66
74
 
67
- And the database, **ToilDB**, distributes the *writes*, not just the reads: every key has one **home** region that orders its writes, while data replicates outward for fast local reads. Distributing writes is the hard part almost nobody does. The trade is eventual consistency: a far read can lag a few milliseconds. See [How toil works](./how-it-works.md) and [How toil is distributed](./distributed.md).
75
+ And the database, **ToilDB**, distributes the *writes*, not just the reads: every key has one **home** region that orders its writes, while data replicates outward for fast local reads. Distributing writes is the hard part almost nobody does. toil is built to do it worldwide and the mechanism is real and tested; live multi-region deployment is configuration-gated rather than on by default, and once it is on, a far read can lag a few milliseconds (the eventual-consistency trade). See [How toil works](./how-it-works.md) and [How toil is distributed](./distributed.md).
68
76
 
69
77
  ## Who it is for
70
78
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "toiljs",
3
3
  "type": "module",
4
- "version": "0.0.101",
4
+ "version": "0.0.103",
5
5
  "author": "Dacely",
6
6
  "description": "The modern React framework: a file-based React frontend and a ToilScript-compiled WebAssembly backend.",
7
7
  "repository": {
@@ -169,26 +169,42 @@ function realm(ctx: RouteContext): string {
169
169
  return h;
170
170
  }
171
171
 
172
- /**
173
- * Whether this domain requires a confirmed email before login. A plain
174
- * (tenant-readable) env var so an app can opt in itself; the edge ALSO force-sets
175
- * it to "true" from the per-domain platform toggle `HostConfig.require_email_confirmation`
176
- * (reserved key `TOIL_AUTH_REQUIRE_EMAIL_CONFIRMATION`), so a Dacely per-domain
177
- * setting can turn it on without the app changing a line.
178
- */
179
- function requireConfirmation(): bool {
180
- const v = Environment.get('AUTH_REQUIRE_EMAIL_CONFIRMATION');
172
+ /** A lenient truthy read of a plain env var, ALIGNED with the edge's HostConfig
173
+ * parse (`!matches!(v.trim(), "0"|"false"|"no"|"off")`). A strict `== "true"` would
174
+ * let a tenant slip a truthy-but-non-canonical value ("1"/"on"/"TRUE"/"true ") past
175
+ * the guest while the edge treated it as opted-in and skipped the force-on
176
+ * injection, defeating the platform mandate. Same parse on both sides closes that. */
177
+ function envTruthy(key: string): bool {
178
+ const v = Environment.get(key);
181
179
  if (v == null) return false;
182
- // Lenient truthy, ALIGNED with the edge's HostConfig parse
183
- // (`!matches!(v.trim(), "0"|"false"|"no"|"off")`). A strict `== "true"` here
184
- // let a tenant slip a truthy-but-non-canonical value ("1"/"on"/"TRUE"/"true ")
185
- // past the guest while the edge treated it as "already opted in" and skipped
186
- // the force-on injection -> the platform mandate was defeatable. Same parse on
187
- // both sides closes that gap.
188
180
  const t = v.trim().toLowerCase();
189
181
  return t.length != 0 && t != '0' && t != 'false' && t != 'no' && t != 'off';
190
182
  }
191
183
 
184
+ /**
185
+ * Whether REGISTRATION emails a confirm link and stores the account UNCONFIRMED.
186
+ * This is the register-time email-verification switch; on its own it does NOT block
187
+ * login (an unconfirmed user can still sign in; the app can nudge them to verify).
188
+ * Turned on by `AUTH_EMAIL_CONFIRMATION`, and IMPLIED by {@link requireConfirmation}
189
+ * (you cannot require a confirmation you never send).
190
+ */
191
+ function sendConfirmationEmail(): bool {
192
+ return envTruthy('AUTH_EMAIL_CONFIRMATION') || requireConfirmation();
193
+ }
194
+
195
+ /**
196
+ * Whether this domain BLOCKS login until the email is confirmed (the stricter
197
+ * form; it also sends the confirm email at register, via {@link sendConfirmationEmail}).
198
+ * A plain (tenant-readable) env var so an app can opt in itself; the edge ALSO
199
+ * force-sets it to "true" from the per-domain platform toggle
200
+ * `HostConfig.require_email_confirmation` (reserved key
201
+ * `TOIL_AUTH_REQUIRE_EMAIL_CONFIRMATION`), so a Dacely per-domain setting can turn it
202
+ * on without the app changing a line.
203
+ */
204
+ function requireConfirmation(): bool {
205
+ return envTruthy('AUTH_REQUIRE_EMAIL_CONFIRMATION');
206
+ }
207
+
192
208
  /**
193
209
  * The absolute origin the emailed confirm/reset links point at. Prefer the
194
210
  * tenant-set `PUBLIC_BASE_URL` (e.g. `https://app.example.com`); fall back to the
@@ -603,7 +619,11 @@ class Auth {
603
619
  return Response.bytes(new DataWriter().writeU8(ST_EMAIL_TAKEN).toBytes());
604
620
  }
605
621
 
606
- const mustConfirm = requireConfirmation();
622
+ // Send the confirm email + store unconfirmed when EITHER flag is on
623
+ // (AUTH_EMAIL_CONFIRMATION or the stricter AUTH_REQUIRE_EMAIL_CONFIRMATION).
624
+ // Whether login is then BLOCKED is a separate check (requireConfirmation,
625
+ // used in login/finish), so a domain can verify-at-register without gating.
626
+ const mustConfirm = sendConfirmationEmail();
607
627
  const a = new AuthAccount();
608
628
  a.username = username;
609
629
  a.email = email;