dokkebi-cli
v1.0.2
Published
QuickJS WASM ClientSide Backend Framework - Dokkebi
Downloads
511
Maintainers
Readme
dokkebi-cli
![]()
A client-side serverless framework where the backend runs in the browser
Dokkebi is an innovative framework that compiles backend TypeScript into QuickJS WASM and runs it directly in the browser. APIs work without a server, and database communication is handled securely through an E2E-encrypted proxy.
"Zero-cost MVP operations"
Building and deploying a service consumes too many resources—from architecture design to infrastructure setup. AI has dramatically accelerated development, but the barrier of server management and maintenance costs remains.
Dokkebi starts from a firm philosophy: use the user's resources wherever possible to deliver a smooth service at no cost. Whether you have 10 or 100 services, we bring operating costs for unpredictable MVP-stage products to exactly zero.
Core features and benefits
Zero Cost: Eliminate infrastructure management and server maintenance costs entirely
One-Click Deploy: Deploy and roll back frontend and backend together in one click (Cloudflare environment)
No Server, No Ops: No need to manage traditional server infrastructure—load balancers, port forwarding, Linux hardening, and the like.
Two operating modes
Dokkebi supports two modes tailored to your project's needs.
Serverless Mode: Uses Cloudflare Functions to validate the Dokkebi environment and runs as a pure client-side backend.
Server Mode: Use when E2E encryption, payment verification, or business-logic protection is required, or when you want to avoid cloud vendor lock-in.
A security architecture that reframes the problem
"No server means nothing to hack."
Shipping backend source to the client (browser) may sound reckless at first. Dokkebi does not try to make hacking impossible; instead, it shifts the security paradigm by exponentially increasing the time and cost of attacks until they are no longer worthwhile.
Heavy obfuscation and encryption: Backend logic is compiled to WASM with aggressive encryption and obfuscation.
Whitelist query validation: Unapproved or abnormal queries are blocked at the proxy layer and never reach the database.
Active Defense: Detects anomalous client behavior and blocks access immediately.
Browser
├── Vue / React frontend
└── QuickJS WASM backend (runs in-browser)
│
│ ECDH P-256 + HKDF + AES-256-GCM + HMAC-SHA256
▼
DB proxy (/api/_dokkebi/db)
┌─────────────────────────────────────────┐
│ 🖥 Server mode dok serve → Node.js │
│ ☁ Serverless Cloudflare Pages Fn │
└─────────────────────────────────────────┘
│
▼
DB (Cloudflare D1 / Supabase / Appwrite)Quick start
npm install -g dokkebi-cli
dok create my-app # Interactive project scaffolding
cd my-app
dok dev # Auto build + hot-reload dev server
open http://localhost:5173Key features
True serverless
- Backend runs in the browser as QuickJS WASM—no separate server process
- Familiar Express-style API (
dokkebi:runtime) for routes, middleware, and DB access - Built-in type-safe query builder (
dokkebi-dsl)
Multi-layer security applied automatically
Multiple security layers are applied automatically during build and deploy—no extra configuration required.
| Category | Security | Description | | -------- | -------- | ----------- | | Transport encryption | ECDH P-256 + AES-256-GCM + HMAC-SHA256 | Forward secrecy, bidirectional encryption, request signing | | Replay protection | Nonce + Timestamp (±30s) + timingSafeEqual | Blocks replay and timing attacks | | SQL defense | SQL Allowlist + Query Registry + db.raw() blocked | Build-time allowlist, query hash registration, arbitrary SQL blocked | | Secret protection | Env Opaque Handle | Sensitive vars never embedded in plaintext in the bundle | | Code protection | Dual-protected bundle | JS obfuscation → AES-256-GCM encryption | | Data isolation | Tenant Policy (pseudo-RLS) | Per-table session tenant conditions enforced automatically | | Access control | Authorization Policy | JWT role-based operation and table-level permission checks | | Session protection | OPFS session encryption (PBKDF2 + AES-GCM) | Defends against browser session theft | | Active defense | Active Defense Layer (opt-in) | Real-time blocking of anomalous behavior via behavioral analysis | | Execution permit | Signed Unlock Token (opt-in) | Worker-signed capability before paid or high-cost features run | | Auth hardening | WebAuthn Passkey (opt-in) | Stronger defense against phishing and replay | | Deploy safety | Preflight checks + build signing | Pre-deploy security config review, supply-chain traceability | | Header protection | CSP · X-Frame-Options auto-applied | Blocks XSS, clickjacking, MIME sniffing |
Defense by attack scenario
| Attack scenario | Defense stack | Defense flow | | --------------- | ------------- | ------------ | | 🔑 Secret theft | Env Opaque Handle | Build-time auto-transform → runtime Host closure isolation | | 🌐 Network eavesdropping / tampering | E2E encryption | ECDH key exchange → AES-GCM + HMAC bidirectional encryption | | 🛡 Code reversing | Dual-protected bundle | JS obfuscation → AES-256-GCM encryption | | 💉 SQL injection | Triple SQL defense | Allowlist → Query Registry → dangerous syntax validation | | 👤 Cross-user data access | Tenant Policy (pseudo-RLS) | Session binding → auto-injected WHERE / deny | | 🍪 Session theft | OPFS session encryption | PBKDF2 100K + AES-GCM + origin salt | | 🔓 Feature permission bypass | Signed Unlock Token | Short-lived execution permit signed with Worker-only secret |
Parallel SELECT (DB read speed)
The browser bootstrap (/api/_dokkebi/db client injected by dokkebi-cli) uses a serial queue for DB calls to preserve replay protection and nonce ordering. However, read-only queries whose string starts with SELECT bypass this queue and can send network requests concurrently, reducing round-trip wait when multiple independent reads overlap.
- Stays serial (queued):
INSERT/UPDATE/DELETE, SQL starting withWITH(CTEs,WITH … INSERT, etc.), tenant setup, capability channels—paths that need counter and ordering guarantees. - Runtime helper:
parallelReads([...])indokkebi:runtimebundles multiple readPromises withPromise.allwithin the same request; use it with the bootstrap behavior above to make parallel SELECT intent explicit in code.
Developer experience
dok dev— one command for build + server + hot reloaddok deploy— one command for build + deploy + domain wiring + security headersdok policy:scaffold— auto-generate security policies from model/controller analysis- Operations admin (
/_dokkebi/_panel) — real-time requests, errors, and security event dashboard - Automatic error collection — WASM errors + browser uncaught exceptions logged automatically
- 12-language CLI — Korean, English, 日本語, 中文, Deutsch, and more
- Upgrade existing projects —
dok updatesafely upgrades without touching user code
CLI commands
| Command | Description |
| ------- | ----------- |
| dok create [name] | Interactive project creation (Vue/React + D1/Supabase/Appwrite) |
| dok dev [src] | Dev server (auto build + hot reload, default port 5173) |
| dok build [src] | QuickJS WASM build + frontend integration |
| dok serve [src] | Production Node.js server (default port 5174) |
| dok deploy [src] | Cloudflare Pages deploy (R2/S3 frontend + domain automation) |
| dok migrate [src] | Apply SQL migrations |
| dok update [src] | Apply latest version to existing project (preserves user code) |
| dok security [src] | Security opt-in interactive (--status for text-only) |
| dok policy:scaffold [src] | Auto-generate Tenant/Authorization Policy from model analysis |
| dok lang [code] | Change CLI language (12 languages supported) |
See
dok <command> --helpfor detailed options per command.
Backend code example
// backend/controllers/users.controller.ts
import { router, db, use, cors, jwtAuth } from 'dokkebi:runtime';
import { users } from '../models/index.js';
use(cors({ origin: '*' }));
use(jwtAuth(process.env.JWT_SECRET, ['/api/auth/login']));
router.get('/api/users', async (ctx) => {
const result = await db.select(users).exec();
return ctx.json(result.rows);
});
router.post('/api/users', async (ctx) => {
const { name, email } = ctx.body;
await db.insert(users).values({ id: crypto.randomUUID(), name, email }).exec();
return ctx.json({ ok: true }, 201);
});// backend/models/index.ts
import { defineTable, text } from 'dokkebi-dsl';
export const users = defineTable('users', {
id: text('id').primaryKey(),
name: text('name').notNull(),
email: text('email').notNull().unique(),
created_at: text('created_at').default('CURRENT_TIMESTAMP'),
});Deployment modes
| | Development (dok dev) | Server (dok serve) | Serverless (dok deploy) |
| - | ----------------------- | -------------------- | ------------------------- |
| Runtime | Node.js (local) | Node.js (server) | Cloudflare Pages Edge |
| Hot reload | ✓ | — | — |
| DB proxy | Node.js | Node.js | Pages Function |
| Default port | 5173 | 5174 | — |
Supported databases
| DB | proxyMode | Notes | | -- | --------- | ----- | | Cloudflare D1 | server / serverless | Recommended (serverless-native) | | Supabase | server | REST API | | Appwrite | server | REST API |
Security options — start with what each attack is blocked by
The security section in dokkebi.config.js has several user-toggleable options. One document summarizes which attack each option blocks and how it is applied.
- Current project:
dok security— in a terminal (TTY), move with arrows + Enter, toggle ON/OFF and levels, see per-item threat summary and required.env/config. Saves patchdokkebi.config.jsautomatically (failed lines get snippet guidance) +.bak. - Text only:
dok security --status(CI / non-TTY). Force TUI:dok security --interactive. - ➡ docs/SECURITY_OPTIN.md — opt-in quick reference (option ↔ attack ↔ config, one line each).
- ➡ docs/SECURITY_OPTIONS.md — per-option attack cases / examples / ops notes, including option ↔ attack mapping table.
Recommended default: enable only capabilities.enabled: true and attestation turns on automatically; client prev-token attachment and recursive unlock are handled automatically. dok build warns if cost-bearing routes lack capability declarations.
Production checklist (external attacker perspective)
We do not assume malicious dependencies or a compromised build machine. This checklist covers what to verify in production assuming only access to the deployed URL—static bundles (JSON·JS·WASM) and public APIs.
Query / SQL boundary
- Cloudflare Pages Secret has
DOKKEBI_QUERY_MODE=strict(or equivalent fail-closed operation). Do not useauto/learnin production. dist/dokkebi/query-registry.jsonis non-empty, and empty-registry deploy is blocked viadok deploy --strict-registryorqueryRegistry.strict: trueindokkebi.config.js.- Prefer
rawAllowed: falseinsql-allowlist.jsonand avoiddb.raw(). - Allowed tables and operations are minimal (no unnecessary
SELECT *, wide JOINs, or subquery sprawl).
Tenant / authorization (server trust boundary)
- Do not authorize from
bindSession()or tenant meta sent by the client alone. Restrict real data access via D1 schema/app-level enforcement or separate trusted server verification / RLS (where the platform supports it). policy(Tenant) indokkebi.config.jsis enabled, andpolicy.strictis not disabled in production.authorizationrules are defined; operate close tostrictwhen needed (defaultwarnalone may be insufficient).
Minimize exposed surface
- If you do not need
/_dokkebi/_panel, put it behind routing/IP restrictions or a private network. If you use it, set a longDOKKEBI_ADMIN_PASSWORDand restrict IPs withDOKKEBI_PANEL_ALLOWED_IPSwhen possible. - Be aware that
/api/_dokkebi/logcan pollute storage or pressure quotas; use rate limits and monitoring if needed. dok serveis for local/internal networks only. Do not expose0.0.0.0binding to the internet.
Build / deploy quality
- Do not disable
--preflightondok deploy; use--preflight-strictto fail deploy on warnings when needed. - Optionally reviewed
security.strictCsp: true(trade off with browser/CDN compatibility). - Allowlist external images/APIs/iframes per app via
security.cspExtraHosts(e.g.imgSrc: ['https://api.dicebear.com']) — the baseline CSP stays strict. Seedocs/SECURITY_OPTIONS.md§12. - Reduce frontend XSS (with CSP allowing
unsafe-inline/unsafe-eval, XSS can lead to compromise of in-browser execution context).
Assume reconnaissance is possible
- Treat
/dokkebi/sql-allowlist.json,query-registry.json, etc. as potentially public and confirm design ensures their contents alone cannot reach other users' data.
Plugins
Extend the WASM backend safely. Enable in plugins in dokkebi.config.js.
| Plugin | Capability | Security | | ------ | ---------- | -------- | | fetch | External HTTP from WASM | Domain whitelist + concurrent request limit + timeout | | bundle | In-browser esbuild-wasm bundling | OPFS sandbox + CDN external |
Operations admin IP restriction
/_dokkebi/_panel can be restricted with an IP allowlist by setting security.panelIpGuard: true in dokkebi.config.js and DOKKEBI_PANEL_ALLOWED_IPS in .env or Cloudflare Pages Secrets. Default is false.
// dokkebi.config.js
export default {
security: {
panelIpGuard: true,
},
};DOKKEBI_ADMIN_PASSWORD=your_secure_password
DOKKEBI_PANEL_ALLOWED_IPS=203.0.113.10,198.51.100.0/24When security.panelIpGuard is false, DOKKEBI_PANEL_ALLOWED_IPS is ignored. When true but env is empty, dok build prints a warning. Comma-separated IPs or IPv4 CIDR are supported; dok dev, dok serve, and Cloudflare Pages Functions panel share the same config.
Existing projects get panelIpGuard: false default and .env.example DOKKEBI_PANEL_ALLOWED_IPS entry reinforced on dok update.
Signed Unlock Token
Paid features, high-cost AI calls, admin export, and similar should not rely on browser-only if (isPremium)—require a Worker-signed execution permit instead.
// dokkebi.config.js
export default {
security: {
capabilities: {
enabled: true,
secretEnv: 'DOKKEBI_CAPABILITY_SECRET',
features: {
'image.generate': {
roles: ['premium', 'admin'],
ttlMs: 10000,
routes: ['POST /api/ai/image'],
},
},
},
},
};With routes set, dok build auto-inserts a guard before the matching Dokkebi runtime route. Users need not call capability.unlock() in handlers manually; passing requests get ctx.capability populated.
You can also declare near controllers via JSDoc:
/**
* @dokkebi-capability feature:image.generate route:"POST /api/ai/image" roles:['premium','admin'] ttl:10000
*/
router.post('/api/ai/image', async (ctx) => {
// Bind ctx.capability.token/proof into execution params or server request material
});For finer manual state binding, call the API directly:
import { capability } from 'dokkebi:runtime';
const unlock = await capability.unlock('image.generate', {
state: { projectId, promptHash },
jwt: userToken,
});
if (!unlock.ok) throw new Error(unlock.error);
// token/proof must be used as execution material, not as a simple flagSet DOKKEBI_CAPABILITY_SECRET in .env or Cloudflare Pages Secrets to a random value of at least 32 bytes. This raises the cost of permission-flag/branch-patch attacks but is not DRM that fully blocks local dumps by already-authorized users.
Capability Chain
You can require a valid token from another capability before issuing a specific one.
features: {
'auth.verified': { public: true, ttlMs: 60000 },
'image.generate': {
roles: ['premium','admin'],
ttlMs: 10000,
requires: { prev: ['auth.verified'] },
},
}const a = await capability.unlock('auth.verified');
const b = await capability.unlock('image.generate', {
prev: [{ feature: 'auth.verified', token: a.capability.token }],
});The Worker verifies HMAC signatures, expiry, sid match, and feature match for all prerequisite tokens.
Bundle Attestation
At build time, encrypted bundle bytes are split into 16KB chunks and a SHA-256 manifest is generated. Each session, the Worker sends random chunk indices as a challenge and compares the client response to the manifest. Tampered bundles cannot pass the challenge.
// dokkebi.config.js
security: {
attestation: {
enabled: true,
sampleSize: 4, // 1–16, default 4
ttlMs: 5 * 60_000, // 30s–30min, default 5 min
},
capabilities: {
enabled: true,
features: {
'image.generate': {
roles: ['premium','admin'],
requires: { attest: true }, // issue only after attest passes
},
},
},
}When the server returns CAPABILITY_ATTEST_REQUIRED for a capability with requires.attest: true, the client automatically runs the _attest challenge and retries once. No user code changes required.
See SECURITY.md §3.6 for details and limitations.
Requirements
- Node.js 20+ — required by Cloudflare Wrangler.
dok deploycallswrangler pages deployinternally, so deploy fails on Node 18. Build/local dev may work on 18, but 20 LTS or newer is recommended.
Installation
# Global install
npm install -g dokkebi-cli
# Or local install
npm install dokkebi-cli
npx dok --helpChange language
dok langLicense
ELv2
