@simple-auth-kit/cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -0
- package/bin/simple-auth-kit.mjs +18 -0
- package/lib/copy.ts +190 -0
- package/lib/rename-native.ts +173 -0
- package/package.json +31 -0
- package/registry/README.md +312 -0
- package/registry/admin-apps/README.md +71 -0
- package/registry/admin-apps/nextjs/shared/components.json +25 -0
- package/registry/admin-apps/nextjs/shared/next.config.ts +9 -0
- package/registry/admin-apps/nextjs/shared/postcss.config.mjs +7 -0
- package/registry/admin-apps/nextjs/shared/src/app/globals.css +159 -0
- package/registry/admin-apps/nextjs/shared/src/app/signup/page.tsx +72 -0
- package/registry/admin-apps/nextjs/shared/src/components/alert-modal.tsx +32 -0
- package/registry/admin-apps/nextjs/shared/src/components/breadcrumb.tsx +48 -0
- package/registry/admin-apps/nextjs/shared/src/components/form-error-alert.tsx +24 -0
- package/registry/admin-apps/nextjs/shared/src/components/loader/skeleton.tsx +39 -0
- package/registry/admin-apps/nextjs/shared/src/components/loader/table-skeleton-loader.tsx +57 -0
- package/registry/admin-apps/nextjs/shared/src/components/permission-group-select.tsx +101 -0
- package/registry/admin-apps/nextjs/shared/src/components/permission-group-view.tsx +53 -0
- package/registry/admin-apps/nextjs/shared/src/components/role-multi-select.tsx +71 -0
- package/registry/admin-apps/nextjs/shared/src/components/theme-toggle.tsx +26 -0
- package/registry/admin-apps/nextjs/shared/src/components/ui/alert.tsx +78 -0
- package/registry/admin-apps/nextjs/shared/src/components/ui/avatar.tsx +53 -0
- package/registry/admin-apps/nextjs/shared/src/components/ui/badge.tsx +51 -0
- package/registry/admin-apps/nextjs/shared/src/components/ui/breadcrumb.tsx +109 -0
- package/registry/admin-apps/nextjs/shared/src/components/ui/button.tsx +67 -0
- package/registry/admin-apps/nextjs/shared/src/components/ui/card.tsx +103 -0
- package/registry/admin-apps/nextjs/shared/src/components/ui/checkbox.tsx +32 -0
- package/registry/admin-apps/nextjs/shared/src/components/ui/collapsible.tsx +33 -0
- package/registry/admin-apps/nextjs/shared/src/components/ui/data-table.tsx +107 -0
- package/registry/admin-apps/nextjs/shared/src/components/ui/dialog.tsx +143 -0
- package/registry/admin-apps/nextjs/shared/src/components/ui/dropdown-menu.tsx +234 -0
- package/registry/admin-apps/nextjs/shared/src/components/ui/heading.tsx +16 -0
- package/registry/admin-apps/nextjs/shared/src/components/ui/input.tsx +19 -0
- package/registry/admin-apps/nextjs/shared/src/components/ui/label.tsx +24 -0
- package/registry/admin-apps/nextjs/shared/src/components/ui/modal.tsx +29 -0
- package/registry/admin-apps/nextjs/shared/src/components/ui/select.tsx +192 -0
- package/registry/admin-apps/nextjs/shared/src/components/ui/separator.tsx +28 -0
- package/registry/admin-apps/nextjs/shared/src/components/ui/sheet.tsx +135 -0
- package/registry/admin-apps/nextjs/shared/src/components/ui/sidebar.tsx +567 -0
- package/registry/admin-apps/nextjs/shared/src/components/ui/skeleton.tsx +13 -0
- package/registry/admin-apps/nextjs/shared/src/components/ui/sonner.tsx +34 -0
- package/registry/admin-apps/nextjs/shared/src/components/ui/table.tsx +116 -0
- package/registry/admin-apps/nextjs/shared/src/components/ui/tooltip.tsx +61 -0
- package/registry/admin-apps/nextjs/shared/src/hooks/use-live-audit-feed.ts +51 -0
- package/registry/admin-apps/nextjs/shared/src/hooks/use-mobile.ts +17 -0
- package/registry/admin-apps/nextjs/shared/src/lib/error.ts +23 -0
- package/registry/admin-apps/nextjs/shared/src/lib/query-client.tsx +10 -0
- package/registry/admin-apps/nextjs/shared/src/lib/token-storage.ts +36 -0
- package/registry/admin-apps/nextjs/shared/src/lib/utils.ts +6 -0
- package/registry/admin-apps/nextjs/shared/tsconfig.json +41 -0
- package/registry/admin-apps/nextjs/variants/base/.env.example +9 -0
- package/registry/admin-apps/nextjs/variants/base/Dockerfile +32 -0
- package/registry/admin-apps/nextjs/variants/base/package.json +58 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/account/change-password/page.tsx +163 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/account/page.tsx +569 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/audit-log/page.tsx +180 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/countries/[id]/edit/page.tsx +357 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/countries/[id]/page.tsx +191 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/countries/country-schema.ts +18 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/countries/new/page.tsx +305 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/countries/page.tsx +367 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/customers/[id]/edit/page.tsx +386 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/customers/[id]/page.tsx +213 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/customers/customer-schema.ts +35 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/customers/new/page.tsx +334 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/customers/page.tsx +400 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/dashboard/page.tsx +263 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/languages/[id]/edit/page.tsx +275 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/languages/[id]/page.tsx +183 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/languages/language-schema.ts +20 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/languages/new/page.tsx +226 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/languages/page.tsx +342 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/layout.tsx +50 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/permissions/[id]/edit/page.tsx +309 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/permissions/[id]/page.tsx +119 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/permissions/new/page.tsx +275 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/permissions/page.tsx +311 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/permissions/permission-schema.ts +44 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/roles/[id]/edit/page.tsx +276 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/roles/[id]/page.tsx +179 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/roles/new/page.tsx +241 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/roles/page.tsx +325 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/roles/role-schema.ts +20 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/users/[id]/edit/page.tsx +411 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/users/[id]/page.tsx +253 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/users/new/page.tsx +444 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/users/page.tsx +410 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/(console)/users/user-schema.ts +37 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/api/auth/[...nextauth]/route.ts +3 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/icon.svg +5 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/layout.tsx +31 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/login/page.tsx +162 -0
- package/registry/admin-apps/nextjs/variants/base/src/app/page.tsx +22 -0
- package/registry/admin-apps/nextjs/variants/base/src/auth.ts +105 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/app-sidebar.tsx +182 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/nav-user.tsx +99 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/permission-required.tsx +32 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/photo-upload.tsx +203 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/accordion.tsx +66 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/alert-dialog.tsx +157 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/button-group.tsx +83 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/calendar.tsx +218 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/carousel.tsx +241 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/combobox.tsx +243 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/command.tsx +184 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/context-menu.tsx +252 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/date-picker.tsx +323 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/datetime-picker.tsx +896 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/drawer.tsx +135 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/empty.tsx +104 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/field.tsx +248 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/form.tsx +168 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/hover-card.tsx +44 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/input-group.tsx +170 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/input-otp.tsx +77 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/item.tsx +193 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/kbd.tsx +28 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/menubar.tsx +276 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/multi-select.tsx +381 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/multi-selector.tsx +641 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/native-select.tsx +48 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/navigation-menu.tsx +168 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/pagination.tsx +127 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/popover.tsx +48 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/progress.tsx +31 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/radio-group.tsx +45 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/resizable.tsx +55 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/scroll-area.tsx +58 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/spinner.tsx +27 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/switch.tsx +31 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/tabs.tsx +66 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/textarea.tsx +18 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/toggle-group.tsx +83 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/ui/toggle.tsx +47 -0
- package/registry/admin-apps/nextjs/variants/base/src/components/user-menu.tsx +61 -0
- package/registry/admin-apps/nextjs/variants/base/src/lib/ability.ts +90 -0
- package/registry/admin-apps/nextjs/variants/base/src/lib/auth-client.ts +10 -0
- package/registry/admin-apps/nextjs/variants/base/src/lib/env.ts +10 -0
- package/registry/admin-apps/nextjs/variants/base/src/lib/server-token-storage.ts +33 -0
- package/registry/admin-apps/nextjs/variants/base/src/lib/stores/auth-store.ts +117 -0
- package/registry/admin-apps/nextjs/variants/base/src/lib/stores/store-context.tsx +50 -0
- package/registry/admin-apps/nextjs/variants/base/src/proxy.ts +81 -0
- package/registry/admin-apps/nextjs/variants/base/src/routes.ts +7 -0
- package/registry/admin-apps/nextjs/variants/workspaces/.env.example +7 -0
- package/registry/admin-apps/nextjs/variants/workspaces/Dockerfile +32 -0
- package/registry/admin-apps/nextjs/variants/workspaces/package.json +48 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/account/page.tsx +360 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/audit-log/page.tsx +185 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/countries/[id]/edit/page.tsx +296 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/countries/[id]/page.tsx +194 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/countries/country-schema.ts +27 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/countries/new/page.tsx +242 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/countries/page.tsx +373 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/customers/[id]/edit/page.tsx +306 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/customers/[id]/page.tsx +219 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/customers/customer-schema.ts +36 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/customers/new/page.tsx +251 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/customers/page.tsx +406 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/dashboard/page.tsx +146 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/languages/[id]/edit/page.tsx +240 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/languages/[id]/page.tsx +186 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/languages/language-schema.ts +26 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/languages/new/page.tsx +189 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/languages/page.tsx +348 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/layout.tsx +96 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/members/page.tsx +263 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/permissions/[id]/edit/page.tsx +264 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/permissions/[id]/page.tsx +126 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/permissions/new/page.tsx +238 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/permissions/page.tsx +294 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/permissions/permission-schema.ts +46 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/roles/[id]/edit/page.tsx +248 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/roles/[id]/page.tsx +186 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/roles/new/page.tsx +205 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/roles/page.tsx +485 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/roles/role-schema.ts +23 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/users/[id]/page.tsx +521 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/users/new/page.tsx +342 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/users/page.tsx +414 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/users/user-schema.ts +44 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/workspaces/new/page.tsx +66 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/layout.tsx +31 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/login/page.tsx +110 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/app/page.tsx +33 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/components/app-sidebar.tsx +180 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/components/change-password-dialog.tsx +119 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/components/nav-user.tsx +105 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/components/permission-required.tsx +32 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/components/photo-upload.tsx +226 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/components/ui/calendar.tsx +218 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/components/ui/datetime-picker.tsx +896 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/components/ui/popover.tsx +48 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/components/user-menu.tsx +67 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/components/workspace-switcher.tsx +57 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/lib/ability.ts +101 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/lib/active-workspace.ts +38 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/lib/auth-client.ts +17 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/lib/env.ts +4 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/lib/stores/auth-store.ts +139 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/lib/stores/store-context.tsx +66 -0
- package/registry/admin-apps/nextjs/variants/workspaces/src/lib/stores/workspace-store.ts +89 -0
- package/registry/admin-apps/react/shared/components.json +25 -0
- package/registry/admin-apps/react/shared/postcss.config.js +5 -0
- package/registry/admin-apps/react/shared/src/components/alert-modal.tsx +30 -0
- package/registry/admin-apps/react/shared/src/components/loader/skeleton.tsx +39 -0
- package/registry/admin-apps/react/shared/src/components/loader/table-skeleton-loader.tsx +57 -0
- package/registry/admin-apps/react/shared/src/components/nav-user.tsx +103 -0
- package/registry/admin-apps/react/shared/src/components/role-multi-select.tsx +69 -0
- package/registry/admin-apps/react/shared/src/components/theme-toggle.tsx +24 -0
- package/registry/admin-apps/react/shared/src/components/ui/accordion.tsx +66 -0
- package/registry/admin-apps/react/shared/src/components/ui/alert-dialog.tsx +157 -0
- package/registry/admin-apps/react/shared/src/components/ui/alert.tsx +78 -0
- package/registry/admin-apps/react/shared/src/components/ui/avatar.tsx +53 -0
- package/registry/admin-apps/react/shared/src/components/ui/badge.tsx +51 -0
- package/registry/admin-apps/react/shared/src/components/ui/breadcrumb.tsx +109 -0
- package/registry/admin-apps/react/shared/src/components/ui/button-group.tsx +83 -0
- package/registry/admin-apps/react/shared/src/components/ui/button.tsx +67 -0
- package/registry/admin-apps/react/shared/src/components/ui/calendar.tsx +218 -0
- package/registry/admin-apps/react/shared/src/components/ui/card.tsx +103 -0
- package/registry/admin-apps/react/shared/src/components/ui/carousel.tsx +241 -0
- package/registry/admin-apps/react/shared/src/components/ui/checkbox.tsx +32 -0
- package/registry/admin-apps/react/shared/src/components/ui/collapsible.tsx +33 -0
- package/registry/admin-apps/react/shared/src/components/ui/context-menu.tsx +252 -0
- package/registry/admin-apps/react/shared/src/components/ui/data-table.tsx +107 -0
- package/registry/admin-apps/react/shared/src/components/ui/datetime-picker.tsx +896 -0
- package/registry/admin-apps/react/shared/src/components/ui/dialog.tsx +143 -0
- package/registry/admin-apps/react/shared/src/components/ui/drawer.tsx +135 -0
- package/registry/admin-apps/react/shared/src/components/ui/dropdown-menu.tsx +234 -0
- package/registry/admin-apps/react/shared/src/components/ui/empty.tsx +104 -0
- package/registry/admin-apps/react/shared/src/components/ui/field.tsx +248 -0
- package/registry/admin-apps/react/shared/src/components/ui/form.tsx +168 -0
- package/registry/admin-apps/react/shared/src/components/ui/heading.tsx +16 -0
- package/registry/admin-apps/react/shared/src/components/ui/hover-card.tsx +44 -0
- package/registry/admin-apps/react/shared/src/components/ui/input-group.tsx +170 -0
- package/registry/admin-apps/react/shared/src/components/ui/input-otp.tsx +77 -0
- package/registry/admin-apps/react/shared/src/components/ui/input.tsx +19 -0
- package/registry/admin-apps/react/shared/src/components/ui/item.tsx +193 -0
- package/registry/admin-apps/react/shared/src/components/ui/kbd.tsx +28 -0
- package/registry/admin-apps/react/shared/src/components/ui/label.tsx +24 -0
- package/registry/admin-apps/react/shared/src/components/ui/menubar.tsx +276 -0
- package/registry/admin-apps/react/shared/src/components/ui/modal.tsx +29 -0
- package/registry/admin-apps/react/shared/src/components/ui/multi-select.tsx +381 -0
- package/registry/admin-apps/react/shared/src/components/ui/multi-selector.tsx +641 -0
- package/registry/admin-apps/react/shared/src/components/ui/native-select.tsx +48 -0
- package/registry/admin-apps/react/shared/src/components/ui/navigation-menu.tsx +168 -0
- package/registry/admin-apps/react/shared/src/components/ui/pagination.tsx +127 -0
- package/registry/admin-apps/react/shared/src/components/ui/popover.tsx +48 -0
- package/registry/admin-apps/react/shared/src/components/ui/progress.tsx +31 -0
- package/registry/admin-apps/react/shared/src/components/ui/radio-group.tsx +45 -0
- package/registry/admin-apps/react/shared/src/components/ui/resizable.tsx +55 -0
- package/registry/admin-apps/react/shared/src/components/ui/scroll-area.tsx +58 -0
- package/registry/admin-apps/react/shared/src/components/ui/select.tsx +192 -0
- package/registry/admin-apps/react/shared/src/components/ui/separator.tsx +28 -0
- package/registry/admin-apps/react/shared/src/components/ui/sheet.tsx +135 -0
- package/registry/admin-apps/react/shared/src/components/ui/sidebar.tsx +567 -0
- package/registry/admin-apps/react/shared/src/components/ui/skeleton.tsx +13 -0
- package/registry/admin-apps/react/shared/src/components/ui/spinner.tsx +27 -0
- package/registry/admin-apps/react/shared/src/components/ui/switch.tsx +31 -0
- package/registry/admin-apps/react/shared/src/components/ui/table.tsx +116 -0
- package/registry/admin-apps/react/shared/src/components/ui/tabs.tsx +66 -0
- package/registry/admin-apps/react/shared/src/components/ui/textarea.tsx +18 -0
- package/registry/admin-apps/react/shared/src/components/ui/toggle-group.tsx +83 -0
- package/registry/admin-apps/react/shared/src/components/ui/toggle.tsx +47 -0
- package/registry/admin-apps/react/shared/src/components/ui/tooltip.tsx +61 -0
- package/registry/admin-apps/react/shared/src/hooks/use-mobile.ts +17 -0
- package/registry/admin-apps/react/shared/src/lib/cn.ts +6 -0
- package/registry/admin-apps/react/shared/src/lib/error.ts +23 -0
- package/registry/admin-apps/react/shared/src/lib/query-client.tsx +8 -0
- package/registry/admin-apps/react/shared/src/lib/utils.ts +1 -0
- package/registry/admin-apps/react/shared/src/vite-env.d.ts +9 -0
- package/registry/admin-apps/react/shared/tsconfig.json +24 -0
- package/registry/admin-apps/react/variants/base/.env.example +3 -0
- package/registry/admin-apps/react/variants/base/Dockerfile +32 -0
- package/registry/admin-apps/react/variants/base/index.html +12 -0
- package/registry/admin-apps/react/variants/base/package.json +61 -0
- package/registry/admin-apps/react/variants/base/src/App.tsx +103 -0
- package/registry/admin-apps/react/variants/base/src/components/app-sidebar.tsx +181 -0
- package/registry/admin-apps/react/variants/base/src/components/breadcrumb.tsx +47 -0
- package/registry/admin-apps/react/variants/base/src/components/change-password-dialog.tsx +102 -0
- package/registry/admin-apps/react/variants/base/src/components/form-error-alert.tsx +23 -0
- package/registry/admin-apps/react/variants/base/src/components/layout/AppShell.tsx +36 -0
- package/registry/admin-apps/react/variants/base/src/components/layout/RequireAuth.tsx +66 -0
- package/registry/admin-apps/react/variants/base/src/components/permission-group-select.tsx +99 -0
- package/registry/admin-apps/react/variants/base/src/components/permission-group-view.tsx +53 -0
- package/registry/admin-apps/react/variants/base/src/components/photo-upload.tsx +221 -0
- package/registry/admin-apps/react/variants/base/src/components/ui/combobox.tsx +243 -0
- package/registry/admin-apps/react/variants/base/src/components/ui/command.tsx +177 -0
- package/registry/admin-apps/react/variants/base/src/components/ui/date-picker.tsx +322 -0
- package/registry/admin-apps/react/variants/base/src/components/ui/sonner.tsx +34 -0
- package/registry/admin-apps/react/variants/base/src/components/user-menu.tsx +65 -0
- package/registry/admin-apps/react/variants/base/src/hooks/use-live-audit-feed.ts +50 -0
- package/registry/admin-apps/react/variants/base/src/index.css +161 -0
- package/registry/admin-apps/react/variants/base/src/lib/ability.ts +72 -0
- package/registry/admin-apps/react/variants/base/src/lib/auth-client.ts +9 -0
- package/registry/admin-apps/react/variants/base/src/lib/theme.tsx +64 -0
- package/registry/admin-apps/react/variants/base/src/lib/token-storage.ts +34 -0
- package/registry/admin-apps/react/variants/base/src/main.tsx +24 -0
- package/registry/admin-apps/react/variants/base/src/pages/AccountPage.tsx +368 -0
- package/registry/admin-apps/react/variants/base/src/pages/AddCountryPage.tsx +227 -0
- package/registry/admin-apps/react/variants/base/src/pages/AddCustomerPage.tsx +220 -0
- package/registry/admin-apps/react/variants/base/src/pages/AddLanguagePage.tsx +167 -0
- package/registry/admin-apps/react/variants/base/src/pages/AddRolePage.tsx +187 -0
- package/registry/admin-apps/react/variants/base/src/pages/AddUserPage.tsx +328 -0
- package/registry/admin-apps/react/variants/base/src/pages/AuditLogPage.tsx +180 -0
- package/registry/admin-apps/react/variants/base/src/pages/CountriesPage.tsx +371 -0
- package/registry/admin-apps/react/variants/base/src/pages/CountryDetailPage.tsx +209 -0
- package/registry/admin-apps/react/variants/base/src/pages/CustomerDetailPage.tsx +231 -0
- package/registry/admin-apps/react/variants/base/src/pages/CustomersPage.tsx +404 -0
- package/registry/admin-apps/react/variants/base/src/pages/DashboardPage.tsx +190 -0
- package/registry/admin-apps/react/variants/base/src/pages/EditCountryPage.tsx +279 -0
- package/registry/admin-apps/react/variants/base/src/pages/EditCustomerPage.tsx +272 -0
- package/registry/admin-apps/react/variants/base/src/pages/EditLanguagePage.tsx +216 -0
- package/registry/admin-apps/react/variants/base/src/pages/EditRolePage.tsx +232 -0
- package/registry/admin-apps/react/variants/base/src/pages/EditUserPage.tsx +308 -0
- package/registry/admin-apps/react/variants/base/src/pages/LanguageDetailPage.tsx +201 -0
- package/registry/admin-apps/react/variants/base/src/pages/LanguagesPage.tsx +346 -0
- package/registry/admin-apps/react/variants/base/src/pages/LoginPage.tsx +149 -0
- package/registry/admin-apps/react/variants/base/src/pages/PermissionDetailPage.tsx +135 -0
- package/registry/admin-apps/react/variants/base/src/pages/PermissionsPage.tsx +331 -0
- package/registry/admin-apps/react/variants/base/src/pages/RoleDetailPage.tsx +167 -0
- package/registry/admin-apps/react/variants/base/src/pages/RolesPage.tsx +613 -0
- package/registry/admin-apps/react/variants/base/src/pages/UserDetailPage.tsx +268 -0
- package/registry/admin-apps/react/variants/base/src/pages/UsersPage.tsx +423 -0
- package/registry/admin-apps/react/variants/base/src/pages/country-schema.ts +29 -0
- package/registry/admin-apps/react/variants/base/src/pages/customer-schema.ts +37 -0
- package/registry/admin-apps/react/variants/base/src/pages/language-schema.ts +28 -0
- package/registry/admin-apps/react/variants/base/src/pages/user-schema.ts +36 -0
- package/registry/admin-apps/react/variants/base/src/stores/auth-store.ts +144 -0
- package/registry/admin-apps/react/variants/base/src/stores/store-context.tsx +15 -0
- package/registry/admin-apps/react/variants/base/vite.config.ts +15 -0
- package/registry/admin-apps/react/variants/workspaces/.env.example +5 -0
- package/registry/admin-apps/react/variants/workspaces/Dockerfile +32 -0
- package/registry/admin-apps/react/variants/workspaces/index.html +12 -0
- package/registry/admin-apps/react/variants/workspaces/package.json +61 -0
- package/registry/admin-apps/react/variants/workspaces/src/App.tsx +118 -0
- package/registry/admin-apps/react/variants/workspaces/src/components/app-sidebar.tsx +186 -0
- package/registry/admin-apps/react/variants/workspaces/src/components/breadcrumb.tsx +39 -0
- package/registry/admin-apps/react/variants/workspaces/src/components/change-password-dialog.tsx +111 -0
- package/registry/admin-apps/react/variants/workspaces/src/components/form-error-alert.tsx +23 -0
- package/registry/admin-apps/react/variants/workspaces/src/components/layout/AppShell.tsx +37 -0
- package/registry/admin-apps/react/variants/workspaces/src/components/layout/CreateWorkspaceDialog.tsx +66 -0
- package/registry/admin-apps/react/variants/workspaces/src/components/layout/RequireAuth.tsx +107 -0
- package/registry/admin-apps/react/variants/workspaces/src/components/layout/WorkspaceSwitcher.tsx +52 -0
- package/registry/admin-apps/react/variants/workspaces/src/components/permission-group-select.tsx +99 -0
- package/registry/admin-apps/react/variants/workspaces/src/components/permission-group-view.tsx +53 -0
- package/registry/admin-apps/react/variants/workspaces/src/components/photo-upload.tsx +223 -0
- package/registry/admin-apps/react/variants/workspaces/src/components/ui/combobox.tsx +243 -0
- package/registry/admin-apps/react/variants/workspaces/src/components/ui/command.tsx +184 -0
- package/registry/admin-apps/react/variants/workspaces/src/components/ui/date-picker.tsx +323 -0
- package/registry/admin-apps/react/variants/workspaces/src/components/ui/sonner.tsx +34 -0
- package/registry/admin-apps/react/variants/workspaces/src/components/user-menu.tsx +66 -0
- package/registry/admin-apps/react/variants/workspaces/src/hooks/use-live-audit-feed.ts +50 -0
- package/registry/admin-apps/react/variants/workspaces/src/index.css +162 -0
- package/registry/admin-apps/react/variants/workspaces/src/lib/ability.ts +78 -0
- package/registry/admin-apps/react/variants/workspaces/src/lib/auth-client.ts +27 -0
- package/registry/admin-apps/react/variants/workspaces/src/lib/permission-groups.ts +22 -0
- package/registry/admin-apps/react/variants/workspaces/src/lib/theme.tsx +64 -0
- package/registry/admin-apps/react/variants/workspaces/src/lib/token-storage.ts +37 -0
- package/registry/admin-apps/react/variants/workspaces/src/lib/user-fields.ts +13 -0
- package/registry/admin-apps/react/variants/workspaces/src/main.tsx +24 -0
- package/registry/admin-apps/react/variants/workspaces/src/pages/AccountPage.tsx +351 -0
- package/registry/admin-apps/react/variants/workspaces/src/pages/AddCountryPage.tsx +230 -0
- package/registry/admin-apps/react/variants/workspaces/src/pages/AddCustomerPage.tsx +224 -0
- package/registry/admin-apps/react/variants/workspaces/src/pages/AddLanguagePage.tsx +170 -0
- package/registry/admin-apps/react/variants/workspaces/src/pages/AddUserPage.tsx +297 -0
- package/registry/admin-apps/react/variants/workspaces/src/pages/AuditLogPage.tsx +195 -0
- package/registry/admin-apps/react/variants/workspaces/src/pages/CountriesPage.tsx +378 -0
- package/registry/admin-apps/react/variants/workspaces/src/pages/CountryDetailPage.tsx +215 -0
- package/registry/admin-apps/react/variants/workspaces/src/pages/CustomerDetailPage.tsx +237 -0
- package/registry/admin-apps/react/variants/workspaces/src/pages/CustomersPage.tsx +411 -0
- package/registry/admin-apps/react/variants/workspaces/src/pages/DashboardPage.tsx +191 -0
- package/registry/admin-apps/react/variants/workspaces/src/pages/EditCountryPage.tsx +285 -0
- package/registry/admin-apps/react/variants/workspaces/src/pages/EditCustomerPage.tsx +279 -0
- package/registry/admin-apps/react/variants/workspaces/src/pages/EditLanguagePage.tsx +222 -0
- package/registry/admin-apps/react/variants/workspaces/src/pages/LanguageDetailPage.tsx +207 -0
- package/registry/admin-apps/react/variants/workspaces/src/pages/LanguagesPage.tsx +353 -0
- package/registry/admin-apps/react/variants/workspaces/src/pages/LoginPage.tsx +149 -0
- package/registry/admin-apps/react/variants/workspaces/src/pages/MembersPage.tsx +349 -0
- package/registry/admin-apps/react/variants/workspaces/src/pages/PermissionDetailPage.tsx +123 -0
- package/registry/admin-apps/react/variants/workspaces/src/pages/PermissionsPage.tsx +317 -0
- package/registry/admin-apps/react/variants/workspaces/src/pages/RoleDetailPage.tsx +207 -0
- package/registry/admin-apps/react/variants/workspaces/src/pages/RolesPage.tsx +617 -0
- package/registry/admin-apps/react/variants/workspaces/src/pages/UserDetailPage.tsx +405 -0
- package/registry/admin-apps/react/variants/workspaces/src/pages/UsersPage.tsx +425 -0
- package/registry/admin-apps/react/variants/workspaces/src/pages/country-schema.ts +29 -0
- package/registry/admin-apps/react/variants/workspaces/src/pages/customer-schema.ts +34 -0
- package/registry/admin-apps/react/variants/workspaces/src/pages/language-schema.ts +27 -0
- package/registry/admin-apps/react/variants/workspaces/src/stores/auth-store.ts +169 -0
- package/registry/admin-apps/react/variants/workspaces/src/stores/store-context.tsx +43 -0
- package/registry/admin-apps/react/variants/workspaces/src/stores/workspace-store.ts +120 -0
- package/registry/admin-apps/react/variants/workspaces/vite.config.ts +15 -0
- package/registry/combos/express-drizzle/package.json +32 -0
- package/registry/combos/express-drizzle/scripts/materialize.mjs +104 -0
- package/registry/combos/express-drizzle/scripts/migrate.mjs +41 -0
- package/registry/combos/express-drizzle/scripts/prove-cycle.mjs +29 -0
- package/registry/combos/express-drizzle/scripts/seed.mjs +25 -0
- package/registry/combos/express-drizzle/shared/drizzle.config.ts +67 -0
- package/registry/combos/express-drizzle/shared/src/ability.ts +44 -0
- package/registry/combos/express-drizzle/shared/src/auth-core-error.middleware.ts +31 -0
- package/registry/combos/express-drizzle/shared/src/auth.config.ts +63 -0
- package/registry/combos/express-drizzle/shared/src/auth.middleware.ts +38 -0
- package/registry/combos/express-drizzle/shared/src/auth.router.ts +266 -0
- package/registry/combos/express-drizzle/shared/src/db.ts +12 -0
- package/registry/combos/express-drizzle/shared/src/http-error.ts +18 -0
- package/registry/combos/express-drizzle/shared/src/id.helper.ts +22 -0
- package/registry/combos/express-drizzle/shared/src/key-provider.ts +52 -0
- package/registry/combos/express-drizzle/shared/src/oauth.repository.ts +47 -0
- package/registry/combos/express-drizzle/shared/src/openapi-fragment.ts +49 -0
- package/registry/combos/express-drizzle/shared/src/openapi-spec.ts +493 -0
- package/registry/combos/express-drizzle/shared/src/pagination.ts +30 -0
- package/registry/combos/express-drizzle/shared/src/password-reset.repository.ts +35 -0
- package/registry/combos/express-drizzle/shared/src/permission-cache.ts +191 -0
- package/registry/combos/express-drizzle/shared/src/rate-limit.store.ts +24 -0
- package/registry/combos/express-drizzle/shared/src/request-context.ts +35 -0
- package/registry/combos/express-drizzle/shared/src/response-envelope.middleware.ts +46 -0
- package/registry/combos/express-drizzle/shared/src/route-tiers.ts +148 -0
- package/registry/combos/express-drizzle/shared/src/session.repository.ts +130 -0
- package/registry/combos/express-drizzle/shared/src/two-factor.repository.ts +38 -0
- package/registry/combos/express-drizzle/test/bootstrap.ts +40 -0
- package/registry/combos/express-drizzle/test/harness.ts +187 -0
- package/registry/combos/express-drizzle/test/prove-cycle.ts +789 -0
- package/registry/combos/express-drizzle/tsconfig.json +20 -0
- package/registry/combos/express-drizzle/variants/base/.env.example +25 -0
- package/registry/combos/express-drizzle/variants/base/drizzle/0000_init.sql +219 -0
- package/registry/combos/express-drizzle/variants/base/drizzle/0001_add_is_active_field.sql +1 -0
- package/registry/combos/express-drizzle/variants/base/drizzle/meta/0000_snapshot.json +1861 -0
- package/registry/combos/express-drizzle/variants/base/drizzle/meta/0001_snapshot.json +1868 -0
- package/registry/combos/express-drizzle/variants/base/drizzle/meta/_journal.json +20 -0
- package/registry/combos/express-drizzle/variants/base/src/admin.router.ts +307 -0
- package/registry/combos/express-drizzle/variants/base/src/audit-log.repository.ts +93 -0
- package/registry/combos/express-drizzle/variants/base/src/auth.service.ts +528 -0
- package/registry/combos/express-drizzle/variants/base/src/authz.middleware.ts +58 -0
- package/registry/combos/express-drizzle/variants/base/src/create-auth-app.ts +78 -0
- package/registry/combos/express-drizzle/variants/base/src/openapi-admin.ts +565 -0
- package/registry/combos/express-drizzle/variants/base/src/rbac.defaults.ts +218 -0
- package/registry/combos/express-drizzle/variants/base/src/rbac.repository.ts +606 -0
- package/registry/combos/express-drizzle/variants/base/src/schema.ts +425 -0
- package/registry/combos/express-drizzle/variants/base/src/seed.ts +138 -0
- package/registry/combos/express-drizzle/variants/base/test/variant-hooks.ts +179 -0
- package/registry/combos/express-drizzle/variants/workspaces/.env.example +30 -0
- package/registry/combos/express-drizzle/variants/workspaces/drizzle/0000_init.sql +251 -0
- package/registry/combos/express-drizzle/variants/workspaces/drizzle/0001_add_is_active_field.sql +1 -0
- package/registry/combos/express-drizzle/variants/workspaces/drizzle/meta/0000_snapshot.json +2155 -0
- package/registry/combos/express-drizzle/variants/workspaces/drizzle/meta/0001_snapshot.json +2162 -0
- package/registry/combos/express-drizzle/variants/workspaces/drizzle/meta/_journal.json +20 -0
- package/registry/combos/express-drizzle/variants/workspaces/src/admin.router.ts +323 -0
- package/registry/combos/express-drizzle/variants/workspaces/src/audit-log.repository.ts +105 -0
- package/registry/combos/express-drizzle/variants/workspaces/src/auth.service.ts +545 -0
- package/registry/combos/express-drizzle/variants/workspaces/src/authz.middleware.ts +94 -0
- package/registry/combos/express-drizzle/variants/workspaces/src/create-auth-app.ts +87 -0
- package/registry/combos/express-drizzle/variants/workspaces/src/openapi-admin.ts +596 -0
- package/registry/combos/express-drizzle/variants/workspaces/src/openapi-workspace.ts +183 -0
- package/registry/combos/express-drizzle/variants/workspaces/src/rbac.defaults.ts +248 -0
- package/registry/combos/express-drizzle/variants/workspaces/src/rbac.repository.ts +698 -0
- package/registry/combos/express-drizzle/variants/workspaces/src/schema.ts +487 -0
- package/registry/combos/express-drizzle/variants/workspaces/src/seed.ts +173 -0
- package/registry/combos/express-drizzle/variants/workspaces/src/workspace.repository.ts +254 -0
- package/registry/combos/express-drizzle/variants/workspaces/src/workspace.router.ts +123 -0
- package/registry/combos/express-drizzle/variants/workspaces/test/variant-hooks.ts +370 -0
- package/registry/combos/express-prisma/package.json +32 -0
- package/registry/combos/express-prisma/scripts/materialize.mjs +84 -0
- package/registry/combos/express-prisma/scripts/migrate.mjs +32 -0
- package/registry/combos/express-prisma/scripts/prove-cycle.mjs +30 -0
- package/registry/combos/express-prisma/scripts/seed.mjs +24 -0
- package/registry/combos/express-prisma/shared/prisma.config.ts +38 -0
- package/registry/combos/express-prisma/shared/src/ability.ts +44 -0
- package/registry/combos/express-prisma/shared/src/auth-core-error.middleware.ts +31 -0
- package/registry/combos/express-prisma/shared/src/auth.config.ts +63 -0
- package/registry/combos/express-prisma/shared/src/auth.middleware.ts +44 -0
- package/registry/combos/express-prisma/shared/src/auth.router.ts +269 -0
- package/registry/combos/express-prisma/shared/src/http-error.ts +18 -0
- package/registry/combos/express-prisma/shared/src/id.helper.ts +22 -0
- package/registry/combos/express-prisma/shared/src/key-provider.ts +52 -0
- package/registry/combos/express-prisma/shared/src/oauth.repository.ts +33 -0
- package/registry/combos/express-prisma/shared/src/openapi-fragment.ts +49 -0
- package/registry/combos/express-prisma/shared/src/openapi-spec.ts +487 -0
- package/registry/combos/express-prisma/shared/src/pagination.ts +30 -0
- package/registry/combos/express-prisma/shared/src/password-reset.repository.ts +29 -0
- package/registry/combos/express-prisma/shared/src/permission-cache.ts +191 -0
- package/registry/combos/express-prisma/shared/src/rate-limit.store.ts +21 -0
- package/registry/combos/express-prisma/shared/src/request-context.ts +35 -0
- package/registry/combos/express-prisma/shared/src/response-envelope.middleware.ts +46 -0
- package/registry/combos/express-prisma/shared/src/route-tiers.ts +148 -0
- package/registry/combos/express-prisma/shared/src/session.repository.ts +140 -0
- package/registry/combos/express-prisma/shared/src/two-factor.repository.ts +30 -0
- package/registry/combos/express-prisma/test/bootstrap.ts +45 -0
- package/registry/combos/express-prisma/test/harness.ts +187 -0
- package/registry/combos/express-prisma/test/prove-cycle.ts +793 -0
- package/registry/combos/express-prisma/tsconfig.json +21 -0
- package/registry/combos/express-prisma/variants/base/.env.example +25 -0
- package/registry/combos/express-prisma/variants/base/prisma/migrations/20260810165456_init/migration.sql +370 -0
- package/registry/combos/express-prisma/variants/base/prisma/migrations/20260811151048_add_is_active_field/migration.sql +2 -0
- package/registry/combos/express-prisma/variants/base/prisma/migrations/migration_lock.toml +3 -0
- package/registry/combos/express-prisma/variants/base/prisma/schema/simple-auth-kit.prisma +332 -0
- package/registry/combos/express-prisma/variants/base/src/admin.router.ts +314 -0
- package/registry/combos/express-prisma/variants/base/src/audit-log.repository.ts +91 -0
- package/registry/combos/express-prisma/variants/base/src/auth.service.ts +521 -0
- package/registry/combos/express-prisma/variants/base/src/authz.middleware.ts +58 -0
- package/registry/combos/express-prisma/variants/base/src/create-auth-app.ts +93 -0
- package/registry/combos/express-prisma/variants/base/src/openapi-admin.ts +569 -0
- package/registry/combos/express-prisma/variants/base/src/rbac.defaults.ts +195 -0
- package/registry/combos/express-prisma/variants/base/src/rbac.repository.ts +484 -0
- package/registry/combos/express-prisma/variants/base/src/seed.ts +115 -0
- package/registry/combos/express-prisma/variants/base/test/variant-hooks.ts +159 -0
- package/registry/combos/express-prisma/variants/workspaces/.env.example +30 -0
- package/registry/combos/express-prisma/variants/workspaces/prisma/migrations/20260810165502_init/migration.sql +443 -0
- package/registry/combos/express-prisma/variants/workspaces/prisma/migrations/20260811151051_add_is_active_field/migration.sql +2 -0
- package/registry/combos/express-prisma/variants/workspaces/prisma/migrations/migration_lock.toml +3 -0
- package/registry/combos/express-prisma/variants/workspaces/prisma/schema/simple-auth-kit.prisma +394 -0
- package/registry/combos/express-prisma/variants/workspaces/src/admin.router.ts +330 -0
- package/registry/combos/express-prisma/variants/workspaces/src/audit-log.repository.ts +102 -0
- package/registry/combos/express-prisma/variants/workspaces/src/auth.service.ts +542 -0
- package/registry/combos/express-prisma/variants/workspaces/src/authz.middleware.ts +94 -0
- package/registry/combos/express-prisma/variants/workspaces/src/create-auth-app.ts +99 -0
- package/registry/combos/express-prisma/variants/workspaces/src/openapi-admin.ts +601 -0
- package/registry/combos/express-prisma/variants/workspaces/src/openapi-workspace.ts +183 -0
- package/registry/combos/express-prisma/variants/workspaces/src/rbac.defaults.ts +222 -0
- package/registry/combos/express-prisma/variants/workspaces/src/rbac.repository.ts +527 -0
- package/registry/combos/express-prisma/variants/workspaces/src/seed.ts +147 -0
- package/registry/combos/express-prisma/variants/workspaces/src/workspace.repository.ts +188 -0
- package/registry/combos/express-prisma/variants/workspaces/src/workspace.router.ts +123 -0
- package/registry/combos/express-prisma/variants/workspaces/test/variant-hooks.ts +358 -0
- package/registry/combos/nestjs-drizzle/package.json +36 -0
- package/registry/combos/nestjs-drizzle/scripts/materialize.mjs +104 -0
- package/registry/combos/nestjs-drizzle/scripts/migrate.mjs +34 -0
- package/registry/combos/nestjs-drizzle/scripts/prove-cycle.mjs +29 -0
- package/registry/combos/nestjs-drizzle/scripts/seed.mjs +24 -0
- package/registry/combos/nestjs-drizzle/shared/drizzle.config.ts +67 -0
- package/registry/combos/nestjs-drizzle/shared/src/ability.guard.ts +46 -0
- package/registry/combos/nestjs-drizzle/shared/src/ability.ts +44 -0
- package/registry/combos/nestjs-drizzle/shared/src/auth-core-error.filter.ts +32 -0
- package/registry/combos/nestjs-drizzle/shared/src/auth.config.ts +65 -0
- package/registry/combos/nestjs-drizzle/shared/src/auth.controller.ts +299 -0
- package/registry/combos/nestjs-drizzle/shared/src/auth.guard.ts +34 -0
- package/registry/combos/nestjs-drizzle/shared/src/db.ts +12 -0
- package/registry/combos/nestjs-drizzle/shared/src/dto/auth.dto.ts +429 -0
- package/registry/combos/nestjs-drizzle/shared/src/id.helper.ts +22 -0
- package/registry/combos/nestjs-drizzle/shared/src/key-provider.ts +51 -0
- package/registry/combos/nestjs-drizzle/shared/src/oauth.repository.ts +36 -0
- package/registry/combos/nestjs-drizzle/shared/src/pagination.ts +30 -0
- package/registry/combos/nestjs-drizzle/shared/src/password-reset.repository.ts +29 -0
- package/registry/combos/nestjs-drizzle/shared/src/permission-cache.ts +196 -0
- package/registry/combos/nestjs-drizzle/shared/src/rate-limit.store.ts +26 -0
- package/registry/combos/nestjs-drizzle/shared/src/request-context.ts +25 -0
- package/registry/combos/nestjs-drizzle/shared/src/response.interceptor.ts +48 -0
- package/registry/combos/nestjs-drizzle/shared/src/route-tiers.ts +144 -0
- package/registry/combos/nestjs-drizzle/shared/src/session.repository.ts +132 -0
- package/registry/combos/nestjs-drizzle/shared/src/two-factor.repository.ts +35 -0
- package/registry/combos/nestjs-drizzle/test/bootstrap.ts +49 -0
- package/registry/combos/nestjs-drizzle/test/harness.ts +187 -0
- package/registry/combos/nestjs-drizzle/test/prove-cycle.ts +795 -0
- package/registry/combos/nestjs-drizzle/tsconfig.json +20 -0
- package/registry/combos/nestjs-drizzle/variants/base/.env.example +25 -0
- package/registry/combos/nestjs-drizzle/variants/base/drizzle/0000_init.sql +219 -0
- package/registry/combos/nestjs-drizzle/variants/base/drizzle/0001_add_is_active_field.sql +1 -0
- package/registry/combos/nestjs-drizzle/variants/base/drizzle/0002_colossal_true_believers.sql +3 -0
- package/registry/combos/nestjs-drizzle/variants/base/drizzle/meta/0000_snapshot.json +1861 -0
- package/registry/combos/nestjs-drizzle/variants/base/drizzle/meta/0001_snapshot.json +1868 -0
- package/registry/combos/nestjs-drizzle/variants/base/drizzle/meta/0002_snapshot.json +1887 -0
- package/registry/combos/nestjs-drizzle/variants/base/drizzle/meta/_journal.json +27 -0
- package/registry/combos/nestjs-drizzle/variants/base/src/admin.controller.ts +361 -0
- package/registry/combos/nestjs-drizzle/variants/base/src/audit-log.repository.ts +90 -0
- package/registry/combos/nestjs-drizzle/variants/base/src/auth.module.ts +83 -0
- package/registry/combos/nestjs-drizzle/variants/base/src/auth.service.ts +544 -0
- package/registry/combos/nestjs-drizzle/variants/base/src/authz.guard.ts +53 -0
- package/registry/combos/nestjs-drizzle/variants/base/src/dto/admin.dto.ts +130 -0
- package/registry/combos/nestjs-drizzle/variants/base/src/rbac.defaults.ts +218 -0
- package/registry/combos/nestjs-drizzle/variants/base/src/rbac.repository.ts +633 -0
- package/registry/combos/nestjs-drizzle/variants/base/src/schema.ts +427 -0
- package/registry/combos/nestjs-drizzle/variants/base/src/seed.ts +138 -0
- package/registry/combos/nestjs-drizzle/variants/base/test/variant-hooks.ts +179 -0
- package/registry/combos/nestjs-drizzle/variants/workspaces/.env.example +30 -0
- package/registry/combos/nestjs-drizzle/variants/workspaces/drizzle/0000_init.sql +251 -0
- package/registry/combos/nestjs-drizzle/variants/workspaces/drizzle/0001_add_is_active_field.sql +1 -0
- package/registry/combos/nestjs-drizzle/variants/workspaces/drizzle/0002_calm_tyger_tiger.sql +3 -0
- package/registry/combos/nestjs-drizzle/variants/workspaces/drizzle/meta/0000_snapshot.json +2155 -0
- package/registry/combos/nestjs-drizzle/variants/workspaces/drizzle/meta/0001_snapshot.json +2162 -0
- package/registry/combos/nestjs-drizzle/variants/workspaces/drizzle/meta/0002_snapshot.json +2181 -0
- package/registry/combos/nestjs-drizzle/variants/workspaces/drizzle/meta/_journal.json +27 -0
- package/registry/combos/nestjs-drizzle/variants/workspaces/src/admin.controller.ts +383 -0
- package/registry/combos/nestjs-drizzle/variants/workspaces/src/audit-log.repository.ts +102 -0
- package/registry/combos/nestjs-drizzle/variants/workspaces/src/auth.module.ts +87 -0
- package/registry/combos/nestjs-drizzle/variants/workspaces/src/auth.service.ts +553 -0
- package/registry/combos/nestjs-drizzle/variants/workspaces/src/authz.guard.ts +87 -0
- package/registry/combos/nestjs-drizzle/variants/workspaces/src/dto/admin.dto.ts +137 -0
- package/registry/combos/nestjs-drizzle/variants/workspaces/src/dto/workspace.dto.ts +60 -0
- package/registry/combos/nestjs-drizzle/variants/workspaces/src/rbac.defaults.ts +248 -0
- package/registry/combos/nestjs-drizzle/variants/workspaces/src/rbac.repository.ts +719 -0
- package/registry/combos/nestjs-drizzle/variants/workspaces/src/schema.ts +489 -0
- package/registry/combos/nestjs-drizzle/variants/workspaces/src/seed.ts +174 -0
- package/registry/combos/nestjs-drizzle/variants/workspaces/src/workspace.controller.ts +123 -0
- package/registry/combos/nestjs-drizzle/variants/workspaces/src/workspace.repository.ts +255 -0
- package/registry/combos/nestjs-drizzle/variants/workspaces/test/variant-hooks.ts +370 -0
- package/registry/combos/nestjs-prisma/package.json +41 -0
- package/registry/combos/nestjs-prisma/scripts/materialize.mjs +84 -0
- package/registry/combos/nestjs-prisma/scripts/migrate.mjs +32 -0
- package/registry/combos/nestjs-prisma/scripts/prove-cycle.mjs +30 -0
- package/registry/combos/nestjs-prisma/scripts/seed.mjs +24 -0
- package/registry/combos/nestjs-prisma/shared/prisma.config.ts +38 -0
- package/registry/combos/nestjs-prisma/shared/src/ability.guard.ts +29 -0
- package/registry/combos/nestjs-prisma/shared/src/ability.ts +23 -0
- package/registry/combos/nestjs-prisma/shared/src/auth-core-error.filter.ts +32 -0
- package/registry/combos/nestjs-prisma/shared/src/auth.config.ts +71 -0
- package/registry/combos/nestjs-prisma/shared/src/auth.controller.ts +303 -0
- package/registry/combos/nestjs-prisma/shared/src/auth.guard.ts +31 -0
- package/registry/combos/nestjs-prisma/shared/src/dto/auth.dto.ts +438 -0
- package/registry/combos/nestjs-prisma/shared/src/id.helper.ts +22 -0
- package/registry/combos/nestjs-prisma/shared/src/key-provider.ts +42 -0
- package/registry/combos/nestjs-prisma/shared/src/oauth.repository.ts +32 -0
- package/registry/combos/nestjs-prisma/shared/src/pagination.ts +30 -0
- package/registry/combos/nestjs-prisma/shared/src/password-reset.repository.ts +29 -0
- package/registry/combos/nestjs-prisma/shared/src/permission-cache.ts +140 -0
- package/registry/combos/nestjs-prisma/shared/src/rate-limit.store.ts +26 -0
- package/registry/combos/nestjs-prisma/shared/src/request-context.ts +19 -0
- package/registry/combos/nestjs-prisma/shared/src/response.interceptor.ts +48 -0
- package/registry/combos/nestjs-prisma/shared/src/route-tiers.ts +102 -0
- package/registry/combos/nestjs-prisma/shared/src/session.repository.ts +129 -0
- package/registry/combos/nestjs-prisma/shared/src/two-factor.repository.ts +29 -0
- package/registry/combos/nestjs-prisma/test/bootstrap.ts +54 -0
- package/registry/combos/nestjs-prisma/test/harness.ts +186 -0
- package/registry/combos/nestjs-prisma/test/prove-cycle.ts +795 -0
- package/registry/combos/nestjs-prisma/tsconfig.json +21 -0
- package/registry/combos/nestjs-prisma/variants/base/.env.example +31 -0
- package/registry/combos/nestjs-prisma/variants/base/prisma/migrations/20260810084937_init/migration.sql +269 -0
- package/registry/combos/nestjs-prisma/variants/base/prisma/migrations/20260810122546_add_profile_audit_soft_delete/migration.sql +96 -0
- package/registry/combos/nestjs-prisma/variants/base/prisma/migrations/20260810123620_add_display_name/migration.sql +3 -0
- package/registry/combos/nestjs-prisma/variants/base/prisma/migrations/20260810131421_drop_signing_keys/migration.sql +3 -0
- package/registry/combos/nestjs-prisma/variants/base/prisma/migrations/20260810161515_bigint_ids/migration.sql +305 -0
- package/registry/combos/nestjs-prisma/variants/base/prisma/migrations/20260810162120_drop_name_unique/migration.sql +6 -0
- package/registry/combos/nestjs-prisma/variants/base/prisma/migrations/20260811145755_add_is_active_field/migration.sql +2 -0
- package/registry/combos/nestjs-prisma/variants/base/prisma/migrations/20260811183529_add_countries_languages_customers/migration.sql +146 -0
- package/registry/combos/nestjs-prisma/variants/base/prisma/migrations/20260812121128_add_user_profile_details/migration.sql +4 -0
- package/registry/combos/nestjs-prisma/variants/base/prisma/migrations/migration_lock.toml +3 -0
- package/registry/combos/nestjs-prisma/variants/base/prisma/schema/simple-auth-kit.prisma +437 -0
- package/registry/combos/nestjs-prisma/variants/base/src/admin.controller.ts +684 -0
- package/registry/combos/nestjs-prisma/variants/base/src/audit-log.gateway.ts +51 -0
- package/registry/combos/nestjs-prisma/variants/base/src/audit-log.repository.ts +111 -0
- package/registry/combos/nestjs-prisma/variants/base/src/auth.module.ts +87 -0
- package/registry/combos/nestjs-prisma/variants/base/src/auth.service.ts +618 -0
- package/registry/combos/nestjs-prisma/variants/base/src/authz.guard.ts +34 -0
- package/registry/combos/nestjs-prisma/variants/base/src/country.repository.ts +149 -0
- package/registry/combos/nestjs-prisma/variants/base/src/customer.repository.ts +169 -0
- package/registry/combos/nestjs-prisma/variants/base/src/docs.ts +60 -0
- package/registry/combos/nestjs-prisma/variants/base/src/dto/admin.dto.ts +130 -0
- package/registry/combos/nestjs-prisma/variants/base/src/dto/country.dto.ts +120 -0
- package/registry/combos/nestjs-prisma/variants/base/src/dto/customer.dto.ts +147 -0
- package/registry/combos/nestjs-prisma/variants/base/src/dto/language.dto.ts +93 -0
- package/registry/combos/nestjs-prisma/variants/base/src/language.repository.ts +135 -0
- package/registry/combos/nestjs-prisma/variants/base/src/rbac.defaults.ts +193 -0
- package/registry/combos/nestjs-prisma/variants/base/src/rbac.repository.ts +514 -0
- package/registry/combos/nestjs-prisma/variants/base/src/seed.ts +89 -0
- package/registry/combos/nestjs-prisma/variants/base/test/variant-hooks.ts +135 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/.env.example +30 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/prisma/migrations/20260810084938_init/migration.sql +308 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/prisma/migrations/20260810123450_add_profile_audit_soft_delete/migration.sql +96 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/prisma/migrations/20260810123632_add_display_name/migration.sql +3 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/prisma/migrations/20260810124243_workspace_audit_soft_delete/migration.sql +25 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/prisma/migrations/20260810131432_drop_signing_keys/migration.sql +3 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/prisma/migrations/20260810161551_bigint_ids/migration.sql +393 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/prisma/migrations/20260810162131_drop_name_unique/migration.sql +3 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/prisma/migrations/20260811145805_add_is_active_field/migration.sql +2 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/prisma/migrations/20260813120000_add_countries_languages_customers/migration.sql +158 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/prisma/migrations/migration_lock.toml +3 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/prisma/schema/simple-auth-kit.prisma +521 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/src/admin.controller.ts +733 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/src/audit-log.repository.ts +98 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/src/auth.module.ts +83 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/src/auth.service.ts +509 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/src/authz.guard.ts +69 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/src/country.repository.ts +158 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/src/customer.repository.ts +179 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/src/dto/admin.dto.ts +128 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/src/dto/country.dto.ts +120 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/src/dto/customer.dto.ts +147 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/src/dto/language.dto.ts +93 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/src/dto/workspace.dto.ts +60 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/src/language.repository.ts +143 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/src/rbac.defaults.ts +211 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/src/rbac.repository.ts +505 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/src/seed.ts +122 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/src/workspace.controller.ts +111 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/src/workspace.repository.ts +177 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/test/variant-hooks.ts +333 -0
- package/registry/core/crypto.ts +43 -0
- package/registry/core/oauth.ts +159 -0
- package/registry/core/package.json +20 -0
- package/registry/core/password-reset.ts +42 -0
- package/registry/core/rate-limit.ts +33 -0
- package/registry/core/rbac.ts +4 -0
- package/registry/core/session-policy.ts +96 -0
- package/registry/core/test/crypto.test.ts +25 -0
- package/registry/core/test/oauth.test.ts +213 -0
- package/registry/core/test/password-reset.test.ts +77 -0
- package/registry/core/test/rate-limit.test.ts +41 -0
- package/registry/core/test/rbac.test.ts +20 -0
- package/registry/core/test/session-policy.test.ts +209 -0
- package/registry/core/test/test-keys.ts +6 -0
- package/registry/core/test/token-service.test.ts +81 -0
- package/registry/core/test/two-factor.test.ts +72 -0
- package/registry/core/token-service.ts +143 -0
- package/registry/core/tsconfig.json +5 -0
- package/registry/core/two-factor.ts +108 -0
- package/registry/core/types.ts +127 -0
- package/registry/mobile-apps/README.md +65 -0
- package/registry/mobile-apps/bare-rn/shared/.bundle/config +2 -0
- package/registry/mobile-apps/bare-rn/shared/.eslintrc.js +4 -0
- package/registry/mobile-apps/bare-rn/shared/.prettierrc.js +5 -0
- package/registry/mobile-apps/bare-rn/shared/.watchmanconfig +1 -0
- package/registry/mobile-apps/bare-rn/shared/App.tsx +28 -0
- package/registry/mobile-apps/bare-rn/shared/Gemfile +17 -0
- package/registry/mobile-apps/bare-rn/shared/README.md +97 -0
- package/registry/mobile-apps/bare-rn/shared/__mocks__/reactNativeConfigMock.js +3 -0
- package/registry/mobile-apps/bare-rn/shared/__mocks__/styleMock.js +1 -0
- package/registry/mobile-apps/bare-rn/shared/__tests__/App.test.tsx +13 -0
- package/registry/mobile-apps/bare-rn/shared/android/app/build.gradle +121 -0
- package/registry/mobile-apps/bare-rn/shared/android/app/debug.keystore +0 -0
- package/registry/mobile-apps/bare-rn/shared/android/app/proguard-rules.pro +10 -0
- package/registry/mobile-apps/bare-rn/shared/android/app/src/main/AndroidManifest.xml +27 -0
- package/registry/mobile-apps/bare-rn/shared/android/app/src/main/java/com/mobilebarern/MainActivity.kt +22 -0
- package/registry/mobile-apps/bare-rn/shared/android/app/src/main/java/com/mobilebarern/MainApplication.kt +27 -0
- package/registry/mobile-apps/bare-rn/shared/android/app/src/main/res/drawable/rn_edit_text_material.xml +37 -0
- package/registry/mobile-apps/bare-rn/shared/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- package/registry/mobile-apps/bare-rn/shared/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
- package/registry/mobile-apps/bare-rn/shared/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- package/registry/mobile-apps/bare-rn/shared/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
- package/registry/mobile-apps/bare-rn/shared/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- package/registry/mobile-apps/bare-rn/shared/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- package/registry/mobile-apps/bare-rn/shared/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- package/registry/mobile-apps/bare-rn/shared/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- package/registry/mobile-apps/bare-rn/shared/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- package/registry/mobile-apps/bare-rn/shared/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
- package/registry/mobile-apps/bare-rn/shared/android/app/src/main/res/values/strings.xml +3 -0
- package/registry/mobile-apps/bare-rn/shared/android/app/src/main/res/values/styles.xml +9 -0
- package/registry/mobile-apps/bare-rn/shared/android/build.gradle +21 -0
- package/registry/mobile-apps/bare-rn/shared/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/registry/mobile-apps/bare-rn/shared/android/gradle/wrapper/gradle-wrapper.properties +7 -0
- package/registry/mobile-apps/bare-rn/shared/android/gradle.properties +44 -0
- package/registry/mobile-apps/bare-rn/shared/android/gradlew +248 -0
- package/registry/mobile-apps/bare-rn/shared/android/gradlew.bat +98 -0
- package/registry/mobile-apps/bare-rn/shared/android/settings.gradle +6 -0
- package/registry/mobile-apps/bare-rn/shared/app.json +4 -0
- package/registry/mobile-apps/bare-rn/shared/babel.config.js +6 -0
- package/registry/mobile-apps/bare-rn/shared/global.css +2 -0
- package/registry/mobile-apps/bare-rn/shared/index.js +10 -0
- package/registry/mobile-apps/bare-rn/shared/ios/.xcode.env +11 -0
- package/registry/mobile-apps/bare-rn/shared/ios/MobileBareRn/AppDelegate.swift +48 -0
- package/registry/mobile-apps/bare-rn/shared/ios/MobileBareRn/Images.xcassets/AppIcon.appiconset/Contents.json +53 -0
- package/registry/mobile-apps/bare-rn/shared/ios/MobileBareRn/Images.xcassets/Contents.json +6 -0
- package/registry/mobile-apps/bare-rn/shared/ios/MobileBareRn/Info.plist +59 -0
- package/registry/mobile-apps/bare-rn/shared/ios/MobileBareRn/LaunchScreen.storyboard +47 -0
- package/registry/mobile-apps/bare-rn/shared/ios/MobileBareRn/PrivacyInfo.xcprivacy +37 -0
- package/registry/mobile-apps/bare-rn/shared/ios/MobileBareRn.xcodeproj/project.pbxproj +475 -0
- package/registry/mobile-apps/bare-rn/shared/ios/MobileBareRn.xcodeproj/xcshareddata/xcschemes/MobileBareRn.xcscheme +88 -0
- package/registry/mobile-apps/bare-rn/shared/ios/Podfile +34 -0
- package/registry/mobile-apps/bare-rn/shared/jest.config.js +17 -0
- package/registry/mobile-apps/bare-rn/shared/metro.config.js +55 -0
- package/registry/mobile-apps/bare-rn/shared/nativewind-env.d.ts +1 -0
- package/registry/mobile-apps/bare-rn/shared/src/api/tokenStorage.ts +29 -0
- package/registry/mobile-apps/bare-rn/shared/src/components/FormInput.tsx +21 -0
- package/registry/mobile-apps/bare-rn/shared/src/components/PrimaryButton.tsx +47 -0
- package/registry/mobile-apps/bare-rn/shared/src/screens/LoginScreen.tsx +58 -0
- package/registry/mobile-apps/bare-rn/shared/src/screens/SessionsScreen.tsx +77 -0
- package/registry/mobile-apps/bare-rn/shared/src/screens/SignupScreen.tsx +54 -0
- package/registry/mobile-apps/bare-rn/shared/src/screens/TwoFactorScreen.tsx +59 -0
- package/registry/mobile-apps/bare-rn/shared/tailwind.config.js +9 -0
- package/registry/mobile-apps/bare-rn/shared/tsconfig.json +17 -0
- package/registry/mobile-apps/bare-rn/variants/base/package.json +58 -0
- package/registry/mobile-apps/bare-rn/variants/base/src/api/authClient.ts +14 -0
- package/registry/mobile-apps/bare-rn/variants/base/src/navigation/RootNavigator.tsx +58 -0
- package/registry/mobile-apps/bare-rn/variants/base/src/navigation/types.ts +15 -0
- package/registry/mobile-apps/bare-rn/variants/base/src/screens/HomeScreen.tsx +64 -0
- package/registry/mobile-apps/bare-rn/variants/base/src/store/authStore.ts +143 -0
- package/registry/mobile-apps/bare-rn/variants/workspaces/package.json +58 -0
- package/registry/mobile-apps/bare-rn/variants/workspaces/src/api/authClient.ts +22 -0
- package/registry/mobile-apps/bare-rn/variants/workspaces/src/navigation/RootNavigator.tsx +72 -0
- package/registry/mobile-apps/bare-rn/variants/workspaces/src/navigation/types.ts +18 -0
- package/registry/mobile-apps/bare-rn/variants/workspaces/src/screens/HomeScreen.tsx +85 -0
- package/registry/mobile-apps/bare-rn/variants/workspaces/src/screens/WorkspaceSelectScreen.tsx +165 -0
- package/registry/mobile-apps/bare-rn/variants/workspaces/src/store/authStore.ts +177 -0
- package/registry/mobile-apps/bare-rn/variants/workspaces/src/store/workspaceStore.ts +90 -0
- package/registry/mobile-apps/bare-rn/variants/workspaces/src/workspace/activeWorkspace.ts +55 -0
- package/registry/mobile-apps/expo/shared/App.tsx +15 -0
- package/registry/mobile-apps/expo/shared/assets/android-icon-background.png +0 -0
- package/registry/mobile-apps/expo/shared/assets/android-icon-foreground.png +0 -0
- package/registry/mobile-apps/expo/shared/assets/android-icon-monochrome.png +0 -0
- package/registry/mobile-apps/expo/shared/assets/favicon.png +0 -0
- package/registry/mobile-apps/expo/shared/assets/icon.png +0 -0
- package/registry/mobile-apps/expo/shared/assets/splash-icon.png +0 -0
- package/registry/mobile-apps/expo/shared/babel.config.js +6 -0
- package/registry/mobile-apps/expo/shared/global.css +2 -0
- package/registry/mobile-apps/expo/shared/index.ts +8 -0
- package/registry/mobile-apps/expo/shared/metro.config.js +6 -0
- package/registry/mobile-apps/expo/shared/nativewind-env.d.ts +3 -0
- package/registry/mobile-apps/expo/shared/postcss.config.mjs +5 -0
- package/registry/mobile-apps/expo/shared/src/screens/LoginScreen.tsx +81 -0
- package/registry/mobile-apps/expo/shared/src/screens/SessionsScreen.tsx +77 -0
- package/registry/mobile-apps/expo/shared/src/screens/SignupScreen.tsx +77 -0
- package/registry/mobile-apps/expo/shared/src/screens/TwoFactorScreen.tsx +59 -0
- package/registry/mobile-apps/expo/shared/src/storage/asyncStorageTokenStorage.ts +32 -0
- package/registry/mobile-apps/expo/shared/tsconfig.json +6 -0
- package/registry/mobile-apps/expo/variants/base/app.json +25 -0
- package/registry/mobile-apps/expo/variants/base/package.json +35 -0
- package/registry/mobile-apps/expo/variants/base/src/api/authClient.ts +17 -0
- package/registry/mobile-apps/expo/variants/base/src/navigation/RootNavigator.tsx +58 -0
- package/registry/mobile-apps/expo/variants/base/src/navigation/types.ts +10 -0
- package/registry/mobile-apps/expo/variants/base/src/screens/HomeScreen.tsx +75 -0
- package/registry/mobile-apps/expo/variants/base/src/store/authStore.ts +146 -0
- package/registry/mobile-apps/expo/variants/workspaces/app.json +25 -0
- package/registry/mobile-apps/expo/variants/workspaces/package.json +35 -0
- package/registry/mobile-apps/expo/variants/workspaces/src/api/authClient.ts +21 -0
- package/registry/mobile-apps/expo/variants/workspaces/src/navigation/RootNavigator.tsx +82 -0
- package/registry/mobile-apps/expo/variants/workspaces/src/navigation/types.ts +20 -0
- package/registry/mobile-apps/expo/variants/workspaces/src/screens/HomeScreen.tsx +94 -0
- package/registry/mobile-apps/expo/variants/workspaces/src/screens/WorkspaceSelectScreen.tsx +175 -0
- package/registry/mobile-apps/expo/variants/workspaces/src/store/authStore.ts +179 -0
- package/registry/mobile-apps/expo/variants/workspaces/src/store/workspaceStore.ts +90 -0
- package/registry/mobile-apps/expo/variants/workspaces/src/workspace/activeWorkspace.ts +55 -0
- package/registry.json +263 -0
- package/simple-auth-kit.ts +715 -0
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
import { resolvePermissions } from "@/lib/auth/core/rbac.js";
|
|
2
|
+
import { Prisma, PrismaClient } from "../generated/prisma/client.js";
|
|
3
|
+
import type { AuthzContext } from "./authz.middleware.js";
|
|
4
|
+
import { HttpError } from "./http-error.js";
|
|
5
|
+
import { buildPageMeta, normalizeLimit, normalizePage, type Paginated } from "./pagination.js";
|
|
6
|
+
import { PermissionCache } from "./permission-cache.js";
|
|
7
|
+
import { toId, toIdOrNull } from "./id.helper.js";
|
|
8
|
+
|
|
9
|
+
export interface MemberSummary {
|
|
10
|
+
memberId: string;
|
|
11
|
+
userId: string;
|
|
12
|
+
uuid: string;
|
|
13
|
+
email: string;
|
|
14
|
+
firstName: string | null;
|
|
15
|
+
lastName: string | null;
|
|
16
|
+
displayName: string | null;
|
|
17
|
+
phone: string | null;
|
|
18
|
+
username: string | null;
|
|
19
|
+
photo: string | null;
|
|
20
|
+
lastLogin: string | null;
|
|
21
|
+
blocked: boolean;
|
|
22
|
+
isActive: boolean;
|
|
23
|
+
twoFactorEnabled: boolean;
|
|
24
|
+
roles: string[];
|
|
25
|
+
createdBy: string | null;
|
|
26
|
+
updatedBy: string | null;
|
|
27
|
+
createdAt: string;
|
|
28
|
+
updatedAt: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface MemberListFilter {
|
|
32
|
+
search?: string;
|
|
33
|
+
page?: number;
|
|
34
|
+
limit?: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type MemberListResult = Paginated<MemberSummary>;
|
|
38
|
+
|
|
39
|
+
const MEMBER_INCLUDE = { user: true, roles: { select: { role: { select: { slug: true } } } } } as const;
|
|
40
|
+
|
|
41
|
+
/** A `WorkspaceMember` row as `findUnique`/`findMany` return it, joined with its user and roles. */
|
|
42
|
+
export type MemberRow = Prisma.WorkspaceMemberGetPayload<{ include: typeof MEMBER_INCLUDE }>;
|
|
43
|
+
|
|
44
|
+
/** Shapes a raw row into the wire DTO. Exported so `listMembers`'s collection can be shaped by the caller. */
|
|
45
|
+
export function toMemberSummary(row: MemberRow): MemberSummary {
|
|
46
|
+
return {
|
|
47
|
+
memberId: row.id.toString(),
|
|
48
|
+
userId: row.userId.toString(),
|
|
49
|
+
uuid: row.user.uuid,
|
|
50
|
+
email: row.user.email,
|
|
51
|
+
firstName: row.user.firstName,
|
|
52
|
+
lastName: row.user.lastName,
|
|
53
|
+
displayName: row.user.displayName,
|
|
54
|
+
phone: row.user.phone,
|
|
55
|
+
username: row.user.username,
|
|
56
|
+
photo: row.user.photo,
|
|
57
|
+
lastLogin: row.user.lastLogin?.toISOString() ?? null,
|
|
58
|
+
blocked: row.user.blocked,
|
|
59
|
+
isActive: row.user.isActive,
|
|
60
|
+
twoFactorEnabled: row.user.twoFactorEnabled,
|
|
61
|
+
roles: row.roles.map((r) => r.role.slug).sort(),
|
|
62
|
+
createdBy: row.user.createdBy?.toString() ?? null,
|
|
63
|
+
updatedBy: row.user.updatedBy?.toString() ?? null,
|
|
64
|
+
createdAt: row.createdAt.toISOString(),
|
|
65
|
+
updatedAt: row.user.updatedAt.toISOString(),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** A `Permission` row as the catalog endpoints return it. */
|
|
70
|
+
export interface PermissionSummary {
|
|
71
|
+
id: string;
|
|
72
|
+
slug: string;
|
|
73
|
+
name: string;
|
|
74
|
+
displayName: string;
|
|
75
|
+
description: string | null;
|
|
76
|
+
group: string;
|
|
77
|
+
groupOrder: number;
|
|
78
|
+
order: number;
|
|
79
|
+
isActive: boolean;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface PermissionInput {
|
|
83
|
+
slug: string;
|
|
84
|
+
name?: string;
|
|
85
|
+
displayName?: string;
|
|
86
|
+
description?: string | null;
|
|
87
|
+
group?: string;
|
|
88
|
+
groupOrder?: number;
|
|
89
|
+
order?: number;
|
|
90
|
+
isActive?: boolean;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface RoleSummary {
|
|
94
|
+
id: string;
|
|
95
|
+
slug: string;
|
|
96
|
+
name: string;
|
|
97
|
+
displayName: string;
|
|
98
|
+
isDefault: boolean;
|
|
99
|
+
isActive: boolean;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const PERMISSION_SELECT = {
|
|
103
|
+
id: true,
|
|
104
|
+
slug: true,
|
|
105
|
+
name: true,
|
|
106
|
+
displayName: true,
|
|
107
|
+
description: true,
|
|
108
|
+
group: true,
|
|
109
|
+
groupOrder: true,
|
|
110
|
+
order: true,
|
|
111
|
+
isActive: true,
|
|
112
|
+
} as const;
|
|
113
|
+
|
|
114
|
+
const ROLE_SELECT = { id: true, slug: true, name: true, displayName: true, isDefault: true, isActive: true } as const;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* The cache subject in this variant: authorization belongs to a membership, so the key has to be
|
|
118
|
+
* the pair. The same user in another workspace is a different subject with its own version
|
|
119
|
+
* counter, which is what keeps invalidation in one workspace from flushing the others.
|
|
120
|
+
*
|
|
121
|
+
* It lives here rather than beside `WORKSPACE_HEADER` in authz.guard.ts only to keep the import
|
|
122
|
+
* between the two one-directional — the guard needs this repository at runtime, so the repository
|
|
123
|
+
* must not need the guard.
|
|
124
|
+
*/
|
|
125
|
+
export const memberCacheKey = (userId: string, workspaceId: string) => `${userId}:${workspaceId}`;
|
|
126
|
+
|
|
127
|
+
export class RbacRepository {
|
|
128
|
+
constructor(
|
|
129
|
+
private readonly prisma: PrismaClient,
|
|
130
|
+
private readonly cache: PermissionCache,
|
|
131
|
+
) {}
|
|
132
|
+
|
|
133
|
+
// Every write below ends by bumping a version counter, and which counter is the whole design:
|
|
134
|
+
// a change to one membership's roles or grants bumps only that membership
|
|
135
|
+
// (`invalidateSubject`, keyed on the `userId:workspaceId` pair, so the same person's other
|
|
136
|
+
// workspaces are untouched), while a change to what a role carries, or to whether a permission
|
|
137
|
+
// is active, bumps everyone (`invalidatePolicy`) — because those genuinely do affect every
|
|
138
|
+
// holder, and enumerating them is the fan-out this scheme exists to avoid.
|
|
139
|
+
|
|
140
|
+
/** Invalidates one membership. Public because `WorkspaceRepository` changes memberships too. */
|
|
141
|
+
async invalidateMember(userId: string, workspaceId: string): Promise<void> {
|
|
142
|
+
await this.cache.invalidateSubject(memberCacheKey(userId, workspaceId));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Takes bigint directly: its one caller (setMemberRoles) already has the membership's id in
|
|
146
|
+
// hand from its own Prisma lookup, so there's nothing to parse here.
|
|
147
|
+
private async invalidateMemberById(memberId: bigint): Promise<void> {
|
|
148
|
+
const member = await this.prisma.workspaceMember.findUnique({ where: { id: memberId }, select: { userId: true, workspaceId: true } });
|
|
149
|
+
if (member) await this.invalidateMember(member.userId.toString(), member.workspaceId.toString());
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* The hot path: every workspace-scoped request runs this once.
|
|
154
|
+
*
|
|
155
|
+
* One call, anchored on the `[userId, workspaceId]` unique index — never a scan over the user's
|
|
156
|
+
* workspaces — walking `member → role_member → roles → permission_role → permissions` and
|
|
157
|
+
* `member → permission_member → permissions`. Cost is constant in the number of users and
|
|
158
|
+
* workspaces.
|
|
159
|
+
*
|
|
160
|
+
* Everything it returns belongs to *this* membership, so the answer is workspace-scoped by
|
|
161
|
+
* construction rather than by a second check: the same login in another workspace resolves a
|
|
162
|
+
* different membership and therefore different roles and permissions.
|
|
163
|
+
*
|
|
164
|
+
* `isActive: false` on a role or a permission takes it out of the answer, which is what makes
|
|
165
|
+
* deactivating either one enforcement-changing without unpicking any grant.
|
|
166
|
+
*/
|
|
167
|
+
async resolveAuthzContext(userId: string, workspaceId: string): Promise<AuthzContext | null> {
|
|
168
|
+
// workspaceId arrives straight from the untrusted `X-Workspace-Id` header — a value that
|
|
169
|
+
// isn't a valid bigint is exactly as "not a member" as one that parses but names no
|
|
170
|
+
// membership, so it must not throw and 500 the request.
|
|
171
|
+
let userIdBig: bigint;
|
|
172
|
+
let workspaceIdBig: bigint;
|
|
173
|
+
try {
|
|
174
|
+
userIdBig = toId(userId);
|
|
175
|
+
workspaceIdBig = toId(workspaceId);
|
|
176
|
+
} catch {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const member = await this.prisma.workspaceMember.findUnique({
|
|
181
|
+
where: { userId_workspaceId: { userId: userIdBig, workspaceId: workspaceIdBig }, user: { isDeleted: false } },
|
|
182
|
+
select: {
|
|
183
|
+
id: true,
|
|
184
|
+
roles: {
|
|
185
|
+
where: { role: { isActive: true, isDeleted: false } },
|
|
186
|
+
select: {
|
|
187
|
+
role: {
|
|
188
|
+
select: {
|
|
189
|
+
slug: true,
|
|
190
|
+
permissions: { where: { permission: { isActive: true, isDeleted: false } }, select: { permission: { select: { slug: true } } } },
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
permissions: { where: { permission: { isActive: true, isDeleted: false } }, select: { permission: { select: { slug: true } } } },
|
|
196
|
+
},
|
|
197
|
+
});
|
|
198
|
+
if (!member) return null;
|
|
199
|
+
|
|
200
|
+
const rolePermissions = member.roles.flatMap((roleMember) => roleMember.role.permissions.map((pr) => pr.permission.slug));
|
|
201
|
+
const directPermissions = member.permissions.map((pm) => pm.permission.slug);
|
|
202
|
+
|
|
203
|
+
return {
|
|
204
|
+
workspaceId,
|
|
205
|
+
memberId: member.id.toString(),
|
|
206
|
+
roles: member.roles.map((roleMember) => roleMember.role.slug).sort(),
|
|
207
|
+
permissions: resolvePermissions(rolePermissions, directPermissions),
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Resolves the membership an admin request is acting on. Never crosses a workspace boundary: a
|
|
213
|
+
* caller can only name a target inside their own scope. Returns bigint directly: every internal
|
|
214
|
+
* caller feeds the id straight into another Prisma call, and the one external caller
|
|
215
|
+
* (AuthService) discards the result.
|
|
216
|
+
*/
|
|
217
|
+
async requireMember(workspaceId: string, userId: string): Promise<{ id: bigint }> {
|
|
218
|
+
const member = await this.prisma.workspaceMember.findUnique({
|
|
219
|
+
where: { userId_workspaceId: { userId: toId(userId), workspaceId: toId(workspaceId) } },
|
|
220
|
+
select: { id: true },
|
|
221
|
+
});
|
|
222
|
+
if (!member) throw new HttpError(404, "user is not a member of this workspace");
|
|
223
|
+
return member;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Newest-first, page-paginated; `search` matches an email substring. Returns raw rows —
|
|
228
|
+
* shaping the collection is the caller's job, see `toMemberSummary`.
|
|
229
|
+
*/
|
|
230
|
+
async listMembers(workspaceId: string, filter: MemberListFilter = {}): Promise<Paginated<MemberRow>> {
|
|
231
|
+
const page = normalizePage(filter.page);
|
|
232
|
+
const limit = normalizeLimit(filter.limit);
|
|
233
|
+
const workspaceIdBig = toId(workspaceId);
|
|
234
|
+
const where = {
|
|
235
|
+
workspaceId: workspaceIdBig,
|
|
236
|
+
user: { isDeleted: false, email: filter.search ? { contains: filter.search, mode: "insensitive" as const } : undefined },
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
const [rows, total] = await this.prisma.$transaction([
|
|
240
|
+
this.prisma.workspaceMember.findMany({
|
|
241
|
+
where,
|
|
242
|
+
include: MEMBER_INCLUDE,
|
|
243
|
+
orderBy: [{ createdAt: "desc" }, { id: "desc" }],
|
|
244
|
+
take: limit,
|
|
245
|
+
skip: (page - 1) * limit,
|
|
246
|
+
}),
|
|
247
|
+
this.prisma.workspaceMember.count({ where }),
|
|
248
|
+
]);
|
|
249
|
+
|
|
250
|
+
return { items: rows, meta: buildPageMeta(page, limit, total) };
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Scoped by workspace via `requireMember` — an admin can only fetch a profile belonging to a
|
|
254
|
+
// member of their own workspace. `requireMember` only checks the membership row exists, not
|
|
255
|
+
// the user's own `isDeleted` — checked here too, so a soft-deleted account 404s like any other
|
|
256
|
+
// deleted row rather than surfacing through a membership that technically still exists.
|
|
257
|
+
async getMember(workspaceId: string, userId: string): Promise<MemberSummary> {
|
|
258
|
+
const member = await this.requireMember(workspaceId, userId);
|
|
259
|
+
const row = await this.prisma.workspaceMember.findFirst({
|
|
260
|
+
where: { id: member.id, user: { isDeleted: false } },
|
|
261
|
+
include: MEMBER_INCLUDE,
|
|
262
|
+
});
|
|
263
|
+
if (!row) throw new HttpError(404, `user "${userId}" not found`);
|
|
264
|
+
return toMemberSummary(row);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Profile fields only — email is the login identifier and stays out of this endpoint.
|
|
268
|
+
async updateMember(
|
|
269
|
+
workspaceId: string,
|
|
270
|
+
userId: string,
|
|
271
|
+
input: { firstName?: string | null; lastName?: string | null; displayName?: string | null; phone?: string | null; username?: string | null; photo?: string | null },
|
|
272
|
+
actorUserId: string | null,
|
|
273
|
+
): Promise<MemberSummary> {
|
|
274
|
+
await this.requireMember(workspaceId, userId);
|
|
275
|
+
await this.prisma.user.update({ where: { id: toId(userId) }, data: { ...input, updatedBy: toIdOrNull(actorUserId) } });
|
|
276
|
+
return this.getMember(workspaceId, userId);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Soft-delete, matching every other table's `isDeleted`/`deletedAt`/`deletedBy`/`deletedReason`
|
|
280
|
+
// pattern, and `block`'s existing precedent of a workspace admin taking a global action on a
|
|
281
|
+
// member's account — this disables the account across every workspace it belongs to, not just
|
|
282
|
+
// this one, which is why it's gated the same way `block` is.
|
|
283
|
+
async deleteMember(workspaceId: string, userId: string, actorUserId: string | null, reason?: string): Promise<void> {
|
|
284
|
+
await this.requireMember(workspaceId, userId);
|
|
285
|
+
await this.prisma.user.update({
|
|
286
|
+
where: { id: toId(userId) },
|
|
287
|
+
data: { isDeleted: true, deletedAt: new Date(), deletedBy: toIdOrNull(actorUserId), deletedReason: reason ?? null },
|
|
288
|
+
});
|
|
289
|
+
await this.invalidateMember(userId, workspaceId);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
async updateRole(
|
|
293
|
+
workspaceId: string,
|
|
294
|
+
roleId: string,
|
|
295
|
+
input: { name?: string; displayName?: string; description?: string | null; isActive?: boolean },
|
|
296
|
+
actorUserId: string | null,
|
|
297
|
+
): Promise<RoleSummary> {
|
|
298
|
+
const workspaceIdBig = toId(workspaceId);
|
|
299
|
+
const roleIdBig = toId(roleId);
|
|
300
|
+
const existing = await this.prisma.role.findUnique({ where: { id: roleIdBig, isDeleted: false }, select: { id: true, workspaceId: true } });
|
|
301
|
+
if (!existing || existing.workspaceId !== workspaceIdBig) throw new HttpError(404, "role not found in this workspace");
|
|
302
|
+
const role = await this.prisma.role.update({
|
|
303
|
+
where: { id: roleIdBig },
|
|
304
|
+
data: { ...input, updatedBy: toIdOrNull(actorUserId) },
|
|
305
|
+
select: ROLE_SELECT,
|
|
306
|
+
});
|
|
307
|
+
await this.cache.invalidatePolicy();
|
|
308
|
+
return { ...role, id: role.id.toString() };
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Soft-delete. `role_member`/`permission_role` rows pointing at it are left in place — the
|
|
312
|
+
// role simply stops being resolved by `resolveAuthzContext`/`listRoles`.
|
|
313
|
+
async deleteRole(workspaceId: string, roleId: string, actorUserId: string | null, reason?: string): Promise<void> {
|
|
314
|
+
const workspaceIdBig = toId(workspaceId);
|
|
315
|
+
const roleIdBig = toId(roleId);
|
|
316
|
+
const existing = await this.prisma.role.findUnique({ where: { id: roleIdBig, isDeleted: false }, select: { id: true, workspaceId: true } });
|
|
317
|
+
if (!existing || existing.workspaceId !== workspaceIdBig) throw new HttpError(404, "role not found in this workspace");
|
|
318
|
+
await this.prisma.role.update({
|
|
319
|
+
where: { id: roleIdBig },
|
|
320
|
+
data: { isDeleted: true, deletedAt: new Date(), deletedBy: toIdOrNull(actorUserId), deletedReason: reason ?? null },
|
|
321
|
+
});
|
|
322
|
+
await this.cache.invalidatePolicy();
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// ---- the catalog itself ----
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Every permission this deployment defines, in the order an admin console should render them.
|
|
329
|
+
* The catalog is global, like the `Permission` table: what is scoped to a workspace is which of
|
|
330
|
+
* its roles and memberships point at each row.
|
|
331
|
+
*/
|
|
332
|
+
async listPermissions(): Promise<PermissionSummary[]> {
|
|
333
|
+
const rows = await this.prisma.permission.findMany({
|
|
334
|
+
where: { isDeleted: false },
|
|
335
|
+
select: PERMISSION_SELECT,
|
|
336
|
+
orderBy: [{ groupOrder: "asc" }, { group: "asc" }, { order: "asc" }, { slug: "asc" }],
|
|
337
|
+
});
|
|
338
|
+
return rows.map((row) => ({ ...row, id: row.id.toString() }));
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Defines a permission, or edits one. The write path for "the catalog is editable in the
|
|
343
|
+
* database": a deployment can add a capability of its own, rename one for the console, or set
|
|
344
|
+
* `isActive: false` to take an existing one out of every ability it appears in — all without a
|
|
345
|
+
* deploy, and all visible on the very next request, in every workspace.
|
|
346
|
+
*
|
|
347
|
+
* Upserted on `slug`, which stays the stable identifier grants and revocations use, so renaming
|
|
348
|
+
* `name`/`displayName` never breaks a grant.
|
|
349
|
+
*/
|
|
350
|
+
async upsertPermission(input: PermissionInput, actorUserId: string | null): Promise<PermissionSummary> {
|
|
351
|
+
const shared = {
|
|
352
|
+
name: input.name,
|
|
353
|
+
displayName: input.displayName,
|
|
354
|
+
description: input.description,
|
|
355
|
+
group: input.group,
|
|
356
|
+
groupOrder: input.groupOrder,
|
|
357
|
+
order: input.order,
|
|
358
|
+
isActive: input.isActive,
|
|
359
|
+
updatedBy: toIdOrNull(actorUserId),
|
|
360
|
+
};
|
|
361
|
+
const permission = await this.prisma.permission.upsert({
|
|
362
|
+
where: { slug: input.slug },
|
|
363
|
+
create: {
|
|
364
|
+
slug: input.slug,
|
|
365
|
+
...shared,
|
|
366
|
+
name: input.name ?? input.displayName ?? input.slug,
|
|
367
|
+
displayName: input.displayName ?? input.slug,
|
|
368
|
+
group: input.group ?? "Custom",
|
|
369
|
+
createdBy: toIdOrNull(actorUserId),
|
|
370
|
+
},
|
|
371
|
+
// Only the fields the caller sent are written; `undefined` leaves a column alone, so a
|
|
372
|
+
// partial edit cannot blank out metadata it did not mention.
|
|
373
|
+
update: shared,
|
|
374
|
+
select: PERMISSION_SELECT,
|
|
375
|
+
});
|
|
376
|
+
// `isActive` can change here, and it changes what every holder resolves to, in every workspace.
|
|
377
|
+
await this.cache.invalidatePolicy();
|
|
378
|
+
return { ...permission, id: permission.id.toString() };
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
async listRoles(workspaceId: string): Promise<RoleSummary[]> {
|
|
382
|
+
const rows = await this.prisma.role.findMany({
|
|
383
|
+
where: { workspaceId: toId(workspaceId), isDeleted: false },
|
|
384
|
+
select: ROLE_SELECT,
|
|
385
|
+
orderBy: [{ order: "asc" }, { slug: "asc" }],
|
|
386
|
+
});
|
|
387
|
+
return rows.map((row) => ({ ...row, id: row.id.toString() }));
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
async createRole(
|
|
391
|
+
workspaceId: string,
|
|
392
|
+
input: { slug: string; name?: string; displayName?: string; description?: string | null },
|
|
393
|
+
actorUserId: string | null,
|
|
394
|
+
): Promise<RoleSummary> {
|
|
395
|
+
const role = await this.prisma.role.create({
|
|
396
|
+
data: {
|
|
397
|
+
workspaceId: toId(workspaceId),
|
|
398
|
+
slug: input.slug,
|
|
399
|
+
name: input.name ?? input.displayName ?? input.slug,
|
|
400
|
+
displayName: input.displayName ?? input.slug,
|
|
401
|
+
description: input.description ?? null,
|
|
402
|
+
createdBy: toIdOrNull(actorUserId),
|
|
403
|
+
updatedBy: toIdOrNull(actorUserId),
|
|
404
|
+
},
|
|
405
|
+
select: ROLE_SELECT,
|
|
406
|
+
});
|
|
407
|
+
return { ...role, id: role.id.toString() };
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Scoped by workspace, so an admin cannot reach a role id belonging to a workspace they are not
|
|
412
|
+
* in. A permission slug this deployment never defined is created on the spot: it exists, it can
|
|
413
|
+
* be granted, and it opens nothing until a route names it — and no route shipped by this
|
|
414
|
+
* library can name it, because `@CheckAbility` only accepts slugs from `rbac.defaults.ts`.
|
|
415
|
+
*/
|
|
416
|
+
async attachPermissionToRole(workspaceId: string, roleId: string, permissionSlug: string, actorUserId: string | null): Promise<void> {
|
|
417
|
+
const workspaceIdBig = toId(workspaceId);
|
|
418
|
+
const roleIdBig = toId(roleId);
|
|
419
|
+
const role = await this.prisma.role.findUnique({ where: { id: roleIdBig, isDeleted: false }, select: { id: true, workspaceId: true } });
|
|
420
|
+
if (!role || role.workspaceId !== workspaceIdBig) throw new HttpError(404, "role not found in this workspace");
|
|
421
|
+
|
|
422
|
+
const permission = await this.ensurePermission(permissionSlug, actorUserId);
|
|
423
|
+
await this.prisma.permissionRole.upsert({
|
|
424
|
+
where: { permissionId_roleId: { permissionId: permission.id, roleId: roleIdBig } },
|
|
425
|
+
create: { permissionId: permission.id, roleId: roleIdBig },
|
|
426
|
+
update: {},
|
|
427
|
+
});
|
|
428
|
+
await this.cache.invalidatePolicy(); // every membership holding this role is affected
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
async assignRoleToMember(workspaceId: string, userId: string, roleSlug: string): Promise<void> {
|
|
432
|
+
const role = await this.requireRole(workspaceId, roleSlug);
|
|
433
|
+
const member = await this.requireMember(workspaceId, userId);
|
|
434
|
+
await this.prisma.roleMember.upsert({
|
|
435
|
+
where: { memberId_roleId: { memberId: member.id, roleId: role.id } },
|
|
436
|
+
create: { memberId: member.id, roleId: role.id },
|
|
437
|
+
update: {},
|
|
438
|
+
});
|
|
439
|
+
await this.invalidateMember(userId, workspaceId);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
async revokeRoleFromMember(workspaceId: string, userId: string, roleSlug: string): Promise<void> {
|
|
443
|
+
const member = await this.requireMember(workspaceId, userId);
|
|
444
|
+
const role = await this.prisma.role.findUnique({ where: { workspaceId_slug: { workspaceId: toId(workspaceId), slug: roleSlug } }, select: { id: true } });
|
|
445
|
+
if (!role) return;
|
|
446
|
+
await this.prisma.roleMember.deleteMany({ where: { memberId: member.id, roleId: role.id } });
|
|
447
|
+
await this.invalidateMember(userId, workspaceId);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/** Replaces the whole set — the "set a member's roles" operation, as opposed to assign/revoke one at a time. */
|
|
451
|
+
async setMemberRoles(workspaceId: string, memberId: string, roleSlugs: string[]): Promise<{ memberId: string; roles: string[] }> {
|
|
452
|
+
const workspaceIdBig = toId(workspaceId);
|
|
453
|
+
const memberIdBig = toId(memberId);
|
|
454
|
+
const member = await this.prisma.workspaceMember.findUnique({ where: { id: memberIdBig }, select: { id: true, workspaceId: true } });
|
|
455
|
+
if (!member || member.workspaceId !== workspaceIdBig) throw new HttpError(404, "member not found in this workspace");
|
|
456
|
+
|
|
457
|
+
const roles = await this.prisma.role.findMany({
|
|
458
|
+
where: { workspaceId: workspaceIdBig, slug: { in: roleSlugs }, isDeleted: false },
|
|
459
|
+
select: { id: true, slug: true },
|
|
460
|
+
});
|
|
461
|
+
const unknown = roleSlugs.filter((slug) => !roles.some((role) => role.slug === slug));
|
|
462
|
+
if (unknown.length) throw new HttpError(404, `role(s) not defined in this workspace: ${unknown.join(", ")}`);
|
|
463
|
+
|
|
464
|
+
// Replace, in one transaction: a member must never be briefly role-less to a concurrent request.
|
|
465
|
+
await this.prisma.$transaction([
|
|
466
|
+
this.prisma.roleMember.deleteMany({ where: { memberId: memberIdBig } }),
|
|
467
|
+
this.prisma.roleMember.createMany({ data: roles.map((role) => ({ memberId: memberIdBig, roleId: role.id })), skipDuplicates: true }),
|
|
468
|
+
]);
|
|
469
|
+
await this.invalidateMemberById(memberIdBig);
|
|
470
|
+
return { memberId, roles: roles.map((role) => role.slug).sort() };
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* The roles a brand-new membership starts with — the rows flagged `isDefault` *in this
|
|
475
|
+
* workspace*, not a string literal. Unused by any caller today; kept bigint-native rather than
|
|
476
|
+
* round-tripped through string.
|
|
477
|
+
*/
|
|
478
|
+
async defaultRoleIdsFor(workspaceId: string): Promise<bigint[]> {
|
|
479
|
+
const roles = await this.prisma.role.findMany({
|
|
480
|
+
where: { workspaceId: toId(workspaceId), isDefault: true, isActive: true, isDeleted: false },
|
|
481
|
+
select: { id: true },
|
|
482
|
+
});
|
|
483
|
+
return roles.map((role) => role.id);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
async grantPermissionToMember(workspaceId: string, userId: string, permissionSlug: string, actorUserId: string | null): Promise<void> {
|
|
487
|
+
const member = await this.requireMember(workspaceId, userId);
|
|
488
|
+
const permission = await this.ensurePermission(permissionSlug, actorUserId);
|
|
489
|
+
await this.prisma.permissionMember.upsert({
|
|
490
|
+
where: { memberId_permissionId: { memberId: member.id, permissionId: permission.id } },
|
|
491
|
+
create: { memberId: member.id, permissionId: permission.id },
|
|
492
|
+
update: {},
|
|
493
|
+
});
|
|
494
|
+
await this.invalidateMember(userId, workspaceId);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
async revokePermissionFromMember(workspaceId: string, userId: string, permissionSlug: string): Promise<void> {
|
|
498
|
+
const member = await this.requireMember(workspaceId, userId);
|
|
499
|
+
const permission = await this.prisma.permission.findUnique({ where: { slug: permissionSlug }, select: { id: true } });
|
|
500
|
+
if (!permission) return;
|
|
501
|
+
await this.prisma.permissionMember.deleteMany({ where: { memberId: member.id, permissionId: permission.id } });
|
|
502
|
+
await this.invalidateMember(userId, workspaceId);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// Returns bigint directly: its one caller (assignRoleToMember) feeds the id straight into
|
|
506
|
+
// another Prisma call.
|
|
507
|
+
private async requireRole(workspaceId: string, slug: string): Promise<{ id: bigint }> {
|
|
508
|
+
const role = await this.prisma.role.findUnique({ where: { workspaceId_slug: { workspaceId: toId(workspaceId), slug }, isDeleted: false }, select: { id: true } });
|
|
509
|
+
if (!role) throw new HttpError(404, `role "${slug}" not found in this workspace`);
|
|
510
|
+
return role;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Creates the row for a slug granted before anyone defined it; leaves an existing definition
|
|
515
|
+
* alone. Returns bigint directly: both callers feed the id straight into another Prisma call.
|
|
516
|
+
*/
|
|
517
|
+
private async ensurePermission(slug: string, actorUserId: string | null): Promise<{ id: bigint }> {
|
|
518
|
+
const existing = await this.prisma.permission.findUnique({ where: { slug }, select: { id: true } });
|
|
519
|
+
return (
|
|
520
|
+
existing ??
|
|
521
|
+
(await this.prisma.permission.create({
|
|
522
|
+
data: { slug, name: slug, displayName: slug, group: "Custom", createdBy: toIdOrNull(actorUserId), updatedBy: toIdOrNull(actorUserId) },
|
|
523
|
+
select: { id: true },
|
|
524
|
+
}))
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// Idempotent database seeder — everything RBAC needs before this deployment can authorize
|
|
2
|
+
// anything. Roles are system-defined with fixed permission sets, so a fresh database has no
|
|
3
|
+
// Permission rows and no Role rows, and every authorization check has nothing to check against.
|
|
4
|
+
//
|
|
5
|
+
// npm run seed
|
|
6
|
+
//
|
|
7
|
+
// It seeds four things, in order:
|
|
8
|
+
//
|
|
9
|
+
// 1. the permission catalog — one slug per capability the admin API exposes. Global, not
|
|
10
|
+
// workspace-scoped, exactly like the Permission table itself;
|
|
11
|
+
// 2. the first workspace (SEED_WORKSPACE_NAME, defaulting below) — roles here are scoped to a
|
|
12
|
+
// workspace, so there has to be one for them to live in;
|
|
13
|
+
// 3. that workspace's default roles and their permission sets;
|
|
14
|
+
// 4. an initial admin user and their membership of that workspace, but only when
|
|
15
|
+
// SEED_ADMIN_EMAIL *and* SEED_ADMIN_PASSWORD are set. There is deliberately no fallback
|
|
16
|
+
// password: a seeder that invents one puts the same known credential on every fresh
|
|
17
|
+
// deployment. With the variables unset it says so and carries on.
|
|
18
|
+
//
|
|
19
|
+
// Re-running is safe: every write is an upsert and nothing is ever deleted. That also means it
|
|
20
|
+
// is additive, on purpose — a permission you attached to a role by hand survives a re-run, and
|
|
21
|
+
// an admin who already exists keeps the password they have now (the seeder never rewrites a
|
|
22
|
+
// password it did not set).
|
|
23
|
+
//
|
|
24
|
+
// Roles seeded here belong to the seeded workspace only — `Role` is unique per
|
|
25
|
+
// `[workspaceId, slug]`, so there is no such thing as a role that exists in all of them. A
|
|
26
|
+
// workspace created later through POST /workspaces provisions its own from the same definition:
|
|
27
|
+
// (1) and (3) both live in `rbac.defaults.ts`, which is also what types `@CheckAbility` on the
|
|
28
|
+
// routes. The seeder is a caller of that definition, not its owner, so the roles a workspace
|
|
29
|
+
// gets, whichever path created it, and the permissions the routes demand cannot drift apart.
|
|
30
|
+
import { PrismaPg } from "@prisma/adapter-pg";
|
|
31
|
+
import { hashPassword } from "@/lib/auth/core/crypto.js";
|
|
32
|
+
import { PrismaClient } from "../generated/prisma/client.js";
|
|
33
|
+
import { DEFAULT_ROLES, PERMISSION_SLUGS, provisionDefaultRoles, SEED_SUPERADMIN_ROLES, WORKSPACE_CREATOR_ROLES } from "./rbac.defaults.js";
|
|
34
|
+
|
|
35
|
+
const DEFAULT_WORKSPACE_NAME = "Default workspace";
|
|
36
|
+
|
|
37
|
+
function requireEnv(name: string): string {
|
|
38
|
+
const value = process.env[name];
|
|
39
|
+
if (!value) throw new Error(`${name} is not set — the seeder cannot reach the database without it`);
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Workspace names are not unique in the schema, so re-running adopts the one it made last time rather than making another. */
|
|
44
|
+
async function seedWorkspace(prisma: PrismaClient): Promise<{ id: bigint; name: string }> {
|
|
45
|
+
const name = process.env["SEED_WORKSPACE_NAME"] || DEFAULT_WORKSPACE_NAME;
|
|
46
|
+
const existing = await prisma.workspace.findFirst({ where: { name }, orderBy: { createdAt: "asc" } });
|
|
47
|
+
if (existing) {
|
|
48
|
+
console.log(`workspace: "${name}" already exists (${existing.id})`);
|
|
49
|
+
return existing;
|
|
50
|
+
}
|
|
51
|
+
const created = await prisma.workspace.create({ data: { name } });
|
|
52
|
+
console.log(`workspace: created "${name}" (${created.id})`);
|
|
53
|
+
return created;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** The catalog and this workspace's roles come from rbac.defaults.ts; this only reports what it wrote. */
|
|
57
|
+
async function seedRbacDefaults(prisma: PrismaClient, workspaceId: bigint): Promise<void> {
|
|
58
|
+
await provisionDefaultRoles(prisma, workspaceId);
|
|
59
|
+
console.log(`permissions: ${PERMISSION_SLUGS.length} slug(s) in the catalog`);
|
|
60
|
+
for (const role of DEFAULT_ROLES) console.log(`role "${role.slug}": ${role.permissions.length} permission(s)${role.isDefault ? " (new-member default)" : ""}`);
|
|
61
|
+
|
|
62
|
+
// Slugs that exist in the database but not in this build's catalog. They are not an error —
|
|
63
|
+
// `POST /auth/admin/permissions` exists so a deployment can define its own, and a grant can
|
|
64
|
+
// create one — but a slug no route names grants nothing, so a typo would otherwise be a
|
|
65
|
+
// permission that mysteriously never works. Printing them is what makes it visible.
|
|
66
|
+
const rows = await prisma.permission.findMany({ select: { slug: true, isActive: true } });
|
|
67
|
+
const unknown = rows.filter((row) => !(PERMISSION_SLUGS as string[]).includes(row.slug));
|
|
68
|
+
if (unknown.length) console.log(`permissions: ${unknown.length} slug(s) outside this build's catalog (no route names them): ${unknown.map((r) => r.slug).join(", ")}`);
|
|
69
|
+
const inactive = rows.filter((row) => !row.isActive);
|
|
70
|
+
if (inactive.length) console.log(`permissions: ${inactive.length} deactivated, granting nothing: ${inactive.map((r) => r.slug).join(", ")}`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** The user is the authentication principal; the membership below is the authorization one. */
|
|
74
|
+
async function seedAdminUser(prisma: PrismaClient, workspace: { id: bigint; name: string }): Promise<void> {
|
|
75
|
+
const email = process.env["SEED_ADMIN_EMAIL"];
|
|
76
|
+
const password = process.env["SEED_ADMIN_PASSWORD"];
|
|
77
|
+
if (!email || !password) {
|
|
78
|
+
console.log(`admin: skipped — set SEED_ADMIN_EMAIL and SEED_ADMIN_PASSWORD to create one (there is no default password)`);
|
|
79
|
+
console.log(`admin: "${workspace.name}" has no members until you re-run with them set`);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const existing = await prisma.user.findUnique({ where: { email } });
|
|
84
|
+
// Their password may have been changed since; rewriting it here would silently reset it.
|
|
85
|
+
const user = existing ?? (await prisma.user.create({ data: { email, passwordHash: await hashPassword(password) } }));
|
|
86
|
+
console.log(existing ? `admin: ${email} already exists — password left unchanged` : `admin: created ${email}`);
|
|
87
|
+
|
|
88
|
+
const membership = await prisma.workspaceMember.upsert({
|
|
89
|
+
where: { userId_workspaceId: { userId: user.id, workspaceId: workspace.id } },
|
|
90
|
+
create: { userId: user.id, workspaceId: workspace.id },
|
|
91
|
+
update: {},
|
|
92
|
+
});
|
|
93
|
+
const roles = await prisma.role.findMany({ where: { workspaceId: workspace.id, slug: { in: WORKSPACE_CREATOR_ROLES } }, select: { id: true, slug: true } });
|
|
94
|
+
await prisma.roleMember.createMany({ data: roles.map((role) => ({ memberId: membership.id, roleId: role.id })), skipDuplicates: true });
|
|
95
|
+
console.log(`admin: member of "${workspace.name}" with roles ${roles.map((r) => r.slug).join(", ")}`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** A second seeded account and membership, held by the "superadmin" role — same full-catalog authority as admin. */
|
|
99
|
+
async function seedSuperAdminUser(prisma: PrismaClient, workspace: { id: bigint; name: string }): Promise<void> {
|
|
100
|
+
const email = process.env["SEED_SUPERADMIN_EMAIL"];
|
|
101
|
+
const password = process.env["SEED_SUPERADMIN_PASSWORD"];
|
|
102
|
+
if (!email || !password) {
|
|
103
|
+
console.log(`super admin: skipped — set SEED_SUPERADMIN_EMAIL and SEED_SUPERADMIN_PASSWORD to create one (there is no default password)`);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const username = process.env["SEED_SUPERADMIN_USERNAME"] || undefined;
|
|
107
|
+
|
|
108
|
+
const existing = await prisma.user.findUnique({ where: { email } });
|
|
109
|
+
// Their password may have been changed since; rewriting it here would silently reset it.
|
|
110
|
+
const user = existing ?? (await prisma.user.create({ data: { email, username, passwordHash: await hashPassword(password) } }));
|
|
111
|
+
console.log(existing ? `super admin: ${email} already exists — password left unchanged` : `super admin: created ${email}${username ? ` (username ${username})` : ""}`);
|
|
112
|
+
|
|
113
|
+
const membership = await prisma.workspaceMember.upsert({
|
|
114
|
+
where: { userId_workspaceId: { userId: user.id, workspaceId: workspace.id } },
|
|
115
|
+
create: { userId: user.id, workspaceId: workspace.id },
|
|
116
|
+
update: {},
|
|
117
|
+
});
|
|
118
|
+
const roles = await prisma.role.findMany({ where: { workspaceId: workspace.id, slug: { in: SEED_SUPERADMIN_ROLES } }, select: { id: true, slug: true } });
|
|
119
|
+
await prisma.roleMember.createMany({ data: roles.map((role) => ({ memberId: membership.id, roleId: role.id })), skipDuplicates: true });
|
|
120
|
+
console.log(`super admin: member of "${workspace.name}" with roles ${roles.map((r) => r.slug).join(", ")}`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function main(): Promise<void> {
|
|
124
|
+
// Loads .env from the working directory if there is one. It never overrides a variable the
|
|
125
|
+
// process was already given, so an explicit `SEED_ADMIN_PASSWORD=... npm run seed` still wins.
|
|
126
|
+
try {
|
|
127
|
+
process.loadEnvFile();
|
|
128
|
+
} catch {
|
|
129
|
+
// No .env here — the environment is expected to carry the variables itself (docker, CI, ...).
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const prisma = new PrismaClient({ adapter: new PrismaPg({ connectionString: requireEnv("DATABASE_URL") }) });
|
|
133
|
+
try {
|
|
134
|
+
const workspace = await seedWorkspace(prisma);
|
|
135
|
+
await seedRbacDefaults(prisma, workspace.id);
|
|
136
|
+
await seedAdminUser(prisma, workspace);
|
|
137
|
+
await seedSuperAdminUser(prisma, workspace);
|
|
138
|
+
console.log("seed complete.");
|
|
139
|
+
} finally {
|
|
140
|
+
await prisma.$disconnect();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
main().catch((err) => {
|
|
145
|
+
console.error(err);
|
|
146
|
+
process.exit(1);
|
|
147
|
+
});
|