covara 0.0.1 → 0.6.1
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.
- package/README.md +839 -0
- package/dist/auth/adapter.d.ts +47 -0
- package/dist/auth/adapter.d.ts.map +1 -0
- package/dist/auth/adapter.js +144 -0
- package/dist/auth/adapter.js.map +1 -0
- package/dist/auth/adapters/authjs.d.ts +31 -0
- package/dist/auth/adapters/authjs.d.ts.map +1 -0
- package/dist/auth/adapters/authjs.js +143 -0
- package/dist/auth/adapters/authjs.js.map +1 -0
- package/dist/auth/adapters/jwt.d.ts +70 -0
- package/dist/auth/adapters/jwt.d.ts.map +1 -0
- package/dist/auth/adapters/jwt.js +368 -0
- package/dist/auth/adapters/jwt.js.map +1 -0
- package/dist/auth/adapters/oidc.d.ts +120 -0
- package/dist/auth/adapters/oidc.d.ts.map +1 -0
- package/dist/auth/adapters/oidc.js +280 -0
- package/dist/auth/adapters/oidc.js.map +1 -0
- package/dist/auth/adapters/passport.d.ts +44 -0
- package/dist/auth/adapters/passport.d.ts.map +1 -0
- package/dist/auth/adapters/passport.js +206 -0
- package/dist/auth/adapters/passport.js.map +1 -0
- package/dist/auth/api-keys.d.ts +68 -0
- package/dist/auth/api-keys.d.ts.map +1 -0
- package/dist/auth/api-keys.js +117 -0
- package/dist/auth/api-keys.js.map +1 -0
- package/dist/auth/config.d.ts +36 -0
- package/dist/auth/config.d.ts.map +1 -0
- package/dist/auth/config.js +50 -0
- package/dist/auth/config.js.map +1 -0
- package/dist/auth/csrf.d.ts +18 -0
- package/dist/auth/csrf.d.ts.map +1 -0
- package/dist/auth/csrf.js +59 -0
- package/dist/auth/csrf.js.map +1 -0
- package/dist/auth/index.d.ts +25 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +22 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/login-throttle.d.ts +21 -0
- package/dist/auth/login-throttle.d.ts.map +1 -0
- package/dist/auth/login-throttle.js +50 -0
- package/dist/auth/login-throttle.js.map +1 -0
- package/dist/auth/magic-link.d.ts +13 -0
- package/dist/auth/magic-link.d.ts.map +1 -0
- package/dist/auth/magic-link.js +14 -0
- package/dist/auth/magic-link.js.map +1 -0
- package/dist/auth/middleware.d.ts +20 -0
- package/dist/auth/middleware.d.ts.map +1 -0
- package/dist/auth/middleware.js +116 -0
- package/dist/auth/middleware.js.map +1 -0
- package/dist/auth/password-policy.d.ts +18 -0
- package/dist/auth/password-policy.d.ts.map +1 -0
- package/dist/auth/password-policy.js +72 -0
- package/dist/auth/password-policy.js.map +1 -0
- package/dist/auth/password-reset.d.ts +13 -0
- package/dist/auth/password-reset.d.ts.map +1 -0
- package/dist/auth/password-reset.js +17 -0
- package/dist/auth/password-reset.js.map +1 -0
- package/dist/auth/password.d.ts +11 -0
- package/dist/auth/password.d.ts.map +1 -0
- package/dist/auth/password.js +98 -0
- package/dist/auth/password.js.map +1 -0
- package/dist/auth/routes.d.ts +111 -0
- package/dist/auth/routes.d.ts.map +1 -0
- package/dist/auth/routes.js +417 -0
- package/dist/auth/routes.js.map +1 -0
- package/dist/auth/rsql.d.ts +33 -0
- package/dist/auth/rsql.d.ts.map +1 -0
- package/dist/auth/rsql.js +102 -0
- package/dist/auth/rsql.js.map +1 -0
- package/dist/auth/scope.d.ts +26 -0
- package/dist/auth/scope.d.ts.map +1 -0
- package/dist/auth/scope.js +166 -0
- package/dist/auth/scope.js.map +1 -0
- package/dist/auth/stores/drizzle.d.ts +39 -0
- package/dist/auth/stores/drizzle.d.ts.map +1 -0
- package/dist/auth/stores/drizzle.js +183 -0
- package/dist/auth/stores/drizzle.js.map +1 -0
- package/dist/auth/stores/index.d.ts +6 -0
- package/dist/auth/stores/index.d.ts.map +1 -0
- package/dist/auth/stores/index.js +4 -0
- package/dist/auth/stores/index.js.map +1 -0
- package/dist/auth/stores/redis.d.ts +25 -0
- package/dist/auth/stores/redis.d.ts.map +1 -0
- package/dist/auth/stores/redis.js +147 -0
- package/dist/auth/stores/redis.js.map +1 -0
- package/dist/auth/totp.d.ts +32 -0
- package/dist/auth/totp.d.ts.map +1 -0
- package/dist/auth/totp.js +126 -0
- package/dist/auth/totp.js.map +1 -0
- package/dist/auth/types.d.ts +82 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +53 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/auth/verification.d.ts +32 -0
- package/dist/auth/verification.d.ts.map +1 -0
- package/dist/auth/verification.js +0 -0
- package/dist/auth/verification.js.map +1 -0
- package/dist/billing/credits.d.ts +29 -0
- package/dist/billing/credits.d.ts.map +1 -0
- package/dist/billing/credits.js +66 -0
- package/dist/billing/credits.js.map +1 -0
- package/dist/billing/index.d.ts +53 -0
- package/dist/billing/index.d.ts.map +1 -0
- package/dist/billing/index.js +139 -0
- package/dist/billing/index.js.map +1 -0
- package/dist/billing/lemonsqueezy.d.ts +29 -0
- package/dist/billing/lemonsqueezy.d.ts.map +1 -0
- package/dist/billing/lemonsqueezy.js +276 -0
- package/dist/billing/lemonsqueezy.js.map +1 -0
- package/dist/billing/paddle.d.ts +30 -0
- package/dist/billing/paddle.d.ts.map +1 -0
- package/dist/billing/paddle.js +247 -0
- package/dist/billing/paddle.js.map +1 -0
- package/dist/billing/polar.d.ts +31 -0
- package/dist/billing/polar.d.ts.map +1 -0
- package/dist/billing/polar.js +284 -0
- package/dist/billing/polar.js.map +1 -0
- package/dist/billing/router.d.ts +9 -0
- package/dist/billing/router.d.ts.map +1 -0
- package/dist/billing/router.js +75 -0
- package/dist/billing/router.js.map +1 -0
- package/dist/billing/stripe.d.ts +31 -0
- package/dist/billing/stripe.d.ts.map +1 -0
- package/dist/billing/stripe.js +319 -0
- package/dist/billing/stripe.js.map +1 -0
- package/dist/billing/types.d.ts +97 -0
- package/dist/billing/types.d.ts.map +1 -0
- package/dist/billing/types.js +9 -0
- package/dist/billing/types.js.map +1 -0
- package/dist/cli/create.d.ts +10 -0
- package/dist/cli/create.d.ts.map +1 -0
- package/dist/cli/create.js +79 -0
- package/dist/cli/create.js.map +1 -0
- package/dist/cli/generate.d.ts +16 -0
- package/dist/cli/generate.d.ts.map +1 -0
- package/dist/cli/generate.js +105 -0
- package/dist/cli/generate.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +185 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/options.d.ts +11 -0
- package/dist/cli/options.d.ts.map +1 -0
- package/dist/cli/options.js +14 -0
- package/dist/cli/options.js.map +1 -0
- package/dist/cli/templates/configs.d.ts +12 -0
- package/dist/cli/templates/configs.d.ts.map +1 -0
- package/dist/cli/templates/configs.js +174 -0
- package/dist/cli/templates/configs.js.map +1 -0
- package/dist/cli/templates/deploy.d.ts +6 -0
- package/dist/cli/templates/deploy.d.ts.map +1 -0
- package/dist/cli/templates/deploy.js +147 -0
- package/dist/cli/templates/deploy.js.map +1 -0
- package/dist/cli/templates/index.d.ts +8 -0
- package/dist/cli/templates/index.d.ts.map +1 -0
- package/dist/cli/templates/index.js +35 -0
- package/dist/cli/templates/index.js.map +1 -0
- package/dist/cli/templates/package-json.d.ts +3 -0
- package/dist/cli/templates/package-json.d.ts.map +1 -0
- package/dist/cli/templates/package-json.js +76 -0
- package/dist/cli/templates/package-json.js.map +1 -0
- package/dist/cli/templates/readme.d.ts +3 -0
- package/dist/cli/templates/readme.d.ts.map +1 -0
- package/dist/cli/templates/readme.js +109 -0
- package/dist/cli/templates/readme.js.map +1 -0
- package/dist/cli/templates/source.d.ts +11 -0
- package/dist/cli/templates/source.d.ts.map +1 -0
- package/dist/cli/templates/source.js +158 -0
- package/dist/cli/templates/source.js.map +1 -0
- package/dist/client/auth/auth-transport.d.ts +24 -0
- package/dist/client/auth/auth-transport.d.ts.map +1 -0
- package/dist/client/auth/auth-transport.js +78 -0
- package/dist/client/auth/auth-transport.js.map +1 -0
- package/dist/client/auth/index.d.ts +52 -0
- package/dist/client/auth/index.d.ts.map +1 -0
- package/dist/client/auth/index.js +350 -0
- package/dist/client/auth/index.js.map +1 -0
- package/dist/client/auth/oidc-client.d.ts +17 -0
- package/dist/client/auth/oidc-client.d.ts.map +1 -0
- package/dist/client/auth/oidc-client.js +159 -0
- package/dist/client/auth/oidc-client.js.map +1 -0
- package/dist/client/auth/token-manager.d.ts +51 -0
- package/dist/client/auth/token-manager.d.ts.map +1 -0
- package/dist/client/auth/token-manager.js +222 -0
- package/dist/client/auth/token-manager.js.map +1 -0
- package/dist/client/auth/types.d.ts +82 -0
- package/dist/client/auth/types.d.ts.map +1 -0
- package/dist/client/auth/types.js +2 -0
- package/dist/client/auth/types.js.map +1 -0
- package/dist/client/billing.d.ts +54 -0
- package/dist/client/billing.d.ts.map +1 -0
- package/dist/client/billing.js +58 -0
- package/dist/client/billing.js.map +1 -0
- package/dist/client/dates.d.ts +40 -0
- package/dist/client/dates.d.ts.map +1 -0
- package/dist/client/dates.js +56 -0
- package/dist/client/dates.js.map +1 -0
- package/dist/client/env.d.ts +24 -0
- package/dist/client/env.d.ts.map +1 -0
- package/dist/client/env.js +105 -0
- package/dist/client/env.js.map +1 -0
- package/dist/client/file-upload.d.ts +53 -0
- package/dist/client/file-upload.d.ts.map +1 -0
- package/dist/client/file-upload.js +162 -0
- package/dist/client/file-upload.js.map +1 -0
- package/dist/client/globals.d.ts +6 -0
- package/dist/client/globals.d.ts.map +1 -0
- package/dist/client/globals.js +23 -0
- package/dist/client/globals.js.map +1 -0
- package/dist/client/index.d.ts +60 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +266 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/indexeddb-storage.d.ts +22 -0
- package/dist/client/indexeddb-storage.d.ts.map +1 -0
- package/dist/client/indexeddb-storage.js +79 -0
- package/dist/client/indexeddb-storage.js.map +1 -0
- package/dist/client/jwt.d.ts +62 -0
- package/dist/client/jwt.d.ts.map +1 -0
- package/dist/client/jwt.js +164 -0
- package/dist/client/jwt.js.map +1 -0
- package/dist/client/live-store.d.ts +49 -0
- package/dist/client/live-store.d.ts.map +1 -0
- package/dist/client/live-store.js +653 -0
- package/dist/client/live-store.js.map +1 -0
- package/dist/client/mutation.d.ts +73 -0
- package/dist/client/mutation.d.ts.map +1 -0
- package/dist/client/mutation.js +72 -0
- package/dist/client/mutation.js.map +1 -0
- package/dist/client/offline.d.ts +110 -0
- package/dist/client/offline.d.ts.map +1 -0
- package/dist/client/offline.js +551 -0
- package/dist/client/offline.js.map +1 -0
- package/dist/client/query-builder.d.ts +130 -0
- package/dist/client/query-builder.d.ts.map +1 -0
- package/dist/client/query-builder.js +300 -0
- package/dist/client/query-builder.js.map +1 -0
- package/dist/client/query-cache.d.ts +64 -0
- package/dist/client/query-cache.d.ts.map +1 -0
- package/dist/client/query-cache.js +112 -0
- package/dist/client/query-cache.js.map +1 -0
- package/dist/client/query-types.d.ts +61 -0
- package/dist/client/query-types.d.ts.map +1 -0
- package/dist/client/query-types.js +2 -0
- package/dist/client/query-types.js.map +1 -0
- package/dist/client/react-billing.d.ts +24 -0
- package/dist/client/react-billing.d.ts.map +1 -0
- package/dist/client/react-billing.js +101 -0
- package/dist/client/react-billing.js.map +1 -0
- package/dist/client/react-files.d.ts +46 -0
- package/dist/client/react-files.d.ts.map +1 -0
- package/dist/client/react-files.js +174 -0
- package/dist/client/react-files.js.map +1 -0
- package/dist/client/react-jwt.d.ts +17 -0
- package/dist/client/react-jwt.d.ts.map +1 -0
- package/dist/client/react-jwt.js +73 -0
- package/dist/client/react-jwt.js.map +1 -0
- package/dist/client/react.d.ts +210 -0
- package/dist/client/react.d.ts.map +1 -0
- package/dist/client/react.js +599 -0
- package/dist/client/react.js.map +1 -0
- package/dist/client/repository.d.ts +49 -0
- package/dist/client/repository.d.ts.map +1 -0
- package/dist/client/repository.js +269 -0
- package/dist/client/repository.js.map +1 -0
- package/dist/client/resource-query-builder.d.ts +35 -0
- package/dist/client/resource-query-builder.d.ts.map +1 -0
- package/dist/client/resource-query-builder.js +177 -0
- package/dist/client/resource-query-builder.js.map +1 -0
- package/dist/client/subscription-manager.d.ts +37 -0
- package/dist/client/subscription-manager.d.ts.map +1 -0
- package/dist/client/subscription-manager.js +164 -0
- package/dist/client/subscription-manager.js.map +1 -0
- package/dist/client/tab-sync.d.ts +35 -0
- package/dist/client/tab-sync.d.ts.map +1 -0
- package/dist/client/tab-sync.js +129 -0
- package/dist/client/tab-sync.js.map +1 -0
- package/dist/client/transport.d.ts +50 -0
- package/dist/client/transport.d.ts.map +1 -0
- package/dist/client/transport.js +205 -0
- package/dist/client/transport.js.map +1 -0
- package/dist/client/typegen.d.ts +20 -0
- package/dist/client/typegen.d.ts.map +1 -0
- package/dist/client/typegen.js +578 -0
- package/dist/client/typegen.js.map +1 -0
- package/dist/client/types.d.ts +472 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +2 -0
- package/dist/client/types.js.map +1 -0
- package/dist/db/index.d.ts +9 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +5 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/internal-schema.d.ts +3831 -0
- package/dist/db/internal-schema.d.ts.map +1 -0
- package/dist/db/internal-schema.js +130 -0
- package/dist/db/internal-schema.js.map +1 -0
- package/dist/db/migrate.d.ts +15 -0
- package/dist/db/migrate.d.ts.map +1 -0
- package/dist/db/migrate.js +127 -0
- package/dist/db/migrate.js.map +1 -0
- package/dist/db/pooling.d.ts +9 -0
- package/dist/db/pooling.d.ts.map +1 -0
- package/dist/db/pooling.js +42 -0
- package/dist/db/pooling.js.map +1 -0
- package/dist/db/seed.d.ts +24 -0
- package/dist/db/seed.d.ts.map +1 -0
- package/dist/db/seed.js +34 -0
- package/dist/db/seed.js.map +1 -0
- package/dist/email/builder.d.ts +38 -0
- package/dist/email/builder.d.ts.map +1 -0
- package/dist/email/builder.js +153 -0
- package/dist/email/builder.js.map +1 -0
- package/dist/email/cloudflare.d.ts +24 -0
- package/dist/email/cloudflare.d.ts.map +1 -0
- package/dist/email/cloudflare.js +146 -0
- package/dist/email/cloudflare.js.map +1 -0
- package/dist/email/index.d.ts +12 -0
- package/dist/email/index.d.ts.map +1 -0
- package/dist/email/index.js +27 -0
- package/dist/email/index.js.map +1 -0
- package/dist/email/resend.d.ts +15 -0
- package/dist/email/resend.d.ts.map +1 -0
- package/dist/email/resend.js +114 -0
- package/dist/email/resend.js.map +1 -0
- package/dist/email/types.d.ts +36 -0
- package/dist/email/types.d.ts.map +1 -0
- package/dist/email/types.js +12 -0
- package/dist/email/types.js.map +1 -0
- package/dist/env/index.d.ts +52 -0
- package/dist/env/index.d.ts.map +1 -0
- package/dist/env/index.js +153 -0
- package/dist/env/index.js.map +1 -0
- package/dist/health/checks.d.ts +40 -0
- package/dist/health/checks.d.ts.map +1 -0
- package/dist/health/checks.js +166 -0
- package/dist/health/checks.js.map +1 -0
- package/dist/health/index.d.ts +26 -0
- package/dist/health/index.d.ts.map +1 -0
- package/dist/health/index.js +104 -0
- package/dist/health/index.js.map +1 -0
- package/dist/index.d.ts +78 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +72 -0
- package/dist/index.js.map +1 -0
- package/dist/kv/durable-object.d.ts +192 -0
- package/dist/kv/durable-object.d.ts.map +1 -0
- package/dist/kv/durable-object.js +1059 -0
- package/dist/kv/durable-object.js.map +1 -0
- package/dist/kv/index.d.ts +56 -0
- package/dist/kv/index.d.ts.map +1 -0
- package/dist/kv/index.js +96 -0
- package/dist/kv/index.js.map +1 -0
- package/dist/kv/memory.d.ts +78 -0
- package/dist/kv/memory.d.ts.map +1 -0
- package/dist/kv/memory.js +599 -0
- package/dist/kv/memory.js.map +1 -0
- package/dist/kv/redis.d.ts +148 -0
- package/dist/kv/redis.d.ts.map +1 -0
- package/dist/kv/redis.js +405 -0
- package/dist/kv/redis.js.map +1 -0
- package/dist/kv/types.d.ts +132 -0
- package/dist/kv/types.d.ts.map +1 -0
- package/dist/kv/types.js +24 -0
- package/dist/kv/types.js.map +1 -0
- package/dist/middleware/error.d.ts +4 -0
- package/dist/middleware/error.d.ts.map +1 -0
- package/dist/middleware/error.js +63 -0
- package/dist/middleware/error.js.map +1 -0
- package/dist/middleware/idempotency.d.ts +21 -0
- package/dist/middleware/idempotency.d.ts.map +1 -0
- package/dist/middleware/idempotency.js +144 -0
- package/dist/middleware/idempotency.js.map +1 -0
- package/dist/middleware/logging.d.ts +3 -0
- package/dist/middleware/logging.d.ts.map +1 -0
- package/dist/middleware/logging.js +6 -0
- package/dist/middleware/logging.js.map +1 -0
- package/dist/middleware/observability.d.ts +104 -0
- package/dist/middleware/observability.d.ts.map +1 -0
- package/dist/middleware/observability.js +231 -0
- package/dist/middleware/observability.js.map +1 -0
- package/dist/middleware/rateLimit.d.ts +83 -0
- package/dist/middleware/rateLimit.d.ts.map +1 -0
- package/dist/middleware/rateLimit.js +255 -0
- package/dist/middleware/rateLimit.js.map +1 -0
- package/dist/middleware/securityHeaders.d.ts +19 -0
- package/dist/middleware/securityHeaders.d.ts.map +1 -0
- package/dist/middleware/securityHeaders.js +61 -0
- package/dist/middleware/securityHeaders.js.map +1 -0
- package/dist/middleware/versioning.d.ts +62 -0
- package/dist/middleware/versioning.d.ts.map +1 -0
- package/dist/middleware/versioning.js +178 -0
- package/dist/middleware/versioning.js.map +1 -0
- package/dist/oidc/backends/email-password.d.ts +3 -0
- package/dist/oidc/backends/email-password.d.ts.map +1 -0
- package/dist/oidc/backends/email-password.js +37 -0
- package/dist/oidc/backends/email-password.js.map +1 -0
- package/dist/oidc/backends/federated.d.ts +13 -0
- package/dist/oidc/backends/federated.d.ts.map +1 -0
- package/dist/oidc/backends/federated.js +225 -0
- package/dist/oidc/backends/federated.js.map +1 -0
- package/dist/oidc/backends/index.d.ts +3 -0
- package/dist/oidc/backends/index.d.ts.map +1 -0
- package/dist/oidc/backends/index.js +3 -0
- package/dist/oidc/backends/index.js.map +1 -0
- package/dist/oidc/body.d.ts +3 -0
- package/dist/oidc/body.d.ts.map +1 -0
- package/dist/oidc/body.js +23 -0
- package/dist/oidc/body.js.map +1 -0
- package/dist/oidc/discovery.d.ts +3 -0
- package/dist/oidc/discovery.d.ts.map +1 -0
- package/dist/oidc/discovery.js +66 -0
- package/dist/oidc/discovery.js.map +1 -0
- package/dist/oidc/endpoints/authorize.d.ts +12 -0
- package/dist/oidc/endpoints/authorize.d.ts.map +1 -0
- package/dist/oidc/endpoints/authorize.js +148 -0
- package/dist/oidc/endpoints/authorize.js.map +1 -0
- package/dist/oidc/endpoints/client-auth.d.ts +9 -0
- package/dist/oidc/endpoints/client-auth.d.ts.map +1 -0
- package/dist/oidc/endpoints/client-auth.js +52 -0
- package/dist/oidc/endpoints/client-auth.js.map +1 -0
- package/dist/oidc/endpoints/index.d.ts +9 -0
- package/dist/oidc/endpoints/index.d.ts.map +1 -0
- package/dist/oidc/endpoints/index.js +9 -0
- package/dist/oidc/endpoints/index.js.map +1 -0
- package/dist/oidc/endpoints/introspection.d.ts +9 -0
- package/dist/oidc/endpoints/introspection.d.ts.map +1 -0
- package/dist/oidc/endpoints/introspection.js +57 -0
- package/dist/oidc/endpoints/introspection.js.map +1 -0
- package/dist/oidc/endpoints/jwks.d.ts +4 -0
- package/dist/oidc/endpoints/jwks.d.ts.map +1 -0
- package/dist/oidc/endpoints/jwks.js +11 -0
- package/dist/oidc/endpoints/jwks.js.map +1 -0
- package/dist/oidc/endpoints/logout.d.ts +12 -0
- package/dist/oidc/endpoints/logout.d.ts.map +1 -0
- package/dist/oidc/endpoints/logout.js +92 -0
- package/dist/oidc/endpoints/logout.js.map +1 -0
- package/dist/oidc/endpoints/register.d.ts +9 -0
- package/dist/oidc/endpoints/register.d.ts.map +1 -0
- package/dist/oidc/endpoints/register.js +104 -0
- package/dist/oidc/endpoints/register.js.map +1 -0
- package/dist/oidc/endpoints/revocation.d.ts +9 -0
- package/dist/oidc/endpoints/revocation.d.ts.map +1 -0
- package/dist/oidc/endpoints/revocation.js +31 -0
- package/dist/oidc/endpoints/revocation.js.map +1 -0
- package/dist/oidc/endpoints/token.d.ts +11 -0
- package/dist/oidc/endpoints/token.d.ts.map +1 -0
- package/dist/oidc/endpoints/token.js +167 -0
- package/dist/oidc/endpoints/token.js.map +1 -0
- package/dist/oidc/endpoints/userinfo.d.ts +10 -0
- package/dist/oidc/endpoints/userinfo.d.ts.map +1 -0
- package/dist/oidc/endpoints/userinfo.js +58 -0
- package/dist/oidc/endpoints/userinfo.js.map +1 -0
- package/dist/oidc/index.d.ts +79 -0
- package/dist/oidc/index.d.ts.map +1 -0
- package/dist/oidc/index.js +44 -0
- package/dist/oidc/index.js.map +1 -0
- package/dist/oidc/keys/index.d.ts +2 -0
- package/dist/oidc/keys/index.d.ts.map +1 -0
- package/dist/oidc/keys/index.js +2 -0
- package/dist/oidc/keys/index.js.map +1 -0
- package/dist/oidc/keys/jwk.d.ts +3 -0
- package/dist/oidc/keys/jwk.d.ts.map +1 -0
- package/dist/oidc/keys/jwk.js +171 -0
- package/dist/oidc/keys/jwk.js.map +1 -0
- package/dist/oidc/provider.d.ts +10 -0
- package/dist/oidc/provider.d.ts.map +1 -0
- package/dist/oidc/provider.js +152 -0
- package/dist/oidc/provider.js.map +1 -0
- package/dist/oidc/rate-limit.d.ts +9 -0
- package/dist/oidc/rate-limit.d.ts.map +1 -0
- package/dist/oidc/rate-limit.js +61 -0
- package/dist/oidc/rate-limit.js.map +1 -0
- package/dist/oidc/stores/index.d.ts +124 -0
- package/dist/oidc/stores/index.d.ts.map +1 -0
- package/dist/oidc/stores/index.js +337 -0
- package/dist/oidc/stores/index.js.map +1 -0
- package/dist/oidc/tokens/index.d.ts +4 -0
- package/dist/oidc/tokens/index.d.ts.map +1 -0
- package/dist/oidc/tokens/index.js +158 -0
- package/dist/oidc/tokens/index.js.map +1 -0
- package/dist/oidc/types.d.ts +442 -0
- package/dist/oidc/types.d.ts.map +1 -0
- package/dist/oidc/types.js +2 -0
- package/dist/oidc/types.js.map +1 -0
- package/dist/oidc/ui/consent.d.ts +12 -0
- package/dist/oidc/ui/consent.d.ts.map +1 -0
- package/dist/oidc/ui/consent.js +180 -0
- package/dist/oidc/ui/consent.js.map +1 -0
- package/dist/oidc/ui/index.d.ts +3 -0
- package/dist/oidc/ui/index.d.ts.map +1 -0
- package/dist/oidc/ui/index.js +3 -0
- package/dist/oidc/ui/index.js.map +1 -0
- package/dist/oidc/ui/login.d.ts +12 -0
- package/dist/oidc/ui/login.d.ts.map +1 -0
- package/dist/oidc/ui/login.js +159 -0
- package/dist/oidc/ui/login.js.map +1 -0
- package/dist/oidc/util.d.ts +5 -0
- package/dist/oidc/util.d.ts.map +1 -0
- package/dist/oidc/util.js +67 -0
- package/dist/oidc/util.js.map +1 -0
- package/dist/openapi/generator.d.ts +131 -0
- package/dist/openapi/generator.d.ts.map +1 -0
- package/dist/openapi/generator.js +609 -0
- package/dist/openapi/generator.js.map +1 -0
- package/dist/openapi/index.d.ts +5 -0
- package/dist/openapi/index.d.ts.map +1 -0
- package/dist/openapi/index.js +3 -0
- package/dist/openapi/index.js.map +1 -0
- package/dist/openapi/schema.d.ts +51 -0
- package/dist/openapi/schema.d.ts.map +1 -0
- package/dist/openapi/schema.js +296 -0
- package/dist/openapi/schema.js.map +1 -0
- package/dist/resource/batch.d.ts +40 -0
- package/dist/resource/batch.d.ts.map +1 -0
- package/dist/resource/batch.js +144 -0
- package/dist/resource/batch.js.map +1 -0
- package/dist/resource/capabilities.d.ts +29 -0
- package/dist/resource/capabilities.d.ts.map +1 -0
- package/dist/resource/capabilities.js +224 -0
- package/dist/resource/capabilities.js.map +1 -0
- package/dist/resource/changelog.d.ts +41 -0
- package/dist/resource/changelog.d.ts.map +1 -0
- package/dist/resource/changelog.js +275 -0
- package/dist/resource/changelog.js.map +1 -0
- package/dist/resource/error.d.ts +110 -0
- package/dist/resource/error.d.ts.map +1 -0
- package/dist/resource/error.js +276 -0
- package/dist/resource/error.js.map +1 -0
- package/dist/resource/etag.d.ts +30 -0
- package/dist/resource/etag.d.ts.map +1 -0
- package/dist/resource/etag.js +148 -0
- package/dist/resource/etag.js.map +1 -0
- package/dist/resource/filter.d.ts +36 -0
- package/dist/resource/filter.d.ts.map +1 -0
- package/dist/resource/filter.js +1136 -0
- package/dist/resource/filter.js.map +1 -0
- package/dist/resource/hook.d.ts +13 -0
- package/dist/resource/hook.d.ts.map +1 -0
- package/dist/resource/hook.js +976 -0
- package/dist/resource/hook.js.map +1 -0
- package/dist/resource/mutate.d.ts +49 -0
- package/dist/resource/mutate.d.ts.map +1 -0
- package/dist/resource/mutate.js +247 -0
- package/dist/resource/mutate.js.map +1 -0
- package/dist/resource/operator-equivalence.d.ts +54 -0
- package/dist/resource/operator-equivalence.d.ts.map +1 -0
- package/dist/resource/operator-equivalence.js +342 -0
- package/dist/resource/operator-equivalence.js.map +1 -0
- package/dist/resource/pagination.d.ts +63 -0
- package/dist/resource/pagination.d.ts.map +1 -0
- package/dist/resource/pagination.js +294 -0
- package/dist/resource/pagination.js.map +1 -0
- package/dist/resource/procedures.d.ts +28 -0
- package/dist/resource/procedures.d.ts.map +1 -0
- package/dist/resource/procedures.js +197 -0
- package/dist/resource/procedures.js.map +1 -0
- package/dist/resource/query.d.ts +37 -0
- package/dist/resource/query.d.ts.map +1 -0
- package/dist/resource/query.js +246 -0
- package/dist/resource/query.js.map +1 -0
- package/dist/resource/relations.d.ts +70 -0
- package/dist/resource/relations.d.ts.map +1 -0
- package/dist/resource/relations.js +395 -0
- package/dist/resource/relations.js.map +1 -0
- package/dist/resource/search-outbox.d.ts +38 -0
- package/dist/resource/search-outbox.d.ts.map +1 -0
- package/dist/resource/search-outbox.js +121 -0
- package/dist/resource/search-outbox.js.map +1 -0
- package/dist/resource/search.d.ts +14 -0
- package/dist/resource/search.d.ts.map +1 -0
- package/dist/resource/search.js +267 -0
- package/dist/resource/search.js.map +1 -0
- package/dist/resource/secure-query.d.ts +55 -0
- package/dist/resource/secure-query.d.ts.map +1 -0
- package/dist/resource/secure-query.js +175 -0
- package/dist/resource/secure-query.js.map +1 -0
- package/dist/resource/subscription.d.ts +46 -0
- package/dist/resource/subscription.d.ts.map +1 -0
- package/dist/resource/subscription.js +684 -0
- package/dist/resource/subscription.js.map +1 -0
- package/dist/resource/track-mutations.d.ts +58 -0
- package/dist/resource/track-mutations.d.ts.map +1 -0
- package/dist/resource/track-mutations.js +721 -0
- package/dist/resource/track-mutations.js.map +1 -0
- package/dist/resource/types.d.ts +298 -0
- package/dist/resource/types.d.ts.map +1 -0
- package/dist/resource/types.js +2 -0
- package/dist/resource/types.js.map +1 -0
- package/dist/search/index.d.ts +11 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +22 -0
- package/dist/search/index.js.map +1 -0
- package/dist/search/memory.d.ts +6 -0
- package/dist/search/memory.d.ts.map +1 -0
- package/dist/search/memory.js +70 -0
- package/dist/search/memory.js.map +1 -0
- package/dist/search/opensearch.d.ts +47 -0
- package/dist/search/opensearch.d.ts.map +1 -0
- package/dist/search/opensearch.js +126 -0
- package/dist/search/opensearch.js.map +1 -0
- package/dist/search/postgres-fts.d.ts +16 -0
- package/dist/search/postgres-fts.d.ts.map +1 -0
- package/dist/search/postgres-fts.js +171 -0
- package/dist/search/postgres-fts.js.map +1 -0
- package/dist/search/sqlite-fts.d.ts +14 -0
- package/dist/search/sqlite-fts.d.ts.map +1 -0
- package/dist/search/sqlite-fts.js +185 -0
- package/dist/search/sqlite-fts.js.map +1 -0
- package/dist/search/types.d.ts +49 -0
- package/dist/search/types.d.ts.map +1 -0
- package/dist/search/types.js +2 -0
- package/dist/search/types.js.map +1 -0
- package/dist/server/app.d.ts +33 -0
- package/dist/server/app.d.ts.map +1 -0
- package/dist/server/app.js +82 -0
- package/dist/server/app.js.map +1 -0
- package/dist/server/context.d.ts +16 -0
- package/dist/server/context.d.ts.map +1 -0
- package/dist/server/context.js +12 -0
- package/dist/server/context.js.map +1 -0
- package/dist/server/env.d.ts +4 -0
- package/dist/server/env.d.ts.map +1 -0
- package/dist/server/env.js +7 -0
- package/dist/server/env.js.map +1 -0
- package/dist/server/lifecycle.d.ts +6 -0
- package/dist/server/lifecycle.d.ts.map +1 -0
- package/dist/server/lifecycle.js +28 -0
- package/dist/server/lifecycle.js.map +1 -0
- package/dist/server/logger.d.ts +28 -0
- package/dist/server/logger.d.ts.map +1 -0
- package/dist/server/logger.js +58 -0
- package/dist/server/logger.js.map +1 -0
- package/dist/server/node.d.ts +18 -0
- package/dist/server/node.d.ts.map +1 -0
- package/dist/server/node.js +47 -0
- package/dist/server/node.js.map +1 -0
- package/dist/server/request.d.ts +4 -0
- package/dist/server/request.d.ts.map +1 -0
- package/dist/server/request.js +29 -0
- package/dist/server/request.js.map +1 -0
- package/dist/server/sse.d.ts +26 -0
- package/dist/server/sse.d.ts.map +1 -0
- package/dist/server/sse.js +115 -0
- package/dist/server/sse.js.map +1 -0
- package/dist/storage/index.d.ts +15 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +41 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/local.d.ts +25 -0
- package/dist/storage/local.d.ts.map +1 -0
- package/dist/storage/local.js +172 -0
- package/dist/storage/local.js.map +1 -0
- package/dist/storage/memory.d.ts +20 -0
- package/dist/storage/memory.d.ts.map +1 -0
- package/dist/storage/memory.js +82 -0
- package/dist/storage/memory.js.map +1 -0
- package/dist/storage/r2.d.ts +62 -0
- package/dist/storage/r2.d.ts.map +1 -0
- package/dist/storage/r2.js +124 -0
- package/dist/storage/r2.js.map +1 -0
- package/dist/storage/resource.d.ts +50 -0
- package/dist/storage/resource.d.ts.map +1 -0
- package/dist/storage/resource.js +346 -0
- package/dist/storage/resource.js.map +1 -0
- package/dist/storage/s3.d.ts +29 -0
- package/dist/storage/s3.d.ts.map +1 -0
- package/dist/storage/s3.js +202 -0
- package/dist/storage/s3.js.map +1 -0
- package/dist/storage/types.d.ts +75 -0
- package/dist/storage/types.d.ts.map +1 -0
- package/dist/storage/types.js +17 -0
- package/dist/storage/types.js.map +1 -0
- package/dist/storage/validation.d.ts +11 -0
- package/dist/storage/validation.d.ts.map +1 -0
- package/dist/storage/validation.js +38 -0
- package/dist/storage/validation.js.map +1 -0
- package/dist/tasks/cloudflare-queues.d.ts +63 -0
- package/dist/tasks/cloudflare-queues.d.ts.map +1 -0
- package/dist/tasks/cloudflare-queues.js +172 -0
- package/dist/tasks/cloudflare-queues.js.map +1 -0
- package/dist/tasks/concurrency.d.ts +8 -0
- package/dist/tasks/concurrency.d.ts.map +1 -0
- package/dist/tasks/concurrency.js +27 -0
- package/dist/tasks/concurrency.js.map +1 -0
- package/dist/tasks/define.d.ts +25 -0
- package/dist/tasks/define.d.ts.map +1 -0
- package/dist/tasks/define.js +17 -0
- package/dist/tasks/define.js.map +1 -0
- package/dist/tasks/dlq.d.ts +29 -0
- package/dist/tasks/dlq.d.ts.map +1 -0
- package/dist/tasks/dlq.js +185 -0
- package/dist/tasks/dlq.js.map +1 -0
- package/dist/tasks/idempotency.d.ts +13 -0
- package/dist/tasks/idempotency.d.ts.map +1 -0
- package/dist/tasks/idempotency.js +21 -0
- package/dist/tasks/idempotency.js.map +1 -0
- package/dist/tasks/index.d.ts +27 -0
- package/dist/tasks/index.d.ts.map +1 -0
- package/dist/tasks/index.js +15 -0
- package/dist/tasks/index.js.map +1 -0
- package/dist/tasks/integration.d.ts +18 -0
- package/dist/tasks/integration.d.ts.map +1 -0
- package/dist/tasks/integration.js +86 -0
- package/dist/tasks/integration.js.map +1 -0
- package/dist/tasks/lock.d.ts +9 -0
- package/dist/tasks/lock.d.ts.map +1 -0
- package/dist/tasks/lock.js +31 -0
- package/dist/tasks/lock.js.map +1 -0
- package/dist/tasks/queue.d.ts +11 -0
- package/dist/tasks/queue.d.ts.map +1 -0
- package/dist/tasks/queue.js +75 -0
- package/dist/tasks/queue.js.map +1 -0
- package/dist/tasks/recurring.d.ts +16 -0
- package/dist/tasks/recurring.d.ts.map +1 -0
- package/dist/tasks/recurring.js +173 -0
- package/dist/tasks/recurring.js.map +1 -0
- package/dist/tasks/retry.d.ts +4 -0
- package/dist/tasks/retry.d.ts.map +1 -0
- package/dist/tasks/retry.js +29 -0
- package/dist/tasks/retry.js.map +1 -0
- package/dist/tasks/scheduler.d.ts +22 -0
- package/dist/tasks/scheduler.d.ts.map +1 -0
- package/dist/tasks/scheduler.js +125 -0
- package/dist/tasks/scheduler.js.map +1 -0
- package/dist/tasks/storage.d.ts +17 -0
- package/dist/tasks/storage.d.ts.map +1 -0
- package/dist/tasks/storage.js +231 -0
- package/dist/tasks/storage.js.map +1 -0
- package/dist/tasks/types.d.ts +144 -0
- package/dist/tasks/types.d.ts.map +1 -0
- package/dist/tasks/types.js +2 -0
- package/dist/tasks/types.js.map +1 -0
- package/dist/tasks/worker.d.ts +21 -0
- package/dist/tasks/worker.d.ts.map +1 -0
- package/dist/tasks/worker.js +267 -0
- package/dist/tasks/worker.js.map +1 -0
- package/dist/ui/admin-auth.d.ts +65 -0
- package/dist/ui/admin-auth.d.ts.map +1 -0
- package/dist/ui/admin-auth.js +248 -0
- package/dist/ui/admin-auth.js.map +1 -0
- package/dist/ui/data-explorer.d.ts +11 -0
- package/dist/ui/data-explorer.d.ts.map +1 -0
- package/dist/ui/data-explorer.js +414 -0
- package/dist/ui/data-explorer.js.map +1 -0
- package/dist/ui/html/client/data-explorer-app.d.ts +2 -0
- package/dist/ui/html/client/data-explorer-app.d.ts.map +1 -0
- package/dist/ui/html/client/data-explorer-app.js +441 -0
- package/dist/ui/html/client/data-explorer-app.js.map +1 -0
- package/dist/ui/html/client/htmx-vendor.d.ts +3 -0
- package/dist/ui/html/client/htmx-vendor.d.ts.map +1 -0
- package/dist/ui/html/client/htmx-vendor.js +5 -0
- package/dist/ui/html/client/htmx-vendor.js.map +1 -0
- package/dist/ui/html/client/runtime.d.ts +2 -0
- package/dist/ui/html/client/runtime.d.ts.map +1 -0
- package/dist/ui/html/client/runtime.js +198 -0
- package/dist/ui/html/client/runtime.js.map +1 -0
- package/dist/ui/html/components/index.d.ts +79 -0
- package/dist/ui/html/components/index.d.ts.map +1 -0
- package/dist/ui/html/components/index.js +159 -0
- package/dist/ui/html/components/index.js.map +1 -0
- package/dist/ui/html/icons.d.ts +3 -0
- package/dist/ui/html/icons.d.ts.map +1 -0
- package/dist/ui/html/icons.js +23 -0
- package/dist/ui/html/icons.js.map +1 -0
- package/dist/ui/html/index.d.ts +6 -0
- package/dist/ui/html/index.d.ts.map +1 -0
- package/dist/ui/html/index.js +6 -0
- package/dist/ui/html/index.js.map +1 -0
- package/dist/ui/html/layout.d.ts +19 -0
- package/dist/ui/html/layout.d.ts.map +1 -0
- package/dist/ui/html/layout.js +178 -0
- package/dist/ui/html/layout.js.map +1 -0
- package/dist/ui/html/pages/admin-audit.d.ts +21 -0
- package/dist/ui/html/pages/admin-audit.d.ts.map +1 -0
- package/dist/ui/html/pages/admin-audit.js +130 -0
- package/dist/ui/html/pages/admin-audit.js.map +1 -0
- package/dist/ui/html/pages/api-explorer.d.ts +40 -0
- package/dist/ui/html/pages/api-explorer.d.ts.map +1 -0
- package/dist/ui/html/pages/api-explorer.js +153 -0
- package/dist/ui/html/pages/api-explorer.js.map +1 -0
- package/dist/ui/html/pages/changelog.d.ts +27 -0
- package/dist/ui/html/pages/changelog.d.ts.map +1 -0
- package/dist/ui/html/pages/changelog.js +129 -0
- package/dist/ui/html/pages/changelog.js.map +1 -0
- package/dist/ui/html/pages/dashboard.d.ts +20 -0
- package/dist/ui/html/pages/dashboard.d.ts.map +1 -0
- package/dist/ui/html/pages/dashboard.js +50 -0
- package/dist/ui/html/pages/dashboard.js.map +1 -0
- package/dist/ui/html/pages/data-explorer.d.ts +48 -0
- package/dist/ui/html/pages/data-explorer.d.ts.map +1 -0
- package/dist/ui/html/pages/data-explorer.js +167 -0
- package/dist/ui/html/pages/data-explorer.js.map +1 -0
- package/dist/ui/html/pages/errors.d.ts +13 -0
- package/dist/ui/html/pages/errors.d.ts.map +1 -0
- package/dist/ui/html/pages/errors.js +38 -0
- package/dist/ui/html/pages/errors.js.map +1 -0
- package/dist/ui/html/pages/filter-tester.d.ts +21 -0
- package/dist/ui/html/pages/filter-tester.d.ts.map +1 -0
- package/dist/ui/html/pages/filter-tester.js +161 -0
- package/dist/ui/html/pages/filter-tester.js.map +1 -0
- package/dist/ui/html/pages/index.d.ts +15 -0
- package/dist/ui/html/pages/index.d.ts.map +1 -0
- package/dist/ui/html/pages/index.js +15 -0
- package/dist/ui/html/pages/index.js.map +1 -0
- package/dist/ui/html/pages/kv-inspector.d.ts +20 -0
- package/dist/ui/html/pages/kv-inspector.d.ts.map +1 -0
- package/dist/ui/html/pages/kv-inspector.js +130 -0
- package/dist/ui/html/pages/kv-inspector.js.map +1 -0
- package/dist/ui/html/pages/requests.d.ts +23 -0
- package/dist/ui/html/pages/requests.d.ts.map +1 -0
- package/dist/ui/html/pages/requests.js +127 -0
- package/dist/ui/html/pages/requests.js.map +1 -0
- package/dist/ui/html/pages/resources.d.ts +27 -0
- package/dist/ui/html/pages/resources.d.ts.map +1 -0
- package/dist/ui/html/pages/resources.js +85 -0
- package/dist/ui/html/pages/resources.js.map +1 -0
- package/dist/ui/html/pages/sessions.d.ts +24 -0
- package/dist/ui/html/pages/sessions.d.ts.map +1 -0
- package/dist/ui/html/pages/sessions.js +157 -0
- package/dist/ui/html/pages/sessions.js.map +1 -0
- package/dist/ui/html/pages/subscriptions.d.ts +32 -0
- package/dist/ui/html/pages/subscriptions.d.ts.map +1 -0
- package/dist/ui/html/pages/subscriptions.js +138 -0
- package/dist/ui/html/pages/subscriptions.js.map +1 -0
- package/dist/ui/html/pages/tasks.d.ts +42 -0
- package/dist/ui/html/pages/tasks.d.ts.map +1 -0
- package/dist/ui/html/pages/tasks.js +225 -0
- package/dist/ui/html/pages/tasks.js.map +1 -0
- package/dist/ui/html/pages/users.d.ts +29 -0
- package/dist/ui/html/pages/users.d.ts.map +1 -0
- package/dist/ui/html/pages/users.js +192 -0
- package/dist/ui/html/pages/users.js.map +1 -0
- package/dist/ui/html/styles.d.ts +2 -0
- package/dist/ui/html/styles.d.ts.map +1 -0
- package/dist/ui/html/styles.js +992 -0
- package/dist/ui/html/styles.js.map +1 -0
- package/dist/ui/html/utils.d.ts +14 -0
- package/dist/ui/html/utils.d.ts.map +1 -0
- package/dist/ui/html/utils.js +76 -0
- package/dist/ui/html/utils.js.map +1 -0
- package/dist/ui/index.d.ts +13 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +7 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/kv-inspector.d.ts +11 -0
- package/dist/ui/kv-inspector.d.ts.map +1 -0
- package/dist/ui/kv-inspector.js +332 -0
- package/dist/ui/kv-inspector.js.map +1 -0
- package/dist/ui/middleware.d.ts +76 -0
- package/dist/ui/middleware.d.ts.map +1 -0
- package/dist/ui/middleware.js +1210 -0
- package/dist/ui/middleware.js.map +1 -0
- package/dist/ui/schema-registry.d.ts +82 -0
- package/dist/ui/schema-registry.d.ts.map +1 -0
- package/dist/ui/schema-registry.js +165 -0
- package/dist/ui/schema-registry.js.map +1 -0
- package/dist/ui/task-monitor.d.ts +12 -0
- package/dist/ui/task-monitor.d.ts.map +1 -0
- package/dist/ui/task-monitor.js +264 -0
- package/dist/ui/task-monitor.js.map +1 -0
- package/package.json +202 -7
package/README.md
ADDED
|
@@ -0,0 +1,839 @@
|
|
|
1
|
+
# Covara
|
|
2
|
+
|
|
3
|
+
**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.
|
|
4
|
+
|
|
5
|
+
## The Goal
|
|
6
|
+
|
|
7
|
+
Every product backend is the same 80%: CRUD endpoints, filtering, pagination, auth, sessions, password reset, file uploads, webhooks for payments, transactional email, a job queue, and a client that talks to all of it. You rewrite this plumbing for every project, and the pieces never quite fit together — your realtime layer doesn't know about your auth scopes, your client types drift from your API, your offline cache fights your subscriptions.
|
|
8
|
+
|
|
9
|
+
Covara's goal is to make that 80% *one coherent system* derived from a single source of truth: your Drizzle schema.
|
|
10
|
+
|
|
11
|
+
- **Define a table** → get a full REST API with filtering, pagination, aggregations, batch ops, and OpenAPI docs.
|
|
12
|
+
- **Add an auth scope** → it's enforced everywhere: queries, mutations, subscriptions, search.
|
|
13
|
+
- **Mutate data anywhere** — generated endpoint, custom route, RPC — and every subscribed client updates in real time.
|
|
14
|
+
- **Use the client** → full TypeScript inference, optimistic updates, offline queue, automatic reconnect. In React, React Native, or plain TS.
|
|
15
|
+
|
|
16
|
+
The remaining 20% — your business logic — goes in lifecycle hooks, RPC procedures, and ordinary Hono routes, with the framework's tracking and typing intact.
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
// server: a table becomes an API
|
|
20
|
+
const app = createCovara({ cors: true })
|
|
21
|
+
.resource("/todos", todosTable, {
|
|
22
|
+
id: todosTable.id,
|
|
23
|
+
db,
|
|
24
|
+
auth: { update: async (user) => rsql`userId=="${user.id}"` },
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// client: the API becomes live UI
|
|
28
|
+
function TodoList() {
|
|
29
|
+
const { items, mutate } = useLiveList<Todo>("/api/todos", { orderBy: "position" });
|
|
30
|
+
return items.map((todo) => (
|
|
31
|
+
<Todo key={todo.id} {...todo} onDelete={() => mutate.delete(todo.id)} />
|
|
32
|
+
));
|
|
33
|
+
// creates/updates/deletes apply optimistically, sync offline,
|
|
34
|
+
// and stream to every other connected client over SSE
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Features
|
|
39
|
+
|
|
40
|
+
### Core API
|
|
41
|
+
- **Automatic REST API** - Full CRUD endpoints from your Drizzle schema
|
|
42
|
+
- **Real-time Subscriptions** - SSE with changelog-based updates, sequence numbers, and seamless reconnection
|
|
43
|
+
- **Relations & Joins** - `belongsTo`, `hasOne`, `hasMany`, `manyToMany` with efficient batch loading
|
|
44
|
+
- **RSQL Filtering** - Comprehensive query language (30+ operators) plus custom operators
|
|
45
|
+
- **Cursor Pagination** - Keyset pagination with multi-field ordering
|
|
46
|
+
- **Aggregations** - Group by, count, sum, avg, min, max, with `HAVING` filtering on aggregate output
|
|
47
|
+
- **Nested Write-Through** - Create `belongsTo` parents and `hasMany`/`hasOne` children in one atomic POST
|
|
48
|
+
- **Soft Delete** - Mark rows deleted instead of removing them; reads hide them unless `?withDeleted=true`
|
|
49
|
+
- **Batch Operations** - Bulk create, update, delete with limits, plus bulk upsert (`POST /batch/upsert`)
|
|
50
|
+
- **Writable Enforcement** - `fields.writable` is an enforced allowlist (mass-assignment protection); `strictInput` rejects unknown fields
|
|
51
|
+
- **Computed Fields** - Virtual `computed` fields added to every response and subscription event
|
|
52
|
+
- **Optimistic Locking** - ETags, If-Match preconditions with compare-and-swap, auto-incrementing version fields
|
|
53
|
+
- **Full-Text Search** - Built-in SQLite FTS5 / Postgres `tsvector` / OpenSearch / in-memory adapters, with an opt-in transactional outbox for at-least-once index convergence
|
|
54
|
+
- **RPC Procedures & Lifecycle Hooks** - Custom Zod-validated endpoints and before/after hooks on every operation
|
|
55
|
+
- **Mutation Tracking** - Wrap your Drizzle db so custom routes feed subscriptions and cache invalidation automatically
|
|
56
|
+
|
|
57
|
+
### Runs Everywhere
|
|
58
|
+
- **Standalone Node** - `startServer(app)` via `covara/node`
|
|
59
|
+
- **Cloudflare Workers** - `export default app`, D1/Postgres, `nodejs_compat`
|
|
60
|
+
- **Durable Object KV** - Cross-isolate subscriptions, rate limits, and sessions on Workers without Redis
|
|
61
|
+
- **SQLite & PostgreSQL** - libsql, better-sqlite3, D1, postgres-js, Neon, PGlite via Drizzle
|
|
62
|
+
|
|
63
|
+
### Authentication & Security
|
|
64
|
+
- **OIDC Provider** - Built-in OpenID Connect server with PKCE, token revocation (RFC 7009) and introspection (RFC 7662)
|
|
65
|
+
- **OIDC Hardening** - Component-wise redirect-URI validation, PKCE-required public clients (plain rejected), federated id_token verification, endpoint rate limiting, KV-backed stores by default
|
|
66
|
+
- **Dynamic Client Registration & Consent Revocation** - Opt-in `POST /register`, plus `POST /consent/revoke` and consent TTL
|
|
67
|
+
- **Federated Login** - Google, Microsoft, Okta, Auth0, Keycloak, custom
|
|
68
|
+
- **JWT Auth** - JWT bearer adapter on the server, `JWTClient` + `useJWTAuth` hook on the client with pluggable token storage (localStorage, memory, AsyncStorage)
|
|
69
|
+
- **Session Auth** - Auth.js, Passport.js, and session adapters with session rotation on login
|
|
70
|
+
- **Multi-Factor Auth** - Opt-in TOTP MFA with backup codes
|
|
71
|
+
- **Magic Links** - Opt-in passwordless email login
|
|
72
|
+
- **API Keys** - Standalone helpers to create, verify, rotate, and revoke hashed API keys
|
|
73
|
+
- **Password Hashing & Policy** - Built-in scrypt `hashPassword`/`verifyPassword`/`needsRehash` (Workers-safe) plus an enforceable password policy
|
|
74
|
+
- **Account Security** - Opt-in CSRF protection, login throttling, email verification, password reset
|
|
75
|
+
- **Security Headers** - HSTS, `X-Frame-Options`, MIME-sniffing protection, and more, auto-mounted by `createCovara`; opt-in CSP (so it never blocks your frontend)
|
|
76
|
+
- **Authorization Scopes** - Row-level security with RSQL expressions, enforced across reads, writes, subscriptions, and search
|
|
77
|
+
- **Field-level Read Masking** - `fields.readable` allowlist strips non-readable columns from every response and subscription event (cannot be bypassed via `?select=`)
|
|
78
|
+
|
|
79
|
+
### File Storage
|
|
80
|
+
- **Storage Adapters** - Local disk, S3, Cloudflare R2 (native binding or S3-compat), and in-memory behind one `StorageAdapter` interface
|
|
81
|
+
- **File Resources** - `useFileResource` generates upload/download/list/delete endpoints with MIME and size validation, per-user key generation, and auth scopes
|
|
82
|
+
- **Presigned URLs** - Optional direct-to-bucket uploads/downloads with configurable expiry
|
|
83
|
+
- **React Hooks** - `useFileUpload` (with progress), `useFile`, `useFiles`; `getDownloadUrl()` for React Native
|
|
84
|
+
|
|
85
|
+
### Background Processing
|
|
86
|
+
- **Task Queue** - Distributed background jobs with Redis, Durable Objects, or in-memory backends
|
|
87
|
+
- **Cloudflare Queues** - Producer/consumer adapter for running tasks on Workers without a poller
|
|
88
|
+
- **Retry Strategies** - Exponential, linear, or fixed backoff
|
|
89
|
+
- **Scheduling** - Delayed execution, cron expressions, recurring tasks with a missed-occurrence `catchup` policy
|
|
90
|
+
- **Progress & Result TTL** - `ctx.reportProgress`, heartbeats, and `resultTtlMs` result expiry
|
|
91
|
+
- **Idempotency & Concurrency** - Per-task idempotency keys and enforced `maxConcurrency`
|
|
92
|
+
- **Graceful Drain** - `worker.drain()` / `worker.stop({ drain: true })`
|
|
93
|
+
- **Dead Letter Queue** - Failed task management with replay lineage and an `onDlqEnqueue` alerting hook
|
|
94
|
+
|
|
95
|
+
### Email
|
|
96
|
+
- **Unified Adapters** - `covara/email` with **Resend** and **Cloudflare Email Service** adapters behind one `EmailAdapter` interface
|
|
97
|
+
- **Template Builder** - Fluent `createEmail().heading().button().code().build()` rendering responsive, escaped HTML + a plaintext fallback, with theming
|
|
98
|
+
- **Batch Sending** - `sendEmailBatch` for bulk delivery
|
|
99
|
+
|
|
100
|
+
### Billing
|
|
101
|
+
- **One Interface, Four Providers** - `covara/billing` over **Stripe**, **Lemon Squeezy**, **Paddle**, and **Polar.sh** (fetch-based, no SDK deps, Workers-safe)
|
|
102
|
+
- **Plans, One-Time & Usage** - Define subscription/one-time/usage plans by key; checkout, subscription management, `reportUsage`, hosted portal
|
|
103
|
+
- **Credits Ledger** - KV-backed atomic `grant`/`consume`/`balance`/`history`
|
|
104
|
+
- **Webhooks** - Per-provider signature verification, idempotent delivery dedupe, and automatic credit granting on `payment.succeeded`
|
|
105
|
+
- **Router & Client** - `createBillingRouter` plus `client.billing.*` and `useCredits`/`useSubscription`/`useCheckout` hooks
|
|
106
|
+
|
|
107
|
+
### Client Library
|
|
108
|
+
- **Type-safe Client** - Full TypeScript inference, `select` projections that narrow return types, typed filter builder, generated types from your API
|
|
109
|
+
- **React Hooks** - `useLiveList`, `useInfiniteList`, `useMutation`, `useSearch`, `useAuth`, `useJWTAuth`, `useFileUpload`/`useFile`/`useFiles`, `useCredits`/`useSubscription`/`useCheckout`, `usePublicEnv`, plus query invalidation and prefetch
|
|
110
|
+
- **React Native Support** - No DOM assumptions: pluggable `TokenStorage` (AsyncStorage-compatible), environment-aware transport and offline backends, `getDownloadUrl()` for native file handling
|
|
111
|
+
- **Resilient Transport** - Per-request `AbortSignal` + timeout, automatic 401 refresh-and-retry, SSE reconnect with jitter
|
|
112
|
+
- **Offline Support** - Optimistic updates, mutation queue, field-level merge, multi-tab coherence, IndexedDB backend
|
|
113
|
+
- **Auth Strategies** - OIDC (PKCE flow, token refresh), JWT, bearer, API key, or cookie sessions — selected per client or auto-detected
|
|
114
|
+
- **HMR-safe** - `getOrCreateClient` for development
|
|
115
|
+
|
|
116
|
+
### Environment Variables
|
|
117
|
+
- **Type-safe Configuration** - Define and validate env vars with Zod via `createEnv` / `envVariable`
|
|
118
|
+
- **Public and Private Vars** - `PUBLIC_`-prefixed or explicitly-marked vars served to clients via `usePublicEnv` (with ETag)
|
|
119
|
+
- **Client Access** - Typed `fetchPublicEnv` / `createEnvClient` and a `usePublicEnv` React hook
|
|
120
|
+
|
|
121
|
+
### Developer Experience
|
|
122
|
+
- **Project Scaffolding** - `npx covara create my-app` (Node/Workers templates, SQLite/Postgres), plus `covara generate resource|migration`
|
|
123
|
+
- **Deploy-Ready Output** - Generated Dockerfile, docker-compose, complete wrangler.toml, GitHub Actions CI, `.env.example`
|
|
124
|
+
- **Framework Migrations** - `covara/db` ships canonical internal-table schemas, an idempotent `autoMigrate`/`migrateInternal`, a generic seeder, and pool-sizing helpers
|
|
125
|
+
- **App Factory** - `createCovara()` wires errors, auth, security headers, health, OpenAPI, admin UI
|
|
126
|
+
- **Graceful Shutdown** - SIGTERM/SIGINT draining with `/readyz` 503 and clean SSE close
|
|
127
|
+
- **Admin UI** - Built-in dashboard at `/__covara/ui`
|
|
128
|
+
- **OpenAPI Generation** - Auto-generated specs from resources (filters, procedures, subscriptions, ETags)
|
|
129
|
+
- **Structured Logging** - Pluggable JSON logger with `COVARA_LOG_LEVEL` and `traceparent` propagation
|
|
130
|
+
- **Middleware** - Observability, versioning, idempotency, rate limiting
|
|
131
|
+
- **RFC 7807 Errors** - Problem+JSON everywhere, even without custom error handling
|
|
132
|
+
|
|
133
|
+
## Quick Start
|
|
134
|
+
|
|
135
|
+
### Scaffold a project
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
npx covara create my-app # Node + SQLite
|
|
139
|
+
npx covara create my-app --db postgres # Node + PostgreSQL
|
|
140
|
+
npx covara create my-app --template cloudflare # Cloudflare Workers + D1
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Or add to an existing app
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
npm install covara hono drizzle-orm zod @libsql/client
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Define your schema:
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
|
|
153
|
+
|
|
154
|
+
export const usersTable = sqliteTable("users", {
|
|
155
|
+
id: integer("id").primaryKey({ autoIncrement: true }),
|
|
156
|
+
name: text("name").notNull(),
|
|
157
|
+
email: text("email").notNull(),
|
|
158
|
+
role: text("role").default("user"),
|
|
159
|
+
});
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Create your API:
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
import { drizzle } from "drizzle-orm/libsql";
|
|
166
|
+
import { createClient } from "@libsql/client";
|
|
167
|
+
import { createCovara } from "covara";
|
|
168
|
+
import { startServer } from "covara/node";
|
|
169
|
+
import { usersTable } from "./schema";
|
|
170
|
+
|
|
171
|
+
const client = createClient({ url: "file:./data.db" });
|
|
172
|
+
const db = drizzle(client);
|
|
173
|
+
|
|
174
|
+
const app = createCovara({ cors: true })
|
|
175
|
+
.resource("/users", usersTable, { id: usersTable.id, db });
|
|
176
|
+
|
|
177
|
+
await startServer(app, { port: 3000 });
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Health endpoints (`/healthz`, `/readyz`), OpenAPI (`/__covara/openapi.json`), the admin UI (`/__covara/ui`), and RFC 7807 error handling are wired automatically. The path is optional — `.resource(usersTable, config)` mounts at the table name.
|
|
181
|
+
|
|
182
|
+
### Cloudflare Workers
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
import { drizzle } from "drizzle-orm/d1";
|
|
186
|
+
import { createCovara, CovaraApp } from "covara";
|
|
187
|
+
import { usersTable } from "./schema";
|
|
188
|
+
|
|
189
|
+
let app: CovaraApp | undefined;
|
|
190
|
+
|
|
191
|
+
export default {
|
|
192
|
+
fetch(request: Request, env: { DB: D1Database }, ctx: ExecutionContext) {
|
|
193
|
+
app ??= createCovara().resource("/users", usersTable, {
|
|
194
|
+
id: usersTable.id,
|
|
195
|
+
db: drizzle(env.DB),
|
|
196
|
+
});
|
|
197
|
+
return app.fetch(request, env, ctx);
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
```toml
|
|
203
|
+
# wrangler.toml
|
|
204
|
+
compatibility_flags = ["nodejs_compat"]
|
|
205
|
+
|
|
206
|
+
[[d1_databases]]
|
|
207
|
+
binding = "DB"
|
|
208
|
+
database_name = "my-app"
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Workers bill CPU time, not wall-clock time — long-lived idle SSE subscriptions cost almost nothing, since heartbeats and event pushes use negligible CPU.
|
|
212
|
+
|
|
213
|
+
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.
|
|
214
|
+
|
|
215
|
+
### Using a plain Hono app
|
|
216
|
+
|
|
217
|
+
`useResource` returns a regular Hono router — compose it however you like:
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
import { Hono } from "hono";
|
|
221
|
+
import { useResource, errorHandler, notFoundHandler } from "covara";
|
|
222
|
+
|
|
223
|
+
const app = new Hono();
|
|
224
|
+
app.onError(errorHandler);
|
|
225
|
+
app.notFound(notFoundHandler);
|
|
226
|
+
app.route("/api/users", useResource(usersTable, { id: usersTable.id, db }));
|
|
227
|
+
|
|
228
|
+
export default app;
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Generated Endpoints
|
|
232
|
+
|
|
233
|
+
| Method | Path | Description |
|
|
234
|
+
|--------|------|-------------|
|
|
235
|
+
| `GET` | `/api/users` | List with filtering, pagination |
|
|
236
|
+
| `GET` | `/api/users/:id` | Get single resource |
|
|
237
|
+
| `POST` | `/api/users` | Create resource |
|
|
238
|
+
| `PATCH` | `/api/users/:id` | Update resource (partial) |
|
|
239
|
+
| `PUT` | `/api/users/:id` | Replace resource |
|
|
240
|
+
| `DELETE` | `/api/users/:id` | Delete resource |
|
|
241
|
+
| `GET` | `/api/users/count` | Count with filtering |
|
|
242
|
+
| `GET` | `/api/users/aggregate` | Aggregations |
|
|
243
|
+
| `GET` | `/api/users/subscribe` | SSE subscription |
|
|
244
|
+
| `GET` | `/api/users/search` | Full-text search (when configured) |
|
|
245
|
+
| `POST` | `/api/users/batch` | Batch create |
|
|
246
|
+
| `PATCH` | `/api/users/batch` | Batch update |
|
|
247
|
+
| `DELETE` | `/api/users/batch` | Batch delete |
|
|
248
|
+
| `POST` | `/api/users/batch/upsert` | Bulk insert-or-update by primary key |
|
|
249
|
+
| `POST` | `/api/users/rpc/:name` | RPC procedures |
|
|
250
|
+
|
|
251
|
+
## Resource Configuration
|
|
252
|
+
|
|
253
|
+
Everything is opt-in per resource:
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
app.resource("/posts", postsTable, {
|
|
257
|
+
id: postsTable.id,
|
|
258
|
+
db,
|
|
259
|
+
|
|
260
|
+
// Batch operation limits
|
|
261
|
+
batch: { create: 100, update: 100, delete: 100 },
|
|
262
|
+
|
|
263
|
+
// Pagination settings
|
|
264
|
+
pagination: { defaultLimit: 20, maxLimit: 100 },
|
|
265
|
+
|
|
266
|
+
// Rate limiting
|
|
267
|
+
rateLimit: { windowMs: 60000, maxRequests: 100 },
|
|
268
|
+
|
|
269
|
+
// Optimistic locking (ETag / If-Match)
|
|
270
|
+
etag: { versionField: "version" },
|
|
271
|
+
|
|
272
|
+
// Authorization scopes (row-level security via RSQL)
|
|
273
|
+
auth: {
|
|
274
|
+
public: { read: true },
|
|
275
|
+
update: async (user) => rsql`authorId=="${user.id}"`,
|
|
276
|
+
delete: async (user) => rsql`authorId=="${user.id}"`,
|
|
277
|
+
},
|
|
278
|
+
|
|
279
|
+
// Relations
|
|
280
|
+
relations: {
|
|
281
|
+
author: {
|
|
282
|
+
resource: "users",
|
|
283
|
+
schema: usersTable,
|
|
284
|
+
type: "belongsTo",
|
|
285
|
+
foreignKey: postsTable.authorId,
|
|
286
|
+
references: usersTable.id,
|
|
287
|
+
},
|
|
288
|
+
comments: {
|
|
289
|
+
resource: "comments",
|
|
290
|
+
schema: commentsTable,
|
|
291
|
+
type: "hasMany",
|
|
292
|
+
foreignKey: commentsTable.postId,
|
|
293
|
+
references: postsTable.id,
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
|
|
297
|
+
// Lifecycle hooks
|
|
298
|
+
hooks: {
|
|
299
|
+
onBeforeCreate: async (ctx, data) => ({ ...data, createdAt: new Date() }),
|
|
300
|
+
},
|
|
301
|
+
|
|
302
|
+
// RPC procedures
|
|
303
|
+
procedures: {
|
|
304
|
+
publish: defineProcedure({
|
|
305
|
+
input: z.object({ id: z.string() }),
|
|
306
|
+
output: z.object({ success: z.boolean() }),
|
|
307
|
+
handler: async (ctx, input) => {
|
|
308
|
+
await db.update(postsTable).set({ published: true }).where(eq(postsTable.id, input.id));
|
|
309
|
+
return { success: true };
|
|
310
|
+
},
|
|
311
|
+
}),
|
|
312
|
+
},
|
|
313
|
+
});
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
See [wiki/resources.md](./wiki/resources.md) for the full option reference (soft delete, computed fields, field allowlists, search, custom filter operators, and more).
|
|
317
|
+
|
|
318
|
+
## Client Library
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
import { getOrCreateClient } from "covara/client";
|
|
322
|
+
import { useLiveList, useAuth } from "covara/client/react";
|
|
323
|
+
|
|
324
|
+
const client = getOrCreateClient({
|
|
325
|
+
baseUrl: "https://api.myapp.com",
|
|
326
|
+
credentials: "include",
|
|
327
|
+
offline: true, // optimistic updates + mutation queue + persistence
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
function TodoApp() {
|
|
331
|
+
const { user, isAuthenticated } = useAuth();
|
|
332
|
+
const { items, status, mutate } = useLiveList<Todo>("/api/todos", {
|
|
333
|
+
orderBy: "position",
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
return (
|
|
337
|
+
<div>
|
|
338
|
+
<p>Welcome, {user?.name}! ({status})</p>
|
|
339
|
+
<ul>
|
|
340
|
+
{items.map((todo) => (
|
|
341
|
+
<li key={todo.id}>
|
|
342
|
+
{todo.title}
|
|
343
|
+
<button onClick={() => mutate.delete(todo.id)}>Delete</button>
|
|
344
|
+
</li>
|
|
345
|
+
))}
|
|
346
|
+
</ul>
|
|
347
|
+
<button onClick={() => mutate.create({ title: "New todo" })}>Add</button>
|
|
348
|
+
</div>
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
`mutate.create/update/delete` apply optimistically, queue while offline, reconcile on sync, and every other subscribed client sees the change over SSE.
|
|
354
|
+
|
|
355
|
+
### Authentication options
|
|
356
|
+
|
|
357
|
+
The client supports OIDC (PKCE), JWT, bearer tokens, API keys, and cookie sessions. `useAuth({ strategy })` selects one explicitly, or auto-detects.
|
|
358
|
+
|
|
359
|
+
**JWT** (works in React Native — bring your own token storage):
|
|
360
|
+
|
|
361
|
+
```typescript
|
|
362
|
+
import { initJWTClient } from "covara/client/react";
|
|
363
|
+
import { useJWTAuth } from "covara/client/react";
|
|
364
|
+
|
|
365
|
+
initJWTClient({
|
|
366
|
+
baseUrl: "https://api.myapp.com",
|
|
367
|
+
// storage: AsyncStorage-backed TokenStorage for React Native;
|
|
368
|
+
// defaults to localStorage in the browser
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
function LoginGate() {
|
|
372
|
+
const { user, isAuthenticated, login, signup, logout } = useJWTAuth<User>();
|
|
373
|
+
|
|
374
|
+
if (!isAuthenticated) {
|
|
375
|
+
return <button onClick={() => login(email, password)}>Sign In</button>;
|
|
376
|
+
}
|
|
377
|
+
return <button onClick={logout}>Sign out, {user?.name}</button>;
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
**OIDC** (PKCE flow, token refresh, automatic 401 retry):
|
|
382
|
+
|
|
383
|
+
```typescript
|
|
384
|
+
const client = getOrCreateClient({
|
|
385
|
+
baseUrl: "https://api.myapp.com",
|
|
386
|
+
auth: {
|
|
387
|
+
issuer: "https://auth.myapp.com/oidc",
|
|
388
|
+
clientId: "web-app",
|
|
389
|
+
redirectUri: window.location.origin + "/callback",
|
|
390
|
+
},
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
client.auth.login(); // redirects to the provider
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### Low-level API
|
|
397
|
+
|
|
398
|
+
```typescript
|
|
399
|
+
const users = client.resource<User>("/users");
|
|
400
|
+
|
|
401
|
+
// CRUD operations
|
|
402
|
+
const allUsers = await users.list({ filter: 'role=="admin"', limit: 10 });
|
|
403
|
+
const user = await users.get("123");
|
|
404
|
+
const newUser = await users.create({ name: "Alice", email: "alice@example.com" });
|
|
405
|
+
await users.update("123", { name: "Alice Smith" });
|
|
406
|
+
await users.delete("123");
|
|
407
|
+
|
|
408
|
+
// Real-time subscriptions
|
|
409
|
+
const subscription = users.subscribe(
|
|
410
|
+
{ filter: 'role=="admin"' },
|
|
411
|
+
{
|
|
412
|
+
onAdded: (user) => console.log("New admin:", user),
|
|
413
|
+
onChanged: (user) => console.log("Updated:", user),
|
|
414
|
+
onRemoved: (id) => console.log("Removed:", id),
|
|
415
|
+
onInvalidate: () => console.log("Out-of-band change, refetching"),
|
|
416
|
+
onConnected: (seq) => console.log("Live from sequence", seq),
|
|
417
|
+
onError: (err) => console.error(err),
|
|
418
|
+
}
|
|
419
|
+
);
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
### React Native
|
|
423
|
+
|
|
424
|
+
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.
|
|
425
|
+
|
|
426
|
+
## File Storage
|
|
427
|
+
|
|
428
|
+
Configure a storage backend once, then mount file resources like any other:
|
|
429
|
+
|
|
430
|
+
```typescript
|
|
431
|
+
import { initializeStorage, useFileResource } from "covara";
|
|
432
|
+
|
|
433
|
+
initializeStorage({
|
|
434
|
+
type: "local", // or "s3" | "r2" | "memory"
|
|
435
|
+
local: { basePath: "./uploads", baseUrl: "/uploads" },
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
app.route("/api/files", useFileResource(filesTable, {
|
|
439
|
+
db,
|
|
440
|
+
schema: filesTable,
|
|
441
|
+
id: filesTable.id,
|
|
442
|
+
allowedMimeTypes: ["image/jpeg", "image/png"],
|
|
443
|
+
maxFileSize: 5 * 1024 * 1024,
|
|
444
|
+
auth: {
|
|
445
|
+
read: async (user) => rsql`userId==${user?.id}`,
|
|
446
|
+
delete: async (user) => rsql`userId==${user?.id}`,
|
|
447
|
+
},
|
|
448
|
+
usePresignedUrls: true, // direct-to-bucket on S3/R2
|
|
449
|
+
}));
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
Upload from React with progress tracking:
|
|
453
|
+
|
|
454
|
+
```typescript
|
|
455
|
+
import { useFileUpload, useFiles } from "covara/client/react";
|
|
456
|
+
|
|
457
|
+
function Uploader() {
|
|
458
|
+
const { upload, isUploading, progress } = useFileUpload({
|
|
459
|
+
resourcePath: "/api/files",
|
|
460
|
+
onSuccess: (file) => console.log("Uploaded", file.id),
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
return (
|
|
464
|
+
<input
|
|
465
|
+
type="file"
|
|
466
|
+
disabled={isUploading}
|
|
467
|
+
onChange={(e) => e.target.files?.[0] && upload(e.target.files[0])}
|
|
468
|
+
/>
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
See [wiki/storage.md](./wiki/storage.md).
|
|
474
|
+
|
|
475
|
+
## Server-side Authentication
|
|
476
|
+
|
|
477
|
+
### Standard auth routes
|
|
478
|
+
|
|
479
|
+
```typescript
|
|
480
|
+
import { useAuth } from "covara/auth";
|
|
481
|
+
|
|
482
|
+
const { router, middleware } = useAuth({
|
|
483
|
+
adapter: authAdapter, // JWT, Auth.js, Passport.js, or OIDC adapter
|
|
484
|
+
login: { validateCredentials: async (email, password) => user },
|
|
485
|
+
signup: { createUser: async ({ email, password, name }) => user },
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
app.route("/api/auth", router); // /me, /login, /signup, /logout
|
|
489
|
+
app.use("*", middleware); // populates c.get("user")
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
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).
|
|
493
|
+
|
|
494
|
+
### OIDC Provider
|
|
495
|
+
|
|
496
|
+
A complete OpenID Connect server, in your app:
|
|
497
|
+
|
|
498
|
+
```typescript
|
|
499
|
+
import { createOIDCProvider } from "covara";
|
|
500
|
+
|
|
501
|
+
const { router, middleware } = createOIDCProvider({
|
|
502
|
+
issuer: "https://auth.myapp.com",
|
|
503
|
+
keys: { algorithm: "RS256" },
|
|
504
|
+
tokens: {
|
|
505
|
+
accessToken: { ttlSeconds: 3600 },
|
|
506
|
+
refreshToken: { ttlSeconds: 30 * 24 * 3600, rotateOnUse: true },
|
|
507
|
+
},
|
|
508
|
+
clients: [{
|
|
509
|
+
id: "web-app",
|
|
510
|
+
name: "My Web App",
|
|
511
|
+
redirectUris: ["https://myapp.com/callback"],
|
|
512
|
+
grantTypes: ["authorization_code", "refresh_token"],
|
|
513
|
+
tokenEndpointAuthMethod: "none", // public client, PKCE required
|
|
514
|
+
}],
|
|
515
|
+
backends: {
|
|
516
|
+
emailPassword: {
|
|
517
|
+
enabled: true,
|
|
518
|
+
validateUser: async (email, password) => { /* ... */ },
|
|
519
|
+
findUserById: async (id) => { /* ... */ },
|
|
520
|
+
},
|
|
521
|
+
federated: [
|
|
522
|
+
oidcProviders.google({ clientId: "...", clientSecret: "..." }),
|
|
523
|
+
],
|
|
524
|
+
},
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
app.route("/oidc", router);
|
|
528
|
+
app.use("/api/*", middleware);
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
The provider exposes discovery, JWKS, `/authorize`, `/token`, `/userinfo`, `/logout`, plus RFC 7009 revocation (`/revoke`) and RFC 7662 introspection (`/introspect`). Confidential client secrets may be stored hashed (`scrypt$...`) and are verified with the built-in `hashPassword`/`verifyPassword` helpers.
|
|
532
|
+
|
|
533
|
+
## Background Tasks
|
|
534
|
+
|
|
535
|
+
Distributed task queue with retries and scheduling:
|
|
536
|
+
|
|
537
|
+
```typescript
|
|
538
|
+
import { defineTask, initializeTasks, getTaskScheduler, getTaskRegistry, startTaskWorkers } from "covara/tasks";
|
|
539
|
+
import { createKV } from "covara/kv";
|
|
540
|
+
|
|
541
|
+
const kv = await createKV({ type: "redis", redis: { url: "redis://localhost" } });
|
|
542
|
+
initializeTasks(kv);
|
|
543
|
+
|
|
544
|
+
const sendEmailTask = defineTask({
|
|
545
|
+
name: "send-email",
|
|
546
|
+
input: z.object({ to: z.string().email(), subject: z.string(), body: z.string() }),
|
|
547
|
+
retry: { maxAttempts: 3, backoff: "exponential" },
|
|
548
|
+
handler: async (ctx, input) => {
|
|
549
|
+
await sendEmail(input.to, input.subject, input.body);
|
|
550
|
+
},
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
getTaskRegistry().register(sendEmailTask);
|
|
554
|
+
await startTaskWorkers(kv, getTaskRegistry(), 3);
|
|
555
|
+
|
|
556
|
+
// Enqueue
|
|
557
|
+
await getTaskScheduler().enqueue(sendEmailTask, {
|
|
558
|
+
to: "user@example.com",
|
|
559
|
+
subject: "Welcome!",
|
|
560
|
+
body: "Thanks for signing up.",
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
// Recurring
|
|
564
|
+
await getTaskScheduler().scheduleRecurring(dailyReportTask, {}, {
|
|
565
|
+
cron: "0 6 * * *",
|
|
566
|
+
timezone: "UTC",
|
|
567
|
+
});
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
On Workers, swap the poller for the Cloudflare Queues adapter. See [wiki/tasks.md](./wiki/tasks.md).
|
|
571
|
+
|
|
572
|
+
## Email
|
|
573
|
+
|
|
574
|
+
```typescript
|
|
575
|
+
import { setGlobalEmail, createResendAdapter, createEmail, sendEmail } from "covara/email";
|
|
576
|
+
|
|
577
|
+
setGlobalEmail(createResendAdapter({ apiKey: process.env.RESEND_API_KEY }));
|
|
578
|
+
|
|
579
|
+
const { html, text } = createEmail({ brandColor: "#4f46e5" })
|
|
580
|
+
.heading("Verify your email")
|
|
581
|
+
.text("Tap the button below to verify your account.")
|
|
582
|
+
.button("Verify email", `https://acme.com/verify?token=${token}`)
|
|
583
|
+
.divider()
|
|
584
|
+
.code("123456")
|
|
585
|
+
.build();
|
|
586
|
+
|
|
587
|
+
await sendEmail({ from: "noreply@acme.com", to: email, subject: "Verify your email", html, text });
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
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).
|
|
591
|
+
|
|
592
|
+
## Billing
|
|
593
|
+
|
|
594
|
+
One interface over Stripe, Lemon Squeezy, Paddle, and Polar.sh — fetch-based, no provider SDKs, Workers-safe:
|
|
595
|
+
|
|
596
|
+
```typescript
|
|
597
|
+
import { createBilling, createBillingRouter, createStripeAdapter } from "covara/billing";
|
|
598
|
+
|
|
599
|
+
const billing = createBilling({
|
|
600
|
+
adapter: createStripeAdapter({ apiKey: env.STRIPE_SECRET_KEY }),
|
|
601
|
+
webhookSecret: env.STRIPE_WEBHOOK_SECRET,
|
|
602
|
+
plans: [
|
|
603
|
+
{ key: "pro_monthly", priceId: "price_123", type: "subscription", credits: 10_000 },
|
|
604
|
+
],
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
app.route("/api/billing", createBillingRouter(billing, {
|
|
608
|
+
getAccount: (c) => c.get("user")?.id,
|
|
609
|
+
getCustomerEmail: (c) => c.get("user")?.email,
|
|
610
|
+
}));
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
```typescript
|
|
614
|
+
import { useCredits, useSubscription, useCheckout } from "covara/client/react";
|
|
615
|
+
|
|
616
|
+
function Account() {
|
|
617
|
+
const { balance } = useCredits();
|
|
618
|
+
const { activeSubscription } = useSubscription();
|
|
619
|
+
const { redirectToCheckout, loading } = useCheckout();
|
|
620
|
+
|
|
621
|
+
return (
|
|
622
|
+
<div>
|
|
623
|
+
<p>Credits: {balance}</p>
|
|
624
|
+
<button onClick={() => redirectToCheckout({ plan: "pro_monthly" })} disabled={loading}>
|
|
625
|
+
Upgrade
|
|
626
|
+
</button>
|
|
627
|
+
</div>
|
|
628
|
+
);
|
|
629
|
+
}
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
Webhooks are signature-verified, deduplicated, and grant credits automatically on `payment.succeeded`. See [wiki/billing.md](./wiki/billing.md).
|
|
633
|
+
|
|
634
|
+
## Mutation Tracking
|
|
635
|
+
|
|
636
|
+
Custom routes participate in the realtime system by wrapping your db once:
|
|
637
|
+
|
|
638
|
+
```typescript
|
|
639
|
+
import { drizzle } from "drizzle-orm/libsql";
|
|
640
|
+
import { trackMutations, readJsonBody, requireUser } from "covara";
|
|
641
|
+
import * as schema from "./schema";
|
|
642
|
+
|
|
643
|
+
const baseDb = drizzle(/* config */);
|
|
644
|
+
|
|
645
|
+
export const db = trackMutations(baseDb, {
|
|
646
|
+
todos: { table: schema.todosTable, id: schema.todosTable.id },
|
|
647
|
+
users: { table: schema.usersTable, id: schema.usersTable.id },
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
app.post("/api/custom-action", async (c) => {
|
|
651
|
+
const body = await readJsonBody(c) as { title: string };
|
|
652
|
+
const user = requireUser(c);
|
|
653
|
+
|
|
654
|
+
const [todo] = await db
|
|
655
|
+
.insert(schema.todosTable)
|
|
656
|
+
.values({ title: body.title, userId: user.id })
|
|
657
|
+
.returning();
|
|
658
|
+
// recorded in the changelog — subscribers are notified
|
|
659
|
+
|
|
660
|
+
return c.json(todo);
|
|
661
|
+
});
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
Optional query caching with automatic invalidation:
|
|
665
|
+
|
|
666
|
+
```typescript
|
|
667
|
+
const db = trackMutations(baseDb, tables, {
|
|
668
|
+
cache: { enabled: true, ttl: 60000 },
|
|
669
|
+
});
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
For writers **outside** the tracked db — cron jobs, other services, manual edits — `recordExternalMutation` appends a changelog entry, invalidates the cache, and tells live subscribers to refetch. It's the portable alternative to database-specific CDC:
|
|
673
|
+
|
|
674
|
+
```typescript
|
|
675
|
+
import { recordExternalMutation } from "covara";
|
|
676
|
+
|
|
677
|
+
await recordExternalMutation("todos", "update", { objectId: "todo-1" });
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
## Typed Environment Variables
|
|
681
|
+
|
|
682
|
+
```typescript
|
|
683
|
+
import { createEnv, envVariable, usePublicEnv } from "covara";
|
|
684
|
+
import { z } from "zod";
|
|
685
|
+
|
|
686
|
+
const env = createEnv({
|
|
687
|
+
PUBLIC_API_URL: z.string().url(), // PUBLIC_ prefix → exposed to clients
|
|
688
|
+
SECRET_KEY: envVariable(process.env.SECRET, z.string()), // explicit source
|
|
689
|
+
PORT: z.string().default("3000").transform(Number),
|
|
690
|
+
});
|
|
691
|
+
|
|
692
|
+
app.route("/api/env", usePublicEnv(env)); // serves public vars (with ETag)
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
Clients read public vars with `fetchPublicEnv`/`createEnvClient` or the `usePublicEnv` React hook. See [wiki/environment-variables.md](./wiki/environment-variables.md).
|
|
696
|
+
|
|
697
|
+
## Query Parameters
|
|
698
|
+
|
|
699
|
+
| Parameter | Example | Description |
|
|
700
|
+
|-----------|---------|-------------|
|
|
701
|
+
| `filter` | `age>=18;role=="admin"` | RSQL filter expression |
|
|
702
|
+
| `select` | `id,name,email` | Field projection |
|
|
703
|
+
| `include` | `author,comments(limit:5)` | Related data to load |
|
|
704
|
+
| `cursor` | `eyJpZCI6MTB9` | Pagination cursor |
|
|
705
|
+
| `limit` | `20` | Page size |
|
|
706
|
+
| `orderBy` | `name:asc,age:desc` | Sort order |
|
|
707
|
+
| `totalCount` | `true` | Include total count |
|
|
708
|
+
| `having` | `count>=5;sum_amount>100` | Filter aggregate groups (`/aggregate` only) |
|
|
709
|
+
| `withDeleted` | `true` | Include soft-deleted rows (when `softDelete` is configured) |
|
|
710
|
+
|
|
711
|
+
## Filter Syntax
|
|
712
|
+
|
|
713
|
+
```bash
|
|
714
|
+
# Comparison
|
|
715
|
+
name=="John" # Equals
|
|
716
|
+
age>=18 # Greater than or equal
|
|
717
|
+
status!="deleted" # Not equals
|
|
718
|
+
|
|
719
|
+
# Logical operators
|
|
720
|
+
age>=18;role=="admin" # AND (semicolon)
|
|
721
|
+
role=="admin",role=="mod" # OR (comma)
|
|
722
|
+
(age>=18;verified==true),role=="admin" # Grouping
|
|
723
|
+
|
|
724
|
+
# String operations
|
|
725
|
+
name=icontains="john" # Case-insensitive contains
|
|
726
|
+
email=iendswith="@company.com"
|
|
727
|
+
title=istartswith="how to"
|
|
728
|
+
|
|
729
|
+
# Set and range
|
|
730
|
+
role=in=("admin","mod") # In list
|
|
731
|
+
age=between=[18,65] # Range (inclusive)
|
|
732
|
+
|
|
733
|
+
# Null and empty
|
|
734
|
+
deletedAt=isnull=true # Is null
|
|
735
|
+
bio=isempty=false # Has non-empty value
|
|
736
|
+
|
|
737
|
+
# See wiki/filtering.md for all 30+ operators
|
|
738
|
+
```
|
|
739
|
+
|
|
740
|
+
The same expression filters database queries, subscription scopes, and auth scopes — parsed once, executed as SQL or in-memory as needed.
|
|
741
|
+
|
|
742
|
+
## Error Handling
|
|
743
|
+
|
|
744
|
+
All errors follow [RFC 7807 Problem Details](https://tools.ietf.org/html/rfc7807) format:
|
|
745
|
+
|
|
746
|
+
```json
|
|
747
|
+
{
|
|
748
|
+
"type": "/__covara/problems/not-found",
|
|
749
|
+
"title": "Not found",
|
|
750
|
+
"status": 404,
|
|
751
|
+
"detail": "users with id '123' not found",
|
|
752
|
+
"code": "NOT_FOUND",
|
|
753
|
+
"resource": "users",
|
|
754
|
+
"id": "123"
|
|
755
|
+
}
|
|
756
|
+
```
|
|
757
|
+
|
|
758
|
+
Error types include:
|
|
759
|
+
- `not-found` (404) - Resource not found
|
|
760
|
+
- `validation-error` (400) - Invalid input data
|
|
761
|
+
- `unauthorized` (401) - Authentication required
|
|
762
|
+
- `forbidden` (403) - Insufficient permissions
|
|
763
|
+
- `rate-limit-exceeded` (429) - Too many requests
|
|
764
|
+
- `batch-limit-exceeded` (400) - Batch size exceeded
|
|
765
|
+
- `filter-parse-error` (400) - Invalid filter syntax
|
|
766
|
+
- `cursor-invalid` (400) - Malformed pagination cursor
|
|
767
|
+
- `precondition-failed` (412) - ETag mismatch
|
|
768
|
+
|
|
769
|
+
Errors extend Hono's `HTTPException` and self-render — resources mounted in any Hono app return proper problem+json without extra setup.
|
|
770
|
+
|
|
771
|
+
## Testing
|
|
772
|
+
|
|
773
|
+
```bash
|
|
774
|
+
npm test # all tests
|
|
775
|
+
npm test -- tests/integration/useResource.test.ts # one file
|
|
776
|
+
npm test -- --coverage
|
|
777
|
+
```
|
|
778
|
+
|
|
779
|
+
Testing your own app needs no HTTP server:
|
|
780
|
+
|
|
781
|
+
```typescript
|
|
782
|
+
const res = await app.request("/api/users", {
|
|
783
|
+
method: "POST",
|
|
784
|
+
body: JSON.stringify({ name: "Alice", email: "a@b.com" }),
|
|
785
|
+
headers: { "content-type": "application/json" },
|
|
786
|
+
});
|
|
787
|
+
expect(res.status).toBe(201);
|
|
788
|
+
```
|
|
789
|
+
|
|
790
|
+
## Documentation
|
|
791
|
+
|
|
792
|
+
Comprehensive documentation is available in the [wiki](./wiki):
|
|
793
|
+
|
|
794
|
+
### Getting Started
|
|
795
|
+
- [Getting Started Guide](./wiki/getting-started.md) - Installation and quick start
|
|
796
|
+
- [Deployment](./wiki/deployment.md) - Node, Cloudflare Workers, database matrix
|
|
797
|
+
- [Migrating from Express](./wiki/migrating-from-express.md) - Upgrading from Covara ≤ 0.5
|
|
798
|
+
|
|
799
|
+
### Core Concepts
|
|
800
|
+
- [Resources](./wiki/resources.md) - Resource configuration and endpoints
|
|
801
|
+
- [Filtering](./wiki/filtering.md) - RSQL filter syntax (30+ operators)
|
|
802
|
+
- [Pagination](./wiki/pagination.md) - Cursor-based pagination
|
|
803
|
+
- [Aggregations](./wiki/aggregations.md) - Group by and statistical queries
|
|
804
|
+
- [Relations](./wiki/relations.md) - Relationships and efficient batch loading
|
|
805
|
+
- [Search](./wiki/search.md) - Full-text search adapters and transactional outbox
|
|
806
|
+
- [Database](./wiki/database.md) - Internal tables, framework migrations, seeding, pooling
|
|
807
|
+
|
|
808
|
+
### Real-time
|
|
809
|
+
- [Subscriptions](./wiki/subscriptions.md) - SSE subscriptions and changelog
|
|
810
|
+
|
|
811
|
+
### Authentication & Security
|
|
812
|
+
- [Authentication](./wiki/authentication.md) - OIDC Provider, federated login, JWT, session auth
|
|
813
|
+
- [Secure Queries](./wiki/secure-queries.md) - Scope-enforced query builder
|
|
814
|
+
|
|
815
|
+
### Platform Services
|
|
816
|
+
- [Storage](./wiki/storage.md) - File uploads, S3/R2/local adapters, presigned URLs
|
|
817
|
+
- [Email](./wiki/email.md) - Email adapters and template builder
|
|
818
|
+
- [Billing](./wiki/billing.md) - Payment providers, plans, credits, webhooks
|
|
819
|
+
- [Tasks](./wiki/tasks.md) - Background job queue, scheduling, retries
|
|
820
|
+
- [Environment Variables](./wiki/environment-variables.md) - Typed env config
|
|
821
|
+
|
|
822
|
+
### Client
|
|
823
|
+
- [Client Library](./wiki/client-library.md) - TypeScript client with React hooks
|
|
824
|
+
- [Offline Support](./wiki/offline-support.md) - Offline-first capabilities
|
|
825
|
+
|
|
826
|
+
### Advanced
|
|
827
|
+
- [Procedures & Hooks](./wiki/procedures.md) - RPC and lifecycle hooks
|
|
828
|
+
- [Mutation Tracking](./wiki/track-mutations.md) - Automatic changelog and cache invalidation
|
|
829
|
+
- [Middleware](./wiki/middleware.md) - Observability, versioning, idempotency
|
|
830
|
+
- [OpenAPI](./wiki/openapi.md) - OpenAPI spec generation
|
|
831
|
+
- [Admin UI](./wiki/admin-ui.md) - Built-in dashboard
|
|
832
|
+
- [Error Handling](./wiki/error-handling.md) - Error types and handling
|
|
833
|
+
|
|
834
|
+
## Requirements
|
|
835
|
+
|
|
836
|
+
- Node.js 18+ or Cloudflare Workers (`nodejs_compat`)
|
|
837
|
+
- TypeScript 5+
|
|
838
|
+
- Drizzle ORM
|
|
839
|
+
- Hono 4+
|