@kardoe/quickback 0.7.3 → 0.8.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/dist/docs/content.js +12 -12
- package/dist/docs/content.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/lib/api-client.d.ts.map +1 -1
- package/dist/lib/api-client.js +26 -6
- package/dist/lib/api-client.js.map +1 -1
- package/dist/skill/skill/SKILL.md +7 -5
- package/dist/skill/skill/agents/quickback-specialist/AGENT.md +4 -2
- package/package.json +1 -1
- package/src/skill/SKILL.md +7 -5
- package/src/skill/agents/quickback-specialist/AGENT.md +4 -2
package/dist/docs/content.js
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
export const DOCS = {
|
|
4
4
|
"account-ui/customization": {
|
|
5
5
|
"title": "Customization",
|
|
6
|
-
"content": "# Customization\n\nCustomize the Account UI to match your brand and messaging.\n\n**Standalone (template):** Configure via environment variables, edit `src/config/app.ts` directly, or use `setAppConfig()` for runtime overrides.\n\n**Library (npm):** Configure entirely via `setAppConfig()`. Import it from `quickback-better-auth-account-ui` instead of `@/config/app`.\n\n## Branding\n\n### App Identity\n\nSet your application's name and description:\n\n```bash\nVITE_APP_NAME=Acme SaaS\nVITE_APP_TAGLINE=Build faster, ship sooner\nVITE_APP_DESCRIPTION=The complete platform for modern web applications\n```\n\nThese values appear in:\n- Page titles (`<title>Acme SaaS | Login</title>`)\n- Meta descriptions\n- UI headers and footers\n- Email templates\n\n### Visual Identity\n\n```bash\n# Primary theme color (used for buttons, links, accents)\nVITE_THEME_COLOR=#3b82f6\n\n# Company name (shown in footer, legal pages)\nVITE_COMPANY_NAME=Acme Corporation\n\n# Company address (shown in footer, receipts)\nVITE_COMPANY_ADDRESS=123 Main St, Suite 100, San Francisco, CA 94105\n```\n\n### Logo and Favicon\n\nPlace your branding assets in the `public/` directory:\n\n```\npublic/\n├── logo.png # Main logo (shown in header)\n├── favicon.ico # Browser favicon\n└── og-image.png # Social media preview image\n```\n\nThen update the paths in `src/config/app.ts`:\n\n```ts title=\"src/config/app.ts\"\nbranding: {\n primaryColor: \"#1e293b\",\n logoUrl: \"/logo.png\",\n faviconUrl: \"/favicon.ico\"\n},\n```\n\nOr set them at runtime in `src/main.tsx`:\n\n```ts\n\nsetAppConfig({\n branding: {\n logoUrl: '/logo.png',\n faviconUrl: '/favicon.ico',\n },\n});\n```\n\n## Custom Labels\n\nOverride default UI labels using runtime configuration:\n\n```ts\n\nsetAppConfig({\n labels: {\n terms: 'Terms and Conditions',\n privacy: 'Privacy Notice',\n support: 'Help Center',\n company: 'My Company',\n organizations: 'Workspaces', // Rename \"Organizations\" to \"Workspaces\"\n },\n});\n```\n\n### Available Labels\n\n| Label | Default | Usage |\n|-------|---------|-------|\n| `terms` | \"Terms of Service\" | Footer link text |\n| `privacy` | \"Privacy Policy\" | Footer link text |\n| `support` | \"Contact Support\" | Footer link text |\n| `company` | (from `VITE_COMPANY_NAME`) | Footer company name |\n| `organizations` | \"Organizations\" | Navigation and page titles |\n\n## Custom Messages\n\nCustomize user-facing messages:\n\n```ts\n\nsetAppConfig({\n messages: {\n noOrganizations: \"You haven't joined any workspaces yet.\",\n contactAdminForInvite: \"Contact your team lead to get access.\",\n noPendingInvitations: \"No pending invites at this time\",\n createOrganization: \"Create Workspace\",\n // ... more messages\n },\n});\n```\n\n### Available Messages\n\n| Message | Default | Usage |\n|---------|---------|-------|\n| `noOrganizations` | \"You're not a member of any organizations yet.\" | Empty organizations list |\n| `contactAdminForInvite` | \"Contact an admin to be invited to an organization.\" | Organizations page help text |\n| `noPendingInvitations` | \"You have no pending invitations\" | Empty invitations list |\n| `createOrganization` | \"Create Organization\" | Button text |\n| `accountInformation` | \"Account Information\" | Profile section header |\n| `timezone` | \"Timezone\" | Label for timezone field |\n| `serverLocation` | \"Server Location\" | Label for server location |\n| `memberSince` | \"Member since\" | Account age label |\n| `pendingInvitations` | \"Pending Invitations\" | Section header |\n| `invitedAs` | \"Invited as\" | Invitation role label |\n| `accept` | \"Accept\" | Accept invitation button |\n| `decline` | \"Decline\" | Decline invitation button |\n| `userFallback` | \"User\" | Fallback for missing name |\n| `noEmailProvided` | \"No email provided\" | Fallback for missing email |\n| `more` | \"More\" | Pagination/load more text |\n| `total` | \"total\" | Total count label |\n| `active` | \"Active\" | Active status label |\n| `new` | \"New\" | New item label |\n\n## Route Customization\n\nCustomize route paths using runtime configuration:\n\n```ts\n\nsetAppConfig({\n routes: {\n public: {\n home: '/',\n login: '/sign-in', // Change from /login\n signup: '/sign-up', // Change from /signup\n forgotPassword: '/reset-password',\n welcome: '/getting-started',\n },\n authenticated: {\n dashboard: '/dashboard',\n profile: '/my-account',\n settings: '/preferences',\n },\n organizations: {\n list: '/workspaces', // Rename route\n create: '/workspaces/new',\n detail: (slug) => `/workspaces/${slug}`,\n },\n },\n});\n```\n\n## Password Requirements\n\nCustomize password validation rules:\n\n```ts\n\nsetAppConfig({\n auth: {\n passwordRequirements: {\n minLength: 12, // Minimum password length\n maxLength: 128, // Maximum password length\n requireUppercase: true, // Must have uppercase letter\n requireLowercase: true, // Must have lowercase letter\n requireNumbers: true, // Must have number\n requireSymbols: true, // Must have special character\n },\n },\n});\n```\n\nPassword requirements are displayed to users during signup and password changes.\n\n## Session Duration\n\nControl how long users stay logged in:\n\n```ts\n\nsetAppConfig({\n auth: {\n sessionDuration: 7 * 24 * 60 * 60, // 7 days in seconds\n },\n});\n```\n\n## Email Customization\n\nConfigure email sender information:\n\n```bash\nVITE_EMAIL_FROM=noreply@acme.com\nVITE_EMAIL_REPLY_TO=support@acme.com\nVITE_SUPPORT_EMAIL=help@acme.com\n```\n\nThe `fromName` is automatically set to `VITE_APP_NAME`:\n\n```ts\n// Emails will show:\n// From: \"Acme SaaS <noreply@acme.com>\"\n```\n\n## URL Configuration\n\nConfigure URLs for external links:\n\n```bash\n# Main application (redirected to after login)\
|
|
6
|
+
"content": "# Customization\n\nCustomize the Account UI to match your brand and messaging.\n\n**Standalone (template):** Configure via environment variables, edit `src/config/app.ts` directly, or use `setAppConfig()` for runtime overrides.\n\n**Library (npm):** Configure entirely via `setAppConfig()`. Import it from `quickback-better-auth-account-ui` instead of `@/config/app`.\n\n## Branding\n\n### App Identity\n\nSet your application's name and description:\n\n```bash\nVITE_APP_NAME=Acme SaaS\nVITE_APP_TAGLINE=Build faster, ship sooner\nVITE_APP_DESCRIPTION=The complete platform for modern web applications\n```\n\nThese values appear in:\n- Page titles (`<title>Acme SaaS | Login</title>`)\n- Meta descriptions\n- UI headers and footers\n- Email templates\n\n### Visual Identity\n\n```bash\n# Primary theme color (used for buttons, links, accents)\nVITE_THEME_COLOR=#3b82f6\n\n# Company name (shown in footer, legal pages)\nVITE_COMPANY_NAME=Acme Corporation\n\n# Company address (shown in footer, receipts)\nVITE_COMPANY_ADDRESS=123 Main St, Suite 100, San Francisco, CA 94105\n```\n\n### Logo and Favicon\n\nPlace your branding assets in the `public/` directory:\n\n```\npublic/\n├── logo.png # Main logo (shown in header)\n├── favicon.ico # Browser favicon\n└── og-image.png # Social media preview image\n```\n\nThen update the paths in `src/config/app.ts`:\n\n```ts title=\"src/config/app.ts\"\nbranding: {\n primaryColor: \"#1e293b\",\n logoUrl: \"/logo.png\",\n faviconUrl: \"/favicon.ico\"\n},\n```\n\nOr set them at runtime in `src/main.tsx`:\n\n```ts\n\nsetAppConfig({\n branding: {\n logoUrl: '/logo.png',\n faviconUrl: '/favicon.ico',\n },\n});\n```\n\n## Custom Labels\n\nOverride default UI labels using runtime configuration:\n\n```ts\n\nsetAppConfig({\n labels: {\n terms: 'Terms and Conditions',\n privacy: 'Privacy Notice',\n support: 'Help Center',\n company: 'My Company',\n organizations: 'Workspaces', // Rename \"Organizations\" to \"Workspaces\"\n },\n});\n```\n\n### Available Labels\n\n| Label | Default | Usage |\n|-------|---------|-------|\n| `terms` | \"Terms of Service\" | Footer link text |\n| `privacy` | \"Privacy Policy\" | Footer link text |\n| `support` | \"Contact Support\" | Footer link text |\n| `company` | (from `VITE_COMPANY_NAME`) | Footer company name |\n| `organizations` | \"Organizations\" | Navigation and page titles |\n\n## Custom Messages\n\nCustomize user-facing messages:\n\n```ts\n\nsetAppConfig({\n messages: {\n noOrganizations: \"You haven't joined any workspaces yet.\",\n contactAdminForInvite: \"Contact your team lead to get access.\",\n noPendingInvitations: \"No pending invites at this time\",\n createOrganization: \"Create Workspace\",\n // ... more messages\n },\n});\n```\n\n### Available Messages\n\n| Message | Default | Usage |\n|---------|---------|-------|\n| `noOrganizations` | \"You're not a member of any organizations yet.\" | Empty organizations list |\n| `contactAdminForInvite` | \"Contact an admin to be invited to an organization.\" | Organizations page help text |\n| `noPendingInvitations` | \"You have no pending invitations\" | Empty invitations list |\n| `createOrganization` | \"Create Organization\" | Button text |\n| `accountInformation` | \"Account Information\" | Profile section header |\n| `timezone` | \"Timezone\" | Label for timezone field |\n| `serverLocation` | \"Server Location\" | Label for server location |\n| `memberSince` | \"Member since\" | Account age label |\n| `pendingInvitations` | \"Pending Invitations\" | Section header |\n| `invitedAs` | \"Invited as\" | Invitation role label |\n| `accept` | \"Accept\" | Accept invitation button |\n| `decline` | \"Decline\" | Decline invitation button |\n| `userFallback` | \"User\" | Fallback for missing name |\n| `noEmailProvided` | \"No email provided\" | Fallback for missing email |\n| `more` | \"More\" | Pagination/load more text |\n| `total` | \"total\" | Total count label |\n| `active` | \"Active\" | Active status label |\n| `new` | \"New\" | New item label |\n\n## Route Customization\n\nCustomize route paths using runtime configuration:\n\n```ts\n\nsetAppConfig({\n routes: {\n public: {\n home: '/',\n login: '/sign-in', // Change from /login\n signup: '/sign-up', // Change from /signup\n forgotPassword: '/reset-password',\n welcome: '/getting-started',\n },\n authenticated: {\n dashboard: '/dashboard',\n profile: '/my-account',\n settings: '/preferences',\n },\n organizations: {\n list: '/workspaces', // Rename route\n create: '/workspaces/new',\n detail: (slug) => `/workspaces/${slug}`,\n },\n },\n});\n```\n\n## Password Requirements\n\nCustomize password validation rules:\n\n```ts\n\nsetAppConfig({\n auth: {\n passwordRequirements: {\n minLength: 12, // Minimum password length\n maxLength: 128, // Maximum password length\n requireUppercase: true, // Must have uppercase letter\n requireLowercase: true, // Must have lowercase letter\n requireNumbers: true, // Must have number\n requireSymbols: true, // Must have special character\n },\n },\n});\n```\n\nPassword requirements are displayed to users during signup and password changes.\n\n## Session Duration\n\nControl how long users stay logged in:\n\n```ts\n\nsetAppConfig({\n auth: {\n sessionDuration: 7 * 24 * 60 * 60, // 7 days in seconds\n },\n});\n```\n\n## Email Customization\n\nConfigure email sender information:\n\n```bash\nVITE_EMAIL_FROM=noreply@acme.com\nVITE_EMAIL_REPLY_TO=support@acme.com\nVITE_SUPPORT_EMAIL=help@acme.com\n```\n\nThe `fromName` is automatically set to `VITE_APP_NAME`:\n\n```ts\n// Emails will show:\n// From: \"Acme SaaS <noreply@acme.com>\"\n```\n\n## URL Configuration\n\nConfigure URLs for external links:\n\n```bash\n# Main application (redirected to after login)\nVITE_QUICKBACK_APP_URL=https://app.acme.com\n\n# Organization/tenant URL pattern\nVITE_TENANT_URL_PATTERN=/workspace/{slug}\n\n# Support pages\nVITE_SUPPORT_URL=https://help.acme.com\nVITE_PRIVACY_URL=https://acme.com/legal/privacy\nVITE_TERMS_URL=https://acme.com/legal/terms\n```\n\n### Tenant URL Patterns\n\nThe tenant URL pattern supports flexible organization routing:\n\n```bash\n# Path-based routing\nVITE_TENANT_URL_PATTERN=/organizations/{slug}\n# Result: https://app.acme.com/organizations/acme-corp\n\n# Subdomain routing\nVITE_TENANT_URL_PATTERN=https://{slug}.acme.com\n# Result: https://acme-corp.acme.com\n\n# Custom pattern\nVITE_TENANT_URL_PATTERN=/workspace/{slug}/dashboard\n# Result: https://app.acme.com/workspace/acme-corp/dashboard\n```\n\n## Complete Customization Example\n\nHere's a complete example showing all customization options:\n\n```ts title=\"src/main.tsx\"\n\n// Apply customizations before rendering\nsetAppConfig({\n name: 'Acme SaaS',\n tagline: 'Build faster, ship sooner',\n description: 'The complete platform for modern web applications',\n\n branding: {\n primaryColor: '#3b82f6',\n logoUrl: '/acme-logo.png',\n faviconUrl: '/favicon.ico',\n },\n\n labels: {\n organizations: 'Workspaces',\n terms: 'Terms and Conditions',\n privacy: 'Privacy Notice',\n support: 'Help Center',\n },\n\n messages: {\n noOrganizations: \"You haven't joined any workspaces yet.\",\n createOrganization: 'Create Workspace',\n contactAdminForInvite: 'Contact your team lead for access.',\n },\n\n routes: {\n public: {\n login: '/sign-in',\n signup: '/sign-up',\n },\n organizations: {\n list: '/workspaces',\n create: '/workspaces/new',\n detail: (slug) => `/workspaces/${slug}`,\n },\n },\n\n auth: {\n passwordRequirements: {\n minLength: 12,\n requireSymbols: true,\n },\n sessionDuration: 7 * 24 * 60 * 60, // 7 days\n },\n});\n\n// Render app\n\nconst root = document.getElementById('root')!;\ncreateRoot(root).render(\n \n);\n```\n\n## Custom Styles\n\nOverride default styles with custom CSS:\n\n```css title=\"custom-styles.css\"\n/* Override primary color */\n:root {\n --primary: 59 130 246; /* Tailwind blue-500 */\n --primary-foreground: 255 255 255;\n}\n\n/* Custom logo size */\n.logo {\n width: 180px;\n height: auto;\n}\n\n/* Custom button styles */\n.btn-primary {\n background-color: var(--primary);\n border-radius: 8px;\n font-weight: 600;\n}\n```\n\nImport your custom CSS after the Account UI styles:\n\n```ts\n\n```\n\n## Next Steps\n\n- **[Worker Setup](/account-ui/worker)** - Deploy your customized UI\n- **[Environment Variables](/account-ui/environment-variables)** - Complete configuration reference\n- **[Feature Flags](/account-ui/features)** - Enable/disable features"
|
|
7
7
|
},
|
|
8
8
|
"account-ui/environment-variables": {
|
|
9
9
|
"title": "Environment Variables",
|
|
10
|
-
"content": "# Environment Variables\n\nConfigure the Account UI by setting environment variables in your `.env` file or deployment platform.\n\n## Required Variables\n\nThese variables are **required** for the Account UI to function:\n\n### API Configuration\n\n```bash\n# Quickback API URL\
|
|
10
|
+
"content": "# Environment Variables\n\nConfigure the Account UI by setting environment variables in your `.env` file or deployment platform.\n\n## Required Variables\n\nThese variables are **required** for the Account UI to function:\n\n### API Configuration\n\n```bash\n# Quickback API URL\nVITE_QUICKBACK_API_URL=https://api.example.com\n\n# Account UI URL (where the Account UI is deployed)\nVITE_ACCOUNT_APP_URL=https://account.example.com\n```\n\n## App Identity\n\nConfigure your application's basic information:\n\n```bash\n# App name (displayed in UI)\nVITE_APP_NAME=My Application\n\n# Tagline (shown on landing pages)\nVITE_APP_TAGLINE=Build faster, ship sooner\n\n# Full description\nVITE_APP_DESCRIPTION=A complete platform for building modern web applications\n\n# Company information\nVITE_COMPANY_NAME=My Company Inc.\nVITE_COMPANY_ADDRESS=123 Main St, Suite 100, San Francisco, CA 94105\n```\n\n## URLs\n\n### Main Application\n\n```bash\n# Your main application URL\n# Users will be redirected here after authentication\nVITE_QUICKBACK_APP_URL=https://app.example.com\n\n# Organization/Tenant URL pattern (optional)\n# Use {slug} as placeholder for organization identifier\n# Examples:\n# /organizations/{slug} -> app.example.com/organizations/acme\n# /workspace/{slug} -> app.example.com/workspace/acme\n# https://{slug}.example.com -> acme.example.com\nVITE_TENANT_URL_PATTERN=/organizations/{slug}\n```\n\n### Support and Legal\n\n```bash\n# Support/help URL\nVITE_SUPPORT_URL=https://support.example.com\n\n# Privacy policy URL\nVITE_PRIVACY_URL=https://example.com/privacy\n\n# Terms of service URL\nVITE_TERMS_URL=https://example.com/terms\n```\n\n## Email Configuration\n\n```bash\n# From address for all emails\nVITE_EMAIL_FROM=noreply@example.com\n\n# Reply-to address\nVITE_EMAIL_REPLY_TO=support@example.com\n\n# Support email address\nVITE_SUPPORT_EMAIL=support@example.com\n\n# AWS Region for SES (if using AWS SES)\nVITE_EMAIL_REGION=us-east-1\n```\n\n## Branding\n\n```bash\n# Primary theme color (hex code)\nVITE_THEME_COLOR=#1e293b\n\n# SEO keywords (comma-separated)\nVITE_SEO_KEYWORDS=saas,authentication,account management\n```\n\n## Feature Flags\n\nEnable or disable features using boolean environment variables:\n\n### Authentication Features\n\n```bash\n# Enable user signup (default: true)\nENABLE_SIGNUP=true\n\n# Enable email verification after signup (default: true)\nENABLE_EMAIL_VERIFICATION=true\n\n# Disable email deliverability checks (default: false)\n# Set to true to skip checking if email addresses are deliverable\nDISABLE_EMAIL_STATUS_CHECK=false\n\n# Enable passkey (WebAuthn) login (default: true)\nENABLE_PASSKEY=true\n\n# Enable email OTP login and signup (default: true)\nENABLE_EMAIL_OTP=true\n\n# Enable email+password login and signup (default: false)\nENABLE_PASSWORD=false\n```\n\n### Account Management Features\n\n```bash\n# Enable file uploads (avatar, etc.) (default: false)\nVITE_ENABLE_FILE_UPLOADS=false\n```\n\n### Organization Features\n\n```bash\n# Enable multi-tenant organizations (default: true)\nENABLE_ORGANIZATIONS=true\n```\n\n### Admin Features\n\n```bash\n# Enable admin panel (default: true)\nENABLE_ADMIN=true\n```\n\n## Complete Example\n\nHere's a complete `.env` file with all common configuration:\n\n```bash title=\".env\"\n# ===== REQUIRED =====\nVITE_QUICKBACK_API_URL=https://api.example.com\nVITE_ACCOUNT_APP_URL=https://account.example.com\n\n# ===== APP IDENTITY =====\nVITE_APP_NAME=Acme SaaS\nVITE_APP_TAGLINE=Build faster, ship sooner\nVITE_APP_DESCRIPTION=The complete platform for modern web applications\nVITE_COMPANY_NAME=Acme Corporation\nVITE_COMPANY_ADDRESS=123 Main St, Suite 100, San Francisco, CA 94105\n\n# ===== URLS =====\nVITE_QUICKBACK_APP_URL=https://app.acme.com\nVITE_TENANT_URL_PATTERN=/organizations/{slug}\nVITE_SUPPORT_URL=https://help.acme.com\nVITE_PRIVACY_URL=https://acme.com/privacy\nVITE_TERMS_URL=https://acme.com/terms\n\n# ===== EMAIL =====\nVITE_EMAIL_FROM=noreply@acme.com\nVITE_EMAIL_REPLY_TO=support@acme.com\nVITE_SUPPORT_EMAIL=support@acme.com\nVITE_EMAIL_REGION=us-east-1\n\n# ===== BRANDING =====\nVITE_THEME_COLOR=#3b82f6\n\n# ===== SEO =====\nVITE_SEO_KEYWORDS=saas,project management,team collaboration\n\n# ===== FEATURES =====\nENABLE_SIGNUP=true\nENABLE_EMAIL_VERIFICATION=true\nENABLE_PASSKEY=true\nENABLE_EMAIL_OTP=true\nENABLE_PASSWORD=false\nENABLE_ORGANIZATIONS=true\nENABLE_ADMIN=true\nVITE_ENABLE_FILE_UPLOADS=true\nDISABLE_EMAIL_STATUS_CHECK=false\n```\n\n## Environment-Specific Configuration\n\n### Development\n\n```bash title=\".env.development\"\nVITE_QUICKBACK_API_URL=http://localhost:8787\nVITE_ACCOUNT_APP_URL=http://localhost:5173\nVITE_QUICKBACK_APP_URL=http://localhost:3000\nDISABLE_EMAIL_STATUS_CHECK=true\n```\n\n### Staging\n\n```bash title=\".env.staging\"\nVITE_QUICKBACK_API_URL=https://api-staging.example.com\nVITE_ACCOUNT_APP_URL=https://account-staging.example.com\nVITE_QUICKBACK_APP_URL=https://app-staging.example.com\n```\n\n### Production\n\n```bash title=\".env.production\"\nVITE_QUICKBACK_API_URL=https://api.example.com\nVITE_ACCOUNT_APP_URL=https://account.example.com\nVITE_QUICKBACK_APP_URL=https://app.example.com\nDISABLE_EMAIL_STATUS_CHECK=false\n```\n\n## Cloudflare Pages Setup\n\nWhen deploying to Cloudflare Pages, set environment variables in the dashboard:\n\n1. Go to **Settings** → **Environment Variables**\n2. Add each `VITE_*` variable\n3. Separate values for **Production** and **Preview** branches\n\n## Wrangler Configuration\n\nFor `wrangler dev` and `wrangler deploy`, add variables to `wrangler.toml`:\n\n```toml title=\"wrangler.toml\"\n[env.production.vars]\nVITE_QUICKBACK_API_URL = \"https://api.example.com\"\nVITE_ACCOUNT_APP_URL = \"https://account.example.com\"\nVITE_APP_NAME = \"My App\"\n# ... other variables\n```\n\nOr use `.dev.vars` for local development (git-ignored):\n\n```bash title=\".dev.vars\"\nVITE_QUICKBACK_API_URL=http://localhost:8787\nVITE_ACCOUNT_APP_URL=http://localhost:5173\n```\n\n## Runtime Configuration\n\nSome values can be overridden at runtime using the config API:\n\n```ts\n\nsetAppConfig({\n name: 'My Custom App',\n branding: {\n primaryColor: '#ff6600',\n logoUrl: '/custom-logo.png',\n },\n urls: {\n base: 'https://account.custom.com',\n app: 'https://app.custom.com',\n },\n});\n```\n\n## Validation\n\nThe Account UI validates configuration on startup:\n\n- **Missing VITE_QUICKBACK_API_URL**: Throws error\n- **Invalid URLs**: Logs warning\n- **Missing optional fields**: Uses defaults\n\nCheck the browser console for configuration warnings.\n\n## Next Steps\n\n- **[Feature Flags](/account-ui/features)** - Detailed feature configuration\n- **[Customization](/account-ui/customization)** - Customize labels and messages\n- **[Worker Setup](/account-ui/worker)** - Deploy to Cloudflare"
|
|
11
11
|
},
|
|
12
12
|
"account-ui/features/admin": {
|
|
13
13
|
"title": "Admin Panel",
|
|
@@ -31,7 +31,7 @@ export const DOCS = {
|
|
|
31
31
|
},
|
|
32
32
|
"account-ui/features/organizations": {
|
|
33
33
|
"title": "Organizations",
|
|
34
|
-
"content": "Account UI provides a complete organization management interface when `ENABLE_ORGANIZATIONS=true`.\n\n## Organization CRUD\n\n- Create new organizations\n- Update organization name and settings\n- Delete organizations (owner only)\n\n## Member Management\n\n- Invite members by email\n- Assign roles: **owner**, **admin**, **member**\n- Remove members\n- Transfer ownership\n\n## Invitations\n\n- Pending invitation list\n- Resend invitations\n- Cancel invitations\n\n> **Note:** These three roles (`owner`, `admin`, `member`) are Better Auth's built-in organization roles and map directly to Account UI's role picker. Use the same roles in your Quickback [Access](/compiler/definitions/access) rules
|
|
34
|
+
"content": "Account UI provides a complete organization management interface when `ENABLE_ORGANIZATIONS=true`.\n\n## Organization CRUD\n\n- Create new organizations\n- Update organization name and settings\n- Delete organizations (owner only)\n\n## Member Management\n\n- Invite members by email\n- Assign roles: **owner**, **admin**, **member**\n- Remove members\n- Transfer ownership\n\n## Invitations\n\n- Pending invitation list\n- Resend invitations\n- Cancel invitations\n\n> **Note:** These three roles (`owner`, `admin`, `member`) are Better Auth's built-in organization roles and map directly to Account UI's role picker. Use the same roles in your Quickback [Access](/compiler/definitions/access) rules — with [`auth.roleHierarchy`](/compiler/definitions/access#role-hierarchy) configured, you can write `roles: [\"member+\"]` to mean \"member and above.\"\n\n## Related\n\n- [Environment Variables](/account-ui/environment-variables)\n- [Account UI Overview](/account-ui)"
|
|
35
35
|
},
|
|
36
36
|
"account-ui/features/passkeys": {
|
|
37
37
|
"title": "Passkeys",
|
|
@@ -51,23 +51,23 @@ export const DOCS = {
|
|
|
51
51
|
},
|
|
52
52
|
"account-ui/library-usage": {
|
|
53
53
|
"title": "Library Usage",
|
|
54
|
-
"content": "# Library Usage\n\nInstead of cloning the template, you can install Account UI as an npm package. This gives you automatic updates via `npm update` while configuring the UI through `setAppConfig()`.\n\n## Installation\n\n```bash\nnpm install quickback-better-auth-account-ui\n```\n\n### Peer Dependencies\n\nAccount UI expects these packages in your app:\n\n```bash\nnpm install react react-dom react-router-dom @tanstack/react-query\n```\n\n## Basic Setup\n\n### 1. Import and Configure\n\n```tsx title=\"src/main.tsx\"\n\nsetAppConfig({\n authRoute: 'quickback', // or 'better-auth' for standalone Better Auth\n name: 'My App',\n companyName: 'My Company Inc.',\n tagline: 'Build faster, ship sooner',\n description: 'My app description',\n});\n\nReactDOM.createRoot(document.getElementById('root')!).render(\n \n </React.StrictMode>\n);\n```\n\n### 2. Set API URLs\n\nThe library reads API URLs from `globalThis` variables. Set these before importing the library:\n\n```tsx title=\"src/main.tsx\"\n// Set API URLs before auth-ui loads\n(globalThis as any).__QUICKBACK_API_URL__ = 'https://api.example.com';\n(globalThis as any).__QUICKBACK_APP_URL__ = 'https://account.example.com';\n\n// Then import dynamically to ensure globals are set first\nconst { AuthApp, setAppConfig } = await import('quickback-better-auth-account-ui');\nawait import('quickback-better-auth-account-ui/styles.css');\n```\n\nOr with Vite environment variables:\n\n```tsx title=\"src/main.tsx\"\n(globalThis as any).__QUICKBACK_API_URL__ = import.meta.env.
|
|
54
|
+
"content": "# Library Usage\n\nInstead of cloning the template, you can install Account UI as an npm package. This gives you automatic updates via `npm update` while configuring the UI through `setAppConfig()`.\n\n## Installation\n\n```bash\nnpm install quickback-better-auth-account-ui\n```\n\n### Peer Dependencies\n\nAccount UI expects these packages in your app:\n\n```bash\nnpm install react react-dom react-router-dom @tanstack/react-query\n```\n\n## Basic Setup\n\n### 1. Import and Configure\n\n```tsx title=\"src/main.tsx\"\n\nsetAppConfig({\n authRoute: 'quickback', // or 'better-auth' for standalone Better Auth\n name: 'My App',\n companyName: 'My Company Inc.',\n tagline: 'Build faster, ship sooner',\n description: 'My app description',\n});\n\nReactDOM.createRoot(document.getElementById('root')!).render(\n \n </React.StrictMode>\n);\n```\n\n### 2. Set API URLs\n\nThe library reads API URLs from `globalThis` variables. Set these before importing the library:\n\n```tsx title=\"src/main.tsx\"\n// Set API URLs before auth-ui loads\n(globalThis as any).__QUICKBACK_API_URL__ = 'https://api.example.com';\n(globalThis as any).__QUICKBACK_APP_URL__ = 'https://account.example.com';\n\n// Then import dynamically to ensure globals are set first\nconst { AuthApp, setAppConfig } = await import('quickback-better-auth-account-ui');\nawait import('quickback-better-auth-account-ui/styles.css');\n```\n\nOr with Vite environment variables:\n\n```tsx title=\"src/main.tsx\"\n(globalThis as any).__QUICKBACK_API_URL__ = import.meta.env.VITE_QUICKBACK_API_URL;\n(globalThis as any).__QUICKBACK_APP_URL__ = import.meta.env.VITE_QUICKBACK_APP_URL;\n\nPromise.all([\n import('quickback-better-auth-account-ui'),\n import('quickback-better-auth-account-ui/styles.css'),\n]).then(([{ AuthApp, setAppConfig }]) => {\n setAppConfig({\n authRoute: 'quickback',\n name: import.meta.env.VITE_APP_NAME || 'My App',\n companyName: import.meta.env.VITE_COMPANY_NAME || 'My Company',\n tagline: import.meta.env.VITE_APP_TAGLINE || 'Welcome',\n });\n\n ReactDOM.createRoot(document.getElementById('root')!).render(\n \n </React.StrictMode>\n );\n});\n```\n\n## Cloudflare Worker\n\nThe library exports a Cloudflare Worker entry point for SPA routing and static asset serving:\n\n```ts title=\"src/worker.ts\"\nexport { default } from 'quickback-better-auth-account-ui/worker';\n```\n\nOr extend it with custom logic:\n\n```ts title=\"src/worker.ts\"\n\nexport default createAuthWorker();\n```\n\n## Configuration via `setAppConfig()`\n\nIn library mode, all configuration happens through `setAppConfig()` instead of environment variables.\n\n### Auth Route Mode\n\n```ts\nsetAppConfig({\n authRoute: 'quickback', // Quickback API: /auth/v1, /api/v1, /storage/v1\n // or\n authRoute: 'better-auth', // Better Auth default: /api/auth\n});\n```\n\n### Branding\n\n```ts\nsetAppConfig({\n name: 'Acme SaaS',\n companyName: 'Acme Corporation',\n tagline: 'Build faster, ship sooner',\n description: 'The complete platform for modern web applications',\n branding: {\n primaryColor: '#3b82f6',\n logoUrl: '/logo.png',\n faviconUrl: '/favicon.ico',\n },\n});\n```\n\n### Labels and Messages\n\n```ts\nsetAppConfig({\n labels: {\n organizations: 'Workspaces',\n terms: 'Terms and Conditions',\n privacy: 'Privacy Notice',\n },\n messages: {\n noOrganizations: \"You haven't joined any workspaces yet.\",\n createOrganization: 'Create Workspace',\n },\n});\n```\n\n### Routes\n\n```ts\nsetAppConfig({\n routes: {\n public: {\n login: '/sign-in',\n signup: '/sign-up',\n },\n organizations: {\n list: '/workspaces',\n create: '/workspaces/new',\n },\n },\n});\n```\n\n### Password and Session\n\n```ts\nsetAppConfig({\n auth: {\n passwordRequirements: {\n minLength: 12,\n requireSymbols: true,\n },\n sessionDuration: 7 * 24 * 60 * 60, // 7 days\n },\n});\n```\n\nSee [Customization](/account-ui/customization) for the full reference of all configurable options.\n\n## Exports\n\nThe library provides the following exports:\n\n### Main Entry (`quickback-better-auth-account-ui`)\n\n| Export | Type | Description |\n|--------|------|-------------|\n| `AuthApp` | Component | The main React application component |\n| `authClient` | Object | Pre-configured Better Auth client |\n| `appConfig` | Object | Current app configuration |\n| `setAppConfig` | Function | Set app configuration overrides |\n| `createAppConfig` | Function | Create a new config object |\n| `getApiBase` | Function | Get the current API base URL |\n| `setApiBase` | Function | Override the API base URL |\n| `getAuthApiUrl` | Function | Get the auth API URL |\n| `getDataApiUrl` | Function | Get the data API URL |\n| `getStorageApiUrl` | Function | Get the storage API URL |\n\n### Styles (`quickback-better-auth-account-ui/styles.css`)\n\nThe compiled CSS for the Account UI. Must be imported for the UI to render correctly.\n\n### Worker (`quickback-better-auth-account-ui/worker`)\n\n| Export | Type | Description |\n|--------|------|-------------|\n| `default` | Worker | Cloudflare Worker with SPA routing |\n| `createAuthWorker` | Function | Factory for creating a worker instance |\n\n## Custom Styles\n\nOverride styles by importing your CSS after the library styles:\n\n```ts\n\n```\n\n```css title=\"my-overrides.css\"\n:root {\n --primary: 59 130 246;\n --primary-foreground: 255 255 255;\n}\n```\n\n## Updating\n\nUpdate to the latest version:\n\n```bash\nnpm update quickback-better-auth-account-ui\n```\n\nThe library follows semantic versioning. Check the [changelog](https://github.com/Kardoe-com/quickback-better-auth-account-ui/releases) for breaking changes.\n\n## Next Steps\n\n- **[Customization](/account-ui/customization)** — Full configuration reference\n- **[Feature Flags](/account-ui/features)** — Enable and disable features\n- **[Worker Setup](/account-ui/worker)** — Deploy to Cloudflare Workers\n- **[With Quickback](/account-ui/with-quickback)** — Quickback-specific configuration"
|
|
55
55
|
},
|
|
56
56
|
"account-ui/standalone": {
|
|
57
57
|
"title": "Standalone Usage",
|
|
58
|
-
"content": "Account UI can be used with **any Better Auth-powered backend**, not just Quickback-compiled projects. This makes it a drop-in authentication frontend for any app using Better Auth.\n\n## Requirements\n\n- A backend running [Better Auth](https://better-auth.com) with API endpoints\n- Node.js 18+ and npm/pnpm/bun\n- A Cloudflare account (for deployment)\n\n## Setup\n\n### 1. Clone or Install the Account UI\n\n```bash\nnpx degit Kardoe-com/quickback-better-auth-account-ui my-account-app\ncd my-account-app\nnpm install\n```\n\n### 2. Configure the Auth Route Mode\n\nThe key difference from Quickback mode is the `VITE_AUTH_ROUTE` variable. Set it to `better-auth` to use Better Auth's default API paths:\n\n```bash title=\".env\"\n# Auth route mode — use 'better-auth' for standalone\nVITE_AUTH_ROUTE=better-auth\n\n# Your Better Auth backend URL\
|
|
58
|
+
"content": "Account UI can be used with **any Better Auth-powered backend**, not just Quickback-compiled projects. This makes it a drop-in authentication frontend for any app using Better Auth.\n\n## Requirements\n\n- A backend running [Better Auth](https://better-auth.com) with API endpoints\n- Node.js 18+ and npm/pnpm/bun\n- A Cloudflare account (for deployment)\n\n## Setup\n\n### 1. Clone or Install the Account UI\n\n```bash\nnpx degit Kardoe-com/quickback-better-auth-account-ui my-account-app\ncd my-account-app\nnpm install\n```\n\n### 2. Configure the Auth Route Mode\n\nThe key difference from Quickback mode is the `VITE_AUTH_ROUTE` variable. Set it to `better-auth` to use Better Auth's default API paths:\n\n```bash title=\".env\"\n# Auth route mode — use 'better-auth' for standalone\nVITE_AUTH_ROUTE=better-auth\n\n# Your Better Auth backend URL\nVITE_QUICKBACK_API_URL=https://api.example.com\n\n# Where this Account UI is hosted\nVITE_ACCOUNT_APP_URL=https://account.example.com\n```\n\nThis configures the auth client to use `/api/auth` as the base path (Better Auth's default), instead of Quickback's `/auth/v1`.\n\n### 3. Configure Your App\n\n```bash title=\".env\"\n# App identity\nVITE_APP_NAME=My App\nVITE_APP_TAGLINE=Welcome to My App\n\n# Redirect after login\nVITE_QUICKBACK_APP_URL=https://app.example.com\n\n# Feature flags\nENABLE_SIGNUP=true\nENABLE_ORGANIZATIONS=true\nENABLE_PASSKEY=true\nENABLE_EMAIL_OTP=true\n```\n\nSee [Environment Variables](/account-ui/environment-variables) for the complete reference.\n\n### 4. Build and Deploy\n\n```bash\nnpm run build\nnpx wrangler deploy\n```\n\n## Auth Route Modes\n\nAccount UI supports three routing modes, controlled by `VITE_AUTH_ROUTE`:\n\n| Mode | Value | Auth Path | Data Path | Storage Path |\n|------|-------|-----------|-----------|--------------|\n| Better Auth | `better-auth` | `/api/auth` | — | — |\n| Quickback | `quickback` | `/auth/v1` | `/api/v1` | `/storage/v1` |\n| Custom | `custom` | Custom | Custom | Custom |\n\n### Better Auth Mode (Default)\n\nRoutes all auth requests to `/api/auth/*` — the standard Better Auth convention:\n\n```bash\nVITE_AUTH_ROUTE=better-auth\n```\n\n### Custom Mode\n\nFor non-standard setups, use custom mode with explicit paths:\n\n```bash\nVITE_AUTH_ROUTE=custom\nVITE_AUTH_BASE_PATH=/my-auth\nVITE_DATA_BASE_PATH=/my-api\nVITE_STORAGE_BASE_PATH=/my-storage\n```\n\n## Backend Requirements\n\nYour Better Auth backend must have the following plugins enabled for full Account UI functionality:\n\n| Feature | Required Plugin | Required For |\n|---------|----------------|--------------|\n| Organizations | `organization` | Multi-tenant org management |\n| Admin panel | `admin` | User management dashboard |\n| API keys | `apiKey` | API key generation UI |\n| Passkeys | `@better-auth/passkey` | WebAuthn authentication |\n| Email OTP | `emailOTP` | One-time password login |\n| CLI login | `deviceAuthorization` | `quickback login` flow |\n\nOnly enable the features that match your backend's plugin configuration. Disable features for plugins you haven't installed:\n\n```bash\n# If your backend doesn't have the organization plugin:\nENABLE_ORGANIZATIONS=false\n\n# If you haven't set up passkeys:\nENABLE_PASSKEYS=false\n```\n\n## CORS Configuration\n\nYour Better Auth backend must allow requests from the Account UI's domain. Configure CORS to include:\n\n```typescript\n// In your Better Auth config\ntrustedOrigins: [\n \"https://account.example.com\", // Account UI domain\n],\n```\n\n## Differences from Quickback Mode\n\n| Aspect | Standalone | With Quickback |\n|--------|-----------|----------------|\n| Auth routes | `/api/auth/*` | `/auth/v1/*` |\n| Data API | Not used | `/api/v1/*` |\n| Storage API | Not used | `/storage/v1/*` |\n| File uploads | Manual setup | Auto-configured |\n| Backend | Any Better Auth app | Quickback-compiled |\n\n## Next Steps\n\n- [Environment Variables](/account-ui/environment-variables) — Complete configuration reference\n- [Customization](/account-ui/customization) — Branding, labels, and theming\n- [Worker Setup](/account-ui/worker) — Cloudflare Workers deployment\n- [Feature Flags](/account-ui/features) — Enable and disable features"
|
|
59
59
|
},
|
|
60
60
|
"account-ui/with-quickback": {
|
|
61
61
|
"title": "With Quickback",
|
|
62
|
-
"content": "When using Account UI with a Quickback-compiled backend, the recommended approach is to let the compiler build and embed the SPA directly into your Worker.\n\n## Compiler-Embedded (Recommended)\n\nAdd `account` to your `quickback.config.ts`:\n\n```typescript title=\"quickback/quickback.config.ts\"\nexport default {\n name: \"my-app\",\n template: \"hono\",\n account: {\n domain: \"auth.example.com\",\n name: \"My App\",\n companyName: \"My Company\",\n auth: {\n password: true,\n passkey: true,\n organizations: true,\n admin: true,\n },\n },\n // ...providers\n};\n```\n\nThen compile and deploy:\n\n```bash\nquickback compile\nnpx wrangler deploy\n```\n\n### What Happens During Compilation\n\n1. The compiler reads your `account` config and generates a `.env` file with the correct Vite environment variables (`
|
|
62
|
+
"content": "When using Account UI with a Quickback-compiled backend, the recommended approach is to let the compiler build and embed the SPA directly into your Worker.\n\n## Compiler-Embedded (Recommended)\n\nAdd `account` to your `quickback.config.ts`:\n\n```typescript title=\"quickback/quickback.config.ts\"\nexport default {\n name: \"my-app\",\n template: \"hono\",\n account: {\n domain: \"auth.example.com\",\n name: \"My App\",\n companyName: \"My Company\",\n auth: {\n password: true,\n passkey: true,\n organizations: true,\n admin: true,\n },\n },\n // ...providers\n};\n```\n\nThen compile and deploy:\n\n```bash\nquickback compile\nnpx wrangler deploy\n```\n\n### What Happens During Compilation\n\n1. The compiler reads your `account` config and generates a `.env` file with the correct Vite environment variables (`VITE_QUICKBACK_API_URL`, `VITE_ENABLE_PASSWORD`, branding, etc.)\n2. The Account SPA source is copied to a temp directory, with disabled feature routes excluded\n3. Pre-installed dependencies are symlinked (no `npm install` during build)\n4. Vite builds the SPA with your settings baked in\n5. Built assets (content-hashed filenames) are placed in the output directory\n\nWhen CMS is also enabled, Account assets go to `src/apps/account/` and are served at `/account/`. When Account is the only SPA, assets go to `src/apps/` and are served at root.\n\n### Custom Domains\n\nWith a custom domain, the Account SPA is served at root (`/`) on that domain:\n\n```typescript\naccount: { domain: \"auth.example.com\" }\n```\n\nAdd an admin domain to serve the admin panel on its own subdomain:\n\n```typescript\naccount: {\n domain: \"auth.example.com\",\n adminDomain: \"admin.example.com\",\n}\n```\n\nSee [Multi-Domain Architecture](/compiler/config/domains) for details on hostname routing and cross-subdomain cookies.\n\n### Auth Feature Flags\n\nFeature flags control which pages are included in the build:\n\n```typescript\nauth: {\n password: true, // Email/password login + inline password change\n emailOTP: false, // Email OTP login flow\n passkey: true, // WebAuthn passkey setup + management\n organizations: true, // Dashboard, org management, invitations\n admin: true, // Admin panel (user management)\n}\n```\n\nDisabled features are excluded at compile time — their route files are removed before the Vite build. See [Configuration](/compiler/config) for all options.\n\n## Manual Deployment\n\nIf you need Account UI as a separate Worker (not embedded in the API Worker), you can deploy it standalone.\n\n### 1. Clone the Template\n\n```bash\nnpx degit Kardoe-com/quickback-better-auth-account-ui my-account-app\ncd my-account-app\nnpm install\n```\n\n### 2. Configure for Quickback\n\nSet the auth route mode to `quickback` to match Quickback's API paths:\n\n```bash title=\".env\"\nVITE_AUTH_ROUTE=quickback\nVITE_QUICKBACK_API_URL=https://api.example.com\nVITE_ACCOUNT_APP_URL=https://account.example.com\nVITE_QUICKBACK_APP_URL=https://app.example.com\n```\n\nIn Quickback mode, Account UI routes requests to three API paths:\n\n| Path | Purpose | Examples |\n|------|---------|---------|\n| `/auth/v1/*` | Authentication | Login, signup, sessions, passkeys |\n| `/api/v1/*` | Data API | Organizations, API keys |\n| `/storage/v1/*` | File storage | Avatar uploads, file management |\n\n### 3. Configure Features\n\nMatch your `quickback.config.ts` plugins:\n\n```bash title=\".env\"\nVITE_APP_NAME=My App\nVITE_APP_TAGLINE=Build faster, ship sooner\nENABLE_SIGNUP=true\nENABLE_ORGANIZATIONS=true\nENABLE_PASSKEY=true\nENABLE_ADMIN=true\n```\n\n### 4. Build and Deploy\n\n```bash\nnpm run build\nnpx wrangler deploy\n```\n\n## Library Mode\n\nInstall as a dependency instead of cloning:\n\n```bash\nnpm install quickback-better-auth-account-ui\n```\n\n```tsx\n\nsetAppConfig({\n authRoute: 'quickback',\n name: 'My App',\n companyName: 'My Company',\n});\n```\n\nSee [Library Usage](/account-ui/library-usage) for the complete guide.\n\n## Next Steps\n\n- [Configuration](/compiler/config) — CMS and Account config reference\n- [Multi-Domain Architecture](/compiler/config/domains) — Custom domains and hostname routing\n- [Environment Variables](/account-ui/environment-variables) — Complete variable reference\n- [Feature Flags](/account-ui/features) — Enable and disable features\n- [Customization](/account-ui/customization) — Branding, labels, and theming"
|
|
63
63
|
},
|
|
64
64
|
"account-ui/worker": {
|
|
65
65
|
"title": "Worker Setup",
|
|
66
|
-
"content": "# Worker Setup\n\nDeploy the Account UI as a Cloudflare Worker with static asset serving.\n\n## Quick Start\n\n### Using the Template\n\n```bash\nnpx degit Kardoe-com/quickback-better-auth-account-ui my-account-app\ncd my-account-app\nnpm install\n```\n\n### Using the Library\n\nIf you're consuming Account UI as an npm package, re-export the worker from the library:\n\n```ts title=\"src/worker.ts\"\nexport { default } from 'quickback-better-auth-account-ui/worker';\n```\n\nThen continue with the Wrangler configuration below.\n\n### 2. Configure Wrangler\n\nThe template includes a `wrangler.toml` pre-configured for Cloudflare Workers:\n\n```toml title=\"wrangler.toml\"\nname = \"my-account-app\"\ncompatibility_date = \"2025-01-01\"\ncompatibility_flags = [\"nodejs_compat\"]\n\n# Custom domain (uncomment and set your domain)\n# routes = [\n# { pattern = \"account.example.com\", custom_domain = true }\n# ]\n\n# Worker entry point\nmain = \"src/worker.ts\"\n\n# Static assets\n[assets]\nbinding = \"ASSETS\"\ndirectory = \"dist/client\"\n```\n\n### 3. Build and Deploy\n\n```bash\nnpm run build\nnpx wrangler deploy\n```\n\n## Worker Entry Point\n\nThe worker is at `src/worker.ts`. It serves static assets and handles SPA routing:\n\n- Static asset serving via the `ASSETS` binding\n- SPA routing (all routes serve `index.html`)\n- Health check endpoint (`/health`)\n\n### Custom Worker Logic\n\nEdit `src/worker.ts` directly to add custom logic:\n\n```ts title=\"src/worker.ts\"\nexport default {\n async fetch(request: Request, env: Env): Promise\n\n### Multiple Environments\n\n```toml title=\"wrangler.toml\"\n# Development\n[env.dev]\nname = \"my-account-app-dev\"\nroute = \"account-dev.example.com/*\"\n\n[env.dev.vars]\
|
|
66
|
+
"content": "# Worker Setup\n\nDeploy the Account UI as a Cloudflare Worker with static asset serving.\n\n## Quick Start\n\n### Using the Template\n\n```bash\nnpx degit Kardoe-com/quickback-better-auth-account-ui my-account-app\ncd my-account-app\nnpm install\n```\n\n### Using the Library\n\nIf you're consuming Account UI as an npm package, re-export the worker from the library:\n\n```ts title=\"src/worker.ts\"\nexport { default } from 'quickback-better-auth-account-ui/worker';\n```\n\nThen continue with the Wrangler configuration below.\n\n### 2. Configure Wrangler\n\nThe template includes a `wrangler.toml` pre-configured for Cloudflare Workers:\n\n```toml title=\"wrangler.toml\"\nname = \"my-account-app\"\ncompatibility_date = \"2025-01-01\"\ncompatibility_flags = [\"nodejs_compat\"]\n\n# Custom domain (uncomment and set your domain)\n# routes = [\n# { pattern = \"account.example.com\", custom_domain = true }\n# ]\n\n# Worker entry point\nmain = \"src/worker.ts\"\n\n# Static assets\n[assets]\nbinding = \"ASSETS\"\ndirectory = \"dist/client\"\n```\n\n### 3. Build and Deploy\n\n```bash\nnpm run build\nnpx wrangler deploy\n```\n\n## Worker Entry Point\n\nThe worker is at `src/worker.ts`. It serves static assets and handles SPA routing:\n\n- Static asset serving via the `ASSETS` binding\n- SPA routing (all routes serve `index.html`)\n- Health check endpoint (`/health`)\n\n### Custom Worker Logic\n\nEdit `src/worker.ts` directly to add custom logic:\n\n```ts title=\"src/worker.ts\"\nexport default {\n async fetch(request: Request, env: Env): Promise\n\n### Multiple Environments\n\n```toml title=\"wrangler.toml\"\n# Development\n[env.dev]\nname = \"my-account-app-dev\"\nroute = \"account-dev.example.com/*\"\n\n[env.dev.vars]\nVITE_QUICKBACK_API_URL = \"https://api-dev.example.com\"\nVITE_ACCOUNT_APP_URL = \"https://account-dev.example.com\"\n\n# Staging\n[env.staging]\nname = \"my-account-app-staging\"\nroute = \"account-staging.example.com/*\"\n\n[env.staging.vars]\nVITE_QUICKBACK_API_URL = \"https://api-staging.example.com\"\nVITE_ACCOUNT_APP_URL = \"https://account-staging.example.com\"\n\n# Production\n[env.production]\nname = \"my-account-app\"\nroute = \"account.example.com/*\"\n\n[env.production.vars]\nVITE_QUICKBACK_API_URL = \"https://api.example.com\"\nVITE_ACCOUNT_APP_URL = \"https://account.example.com\"\n```\n\nDeploy to specific environment:\n\n```bash\nwrangler deploy --env staging\nwrangler deploy --env production\n```\n\n## Cloudflare Pages Alternative\n\nYou can also deploy to Cloudflare Pages instead of Workers:\n\n### 1. Configure Build\n\n```toml title=\"wrangler.toml\"\n# Remove [assets] section - Pages handles this\n\nname = \"my-account-app\"\npages_build_output_dir = \"dist/client\"\n```\n\n### 2. Deploy to Pages\n\n```bash\n# First time setup\nwrangler pages project create my-account-app\n\n# Deploy\nwrangler pages deploy dist/client\n```\n\n### 3. Configure Environment Variables\n\nSet environment variables in Cloudflare Pages dashboard:\n1. Go to your Pages project\n2. **Settings** → **Environment Variables**\n3. Add `VITE_*` variables\n4. Redeploy\n\n## Local Development\n\n### Option 1: Vite Dev Server\n\nThe fastest way to develop locally:\n\n```bash\nnpx vite dev\n```\n\nThis starts the Vite dev server with hot module replacement on `localhost:5173`.\n\n### Option 2: Wrangler Dev\n\nTest the worker locally with `wrangler dev`:\n\n```bash\nnpm run build && wrangler dev\n```\n\nThis runs the worker on `localhost:8787`.\n\n## Health Check\n\nThe worker includes a built-in health check endpoint:\n\n```bash\ncurl https://account.example.com/health\n```\n\nResponse:\n\n```json\n{\n \"status\": \"ok\",\n \"app\": \"auth-ui\"\n}\n```\n\nUse this for:\n- Uptime monitoring\n- Load balancer health checks\n- Deployment verification\n\n## Security Headers\n\nAdd security headers by editing `src/worker.ts`:\n\n```ts title=\"src/worker.ts\"\nexport default {\n async fetch(request: Request, env: Env): Promise<Response> {\n // ... routing logic ...\n\n // Add security headers to response\n const response = await env.ASSETS.fetch(request);\n\n const headers = new Headers(response.headers);\n headers.set('X-Frame-Options', 'DENY');\n headers.set('X-Content-Type-Options', 'nosniff');\n headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');\n headers.set('Permissions-Policy', 'geolocation=(), microphone=(), camera=()');\n\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n },\n};\n```\n\n## Custom 404 Page\n\nServe a custom 404 page for unmatched routes:\n\n```ts title=\"src/worker.ts\"\nexport default {\n async fetch(request: Request, env: Env): Promise<Response> {\n const url = new URL(request.url);\n\n // Try to serve static asset\n const assetResponse = await env.ASSETS.fetch(request);\n\n if (assetResponse.status !== 404) {\n return assetResponse;\n }\n\n // Serve index.html for SPA routes\n if (!url.pathname.startsWith('/api/')) {\n const indexRequest = new Request(`${url.origin}/index.html`, request);\n return env.ASSETS.fetch(indexRequest);\n }\n\n // Custom 404 for API routes\n return new Response('Not Found', { status: 404 });\n },\n};\n```\n\n## Deployment Checklist\n\nBefore deploying to production:\n\n- [ ] Set all required environment variables (`VITE_QUICKBACK_API_URL`, etc.)\n- [ ] Configure custom domain in Cloudflare\n- [ ] Add SSL certificate (automatic with Cloudflare)\n- [ ] Test all authentication flows\n- [ ] Configure DNS records\n- [ ] Set up monitoring/health checks\n- [ ] Test email sending\n- [ ] Verify passkey functionality (requires HTTPS)\n- [ ] Check CORS configuration on API\n- [ ] Review security headers\n- [ ] Test organization invitations\n- [ ] Verify redirection to main app works\n\n## Troubleshooting\n\n### Assets Not Loading\n\n**Problem**: 404 errors for static assets (JS, CSS)\n\n**Solution**: Check `directory` path in `wrangler.toml`:\n\n```toml\n[assets]\nbinding = \"ASSETS\"\ndirectory = \"dist/client\" # Must point to Vite's client build output\n```\n\n### Environment Variables Not Working\n\n**Problem**: Config values are undefined\n\n**Solution**: Remember that `VITE_*` variables are build-time. Either:\n1. Set them in `.env.production` before building\n2. Use `setAppConfig()` in `src/main.tsx` for runtime overrides\n3. Edit `src/config/app.ts` defaults directly\n\n### SPA Routing Issues\n\n**Problem**: Refreshing on `/profile` returns 404\n\n**Solution**: Ensure your worker serves `index.html` for all non-asset routes:\n\n```ts\nif (assetResponse.status === 404 && !url.pathname.startsWith('/api/')) {\n return env.ASSETS.fetch(new Request(`${url.origin}/index.html`, request));\n}\n```\n\n## Next Steps\n\n- **[Environment Variables](/account-ui/environment-variables)** - Configure your deployment\n- **[Feature Flags](/account-ui/features)** - Enable features\n- **[Customization](/account-ui/customization)** - Brand your UI"
|
|
67
67
|
},
|
|
68
68
|
"changelog": {
|
|
69
69
|
"title": "Changelog",
|
|
70
|
-
"content": "# Changelog\n\nRelease notes for the Quickback compiler, CLI, and platform.\n\n---\n\n## v0.5.11 — February 24, 2026\n\n### Email OTP & Auth Fixes\n\n- Fixed email-OTP magic links not working correctly\n- Removed deprecated `/internal/validate` endpoint — use standard Better Auth session validation instead\n- Auth is now required for all API routes when running locally (previously some routes were unprotected in dev)\n\n### Multiple Table Exports Fix\n\n- Fixed a compiler error when a single file exports multiple Drizzle tables alongside a `defineTable()` default export\n- The CLI now properly detects and reports this with a clear error message pointing to the fix\n\n### Headless Drizzle Rename Hints\n\n- Added `compiler.migrations.renames` configuration for CI/CD environments where Drizzle's interactive rename prompts would block compilation\n- Compile errors now include explicit rename key paths and fail fast on malformed rename config keys\n- See [Configuration](/compiler/config) for details\n\n### Security Contract Report Artifacts\n\n- Added generated security contract artifacts to compiler output:\n - `reports/security-contracts.report.json`\n - `reports/security-contracts.report.sig.json`\n- Added config-driven signing controls:\n - `compiler.securityContracts.report.signature.enabled`\n - `compiler.securityContracts.report.signature.required`\n - `compiler.securityContracts.report.signature.key` / `keyEnv` / `keyId`\n- Missing required signing keys now fail loudly with explicit remediation guidance\n- Added strict config validation for report/signature paths and signing options\n\n### Mandatory Unsafe Action Audit Trail\n\n- Added structured unsafe action config (`unsafe: { reason, adminOnly, crossTenant, targetScope }`)\n- Cross-tenant unsafe actions now require Better Auth authentication plus platform admin role (`ctx.userRole === \"admin\"`)\n- Added mandatory audit logging for unsafe cross-tenant actions (success, denial, and error paths)\n- Cloudflare output now includes optional `AUDIT_DB` wiring, `drizzle.audit.config.ts`, and `db:migrate:audit:*` scripts when unsafe actions are present\n- Added compile-time raw SQL guard for actions and handlers (`allowRawSql: true` required per action)\n\n---\n\n## v0.5.10 — February 19, 2026\n\n### Compiler Page Parsing & CLI Output\n\n- Improved compiler page parsing for `definePage()` definitions\n- Better CLI output formatting during compilation\n- Added `apiPath` to schema registry for CMS integration\n\n### Bug Fixes\n\n- Fixed hyphenated action names not being properly quoted in generated code (e.g., `mark-complete` now generates valid JavaScript)\n- API key authentication (`x-api-key` header) is now handled separately from session tokens (`Bearer` header)\n\n---\n\n## v0.5.9 — February 16, 2026\n\n### CMS Pages & CLI Page Support\n\n- Added `definePage()` support for CMS-managed pages\n- Auth middleware improvements for page routes\n- CLI now supports page definitions alongside table and action definitions\n\n---\n\n## v0.5.8 — February 14, 2026\n\n### CMS App\n\n- Introduced the Quickback CMS — a schema-driven admin panel that connects to your generated API\n- CMS namespace added to actions for admin-specific operations\n- Fixed `guard` → `access` naming inconsistency in CMS action definitions\n\n### Schema Registry & Firewall Improvements\n\n- Added schema registry generator — the compiler now outputs a JSON schema registry used by the CMS\n- Firewall error modes: choose between `reveal` (403 with details) and `hide` (opaque 404) for security-sensitive deployments\n\n### Bug Fixes\n\n- Fixed anonymous user email format generation\n- Organization selector improvements in Account UI\n- Config validation now catches more errors at compile time\n- Better CRUD error handling with structured error responses\n- Fixed masking to use representative star counts instead of fixed formatting\n\n---\n\n## v0.5.7 — February 12, 2026\n\n### Scoped Database for Actions\n\nActions now receive a **security-scoped database** instead of a raw Drizzle instance. The compiler generates a proxy wrapper that automatically enforces org isolation, owner filtering, and soft-delete visibility — the same protections that CRUD routes have always had.\n\nThe scoped DB uses duck-typed column detection at runtime:\n\n| Column Detected | SELECT / UPDATE / DELETE | INSERT |\n|---|---|---|\n| `organizationId` | Adds `WHERE organizationId = ?` | Auto-injects `organizationId` from context |\n| `ownerId` | Adds `WHERE ownerId = ?` | Auto-injects `ownerId` from context |\n| `deletedAt` | Adds `WHERE deletedAt IS NULL` | — |\n\nThis means **every action is secure by default** — no manual `WHERE` clauses needed.\n\n```typescript\ndefineActions(todos, {\n complete: {\n type: \"record\",\n execute: async ({ db, ctx, record, input }) => {\n // db is scoped — only sees records in user's org, excludes soft-deleted\n const siblings = await db.select().from(todos);\n // ↑ automatically filtered to ctx.activeOrgId + deletedAt IS NULL\n },\n },\n});\n```\n\n#### Unsafe Mode\n\nActions that intentionally need to bypass security (admin reports, cross-org queries, migrations) can declare `unsafe: true` to receive a raw, unscoped database handle:\n\n```typescript\ndefineActions(analytics, {\n globalReport: {\n unsafe: true,\n execute: async ({ db, rawDb, ctx, input }) => {\n // db → still scoped (safety net)\n // rawDb → bypasses all security filters\n const allOrgs = await rawDb.select().from(organizations);\n },\n },\n});\n```\n\nWithout `unsafe: true`, `rawDb` is `undefined`.\n\n**Related docs:** [Actions](/compiler/definitions/actions), [Actions API](/compiler/using-the-api/actions-api)\n\n---\n\n### Cascading Soft Delete\n\nSoft-deleting a parent record now **automatically cascades** to child and junction tables within the same feature. The compiler detects foreign key references at build time and generates cascade UPDATE statements.\n\n```\nDELETE /api/v1/projects/:id\n```\n\nGenerated behavior:\n```typescript\n// 1. Soft delete the parent\nawait db.update(projects)\n .set({ deletedAt: now, deletedBy: userId })\n .where(eq(projects.id, id));\n\n// 2. Auto-cascade to children (compiler-generated)\nawait db.update(projectMembers)\n .set({ deletedAt: now, deletedBy: userId })\n .where(eq(projectMembers.projectId, id));\n\nawait db.update(projectTasks)\n .set({ deletedAt: now, deletedBy: userId })\n .where(eq(projectTasks.projectId, id));\n```\n\nRules:\n- Only applies to **soft delete** (the default). Hard delete relies on database-level `ON DELETE CASCADE`.\n- Only cascades within the **same feature** — cross-feature references are not affected.\n- Child tables must have `deletedAt` / `deletedBy` columns (auto-added by the compiler's audit fields).\n\n**Related docs:** [Actions API — Cascading Soft Delete](/compiler/using-the-api/actions-api#cascading-soft-delete)\n\n---\n\n### Advanced Query Parameters\n\nNew query parameter capabilities for all list endpoints:\n\n- **Field selection** — `?fields=id,name,status` returns only the columns you need\n- **Multi-sort** — `?sort=status:asc,createdAt:desc` sorts by multiple fields\n- **Total count** — `?count=true` returns total matching records in response headers (`X-Total-Count`)\n- **Full-text search** — `?search=keyword` searches across all text columns\n\n```bash\n# Get only names and statuses, sorted by status then date, with total count\nGET /api/v1/todos?fields=id,name,status&sort=status:asc,createdAt:desc&count=true\n\n# Search across all text fields\nGET /api/v1/todos?search=urgent\n```\n\n**Related docs:** [Query Parameters](/compiler/using-the-api/query-params)\n\n---\n\n### Audit Field Improvements\n\n- `deletedAt` and `deletedBy` fields are now **always injected** by the compiler for tables with soft delete enabled — no need to define them in your schema\n- All audit fields (`createdAt`, `createdBy`, `modifiedAt`, `modifiedBy`, `deletedAt`, `deletedBy`) are auto-managed\n\n---\n\n## v0.5.6 — February 8, 2026\n\n### Database Naming Conventions\n\n- Default table and column naming changed to **snake_case** with `usePlurals: false`\n- Table names derived from generated Better Auth schema for consistency\n- Removed legacy single-database mode — split databases (auth + features) is now the standard\n\n### Auth Variable Shadowing Fix\n\n- Fixed `member` variable in auth middleware that shadowed the Drizzle `member` table import\n- Renamed to `sessionMember` to avoid conflicts in generated routes\n\n---\n\n## v0.5.5 — February 5, 2026\n\n### Better Auth Plugins\n\n- Published `@kardoe/better-auth-upgrade-anonymous` v1.1.0 — post-passkey email collection flow\n- Published `@kardoe/better-auth-combo-auth` — combined email + password + OTP authentication\n- Published `@kardoe/better-auth-aws-ses` — AWS SES email provider for Better Auth\n\n### OpenAPI Spec Generation\n\n- Generated APIs now include a full OpenAPI specification at `/openapi.json`\n- Better Auth endpoints included in the spec\n- Runtime route: `GET /openapi.json`\n\n### Security Hardening\n\n- Global error handler prevents leaking internal error details\n- Security headers middleware (CSP, HSTS, X-Frame-Options, X-Content-Type-Options)\n- `BETTER_AUTH_SECRET` properly passed to generated config\n\n---\n\n## v0.5.4 — January 30, 2026\n\n### Account UI\n\n- Pre-built authentication UI deployed as Cloudflare Workers\n- Features: sessions, organizations, passkeys, passwordless, admin panel, API keys\n- Dual-mode: standalone (degit template) or embedded with Quickback projects\n\n### Webhook System\n\n- Inbound webhook endpoints with signature verification\n- Outbound webhooks via Cloudflare Queues with automatic retries\n- Configurable per-feature webhook events\n\n### Realtime & Vector Search\n\n- Durable Objects + WebSocket realtime subscriptions\n- Vector embeddings via Cloudflare Vectorize\n- KV and R2 storage integrations\n\n---\n\n## v0.5.0 — January 2026\n\n### Initial Release\n\n- **Quickback Compiler** — TypeScript-first backend compiler\n- **Four Security Pillars** — Firewall, Access, Guards, Masking\n- **`defineTable()`** — Schema + security configuration in a single file\n- **Templates** — Cloudflare Workers, Bun standalone, B2B SaaS\n- **Cloud Compiler** — Remote compilation via `compiler.quickback.dev`\n- **CLI** — `quickback create`, `quickback compile`, `quickback init`\n- **Better Auth Integration** — Organizations, roles, sessions\n- **Drizzle ORM** — Schema-first with automatic migrations\n- **Cloudflare D1** — Split database support (auth + features)"
|
|
70
|
+
"content": "# Changelog\n\nRelease notes for the Quickback compiler, CLI, and platform.\n\n---\n\n## v0.8.1 — April 9, 2026\n\n### Role Hierarchy with `+` Suffix\n\nYou can now define a role hierarchy in your config and use the `+` suffix in access rules to mean \"this role and above\":\n\n```typescript\n// quickback.config.ts\nauth: {\n roleHierarchy: ['member', 'admin', 'owner'],\n}\n\n// In resource definitions\ncrud: {\n list: { access: { roles: [\"member+\"] } }, // member, admin, owner\n create: { access: { roles: [\"admin+\"] } }, // admin, owner\n delete: { access: { roles: [\"owner\"] } }, // owner only\n}\n```\n\nRoles are expanded at compile time. No `+` = exact match. See [Access - Role Hierarchy](/compiler/definitions/access#role-hierarchy) for details.\n\n---\n\n## v0.8.0 — April 9, 2026\n\n### Breaking: VITE URL Environment Variables Renamed\n\nAll Quickback-generated URL environment variables are now namespaced under `VITE_QUICKBACK_*` to avoid collisions with other Vite projects.\n\n| Old | New |\n|-----|-----|\n| `VITE_API_URL` | `VITE_QUICKBACK_API_URL` |\n| `VITE_ACCOUNT_URL` | `VITE_QUICKBACK_ACCOUNT_URL` |\n| `VITE_APP_URL` | `VITE_QUICKBACK_APP_URL` |\n| `VITE_CMS_URL` | `VITE_QUICKBACK_CMS_URL` |\n\n**Non-URL variables are unchanged:** `VITE_ENABLE_*` feature flags, branding vars (`VITE_APP_NAME`, etc.), and `VITE_STRIPE_PUBLISHABLE_KEY` stay as-is.\n\n**Action required:**\n- **Compiled projects** — re-run `quickback compile`. The compiler generates the new names automatically.\n- **Standalone deploys** — update `.env`, `.env.production`, and `wrangler.toml` files manually.\n- **Library users** — the `__QUICKBACK_API_URL__` / `__QUICKBACK_APP_URL__` globalThis names are unchanged, but if you pipe Vite env vars into them, update the var names.\n\nSee [Environment Variables](/account-ui/environment-variables) for the full reference.\n\n### CMS Access Control\n\nThe `cms.access` config option now enforces access at the CMS level, not just link visibility in Account UI.\n\n```typescript\ncms: { access: \"admin\" }\n```\n\nWhen set to `\"admin\"`, non-admin users (`user.role !== \"admin\"`) see an \"Access Denied\" screen with a sign-out button instead of the CMS. When set to `\"user\"` (the default), any authenticated user can access the CMS.\n\nSee [CMS Connecting](/cms/connecting) and [Compiler Config](/compiler/config) for details.\n\n### SPA Sub-Route Fix\n\nFixed a bug where hard-refreshing or directly navigating to SPA sub-routes (e.g., `/account/profile`, `/cms/tables/users`) returned a blank white screen. The Worker now correctly serves `index.html` for all SPA paths, allowing the client-side router to handle routing.\n\n---\n\n## v0.5.11 — February 24, 2026\n\n### Email OTP & Auth Fixes\n\n- Fixed email-OTP magic links not working correctly\n- Removed deprecated `/internal/validate` endpoint — use standard Better Auth session validation instead\n- Auth is now required for all API routes when running locally (previously some routes were unprotected in dev)\n\n### Multiple Table Exports Fix\n\n- Fixed a compiler error when a single file exports multiple Drizzle tables alongside a `defineTable()` default export\n- The CLI now properly detects and reports this with a clear error message pointing to the fix\n\n### Headless Drizzle Rename Hints\n\n- Added `compiler.migrations.renames` configuration for CI/CD environments where Drizzle's interactive rename prompts would block compilation\n- Compile errors now include explicit rename key paths and fail fast on malformed rename config keys\n- See [Configuration](/compiler/config) for details\n\n### Security Contract Report Artifacts\n\n- Added generated security contract artifacts to compiler output:\n - `reports/security-contracts.report.json`\n - `reports/security-contracts.report.sig.json`\n- Added config-driven signing controls:\n - `compiler.securityContracts.report.signature.enabled`\n - `compiler.securityContracts.report.signature.required`\n - `compiler.securityContracts.report.signature.key` / `keyEnv` / `keyId`\n- Missing required signing keys now fail loudly with explicit remediation guidance\n- Added strict config validation for report/signature paths and signing options\n\n### Mandatory Unsafe Action Audit Trail\n\n- Added structured unsafe action config (`unsafe: { reason, adminOnly, crossTenant, targetScope }`)\n- Cross-tenant unsafe actions now require Better Auth authentication plus platform admin role (`ctx.userRole === \"admin\"`)\n- Added mandatory audit logging for unsafe cross-tenant actions (success, denial, and error paths)\n- Cloudflare output now includes optional `AUDIT_DB` wiring, `drizzle.audit.config.ts`, and `db:migrate:audit:*` scripts when unsafe actions are present\n- Added compile-time raw SQL guard for actions and handlers (`allowRawSql: true` required per action)\n\n---\n\n## v0.5.10 — February 19, 2026\n\n### Compiler Page Parsing & CLI Output\n\n- Improved compiler page parsing for `definePage()` definitions\n- Better CLI output formatting during compilation\n- Added `apiPath` to schema registry for CMS integration\n\n### Bug Fixes\n\n- Fixed hyphenated action names not being properly quoted in generated code (e.g., `mark-complete` now generates valid JavaScript)\n- API key authentication (`x-api-key` header) is now handled separately from session tokens (`Bearer` header)\n\n---\n\n## v0.5.9 — February 16, 2026\n\n### CMS Pages & CLI Page Support\n\n- Added `definePage()` support for CMS-managed pages\n- Auth middleware improvements for page routes\n- CLI now supports page definitions alongside table and action definitions\n\n---\n\n## v0.5.8 — February 14, 2026\n\n### CMS App\n\n- Introduced the Quickback CMS — a schema-driven admin panel that connects to your generated API\n- CMS namespace added to actions for admin-specific operations\n- Fixed `guard` → `access` naming inconsistency in CMS action definitions\n\n### Schema Registry & Firewall Improvements\n\n- Added schema registry generator — the compiler now outputs a JSON schema registry used by the CMS\n- Firewall error modes: choose between `reveal` (403 with details) and `hide` (opaque 404) for security-sensitive deployments\n\n### Bug Fixes\n\n- Fixed anonymous user email format generation\n- Organization selector improvements in Account UI\n- Config validation now catches more errors at compile time\n- Better CRUD error handling with structured error responses\n- Fixed masking to use representative star counts instead of fixed formatting\n\n---\n\n## v0.5.7 — February 12, 2026\n\n### Scoped Database for Actions\n\nActions now receive a **security-scoped database** instead of a raw Drizzle instance. The compiler generates a proxy wrapper that automatically enforces org isolation, owner filtering, and soft-delete visibility — the same protections that CRUD routes have always had.\n\nThe scoped DB uses duck-typed column detection at runtime:\n\n| Column Detected | SELECT / UPDATE / DELETE | INSERT |\n|---|---|---|\n| `organizationId` | Adds `WHERE organizationId = ?` | Auto-injects `organizationId` from context |\n| `ownerId` | Adds `WHERE ownerId = ?` | Auto-injects `ownerId` from context |\n| `deletedAt` | Adds `WHERE deletedAt IS NULL` | — |\n\nThis means **every action is secure by default** — no manual `WHERE` clauses needed.\n\n```typescript\ndefineActions(todos, {\n complete: {\n type: \"record\",\n execute: async ({ db, ctx, record, input }) => {\n // db is scoped — only sees records in user's org, excludes soft-deleted\n const siblings = await db.select().from(todos);\n // ↑ automatically filtered to ctx.activeOrgId + deletedAt IS NULL\n },\n },\n});\n```\n\n#### Unsafe Mode\n\nActions that intentionally need to bypass security (admin reports, cross-org queries, migrations) can declare `unsafe: true` to receive a raw, unscoped database handle:\n\n```typescript\ndefineActions(analytics, {\n globalReport: {\n unsafe: true,\n execute: async ({ db, rawDb, ctx, input }) => {\n // db → still scoped (safety net)\n // rawDb → bypasses all security filters\n const allOrgs = await rawDb.select().from(organizations);\n },\n },\n});\n```\n\nWithout `unsafe: true`, `rawDb` is `undefined`.\n\n**Related docs:** [Actions](/compiler/definitions/actions), [Actions API](/compiler/using-the-api/actions-api)\n\n---\n\n### Cascading Soft Delete\n\nSoft-deleting a parent record now **automatically cascades** to child and junction tables within the same feature. The compiler detects foreign key references at build time and generates cascade UPDATE statements.\n\n```\nDELETE /api/v1/projects/:id\n```\n\nGenerated behavior:\n```typescript\n// 1. Soft delete the parent\nawait db.update(projects)\n .set({ deletedAt: now, deletedBy: userId })\n .where(eq(projects.id, id));\n\n// 2. Auto-cascade to children (compiler-generated)\nawait db.update(projectMembers)\n .set({ deletedAt: now, deletedBy: userId })\n .where(eq(projectMembers.projectId, id));\n\nawait db.update(projectTasks)\n .set({ deletedAt: now, deletedBy: userId })\n .where(eq(projectTasks.projectId, id));\n```\n\nRules:\n- Only applies to **soft delete** (the default). Hard delete relies on database-level `ON DELETE CASCADE`.\n- Only cascades within the **same feature** — cross-feature references are not affected.\n- Child tables must have `deletedAt` / `deletedBy` columns (auto-added by the compiler's audit fields).\n\n**Related docs:** [Actions API — Cascading Soft Delete](/compiler/using-the-api/actions-api#cascading-soft-delete)\n\n---\n\n### Advanced Query Parameters\n\nNew query parameter capabilities for all list endpoints:\n\n- **Field selection** — `?fields=id,name,status` returns only the columns you need\n- **Multi-sort** — `?sort=status:asc,createdAt:desc` sorts by multiple fields\n- **Total count** — `?count=true` returns total matching records in response headers (`X-Total-Count`)\n- **Full-text search** — `?search=keyword` searches across all text columns\n\n```bash\n# Get only names and statuses, sorted by status then date, with total count\nGET /api/v1/todos?fields=id,name,status&sort=status:asc,createdAt:desc&count=true\n\n# Search across all text fields\nGET /api/v1/todos?search=urgent\n```\n\n**Related docs:** [Query Parameters](/compiler/using-the-api/query-params)\n\n---\n\n### Audit Field Improvements\n\n- `deletedAt` and `deletedBy` fields are now **always injected** by the compiler for tables with soft delete enabled — no need to define them in your schema\n- All audit fields (`createdAt`, `createdBy`, `modifiedAt`, `modifiedBy`, `deletedAt`, `deletedBy`) are auto-managed\n\n---\n\n## v0.5.6 — February 8, 2026\n\n### Database Naming Conventions\n\n- Default table and column naming changed to **snake_case** with `usePlurals: false`\n- Table names derived from generated Better Auth schema for consistency\n- Removed legacy single-database mode — split databases (auth + features) is now the standard\n\n### Auth Variable Shadowing Fix\n\n- Fixed `member` variable in auth middleware that shadowed the Drizzle `member` table import\n- Renamed to `sessionMember` to avoid conflicts in generated routes\n\n---\n\n## v0.5.5 — February 5, 2026\n\n### Better Auth Plugins\n\n- Published `@kardoe/better-auth-upgrade-anonymous` v1.1.0 — post-passkey email collection flow\n- Published `@kardoe/better-auth-combo-auth` — combined email + password + OTP authentication\n- Published `@kardoe/better-auth-aws-ses` — AWS SES email provider for Better Auth\n\n### OpenAPI Spec Generation\n\n- Generated APIs now include a full OpenAPI specification at `/openapi.json`\n- Better Auth endpoints included in the spec\n- Runtime route: `GET /openapi.json`\n\n### Security Hardening\n\n- Global error handler prevents leaking internal error details\n- Security headers middleware (CSP, HSTS, X-Frame-Options, X-Content-Type-Options)\n- `BETTER_AUTH_SECRET` properly passed to generated config\n\n---\n\n## v0.5.4 — January 30, 2026\n\n### Account UI\n\n- Pre-built authentication UI deployed as Cloudflare Workers\n- Features: sessions, organizations, passkeys, passwordless, admin panel, API keys\n- Dual-mode: standalone (degit template) or embedded with Quickback projects\n\n### Webhook System\n\n- Inbound webhook endpoints with signature verification\n- Outbound webhooks via Cloudflare Queues with automatic retries\n- Configurable per-feature webhook events\n\n### Realtime & Vector Search\n\n- Durable Objects + WebSocket realtime subscriptions\n- Vector embeddings via Cloudflare Vectorize\n- KV and R2 storage integrations\n\n---\n\n## v0.5.0 — January 2026\n\n### Initial Release\n\n- **Quickback Compiler** — TypeScript-first backend compiler\n- **Four Security Pillars** — Firewall, Access, Guards, Masking\n- **`defineTable()`** — Schema + security configuration in a single file\n- **Templates** — Cloudflare Workers, Bun standalone, B2B SaaS\n- **Cloud Compiler** — Remote compilation via `compiler.quickback.dev`\n- **CLI** — `quickback create`, `quickback compile`, `quickback init`\n- **Better Auth Integration** — Organizations, roles, sessions\n- **Drizzle ORM** — Schema-first with automatic migrations\n- **Cloudflare D1** — Split database support (auth + features)"
|
|
71
71
|
},
|
|
72
72
|
"cms/actions": {
|
|
73
73
|
"title": "Actions",
|
|
@@ -79,7 +79,7 @@ export const DOCS = {
|
|
|
79
79
|
},
|
|
80
80
|
"cms/connecting": {
|
|
81
81
|
"title": "Connecting",
|
|
82
|
-
"content": "# Connecting\n\nThe CMS supports two modes: **demo mode** for development and testing, and **live mode** for connecting to a real Quickback API.\n\n## Demo Mode\n\nWhen no `
|
|
82
|
+
"content": "# Connecting\n\nThe CMS supports two modes: **demo mode** for development and testing, and **live mode** for connecting to a real Quickback API.\n\n## Demo Mode\n\nWhen no `VITE_QUICKBACK_API_URL` is set, the CMS runs in demo mode:\n\n- Uses a **mock API client** backed by `localStorage`\n- Loads seed data from JSON files in `data/mock/`\n- Provides a **role switcher** in the header to test owner/admin/member access\n- Simulates authentication sessions without a real backend\n\nDemo mode is useful for prototyping your schema, testing guard behavior across roles, and verifying masking rules before deploying.\n\n```bash title=\".env.development\"\n# No VITE_QUICKBACK_API_URL — CMS runs in demo mode\n```\n\n### Mock Data\n\nPlace JSON files in `data/mock/` matching your table names:\n\n```\ndata/mock/\n contact.json # Array of contact records\n project.json # Array of project records\n invoice.json # Array of invoice records\n _meta.json # Mock session and org metadata\n```\n\nEach file contains an array of records. The mock client loads them on startup and persists changes to `localStorage`.\n\n### Role Switcher\n\nIn demo mode, the header displays a role switcher dropdown allowing you to switch between `owner`, `admin`, and `member` roles in real time. This lets you verify:\n\n- Which CRUD buttons appear per role\n- Which form fields are editable\n- Which masking rules apply\n- Which actions are available\n- Which views are accessible\n\n## Live Mode\n\nSet `VITE_QUICKBACK_API_URL` to connect to a real Quickback API:\n\n```bash title=\".env.production\"\nVITE_QUICKBACK_API_URL=https://api.example.com\n```\n\nIn live mode, the CMS:\n\n- Reads the **Better Auth session** from cookies\n- Fetches the user's **organization membership** and role\n- Makes real API calls to the Quickback backend for all CRUD operations\n- Applies server-side security (firewall, guards, masking) in addition to client-side UI filtering\n\n## API Client Interface\n\nThe CMS communicates with the backend through a standard interface:\n\n```typescript\ninterface IApiClient {\n list(table: string, params?: ListParams): Promise\n\n## How the Client is Created\n\nThe CMS auto-creates the API client based on configuration:\n\n1. **No `VITE_QUICKBACK_API_URL`** — Instantiates the mock client, loads seed data from `data/mock/`, and uses `localStorage` for persistence.\n2. **`VITE_QUICKBACK_API_URL` is set** — Instantiates the live client, reads the auth session cookie, and makes fetch requests to the Quickback API using the standard REST endpoints (`/api/v1/{table}`).\n\nThe client is provided via React context (`ApiClientContext`) and available throughout the component tree.\n\n## Embedded Mode (Recommended)\n\nSet `cms: true` in your config to embed the CMS directly in your compiled Worker:\n\n```typescript title=\"quickback/quickback.config.ts\"\nexport default defineConfig({\n name: \"my-app\",\n cms: true,\n // ...providers\n});\n```\n\nWhen you run `quickback compile`, the CLI:\n1. Builds the CMS SPA from source and places assets in `src/apps/cms/`\n2. Adds `[assets]` config to `wrangler.toml` with `run_worker_first = true`\n3. Generates Worker routing to serve the CMS SPA\n\nRun `wrangler dev` and the CMS is served at `/cms/`. API routes (`/api/*`, `/auth/*`, etc.) pass through to your Hono app. Same origin — no CORS, auth cookies work naturally. On a custom domain, the CMS is served at root (`/`).\n\n### Custom CMS Domain\n\nOptionally serve the CMS on a separate subdomain:\n\n```typescript\ncms: { domain: \"cms.example.com\" }\n```\n\nThis adds a custom domain route to `wrangler.toml`. Both `api.example.com` and `cms.example.com` point to the same Worker. The compiler auto-configures hostname-based routing and cross-subdomain cookies.\n\nYou can also restrict CMS access to admin users only:\n\n```typescript\ncms: { domain: \"cms.example.com\", access: \"admin\" }\n```\n\nWhen `access: \"admin\"` is set, non-admin users see an \"Access Denied\" screen instead of the CMS. The CMS link in Account UI is also hidden for non-admin users.\n\nSee [Multi-Domain Architecture](/compiler/config/domains) for details on multi-domain routing.\n\n## Multi-Tenant vs Single-Tenant\n\nThe CMS supports two authentication modes depending on your project's organization configuration.\n\n### Multi-Tenant (Default)\n\nIn multi-tenant mode, the CMS gates access behind organization membership:\n\n1. User logs in via Better Auth session\n2. CMS fetches the user's organization memberships\n3. If the user belongs to multiple organizations, an **org selector** is displayed\n4. Once an org is selected, the user's role within that org determines their CMS permissions\n\nThis is the default behavior for all Quickback projects.\n\n### Single-Tenant Mode\n\nWhen your project disables organizations (`features.organizations: false` in config), the compiler sets `singleTenant: true` in the schema registry. In this mode:\n\n- No org gate or org selector is shown\n- The user's role is read directly from `user.role` on the session\n- All data is unscoped (no `organizationId` filtering)\n\nSingle-tenant mode is useful for internal tools, personal projects, or apps that don't need multi-org isolation.\n\n## Next Steps\n\n- **[Table Views](/cms/table-views)** — Browse and Data Table view modes\n- **[Security](/cms/security)** — How roles, guards, and masking work in the CMS"
|
|
83
83
|
},
|
|
84
84
|
"cms/dashboard": {
|
|
85
85
|
"title": "Dashboard",
|
|
@@ -135,7 +135,7 @@ export const DOCS = {
|
|
|
135
135
|
},
|
|
136
136
|
"compiler/cloud-compiler/local-compiler": {
|
|
137
137
|
"title": "Local Compiler",
|
|
138
|
-
"content": "Run the Quickback compiler locally using Docker. The local compiler uses the exact same Docker image as the cloud compiler, ensuring identical behavior — including SPA builds with correct environment variables.\n\n## Prerequisites\n\n- Docker Desktop installed and running\n- Quickback monorepo cloned locally\n- Authenticated via `quickback login`\n\n## Quick Start\n\nFrom the monorepo root:\n\n```bash\ncd apps/compiler-local && bash dev.sh\n```\n\nThis will:\n1. Ensure Docker Desktop is running\n2. Stop any existing compiler container\n3. Build the Docker image from `apps/compiler/Dockerfile`\n4. Run it on port 3000\n\n### Custom Port\n\n```bash\nbash dev.sh 3001\n```\n\n## Compiling a Project\n\nPoint the CLI to your local compiler:\n\n```bash\nQUICKBACK_API_URL=http://localhost:3000 quickback compile\n```\n\nOr export it for the session:\n\n```bash\nexport QUICKBACK_API_URL=http://localhost:3000\nquickback compile\n```\n\nAuthentication is always required. Run `quickback login` first if you haven't already.\n\n## Manual Build & Run\n\nYou can also build and run the Docker image directly from the monorepo root:\n\n```bash\n# Build\ndocker build -t quickback-compiler -f apps/compiler/Dockerfile .\n\n# Run\ndocker run --rm -p 3000:3000 quickback-compiler\n```\n\n## Verify\n\nCheck the compiler is running:\n\n```bash\ncurl http://localhost:3000/health\n```\n\n## How It Works\n\nThe Docker image includes:\n- Pre-installed dependencies for compiled projects (`/deps/node_modules`)\n- CMS and Account SPA source code (`/spa/cms/`, `/spa/account/`)\n- Pre-installed SPA dependencies (`/spa-deps/cms/`, `/spa-deps/account/`)\n\nWhen compiling a project with `cms: true` or `account: true`, the compiler builds the SPAs from source inside the container with the correct Vite environment variables (e.g., `
|
|
138
|
+
"content": "Run the Quickback compiler locally using Docker. The local compiler uses the exact same Docker image as the cloud compiler, ensuring identical behavior — including SPA builds with correct environment variables.\n\n## Prerequisites\n\n- Docker Desktop installed and running\n- Quickback monorepo cloned locally\n- Authenticated via `quickback login`\n\n## Quick Start\n\nFrom the monorepo root:\n\n```bash\ncd apps/compiler-local && bash dev.sh\n```\n\nThis will:\n1. Ensure Docker Desktop is running\n2. Stop any existing compiler container\n3. Build the Docker image from `apps/compiler/Dockerfile`\n4. Run it on port 3000\n\n### Custom Port\n\n```bash\nbash dev.sh 3001\n```\n\n## Compiling a Project\n\nPoint the CLI to your local compiler:\n\n```bash\nQUICKBACK_API_URL=http://localhost:3000 quickback compile\n```\n\nOr export it for the session:\n\n```bash\nexport QUICKBACK_API_URL=http://localhost:3000\nquickback compile\n```\n\nAuthentication is always required. Run `quickback login` first if you haven't already.\n\n## Manual Build & Run\n\nYou can also build and run the Docker image directly from the monorepo root:\n\n```bash\n# Build\ndocker build -t quickback-compiler -f apps/compiler/Dockerfile .\n\n# Run\ndocker run --rm -p 3000:3000 quickback-compiler\n```\n\n## Verify\n\nCheck the compiler is running:\n\n```bash\ncurl http://localhost:3000/health\n```\n\n## How It Works\n\nThe Docker image includes:\n- Pre-installed dependencies for compiled projects (`/deps/node_modules`)\n- CMS and Account SPA source code (`/spa/cms/`, `/spa/account/`)\n- Pre-installed SPA dependencies (`/spa-deps/cms/`, `/spa-deps/account/`)\n\nWhen compiling a project with `cms: true` or `account: true`, the compiler builds the SPAs from source inside the container with the correct Vite environment variables (e.g., `VITE_QUICKBACK_API_URL`, `VITE_QUICKBACK_ACCOUNT_URL`). This ensures each project gets properly configured SPA assets without manual intervention.\n\n## Deploying to Cloud\n\nAfter making changes to the compiler, deploy to `compiler.quickback.dev`:\n\n```bash\ncd apps/compiler-cloud && bash deploy.sh\n```\n\n## Troubleshooting\n\n### Container not starting\n\n```bash\ndocker logs quickback-compiler-local\n```\n\n### Port already in use\n\n```bash\n# Find what's using the port\nlsof -i :3000\n\n# Use a different port\nbash dev.sh 3001\n```\n\n### Docker out of disk space\n\n```bash\ndocker system prune -af\n```\n\n### SPA build warnings\n\nIf you see SPA build warnings during compilation, ensure the SPA dependency files are up to date:\n- `apps/compiler/deps-spa-cms-package.json`\n- `apps/compiler/deps-spa-account-package.json`\n\nThese must include all dependencies from `packages/cms/package.json` and `packages/account/package.json` respectively."
|
|
139
139
|
},
|
|
140
140
|
"compiler/cloud-compiler/troubleshooting": {
|
|
141
141
|
"title": "Troubleshooting",
|
|
@@ -147,7 +147,7 @@ export const DOCS = {
|
|
|
147
147
|
},
|
|
148
148
|
"compiler/config": {
|
|
149
149
|
"title": "Configuration",
|
|
150
|
-
"content": "The `quickback.config.ts` file configures your Quickback project. It defines which providers to use, which features to enable, and how the compiler generates code.\n\n```typescript\n\nexport default defineConfig({\n name: \"my-app\",\n template: \"hono\",\n features: { organizations: true },\n providers: {\n runtime: defineRuntime(\"cloudflare\"),\n database: defineDatabase(\"cloudflare-d1\"),\n auth: defineAuth(\"better-auth\"),\n },\n});\n```\n\n## Required Fields\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `name` | `string` | Project name |\n| `template` | `\"hono\"` | Application template (`\"nextjs\"` is experimental) |\n| `providers` | `object` | Runtime, database, and auth provider configuration |\n\n## Optional Fields\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `features` | `object` | Feature flags — see [Single-Tenant Mode](/compiler/config/single-tenant) |\n| `build` | `object` | Build options (`outputDir`, `packageManager`, `dependencies`) |\n| `compiler` | `object` | Compiler options (including migration rename hints for headless CI) |\n| `openapi` | `object` | OpenAPI spec generation (`generate`, `publish`) — see [OpenAPI](/compiler/using-the-api/openapi) |\n| `schemaRegistry` | `object` | Schema registry generation for the CMS (enabled by default, `{ generate: false }` to disable) — see [Schema Registry](/cms/schema-registry) |\n| `etag` | `object` | ETag caching for GET responses (enabled by default, `{ enabled: false }` to disable) — see [Caching & ETags](/compiler/using-the-api/caching) |\n| `cms` | `boolean \\| object` | Embed CMS in compiled Worker — see [CMS](/cms) |\n| `account` | `boolean \\| object` | Embed Account UI in compiled Worker — see [Account UI](/account-ui) |\n| `trustedOrigins` | `string[]` | CORS trusted origins for cross-domain auth |\n| `domain` | `string` | Primary API domain (auto-inferred from custom domains if not set) |\n| `email` | `object` | Email delivery config (`provider`, `from`, `fromName`) |\n\n## Custom Dependencies\n\nAdd third-party npm packages to the generated `package.json` using `build.dependencies`. This is useful when your action handlers import external libraries.\n\n```typescript\nexport default defineConfig({\n name: \"my-app\",\n template: \"hono\",\n build: {\n dependencies: {\n \"fast-xml-parser\": \"^4.5.0\",\n \"lodash-es\": \"^4.17.21\",\n },\n },\n providers: {\n runtime: defineRuntime(\"cloudflare\"),\n database: defineDatabase(\"cloudflare-d1\"),\n auth: defineAuth(\"better-auth\"),\n },\n});\n```\n\nThese are merged into the generated `package.json` alongside Quickback's own dependencies. Run `npm install` after compiling to install them.\n\n## Headless Migration Rename Hints\n\nWhen `drizzle-kit generate` detects a potential rename, it normally prompts for confirmation. Cloud/CI compiles are non-interactive, so you must provide explicit rename hints.\n\nAdd hints in `compiler.migrations.renames`:\n\n```typescript\nexport default defineConfig({\n // ...\n compiler: {\n migrations: {\n renames: {\n // Keys are NEW names, values are OLD names\n tables: {\n events_v2: \"events\",\n },\n columns: {\n events: {\n summary_text: \"summary\",\n },\n },\n },\n },\n },\n});\n```\n\nRules:\n- `tables`: `new_table_name -> old_table_name`\n- `columns.<table>`: `new_column_name -> old_column_name`\n- Keys must match the names in your current schema (the new names)\n- Validation fails fast for malformed rename config, unsupported keys, or conflicting legacy/new rename paths.\n\n## Security Contract Reports and Signing\n\nAfter generation, Quickback verifies machine-checkable security contracts for Hono routes and RLS SQL.\n\nIt also emits a report artifact and signature artifact by default:\n\n- `reports/security-contracts.report.json`\n- `reports/security-contracts.report.sig.json`\n\nYou can configure output paths and signing behavior:\n\n```typescript\nexport default defineConfig({\n // ...\n compiler: {\n securityContracts: {\n failMode: \"error\", // or \"warn\"\n report: {\n path: \"reports/security-contracts.report.json\",\n signature: {\n enabled: true,\n required: true,\n keyEnv: \"QUICKBACK_SECURITY_REPORT_SIGNING_KEY\",\n keyId: \"prod-k1\",\n path: \"reports/security-contracts.report.sig.json\",\n },\n },\n },\n },\n});\n```\n\nIf `signature.required: true` and no key is available, compilation fails with a clear error message (or warning in `failMode: \"warn\"`).\n\n## CMS Configuration\n\nEmbed the [Quickback CMS](/cms) in your compiled Worker. The CMS reads your schema registry and renders a complete admin interface — zero UI code per table.\n\n```typescript\n// Simple — embed CMS at root\ncms: true,\n\n// With custom domain\ncms: { domain: \"cms.example.com\" },\n\n// With access control (only admins see CMS link in Account UI)\ncms: { domain: \"cms.example.com\", access: \"admin\" },\n```\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `domain` | `string` | — | Custom domain for CMS. Adds a `custom_domain` route to `wrangler.toml`. |\n| `access` | `\"user\" \\| \"admin\"` | `\"user\"` | Who can see the \"Go to CMS\" button in Account UI. Set to `\"admin\"` to restrict the link to admin users only. |\n\n## Account UI Configuration\n\nEmbed the [Account UI](/account-ui) in your compiled Worker. Provides login, signup, profile management, organization management, and admin — all built from your config at compile time.\n\n```typescript\n// Simple — embed Account UI with defaults\naccount: true,\n\n// Full configuration\naccount: {\n domain: \"auth.example.com\",\n adminDomain: \"admin.example.com\",\n name: \"My App\",\n companyName: \"My Company\",\n auth: {\n password: true,\n emailOTP: false,\n passkey: true,\n organizations: true,\n admin: true,\n },\n},\n```\n\n| Option | Type | Description |\n|--------|------|-------------|\n| `domain` | `string` | Custom domain for Account UI (e.g., `auth.example.com`) |\n| `adminDomain` | `string` | Custom domain for admin-only access (e.g., `admin.example.com`). Serves the same Account SPA — the client-side router handles admin routing. |\n| `name` | `string` | App display name shown on login, profile, and email templates |\n| `companyName` | `string` | Company name for branding |\n| `tagline` | `string` | App tagline shown on login page |\n| `description` | `string` | App description |\n\n### Auth Feature Flags\n\nControl which authentication features are included in the Account UI bundle. Disabled features are excluded at compile time — their routes are removed before the Vite build, keeping bundle sizes minimal.\n\n| Flag | Type | Default | Description |\n|------|------|---------|-------------|\n| `auth.password` | `boolean` | `true` | Email/password authentication |\n| `auth.emailOTP` | `boolean` | `false` | Email one-time password login |\n| `auth.passkey` | `boolean` | `false` | WebAuthn/FIDO2 passkey authentication |\n| `auth.signup` | `boolean` | `true` | Self-service account registration |\n| `auth.organizations` | `boolean` | `false` | Multi-tenant organization management (dashboard, invitations, roles) |\n| `auth.admin` | `boolean` | `false` | Admin panel for user management (requires Better Auth admin plugin) |\n| `auth.emailVerification` | `boolean` | `false` | Require email verification after signup |\n\n## Trusted Origins\n\nList of origins allowed to make cross-origin requests to your API. Required when your CMS, Account UI, or frontend app run on different domains.\n\n```typescript\ntrustedOrigins: [\n \"https://auth.example.com\",\n \"https://admin.example.com\",\n \"https://cms.example.com\",\n \"https://app.example.com\",\n],\n```\n\n## Email Configuration\n\nConfigure email delivery for authentication emails (verification, password reset, invitations).\n\n```typescript\n// Cloudflare Email Service (default) — uses send_email binding, no API keys needed\nemail: {\n from: \"noreply@example.com\",\n fromName: \"My App\",\n},\n\n// AWS SES — requires AWS credentials set as Wrangler secrets\nemail: {\n provider: \"aws-ses\",\n region: \"us-east-2\",\n from: \"noreply@example.com\",\n fromName: \"My App\",\n},\n```\n\n| Field | Type | Default | Description |\n|-------|------|---------|-------------|\n| `provider` | `\"cloudflare\" \\| \"aws-ses\"` | `\"cloudflare\"` | Email transport |\n| `from` | `string` | `\"noreply@example.com\"` | Sender email address |\n| `fromName` | `string` | `\"{name} \\| Account Services\"` | Sender display name |\n| `region` | `string` | `\"us-east-2\"` | AWS SES region (aws-ses only) |\n\n## Multi-Domain Example\n\nA complete config with CMS, Account UI, and Admin on separate subdomains:\n\n```typescript\nexport default {\n name: \"my-app\",\n template: \"hono\",\n cms: { domain: \"cms.example.com\", access: \"admin\" },\n account: {\n domain: \"auth.example.com\",\n adminDomain: \"admin.example.com\",\n name: \"My App\",\n companyName: \"Example Inc.\",\n auth: {\n password: true,\n emailOTP: false,\n passkey: true,\n organizations: false,\n admin: true,\n },\n },\n email: {\n from: \"noreply@example.com\",\n fromName: \"My App\",\n },\n trustedOrigins: [\n \"https://auth.example.com\",\n \"https://admin.example.com\",\n \"https://cms.example.com\",\n \"https://example.com\",\n ],\n providers: {\n runtime: { name: \"cloudflare\", config: {\n routes: [{ pattern: \"api.example.com\", custom_domain: true }],\n }},\n database: { name: \"cloudflare-d1\", config: { binding: \"DB\" } },\n auth: { name: \"better-auth\", config: { plugins: [\"admin\"] } },\n },\n};\n```\n\nThis produces a single Cloudflare Worker serving five domains. See [Multi-Domain Architecture](/compiler/config/domains) for details on hostname routing, cross-subdomain cookies, and the unified fallback domain.\n\n---\n\nSee the sub-pages for detailed reference on each section:\n- [Providers](/compiler/config/providers) — Runtime, database, and auth options\n- [Variables](/compiler/config/variables) — Environment variables and flags\n- [Output](/compiler/config/output) — Generated file structure\n- [Single-Tenant Mode](/compiler/config/single-tenant) — Admin-only and public-facing apps without organizations\n- [Multi-Domain Architecture](/compiler/config/domains) — Custom domains, hostname routing, and cross-subdomain auth"
|
|
150
|
+
"content": "The `quickback.config.ts` file configures your Quickback project. It defines which providers to use, which features to enable, and how the compiler generates code.\n\n```typescript\n\nexport default defineConfig({\n name: \"my-app\",\n template: \"hono\",\n features: { organizations: true },\n providers: {\n runtime: defineRuntime(\"cloudflare\"),\n database: defineDatabase(\"cloudflare-d1\"),\n auth: defineAuth(\"better-auth\"),\n },\n});\n```\n\n## Required Fields\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `name` | `string` | Project name |\n| `template` | `\"hono\"` | Application template (`\"nextjs\"` is experimental) |\n| `providers` | `object` | Runtime, database, and auth provider configuration |\n\n## Optional Fields\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `features` | `object` | Feature flags — see [Single-Tenant Mode](/compiler/config/single-tenant) |\n| `build` | `object` | Build options (`outputDir`, `packageManager`, `dependencies`) |\n| `compiler` | `object` | Compiler options (including migration rename hints for headless CI) |\n| `openapi` | `object` | OpenAPI spec generation (`generate`, `publish`) — see [OpenAPI](/compiler/using-the-api/openapi) |\n| `schemaRegistry` | `object` | Schema registry generation for the CMS (enabled by default, `{ generate: false }` to disable) — see [Schema Registry](/cms/schema-registry) |\n| `etag` | `object` | ETag caching for GET responses (enabled by default, `{ enabled: false }` to disable) — see [Caching & ETags](/compiler/using-the-api/caching) |\n| `cms` | `boolean \\| object` | Embed CMS in compiled Worker — see [CMS](/cms) |\n| `account` | `boolean \\| object` | Embed Account UI in compiled Worker — see [Account UI](/account-ui) |\n| `trustedOrigins` | `string[]` | CORS trusted origins for cross-domain auth |\n| `domain` | `string` | Primary API domain (auto-inferred from custom domains if not set) |\n| `dev` | `object` | Local development settings (`port`) |\n| `auth` | `object` | App-level auth settings (`roleHierarchy`) — see [Access](/compiler/definitions/access#role-hierarchy) |\n| `email` | `object` | Email delivery config (`provider`, `from`, `fromName`) |\n\n## Custom Dependencies\n\nAdd third-party npm packages to the generated `package.json` using `build.dependencies`. This is useful when your action handlers import external libraries.\n\n```typescript\nexport default defineConfig({\n name: \"my-app\",\n template: \"hono\",\n build: {\n dependencies: {\n \"fast-xml-parser\": \"^4.5.0\",\n \"lodash-es\": \"^4.17.21\",\n },\n },\n providers: {\n runtime: defineRuntime(\"cloudflare\"),\n database: defineDatabase(\"cloudflare-d1\"),\n auth: defineAuth(\"better-auth\"),\n },\n});\n```\n\nThese are merged into the generated `package.json` alongside Quickback's own dependencies. Run `npm install` after compiling to install them.\n\n## Headless Migration Rename Hints\n\nWhen `drizzle-kit generate` detects a potential rename, it normally prompts for confirmation. Cloud/CI compiles are non-interactive, so you must provide explicit rename hints.\n\nAdd hints in `compiler.migrations.renames`:\n\n```typescript\nexport default defineConfig({\n // ...\n compiler: {\n migrations: {\n renames: {\n // Keys are NEW names, values are OLD names\n tables: {\n events_v2: \"events\",\n },\n columns: {\n events: {\n summary_text: \"summary\",\n },\n },\n },\n },\n },\n});\n```\n\nRules:\n- `tables`: `new_table_name -> old_table_name`\n- `columns.<table>`: `new_column_name -> old_column_name`\n- Keys must match the names in your current schema (the new names)\n- Validation fails fast for malformed rename config, unsupported keys, or conflicting legacy/new rename paths.\n\n## Security Contract Reports and Signing\n\nAfter generation, Quickback verifies machine-checkable security contracts for Hono routes and RLS SQL.\n\nIt also emits a report artifact and signature artifact by default:\n\n- `reports/security-contracts.report.json`\n- `reports/security-contracts.report.sig.json`\n\nYou can configure output paths and signing behavior:\n\n```typescript\nexport default defineConfig({\n // ...\n compiler: {\n securityContracts: {\n failMode: \"error\", // or \"warn\"\n report: {\n path: \"reports/security-contracts.report.json\",\n signature: {\n enabled: true,\n required: true,\n keyEnv: \"QUICKBACK_SECURITY_REPORT_SIGNING_KEY\",\n keyId: \"prod-k1\",\n path: \"reports/security-contracts.report.sig.json\",\n },\n },\n },\n },\n});\n```\n\nIf `signature.required: true` and no key is available, compilation fails with a clear error message (or warning in `failMode: \"warn\"`).\n\n## CMS Configuration\n\nEmbed the [Quickback CMS](/cms) in your compiled Worker. The CMS reads your schema registry and renders a complete admin interface — zero UI code per table.\n\n```typescript\n// Simple — embed CMS at root\ncms: true,\n\n// With custom domain\ncms: { domain: \"cms.example.com\" },\n\n// With access control (only admins can access CMS)\ncms: { domain: \"cms.example.com\", access: \"admin\" },\n```\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `domain` | `string` | — | Custom domain for CMS. Adds a `custom_domain` route to `wrangler.toml`. |\n| `access` | `\"user\" \\| \"admin\"` | `\"user\"` | Controls who can access the CMS. When `\"admin\"`, only users with `user.role === \"admin\"` can enter — non-admins see an \"Access Denied\" screen. Also hides the CMS link in Account UI for non-admin users. |\n\n## Account UI Configuration\n\nEmbed the [Account UI](/account-ui) in your compiled Worker. Provides login, signup, profile management, organization management, and admin — all built from your config at compile time.\n\n```typescript\n// Simple — embed Account UI with defaults\naccount: true,\n\n// Full configuration\naccount: {\n domain: \"auth.example.com\",\n adminDomain: \"admin.example.com\",\n name: \"My App\",\n companyName: \"My Company\",\n auth: {\n password: true,\n emailOTP: false,\n passkey: true,\n organizations: true,\n admin: true,\n },\n},\n```\n\n| Option | Type | Description |\n|--------|------|-------------|\n| `domain` | `string` | Custom domain for Account UI (e.g., `auth.example.com`) |\n| `adminDomain` | `string` | Custom domain for admin-only access (e.g., `admin.example.com`). Serves the same Account SPA — the client-side router handles admin routing. |\n| `name` | `string` | App display name shown on login, profile, and email templates |\n| `companyName` | `string` | Company name for branding |\n| `tagline` | `string` | App tagline shown on login page |\n| `description` | `string` | App description |\n\n### Auth Feature Flags\n\nControl which authentication features are included in the Account UI bundle. Disabled features are excluded at compile time — their routes are removed before the Vite build, keeping bundle sizes minimal.\n\n| Flag | Type | Default | Description |\n|------|------|---------|-------------|\n| `auth.password` | `boolean` | `true` | Email/password authentication |\n| `auth.emailOTP` | `boolean` | `false` | Email one-time password login |\n| `auth.passkey` | `boolean` | `false` | WebAuthn/FIDO2 passkey authentication |\n| `auth.signup` | `boolean` | `true` | Self-service account registration |\n| `auth.organizations` | `boolean` | `false` | Multi-tenant organization management (dashboard, invitations, roles) |\n| `auth.admin` | `boolean` | `false` | Admin panel for user management (requires Better Auth admin plugin) |\n| `auth.emailVerification` | `boolean` | `false` | Require email verification after signup |\n\n## Trusted Origins\n\nList of origins allowed to make cross-origin requests to your API. Required when your CMS, Account UI, or frontend app run on different domains.\n\n```typescript\ntrustedOrigins: [\n \"https://auth.example.com\",\n \"https://admin.example.com\",\n \"https://cms.example.com\",\n \"https://app.example.com\",\n],\n```\n\n## Local Development\n\nConfigure local development URLs. These are automatically added to the trusted origins list for CORS and Better Auth, so authentication works out of the box during local development.\n\n```typescript\ndev: {\n port: 8787, // wrangler dev port (default: 8787)\n api: \"http://localhost:8787\", // API backend URL\n cms: \"http://localhost:8787/cms\", // CMS URL (path on same worker)\n account: \"http://localhost:8787/account\", // Account URL (path on same worker)\n},\n```\n\nIf you run a SPA standalone on its own Vite dev server, set its URL here so CORS allows it:\n\n```typescript\ndev: {\n port: 8787,\n api: \"http://localhost:8787\",\n account: \"http://localhost:5173\", // standalone Account dev server\n},\n```\n\n| Field | Type | Default | Description |\n|-------|------|---------|-------------|\n| `port` | `number` | `8787` | Local dev server port (sets `[dev].port` in wrangler.toml) |\n| `api` | `string` | `http://localhost:{port}` | API backend URL |\n| `cms` | `string` | — | CMS dev URL (added to trusted origins if set) |\n| `account` | `string` | — | Account dev URL (added to trusted origins if set) |\n\n## Email Configuration\n\nConfigure email delivery for authentication emails (verification, password reset, invitations).\n\n```typescript\n// Cloudflare Email Service (default) — uses send_email binding, no API keys needed\nemail: {\n from: \"noreply@example.com\",\n fromName: \"My App\",\n},\n\n// AWS SES — requires AWS credentials set as Wrangler secrets\nemail: {\n provider: \"aws-ses\",\n region: \"us-east-2\",\n from: \"noreply@example.com\",\n fromName: \"My App\",\n},\n```\n\n| Field | Type | Default | Description |\n|-------|------|---------|-------------|\n| `provider` | `\"cloudflare\" \\| \"aws-ses\"` | `\"cloudflare\"` | Email transport |\n| `from` | `string` | `\"noreply@example.com\"` | Sender email address |\n| `fromName` | `string` | `\"{name} \\| Account Services\"` | Sender display name |\n| `region` | `string` | `\"us-east-2\"` | AWS SES region (aws-ses only) |\n\n## Multi-Domain Example\n\nA complete config with CMS, Account UI, and Admin on separate subdomains:\n\n```typescript\nexport default {\n name: \"my-app\",\n template: \"hono\",\n cms: { domain: \"cms.example.com\", access: \"admin\" },\n account: {\n domain: \"auth.example.com\",\n adminDomain: \"admin.example.com\",\n name: \"My App\",\n companyName: \"Example Inc.\",\n auth: {\n password: true,\n emailOTP: false,\n passkey: true,\n organizations: false,\n admin: true,\n },\n },\n email: {\n from: \"noreply@example.com\",\n fromName: \"My App\",\n },\n trustedOrigins: [\n \"https://auth.example.com\",\n \"https://admin.example.com\",\n \"https://cms.example.com\",\n \"https://example.com\",\n ],\n providers: {\n runtime: { name: \"cloudflare\", config: {\n routes: [{ pattern: \"api.example.com\", custom_domain: true }],\n }},\n database: { name: \"cloudflare-d1\", config: { binding: \"DB\" } },\n auth: { name: \"better-auth\", config: { plugins: [\"admin\"] } },\n },\n};\n```\n\nThis produces a single Cloudflare Worker serving five domains. See [Multi-Domain Architecture](/compiler/config/domains) for details on hostname routing, cross-subdomain cookies, and the unified fallback domain.\n\n---\n\nSee the sub-pages for detailed reference on each section:\n- [Providers](/compiler/config/providers) — Runtime, database, and auth options\n- [Variables](/compiler/config/variables) — Environment variables and flags\n- [Output](/compiler/config/output) — Generated file structure\n- [Single-Tenant Mode](/compiler/config/single-tenant) — Admin-only and public-facing apps without organizations\n- [Multi-Domain Architecture](/compiler/config/domains) — Custom domains, hostname routing, and cross-subdomain auth"
|
|
151
151
|
},
|
|
152
152
|
"compiler/config/output": {
|
|
153
153
|
"title": "Output Structure",
|
|
@@ -167,7 +167,7 @@ export const DOCS = {
|
|
|
167
167
|
},
|
|
168
168
|
"compiler/definitions/access": {
|
|
169
169
|
"title": "Access - Role & Condition-Based Access Control",
|
|
170
|
-
"content": "Define who can perform CRUD operations and under what conditions.\n\n## Basic Usage\n\n```typescript\n// features/applications/applications.ts\n\nexport const applications = sqliteTable('applications', {\n id: text('id').primaryKey(),\n candidateId: text('candidate_id').notNull(),\n jobId: text('job_id').notNull(),\n stage: text('stage').notNull(),\n notes: text('notes'),\n organizationId: text('organization_id').notNull(),\n});\n\nexport default defineTable(applications, {\n firewall: { organization: {} },\n guards: { createable: [\"candidateId\", \"jobId\", \"notes\"], updatable: [\"notes\"] },\n crud: {\n list: { access: { roles: [\"owner\", \"hiring-manager\", \"recruiter\", \"interviewer\"] } },\n get: { access: { roles: [\"owner\", \"hiring-manager\", \"recruiter\", \"interviewer\"] } },\n create: { access: { roles: [\"owner\", \"hiring-manager\", \"recruiter\"] } },\n update: { access: { roles: [\"owner\", \"hiring-manager\", \"recruiter\"] } },\n delete: { access: { roles: [\"owner\", \"hiring-manager\"] } },\n },\n});\n```\n\n## Configuration Options\n\n```typescript\ninterface Access {\n // Required roles (OR logic - user needs at least one)\n roles?: string[];\n\n // Record-level conditions\n record?: {\n [field: string]: FieldCondition;\n };\n\n // Combinators\n or?: Access[];\n and?: Access[];\n}\n```\n\n### Special Role: `PUBLIC`\n\nUse `roles: [\"PUBLIC\"]` to make an endpoint accessible without authentication. This is intended for public-facing endpoints like contact forms, public listings, or webhooks.\n\n```typescript\naccess: { roles: [\"PUBLIC\"] }\n```\n\n**Important:**\n- `PUBLIC` skips authentication and role checks — anyone can call the endpoint\n- **Firewall still applies** — data is still scoped by the firewall (organization, owner, team)\n- Every `PUBLIC` action invocation is **mandatory audit logged** to the security audit table (IP address, input, result, timing)\n- The wildcard `\"*\"` is **not supported** — using it will throw a compile-time error\n- Tables with no isolation columns and any `PUBLIC` route do not require `firewall: { exception: true }`\n\n#### PUBLIC on Org-Scoped Tables\n\nFor org-scoped tables, PUBLIC routes still filter by organization. Since the user isn't authenticated, the organization ID must be passed as a **query parameter**:\n\n```\nGET /api/v1/listings?organizationId=org_abc123\n```\n\nThis returns only that organization's records — the firewall WHERE clause is always enforced. If no `organizationId` is provided, the API returns a `400` error with code `ORG_REQUIRED`.\n\n```typescript\n// Public listing page — anyone can browse, but scoped to an org\nexport default defineTable(listings, {\n firewall: { organization: {} },\n crud: {\n list: { access: { roles: [\"PUBLIC\"] } }, // Public browsing\n get: { access: { roles: [\"PUBLIC\"] } }, // Public detail view\n create: { access: { roles: [\"admin\", \"member\"] } }, // Auth required to create\n },\n});\n```\n\n```typescript\n// Contact form — public, no auth\naccess: { roles: [\"PUBLIC\"] }\n\n// Any authenticated user with any org role\naccess: { roles: [\"member\", \"admin\", \"owner\"] }\n\n// Specific
|
|
170
|
+
"content": "Define who can perform CRUD operations and under what conditions.\n\n## Basic Usage\n\n```typescript\n// features/applications/applications.ts\n\nexport const applications = sqliteTable('applications', {\n id: text('id').primaryKey(),\n candidateId: text('candidate_id').notNull(),\n jobId: text('job_id').notNull(),\n stage: text('stage').notNull(),\n notes: text('notes'),\n organizationId: text('organization_id').notNull(),\n});\n\nexport default defineTable(applications, {\n firewall: { organization: {} },\n guards: { createable: [\"candidateId\", \"jobId\", \"notes\"], updatable: [\"notes\"] },\n crud: {\n list: { access: { roles: [\"owner\", \"hiring-manager\", \"recruiter\", \"interviewer\"] } },\n get: { access: { roles: [\"owner\", \"hiring-manager\", \"recruiter\", \"interviewer\"] } },\n create: { access: { roles: [\"owner\", \"hiring-manager\", \"recruiter\"] } },\n update: { access: { roles: [\"owner\", \"hiring-manager\", \"recruiter\"] } },\n delete: { access: { roles: [\"owner\", \"hiring-manager\"] } },\n },\n});\n```\n\n## Role Hierarchy\n\nIf your project uses a tiered role system (e.g., `member` < `admin` < `owner`), you can define a hierarchy in your config and use the `+` suffix to mean \"this role and above\":\n\n```typescript\n// quickback.config.ts\nexport default defineConfig({\n name: \"my-app\",\n auth: {\n roleHierarchy: ['member', 'admin', 'owner'], // lowest → highest\n },\n // ...\n});\n```\n\nThen in your resource definitions:\n\n```typescript\ncrud: {\n list: { access: { roles: [\"member+\"] } }, // member, admin, owner\n create: { access: { roles: [\"admin+\"] } }, // admin, owner\n delete: { access: { roles: [\"owner\"] } }, // owner only (no +)\n}\n```\n\nThe `+` suffix expands at compile time — `\"member+\"` becomes `[\"member\", \"admin\", \"owner\"]` in the generated code. You can mix hierarchical and exact roles: `roles: [\"member+\", \"finance\"]` expands to `[\"member\", \"admin\", \"owner\", \"finance\"]`.\n\n- Roles without `+` are exact matches (no expansion)\n- `PUBLIC` cannot use the `+` suffix\n- Using `+` with a role not in the hierarchy throws a compile error\n- Using `+` without configuring `auth.roleHierarchy` throws a compile error\n\n## Configuration Options\n\n```typescript\ninterface Access {\n // Required roles (OR logic - user needs at least one)\n // Use \"role+\" suffix for hierarchy expansion (see Role Hierarchy above)\n roles?: string[];\n\n // Record-level conditions\n record?: {\n [field: string]: FieldCondition;\n };\n\n // Combinators\n or?: Access[];\n and?: Access[];\n}\n```\n\n### Special Role: `PUBLIC`\n\nUse `roles: [\"PUBLIC\"]` to make an endpoint accessible without authentication. This is intended for public-facing endpoints like contact forms, public listings, or webhooks.\n\n```typescript\naccess: { roles: [\"PUBLIC\"] }\n```\n\n**Important:**\n- `PUBLIC` skips authentication and role checks — anyone can call the endpoint\n- **Firewall still applies** — data is still scoped by the firewall (organization, owner, team)\n- Every `PUBLIC` action invocation is **mandatory audit logged** to the security audit table (IP address, input, result, timing)\n- The wildcard `\"*\"` is **not supported** — using it will throw a compile-time error\n- Tables with no isolation columns and any `PUBLIC` route do not require `firewall: { exception: true }`\n\n#### PUBLIC on Org-Scoped Tables\n\nFor org-scoped tables, PUBLIC routes still filter by organization. Since the user isn't authenticated, the organization ID must be passed as a **query parameter**:\n\n```\nGET /api/v1/listings?organizationId=org_abc123\n```\n\nThis returns only that organization's records — the firewall WHERE clause is always enforced. If no `organizationId` is provided, the API returns a `400` error with code `ORG_REQUIRED`.\n\n```typescript\n// Public listing page — anyone can browse, but scoped to an org\nexport default defineTable(listings, {\n firewall: { organization: {} },\n crud: {\n list: { access: { roles: [\"PUBLIC\"] } }, // Public browsing\n get: { access: { roles: [\"PUBLIC\"] } }, // Public detail view\n create: { access: { roles: [\"admin\", \"member\"] } }, // Auth required to create\n },\n});\n```\n\n```typescript\n// Contact form — public, no auth\naccess: { roles: [\"PUBLIC\"] }\n\n// Any authenticated user with any org role\naccess: { roles: [\"member+\"] } // expands to [\"member\", \"admin\", \"owner\"]\n\n// Admin and above\naccess: { roles: [\"admin+\"] } // expands to [\"admin\", \"owner\"]\n\n// Specific role only (no hierarchy expansion)\naccess: { roles: [\"admin\"] }\n```\n\n```typescript\n// Field conditions - value can be string | number | boolean\ntype FieldCondition =\n | { equals: value | '$ctx.userId' | '$ctx.activeOrgId' }\n | { notEquals: value }\n | { in: value[] }\n | { notIn: value[] }\n | { lessThan: number }\n | { greaterThan: number }\n | { lessThanOrEqual: number }\n | { greaterThanOrEqual: number };\n```\n\n## CRUD Configuration\n\n```typescript\ncrud: {\n // LIST - GET /resource\n list: {\n access: { roles: [\"owner\", \"hiring-manager\", \"recruiter\", \"interviewer\"] },\n pageSize: 25, // Default page size\n maxPageSize: 100, // Client can't exceed this\n fields: ['id', 'candidateId', 'jobId', 'stage'], // Selective field returns (optional)\n },\n\n // GET - GET /resource/:id\n get: {\n access: { roles: [\"owner\", \"hiring-manager\", \"recruiter\", \"interviewer\"] },\n fields: ['id', 'candidateId', 'jobId', 'stage', 'notes'], // Optional field selection\n },\n\n // CREATE - POST /resource\n create: {\n access: { roles: [\"owner\", \"hiring-manager\", \"recruiter\"] },\n defaults: { // Default values for new records\n stage: 'applied',\n },\n },\n\n // UPDATE - PATCH /resource/:id\n update: {\n access: {\n or: [\n { roles: [\"hiring-manager\", \"recruiter\"] },\n { roles: [\"interviewer\"], record: { stage: { equals: \"interview\" } } }\n ]\n },\n },\n\n // DELETE - DELETE /resource/:id\n delete: {\n access: { roles: [\"owner\", \"hiring-manager\"] },\n mode: \"soft\", // 'soft' (default) or 'hard'\n },\n\n // PUT - PUT /resource/:id (only when generateId: false + guards: false)\n put: {\n access: { roles: [\"hiring-manager\", \"sync-service\"] },\n },\n}\n```\n\n## List Filtering (Query Parameters)\n\nThe LIST endpoint automatically supports filtering via query params:\n\n```\nGET /jobs?status=open # Exact match\nGET /jobs?salaryMin.gt=50000 # Greater than\nGET /jobs?salaryMin.gte=50000 # Greater than or equal\nGET /jobs?salaryMax.lt=200000 # Less than\nGET /jobs?salaryMax.lte=200000 # Less than or equal\nGET /jobs?status.ne=closed # Not equal\nGET /jobs?title.like=Engineer # Pattern match (LIKE %value%)\nGET /jobs?status.in=open,draft # IN clause\n```\n\n| Operator | Query Param | SQL Equivalent |\n|----------|-------------|----------------|\n| Equals | `?field=value` | `WHERE field = value` |\n| Not equals | `?field.ne=value` | `WHERE field != value` |\n| Greater than | `?field.gt=value` | `WHERE field > value` |\n| Greater or equal | `?field.gte=value` | `WHERE field >= value` |\n| Less than | `?field.lt=value` | `WHERE field < value` |\n| Less or equal | `?field.lte=value` | `WHERE field <= value` |\n| Pattern match | `?field.like=value` | `WHERE field LIKE '%value%'` |\n| In list | `?field.in=a,b,c` | `WHERE field IN ('a','b','c')` |\n\n## Sorting & Pagination\n\n```\nGET /jobs?sort=createdAt&order=desc # Sort by field\nGET /jobs?limit=25&offset=50 # Pagination\n```\n\n- **Default limit**: 50\n- **Max limit**: 100 (or `maxPageSize` if configured)\n- **Default order**: `asc`\n\n## Delete Modes\n\n```typescript\ndelete: {\n access: { roles: [\"owner\", \"hiring-manager\"] },\n mode: \"soft\", // Sets deletedAt/deletedBy, record stays in DB\n}\n\ndelete: {\n access: { roles: [\"owner\", \"hiring-manager\"] },\n mode: \"hard\", // Permanent deletion from database\n}\n```\n\n## Context Variables\n\nUse `$ctx.` prefix to reference context values in conditions:\n\n```typescript\n// User can only view their own records\naccess: {\n record: { userId: { equals: \"$ctx.userId\" } }\n}\n\n// Nested path support for complex context objects\naccess: {\n record: { ownerId: { equals: \"$ctx.user.id\" } }\n}\n```\n\n### AppContext Reference\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `$ctx.userId` | `string` | Current authenticated user's ID |\n| `$ctx.activeOrgId` | `string` | User's active organization ID |\n| `$ctx.activeTeamId` | `string \\| null` | User's active team ID (if applicable) |\n| `$ctx.roles` | `string[]` | User's roles in current context |\n| `$ctx.isAnonymous` | `boolean` | Whether user is anonymous |\n| `$ctx.user` | `object` | Full user object from auth provider |\n| `$ctx.user.id` | `string` | User ID (nested path example) |\n| `$ctx.user.email` | `string` | User's email address |\n| `$ctx.{property}` | `any` | Any custom context property |\n\n## Function-Based Access\n\nFor complex access logic that can't be expressed declaratively, use a function:\n\n```typescript\ncrud: {\n update: {\n access: async (ctx, record) => {\n // Custom logic - return true to allow, false to deny\n if (ctx.roles.includes('admin')) return true;\n if (record.ownerId === ctx.userId) return true;\n\n // Check custom business logic\n const membership = await checkTeamMembership(ctx.userId, record.teamId);\n return membership.canEdit;\n }\n }\n}\n```\n\nFunction access receives:\n- `ctx`: The full AppContext object\n- `record`: The record being accessed (for get/update/delete operations)"
|
|
171
171
|
},
|
|
172
172
|
"compiler/definitions/actions": {
|
|
173
173
|
"title": "Actions",
|
package/dist/docs/content.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content.js","sourceRoot":"","sources":["../../src/docs/content.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,0DAA0D;AAO1D,MAAM,CAAC,MAAM,IAAI,GAA6B;IAC5C,0BAA0B,EAAE;QAC1B,OAAO,EAAE,eAAe;QACxB,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"content.js","sourceRoot":"","sources":["../../src/docs/content.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../../src/lib/api-client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGrD,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,KAAK,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE;YAAE,SAAS,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,GAAG,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC;QAC5D,MAAM,CAAC,EAAE,KAAK,CAAC;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAC;YAAC,iBAAiB,EAAE,OAAO,CAAA;SAAE,CAAC,CAAC;QACpG,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACvC,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,GAAG,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC5B;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,IAAI,EAAE;QACJ,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE;YACR,OAAO,EAAE,MAAM,CAAC;YAChB,UAAU,EAAE,MAAM,CAAC;YACnB,SAAS,EAAE,MAAM,CAAC;YAClB,UAAU,EAAE,MAAM,CAAC;YACnB,SAAS,EAAE,MAAM,CAAC;YAClB,OAAO,EAAE,MAAM,CAAC;YAChB,QAAQ,EAAE,KAAK,CAAC;gBAAE,WAAW,EAAE,MAAM,CAAC;gBAAC,EAAE,EAAE,MAAM,CAAC;gBAAC,OAAO,EAAE,OAAO,CAAA;aAAE,CAAC,CAAC;SACxE,CAAC;KACH,CAAC;IACF,QAAQ,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAoBD;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAQ5E;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,aAAa,EACpB,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GACnC,OAAO,CAAC,cAAc,CAAC,
|
|
1
|
+
{"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../../src/lib/api-client.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/api-client.js
CHANGED
|
@@ -60,12 +60,27 @@ export async function callCompiler(input, onStatus) {
|
|
|
60
60
|
const body = JSON.stringify(input);
|
|
61
61
|
const maxRetries = 3;
|
|
62
62
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
63
|
-
//
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
63
|
+
// Abort if the request takes longer than 120 seconds
|
|
64
|
+
const controller = new AbortController();
|
|
65
|
+
const timeout = setTimeout(() => controller.abort(), 120_000);
|
|
66
|
+
let response;
|
|
67
|
+
try {
|
|
68
|
+
// Try SSE streaming first for live progress updates
|
|
69
|
+
response = await fetch(`${API_URL}/compile`, {
|
|
70
|
+
method: 'POST',
|
|
71
|
+
headers: { ...headers, 'Accept': 'text/event-stream' },
|
|
72
|
+
body,
|
|
73
|
+
signal: controller.signal,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
clearTimeout(timeout);
|
|
78
|
+
if (err.name === 'AbortError') {
|
|
79
|
+
throw new Error('Compilation timed out after 120 seconds. The compiler may be overloaded — please try again.');
|
|
80
|
+
}
|
|
81
|
+
throw err;
|
|
82
|
+
}
|
|
83
|
+
clearTimeout(timeout);
|
|
69
84
|
if (!response.ok) {
|
|
70
85
|
const error = await readErrorPayload(response);
|
|
71
86
|
// Retry on transient container proxy errors (cold start race)
|
|
@@ -79,6 +94,11 @@ export async function callCompiler(input, onStatus) {
|
|
|
79
94
|
if (response.status === 403 && error.hint) {
|
|
80
95
|
throw new Error(`${error.error}\n${error.hint}`);
|
|
81
96
|
}
|
|
97
|
+
// Friendly message for transient infrastructure errors
|
|
98
|
+
if (response.status === 502 || response.status === 503 || response.status === 504) {
|
|
99
|
+
const raw = error.raw ? `\n${error.raw}` : '';
|
|
100
|
+
throw new Error(`Compiler returned ${response.status} ${response.statusText} — please try again.${raw}`);
|
|
101
|
+
}
|
|
82
102
|
// Include detailed error info for debugging
|
|
83
103
|
// Prefer .message (specific reason) over .error (generic category like "Compilation failed")
|
|
84
104
|
const errorMsg = error.message || error.error || 'Compilation failed';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../../src/lib/api-client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,gCAAgC,CAAC;AAmElF,KAAK,UAAU,gBAAgB,CAAC,QAAkB;IAChD,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;IAC/D,IAAI,WAAW,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAC7C,IAAI,CAAC;YACH,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAc,CAAC;QAC3C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,KAAK,EAAE,qCAAqC,EAAE,CAAC;QAC1D,CAAC;IACH,CAAC;IAED,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC;IACrC,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,YAAY,CAAC,CAAC;IAErD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC/C,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,EAA2C,CAAC;AAClE,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,KAAoB,EACpB,QAAoC;IAEpC,wEAAwE;IACxE,MAAM,YAAY,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IAEvC,QAAQ,EAAE,CAAC,cAAc,CAAC,CAAC;IAE3B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAE7C,MAAM,OAAO,GAA2B;QACtC,cAAc,EAAE,kBAAkB;KACnC,CAAC;IAEF,IAAI,MAAM,EAAE,CAAC;QACX,sDAAsD;QACtD,OAAO,CAAC,WAAW,CAAC,GAAG,MAAM,CAAC;IAChC,CAAC;SAAM,CAAC;QACN,4DAA4D;QAC5D,MAAM,KAAK,GAAG,MAAM,cAAc,EAAE,CAAC;QACrC,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,eAAe,CAAC,GAAG,UAAU,KAAK,EAAE,CAAC;QAC/C,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,UAAU,GAAG,CAAC,CAAC;IAErB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC;QACtD,
|
|
1
|
+
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../../src/lib/api-client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,gCAAgC,CAAC;AAmElF,KAAK,UAAU,gBAAgB,CAAC,QAAkB;IAChD,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;IAC/D,IAAI,WAAW,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAC7C,IAAI,CAAC;YACH,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAc,CAAC;QAC3C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,KAAK,EAAE,qCAAqC,EAAE,CAAC;QAC1D,CAAC;IACH,CAAC;IAED,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC;IACrC,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,YAAY,CAAC,CAAC;IAErD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC/C,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,EAA2C,CAAC;AAClE,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,KAAoB,EACpB,QAAoC;IAEpC,wEAAwE;IACxE,MAAM,YAAY,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IAEvC,QAAQ,EAAE,CAAC,cAAc,CAAC,CAAC;IAE3B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAE7C,MAAM,OAAO,GAA2B;QACtC,cAAc,EAAE,kBAAkB;KACnC,CAAC;IAEF,IAAI,MAAM,EAAE,CAAC;QACX,sDAAsD;QACtD,OAAO,CAAC,WAAW,CAAC,GAAG,MAAM,CAAC;IAChC,CAAC;SAAM,CAAC;QACN,4DAA4D;QAC5D,MAAM,KAAK,GAAG,MAAM,cAAc,EAAE,CAAC;QACrC,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,eAAe,CAAC,GAAG,UAAU,KAAK,EAAE,CAAC;QAC/C,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,UAAU,GAAG,CAAC,CAAC;IAErB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC;QACtD,qDAAqD;QACrD,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,OAAO,CAAC,CAAC;QAE9D,IAAI,QAAkB,CAAC;QACvB,IAAI,CAAC;YACH,oDAAoD;YACpD,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,UAAU,EAAE;gBAC3C,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,mBAAmB,EAAE;gBACtD,IAAI;gBACJ,MAAM,EAAE,UAAU,CAAC,MAAM;aAC1B,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,YAAY,CAAC,OAAO,CAAC,CAAC;YACtB,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBAC9B,MAAM,IAAI,KAAK,CAAC,6FAA6F,CAAC,CAAC;YACjH,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;QACD,YAAY,CAAC,OAAO,CAAC,CAAC;QAEtB,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC;YAE/C,8DAA8D;YAC9D,+EAA+E;YAC/E,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,OAAO,GAAG,UAAU,GAAG,CAAC,IAAI,KAAK,CAAC,GAAG,EAAE,CAAC;gBACrE,QAAQ,EAAE,CAAC,8BAA8B,CAAC,CAAC;gBAC3C,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;gBAC5C,QAAQ,EAAE,CAAC,cAAc,CAAC,CAAC;gBAC3B,SAAS;YACX,CAAC;YAED,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;gBAC1C,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YACnD,CAAC;YAED,uDAAuD;YACvD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAClF,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC9C,MAAM,IAAI,KAAK,CAAC,qBAAqB,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,uBAAuB,GAAG,EAAE,CAAC,CAAC;YAC3G,CAAC;YAED,4CAA4C;YAC5C,6FAA6F;YAC7F,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,KAAK,IAAI,oBAAoB,CAAC;YACtE,MAAM,OAAO,GAAI,KAAa,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,IAAI,CAAC,SAAS,CAAE,KAAa,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9G,MAAM,MAAM,GAAI,KAAa,CAAC,MAAM,CAAC,CAAC,CAAC,aAAc,KAAa,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjF,MAAM,MAAM,GAAI,KAAa,CAAC,MAAM,CAAC,CAAC,CAAC,aAAc,KAAa,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjF,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,eAAe,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxD,MAAM,MAAM,GAAG,aAAa,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;YACrE,MAAM,IAAI,KAAK,CAAC,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,GAAG,CAAC,CAAC;QACvE,CAAC;QAED,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;QAE/D,gCAAgC;QAChC,IAAI,WAAW,CAAC,QAAQ,CAAC,mBAAmB,CAAC,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;YAC/D,OAAO,gBAAgB,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACnD,CAAC;QAED,mEAAmE;QACnE,OAAO,QAAQ,CAAC,IAAI,EAA6B,CAAC;IACpD,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;AACtD,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,SAAS,CAAC,CAAC;IAElD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAClD,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,EAAkD,CAAC;AACzE,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,gBAAgB,CAC7B,IAAgC,EAChC,QAAoC;IAEpC,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;IAChC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,YAAY,GAAG,EAAE,CAAC;IACtB,IAAI,MAAM,GAA0B,IAAI,CAAC;IAEzC,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QAC5C,IAAI,IAAI;YAAE,MAAM;QAChB,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QAElD,+BAA+B;QAC/B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACjC,MAAM,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,iCAAiC;QAE7D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC/B,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACtC,CAAC;iBAAM,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACrC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBAC3B,IAAI,CAAC;oBACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBAEhC,IAAI,YAAY,KAAK,UAAU,EAAE,CAAC;wBAChC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;wBAClD,QAAQ,EAAE,CAAC,GAAG,MAAM,CAAC,OAAO,KAAK,IAAI,IAAI,CAAC,CAAC;oBAC7C,CAAC;yBAAM,IAAI,YAAY,KAAK,QAAQ,EAAE,CAAC;wBACrC,MAAM,GAAG,MAAwB,CAAC;oBACpC,CAAC;yBAAM,IAAI,YAAY,KAAK,OAAO,EAAE,CAAC;wBACpC,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,KAAK,IAAI,oBAAoB,CAAC;wBACxE,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;oBAC5B,CAAC;gBACH,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,IAAI,CAAC,YAAY,KAAK,IAAI,CAAC,CAAC,OAAO,KAAK,oBAAoB;wBAAE,MAAM,CAAC,CAAC;oBACtE,+CAA+C;gBACjD,CAAC;gBACD,YAAY,GAAG,EAAE,CAAC;YACpB,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC/D,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,WAAW,GAAG,EAAE,EAChB,UAAU,GAAG,IAAI,EACjB,QAAoC;IAEpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,WAAW,EAAE,CAAC;YACnC,IAAI,MAAM,CAAC,MAAM,KAAK,OAAO;gBAAE,OAAO;YACtC,QAAQ,EAAE,CAAC,wBAAwB,MAAM,CAAC,MAAM,MAAM,CAAC,CAAC;QAC1D,CAAC;QAAC,MAAM,CAAC;YACP,QAAQ,EAAE,CAAC,2BAA2B,CAAC,CAAC;QAC1C,CAAC;QACD,IAAI,CAAC,GAAG,WAAW,GAAG,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;AACrE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS;IACvB,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -269,21 +269,23 @@ Role-based and record-based access control. Deny by default.
|
|
|
269
269
|
|
|
270
270
|
```typescript
|
|
271
271
|
crud: {
|
|
272
|
-
list: { access: { roles: ['member'] } },
|
|
273
|
-
get: { access: { roles: ['member'] } },
|
|
274
|
-
create: { access: { roles: ['admin'
|
|
272
|
+
list: { access: { roles: ['member+'] } }, // member, admin, owner
|
|
273
|
+
get: { access: { roles: ['member+'] } },
|
|
274
|
+
create: { access: { roles: ['admin+'] } }, // admin, owner
|
|
275
275
|
update: {
|
|
276
276
|
access: {
|
|
277
277
|
or: [
|
|
278
|
-
{ roles: ['admin'] },
|
|
278
|
+
{ roles: ['admin+'] },
|
|
279
279
|
{ record: { createdBy: { equals: '$ctx.userId' } } },
|
|
280
280
|
],
|
|
281
281
|
},
|
|
282
282
|
},
|
|
283
|
-
delete: { access: { roles: ['
|
|
283
|
+
delete: { access: { roles: ['owner'] } }, // owner only
|
|
284
284
|
}
|
|
285
285
|
```
|
|
286
286
|
|
|
287
|
+
**Role hierarchy**: Configure `auth.roleHierarchy` in your config (e.g., `['member', 'admin', 'owner']`) and use the `+` suffix to mean "this role and above". `"member+"` expands to `["member", "admin", "owner"]` at compile time. Roles without `+` are exact matches.
|
|
288
|
+
|
|
287
289
|
Record condition operators: `equals`, `notEquals`, `in`, `notIn`, `greaterThan`, `lessThan`
|
|
288
290
|
|
|
289
291
|
Context variables: `$ctx.userId`, `$ctx.activeOrgId`, `$ctx.activeTeamId`, `$ctx.roles`, `$ctx.isAnonymous`
|
|
@@ -162,15 +162,17 @@ masking: {
|
|
|
162
162
|
views: {
|
|
163
163
|
summary: {
|
|
164
164
|
fields: ['id', 'name', 'email'],
|
|
165
|
-
access: { roles: ['member',
|
|
165
|
+
access: { roles: ['member+'] }, // member, admin, owner
|
|
166
166
|
},
|
|
167
167
|
full: {
|
|
168
168
|
fields: ['id', 'name', 'email', 'phone', 'ssn'],
|
|
169
|
-
access: { roles: ['admin'] },
|
|
169
|
+
access: { roles: ['admin+'] }, // admin, owner
|
|
170
170
|
},
|
|
171
171
|
}
|
|
172
172
|
```
|
|
173
173
|
|
|
174
|
+
> Use `+` suffix with `auth.roleHierarchy` configured (e.g., `['member', 'admin', 'owner']`) to expand roles at compile time. `"member+"` → `["member", "admin", "owner"]`.
|
|
175
|
+
|
|
174
176
|
### Standalone actions (not record-based)
|
|
175
177
|
```typescript
|
|
176
178
|
// In actions.ts
|
package/package.json
CHANGED
package/src/skill/SKILL.md
CHANGED
|
@@ -269,21 +269,23 @@ Role-based and record-based access control. Deny by default.
|
|
|
269
269
|
|
|
270
270
|
```typescript
|
|
271
271
|
crud: {
|
|
272
|
-
list: { access: { roles: ['member'] } },
|
|
273
|
-
get: { access: { roles: ['member'] } },
|
|
274
|
-
create: { access: { roles: ['admin'
|
|
272
|
+
list: { access: { roles: ['member+'] } }, // member, admin, owner
|
|
273
|
+
get: { access: { roles: ['member+'] } },
|
|
274
|
+
create: { access: { roles: ['admin+'] } }, // admin, owner
|
|
275
275
|
update: {
|
|
276
276
|
access: {
|
|
277
277
|
or: [
|
|
278
|
-
{ roles: ['admin'] },
|
|
278
|
+
{ roles: ['admin+'] },
|
|
279
279
|
{ record: { createdBy: { equals: '$ctx.userId' } } },
|
|
280
280
|
],
|
|
281
281
|
},
|
|
282
282
|
},
|
|
283
|
-
delete: { access: { roles: ['
|
|
283
|
+
delete: { access: { roles: ['owner'] } }, // owner only
|
|
284
284
|
}
|
|
285
285
|
```
|
|
286
286
|
|
|
287
|
+
**Role hierarchy**: Configure `auth.roleHierarchy` in your config (e.g., `['member', 'admin', 'owner']`) and use the `+` suffix to mean "this role and above". `"member+"` expands to `["member", "admin", "owner"]` at compile time. Roles without `+` are exact matches.
|
|
288
|
+
|
|
287
289
|
Record condition operators: `equals`, `notEquals`, `in`, `notIn`, `greaterThan`, `lessThan`
|
|
288
290
|
|
|
289
291
|
Context variables: `$ctx.userId`, `$ctx.activeOrgId`, `$ctx.activeTeamId`, `$ctx.roles`, `$ctx.isAnonymous`
|
|
@@ -162,15 +162,17 @@ masking: {
|
|
|
162
162
|
views: {
|
|
163
163
|
summary: {
|
|
164
164
|
fields: ['id', 'name', 'email'],
|
|
165
|
-
access: { roles: ['member',
|
|
165
|
+
access: { roles: ['member+'] }, // member, admin, owner
|
|
166
166
|
},
|
|
167
167
|
full: {
|
|
168
168
|
fields: ['id', 'name', 'email', 'phone', 'ssn'],
|
|
169
|
-
access: { roles: ['admin'] },
|
|
169
|
+
access: { roles: ['admin+'] }, // admin, owner
|
|
170
170
|
},
|
|
171
171
|
}
|
|
172
172
|
```
|
|
173
173
|
|
|
174
|
+
> Use `+` suffix with `auth.roleHierarchy` configured (e.g., `['member', 'admin', 'owner']`) to expand roles at compile time. `"member+"` → `["member", "admin", "owner"]`.
|
|
175
|
+
|
|
174
176
|
### Standalone actions (not record-based)
|
|
175
177
|
```typescript
|
|
176
178
|
// In actions.ts
|