covara 0.7.0 → 0.8.0

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.
Files changed (204) hide show
  1. package/README.md +98 -62
  2. package/dist/cli/args.d.ts +14 -0
  3. package/dist/cli/args.d.ts.map +1 -0
  4. package/dist/cli/args.js +78 -0
  5. package/dist/cli/args.js.map +1 -0
  6. package/dist/cli/commands/data.d.ts +2 -0
  7. package/dist/cli/commands/data.d.ts.map +1 -0
  8. package/dist/cli/commands/data.js +31 -0
  9. package/dist/cli/commands/data.js.map +1 -0
  10. package/dist/cli/commands/db.d.ts +2 -0
  11. package/dist/cli/commands/db.d.ts.map +1 -0
  12. package/dist/cli/commands/db.js +100 -0
  13. package/dist/cli/commands/db.js.map +1 -0
  14. package/dist/cli/commands/dev.d.ts +2 -0
  15. package/dist/cli/commands/dev.d.ts.map +1 -0
  16. package/dist/cli/commands/dev.js +125 -0
  17. package/dist/cli/commands/dev.js.map +1 -0
  18. package/dist/cli/commands/env.d.ts +2 -0
  19. package/dist/cli/commands/env.d.ts.map +1 -0
  20. package/dist/cli/commands/env.js +94 -0
  21. package/dist/cli/commands/env.js.map +1 -0
  22. package/dist/cli/commands/import-export.d.ts +3 -0
  23. package/dist/cli/commands/import-export.d.ts.map +1 -0
  24. package/dist/cli/commands/import-export.js +156 -0
  25. package/dist/cli/commands/import-export.js.map +1 -0
  26. package/dist/cli/commands/migrate.d.ts +2 -0
  27. package/dist/cli/commands/migrate.d.ts.map +1 -0
  28. package/dist/cli/commands/migrate.js +12 -0
  29. package/dist/cli/commands/migrate.js.map +1 -0
  30. package/dist/cli/commands/push.d.ts +2 -0
  31. package/dist/cli/commands/push.d.ts.map +1 -0
  32. package/dist/cli/commands/push.js +45 -0
  33. package/dist/cli/commands/push.js.map +1 -0
  34. package/dist/cli/commands/run.d.ts +2 -0
  35. package/dist/cli/commands/run.d.ts.map +1 -0
  36. package/dist/cli/commands/run.js +54 -0
  37. package/dist/cli/commands/run.js.map +1 -0
  38. package/dist/cli/commands/seed.d.ts +2 -0
  39. package/dist/cli/commands/seed.d.ts.map +1 -0
  40. package/dist/cli/commands/seed.js +32 -0
  41. package/dist/cli/commands/seed.js.map +1 -0
  42. package/dist/cli/commands/studio.d.ts +2 -0
  43. package/dist/cli/commands/studio.d.ts.map +1 -0
  44. package/dist/cli/commands/studio.js +22 -0
  45. package/dist/cli/commands/studio.js.map +1 -0
  46. package/dist/cli/commands/types.d.ts +2 -0
  47. package/dist/cli/commands/types.d.ts.map +1 -0
  48. package/dist/cli/commands/types.js +28 -0
  49. package/dist/cli/commands/types.js.map +1 -0
  50. package/dist/cli/config.d.ts +28 -0
  51. package/dist/cli/config.d.ts.map +1 -0
  52. package/dist/cli/config.js +81 -0
  53. package/dist/cli/config.js.map +1 -0
  54. package/dist/cli/drizzle-bridge.d.ts +29 -0
  55. package/dist/cli/drizzle-bridge.d.ts.map +1 -0
  56. package/dist/cli/drizzle-bridge.js +85 -0
  57. package/dist/cli/drizzle-bridge.js.map +1 -0
  58. package/dist/cli/index.d.ts +2 -1
  59. package/dist/cli/index.d.ts.map +1 -1
  60. package/dist/cli/index.js +74 -20
  61. package/dist/cli/index.js.map +1 -1
  62. package/dist/cli/prompt.d.ts +2 -0
  63. package/dist/cli/prompt.d.ts.map +1 -0
  64. package/dist/cli/prompt.js +16 -0
  65. package/dist/cli/prompt.js.map +1 -0
  66. package/dist/cli/templates/package-json.js +1 -1
  67. package/dist/cli/worker.d.ts +2 -0
  68. package/dist/cli/worker.d.ts.map +1 -0
  69. package/dist/cli/worker.js +120 -0
  70. package/dist/cli/worker.js.map +1 -0
  71. package/dist/client/file-upload.d.ts +2 -1
  72. package/dist/client/file-upload.d.ts.map +1 -1
  73. package/dist/client/file-upload.js +5 -5
  74. package/dist/client/file-upload.js.map +1 -1
  75. package/dist/client/live-store.d.ts.map +1 -1
  76. package/dist/client/live-store.js +12 -6
  77. package/dist/client/live-store.js.map +1 -1
  78. package/dist/client/react-files.js +1 -1
  79. package/dist/client/react-files.js.map +1 -1
  80. package/dist/client/subscription-manager.d.ts.map +1 -1
  81. package/dist/client/subscription-manager.js +7 -0
  82. package/dist/client/subscription-manager.js.map +1 -1
  83. package/dist/htmx/client/runtime.d.ts +2 -0
  84. package/dist/htmx/client/runtime.d.ts.map +1 -0
  85. package/dist/htmx/client/runtime.js +195 -0
  86. package/dist/htmx/client/runtime.js.map +1 -0
  87. package/dist/htmx/context.d.ts +16 -0
  88. package/dist/htmx/context.d.ts.map +1 -0
  89. package/dist/htmx/context.js +52 -0
  90. package/dist/htmx/context.js.map +1 -0
  91. package/dist/htmx/forms.d.ts +3 -0
  92. package/dist/htmx/forms.d.ts.map +1 -0
  93. package/dist/htmx/forms.js +32 -0
  94. package/dist/htmx/forms.js.map +1 -0
  95. package/dist/htmx/ids.d.ts +11 -0
  96. package/dist/htmx/ids.d.ts.map +1 -0
  97. package/dist/htmx/ids.js +27 -0
  98. package/dist/htmx/ids.js.map +1 -0
  99. package/dist/htmx/index.d.ts +11 -0
  100. package/dist/htmx/index.d.ts.map +1 -0
  101. package/dist/htmx/index.js +15 -0
  102. package/dist/htmx/index.js.map +1 -0
  103. package/dist/htmx/live.d.ts +39 -0
  104. package/dist/htmx/live.d.ts.map +1 -0
  105. package/dist/htmx/live.js +37 -0
  106. package/dist/htmx/live.js.map +1 -0
  107. package/dist/htmx/page.d.ts +14 -0
  108. package/dist/htmx/page.d.ts.map +1 -0
  109. package/dist/htmx/page.js +59 -0
  110. package/dist/htmx/page.js.map +1 -0
  111. package/dist/htmx/render-util.d.ts +2 -0
  112. package/dist/htmx/render-util.d.ts.map +1 -0
  113. package/dist/htmx/render-util.js +15 -0
  114. package/dist/htmx/render-util.js.map +1 -0
  115. package/dist/htmx/server.d.ts +21 -0
  116. package/dist/htmx/server.d.ts.map +1 -0
  117. package/dist/htmx/server.js +286 -0
  118. package/dist/htmx/server.js.map +1 -0
  119. package/dist/htmx/sse-render.d.ts +10 -0
  120. package/dist/htmx/sse-render.d.ts.map +1 -0
  121. package/dist/htmx/sse-render.js +40 -0
  122. package/dist/htmx/sse-render.js.map +1 -0
  123. package/dist/htmx/template-gen.d.ts +7 -0
  124. package/dist/htmx/template-gen.d.ts.map +1 -0
  125. package/dist/htmx/template-gen.js +38 -0
  126. package/dist/htmx/template-gen.js.map +1 -0
  127. package/dist/resource/hook.d.ts.map +1 -1
  128. package/dist/resource/hook.js +101 -24
  129. package/dist/resource/hook.js.map +1 -1
  130. package/dist/resource/relations.d.ts +15 -4
  131. package/dist/resource/relations.d.ts.map +1 -1
  132. package/dist/resource/relations.js +146 -26
  133. package/dist/resource/relations.js.map +1 -1
  134. package/dist/resource/subscription.d.ts +15 -2
  135. package/dist/resource/subscription.d.ts.map +1 -1
  136. package/dist/resource/subscription.js +184 -3
  137. package/dist/resource/subscription.js.map +1 -1
  138. package/dist/resource/track-mutations.d.ts.map +1 -1
  139. package/dist/resource/track-mutations.js +11 -1
  140. package/dist/resource/track-mutations.js.map +1 -1
  141. package/dist/resource/types.d.ts +8 -0
  142. package/dist/resource/types.d.ts.map +1 -1
  143. package/dist/server/admin-bypass.d.ts +7 -0
  144. package/dist/server/admin-bypass.d.ts.map +1 -0
  145. package/dist/server/admin-bypass.js +22 -0
  146. package/dist/server/admin-bypass.js.map +1 -0
  147. package/dist/server/app.d.ts +9 -0
  148. package/dist/server/app.d.ts.map +1 -1
  149. package/dist/server/app.js +101 -1
  150. package/dist/server/app.js.map +1 -1
  151. package/dist/server/impersonation.d.ts +18 -0
  152. package/dist/server/impersonation.d.ts.map +1 -0
  153. package/dist/server/impersonation.js +53 -0
  154. package/dist/server/impersonation.js.map +1 -0
  155. package/dist/shared/escape.d.ts +3 -0
  156. package/dist/shared/escape.d.ts.map +1 -0
  157. package/dist/shared/escape.js +12 -0
  158. package/dist/shared/escape.js.map +1 -0
  159. package/dist/storage/local.d.ts +4 -0
  160. package/dist/storage/local.d.ts.map +1 -1
  161. package/dist/storage/local.js +5 -0
  162. package/dist/storage/local.js.map +1 -1
  163. package/dist/storage/resource.d.ts +5 -11
  164. package/dist/storage/resource.d.ts.map +1 -1
  165. package/dist/storage/resource.js +156 -194
  166. package/dist/storage/resource.js.map +1 -1
  167. package/dist/ui/admin-auth.d.ts +6 -0
  168. package/dist/ui/admin-auth.d.ts.map +1 -1
  169. package/dist/ui/admin-auth.js +59 -1
  170. package/dist/ui/admin-auth.js.map +1 -1
  171. package/dist/ui/data-explorer.d.ts.map +1 -1
  172. package/dist/ui/data-explorer.js +91 -4
  173. package/dist/ui/data-explorer.js.map +1 -1
  174. package/dist/ui/html/client/data-explorer-app.d.ts.map +1 -1
  175. package/dist/ui/html/client/data-explorer-app.js +20 -7
  176. package/dist/ui/html/client/data-explorer-app.js.map +1 -1
  177. package/dist/ui/html/client/runtime.d.ts.map +1 -1
  178. package/dist/ui/html/client/runtime.js +70 -2
  179. package/dist/ui/html/client/runtime.js.map +1 -1
  180. package/dist/ui/html/icons.d.ts.map +1 -1
  181. package/dist/ui/html/icons.js +2 -0
  182. package/dist/ui/html/icons.js.map +1 -1
  183. package/dist/ui/html/layout.d.ts +1 -0
  184. package/dist/ui/html/layout.d.ts.map +1 -1
  185. package/dist/ui/html/layout.js +274 -146
  186. package/dist/ui/html/layout.js.map +1 -1
  187. package/dist/ui/html/pages/filter-tester.d.ts.map +1 -1
  188. package/dist/ui/html/pages/filter-tester.js +15 -0
  189. package/dist/ui/html/pages/filter-tester.js.map +1 -1
  190. package/dist/ui/html/pages/users.d.ts.map +1 -1
  191. package/dist/ui/html/pages/users.js +8 -1
  192. package/dist/ui/html/pages/users.js.map +1 -1
  193. package/dist/ui/index.d.ts +1 -1
  194. package/dist/ui/index.d.ts.map +1 -1
  195. package/dist/ui/index.js +1 -1
  196. package/dist/ui/index.js.map +1 -1
  197. package/dist/ui/middleware.d.ts.map +1 -1
  198. package/dist/ui/middleware.js +121 -5
  199. package/dist/ui/middleware.js.map +1 -1
  200. package/dist/ui/schema-registry.d.ts +5 -0
  201. package/dist/ui/schema-registry.d.ts.map +1 -1
  202. package/dist/ui/schema-registry.js +14 -0
  203. package/dist/ui/schema-registry.js.map +1 -1
  204. package/package.json +6 -2
