create-bubbles 0.1.20 → 0.1.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{index.js → index.mjs} +14 -7
- package/package.json +5 -4
- package/template-nextjs-vinext-eslint/vite.config.ts +1 -1
- package/template-vp-monorepo-react-nestjs/.spaces/server//347/231/273/345/275/225/JWT/344/270/216RefreshToken/350/275/256/346/215/242/351/211/264/346/235/203/346/236/266/346/236/204/345/256/236/347/216/260/346/214/207/345/215/227.md +6614 -0
- package/template-vp-monorepo-react-nestjs/.vite-hooks/commit-msg +1 -0
- package/template-vp-monorepo-react-nestjs/.vite-hooks/pre-commit +2 -1
- package/template-vp-monorepo-react-nestjs/.vscode/settings.json +26 -0
- package/template-vp-monorepo-react-nestjs/AGENTS.md +16 -0
- package/template-vp-monorepo-react-nestjs/README.md +2 -2
- package/template-vp-monorepo-react-nestjs/apps/server/.env.development +61 -0
- package/template-vp-monorepo-react-nestjs/apps/server/.env.production +20 -0
- package/template-vp-monorepo-react-nestjs/apps/server/README.md +3 -0
- package/template-vp-monorepo-react-nestjs/apps/server/drizzle.config.ts +15 -0
- package/template-vp-monorepo-react-nestjs/apps/server/nest-cli.json +8 -0
- package/template-vp-monorepo-react-nestjs/apps/server/package.json +57 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/app.controller.ts +12 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/app.module.ts +58 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/app.service.ts +8 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/constants/decorator.ts +2 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/constants/response.ts +15 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/decorators/bypass.ts +12 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/interceptors/transform.ts +34 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/model/response.ts +23 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/config/app.config.ts +6 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/config/auth.config.ts +64 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/config/database.config.ts +10 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/config/index.ts +5 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/config/llm.config.ts +7 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/config/redis.config.ts +18 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/database/db.module.ts +32 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/database/schema.ts +73 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/main.ts +34 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/test/db/db.controller.ts +28 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/test/db/db.module.ts +9 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/test/db/db.service.ts +22 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/test/db/dto/create-user.dto.ts +27 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/test/redis/dto/redis-quary.dto.ts +18 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/test/redis/redis.controller.ts +31 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/test/redis/redis.module.ts +9 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/test/redis/redis.service.ts +37 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/utils/server-address.ts +33 -0
- package/template-vp-monorepo-react-nestjs/apps/server/tsconfig.build.json +4 -0
- package/template-vp-monorepo-react-nestjs/apps/server/tsconfig.json +28 -0
- package/template-vp-monorepo-react-nestjs/apps/web/.env +1 -0
- package/template-vp-monorepo-react-nestjs/apps/web/.env.dev +1 -0
- package/template-vp-monorepo-react-nestjs/apps/web/.env.prod +1 -0
- package/template-vp-monorepo-react-nestjs/apps/web/package.json +21 -25
- package/template-vp-monorepo-react-nestjs/apps/web/src/App.tsx +5 -4
- package/template-vp-monorepo-react-nestjs/apps/web/src/locales/en_US.json +4 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/locales/zh_CN.json +4 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/main.tsx +4 -4
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/home/index.tsx +38 -8
- package/template-vp-monorepo-react-nestjs/apps/web/src/router/index.tsx +15 -15
- package/template-vp-monorepo-react-nestjs/apps/web/src/utils/env/index.ts +6 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/utils/request/core/index.ts +420 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/utils/request/core/utils.ts +39 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/utils/request/index.ts +61 -0
- package/template-vp-monorepo-react-nestjs/apps/web/tsconfig.json +10 -14
- package/template-vp-monorepo-react-nestjs/apps/web/vite.config.ts +15 -2
- package/template-vp-monorepo-react-nestjs/apps/web-vue/.env.production +2 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/.vscode/extensions.json +3 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/AGENTS.md +16 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/README.md +98 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/commitlint.config.js +1 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/eslint.config.js +13 -0
- package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/lefthook.yml +1 -1
- package/template-vp-monorepo-react-nestjs/apps/web-vue/package.json +67 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/pnpm-workspace.yaml +16 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/App.vue +12 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/api/index.ts +12 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/assets/image/.gitkeep +0 -0
- package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/src/components/Icon/svg-icon.vue +3 -3
- package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/src/hooks/chart/lib.ts +6 -6
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/hooks/chart/useEcharts.ts +65 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/i18n/instance.ts +8 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/layout/default/header/index.vue +30 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/layout/default/index.vue +138 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/locales/en_US.json +4 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/locales/zh_CN.json +4 -0
- package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/src/main.ts +0 -3
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/router/guard/index.ts +7 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/router/guard/permissionGuard.ts +13 -0
- package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/src/router/index.ts +7 -7
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/router/interface.ts +9 -0
- package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/src/router/modules/index.ts +1 -4
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/store/index.ts +11 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/store/modules/user.ts +17 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/styles/font.scss +0 -0
- package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/src/styles/index.scss +3 -3
- package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/src/types/components.d.ts +8 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/types/vite-env.d.ts +15 -0
- package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/src/utils/env.ts +1 -1
- package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/src/utils/request/index.ts +5 -3
- package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/src/views/example/echart/config.ts +687 -687
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/views/example/echart/index.vue +20 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/views/example/tree-chart.vue +16 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/views/home/index.vue +27 -0
- package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/tsconfig.json +2 -9
- package/template-vp-monorepo-react-nestjs/apps/web-vue/uno.config.ts +17 -0
- package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/vite.config.ts +4 -6
- package/template-vp-monorepo-react-nestjs/commitlint.config.js +0 -0
- package/template-vp-monorepo-react-nestjs/docker-compose.yml +41 -0
- package/template-vp-monorepo-react-nestjs/mise.toml +3 -0
- package/template-vp-monorepo-react-nestjs/package.json +16 -11
- package/template-vp-monorepo-react-nestjs/packages/i18n/core/package.json +20 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/core/src/format.ts +9 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/core/src/i18n.ts +73 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/core/src/index.ts +24 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/core/src/storage.ts +47 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/core/src/store.ts +48 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/core/src/types.ts +36 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/core/tsconfig.json +15 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/core/vite.config.ts +13 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/react/package.json +28 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/react/src/index.tsx +26 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/react/src/use-store.ts +14 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/react/tsconfig.json +16 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/react/vite.config.ts +16 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/vue/package.json +27 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/vue/src/index.ts +52 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/vue/src/use-store.ts +19 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/vue/tsconfig.json +15 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/vue/vite.config.ts +16 -0
- package/template-vp-monorepo-react-nestjs/pnpm-workspace.yaml +97 -9
- package/template-vp-monorepo-react-nestjs/vite.config.ts +16 -4
- package/template-vp-vue-eslint-vapor/.env +6 -0
- package/template-vp-vue-eslint-vapor/.env.development +2 -0
- package/template-vp-vue-eslint-vapor/.env.production +2 -0
- package/template-vp-vue-eslint-vapor/.vite-hooks/commit-msg +1 -0
- package/template-vp-vue-eslint-vapor/.vite-hooks/pre-commit +1 -0
- package/template-vp-vue-eslint-vapor/.vscode/extensions.json +3 -0
- package/template-vp-vue-eslint-vapor/AGENTS.md +16 -0
- package/template-vp-vue-eslint-vapor/README.md +93 -0
- package/template-vp-vue-eslint-vapor/commitlint.config.js +1 -0
- package/template-vp-vue-eslint-vapor/eslint.config.js +13 -0
- package/template-vp-vue-eslint-vapor/index.html +13 -0
- package/template-vp-vue-eslint-vapor/package.json +64 -0
- package/template-vp-vue-eslint-vapor/pnpm-workspace.yaml +2 -0
- package/template-vp-vue-eslint-vapor/public/vite.svg +1 -0
- package/template-vp-vue-eslint-vapor/src/App.vue +7 -0
- package/template-vp-vue-eslint-vapor/src/api/index.ts +12 -0
- package/template-vp-vue-eslint-vapor/src/assets/icon/home.svg +3 -0
- package/template-vp-vue-eslint-vapor/src/assets/icon/logo.svg +1 -0
- package/template-vp-vue-eslint-vapor/src/assets/image/.gitkeep +0 -0
- package/template-vp-vue-eslint-vapor/src/components/Icon/svg-icon.vue +29 -0
- package/template-vp-vue-eslint-vapor/src/hooks/chart/lib.ts +57 -0
- package/template-vp-vue-eslint-vapor/src/hooks/chart/useEcharts.ts +65 -0
- package/template-vp-vue-eslint-vapor/src/layout/default/header/index.vue +57 -0
- package/template-vp-vue-eslint-vapor/src/layout/default/index.vue +138 -0
- package/template-vp-vue-eslint-vapor/src/main.ts +19 -0
- package/template-vp-vue-eslint-vapor/src/router/guard/index.ts +7 -0
- package/{template-vue-vite-eslint → template-vp-vue-eslint-vapor}/src/router/guard/permissionGuard.ts +3 -3
- package/template-vp-vue-eslint-vapor/src/router/index.ts +18 -0
- package/template-vp-vue-eslint-vapor/src/router/interface.ts +9 -0
- package/template-vp-vue-eslint-vapor/src/router/modules/index.ts +33 -0
- package/template-vp-vue-eslint-vapor/src/store/index.ts +11 -0
- package/template-vp-vue-eslint-vapor/src/store/modules/user.ts +17 -0
- package/template-vp-vue-eslint-vapor/src/styles/font.scss +0 -0
- package/template-vp-vue-eslint-vapor/src/styles/index.scss +29 -0
- package/template-vp-vue-eslint-vapor/src/styles/variables.scss +3 -0
- package/template-vp-vue-eslint-vapor/src/types/vite-env.d.ts +15 -0
- package/template-vp-vue-eslint-vapor/src/utils/env.ts +11 -0
- package/template-vp-vue-eslint-vapor/src/utils/request/core/index.ts +425 -0
- package/template-vp-vue-eslint-vapor/src/utils/request/core/utils.ts +39 -0
- package/template-vp-vue-eslint-vapor/src/utils/request/index.ts +44 -0
- package/template-vp-vue-eslint-vapor/src/views/example/echart/config.ts +1794 -0
- package/template-vp-vue-eslint-vapor/src/views/example/echart/index.vue +20 -0
- package/template-vp-vue-eslint-vapor/src/views/example/tree-chart.vue +16 -0
- package/template-vp-vue-eslint-vapor/src/views/home/index.vue +16 -0
- package/template-vp-vue-eslint-vapor/src/views/login/index.vue +9 -0
- package/template-vp-vue-eslint-vapor/tsconfig.json +32 -0
- package/template-vp-vue-eslint-vapor/tsconfig.tsbuildinfo +1 -0
- package/template-vp-vue-eslint-vapor/uno.config.ts +17 -0
- package/template-vp-vue-eslint-vapor/vite.config.ts +66 -0
- package/template-vue-vp-eslint/.env +6 -0
- package/template-vue-vp-eslint/.env.development +2 -0
- package/template-vue-vp-eslint/.env.production +2 -0
- package/template-vue-vp-eslint/.vscode/extensions.json +3 -0
- package/template-vue-vp-eslint/AGENTS.md +16 -0
- package/template-vue-vp-eslint/README.md +98 -0
- package/template-vue-vp-eslint/commitlint.config.js +1 -0
- package/template-vue-vp-eslint/eslint.config.js +13 -0
- package/template-vue-vp-eslint/index.html +13 -0
- package/template-vue-vp-eslint/lefthook.yml +11 -0
- package/template-vue-vp-eslint/package.json +63 -0
- package/template-vue-vp-eslint/pnpm-workspace.yaml +3 -0
- package/template-vue-vp-eslint/public/vite.svg +1 -0
- package/template-vue-vp-eslint/src/App.vue +7 -0
- package/template-vue-vp-eslint/src/api/index.ts +12 -0
- package/template-vue-vp-eslint/src/assets/icon/home.svg +3 -0
- package/template-vue-vp-eslint/src/assets/icon/logo.svg +1 -0
- package/template-vue-vp-eslint/src/assets/image/.gitkeep +0 -0
- package/template-vue-vp-eslint/src/components/Icon/svg-icon.vue +29 -0
- package/template-vue-vp-eslint/src/hooks/chart/lib.ts +57 -0
- package/template-vue-vp-eslint/src/hooks/chart/useEcharts.ts +65 -0
- package/template-vue-vp-eslint/src/layout/default/header/index.vue +30 -0
- package/template-vue-vp-eslint/src/layout/default/index.vue +138 -0
- package/template-vue-vp-eslint/src/main.ts +16 -0
- package/template-vue-vp-eslint/src/router/guard/index.ts +7 -0
- package/template-vue-vp-eslint/src/router/guard/permissionGuard.ts +13 -0
- package/template-vue-vp-eslint/src/router/index.ts +18 -0
- package/template-vue-vp-eslint/src/router/interface.ts +9 -0
- package/template-vue-vp-eslint/src/router/modules/index.ts +33 -0
- package/template-vue-vp-eslint/src/store/index.ts +11 -0
- package/template-vue-vp-eslint/src/store/modules/user.ts +17 -0
- package/template-vue-vp-eslint/src/styles/font.scss +0 -0
- package/template-vue-vp-eslint/src/styles/index.scss +29 -0
- package/template-vue-vp-eslint/src/styles/variables.scss +3 -0
- package/template-vue-vp-eslint/src/types/vite-env.d.ts +15 -0
- package/template-vue-vp-eslint/src/utils/env.ts +11 -0
- package/template-vue-vp-eslint/src/utils/request/core/index.ts +425 -0
- package/template-vue-vp-eslint/src/utils/request/core/utils.ts +39 -0
- package/template-vue-vp-eslint/src/utils/request/index.ts +44 -0
- package/template-vue-vp-eslint/src/views/example/echart/config.ts +1794 -0
- package/template-vue-vp-eslint/src/views/example/echart/index.vue +20 -0
- package/template-vue-vp-eslint/src/views/example/tree-chart.vue +16 -0
- package/template-vue-vp-eslint/src/views/home/index.vue +16 -0
- package/template-vue-vp-eslint/src/views/login/index.vue +9 -0
- package/template-vue-vp-eslint/tsconfig.json +29 -0
- package/template-vue-vp-eslint/uno.config.ts +17 -0
- package/template-vue-vp-eslint/vite.config.ts +58 -0
- package/template-vp-monorepo-react-nestjs/.oxfmtrc.jsonc +0 -8
- package/template-vp-monorepo-react-nestjs/.oxlintrc.jsonc +0 -3
- package/template-vp-monorepo-react-nestjs/.specs//351/234/200/346/261/202.md +0 -5
- package/template-vp-monorepo-react-nestjs/apps/service/.oxlintrc.jsonc +0 -3
- package/template-vp-monorepo-react-nestjs/apps/web/.oxlintrc.jsonc +0 -4
- package/template-vp-monorepo-react-nestjs/packages/utils/README.md +0 -23
- package/template-vp-monorepo-react-nestjs/packages/utils/package.json +0 -39
- package/template-vp-monorepo-react-nestjs/packages/utils/src/index.ts +0 -3
- package/template-vp-monorepo-react-nestjs/packages/utils/tests/index.test.ts +0 -6
- package/template-vp-monorepo-react-nestjs/packages/utils/tsconfig.json +0 -20
- package/template-vp-monorepo-react-nestjs/packages/utils/tsdown.config.ts +0 -9
- package/template-vp-monorepo-react-nestjs/packages/utils/vite.config.ts +0 -7
- package/template-vue-vite-eslint/.env.production +0 -1
- package/template-vue-vite-eslint/README.md +0 -3
- package/template-vue-vite-eslint/commitlint.config.js +0 -1
- package/template-vue-vite-eslint/eslint.config.js +0 -69
- package/template-vue-vite-eslint/package.json +0 -56
- package/template-vue-vite-eslint/src/App.vue +0 -19
- package/template-vue-vite-eslint/src/api/index.ts +0 -12
- package/template-vue-vite-eslint/src/hooks/chart/useEcharts.ts +0 -65
- package/template-vue-vite-eslint/src/layout/default/header/index.vue +0 -12
- package/template-vue-vite-eslint/src/layout/default/index.vue +0 -55
- package/template-vue-vite-eslint/src/router/guard/index.ts +0 -7
- package/template-vue-vite-eslint/src/router/interface.ts +0 -9
- package/template-vue-vite-eslint/src/router/modules/example.ts +0 -21
- package/template-vue-vite-eslint/src/store/index.ts +0 -11
- package/template-vue-vite-eslint/src/store/modules/user.ts +0 -20
- package/template-vue-vite-eslint/src/types/vite-env.d.ts +0 -15
- package/template-vue-vite-eslint/src/views/example/echart/index.vue +0 -22
- package/template-vue-vite-eslint/src/views/example/h-full.vue +0 -24
- package/template-vue-vite-eslint/src/views/example/tree-chart.vue +0 -94
- package/template-vue-vite-eslint/src/views/home/index.vue +0 -25
- package/template-vue-vite-eslint/uno.config.ts +0 -21
- /package/{template-vue-vite-eslint/src/assets/image/.gitkeep → template-vp-monorepo-react-nestjs/.agents/auth.config.ts} +0 -0
- /package/{template-vue-vite-eslint/src/styles/font.scss → template-vp-monorepo-react-nestjs/apps/server/src/config/security.config.ts} +0 -0
- /package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/.env +0 -0
- /package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/.env.development +0 -0
- /package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/index.html +0 -0
- /package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/public/vite.svg +0 -0
- /package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/src/assets/icon/computer-data.svg +0 -0
- /package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/src/assets/icon/cpu.svg +0 -0
- /package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/src/assets/icon/data-search.svg +0 -0
- /package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/src/assets/icon/home.svg +0 -0
- /package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/src/assets/icon/knowledge-graph.svg +0 -0
- /package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/src/assets/icon/logo.svg +0 -0
- /package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/src/assets/icon/robot.svg +0 -0
- /package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/src/styles/variables.scss +0 -0
- /package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/src/types/auto-import.d.ts +0 -0
- /package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/src/utils/request/core/index.ts +0 -0
- /package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/src/utils/request/core/utils.ts +0 -0
- /package/{template-vue-vite-eslint → template-vp-monorepo-react-nestjs/apps/web-vue}/src/views/login/index.vue +0 -0
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# vp staged
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"eslint.enable": false,
|
|
3
|
+
"prettier.enable": false,
|
|
4
|
+
"biome.enabled": false,
|
|
5
|
+
// "npm.scriptRunner": "vp",
|
|
6
|
+
"editor.defaultFormatter": "oxc.oxc-vscode",
|
|
7
|
+
"[javascript]": {
|
|
8
|
+
"editor.defaultFormatter": "oxc.oxc-vscode"
|
|
9
|
+
},
|
|
10
|
+
"[javascriptreact]": {
|
|
11
|
+
"editor.defaultFormatter": "oxc.oxc-vscode"
|
|
12
|
+
},
|
|
13
|
+
"[typescript]": {
|
|
14
|
+
"editor.defaultFormatter": "oxc.oxc-vscode"
|
|
15
|
+
},
|
|
16
|
+
"[typescriptreact]": {
|
|
17
|
+
"editor.defaultFormatter": "oxc.oxc-vscode"
|
|
18
|
+
},
|
|
19
|
+
"oxc.fmt.configPath": "./vite.config.ts",
|
|
20
|
+
"editor.formatOnSave": true,
|
|
21
|
+
"editor.formatOnSaveMode": "file",
|
|
22
|
+
"editor.codeActionsOnSave": {
|
|
23
|
+
"source.organizeImports": "always",
|
|
24
|
+
"source.fixAll.oxc": "always"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<!--VITE PLUS START-->
|
|
2
|
+
|
|
3
|
+
# Using Vite+, the Unified Toolchain for the Web
|
|
4
|
+
|
|
5
|
+
This project is using Vite+, a unified toolchain built on top of Vite, Rolldown, Vitest, tsdown, Oxlint, Oxfmt, and Vite Task. Vite+ wraps runtime management, package management, and frontend tooling in a single global CLI called `vp`. Vite+ is distinct from Vite, and it invokes Vite through `vp dev` and `vp build`. Run `vp help` to print a list of commands and `vp <command> --help` for information about a specific command.
|
|
6
|
+
|
|
7
|
+
Docs are local at `node_modules/vite-plus/docs` or online at https://viteplus.dev/guide/.
|
|
8
|
+
|
|
9
|
+
## Review Checklist
|
|
10
|
+
|
|
11
|
+
- [ ] Run `vp install` after pulling remote changes and before getting started.
|
|
12
|
+
- [ ] Run `vp check` and `vp test` to format, lint, type check and test changes.
|
|
13
|
+
- [ ] Check if there are `vite.config.ts` tasks or `package.json` scripts necessary for validation, run via `vp run <script>`.
|
|
14
|
+
- [ ] If setup, runtime, or package-manager behavior looks wrong, run `vp env doctor` and include its output when asking for help.
|
|
15
|
+
|
|
16
|
+
<!--VITE PLUS END-->
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
NODE_ENV=development
|
|
2
|
+
JWT_SECRET=development_jwt_secret_change_me
|
|
3
|
+
|
|
4
|
+
DATABASE_URL=postgresql://postgres:ml@localhost:5432/postgres
|
|
5
|
+
DB_HOST=localhost
|
|
6
|
+
DB_PORT=5432
|
|
7
|
+
DB_DATABASE=postgres
|
|
8
|
+
DB_USERNAME=postgres
|
|
9
|
+
DB_PASSWORD=ml
|
|
10
|
+
|
|
11
|
+
LLM_API_URL=https://api-inference.modelscope.cn/v1
|
|
12
|
+
LLM_API_MODEL=deepseek-ai/DeepSeek-V3.2
|
|
13
|
+
##ZhipuAI/GLM-5.1
|
|
14
|
+
LLM_API_KEY=ms-6c0d8bc9-ed99-4515-81f3-db1341fe9e76
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# Redis
|
|
18
|
+
REDIS_HOST=localhost
|
|
19
|
+
REDIS_PORT=6379
|
|
20
|
+
REDIS_PASSWORD=ml
|
|
21
|
+
REDIS_DB=0
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# JWT的签名密钥 服务器签发access token 使用它签名 整整token shi
|
|
25
|
+
JWT_ACCESS_SECRET=oM1FmlgA-tpflskKz5jZRYf2-_QK-aPhjtboFYaqTtlqB4RNgWUFNsp3irMUUdJF
|
|
26
|
+
# JWT 的签发者,对应 JWT 中的 iss 字段:
|
|
27
|
+
JWT_ISSUER=bubbles-auth
|
|
28
|
+
# 验证 Token 时,服务器会检查它是不是由 bubbles-auth 签发的。它是标识符,不是密码。 JWT 的目标使用者,对应 aud 字段
|
|
29
|
+
# 表示这个 Token 是给 bubbles-api 使用的,避免一个系统签发的 JWT 被误用到另一个系统。
|
|
30
|
+
JWT_AUDIENCE=bubbles-api
|
|
31
|
+
# Access Token 的有效时间:
|
|
32
|
+
JWT_ACCESS_TTL_SECONDS=600
|
|
33
|
+
# JWT 时间校验的允许误差:
|
|
34
|
+
JWT_CLOCK_TOLERANCE_SECONDS=30
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# Refresh Token 的服务端“椒值”,通常用于计算哈希:
|
|
38
|
+
REFRESH_TOKEN_PEPPER=ON-ECMSvcmjVryktpp-1BLpDl3r7Sl63-GXyy1uto2_1AbqCbNOndIfdtuBVe1o_
|
|
39
|
+
# Refresh Token 的有效时间: 30 天
|
|
40
|
+
REFRESH_TOKEN_TTL_SECONDS=2592000
|
|
41
|
+
# 保存 Refresh Token 的 Cookie 名称,浏览器中大致是:
|
|
42
|
+
# 生产环境如果使用 __Host- 安全前缀,可以改成: __Host-refresh_token
|
|
43
|
+
# REFRESH_COOKIE_PATH=/
|
|
44
|
+
# REFRESH_COOKIE_SECURE=true
|
|
45
|
+
# 并且不能设置 Domain。
|
|
46
|
+
REFRESH_COOKIE_NAME=refresh_token
|
|
47
|
+
# Cookie 只会自动发送给 /auth 路径下的接口 这样可以减少 Refresh Token 暴露给无关接口的机会。
|
|
48
|
+
REFRESH_COOKIE_PATH=/auth
|
|
49
|
+
# 表示这个 Cookie 不强制要求 HTTPS,适合本地 HTTP 开发
|
|
50
|
+
REFRESH_COOKIE_SECURE=false
|
|
51
|
+
|
|
52
|
+
# 认证状态在当前服务进程的本地内存中缓存
|
|
53
|
+
# 例如服务器查到“用户正常、会话有效”,可以缓存 30 秒,避免每个请求都查询数据库或 Redis。
|
|
54
|
+
# 本地缓存意味着每个 NestJS 实例都有自己的缓存,所以还需要下面的失效通知机制。
|
|
55
|
+
AUTH_LOCAL_CACHE_TTL_MS=30000
|
|
56
|
+
|
|
57
|
+
#
|
|
58
|
+
AUTH_TOMBSTONE_TTL_SECONDS=900
|
|
59
|
+
|
|
60
|
+
# 当修改密码或者踢人的时候通过这个通道 通知用户失效
|
|
61
|
+
AUTH_EVENT_CHANNEL=auth-state:invalidate
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
NODE_ENV=production
|
|
2
|
+
JWT_SECRET=production_jwt_secret_change_me
|
|
3
|
+
|
|
4
|
+
DATABASE_URL=postgresql://postgres:ml@localhost:5432/postgres
|
|
5
|
+
DB_HOST=localhost
|
|
6
|
+
DB_PORT=5432
|
|
7
|
+
DB_DATABASE=postgres
|
|
8
|
+
DB_USERNAME=postgres
|
|
9
|
+
DB_PASSWORD=ml
|
|
10
|
+
|
|
11
|
+
LLM_API_URL=https://api-inference.modelscope.cn/v1
|
|
12
|
+
LLM_API_MODEL=deepseek-ai/DeepSeek-V4-Pro
|
|
13
|
+
LLM_API_KEY=ms-6c0d8bc9-ed99-4515-81f3-db1341fe9e76
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# Redis
|
|
17
|
+
REDIS_HOST=localhost
|
|
18
|
+
REDIS_PORT=6379
|
|
19
|
+
REDIS_PASSWORD=ml
|
|
20
|
+
REDIS_DB=0
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { config } from 'dotenv'
|
|
2
|
+
import { defineConfig } from 'drizzle-kit'
|
|
3
|
+
|
|
4
|
+
config({
|
|
5
|
+
path: '.env.development',
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
export default defineConfig({
|
|
9
|
+
schema: './src/database/schema.ts',
|
|
10
|
+
out: './drizzle',
|
|
11
|
+
dialect: 'postgresql',
|
|
12
|
+
dbCredentials: {
|
|
13
|
+
url: process.env.DATABASE_URL!,
|
|
14
|
+
},
|
|
15
|
+
})
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "server",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"private": true,
|
|
5
|
+
"description": "",
|
|
6
|
+
"license": "UNLICENSED",
|
|
7
|
+
"author": "",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "nest build",
|
|
10
|
+
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
|
11
|
+
"dev": "nest start --watch",
|
|
12
|
+
"debug": "nest start --debug --watch",
|
|
13
|
+
"build:preview": "node dist/main",
|
|
14
|
+
"db:push": "drizzle-kit push",
|
|
15
|
+
"db:generate": "drizzle-kit generate",
|
|
16
|
+
"db:migrate": "drizzle-kit migrate",
|
|
17
|
+
"db:studio": "drizzle-kit studio"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@fastify/cookie": "catalog:",
|
|
21
|
+
"@nestjs-modules/ioredis": "catalog:",
|
|
22
|
+
"@nestjs/common": "catalog:",
|
|
23
|
+
"@nestjs/config": "catalog:",
|
|
24
|
+
"@nestjs/core": "catalog:",
|
|
25
|
+
"@nestjs/jwt": "catalog:",
|
|
26
|
+
"@nestjs/mapped-types": "catalog:",
|
|
27
|
+
"@nestjs/platform-fastify": "catalog:",
|
|
28
|
+
"argon2": "catalog:",
|
|
29
|
+
"drizzle-orm": "catalog:",
|
|
30
|
+
"drizzle-zod": "catalog:",
|
|
31
|
+
"fastify": "5.8.5",
|
|
32
|
+
"ioredis": "catalog:",
|
|
33
|
+
"nestjs-zod": "catalog:",
|
|
34
|
+
"pg": "catalog:",
|
|
35
|
+
"reflect-metadata": "catalog:",
|
|
36
|
+
"rxjs": "catalog:",
|
|
37
|
+
"zod": "catalog:"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@fastify/static": "catalog:",
|
|
41
|
+
"@nestjs/cli": "catalog:",
|
|
42
|
+
"@nestjs/schematics": "catalog:",
|
|
43
|
+
"@nestjs/swagger": "catalog:",
|
|
44
|
+
"@nestjs/testing": "catalog:",
|
|
45
|
+
"@types/express": "catalog:",
|
|
46
|
+
"@types/node": "catalog:node24",
|
|
47
|
+
"cross-env": "catalog:",
|
|
48
|
+
"dotenv": "catalog:",
|
|
49
|
+
"drizzle-kit": "catalog:",
|
|
50
|
+
"globals": "catalog:",
|
|
51
|
+
"source-map-support": "catalog:",
|
|
52
|
+
"ts-loader": "catalog:",
|
|
53
|
+
"ts-node": "catalog:",
|
|
54
|
+
"tsconfig-paths": "catalog:",
|
|
55
|
+
"typescript": "catalog:"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Controller, Get } from '@nestjs/common'
|
|
2
|
+
import { AppService } from './app.service'
|
|
3
|
+
|
|
4
|
+
@Controller()
|
|
5
|
+
export class AppController {
|
|
6
|
+
constructor(private readonly appService: AppService) {}
|
|
7
|
+
|
|
8
|
+
@Get()
|
|
9
|
+
getHello(): string {
|
|
10
|
+
return this.appService.getHello()
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Module } from '@nestjs/common'
|
|
2
|
+
import { AppController } from './app.controller'
|
|
3
|
+
import { AppService } from './app.service'
|
|
4
|
+
import { ConfigModule, ConfigService } from '@nestjs/config'
|
|
5
|
+
import { appConfig, databaseConfig, llmConfig, redisConfig, authConfig } from '@/config'
|
|
6
|
+
import { ResponseInterceptor } from '@/common/interceptors/transform'
|
|
7
|
+
import { APP_INTERCEPTOR, APP_PIPE } from '@nestjs/core'
|
|
8
|
+
import { RedisModule } from '@nestjs-modules/ioredis'
|
|
9
|
+
import { TestRedisModule } from './modules/test/redis/redis.module'
|
|
10
|
+
import { DatabaseModule } from './database/db.module'
|
|
11
|
+
import { TestDbModule } from './modules/test/db/db.module'
|
|
12
|
+
import { ZodSerializerInterceptor, ZodValidationPipe } from 'nestjs-zod'
|
|
13
|
+
|
|
14
|
+
const nodeEnv = process.env.NODE_ENV ?? 'development'
|
|
15
|
+
|
|
16
|
+
@Module({
|
|
17
|
+
imports: [
|
|
18
|
+
ConfigModule.forRoot({
|
|
19
|
+
isGlobal: true,
|
|
20
|
+
envFilePath: [`.env.${nodeEnv}.local`, '.env.local', `.env.${nodeEnv}`, '.env'],
|
|
21
|
+
load: [appConfig, databaseConfig, llmConfig, redisConfig, authConfig],
|
|
22
|
+
}),
|
|
23
|
+
DatabaseModule,
|
|
24
|
+
RedisModule.forRootAsync({
|
|
25
|
+
inject: [ConfigService],
|
|
26
|
+
useFactory: (config) => ({
|
|
27
|
+
type: 'single',
|
|
28
|
+
options: {
|
|
29
|
+
host: config.get('redis.host'),
|
|
30
|
+
port: config.get('redis.port'),
|
|
31
|
+
password: config.get('redis.password'),
|
|
32
|
+
db: config.get('redis.db'),
|
|
33
|
+
},
|
|
34
|
+
}),
|
|
35
|
+
}),
|
|
36
|
+
TestRedisModule,
|
|
37
|
+
TestDbModule,
|
|
38
|
+
],
|
|
39
|
+
controllers: [AppController],
|
|
40
|
+
providers: [
|
|
41
|
+
AppService,
|
|
42
|
+
{
|
|
43
|
+
provide: APP_INTERCEPTOR,
|
|
44
|
+
useClass: ResponseInterceptor,
|
|
45
|
+
},
|
|
46
|
+
// ZOD 全局校验管道
|
|
47
|
+
{
|
|
48
|
+
provide: APP_PIPE,
|
|
49
|
+
useClass: ZodValidationPipe,
|
|
50
|
+
},
|
|
51
|
+
// 相应序列化拦截器(让相应也走Zod 防泄漏字段)
|
|
52
|
+
{
|
|
53
|
+
provide: APP_INTERCEPTOR,
|
|
54
|
+
useClass: ZodSerializerInterceptor,
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
})
|
|
58
|
+
export class AppModule {}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const RESPONSE_SUCCESS_CODE = 200
|
|
2
|
+
|
|
3
|
+
export const RESPONSE_SUCCESS_MSG = 'success'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @description contentType
|
|
7
|
+
*/
|
|
8
|
+
export enum ContentTypeEnum {
|
|
9
|
+
// json
|
|
10
|
+
JSON = 'application/json;charset=UTF-8',
|
|
11
|
+
// form-data qs
|
|
12
|
+
FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8',
|
|
13
|
+
// form-data upload
|
|
14
|
+
FORM_DATA = 'multipart/form-data;charset=UTF-8',
|
|
15
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CallHandler,
|
|
3
|
+
ExecutionContext,
|
|
4
|
+
HttpStatus,
|
|
5
|
+
Injectable,
|
|
6
|
+
NestInterceptor,
|
|
7
|
+
} from '@nestjs/common'
|
|
8
|
+
import { Reflector } from '@nestjs/core'
|
|
9
|
+
import { map } from 'rxjs'
|
|
10
|
+
|
|
11
|
+
import { BYPASS_KEY } from '../constants/decorator'
|
|
12
|
+
import { ResOp } from '../model/response'
|
|
13
|
+
|
|
14
|
+
@Injectable()
|
|
15
|
+
export class ResponseInterceptor<T> implements NestInterceptor<T> {
|
|
16
|
+
constructor(private readonly reflector: Reflector) {}
|
|
17
|
+
|
|
18
|
+
intercept(context: ExecutionContext, next: CallHandler<T>) {
|
|
19
|
+
const skip = this.reflector.getAllAndOverride<boolean>(BYPASS_KEY, [
|
|
20
|
+
context.getHandler(),
|
|
21
|
+
context.getClass(),
|
|
22
|
+
])
|
|
23
|
+
|
|
24
|
+
if (skip) {
|
|
25
|
+
return next.handle()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return next.handle().pipe(
|
|
29
|
+
map((data) => {
|
|
30
|
+
return new ResOp(HttpStatus.OK, data ?? null)
|
|
31
|
+
}),
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { RESPONSE_SUCCESS_CODE, RESPONSE_SUCCESS_MSG } from '@/common/constants/response'
|
|
2
|
+
|
|
3
|
+
export class ResOp<T = any> {
|
|
4
|
+
data?: T
|
|
5
|
+
|
|
6
|
+
code: number
|
|
7
|
+
|
|
8
|
+
message: string
|
|
9
|
+
|
|
10
|
+
constructor(code: number, data: T, message = RESPONSE_SUCCESS_MSG) {
|
|
11
|
+
this.code = code
|
|
12
|
+
this.data = data
|
|
13
|
+
this.message = message
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static success<T>(data?: T, message?: string) {
|
|
17
|
+
return new ResOp(RESPONSE_SUCCESS_CODE, data, message)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
static error(code: number, message) {
|
|
21
|
+
return new ResOp(code, {}, message)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { registerAs } from '@nestjs/config'
|
|
2
|
+
|
|
3
|
+
export interface AuthConfig {
|
|
4
|
+
accessSecret: string
|
|
5
|
+
issuer: string
|
|
6
|
+
audience: string
|
|
7
|
+
accessTtlSeconds: number
|
|
8
|
+
refreshTtlSeconds: number
|
|
9
|
+
refreshPepper: string
|
|
10
|
+
clockToleranceSeconds: number
|
|
11
|
+
localCacheTtlMs: number
|
|
12
|
+
tombstoneTtlSeconds: number
|
|
13
|
+
cookieName: string
|
|
14
|
+
cookiePath: string
|
|
15
|
+
cookieSecure: boolean
|
|
16
|
+
cookieDomain?: string
|
|
17
|
+
eventChannel: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function requireSecret(name: string) {
|
|
21
|
+
const value = process.env[name]?.trim()
|
|
22
|
+
|
|
23
|
+
if (!value || value.length < 32) {
|
|
24
|
+
throw new Error(name + ' 必须配置,并且至少 32 个字符')
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return value
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function positiveInt(name: string, fallback: number) {
|
|
31
|
+
const raw = process.env[name]
|
|
32
|
+
|
|
33
|
+
if (!raw) {
|
|
34
|
+
return fallback
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const value = Number.parseInt(raw, 10)
|
|
38
|
+
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
39
|
+
throw new Error(name + ' 必须是正整数')
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return value
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export default registerAs(
|
|
46
|
+
'auth',
|
|
47
|
+
(): AuthConfig => ({
|
|
48
|
+
accessSecret: requireSecret('JWT_ACCESS_SECRET'),
|
|
49
|
+
issuer: process.env.JWT_ISSUER ?? 'bubbles-auth',
|
|
50
|
+
audience: process.env.JWT_AUDIENCE ?? 'bubbles-api',
|
|
51
|
+
accessTtlSeconds: positiveInt('JWT_ACCESS_TTL_SECONDS', 10 * 60),
|
|
52
|
+
refreshTtlSeconds: positiveInt('REFRESH_TOKEN_TTL_SECONDS', 30 * 24 * 60 * 60),
|
|
53
|
+
refreshPepper: requireSecret('REFRESH_TOKEN_PEPPER'),
|
|
54
|
+
clockToleranceSeconds: positiveInt('JWT_CLOCK_TOLERANCE_SECONDS', 30),
|
|
55
|
+
localCacheTtlMs: positiveInt('AUTH_LOCAL_CACHE_TTL_MS', 30_000),
|
|
56
|
+
tombstoneTtlSeconds: positiveInt('AUTH_TOMBSTONE_TTL_SECONDS', 15 * 60),
|
|
57
|
+
cookieName: process.env.REFRESH_COOKIE_NAME ?? 'refresh_token',
|
|
58
|
+
cookiePath: process.env.REFRESH_COOKIE_PATH ?? '/auth',
|
|
59
|
+
cookieSecure:
|
|
60
|
+
process.env.REFRESH_COOKIE_SECURE === 'true' || process.env.NODE_ENV === 'production',
|
|
61
|
+
cookieDomain: process.env.REFRESH_COOKIE_DOMAIN,
|
|
62
|
+
eventChannel: process.env.AUTH_EVENT_CHANNEL ?? 'auth-state:invalidate',
|
|
63
|
+
}),
|
|
64
|
+
)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { registerAs } from '@nestjs/config'
|
|
2
|
+
|
|
3
|
+
export default registerAs('database', () => ({
|
|
4
|
+
url: process.env.DATABASE_URL,
|
|
5
|
+
host: process.env.DB_HOST ?? 'localhost',
|
|
6
|
+
port: Number.parseInt(process.env.DB_PORT ?? '5432', 10),
|
|
7
|
+
database: process.env.DB_DATABASE ?? 'postgres',
|
|
8
|
+
username: process.env.DB_USERNAME ?? 'postgres',
|
|
9
|
+
password: process.env.DB_PASSWORD,
|
|
10
|
+
}))
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { default as appConfig } from './app.config'
|
|
2
|
+
export { default as databaseConfig } from './database.config'
|
|
3
|
+
export { default as llmConfig } from './llm.config'
|
|
4
|
+
export { default as redisConfig } from './redis.config'
|
|
5
|
+
export { default as authConfig } from './auth.config'
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { registerAs } from '@nestjs/config'
|
|
2
|
+
|
|
3
|
+
export interface RedisConfig {
|
|
4
|
+
host: string
|
|
5
|
+
port: number
|
|
6
|
+
password?: string
|
|
7
|
+
db: number
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default registerAs(
|
|
11
|
+
'redis',
|
|
12
|
+
(): RedisConfig => ({
|
|
13
|
+
host: process.env.REDIS_HOST ?? 'localhost',
|
|
14
|
+
port: Number.parseInt(process.env.REDIS_PORT ?? '6379', 10),
|
|
15
|
+
password: process.env.REDIS_PASSWORD || undefined,
|
|
16
|
+
db: Number.parseInt(process.env.REDIS_DB ?? '0', 10),
|
|
17
|
+
}),
|
|
18
|
+
)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Global, Module } from '@nestjs/common'
|
|
2
|
+
import { drizzle, NodePgDatabase } from 'drizzle-orm/node-postgres'
|
|
3
|
+
import * as schema from '@/database/schema'
|
|
4
|
+
import { ConfigService } from '@nestjs/config'
|
|
5
|
+
import { Pool } from 'pg'
|
|
6
|
+
|
|
7
|
+
export const DRIZZLE = Symbol('DRIZZLE_DB')
|
|
8
|
+
|
|
9
|
+
export type DrizzleDB = NodePgDatabase<typeof schema>
|
|
10
|
+
|
|
11
|
+
@Global()
|
|
12
|
+
@Module({
|
|
13
|
+
providers: [
|
|
14
|
+
{
|
|
15
|
+
provide: DRIZZLE,
|
|
16
|
+
inject: [ConfigService],
|
|
17
|
+
useFactory: (config: ConfigService) => {
|
|
18
|
+
const pool = new Pool({
|
|
19
|
+
host: config.get<string>('database.host'),
|
|
20
|
+
port: config.get<number>('database.port'),
|
|
21
|
+
database: config.get<string>('database.database'),
|
|
22
|
+
user: config.get<string>('database.username'),
|
|
23
|
+
password: config.get<string>('database.password'),
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
return drizzle(pool, { schema })
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
exports: [DRIZZLE],
|
|
31
|
+
})
|
|
32
|
+
export class DatabaseModule {}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import {
|
|
2
|
+
index,
|
|
3
|
+
integer,
|
|
4
|
+
pgEnum,
|
|
5
|
+
pgTable,
|
|
6
|
+
serial,
|
|
7
|
+
timestamp,
|
|
8
|
+
uuid,
|
|
9
|
+
varchar,
|
|
10
|
+
} from 'drizzle-orm/pg-core'
|
|
11
|
+
|
|
12
|
+
export const userStatusEnum = pgEnum('user_status', ['active', 'locked', 'disabled'])
|
|
13
|
+
|
|
14
|
+
export const authSessionStatusEnum = pgEnum('auth_session_status', ['active', 'revoked'])
|
|
15
|
+
|
|
16
|
+
export const refreshFamilyStatusEnum = pgEnum('refresh_family_status', [
|
|
17
|
+
'active',
|
|
18
|
+
'revoked',
|
|
19
|
+
'compromised',
|
|
20
|
+
])
|
|
21
|
+
|
|
22
|
+
export const refreshTokenStatusEnum = pgEnum('refresh_token_status', [
|
|
23
|
+
'active',
|
|
24
|
+
'consumed',
|
|
25
|
+
'revoked',
|
|
26
|
+
])
|
|
27
|
+
|
|
28
|
+
export const users = pgTable('users', {
|
|
29
|
+
id: serial('id').primaryKey(),
|
|
30
|
+
name: varchar('name', { length: 100 }).notNull(),
|
|
31
|
+
email: varchar('email', { length: 255 }).notNull().unique(),
|
|
32
|
+
// 第一阶段先允许 null,旧账号完成密码回填后再改成 notNull
|
|
33
|
+
passwordHash: varchar('password_hash', { length: 255 }), // .notNull(),
|
|
34
|
+
|
|
35
|
+
status: userStatusEnum('status').default('active').notNull(),
|
|
36
|
+
authEpoch: integer('auth_epoch').default(1).notNull(),
|
|
37
|
+
passwordChangeAt: timestamp('password_change_at', {
|
|
38
|
+
withTimezone: true,
|
|
39
|
+
}),
|
|
40
|
+
|
|
41
|
+
createdAt: timestamp('create_at').defaultNow().notNull(),
|
|
42
|
+
updatedAt: timestamp('update_at', { withTimezone: true }).defaultNow().notNull(),
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
export const authSessions = pgTable(
|
|
46
|
+
'auth_sessions',
|
|
47
|
+
{
|
|
48
|
+
id: uuid('id').defaultRandom().primaryKey(),
|
|
49
|
+
userId: integer('user_id')
|
|
50
|
+
.notNull()
|
|
51
|
+
.references(() => users.id, { onDelete: 'restrict' }),
|
|
52
|
+
version: integer('version').default(1).notNull(),
|
|
53
|
+
status: authSessionStatusEnum('status').default('active').notNull(),
|
|
54
|
+
expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(),
|
|
55
|
+
revokedAt: timestamp('revoked_at', { withTimezone: true }),
|
|
56
|
+
revokeReason: varchar('revoke_reason', { length: 100 }),
|
|
57
|
+
ip: varchar('ip', { length: 64 }),
|
|
58
|
+
userAgent: varchar('user_agent', { length: 500 }),
|
|
59
|
+
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
|
60
|
+
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
|
61
|
+
},
|
|
62
|
+
(table) => [
|
|
63
|
+
index('auth_sessions_user_id_idx').on(table.userId),
|
|
64
|
+
index('auth_sessions_user_status_idx').on(table.userId, table.status),
|
|
65
|
+
],
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
export const refreshTokenFamilies = pgTable('refresh_token_families', {
|
|
69
|
+
id: uuid('id').defaultRandom().primaryKey(),
|
|
70
|
+
sessionId: uuid('session_id')
|
|
71
|
+
.notNull()
|
|
72
|
+
.references(() => authSessions.id, { onDelete: 'restrict' }),
|
|
73
|
+
})
|