@podosoft/podokit 0.2.0 → 0.4.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 +1 -1
- package/dist/index.js +1 -1
- package/dist/templates/fullstack-nest-svelte/apps/api/package.json +29 -11
- package/dist/templates/fullstack-nest-svelte/apps/api/src/app.module.ts +3 -0
- package/dist/templates/fullstack-nest-svelte/apps/api/tsconfig.json +14 -5
- package/dist/templates/fullstack-nest-svelte/apps/web/package.json +8 -6
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/api.ts +5 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/alert/alert-action.svelte +20 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/alert/alert-description.svelte +23 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/alert/alert-title.svelte +23 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/alert/alert.svelte +43 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/alert/index.ts +17 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar-badge.svelte +26 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar-fallback.svelte +20 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar-group-count.svelte +23 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar-group.svelte +23 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar-image.svelte +17 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar.svelte +26 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/index.ts +22 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/badge/badge.svelte +49 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/badge/index.ts +2 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-close.svelte +11 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-content.svelte +48 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-description.svelte +17 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-footer.svelte +32 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-header.svelte +20 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-overlay.svelte +17 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-portal.svelte +7 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-title.svelte +17 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-trigger.svelte +11 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog.svelte +7 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/index.ts +34 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte +16 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +44 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte +31 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte +22 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-group.svelte +7 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte +27 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte +24 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.svelte +7 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte +16 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +34 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte +17 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte +20 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte +17 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +29 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.svelte +7 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +7 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu.svelte +7 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/index.ts +54 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/index.ts +37 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-content.svelte +45 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-group-heading.svelte +21 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-group.svelte +17 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-item.svelte +40 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-label.svelte +20 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-portal.svelte +7 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-scroll-down-button.svelte +20 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-scroll-up-button.svelte +20 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-separator.svelte +18 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-trigger.svelte +29 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select.svelte +11 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/separator/index.ts +7 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/separator/separator.svelte +23 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/skeleton/index.ts +7 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/skeleton/skeleton.svelte +17 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/sonner/index.ts +1 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/sonner/sonner.svelte +34 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/index.ts +28 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-body.svelte +15 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-caption.svelte +20 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-cell.svelte +15 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-footer.svelte +20 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-head.svelte +15 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-header.svelte +20 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-row.svelte +15 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table.svelte +17 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tabs/index.ts +18 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tabs/tabs-content.svelte +17 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tabs/tabs-list.svelte +40 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tabs/tabs-trigger.svelte +23 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tabs/tabs.svelte +19 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tooltip/index.ts +19 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tooltip/tooltip-content.svelte +52 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tooltip/tooltip-portal.svelte +7 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tooltip/tooltip-provider.svelte +7 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tooltip/tooltip-trigger.svelte +7 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tooltip/tooltip.svelte +7 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/i18n/ko.ts +5 -2
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/server/api.ts +19 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/server/backend-proxy.ts +43 -4
- package/dist/templates/fullstack-nest-svelte/apps/web/src/routes/+page.svelte +8 -3
- package/dist/templates/fullstack-nest-svelte/apps/web/src/routes/api/[...path]/+server.ts +12 -0
- package/dist/templates/fullstack-nest-svelte/apps/web/src/routes/api/auth/[...all]/+server.ts +12 -0
- package/dist/templates/fullstack-nest-svelte/dot-gitignore +5 -0
- package/dist/templates/fullstack-nest-svelte/package.json +11 -3
- package/dist/templates/fullstack-nest-svelte/tests/README.md +15 -0
- package/dist/templates/fullstack-nest-svelte/tests/api/health.api.spec.ts +14 -0
- package/dist/templates/fullstack-nest-svelte/tests/package.json +14 -0
- package/dist/templates/fullstack-nest-svelte/tests/playwright.config.ts +25 -0
- package/dist/templates/fullstack-nest-svelte/tests/ui/smoke.ui.spec.ts +8 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/app.d.ts +23 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/hooks.server.ts +20 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/app-sidebar.svelte +59 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/language-switch.svelte +33 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/sidebar-user-menu.svelte +44 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/table-pagination.svelte +40 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/theme-toggle.svelte +27 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/collapsible/collapsible-content.svelte +7 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/collapsible/collapsible-trigger.svelte +7 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/collapsible/collapsible.svelte +11 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/collapsible/index.ts +13 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/index.ts +31 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/pagination-content.svelte +20 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/pagination-ellipsis.svelte +22 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/pagination-item.svelte +14 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/pagination-link.svelte +42 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/pagination-next-button.svelte +31 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/pagination-next.svelte +26 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/pagination-prev-button.svelte +31 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/pagination-previous.svelte +26 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/pagination.svelte +28 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/index.ts +34 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/sheet-close.svelte +7 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/sheet-content.svelte +55 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/sheet-description.svelte +17 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/sheet-footer.svelte +20 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/sheet-header.svelte +20 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/sheet-overlay.svelte +17 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/sheet-portal.svelte +7 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/sheet-title.svelte +17 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/sheet-trigger.svelte +7 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/sheet.svelte +7 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/constants.ts +6 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/context.svelte.ts +81 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/index.ts +75 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-content.svelte +24 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-footer.svelte +21 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-group-action.svelte +33 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-group-content.svelte +21 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-group-label.svelte +33 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-group.svelte +21 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-header.svelte +21 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-input.svelte +21 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-inset.svelte +20 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-menu-action.svelte +37 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-menu-badge.svelte +24 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-menu-button.svelte +102 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-menu-item.svelte +21 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-menu-skeleton.svelte +36 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-menu-sub-button.svelte +39 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-menu-sub-item.svelte +21 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-menu-sub.svelte +21 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-menu.svelte +21 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-provider.svelte +53 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-rail.svelte +36 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-separator.svelte +19 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-trigger.svelte +36 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar.svelte +108 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/user-avatar.svelte +12 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/hooks/is-mobile.svelte.ts +9 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/i18n/index.ts +27 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/i18n/messages.ts +359 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/+layout.server.ts +14 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/+layout.svelte +50 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/admin/+page.svelte +25 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/admin/account/+page.server.ts +5 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/admin/account/+page.svelte +374 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/admin/audit/+page.server.ts +8 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/admin/audit/+page.svelte +78 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/admin/sessions/+page.server.ts +8 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/admin/sessions/+page.svelte +122 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/admin/users/+page.server.ts +9 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/admin/users/+page.svelte +406 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(auth)/+layout.svelte +13 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(auth)/forgot-password/+page.svelte +54 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(auth)/login/+page.svelte +59 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(auth)/reset-password/+page.svelte +51 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(auth)/signup/+page.svelte +60 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/+layout.server.ts +22 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/+layout.svelte +20 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/+page.svelte +22 -0
- package/dist/templates/modules/admin-dashboard/files/tests/api/audit.api.spec.ts +48 -0
- package/dist/templates/modules/admin-dashboard/files/tests/api/auth.api.spec.ts +43 -0
- package/dist/templates/modules/admin-dashboard/files/tests/api/users-admin.api.spec.ts +134 -0
- package/dist/templates/modules/admin-dashboard/files/tests/helpers/accounts.ts +6 -0
- package/dist/templates/modules/admin-dashboard/files/tests/helpers/hydration.ts +9 -0
- package/dist/templates/modules/admin-dashboard/files/tests/playwright.config.ts +26 -0
- package/dist/templates/modules/admin-dashboard/files/tests/seed.setup.ts +29 -0
- package/dist/templates/modules/admin-dashboard/files/tests/ui/account.ui.spec.ts +55 -0
- package/dist/templates/modules/admin-dashboard/files/tests/ui/audit.ui.spec.ts +16 -0
- package/dist/templates/modules/admin-dashboard/files/tests/ui/auth.ui.spec.ts +45 -0
- package/dist/templates/modules/admin-dashboard/files/tests/ui/dashboard.ui.spec.ts +25 -0
- package/dist/templates/modules/admin-dashboard/files/tests/ui/guards.ui.spec.ts +21 -0
- package/dist/templates/modules/admin-dashboard/files/tests/ui/i18n.ui.spec.ts +13 -0
- package/dist/templates/modules/admin-dashboard/files/tests/ui/sessions.ui.spec.ts +15 -0
- package/dist/templates/modules/admin-dashboard/files/tests/ui/sidebar.ui.spec.ts +16 -0
- package/dist/templates/modules/admin-dashboard/files/tests/ui/users-crud.ui.spec.ts +129 -0
- package/dist/templates/modules/admin-dashboard/files/tests/ui/users.ui.spec.ts +19 -0
- package/dist/templates/modules/admin-dashboard/module.manifest.json +41 -0
- package/dist/templates/modules/api-key-auth/files/apps/api/src/api-key/api-key.decorator.ts +9 -0
- package/dist/templates/modules/api-key-auth/files/apps/api/src/api-key/api-key.guard.ts +29 -0
- package/dist/templates/modules/api-key-auth/files/apps/api/src/api-key/api-key.module.ts +9 -0
- package/dist/templates/modules/api-key-auth/files/apps/api/src/machine/machine.controller.ts +14 -0
- package/dist/templates/modules/api-key-auth/module.manifest.json +19 -0
- package/dist/templates/modules/audit-log/files/apps/api/src/audit/README.md +59 -0
- package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit-events.ts +34 -0
- package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit-hook.ts +70 -0
- package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit-log.entity.ts +46 -0
- package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.controller.ts +21 -0
- package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.decorator.ts +23 -0
- package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.interceptor.ts +54 -0
- package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.module.ts +14 -0
- package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.service.ts +36 -0
- package/dist/templates/modules/audit-log/files/apps/api/src/migrations/1720300000000-InitAuditLogs.ts +31 -0
- package/dist/templates/modules/audit-log/module.manifest.json +39 -0
- package/dist/templates/modules/auth/files/apps/api/src/account/account.controller.ts +30 -0
- package/dist/templates/modules/auth/files/apps/api/src/account/account.module.ts +5 -0
- package/dist/templates/modules/auth/files/apps/api/src/auth/auth.ts +59 -0
- package/dist/templates/modules/auth/files/apps/api/src/health/health.controller.ts +26 -0
- package/dist/templates/modules/auth/module.manifest.json +70 -0
- package/dist/templates/modules/bullmq/module.manifest.json +11 -3
- package/dist/templates/modules/logging/files/apps/api/src/logging/logging.module.ts +29 -0
- package/dist/templates/modules/logging/module.manifest.json +27 -0
- package/dist/templates/modules/rate-limit/files/apps/api/src/rate-limit/rate-limit.module.ts +26 -0
- package/dist/templates/modules/rate-limit/module.manifest.json +25 -0
- package/dist/templates/todo/apps/api/package.json +29 -11
- package/dist/templates/todo/apps/api/src/app.module.ts +3 -0
- package/dist/templates/todo/apps/api/tsconfig.json +14 -5
- package/dist/templates/todo/apps/web/package.json +8 -6
- package/dist/templates/todo/apps/web/src/lib/api.ts +5 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/alert/alert-action.svelte +20 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/alert/alert-description.svelte +23 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/alert/alert-title.svelte +23 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/alert/alert.svelte +43 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/alert/index.ts +17 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/avatar-badge.svelte +26 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/avatar-fallback.svelte +20 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/avatar-group-count.svelte +23 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/avatar-group.svelte +23 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/avatar-image.svelte +17 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/avatar.svelte +26 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/index.ts +22 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/badge/badge.svelte +49 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/badge/index.ts +2 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-close.svelte +11 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-content.svelte +48 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-description.svelte +17 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-footer.svelte +32 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-header.svelte +20 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-overlay.svelte +17 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-portal.svelte +7 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-title.svelte +17 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-trigger.svelte +11 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog.svelte +7 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/index.ts +34 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte +16 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +44 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte +31 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte +22 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-group.svelte +7 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte +27 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte +24 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.svelte +7 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte +16 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +34 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte +17 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte +20 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte +17 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +29 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.svelte +7 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +7 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu.svelte +7 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/index.ts +54 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/select/index.ts +37 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-content.svelte +45 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-group-heading.svelte +21 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-group.svelte +17 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-item.svelte +40 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-label.svelte +20 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-portal.svelte +7 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-scroll-down-button.svelte +20 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-scroll-up-button.svelte +20 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-separator.svelte +18 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-trigger.svelte +29 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/select/select.svelte +11 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/separator/index.ts +7 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/separator/separator.svelte +23 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/skeleton/index.ts +7 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/skeleton/skeleton.svelte +17 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/sonner/index.ts +1 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/sonner/sonner.svelte +34 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/table/index.ts +28 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-body.svelte +15 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-caption.svelte +20 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-cell.svelte +15 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-footer.svelte +20 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-head.svelte +15 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-header.svelte +20 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-row.svelte +15 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/table/table.svelte +17 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/tabs/index.ts +18 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/tabs/tabs-content.svelte +17 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/tabs/tabs-list.svelte +40 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/tabs/tabs-trigger.svelte +23 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/tabs/tabs.svelte +19 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/index.ts +19 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/tooltip-content.svelte +52 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/tooltip-portal.svelte +7 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/tooltip-provider.svelte +7 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/tooltip-trigger.svelte +7 -0
- package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/tooltip.svelte +7 -0
- package/dist/templates/todo/apps/web/src/lib/i18n/ko.ts +5 -2
- package/dist/templates/todo/apps/web/src/lib/server/api.ts +19 -0
- package/dist/templates/todo/apps/web/src/lib/server/backend-proxy.ts +43 -4
- package/dist/templates/todo/apps/web/src/routes/+page.svelte +19 -18
- package/dist/templates/todo/apps/web/src/routes/api/[...path]/+server.ts +12 -0
- package/dist/templates/todo/apps/web/src/routes/api/auth/[...all]/+server.ts +12 -0
- package/dist/templates/todo/dot-gitignore +5 -0
- package/dist/templates/todo/package.json +11 -3
- package/dist/templates/todo/tests/README.md +15 -0
- package/dist/templates/todo/tests/api/health.api.spec.ts +14 -0
- package/dist/templates/todo/tests/package.json +14 -0
- package/dist/templates/todo/tests/playwright.config.ts +25 -0
- package/dist/templates/todo/tests/ui/smoke.ui.spec.ts +8 -0
- package/package.json +2 -2
- package/dist/templates/fullstack-nest-svelte/apps/api/test/health.e2e-spec.ts +0 -23
- package/dist/templates/fullstack-nest-svelte/apps/web/src/routes/api/health/+server.ts +0 -12
- package/dist/templates/modules/auth-jwt/files/apps/api/src/auth/auth.controller.ts +0 -31
- package/dist/templates/modules/auth-jwt/files/apps/api/src/auth/auth.module.ts +0 -22
- package/dist/templates/modules/auth-jwt/files/apps/api/src/auth/auth.service.ts +0 -44
- package/dist/templates/modules/auth-jwt/files/apps/api/src/auth/dto/login.dto.ts +0 -12
- package/dist/templates/modules/auth-jwt/files/apps/api/src/auth/dto/register.dto.ts +0 -13
- package/dist/templates/modules/auth-jwt/files/apps/api/src/auth/jwt-auth.guard.ts +0 -5
- package/dist/templates/modules/auth-jwt/files/apps/api/src/auth/jwt.strategy.ts +0 -23
- package/dist/templates/modules/auth-jwt/files/apps/api/src/auth/user.entity.ts +0 -16
- package/dist/templates/modules/auth-jwt/files/apps/api/src/migrations/1720200000000-InitUsers.ts +0 -23
- package/dist/templates/modules/auth-jwt/module.manifest.json +0 -31
- package/dist/templates/todo/apps/api/test/health.e2e-spec.ts +0 -23
- package/dist/templates/todo/apps/web/src/routes/api/health/+server.ts +0 -12
- package/dist/templates/todo/apps/web/src/routes/api/todos/+server.ts +0 -24
- package/dist/templates/todo/apps/web/src/routes/api/todos/[id]/+server.ts +0 -24
|
@@ -2,12 +2,20 @@
|
|
|
2
2
|
"name": "{{projectName}}",
|
|
3
3
|
"version": "0.0.0",
|
|
4
4
|
"private": true,
|
|
5
|
-
"engines": {
|
|
6
|
-
|
|
5
|
+
"engines": {
|
|
6
|
+
"node": ">=20"
|
|
7
|
+
},
|
|
8
|
+
"workspaces": [
|
|
9
|
+
"apps/*",
|
|
10
|
+
"tests"
|
|
11
|
+
],
|
|
7
12
|
"scripts": {
|
|
8
13
|
"dev": "npm run dev --workspaces --if-present",
|
|
9
14
|
"build": "npm run build --workspaces --if-present",
|
|
10
15
|
"lint": "npm run lint --workspaces --if-present",
|
|
11
|
-
"test": "npm run test --workspaces --if-present"
|
|
16
|
+
"test": "npm run test --workspaces --if-present",
|
|
17
|
+
"test:e2e": "npm run test:e2e -w tests",
|
|
18
|
+
"test:e2e:ui": "npm run test:e2e:ui -w tests",
|
|
19
|
+
"test:e2e:api": "npm run test:e2e:api -w tests"
|
|
12
20
|
}
|
|
13
21
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# tests
|
|
2
|
+
|
|
3
|
+
End-to-end tests for this app, run with [`@playwright/test`](https://playwright.dev):
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm run test:e2e # all specs (api + ui)
|
|
7
|
+
npm run test:e2e:api # backend endpoints (request-only)
|
|
8
|
+
npm run test:e2e:ui # pages (chromium)
|
|
9
|
+
npm run test:e2e:report # open the HTML report
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
The suite runs against a live stack (web on `E2E_BASE_URL`, default
|
|
13
|
+
`http://localhost:5173`, proxying `/api/*` to the API). Start PostgreSQL, run the
|
|
14
|
+
auth migration, and start the API + web first. Files ending in `*.api.spec.ts` run
|
|
15
|
+
in the request-only `api` project; `*.ui.spec.ts` run in the chromium `ui` project.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { expect, test } from "@playwright/test";
|
|
2
|
+
|
|
3
|
+
// Health endpoints are public and present in every generated app.
|
|
4
|
+
test("GET /health is public and ok @smoke", async ({ request }) => {
|
|
5
|
+
const res = await request.get("/api/health");
|
|
6
|
+
expect(res.ok()).toBeTruthy();
|
|
7
|
+
expect((await res.json()).status).toBe("ok");
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
test("GET /health/ready reports the database", async ({ request }) => {
|
|
11
|
+
const res = await request.get("/api/health/ready");
|
|
12
|
+
expect(res.status()).toBe(200);
|
|
13
|
+
expect((await res.json()).status).toBe("ready");
|
|
14
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectName}}-tests",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"test:e2e": "playwright test",
|
|
7
|
+
"test:e2e:ui": "playwright test --project=ui",
|
|
8
|
+
"test:e2e:api": "playwright test --project=api",
|
|
9
|
+
"test:e2e:report": "playwright show-report"
|
|
10
|
+
},
|
|
11
|
+
"devDependencies": {
|
|
12
|
+
"@playwright/test": "^1.61.1"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { defineConfig, devices } from "@playwright/test";
|
|
2
|
+
|
|
3
|
+
// The suite runs against a live stack: web on E2E_BASE_URL (proxying /api/* to
|
|
4
|
+
// the API). Start it first (see docs/testing.md) — locally via the dev harness,
|
|
5
|
+
// in CI via scripts/e2e-ci.mjs. Two projects: `api` (request-only, backend e2e)
|
|
6
|
+
// and `ui` (chromium, pages). Files are routed by suffix (*.api/*.ui.spec.ts).
|
|
7
|
+
const baseURL = process.env.E2E_BASE_URL ?? "http://localhost:5173";
|
|
8
|
+
|
|
9
|
+
export default defineConfig({
|
|
10
|
+
testDir: ".",
|
|
11
|
+
fullyParallel: true,
|
|
12
|
+
forbidOnly: !!process.env.CI,
|
|
13
|
+
retries: process.env.CI ? 2 : 0,
|
|
14
|
+
workers: process.env.CI ? 1 : undefined,
|
|
15
|
+
reporter: [["list"], ["html", { open: "never" }]],
|
|
16
|
+
use: {
|
|
17
|
+
baseURL,
|
|
18
|
+
trace: "on-first-retry",
|
|
19
|
+
screenshot: "only-on-failure",
|
|
20
|
+
},
|
|
21
|
+
projects: [
|
|
22
|
+
{ name: "api", testMatch: /.*\.api\.spec\.ts/ },
|
|
23
|
+
{ name: "ui", testMatch: /.*\.ui\.spec\.ts/, use: { ...devices["Desktop Chrome"] } },
|
|
24
|
+
],
|
|
25
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { expect, test } from "@playwright/test";
|
|
2
|
+
|
|
3
|
+
// Module-agnostic: the app responds at "/" (a page or a redirect to it).
|
|
4
|
+
test("app is reachable @smoke", async ({ page }) => {
|
|
5
|
+
const res = await page.goto("/");
|
|
6
|
+
expect(res?.status()).toBeLessThan(400);
|
|
7
|
+
await expect(page.locator("body")).toBeVisible();
|
|
8
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@podosoft/podokit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "An opinionated but extensible starter toolkit and CLI for full-stack TypeScript apps with NestJS, SvelteKit, TailwindCSS, shadcn-svelte, Docker, and k3s.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -36,6 +36,6 @@
|
|
|
36
36
|
"test": "vitest run"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@podosoft/podokit-template-engine": "^0.
|
|
39
|
+
"@podosoft/podokit-template-engine": "^0.3.0"
|
|
40
40
|
}
|
|
41
41
|
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { Test } from "@nestjs/testing";
|
|
2
|
-
import type { INestApplication } from "@nestjs/common";
|
|
3
|
-
import request from "supertest";
|
|
4
|
-
import { HealthModule } from "../src/health/health.module";
|
|
5
|
-
|
|
6
|
-
describe("Health (e2e)", () => {
|
|
7
|
-
let app: INestApplication;
|
|
8
|
-
|
|
9
|
-
beforeAll(async () => {
|
|
10
|
-
const moduleRef = await Test.createTestingModule({ imports: [HealthModule] }).compile();
|
|
11
|
-
app = moduleRef.createNestApplication();
|
|
12
|
-
await app.init();
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
afterAll(async () => {
|
|
16
|
-
await app.close();
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it("GET /health returns ok", async () => {
|
|
20
|
-
const res = await request(app.getHttpServer()).get("/health").expect(200);
|
|
21
|
-
expect(res.body.status).toBe("ok");
|
|
22
|
-
});
|
|
23
|
-
});
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { RequestHandler } from "@sveltejs/kit";
|
|
2
|
-
import { backendBaseUrl, backendProxyHeaders } from "$lib/server/backend-proxy";
|
|
3
|
-
|
|
4
|
-
export const GET: RequestHandler = async ({ request }) => {
|
|
5
|
-
const upstream = await fetch(`${backendBaseUrl()}/health`, {
|
|
6
|
-
headers: backendProxyHeaders(request),
|
|
7
|
-
});
|
|
8
|
-
return new Response(await upstream.text(), {
|
|
9
|
-
status: upstream.status,
|
|
10
|
-
headers: { "content-type": "application/json" },
|
|
11
|
-
});
|
|
12
|
-
};
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { Body, Controller, Get, HttpCode, Post, Req, UseGuards } from "@nestjs/common";
|
|
2
|
-
import { ApiBearerAuth, ApiTags } from "@nestjs/swagger";
|
|
3
|
-
import type { Request } from "express";
|
|
4
|
-
import { AuthService } from "./auth.service";
|
|
5
|
-
import { RegisterDto } from "./dto/register.dto";
|
|
6
|
-
import { LoginDto } from "./dto/login.dto";
|
|
7
|
-
import { JwtAuthGuard } from "./jwt-auth.guard";
|
|
8
|
-
|
|
9
|
-
@ApiTags("auth")
|
|
10
|
-
@Controller("auth")
|
|
11
|
-
export class AuthController {
|
|
12
|
-
constructor(private readonly auth: AuthService) {}
|
|
13
|
-
|
|
14
|
-
@Post("register")
|
|
15
|
-
register(@Body() dto: RegisterDto) {
|
|
16
|
-
return this.auth.register(dto);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
@Post("login")
|
|
20
|
-
@HttpCode(200)
|
|
21
|
-
login(@Body() dto: LoginDto) {
|
|
22
|
-
return this.auth.login(dto);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
@UseGuards(JwtAuthGuard)
|
|
26
|
-
@ApiBearerAuth()
|
|
27
|
-
@Get("me")
|
|
28
|
-
me(@Req() req: Request): unknown {
|
|
29
|
-
return req.user;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { Module } from "@nestjs/common";
|
|
2
|
-
import { JwtModule } from "@nestjs/jwt";
|
|
3
|
-
import { PassportModule } from "@nestjs/passport";
|
|
4
|
-
import { TypeOrmModule } from "@nestjs/typeorm";
|
|
5
|
-
import { AuthController } from "./auth.controller";
|
|
6
|
-
import { AuthService } from "./auth.service";
|
|
7
|
-
import { JwtStrategy } from "./jwt.strategy";
|
|
8
|
-
import { User } from "./user.entity";
|
|
9
|
-
|
|
10
|
-
@Module({
|
|
11
|
-
imports: [
|
|
12
|
-
TypeOrmModule.forFeature([User]),
|
|
13
|
-
PassportModule,
|
|
14
|
-
JwtModule.register({
|
|
15
|
-
secret: process.env.JWT_SECRET ?? "change-me-in-production",
|
|
16
|
-
signOptions: { expiresIn: process.env.JWT_EXPIRES_IN ?? "3600s" },
|
|
17
|
-
}),
|
|
18
|
-
],
|
|
19
|
-
controllers: [AuthController],
|
|
20
|
-
providers: [AuthService, JwtStrategy],
|
|
21
|
-
})
|
|
22
|
-
export class AuthModule {}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { ConflictException, Injectable, UnauthorizedException } from "@nestjs/common";
|
|
2
|
-
import { JwtService } from "@nestjs/jwt";
|
|
3
|
-
import { InjectRepository } from "@nestjs/typeorm";
|
|
4
|
-
import { Repository } from "typeorm";
|
|
5
|
-
import * as bcrypt from "bcryptjs";
|
|
6
|
-
import { User } from "./user.entity";
|
|
7
|
-
import { RegisterDto } from "./dto/register.dto";
|
|
8
|
-
import { LoginDto } from "./dto/login.dto";
|
|
9
|
-
|
|
10
|
-
export interface AuthResult {
|
|
11
|
-
accessToken: string;
|
|
12
|
-
user: { id: string; email: string };
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
@Injectable()
|
|
16
|
-
export class AuthService {
|
|
17
|
-
constructor(
|
|
18
|
-
@InjectRepository(User) private readonly users: Repository<User>,
|
|
19
|
-
private readonly jwt: JwtService,
|
|
20
|
-
) {}
|
|
21
|
-
|
|
22
|
-
async register(dto: RegisterDto): Promise<AuthResult> {
|
|
23
|
-
const existing = await this.users.findOne({ where: { email: dto.email } });
|
|
24
|
-
if (existing) {
|
|
25
|
-
throw new ConflictException("Email already registered");
|
|
26
|
-
}
|
|
27
|
-
const passwordHash = await bcrypt.hash(dto.password, 10);
|
|
28
|
-
const user = await this.users.save(this.users.create({ email: dto.email, passwordHash }));
|
|
29
|
-
return this.sign(user);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
async login(dto: LoginDto): Promise<AuthResult> {
|
|
33
|
-
const user = await this.users.findOne({ where: { email: dto.email } });
|
|
34
|
-
if (!user || !(await bcrypt.compare(dto.password, user.passwordHash))) {
|
|
35
|
-
throw new UnauthorizedException("Invalid credentials");
|
|
36
|
-
}
|
|
37
|
-
return this.sign(user);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
private sign(user: User): AuthResult {
|
|
41
|
-
const accessToken = this.jwt.sign({ sub: user.id, email: user.email });
|
|
42
|
-
return { accessToken, user: { id: user.id, email: user.email } };
|
|
43
|
-
}
|
|
44
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { ApiProperty } from "@nestjs/swagger";
|
|
2
|
-
import { IsEmail, IsString } from "class-validator";
|
|
3
|
-
|
|
4
|
-
export class LoginDto {
|
|
5
|
-
@ApiProperty({ example: "user@example.com" })
|
|
6
|
-
@IsEmail()
|
|
7
|
-
email!: string;
|
|
8
|
-
|
|
9
|
-
@ApiProperty({ example: "password123" })
|
|
10
|
-
@IsString()
|
|
11
|
-
password!: string;
|
|
12
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { ApiProperty } from "@nestjs/swagger";
|
|
2
|
-
import { IsEmail, IsString, MinLength } from "class-validator";
|
|
3
|
-
|
|
4
|
-
export class RegisterDto {
|
|
5
|
-
@ApiProperty({ example: "user@example.com" })
|
|
6
|
-
@IsEmail()
|
|
7
|
-
email!: string;
|
|
8
|
-
|
|
9
|
-
@ApiProperty({ example: "password123", minLength: 8 })
|
|
10
|
-
@IsString()
|
|
11
|
-
@MinLength(8)
|
|
12
|
-
password!: string;
|
|
13
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { Injectable } from "@nestjs/common";
|
|
2
|
-
import { PassportStrategy } from "@nestjs/passport";
|
|
3
|
-
import { ExtractJwt, Strategy } from "passport-jwt";
|
|
4
|
-
|
|
5
|
-
export interface JwtPayload {
|
|
6
|
-
sub: string;
|
|
7
|
-
email: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
@Injectable()
|
|
11
|
-
export class JwtStrategy extends PassportStrategy(Strategy) {
|
|
12
|
-
constructor() {
|
|
13
|
-
super({
|
|
14
|
-
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
|
15
|
-
ignoreExpiration: false,
|
|
16
|
-
secretOrKey: process.env.JWT_SECRET ?? "change-me-in-production",
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
validate(payload: JwtPayload): { userId: string; email: string } {
|
|
21
|
-
return { userId: payload.sub, email: payload.email };
|
|
22
|
-
}
|
|
23
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn } from "typeorm";
|
|
2
|
-
|
|
3
|
-
@Entity("users")
|
|
4
|
-
export class User {
|
|
5
|
-
@PrimaryGeneratedColumn("uuid")
|
|
6
|
-
id!: string;
|
|
7
|
-
|
|
8
|
-
@Column({ type: "varchar", length: 320, unique: true })
|
|
9
|
-
email!: string;
|
|
10
|
-
|
|
11
|
-
@Column({ type: "varchar" })
|
|
12
|
-
passwordHash!: string;
|
|
13
|
-
|
|
14
|
-
@CreateDateColumn({ type: "timestamptz" })
|
|
15
|
-
createdAt!: Date;
|
|
16
|
-
}
|
package/dist/templates/modules/auth-jwt/files/apps/api/src/migrations/1720200000000-InitUsers.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import type { MigrationInterface, QueryRunner } from "typeorm";
|
|
2
|
-
|
|
3
|
-
export class InitUsers1720200000000 implements MigrationInterface {
|
|
4
|
-
name = "InitUsers1720200000000";
|
|
5
|
-
|
|
6
|
-
async up(queryRunner: QueryRunner): Promise<void> {
|
|
7
|
-
await queryRunner.query(`CREATE EXTENSION IF NOT EXISTS "pgcrypto"`);
|
|
8
|
-
await queryRunner.query(`
|
|
9
|
-
CREATE TABLE "users" (
|
|
10
|
-
"id" uuid NOT NULL DEFAULT gen_random_uuid(),
|
|
11
|
-
"email" character varying(320) NOT NULL,
|
|
12
|
-
"passwordHash" character varying NOT NULL,
|
|
13
|
-
"createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
|
|
14
|
-
CONSTRAINT "PK_users_id" PRIMARY KEY ("id"),
|
|
15
|
-
CONSTRAINT "UQ_users_email" UNIQUE ("email")
|
|
16
|
-
)
|
|
17
|
-
`);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
async down(queryRunner: QueryRunner): Promise<void> {
|
|
21
|
-
await queryRunner.query(`DROP TABLE "users"`);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "auth-jwt",
|
|
3
|
-
"description": "JWT auth: register, login, a JWT guard, and a protected /auth/me route (TypeORM users).",
|
|
4
|
-
"requires": [],
|
|
5
|
-
"targetApp": "api",
|
|
6
|
-
"dependencies": {
|
|
7
|
-
"@nestjs/jwt": "^10.2.0",
|
|
8
|
-
"@nestjs/passport": "^10.0.3",
|
|
9
|
-
"bcryptjs": "^2.4.3",
|
|
10
|
-
"passport": "^0.7.0",
|
|
11
|
-
"passport-jwt": "^4.0.1"
|
|
12
|
-
},
|
|
13
|
-
"devDependencies": {
|
|
14
|
-
"@types/bcryptjs": "^2.4.6",
|
|
15
|
-
"@types/passport-jwt": "^4.0.1"
|
|
16
|
-
},
|
|
17
|
-
"env": [
|
|
18
|
-
"# auth-jwt",
|
|
19
|
-
"JWT_SECRET=change-me-in-production",
|
|
20
|
-
"JWT_EXPIRES_IN=3600s"
|
|
21
|
-
],
|
|
22
|
-
"inject": [
|
|
23
|
-
{ "file": "apps/api/src/app.module.ts", "marker": "// podokit:imports", "text": "import { AuthModule } from \"./auth/auth.module\";" },
|
|
24
|
-
{ "file": "apps/api/src/app.module.ts", "marker": "// podokit:module-imports", "text": "AuthModule," }
|
|
25
|
-
],
|
|
26
|
-
"instructions": [
|
|
27
|
-
"Run the users migration: npm run migration:run -w <app>-api",
|
|
28
|
-
"Register: curl -XPOST localhost:3000/auth/register -H 'content-type: application/json' -d '{\"email\":\"a@example.com\",\"password\":\"password123\"}'",
|
|
29
|
-
"Call the protected route with the returned token: curl localhost:3000/auth/me -H 'authorization: Bearer <token>'"
|
|
30
|
-
]
|
|
31
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { Test } from "@nestjs/testing";
|
|
2
|
-
import type { INestApplication } from "@nestjs/common";
|
|
3
|
-
import request from "supertest";
|
|
4
|
-
import { HealthModule } from "../src/health/health.module";
|
|
5
|
-
|
|
6
|
-
describe("Health (e2e)", () => {
|
|
7
|
-
let app: INestApplication;
|
|
8
|
-
|
|
9
|
-
beforeAll(async () => {
|
|
10
|
-
const moduleRef = await Test.createTestingModule({ imports: [HealthModule] }).compile();
|
|
11
|
-
app = moduleRef.createNestApplication();
|
|
12
|
-
await app.init();
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
afterAll(async () => {
|
|
16
|
-
await app.close();
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it("GET /health returns ok", async () => {
|
|
20
|
-
const res = await request(app.getHttpServer()).get("/health").expect(200);
|
|
21
|
-
expect(res.body.status).toBe("ok");
|
|
22
|
-
});
|
|
23
|
-
});
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { RequestHandler } from "@sveltejs/kit";
|
|
2
|
-
import { backendBaseUrl, backendProxyHeaders } from "$lib/server/backend-proxy";
|
|
3
|
-
|
|
4
|
-
export const GET: RequestHandler = async ({ request }) => {
|
|
5
|
-
const upstream = await fetch(`${backendBaseUrl()}/health`, {
|
|
6
|
-
headers: backendProxyHeaders(request),
|
|
7
|
-
});
|
|
8
|
-
return new Response(await upstream.text(), {
|
|
9
|
-
status: upstream.status,
|
|
10
|
-
headers: { "content-type": "application/json" },
|
|
11
|
-
});
|
|
12
|
-
};
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { RequestHandler } from "@sveltejs/kit";
|
|
2
|
-
import { backendBaseUrl, backendProxyHeaders } from "$lib/server/backend-proxy";
|
|
3
|
-
|
|
4
|
-
export const GET: RequestHandler = async ({ request }) => {
|
|
5
|
-
const upstream = await fetch(`${backendBaseUrl()}/todos`, { headers: backendProxyHeaders(request) });
|
|
6
|
-
return new Response(await upstream.text(), {
|
|
7
|
-
status: upstream.status,
|
|
8
|
-
headers: { "content-type": "application/json" },
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export const POST: RequestHandler = async ({ request }) => {
|
|
13
|
-
const headers = backendProxyHeaders(request);
|
|
14
|
-
headers.set("content-type", "application/json");
|
|
15
|
-
const upstream = await fetch(`${backendBaseUrl()}/todos`, {
|
|
16
|
-
method: "POST",
|
|
17
|
-
headers,
|
|
18
|
-
body: await request.text(),
|
|
19
|
-
});
|
|
20
|
-
return new Response(await upstream.text(), {
|
|
21
|
-
status: upstream.status,
|
|
22
|
-
headers: { "content-type": "application/json" },
|
|
23
|
-
});
|
|
24
|
-
};
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { RequestHandler } from "@sveltejs/kit";
|
|
2
|
-
import { backendBaseUrl, backendProxyHeaders } from "$lib/server/backend-proxy";
|
|
3
|
-
|
|
4
|
-
export const PATCH: RequestHandler = async ({ request, params }) => {
|
|
5
|
-
const headers = backendProxyHeaders(request);
|
|
6
|
-
headers.set("content-type", "application/json");
|
|
7
|
-
const upstream = await fetch(`${backendBaseUrl()}/todos/${params.id}`, {
|
|
8
|
-
method: "PATCH",
|
|
9
|
-
headers,
|
|
10
|
-
body: await request.text(),
|
|
11
|
-
});
|
|
12
|
-
return new Response(await upstream.text(), {
|
|
13
|
-
status: upstream.status,
|
|
14
|
-
headers: { "content-type": "application/json" },
|
|
15
|
-
});
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export const DELETE: RequestHandler = async ({ request, params }) => {
|
|
19
|
-
const upstream = await fetch(`${backendBaseUrl()}/todos/${params.id}`, {
|
|
20
|
-
method: "DELETE",
|
|
21
|
-
headers: backendProxyHeaders(request),
|
|
22
|
-
});
|
|
23
|
-
return new Response(null, { status: upstream.status });
|
|
24
|
-
};
|