package/README.md CHANGED
@@ -4,6 +4,14 @@
4
4
 
5
5
  <h1 align="center">Covara</h1>
6
6
 
7
+ <p align="center">
8
+ <strong>📚 <a href="https://kahveciderin.github.io/covara">Documentation</a></strong>
9
+ &nbsp;·&nbsp;
10
+ <a href="https://kahveciderin.github.io/covara/quick-start">Quick Start</a>
11
+ &nbsp;·&nbsp;
12
+ <a href="https://kahveciderin.github.io/covara/tutorial">Tutorial</a>
13
+ </p>
14
+
7
15
  **Your Drizzle schema is already a backend.** Covara turns it into a complete, production-ready API — REST endpoints, real-time subscriptions, auth, file uploads, billing, email, and background jobs — with a type-safe, offline-first TypeScript client on the other end. Built on [Hono](https://hono.dev), it runs standalone on Node or at the edge on Cloudflare Workers.
8
16
 
9
17
  ## The Goal
@@ -44,7 +52,7 @@ function TodoList() {
44
52
  ### Core API
45
53
  - **Automatic REST API** - Full CRUD endpoints from your Drizzle schema
46
54
  - **Real-time Subscriptions** - SSE with changelog-based updates, sequence numbers, and seamless reconnection
47
- - **Relations & Joins** - `belongsTo`, `hasOne`, `hasMany`, `manyToMany` with efficient batch loading
55
+ - **Relations & Joins** - `belongsTo`, `hasOne`, `hasMany`, `manyToMany` with efficient batch loading, optional foreign-key **auto-discovery** (`autoRelations`), and **scope-enforced includes** (a relation never reveals rows the user couldn't read directly)
48
56
  - **RSQL Filtering** - Comprehensive query language (30+ operators) plus custom operators
49
57
  - **Cursor Pagination** - Keyset pagination with multi-field ordering
50
58
  - **Aggregations** - Group by, count, sum, avg, min, max, with `HAVING` filtering on aggregate output — available as a one-shot query or a live subscription (`useLiveAggregate`) that recomputes on every change
@@ -82,7 +90,8 @@ function TodoList() {
82
90
 
83
91
  ### File Storage
84
92
  - **Storage Adapters** - Local disk, S3, Cloudflare R2 (native binding or S3-compat), and in-memory behind one `StorageAdapter` interface
85
- - **File Resources** - `useFileResource` generates upload/download/list/delete endpoints with MIME and size validation, per-user key generation, and auth scopes
93
+ - **File Resources** - First-class resources with an upload/download layer: `app.fileResource(...)` chains like any resource and inherits the full CRUD/hooks/procedures/relations/subscriptions/scopes surface, plus MIME/size validation, per-user keys, and storage cleanup on delete
94
+ - **Zero-config local serving** - `createCovara` auto-serves a local adapter's `baseUrl` (no manual `serveStatic`); admin data explorer gets a per-row Download action
86
95
  - **Presigned URLs** - Optional direct-to-bucket uploads/downloads with configurable expiry
87
96
  - **React Hooks** - `useFileUpload` (with progress), `useFile`, `useFiles`; `getDownloadUrl()` for React Native
88
97
 
@@ -117,6 +126,13 @@ function TodoList() {
117
126
  - **Auth Strategies** - OIDC (PKCE flow, token refresh), JWT, bearer, API key, or cookie sessions — selected per client or auto-detected
118
127
  - **HMR-safe** - `getOrCreateClient` for development
119
128
 
129
+ ### Server-rendered htmx (Beta)
130
+ - **One JSX page → full app** - `app.page(path, Component)` server-renders a page whose `<Live>` regions auto-generate the htmx endpoints (list/create/update/delete/subscribe). Covara generates wiring, not UI components
131
+ - **Live by default** - each region streams server-rendered fragments over SSE (reusing the existing subscription engine); rows update in place as anyone mutates the resource
132
+ - **Optimistic & offline** - new rows insert once via the live SSE (no duplicate/phantom), deletes are optimistic, and mutations queue offline and replay on reconnect
133
+ - **No client framework** - vendored htmx core + a tiny runtime, served and injected automatically
134
+ - **Beta** - newer than the JSON API + TypeScript client; the API may still change
135
+
120
136
  ### Environment Variables
121
137
  - **Type-safe Configuration** - Define and validate env vars with Zod via `createEnv` / `envVariable`
122
138
  - **Public and Private Vars** - `PUBLIC_`-prefixed or explicitly-marked vars served to clients via `usePublicEnv` (with ETag)
@@ -124,6 +140,7 @@ function TodoList() {
124
140
 
125
141
  ### Developer Experience
126
142
  - **Project Scaffolding** - `npx covara create my-app` (Node/Workers templates, SQLite/Postgres), plus `covara generate resource|migration`
143
+ - **`covara dev` Loop** - Dev watcher: streams schema changes to the DB (additive auto-applied, destructive gated), regenerates the typed client, runs the server — no manual push. Plus `covara db` connection profiles (local/remote/Turso/Postgres), `push`/`migrate`/`studio`, and `data`/`import`/`export`/`run`/`types`
127
144
  - **Deploy-Ready Output** - Generated Dockerfile, docker-compose, complete wrangler.toml, GitHub Actions CI, `.env.example`
128
145
  - **Framework Migrations** - `covara/db` ships canonical internal-table schemas, an idempotent `autoMigrate`/`migrateInternal`, a generic seeder, and pool-sizing helpers
129
146
  - **App Factory** - `createCovara()` wires errors, auth, security headers, health, OpenAPI, admin UI
@@ -214,7 +231,7 @@ database_name = "my-app"
214
231
 
215
232
  Workers bill CPU time, not wall-clock time — long-lived idle SSE subscriptions cost almost nothing, since heartbeats and event pushes use negligible CPU.
216
233
 
217
- For production Workers deployments, bind the bundled `CovaraKVDurableObject` as Covara's KV store so subscriptions, rate limits, and sessions are shared across isolates — see [wiki/deployment.md](./wiki/deployment.md). Projects scaffolded with `covara create --template cloudflare` have it wired up already.
234
+ For production Workers deployments, bind the bundled `CovaraKVDurableObject` as Covara's KV store so subscriptions, rate limits, and sessions are shared across isolates — see the [Durable Object KV guide](https://kahveciderin.github.io/covara/deployment/durable-object-kv). Projects scaffolded with `covara create --template cloudflare` have it wired up already.
218
235
 
219
236
  ### Using a plain Hono app
220
237
 
@@ -318,7 +335,7 @@ app.resource("/posts", postsTable, {
318
335
  });
319
336
  ```
320
337
 
321
- See [wiki/resources.md](./wiki/resources.md) for the full option reference (soft delete, computed fields, field allowlists, search, custom filter operators, and more).
338
+ See the [Resources reference](https://kahveciderin.github.io/covara/core/resources-and-app) for the full option reference (soft delete, computed fields, field allowlists, search, custom filter operators, and more).
322
339
 
323
340
  ## Client Library
324
341
 
@@ -428,30 +445,69 @@ const subscription = users.subscribe(
428
445
 
429
446
  The client has no hard DOM dependencies: pass an AsyncStorage-backed `TokenStorage` for JWT auth, offline persistence picks an environment-appropriate backend, and the file hooks expose `getDownloadUrl()` for use with `Linking` instead of browser downloads.
430
447
 
448
+ ## Server-rendered htmx (Beta)
449
+
450
+ > **Beta.** This is newer than the JSON API and TypeScript client and may still change between releases. The JSON API it builds on is stable.
451
+
452
+ Prefer hypermedia over a client framework? Register a single JSX page; `<Live>` is the only special element, and Covara generates the htmx endpoints, the live SSE stream, and the optimistic/offline client runtime for you.
453
+
454
+ ```tsx
455
+ // tsconfig: { "jsx": "react-jsx", "jsxImportSource": "hono/jsx" }
456
+ import { createCovara } from "covara/server";
457
+ import { Live } from "covara/htmx";
458
+ import { todos } from "./schema";
459
+
460
+ const app = createCovara()
461
+ .resource("/todos", todos, { id: todos.id, db })
462
+ .page("/todos", () => (
463
+ <Live
464
+ resource={todos}
465
+ query={{ orderBy: "position" }}
466
+ create={(c) => (
467
+ <form {...c.create()}>
468
+ <input name="title" />
469
+ <button>Add</button>
470
+ </form>
471
+ )}
472
+ container={(rows, c) => <ul {...c.container()}>{rows}</ul>}
473
+ render={(t, c) => (
474
+ <li {...c.row(t.id)}>
475
+ {t.title}
476
+ <button {...c.delete(t.id)}>Delete</button>
477
+ </li>
478
+ )}
479
+ />
480
+ ));
481
+ ```
482
+
483
+ `GET /todos` is now a full server-rendered page. Creating a todo in one browser tab streams the new row into every other tab over SSE; updates and deletes patch rows in place. The helpers (`c.create()`, `c.row(id)`, `c.update(id)`, `c.delete(id)`, `c.container()`) emit plain htmx attributes pointing at auto-generated endpoints under `/__covara/live`. See the [htmx docs](https://kahveciderin.github.io/covara/htmx/overview) for optimistic/offline behavior, live aggregates, and scoping.
484
+
431
485
  ## File Storage
432
486
 
433
- Configure a storage backend once, then mount file resources like any other:
487
+ Configure a storage backend once, then chain a file resource like any other. Local uploads are auto-served at `baseUrl` — no `serveStatic` wiring:
434
488
 
435
489
  ```typescript
436
- import { initializeStorage, useFileResource } from "covara";
490
+ import { createCovara, initializeStorage } from "covara";
437
491
 
438
492
  initializeStorage({
439
493
  type: "local", // or "s3" | "r2" | "memory"
440
494
  local: { basePath: "./uploads", baseUrl: "/uploads" },
441
495
  });
442
496
 
443
- app.route("/api/files", useFileResource(filesTable, {
444
- db,
445
- schema: filesTable,
446
- id: filesTable.id,
447
- allowedMimeTypes: ["image/jpeg", "image/png"],
448
- maxFileSize: 5 * 1024 * 1024,
449
- auth: {
450
- read: async (user) => rsql`userId==${user?.id}`,
451
- delete: async (user) => rsql`userId==${user?.id}`,
452
- },
453
- usePresignedUrls: true, // direct-to-bucket on S3/R2
454
- }));
497
+ const app = createCovara({ cors: true })
498
+ .resource("/todos", todosTable, { id: todosTable.id, db })
499
+ .fileResource("/files", filesTable, {
500
+ db,
501
+ id: filesTable.id,
502
+ allowedMimeTypes: ["image/jpeg", "image/png"],
503
+ maxFileSize: 5 * 1024 * 1024,
504
+ auth: {
505
+ read: async (user) => rsql`userId==${user?.id}`,
506
+ delete: async (user) => rsql`userId==${user?.id}`,
507
+ },
508
+ usePresignedUrls: true, // direct-to-bucket on S3/R2
509
+ // ...plus any resource option: hooks, relations, procedures, subscriptions
510
+ });
455
511
  ```
456
512
 
457
513
  Upload from React with progress tracking:
@@ -475,7 +531,7 @@ function Uploader() {
475
531
  }
476
532
  ```
477
533
 
478
- See [wiki/storage.md](./wiki/storage.md).
534
+ See [Storage](https://kahveciderin.github.io/covara/platform/storage).
479
535
 
480
536
  ## Server-side Authentication
481
537
 
@@ -494,7 +550,7 @@ app.route("/api/auth", router); // /me, /login, /signup, /logout
494
550
  app.use("*", middleware); // populates c.get("user")
495
551
  ```
496
552
 
497
- Opt-in extras: TOTP MFA with backup codes, magic links, email verification, password reset, login throttling, CSRF protection, and API key management. See [wiki/authentication.md](./wiki/authentication.md).
553
+ Opt-in extras: TOTP MFA with backup codes, magic links, email verification, password reset, login throttling, CSRF protection, and API key management. See [Authentication](https://kahveciderin.github.io/covara/auth/overview).
498
554
 
499
555
  ### OIDC Provider
500
556
 
@@ -572,7 +628,7 @@ await getTaskScheduler().scheduleRecurring(dailyReportTask, {}, {
572
628
  });
573
629
  ```
574
630
 
575
- On Workers, swap the poller for the Cloudflare Queues adapter. See [wiki/tasks.md](./wiki/tasks.md).
631
+ On Workers, swap the poller for the Cloudflare Queues adapter. See [Background tasks](https://kahveciderin.github.io/covara/platform/tasks).
576
632
 
577
633
  ## Email
578
634
 
@@ -592,7 +648,7 @@ const { html, text } = createEmail({ brandColor: "#4f46e5" })
592
648
  await sendEmail({ from: "noreply@acme.com", to: email, subject: "Verify your email", html, text });
593
649
  ```
594
650
 
595
- The builder renders responsive, escaped HTML plus a plaintext fallback. A Cloudflare Email Service adapter is included for Workers. See [wiki/email.md](./wiki/email.md).
651
+ The builder renders responsive, escaped HTML plus a plaintext fallback. A Cloudflare Email Service adapter is included for Workers. See [Email](https://kahveciderin.github.io/covara/platform/email).
596
652
 
597
653
  ## Billing
598
654
 
@@ -634,7 +690,7 @@ function Account() {
634
690
  }
635
691
  ```
636
692
 
637
- Webhooks are signature-verified, deduplicated, and grant credits automatically on `payment.succeeded`. See [wiki/billing.md](./wiki/billing.md).
693
+ Webhooks are signature-verified, deduplicated, and grant credits automatically on `payment.succeeded`. See [Billing](https://kahveciderin.github.io/covara/platform/billing).
638
694
 
639
695
  ## Mutation Tracking
640
696
 
@@ -697,7 +753,7 @@ const env = createEnv({
697
753
  app.route("/api/env", usePublicEnv(env)); // serves public vars (with ETag)
698
754
  ```
699
755
 
700
- Clients read public vars with `fetchPublicEnv`/`createEnvClient` or the `usePublicEnv` React hook. See [wiki/environment-variables.md](./wiki/environment-variables.md).
756
+ Clients read public vars with `fetchPublicEnv`/`createEnvClient` or the `usePublicEnv` React hook. See [Environment variables](https://kahveciderin.github.io/covara/deployment/environment-variables).
701
757
 
702
758
  ## Query Parameters
703
759
 
@@ -739,7 +795,7 @@ age=between=[18,65] # Range (inclusive)
739
795
  deletedAt=isnull=true # Is null
740
796
  bio=isempty=false # Has non-empty value
741
797
 
742
- # See wiki/filtering.md for all 30+ operators
798
+ # See https://kahveciderin.github.io/covara/core/filtering for all 30+ operators
743
799
  ```
744
800
 
745
801
  The same expression filters database queries, subscription scopes, and auth scopes — parsed once, executed as SQL or in-memory as needed.
@@ -794,47 +850,27 @@ expect(res.status).toBe(201);
794
850
 
795
851
  ## Documentation
796
852
 
797
- Comprehensive documentation is available in the [wiki](./wiki):
853
+ 📚 **Full documentation: [kahveciderin.github.io/covara](https://kahveciderin.github.io/covara)**
798
854
 
799
- ### Getting Started
800
- - [Getting Started Guide](./wiki/getting-started.md) - Installation and quick start
801
- - [Deployment](./wiki/deployment.md) - Node, Cloudflare Workers, database matrix
802
- - [Migrating from Express](./wiki/migrating-from-express.md) - Upgrading from Covara ≤ 0.5
855
+ The docs site is built with Docusaurus from the [`website/`](./website) folder and published to GitHub Pages automatically (`.github/workflows/docs.yml`). Highlights:
803
856
 
804
- ### Core Concepts
805
- - [Resources](./wiki/resources.md) - Resource configuration and endpoints
806
- - [Filtering](./wiki/filtering.md) - RSQL filter syntax (30+ operators)
807
- - [Pagination](./wiki/pagination.md) - Cursor-based pagination
808
- - [Aggregations](./wiki/aggregations.md) - Group by and statistical queries
809
- - [Relations](./wiki/relations.md) - Relationships and efficient batch loading
810
- - [Search](./wiki/search.md) - Full-text search adapters and transactional outbox
811
- - [Database](./wiki/database.md) - Internal tables, framework migrations, seeding, pooling
857
+ - **Get started** — [Introduction](https://kahveciderin.github.io/covara/), [Quick Start](https://kahveciderin.github.io/covara/quick-start), [Tutorial](https://kahveciderin.github.io/covara/tutorial)
858
+ - **Core** — [Resources](https://kahveciderin.github.io/covara/core/resources-and-app), [Filtering](https://kahveciderin.github.io/covara/core/filtering), [Pagination](https://kahveciderin.github.io/covara/core/pagination), [Aggregations](https://kahveciderin.github.io/covara/core/aggregations), [Relations](https://kahveciderin.github.io/covara/core/relations), [Search](https://kahveciderin.github.io/covara/core/search)
859
+ - **Real-time** — [Subscriptions](https://kahveciderin.github.io/covara/realtime/subscriptions), [Aggregate subscriptions](https://kahveciderin.github.io/covara/realtime/aggregate-subscriptions), [Mutation tracking](https://kahveciderin.github.io/covara/realtime/mutation-tracking)
860
+ - **Auth & security** — [Overview](https://kahveciderin.github.io/covara/auth/overview), [OIDC provider](https://kahveciderin.github.io/covara/auth/oidc-provider), [JWT](https://kahveciderin.github.io/covara/auth/jwt), [Scopes](https://kahveciderin.github.io/covara/auth/scopes)
861
+ - **Platform** — [Storage](https://kahveciderin.github.io/covara/platform/storage), [Email](https://kahveciderin.github.io/covara/platform/email), [Billing](https://kahveciderin.github.io/covara/platform/billing), [Tasks](https://kahveciderin.github.io/covara/platform/tasks), [KV](https://kahveciderin.github.io/covara/platform/kv)
862
+ - **Client** — [Overview](https://kahveciderin.github.io/covara/client/overview), [React hooks](https://kahveciderin.github.io/covara/client/react-hooks), [Offline](https://kahveciderin.github.io/covara/client/offline), [Type generation](https://kahveciderin.github.io/covara/client/typegen)
863
+ - **Deploy** — [Node](https://kahveciderin.github.io/covara/deployment/node), [Cloudflare Workers](https://kahveciderin.github.io/covara/deployment/workers), [Databases](https://kahveciderin.github.io/covara/deployment/databases)
864
+ - **Reference** — [Contracts (invariants)](https://kahveciderin.github.io/covara/contracts/overview), [Error handling](https://kahveciderin.github.io/covara/tooling/error-handling), [Migrating from Express](https://kahveciderin.github.io/covara/migration/from-express)
812
865
 
813
- ### Real-time
814
- - [Subscriptions](./wiki/subscriptions.md) - SSE subscriptions and changelog
866
+ Run the docs locally:
815
867
 
816
- ### Authentication & Security
817
- - [Authentication](./wiki/authentication.md) - OIDC Provider, federated login, JWT, session auth
818
- - [Secure Queries](./wiki/secure-queries.md) - Scope-enforced query builder
819
-
820
- ### Platform Services
821
- - [Storage](./wiki/storage.md) - File uploads, S3/R2/local adapters, presigned URLs
822
- - [Email](./wiki/email.md) - Email adapters and template builder
823
- - [Billing](./wiki/billing.md) - Payment providers, plans, credits, webhooks
824
- - [Tasks](./wiki/tasks.md) - Background job queue, scheduling, retries
825
- - [Environment Variables](./wiki/environment-variables.md) - Typed env config
826
-
827
- ### Client
828
- - [Client Library](./wiki/client-library.md) - TypeScript client with React hooks
829
- - [Offline Support](./wiki/offline-support.md) - Offline-first capabilities
830
-
831
- ### Advanced
832
- - [Procedures & Hooks](./wiki/procedures.md) - RPC and lifecycle hooks
833
- - [Mutation Tracking](./wiki/track-mutations.md) - Automatic changelog and cache invalidation
834
- - [Middleware](./wiki/middleware.md) - Observability, versioning, idempotency
835
- - [OpenAPI](./wiki/openapi.md) - OpenAPI spec generation
836
- - [Admin UI](./wiki/admin-ui.md) - Built-in dashboard
837
- - [Error Handling](./wiki/error-handling.md) - Error types and handling
868
+ ```bash
869
+ cd website
870
+ pnpm install
871
+ pnpm start # dev server with hot reload
872
+ pnpm build # production build (validates all internal links)
873
+ ```
838
874
 
839
875
  ## Requirements
840
876
 
@@ -0,0 +1,14 @@
1
+ export interface ParsedArgs {
2
+ positionals: string[];
3
+ flags: Record<string, string | boolean>;
4
+ passthrough: string[];
5
+ }
6
+ export interface ParseOptions {
7
+ booleans?: string[];
8
+ aliases?: Record<string, string>;
9
+ }
10
+ export declare const parseArgs: (argv: string[], opts?: ParseOptions) => ParsedArgs;
11
+ export declare const getString: (parsed: ParsedArgs, name: string) => string | undefined;
12
+ export declare const getBool: (parsed: ParsedArgs, name: string) => boolean;
13
+ export declare const hasFlag: (parsed: ParsedArgs, name: string) => boolean;
14
+ //# sourceMappingURL=args.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC;IACxC,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAQD,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,EAAE,EAAE,OAAM,YAAiB,KAAG,UA4DnE,CAAC;AAEF,eAAO,MAAM,SAAS,GACpB,QAAQ,UAAU,EAClB,MAAM,MAAM,KACX,MAAM,GAAG,SAGX,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,QAAQ,UAAU,EAAE,MAAM,MAAM,KAAG,OAE1D,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,QAAQ,UAAU,EAAE,MAAM,MAAM,KAAG,OAE1D,CAAC"}
@@ -0,0 +1,78 @@
1
+ const splitInline = (arg) => {
2
+ const eq = arg.indexOf("=");
3
+ if (eq === -1)
4
+ return [arg, undefined];
5
+ return [arg.slice(0, eq), arg.slice(eq + 1)];
6
+ };
7
+ export const parseArgs = (argv, opts = {}) => {
8
+ const booleans = new Set(opts.booleans ?? []);
9
+ const aliases = opts.aliases ?? {};
10
+ const positionals = [];
11
+ const flags = {};
12
+ const passthrough = [];
13
+ const rest = [...argv];
14
+ while (rest.length > 0) {
15
+ const arg = rest.shift();
16
+ if (arg === "--") {
17
+ passthrough.push(...rest);
18
+ break;
19
+ }
20
+ if (arg.startsWith("--")) {
21
+ const [rawName, inline] = splitInline(arg.slice(2));
22
+ if (rawName.startsWith("no-") && inline === undefined && !booleans.has(rawName)) {
23
+ flags[rawName.slice(3)] = false;
24
+ continue;
25
+ }
26
+ const name = aliases[rawName] ?? rawName;
27
+ if (inline !== undefined) {
28
+ flags[name] = inline;
29
+ }
30
+ else if (booleans.has(rawName) || booleans.has(name)) {
31
+ flags[name] = true;
32
+ }
33
+ else {
34
+ const next = rest[0];
35
+ if (next === undefined || next.startsWith("-")) {
36
+ flags[name] = true;
37
+ }
38
+ else {
39
+ flags[name] = rest.shift();
40
+ }
41
+ }
42
+ continue;
43
+ }
44
+ if (arg.startsWith("-") && arg.length > 1) {
45
+ const [rawName, inline] = splitInline(arg.slice(1));
46
+ const name = aliases[rawName] ?? rawName;
47
+ if (inline !== undefined) {
48
+ flags[name] = inline;
49
+ }
50
+ else if (booleans.has(rawName) || booleans.has(name)) {
51
+ flags[name] = true;
52
+ }
53
+ else {
54
+ const next = rest[0];
55
+ if (next === undefined || next.startsWith("-")) {
56
+ flags[name] = true;
57
+ }
58
+ else {
59
+ flags[name] = rest.shift();
60
+ }
61
+ }
62
+ continue;
63
+ }
64
+ positionals.push(arg);
65
+ }
66
+ return { positionals, flags, passthrough };
67
+ };
68
+ export const getString = (parsed, name) => {
69
+ const v = parsed.flags[name];
70
+ return typeof v === "string" ? v : undefined;
71
+ };
72
+ export const getBool = (parsed, name) => {
73
+ return parsed.flags[name] === true;
74
+ };
75
+ export const hasFlag = (parsed, name) => {
76
+ return name in parsed.flags;
77
+ };
78
+ //# sourceMappingURL=args.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.js","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const dataCommand: (args: string[]) => Promise<number>;
2
+ //# sourceMappingURL=data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/data.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,WAAW,GAAU,MAAM,MAAM,EAAE,KAAG,OAAO,CAAC,MAAM,CAyBhE,CAAC"}
@@ -0,0 +1,31 @@
1
+ import { resolveProfile, resolveSchemaPath } from "../config.js";
2
+ import { queryData } from "../drizzle-bridge.js";
3
+ import { parseArgs, getString } from "../args.js";
4
+ export const dataCommand = async (args) => {
5
+ const parsed = parseArgs(args);
6
+ const table = parsed.positionals[0];
7
+ if (!table) {
8
+ console.error("error: usage: covara data <table> [--limit n] [--profile name]");
9
+ return 1;
10
+ }
11
+ const cwd = process.cwd();
12
+ try {
13
+ const profile = resolveProfile(cwd, {
14
+ profile: getString(parsed, "profile"),
15
+ url: getString(parsed, "url"),
16
+ });
17
+ const schemaPath = resolveSchemaPath(cwd);
18
+ const limit = getString(parsed, "limit");
19
+ const { rows } = await queryData(cwd, profile, schemaPath, table, {
20
+ limit: limit ? parseInt(limit, 10) : undefined,
21
+ });
22
+ console.log(JSON.stringify(rows, null, 2));
23
+ console.log(`\n(${rows.length} row(s))`);
24
+ return 0;
25
+ }
26
+ catch (e) {
27
+ console.error(`error: ${e instanceof Error ? e.message : String(e)}`);
28
+ return 1;
29
+ }
30
+ };
31
+ //# sourceMappingURL=data.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data.js","sourceRoot":"","sources":["../../../src/cli/commands/data.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,EAAE,IAAc,EAAmB,EAAE;IACnE,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IACpC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,gEAAgE,CAAC,CAAC;QAChF,OAAO,CAAC,CAAC;IACX,CAAC;IACD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,EAAE;YAClC,OAAO,EAAE,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC;YACrC,GAAG,EAAE,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC;SAC9B,CAAC,CAAC;QACH,MAAM,UAAU,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;QAC1C,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACzC,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE;YAChE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS;SAC/C,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC3C,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,MAAM,UAAU,CAAC,CAAC;QACzC,OAAO,CAAC,CAAC;IACX,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACtE,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const dbCommand: (args: string[]) => number;
2
+ //# sourceMappingURL=db.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/db.ts"],"names":[],"mappings":"AAmBA,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,EAAE,KAAG,MA2F1C,CAAC"}
@@ -0,0 +1,100 @@
1
+ import { loadConfig, saveConfig, resolveProfile, dialectFromUrl, } from "../config.js";
2
+ import { parseArgs, getString } from "../args.js";
3
+ const DB_HELP = `covara db - manage database connection profiles
4
+
5
+ Usage:
6
+ covara db list
7
+ covara db current
8
+ covara db use <name>
9
+ covara db add <name> --url <url> [--token <token>] [--dialect sqlite|postgres]
10
+ covara db remove <name>
11
+ `;
12
+ export const dbCommand = (args) => {
13
+ const [sub, ...rest] = args;
14
+ const cwd = process.cwd();
15
+ if (!sub || sub === "help" || sub === "--help") {
16
+ console.log(DB_HELP);
17
+ return sub ? 0 : 1;
18
+ }
19
+ if (sub === "list") {
20
+ const config = loadConfig(cwd);
21
+ const names = Object.keys(config.profiles);
22
+ if (names.length === 0) {
23
+ console.log("No profiles configured. Add one with `covara db add <name> --url <url>`.");
24
+ return 0;
25
+ }
26
+ for (const name of names) {
27
+ const p = config.profiles[name];
28
+ const marker = name === config.active ? "* " : " ";
29
+ console.log(`${marker}${name} [${p.dialect}] ${p.url}`);
30
+ }
31
+ return 0;
32
+ }
33
+ if (sub === "current") {
34
+ try {
35
+ const p = resolveProfile(cwd);
36
+ console.log(`${p.name} [${p.dialect}] ${p.url}`);
37
+ return 0;
38
+ }
39
+ catch (e) {
40
+ console.error(`error: ${e instanceof Error ? e.message : String(e)}`);
41
+ return 1;
42
+ }
43
+ }
44
+ if (sub === "use") {
45
+ const name = rest.find((a) => !a.startsWith("-"));
46
+ if (!name) {
47
+ console.error("error: missing profile name (usage: covara db use <name>)");
48
+ return 1;
49
+ }
50
+ const config = loadConfig(cwd);
51
+ if (!config.profiles[name]) {
52
+ console.error(`error: unknown profile "${name}"`);
53
+ return 1;
54
+ }
55
+ config.active = name;
56
+ saveConfig(cwd, config);
57
+ console.log(`Active profile is now "${name}".`);
58
+ return 0;
59
+ }
60
+ if (sub === "add") {
61
+ const parsed = parseArgs(rest, { aliases: { t: "token", d: "dialect" } });
62
+ const name = parsed.positionals[0];
63
+ const url = getString(parsed, "url");
64
+ if (!name || !url) {
65
+ console.error("error: usage: covara db add <name> --url <url> [--token <token>] [--dialect sqlite|postgres]");
66
+ return 1;
67
+ }
68
+ const dialect = getString(parsed, "dialect") ?? dialectFromUrl(url);
69
+ const token = getString(parsed, "token");
70
+ const config = loadConfig(cwd);
71
+ config.profiles[name] = { dialect, url, ...(token ? { authToken: token } : {}) };
72
+ if (!config.active)
73
+ config.active = name;
74
+ saveConfig(cwd, config);
75
+ console.log(`Added profile "${name}" [${dialect}].`);
76
+ return 0;
77
+ }
78
+ if (sub === "remove" || sub === "rm") {
79
+ const name = rest.find((a) => !a.startsWith("-"));
80
+ if (!name) {
81
+ console.error("error: missing profile name (usage: covara db remove <name>)");
82
+ return 1;
83
+ }
84
+ const config = loadConfig(cwd);
85
+ if (!config.profiles[name]) {
86
+ console.error(`error: unknown profile "${name}"`);
87
+ return 1;
88
+ }
89
+ delete config.profiles[name];
90
+ if (config.active === name)
91
+ delete config.active;
92
+ saveConfig(cwd, config);
93
+ console.log(`Removed profile "${name}".`);
94
+ return 0;
95
+ }
96
+ console.error(`error: unknown db subcommand "${sub}"\n`);
97
+ console.log(DB_HELP);
98
+ return 1;
99
+ };
100
+ //# sourceMappingURL=db.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../../../src/cli/commands/db.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const devCommand: (args: string[]) => Promise<number>;
2
+ //# sourceMappingURL=dev.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/dev.ts"],"names":[],"mappings":"AA4BA,eAAO,MAAM,UAAU,GAAU,MAAM,MAAM,EAAE,KAAG,OAAO,CAAC,MAAM,CAkG/D,CAAC"}