@qlover/create-app 0.9.0 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/templates/next-app/.env.template +9 -10
- package/dist/templates/next-app/eslint.config.mjs +5 -0
- package/dist/templates/next-app/migrations/schema/UserSchema.ts +17 -3
- package/dist/templates/next-app/next.config.ts +1 -1
- package/dist/templates/next-app/package.json +2 -3
- package/dist/templates/next-app/src/app/[locale]/login/page.tsx +1 -1
- package/dist/templates/next-app/src/app/[locale]/page.tsx +1 -1
- package/dist/templates/next-app/src/app/[locale]/register/page.tsx +1 -1
- package/dist/templates/next-app/src/app/api/locales/json/route.ts +2 -1
- package/dist/templates/next-app/src/base/cases/DialogHandler.ts +1 -2
- package/dist/templates/next-app/src/base/cases/RequestEncryptPlugin.ts +4 -5
- package/dist/templates/next-app/src/base/cases/UserServiceApi.ts +44 -29
- package/dist/templates/next-app/src/base/cases/ZodColumnBuilder.ts +1 -2
- package/dist/templates/next-app/src/base/port/AppUserApiInterface.ts +22 -10
- package/dist/templates/next-app/src/base/port/UserServiceInterface.ts +17 -9
- package/dist/templates/next-app/src/base/services/ResourceService.ts +3 -4
- package/dist/templates/next-app/src/base/services/UserService.ts +37 -13
- package/dist/templates/next-app/src/base/services/appApi/AppApiRequester.ts +8 -7
- package/dist/templates/next-app/src/base/services/appApi/AppUserApi.ts +15 -26
- package/dist/templates/next-app/src/core/clientIoc/ClientIOC.ts +4 -3
- package/dist/templates/next-app/src/core/clientIoc/ClientIOCRegister.ts +4 -3
- package/dist/templates/next-app/src/core/globals.ts +2 -1
- package/dist/templates/next-app/src/core/serverIoc/ServerIOC.ts +4 -3
- package/dist/templates/next-app/src/core/serverIoc/ServerIOCRegister.ts +5 -6
- package/dist/templates/next-app/src/i18n/request.ts +2 -2
- package/dist/templates/next-app/src/server/UserCredentialToken.ts +1 -3
- package/dist/templates/next-app/src/uikit/components/LocaleLink.tsx +1 -2
- package/dist/templates/react-app/__tests__/__mocks__/{MockAppConfit.ts → MockAppConfig.ts} +1 -1
- package/dist/templates/react-app/__tests__/__mocks__/components/TestApp.tsx +10 -17
- package/dist/templates/react-app/__tests__/__mocks__/components/TestBootstrapsProvider.tsx +27 -8
- package/dist/templates/react-app/__tests__/__mocks__/createMockGlobals.ts +1 -1
- package/dist/templates/react-app/__tests__/__mocks__/i18nextHttpBackend.ts +110 -0
- package/dist/templates/react-app/__tests__/__mocks__/testIOC/TestIOCRegister.ts +3 -2
- package/dist/templates/react-app/__tests__/setup/setupGlobal.ts +13 -0
- package/dist/templates/react-app/__tests__/src/base/services/I18nService.test.ts +3 -1
- package/dist/templates/react-app/config/IOCIdentifier.ts +9 -6
- package/dist/templates/react-app/config/common.ts +38 -0
- package/dist/templates/react-app/config/feapi.mock.json +5 -12
- package/dist/templates/react-app/eslint.config.mjs +6 -5
- package/dist/templates/react-app/package.json +1 -1
- package/dist/templates/react-app/src/base/apis/userApi/UserApi.ts +22 -13
- package/dist/templates/react-app/src/base/apis/userApi/UserApiBootstarp.ts +3 -3
- package/dist/templates/react-app/src/base/apis/userApi/UserApiType.ts +17 -12
- package/dist/templates/react-app/src/base/cases/I18nKeyErrorPlugin.ts +19 -2
- package/dist/templates/react-app/src/base/port/RouteServiceInterface.ts +2 -4
- package/dist/templates/react-app/src/base/port/UserServiceInterface.ts +15 -9
- package/dist/templates/react-app/src/base/services/BaseLayoutService.ts +55 -0
- package/dist/templates/react-app/src/base/services/I18nService.ts +1 -0
- package/dist/templates/react-app/src/base/services/UserBootstrap.ts +43 -0
- package/dist/templates/react-app/src/base/services/UserGatewayPlugin.ts +16 -0
- package/dist/templates/react-app/src/base/services/UserService.ts +51 -80
- package/dist/templates/react-app/src/core/bootstraps/BootstrapClient.ts +8 -3
- package/dist/templates/react-app/src/core/bootstraps/BootstrapsRegistry.ts +6 -6
- package/dist/templates/react-app/src/core/bootstraps/SaveAppInfo.ts +28 -0
- package/dist/templates/react-app/src/core/clientIoc/ClientIOCRegister.ts +24 -18
- package/dist/templates/react-app/src/core/globals.ts +10 -11
- package/dist/templates/react-app/src/main.tsx +1 -1
- package/dist/templates/react-app/src/pages/auth/Layout.tsx +4 -4
- package/dist/templates/react-app/src/pages/auth/RegisterPage.tsx +1 -1
- package/dist/templates/react-app/src/pages/base/Layout.tsx +3 -3
- package/dist/templates/react-app/src/uikit/components/BaseLayoutProvider.tsx +44 -0
- package/dist/templates/react-app/src/uikit/components/LogoutButton.tsx +1 -3
- package/dist/templates/react-app/src/uikit/hooks/useNavigateBridge.ts +9 -0
- package/dist/templates/react-app/src/uikit/hooks/{useI18nGuard.ts → useRouterI18nGuard.ts} +7 -4
- package/dist/templates/react-app/tsconfig.app.json +1 -1
- package/package.json +3 -3
- package/dist/templates/react-app/__tests__/src/base/cases/AppError.test.ts +0 -102
- package/dist/templates/react-app/__tests__/src/main.integration.test.tsx +0 -61
- package/dist/templates/react-app/src/base/services/ProcesserExecutor.ts +0 -57
- package/dist/templates/react-app/src/uikit/components/ProcessExecutorProvider.tsx +0 -28
- package/dist/templates/react-app/src/uikit/components/UserAuthProvider.tsx +0 -16
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @qlover/create-app
|
|
2
2
|
|
|
3
|
+
## 0.10.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
## 0.10.0
|
|
8
|
+
|
|
9
|
+
### Minor Changes
|
|
10
|
+
|
|
11
|
+
#### ✨ Features
|
|
12
|
+
|
|
13
|
+
- **react-app:** Update TypeScript configurations and enhance user services ([6b33d18](https://github.com/qlover/fe-base/commit/6b33d18bdec4d0943a615d746e929348ea965031)) ([#545](https://github.com/qlover/fe-base/pull/545))
|
|
14
|
+
- Added path mappings for corekit-bridge and fe-corekit in TypeScript configuration files.
|
|
15
|
+
- Refactored integration tests to use updated import paths and improved error handling.
|
|
16
|
+
- Introduced a new BaseLayoutService for managing user authentication and layout rendering.
|
|
17
|
+
- Enhanced UserService with credential management and user information validation.
|
|
18
|
+
- Removed obsolete ProcesserExecutor and UserAuthProvider components to streamline the codebase.
|
|
19
|
+
- Updated mock API configurations for improved endpoint handling and response structures.
|
|
20
|
+
- Added new hooks for router internationalization and layout management.
|
|
21
|
+
|
|
3
22
|
## 0.9.0
|
|
4
23
|
|
|
5
24
|
### Minor Changes
|
package/dist/index.cjs
CHANGED
|
@@ -8,4 +8,4 @@ ${t}`,_n=Object.getOwnPropertyDescriptor(Function.prototype,"toString"),mn=Objec
|
|
|
8
8
|
`))this.#e+=Math.max(1,Math.ceil(Ye(D,{countAnsiEscapeCodes:!0})/t))}get isEnabled(){return this.#a&&!this.#F}set isEnabled(t){if(typeof t!="boolean")throw new TypeError("The `isEnabled` option must be a boolean");this.#a=t}get isSilent(){return this.#F}set isSilent(t){if(typeof t!="boolean")throw new TypeError("The `isSilent` option must be a boolean");this.#F=t}frame(){let t=Date.now();(this.#i===-1||t-this.#c>=this.interval)&&(this.#i=++this.#i%this.#D.frames.length,this.#c=t);let{frames:r}=this.#D,u=r[this.#i];this.color&&(u=d[this.color](u));let i=typeof this.#s=="string"&&this.#s!==""?this.#s+" ":"",D=typeof this.text=="string"?" "+this.text:"",o=typeof this.#o=="string"&&this.#o!==""?" "+this.#o:"";return i+u+D+o}clear(){if(!this.#a||!this.#u.isTTY)return this;this.#u.cursorTo(0);for(let t=0;t<this.#n;t++)t>0&&this.#u.moveCursor(0,-1),this.#u.clearLine(1);return(this.#l||this.lastIndent!==this.#l)&&this.#u.cursorTo(this.#l),this.lastIndent=this.#l,this.#n=0,this}render(){return this.#F?this:(this.clear(),this.#u.write(this.frame()),this.#n=this.#e,this)}start(t){return t&&(this.text=t),this.#F?this:this.#a?this.isSpinning?this:(this.#t.hideCursor&&$e.hide(this.#u),this.#t.discardStdin&&V.default.stdin.isTTY&&(this.#r=!0,Je.start()),this.render(),this.#f=setInterval(this.render.bind(this),this.interval),this):(this.text&&this.#u.write(`- ${this.text}
|
|
9
9
|
`),this)}stop(){return this.#a?(clearInterval(this.#f),this.#f=void 0,this.#i=0,this.clear(),this.#t.hideCursor&&$e.show(this.#u),this.#t.discardStdin&&V.default.stdin.isTTY&&this.#r&&(Je.stop(),this.#r=!1),this):this}succeed(t){return this.stopAndPersist({symbol:H.success,text:t})}fail(t){return this.stopAndPersist({symbol:H.error,text:t})}warn(t){return this.stopAndPersist({symbol:H.warning,text:t})}info(t){return this.stopAndPersist({symbol:H.info,text:t})}stopAndPersist(t={}){if(this.#F)return this;let r=t.prefixText??this.#s,u=this.#E(r," "),i=t.symbol??" ",D=t.text??this.text,s=typeof D=="string"?(i?" ":"")+D:"",a=t.suffixText??this.#o,l=this.#g(a," "),p=u+i+s+l+`
|
|
10
10
|
`;return this.stop(),this.#u.write(p),this}};function rr(e){return new Ze(e)}async function ur(e,t){let r=typeof e=="function",u=typeof e.then=="function";if(!r&&!u)throw new TypeError("Parameter `action` must be a Function or a Promise");let{successText:i,failText:D}=typeof t=="object"?t:{successText:void 0,failText:void 0},o=rr(t).start();try{let a=await(r?e(o):e);return o.succeed(i===void 0?void 0:typeof i=="string"?i:i(a)),a}catch(s){throw o.fail(D===void 0?void 0:typeof D=="string"?D:D(s)),s}}var bt=require("fs");var P=require("path"),me=require("fs"),fr=h(cr(),1),Dt=require("fs");var de=require("fs"),X=class{static ensureDir(t){(0,de.existsSync)(t)||(0,de.mkdirSync)(t,{recursive:!0})}};var{copyFile:us,stat:is}=Dt.promises,_e=class e{constructor(t,r=e.IGNORE_FILE){this.ignoreTargetPath=t;this.ignoreFile=r}static IGNORE_FILE=".gitignore.template";getIg(t=this.ignoreTargetPath){let r=(0,P.join)(t,this.ignoreFile);if(!(0,me.existsSync)(r))return;let D=(0,me.readFileSync)(r,"utf8").split(`
|
|
11
|
-
`).map(o=>o.trim()).filter(o=>o&&!o.startsWith("#"));return(0,fr.default)().add(D)}async copyFiles(t,r,u,i){let D=await Dt.promises.readdir(t);await Promise.all(D.map(async o=>{let s=(0,P.join)(t,o),a=(0,P.join)(r,o);if(u&&u.ignores(o))return;if(X.ensureDir((0,P.dirname)(a)),(await is(s)).isDirectory())await this.copyFiles(s,a,u,i);else{if(i&&await i(s,a))return;await us(s,a)}}))}copyPaths({sourcePath:t,targetPath:r,copyCallback:u}){X.ensureDir(r);let i=this.getIg();return this.copyFiles(t,r,i,u)}};var L=require("fs"),$D=h(kD(),1),xe=class{constructor(){}isJSONFilePath(t){return t.endsWith(".json")||t.endsWith(".json.template")}isTemplateFilePath(t){return t.endsWith(".template")}getRealTemplateFilePath(t){return t.replace(".template","")}readFile(t){return(0,L.readFileSync)(t,"utf-8")}readJSONFile(t){return JSON.parse(this.readFile(t))}writeFile(t,r){(0,L.writeFileSync)(this.getRealTemplateFilePath(t),r,{encoding:"utf-8"})}replaceFile(t,r){let u=this.readFile(t);return Object.keys(r).forEach(i=>{let D=r[i];u=u.replace(new RegExp(`\\[TPL:${i}\\]`,"g"),typeof D=="string"?D:JSON.stringify(D))}),u}mergeJSONFile(t,r){let u=this.readJSONFile(t),i=(0,$D.default)(r,u);this.writeFile(t,JSON.stringify(i,null,2))}composeConfigFile(t,r,u){if(this.isTemplateFilePath(r)){let i=this.replaceFile(r,t);if(this.isJSONFilePath(r)&&this.isJSONFilePath(u)){let D=this.getRealTemplateFilePath(u);return(0,L.existsSync)(D)?(this.mergeJSONFile(D,JSON.parse(i)),!0):(this.writeFile(D,i),!0)}return this.writeFile(u,i),!0}return!1}};var UD=["pack-app"],ye=class{ora;context;subPackages;copyer;compose;constructor(t){let r=t.options?.templateRootPath;if(!r)throw new Error("template path not exit");if(!(0,bt.existsSync)(r))throw new Error("template path not exit");this.ora=ur,this.context=new WD.ScriptContext("create-app",t),this.subPackages=["node-lib","react-app","next-app"],this.copyer=new _e((0,v.join)(this.context.options.configsRootPath,"_common")),this.compose=new xe}get logger(){return this.context.logger}async steps(t){try{return await HD.default.prompt(t)}catch(r){throw r.isTtyError,this.logger.error(r),r}}async action({label:t,task:r}){let u=r();u instanceof Promise||(u=Promise.resolve(u));let i=t;return this.ora(u,i),u}isPackageTemplate(t){return UD.includes(t)}async getGeneratorContext(){let t=wt(this.subPackages,UD),r=await this.steps(t);if(this.isPackageTemplate(r.template)){let u=Pt(this.subPackages),i=await this.steps(u);Object.assign(r,i)}return r.targetPath=(0,v.join)(process.cwd(),r.projectName),r.releasePath=r.releasePath||"src",r}async generate(){let t=await this.getGeneratorContext();if(this.logger.debug("context is:",t,this.context.options.templateRootPath),t.subPackages){await this.action({label:"Generate Directories(subPackages)",task:async()=>{await this.generateTemplateDir(t),await this.generateSubPackages(t),await this.generateConfigs(t,t.targetPath,"_common")}});return}await this.action({label:"Generate Directory",task:async()=>{await this.generateTemplateDir(t),await this.generateConfigs(t,t.targetPath,"_common"),await this.generateConfigs(t,t.targetPath,t.template)}})}async generateConfigs(t,r,u){let i=(a,l)=>(this.logger.debug("copyCallback",a,l),this.compose.composeConfigFile(t,a,l)),{configsRootPath:D,config:o}=this.context.options;if(!o){this.logger.debug("no copy config files");return}let s=(0,v.join)(D,u);if(!(0,bt.existsSync)(s)){this.logger.debug(`Config path not found: ${s}`);return}await this.copyer.copyPaths({sourcePath:s,targetPath:r,copyCallback:i})}generateTemplateDir(t){return this.copyer.copyPaths({sourcePath:(0,v.join)(this.context.options.templateRootPath,t.template),targetPath:t.targetPath})}async generateSubPackages(t){let{packagesNames:r="packages",subPackages:u=[],targetPath:i=""}=t,{templateRootPath:D}=this.context.options;for(let o of u){let s=(0,v.join)(D,o),a=(0,v.join)(i,r,o);this.logger.debug("copy sub package",s,a),await this.copyer.copyPaths({sourcePath:s,targetPath:a})}}};var vt={name:"@qlover/create-app",version:"0.
|
|
11
|
+
`).map(o=>o.trim()).filter(o=>o&&!o.startsWith("#"));return(0,fr.default)().add(D)}async copyFiles(t,r,u,i){let D=await Dt.promises.readdir(t);await Promise.all(D.map(async o=>{let s=(0,P.join)(t,o),a=(0,P.join)(r,o);if(u&&u.ignores(o))return;if(X.ensureDir((0,P.dirname)(a)),(await is(s)).isDirectory())await this.copyFiles(s,a,u,i);else{if(i&&await i(s,a))return;await us(s,a)}}))}copyPaths({sourcePath:t,targetPath:r,copyCallback:u}){X.ensureDir(r);let i=this.getIg();return this.copyFiles(t,r,i,u)}};var L=require("fs"),$D=h(kD(),1),xe=class{constructor(){}isJSONFilePath(t){return t.endsWith(".json")||t.endsWith(".json.template")}isTemplateFilePath(t){return t.endsWith(".template")}getRealTemplateFilePath(t){return t.replace(".template","")}readFile(t){return(0,L.readFileSync)(t,"utf-8")}readJSONFile(t){return JSON.parse(this.readFile(t))}writeFile(t,r){(0,L.writeFileSync)(this.getRealTemplateFilePath(t),r,{encoding:"utf-8"})}replaceFile(t,r){let u=this.readFile(t);return Object.keys(r).forEach(i=>{let D=r[i];u=u.replace(new RegExp(`\\[TPL:${i}\\]`,"g"),typeof D=="string"?D:JSON.stringify(D))}),u}mergeJSONFile(t,r){let u=this.readJSONFile(t),i=(0,$D.default)(r,u);this.writeFile(t,JSON.stringify(i,null,2))}composeConfigFile(t,r,u){if(this.isTemplateFilePath(r)){let i=this.replaceFile(r,t);if(this.isJSONFilePath(r)&&this.isJSONFilePath(u)){let D=this.getRealTemplateFilePath(u);return(0,L.existsSync)(D)?(this.mergeJSONFile(D,JSON.parse(i)),!0):(this.writeFile(D,i),!0)}return this.writeFile(u,i),!0}return!1}};var UD=["pack-app"],ye=class{ora;context;subPackages;copyer;compose;constructor(t){let r=t.options?.templateRootPath;if(!r)throw new Error("template path not exit");if(!(0,bt.existsSync)(r))throw new Error("template path not exit");this.ora=ur,this.context=new WD.ScriptContext("create-app",t),this.subPackages=["node-lib","react-app","next-app"],this.copyer=new _e((0,v.join)(this.context.options.configsRootPath,"_common")),this.compose=new xe}get logger(){return this.context.logger}async steps(t){try{return await HD.default.prompt(t)}catch(r){throw r.isTtyError,this.logger.error(r),r}}async action({label:t,task:r}){let u=r();u instanceof Promise||(u=Promise.resolve(u));let i=t;return this.ora(u,i),u}isPackageTemplate(t){return UD.includes(t)}async getGeneratorContext(){let t=wt(this.subPackages,UD),r=await this.steps(t);if(this.isPackageTemplate(r.template)){let u=Pt(this.subPackages),i=await this.steps(u);Object.assign(r,i)}return r.targetPath=(0,v.join)(process.cwd(),r.projectName),r.releasePath=r.releasePath||"src",r}async generate(){let t=await this.getGeneratorContext();if(this.logger.debug("context is:",t,this.context.options.templateRootPath),t.subPackages){await this.action({label:"Generate Directories(subPackages)",task:async()=>{await this.generateTemplateDir(t),await this.generateSubPackages(t),await this.generateConfigs(t,t.targetPath,"_common")}});return}await this.action({label:"Generate Directory",task:async()=>{await this.generateTemplateDir(t),await this.generateConfigs(t,t.targetPath,"_common"),await this.generateConfigs(t,t.targetPath,t.template)}})}async generateConfigs(t,r,u){let i=(a,l)=>(this.logger.debug("copyCallback",a,l),this.compose.composeConfigFile(t,a,l)),{configsRootPath:D,config:o}=this.context.options;if(!o){this.logger.debug("no copy config files");return}let s=(0,v.join)(D,u);if(!(0,bt.existsSync)(s)){this.logger.debug(`Config path not found: ${s}`);return}await this.copyer.copyPaths({sourcePath:s,targetPath:r,copyCallback:i})}generateTemplateDir(t){return this.copyer.copyPaths({sourcePath:(0,v.join)(this.context.options.templateRootPath,t.template),targetPath:t.targetPath})}async generateSubPackages(t){let{packagesNames:r="packages",subPackages:u=[],targetPath:i=""}=t,{templateRootPath:D}=this.context.options;for(let o of u){let s=(0,v.join)(D,o),a=(0,v.join)(i,r,o);this.logger.debug("copy sub package",s,a),await this.copyer.copyPaths({sourcePath:s,targetPath:a})}}};var vt={name:"@qlover/create-app",version:"0.10.1",description:"Create a new app with a single command",private:!1,type:"module",files:["dist","package.json","README.md","CHANGELOG.md"],bin:{"create-app":"dist/index.js"},scripts:{lint:"eslint src --fix",build:"tsup","create:app":"node ./dist/index.js"},repository:{type:"git",url:"git+https://github.com/qlover/fe-base.git",directory:"packages/create-app"},homepage:"https://github.com/qlover/fe-base#readme",keywords:["create-app","fe-scripts","scripts"],author:"qlover",license:"ISC",publishConfig:{access:"public"},devDependencies:{"@qlover/logger":"workspace:*",ignore:"^7.0.3",lodash:"^4.17.21",ora:"^8.1.1"},dependencies:{"@qlover/scripts-context":"workspace:*",commander:"^13.1.0",inquirer:"^12.3.2"}};function Wl(){let e=new YD.Command;return e.version(vt.version,"-v, --version","Show version").description(vt.description).option("-d, --dry-run","Do not touch or write anything, but show the commands").option("-V, --verbose","Show more information").option("--config","Copy config files (default: true)",!0).option("--no-config","Do not copy config files"),e.parse(),e.opts()}async function VD(e=process.cwd()){let{dryRun:t,verbose:r,...u}=Wl(),i=(0,xt.resolve)(e,"./templates"),D=(0,xt.resolve)(e,"./configs");(0,yt.existsSync)(i)||(console.error("Template is empty!"),process.exit(1)),(0,yt.existsSync)(D)||(console.error("Configs is empty!"),process.exit(1)),await new ye({dryRun:t,verbose:r,options:{...u,templateRootPath:i,configsRootPath:D}}).generate()}VD(__dirname).catch(e=>{console.error(e),process.exit(1)});
|
package/dist/index.js
CHANGED
|
@@ -8,4 +8,4 @@ ${t}`,pD=Object.getOwnPropertyDescriptor(Function.prototype,"toString"),hD=Objec
|
|
|
8
8
|
`))this.#e+=Math.max(1,Math.ceil(Le(n,{countAnsiEscapeCodes:!0})/t))}get isEnabled(){return this.#a&&!this.#F}set isEnabled(t){if(typeof t!="boolean")throw new TypeError("The `isEnabled` option must be a boolean");this.#a=t}get isSilent(){return this.#F}set isSilent(t){if(typeof t!="boolean")throw new TypeError("The `isSilent` option must be a boolean");this.#F=t}frame(){let t=Date.now();(this.#i===-1||t-this.#c>=this.interval)&&(this.#i=++this.#i%this.#n.frames.length,this.#c=t);let{frames:r}=this.#n,u=r[this.#i];this.color&&(u=E[this.color](u));let i=typeof this.#s=="string"&&this.#s!==""?this.#s+" ":"",n=typeof this.text=="string"?" "+this.text:"",o=typeof this.#o=="string"&&this.#o!==""?" "+this.#o:"";return i+u+n+o}clear(){if(!this.#a||!this.#u.isTTY)return this;this.#u.cursorTo(0);for(let t=0;t<this.#D;t++)t>0&&this.#u.moveCursor(0,-1),this.#u.clearLine(1);return(this.#l||this.lastIndent!==this.#l)&&this.#u.cursorTo(this.#l),this.lastIndent=this.#l,this.#D=0,this}render(){return this.#F?this:(this.clear(),this.#u.write(this.frame()),this.#D=this.#e,this)}start(t){return t&&(this.text=t),this.#F?this:this.#a?this.isSpinning?this:(this.#t.hideCursor&&je.hide(this.#u),this.#t.discardStdin&&ce.stdin.isTTY&&(this.#r=!0,We.start()),this.render(),this.#f=setInterval(this.render.bind(this),this.interval),this):(this.text&&this.#u.write(`- ${this.text}
|
|
9
9
|
`),this)}stop(){return this.#a?(clearInterval(this.#f),this.#f=void 0,this.#i=0,this.clear(),this.#t.hideCursor&&je.show(this.#u),this.#t.discardStdin&&ce.stdin.isTTY&&this.#r&&(We.stop(),this.#r=!1),this):this}succeed(t){return this.stopAndPersist({symbol:k.success,text:t})}fail(t){return this.stopAndPersist({symbol:k.error,text:t})}warn(t){return this.stopAndPersist({symbol:k.warning,text:t})}info(t){return this.stopAndPersist({symbol:k.info,text:t})}stopAndPersist(t={}){if(this.#F)return this;let r=t.prefixText??this.#s,u=this.#E(r," "),i=t.symbol??" ",n=t.text??this.text,s=typeof n=="string"?(i?" ":"")+n:"",a=t.suffixText??this.#o,l=this.#g(a," "),p=u+i+s+l+`
|
|
10
10
|
`;return this.stop(),this.#u.write(p),this}};function zt(e){return new He(e)}async function Kt(e,t){let r=typeof e=="function",u=typeof e.then=="function";if(!r&&!u)throw new TypeError("Parameter `action` must be a Function or a Promise");let{successText:i,failText:n}=typeof t=="object"?t:{successText:void 0,failText:void 0},o=zt(t).start();try{let a=await(r?e(o):e);return o.succeed(i===void 0?void 0:typeof i=="string"?i:i(a)),a}catch(s){throw o.fail(n===void 0?void 0:typeof n=="string"?n:n(s)),s}}import{existsSync as Nn}from"fs";var nr=ue(ir(),1);import{dirname as QD,join as Ze}from"path";import{existsSync as es,readFileSync as ts}from"fs";import{promises as Dr}from"fs";import{existsSync as JD,mkdirSync as ZD}from"fs";var H=class{static ensureDir(t){JD(t)||ZD(t,{recursive:!0})}};var{copyFile:rs,stat:us}=Dr,Ce=class e{constructor(t,r=e.IGNORE_FILE){this.ignoreTargetPath=t;this.ignoreFile=r}static IGNORE_FILE=".gitignore.template";getIg(t=this.ignoreTargetPath){let r=Ze(t,this.ignoreFile);if(!es(r))return;let n=ts(r,"utf8").split(`
|
|
11
|
-
`).map(o=>o.trim()).filter(o=>o&&!o.startsWith("#"));return(0,nr.default)().add(n)}async copyFiles(t,r,u,i){let n=await Dr.readdir(t);await Promise.all(n.map(async o=>{let s=Ze(t,o),a=Ze(r,o);if(u&&u.ignores(o))return;if(H.ensureDir(QD(a)),(await us(s)).isDirectory())await this.copyFiles(s,a,u,i);else{if(i&&await i(s,a))return;await rs(s,a)}}))}copyPaths({sourcePath:t,targetPath:r,copyCallback:u}){H.ensureDir(r);let i=this.getIg();return this.copyFiles(t,r,i,u)}};var jn=ue(In(),1);import{readFileSync as $l,writeFileSync as Ul,existsSync as Wl}from"fs";var _e=class{constructor(){}isJSONFilePath(t){return t.endsWith(".json")||t.endsWith(".json.template")}isTemplateFilePath(t){return t.endsWith(".template")}getRealTemplateFilePath(t){return t.replace(".template","")}readFile(t){return $l(t,"utf-8")}readJSONFile(t){return JSON.parse(this.readFile(t))}writeFile(t,r){Ul(this.getRealTemplateFilePath(t),r,{encoding:"utf-8"})}replaceFile(t,r){let u=this.readFile(t);return Object.keys(r).forEach(i=>{let n=r[i];u=u.replace(new RegExp(`\\[TPL:${i}\\]`,"g"),typeof n=="string"?n:JSON.stringify(n))}),u}mergeJSONFile(t,r){let u=this.readJSONFile(t),i=(0,jn.default)(r,u);this.writeFile(t,JSON.stringify(i,null,2))}composeConfigFile(t,r,u){if(this.isTemplateFilePath(r)){let i=this.replaceFile(r,t);if(this.isJSONFilePath(r)&&this.isJSONFilePath(u)){let n=this.getRealTemplateFilePath(u);return Wl(n)?(this.mergeJSONFile(n,JSON.parse(i)),!0):(this.writeFile(n,i),!0)}return this.writeFile(u,i),!0}return!1}};var Gn=["pack-app"],Be=class{ora;context;subPackages;copyer;compose;constructor(t){let r=t.options?.templateRootPath;if(!r)throw new Error("template path not exit");if(!Nn(r))throw new Error("template path not exit");this.ora=Kt,this.context=new Hl("create-app",t),this.subPackages=["node-lib","react-app","next-app"],this.copyer=new Ce(N(this.context.options.configsRootPath,"_common")),this.compose=new _e}get logger(){return this.context.logger}async steps(t){try{return await Yl.prompt(t)}catch(r){throw r.isTtyError,this.logger.error(r),r}}async action({label:t,task:r}){let u=r();u instanceof Promise||(u=Promise.resolve(u));let i=t;return this.ora(u,i),u}isPackageTemplate(t){return Gn.includes(t)}async getGeneratorContext(){let t=mt(this.subPackages,Gn),r=await this.steps(t);if(this.isPackageTemplate(r.template)){let u=_t(this.subPackages),i=await this.steps(u);Object.assign(r,i)}return r.targetPath=N(process.cwd(),r.projectName),r.releasePath=r.releasePath||"src",r}async generate(){let t=await this.getGeneratorContext();if(this.logger.debug("context is:",t,this.context.options.templateRootPath),t.subPackages){await this.action({label:"Generate Directories(subPackages)",task:async()=>{await this.generateTemplateDir(t),await this.generateSubPackages(t),await this.generateConfigs(t,t.targetPath,"_common")}});return}await this.action({label:"Generate Directory",task:async()=>{await this.generateTemplateDir(t),await this.generateConfigs(t,t.targetPath,"_common"),await this.generateConfigs(t,t.targetPath,t.template)}})}async generateConfigs(t,r,u){let i=(a,l)=>(this.logger.debug("copyCallback",a,l),this.compose.composeConfigFile(t,a,l)),{configsRootPath:n,config:o}=this.context.options;if(!o){this.logger.debug("no copy config files");return}let s=N(n,u);if(!Nn(s)){this.logger.debug(`Config path not found: ${s}`);return}await this.copyer.copyPaths({sourcePath:s,targetPath:r,copyCallback:i})}generateTemplateDir(t){return this.copyer.copyPaths({sourcePath:N(this.context.options.templateRootPath,t.template),targetPath:t.targetPath})}async generateSubPackages(t){let{packagesNames:r="packages",subPackages:u=[],targetPath:i=""}=t,{templateRootPath:n}=this.context.options;for(let o of u){let s=N(n,o),a=N(i,r,o);this.logger.debug("copy sub package",s,a),await this.copyer.copyPaths({sourcePath:s,targetPath:a})}}};var Et={name:"@qlover/create-app",version:"0.
|
|
11
|
+
`).map(o=>o.trim()).filter(o=>o&&!o.startsWith("#"));return(0,nr.default)().add(n)}async copyFiles(t,r,u,i){let n=await Dr.readdir(t);await Promise.all(n.map(async o=>{let s=Ze(t,o),a=Ze(r,o);if(u&&u.ignores(o))return;if(H.ensureDir(QD(a)),(await us(s)).isDirectory())await this.copyFiles(s,a,u,i);else{if(i&&await i(s,a))return;await rs(s,a)}}))}copyPaths({sourcePath:t,targetPath:r,copyCallback:u}){H.ensureDir(r);let i=this.getIg();return this.copyFiles(t,r,i,u)}};var jn=ue(In(),1);import{readFileSync as $l,writeFileSync as Ul,existsSync as Wl}from"fs";var _e=class{constructor(){}isJSONFilePath(t){return t.endsWith(".json")||t.endsWith(".json.template")}isTemplateFilePath(t){return t.endsWith(".template")}getRealTemplateFilePath(t){return t.replace(".template","")}readFile(t){return $l(t,"utf-8")}readJSONFile(t){return JSON.parse(this.readFile(t))}writeFile(t,r){Ul(this.getRealTemplateFilePath(t),r,{encoding:"utf-8"})}replaceFile(t,r){let u=this.readFile(t);return Object.keys(r).forEach(i=>{let n=r[i];u=u.replace(new RegExp(`\\[TPL:${i}\\]`,"g"),typeof n=="string"?n:JSON.stringify(n))}),u}mergeJSONFile(t,r){let u=this.readJSONFile(t),i=(0,jn.default)(r,u);this.writeFile(t,JSON.stringify(i,null,2))}composeConfigFile(t,r,u){if(this.isTemplateFilePath(r)){let i=this.replaceFile(r,t);if(this.isJSONFilePath(r)&&this.isJSONFilePath(u)){let n=this.getRealTemplateFilePath(u);return Wl(n)?(this.mergeJSONFile(n,JSON.parse(i)),!0):(this.writeFile(n,i),!0)}return this.writeFile(u,i),!0}return!1}};var Gn=["pack-app"],Be=class{ora;context;subPackages;copyer;compose;constructor(t){let r=t.options?.templateRootPath;if(!r)throw new Error("template path not exit");if(!Nn(r))throw new Error("template path not exit");this.ora=Kt,this.context=new Hl("create-app",t),this.subPackages=["node-lib","react-app","next-app"],this.copyer=new Ce(N(this.context.options.configsRootPath,"_common")),this.compose=new _e}get logger(){return this.context.logger}async steps(t){try{return await Yl.prompt(t)}catch(r){throw r.isTtyError,this.logger.error(r),r}}async action({label:t,task:r}){let u=r();u instanceof Promise||(u=Promise.resolve(u));let i=t;return this.ora(u,i),u}isPackageTemplate(t){return Gn.includes(t)}async getGeneratorContext(){let t=mt(this.subPackages,Gn),r=await this.steps(t);if(this.isPackageTemplate(r.template)){let u=_t(this.subPackages),i=await this.steps(u);Object.assign(r,i)}return r.targetPath=N(process.cwd(),r.projectName),r.releasePath=r.releasePath||"src",r}async generate(){let t=await this.getGeneratorContext();if(this.logger.debug("context is:",t,this.context.options.templateRootPath),t.subPackages){await this.action({label:"Generate Directories(subPackages)",task:async()=>{await this.generateTemplateDir(t),await this.generateSubPackages(t),await this.generateConfigs(t,t.targetPath,"_common")}});return}await this.action({label:"Generate Directory",task:async()=>{await this.generateTemplateDir(t),await this.generateConfigs(t,t.targetPath,"_common"),await this.generateConfigs(t,t.targetPath,t.template)}})}async generateConfigs(t,r,u){let i=(a,l)=>(this.logger.debug("copyCallback",a,l),this.compose.composeConfigFile(t,a,l)),{configsRootPath:n,config:o}=this.context.options;if(!o){this.logger.debug("no copy config files");return}let s=N(n,u);if(!Nn(s)){this.logger.debug(`Config path not found: ${s}`);return}await this.copyer.copyPaths({sourcePath:s,targetPath:r,copyCallback:i})}generateTemplateDir(t){return this.copyer.copyPaths({sourcePath:N(this.context.options.templateRootPath,t.template),targetPath:t.targetPath})}async generateSubPackages(t){let{packagesNames:r="packages",subPackages:u=[],targetPath:i=""}=t,{templateRootPath:n}=this.context.options;for(let o of u){let s=N(n,o),a=N(i,r,o);this.logger.debug("copy sub package",s,a),await this.copyer.copyPaths({sourcePath:s,targetPath:a})}}};var Et={name:"@qlover/create-app",version:"0.10.1",description:"Create a new app with a single command",private:!1,type:"module",files:["dist","package.json","README.md","CHANGELOG.md"],bin:{"create-app":"dist/index.js"},scripts:{lint:"eslint src --fix",build:"tsup","create:app":"node ./dist/index.js"},repository:{type:"git",url:"git+https://github.com/qlover/fe-base.git",directory:"packages/create-app"},homepage:"https://github.com/qlover/fe-base#readme",keywords:["create-app","fe-scripts","scripts"],author:"qlover",license:"ISC",publishConfig:{access:"public"},devDependencies:{"@qlover/logger":"workspace:*",ignore:"^7.0.3",lodash:"^4.17.21",ora:"^8.1.1"},dependencies:{"@qlover/scripts-context":"workspace:*",commander:"^13.1.0",inquirer:"^12.3.2"}};function Kl(){let e=new zl;return e.version(Et.version,"-v, --version","Show version").description(Et.description).option("-d, --dry-run","Do not touch or write anything, but show the commands").option("-V, --verbose","Show more information").option("--config","Copy config files (default: true)",!0).option("--no-config","Do not copy config files"),e.parse(),e.opts()}async function kn(e=process.cwd()){let{dryRun:t,verbose:r,...u}=Kl(),i=Mn(e,"./templates"),n=Mn(e,"./configs");Ln(i)||(console.error("Template is empty!"),process.exit(1)),Ln(n)||(console.error("Configs is empty!"),process.exit(1)),await new Be({dryRun:t,verbose:r,options:{...u,templateRootPath:i,configsRootPath:n}}).generate()}import{fileURLToPath as Xl}from"url";import{dirname as Jl}from"path";var Zl=Xl(import.meta.url),Ql=Jl(Zl);kn(Ql).catch(e=>{console.error(e),process.exit(1)});
|
|
@@ -1,26 +1,25 @@
|
|
|
1
1
|
# ci
|
|
2
2
|
NPM_TOKEN=
|
|
3
3
|
GITHUB_TOKEN=
|
|
4
|
-
|
|
5
4
|
# fe-scripts
|
|
6
5
|
FE_RELEASE_BRANCH=master
|
|
7
6
|
FE_RELEASE=false
|
|
8
7
|
FE_RELEASE_ENV=localhost
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
APP_HOST=http://localhost:3100
|
|
8
|
+
# ===== server
|
|
9
|
+
APP_HOST=
|
|
12
10
|
SUPABASE_URL=
|
|
13
11
|
SUPABASE_ANON_KEY=
|
|
14
12
|
JWT_SECRET=
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
CEREBRAS_API_KEY=
|
|
14
|
+
CEREBRAS_BASE_URL=
|
|
15
|
+
# ===== browser
|
|
17
16
|
NEXT_PUBLIC_USER_TOKEN_STORAGE_KEY=fe_user_token
|
|
18
17
|
NEXT_PUBLIC_OPEN_AI_MODELS='["gpt-4o-mini","gpt-3.5-turbo","gpt-3.5-turbo-2","gpt-4","gpt-4-32k"]'
|
|
19
18
|
NEXT_PUBLIC_OPEN_AI_BASE_URL=
|
|
20
19
|
NEXT_PUBLIC_OPEN_AI_TOKEN=sk-proj-1234567890
|
|
21
20
|
NEXT_PUBLIC_OPEN_AI_TOKEN_PREFIX=Bearer
|
|
22
21
|
NEXT_PUBLIC_OPEN_AI_REQUIRE_TOKEN=true
|
|
23
|
-
NEXT_PUBLIC_LOGIN_USER=
|
|
24
|
-
NEXT_PUBLIC_LOGIN_PASSWORD=
|
|
25
|
-
NEXT_PUBLIC_FE_API_BASE_URL=https://
|
|
26
|
-
NEXT_PUBLIC_STRING_ENCRYPT_KEY=
|
|
22
|
+
NEXT_PUBLIC_LOGIN_USER=xxxx
|
|
23
|
+
NEXT_PUBLIC_LOGIN_PASSWORD=xxx
|
|
24
|
+
NEXT_PUBLIC_FE_API_BASE_URL=https://xxx.example.com/
|
|
25
|
+
NEXT_PUBLIC_STRING_ENCRYPT_KEY=xxx!@#
|
|
@@ -173,6 +173,11 @@ const eslintConfig = [
|
|
|
173
173
|
singleQuote: true,
|
|
174
174
|
trailingComma: 'none',
|
|
175
175
|
endOfLine: 'lf'
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
// 仅用于单独部署时对 eslint prettier 插件自动查找 prettierrc 时报错
|
|
179
|
+
// 注意: vscode 等编辑器会失效, 作为单独项目开发时可以去掉
|
|
180
|
+
usePrettierrc: false
|
|
176
181
|
}
|
|
177
182
|
],
|
|
178
183
|
// 默认禁用 export default
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import type { SafeParseReturnType } from 'zod';
|
|
2
3
|
|
|
3
4
|
export const UserRole = {
|
|
4
5
|
ADMIN: 0,
|
|
@@ -16,9 +17,22 @@ export const userSchema = z.object({
|
|
|
16
17
|
* 加密的token, 包含token, 过期时间
|
|
17
18
|
*/
|
|
18
19
|
credential_token: z.string(),
|
|
19
|
-
email_confirmed_at: z.number(),
|
|
20
|
-
created_at: z.
|
|
21
|
-
updated_at: z.
|
|
20
|
+
email_confirmed_at: z.number().nullable().optional(),
|
|
21
|
+
created_at: z.string(),
|
|
22
|
+
updated_at: z.string().nullable().optional()
|
|
22
23
|
});
|
|
23
24
|
|
|
24
25
|
export type UserSchema = z.infer<typeof userSchema>;
|
|
26
|
+
|
|
27
|
+
export type UserCredential = {
|
|
28
|
+
credential_token: string;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export function isWebUserSchema(
|
|
32
|
+
value: unknown
|
|
33
|
+
): SafeParseReturnType<
|
|
34
|
+
Omit<UserSchema, 'password'>,
|
|
35
|
+
Omit<UserSchema, 'password'>
|
|
36
|
+
> {
|
|
37
|
+
return userSchema.omit({ password: true }).safeParse(value);
|
|
38
|
+
}
|
|
@@ -2,7 +2,7 @@ import createNextIntlPlugin from 'next-intl/plugin';
|
|
|
2
2
|
import { generateLocales } from './make/generateLocales';
|
|
3
3
|
import type { NextConfig } from 'next';
|
|
4
4
|
|
|
5
|
-
const withNextIntl = createNextIntlPlugin();
|
|
5
|
+
const withNextIntl = createNextIntlPlugin('./src/i18n/request.ts');
|
|
6
6
|
|
|
7
7
|
// 在构建开始时生成本地化文件
|
|
8
8
|
generateLocales().catch((error) => {
|
|
@@ -24,10 +24,9 @@
|
|
|
24
24
|
"@brain-toolkit/antd-theme-override": "^0.0.3",
|
|
25
25
|
"@brain-toolkit/bridge": "^0.0.1",
|
|
26
26
|
"@brain-toolkit/react-kit": "^0.1.0",
|
|
27
|
-
"@qlover/corekit-bridge": "
|
|
28
|
-
"@qlover/fe-corekit": "
|
|
27
|
+
"@qlover/corekit-bridge": "latest",
|
|
28
|
+
"@qlover/fe-corekit": "latest",
|
|
29
29
|
"@qlover/slice-store-react": "^1.4.1",
|
|
30
|
-
"@supabase/auth-helpers-nextjs": "^0.10.0",
|
|
31
30
|
"@supabase/ssr": "^0.7.0",
|
|
32
31
|
"@supabase/supabase-js": "^2.57.2",
|
|
33
32
|
"@types/jsonwebtoken": "^9.0.10",
|
|
@@ -17,7 +17,7 @@ export async function generateStaticParams() {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
// Allow Next.js to statically generate this page if possible (default behavior)
|
|
20
|
-
|
|
20
|
+
// Note: 'auto' is not a valid value in Next.js 15, removed to use default behavior
|
|
21
21
|
|
|
22
22
|
// Optional: Use revalidate if you want ISR (Incremental Static Regeneration)
|
|
23
23
|
// export const revalidate = 3600; // Rebuild every hour (optional)
|
|
@@ -23,7 +23,7 @@ export async function generateStaticParams() {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
// Allow Next.js to statically generate this page if possible (default behavior)
|
|
26
|
-
|
|
26
|
+
// Note: 'auto' is not a valid value in Next.js 15, removed to use default behavior
|
|
27
27
|
|
|
28
28
|
// Optional: Use revalidate if you want ISR (Incremental Static Regeneration)
|
|
29
29
|
// export const revalidate = 3600; // Rebuild every hour (optional)
|
|
@@ -17,7 +17,7 @@ export async function generateStaticParams() {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
// Allow Next.js to statically generate this page if possible (default behavior)
|
|
20
|
-
|
|
20
|
+
// Note: 'auto' is not a valid value in Next.js 15, removed to use default behavior
|
|
21
21
|
|
|
22
22
|
// Optional: Use revalidate if you want ISR (Incremental Static Regeneration)
|
|
23
23
|
// export const revalidate = 3600; // Rebuild every hour (optional)
|
|
@@ -5,7 +5,8 @@ import { ApiLocaleService } from '@/server/services/ApiLocaleService';
|
|
|
5
5
|
import { i18nConfig } from '@config/i18n';
|
|
6
6
|
import type { LocaleType } from '@config/i18n';
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
// Use literal value instead of imported config to ensure static analysis
|
|
9
|
+
export const revalidate = 60; // Cache time in seconds (matches i18nConfig.localeCacheTime)
|
|
9
10
|
|
|
10
11
|
export async function GET(req: NextRequest) {
|
|
11
12
|
const searchParams = Object.fromEntries(req.nextUrl.searchParams.entries());
|
|
@@ -6,8 +6,9 @@ import type {
|
|
|
6
6
|
RequestAdapterConfig
|
|
7
7
|
} from '@qlover/fe-corekit';
|
|
8
8
|
|
|
9
|
-
export interface RequestEncryptPluginProps<
|
|
10
|
-
|
|
9
|
+
export interface RequestEncryptPluginProps<
|
|
10
|
+
Request = unknown
|
|
11
|
+
> extends RequestAdapterConfig<Request> {
|
|
11
12
|
/**
|
|
12
13
|
* 加密密码在 HTTP 请求中
|
|
13
14
|
*
|
|
@@ -18,9 +19,7 @@ export interface RequestEncryptPluginProps<Request = unknown>
|
|
|
18
19
|
encryptProps?: string[] | string;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
export class RequestEncryptPlugin
|
|
22
|
-
implements ExecutorPlugin<RequestEncryptPluginProps>
|
|
23
|
-
{
|
|
22
|
+
export class RequestEncryptPlugin implements ExecutorPlugin<RequestEncryptPluginProps> {
|
|
24
23
|
readonly pluginName = 'RequestEncryptPlugin';
|
|
25
24
|
|
|
26
25
|
constructor(protected encryptor: Encryptor<string, string>) {}
|
|
@@ -1,48 +1,63 @@
|
|
|
1
1
|
import { inject, injectable } from 'inversify';
|
|
2
|
-
import
|
|
2
|
+
import { omit } from 'lodash';
|
|
3
|
+
import type { LoginValidatorData } from '@/server/validators/LoginValidator';
|
|
4
|
+
import {
|
|
5
|
+
isWebUserSchema,
|
|
6
|
+
type UserCredential,
|
|
7
|
+
type UserSchema
|
|
8
|
+
} from '@migrations/schema/UserSchema';
|
|
3
9
|
import { AppUserApi } from '../services/appApi/AppUserApi';
|
|
4
|
-
import type { AppApiSuccessInterface } from '../port/AppApiInterface';
|
|
5
10
|
import type { AppUserApiInterface } from '../port/AppUserApiInterface';
|
|
6
|
-
import type {
|
|
7
|
-
LoginResponseData,
|
|
8
|
-
UserAuthApiInterface,
|
|
9
|
-
UserAuthStoreInterface
|
|
10
|
-
} from '@qlover/corekit-bridge';
|
|
11
|
+
import type { UserServiceGateway } from '@qlover/corekit-bridge';
|
|
11
12
|
|
|
12
13
|
@injectable()
|
|
13
|
-
export class UserServiceApi implements
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
export class UserServiceApi implements UserServiceGateway<
|
|
15
|
+
UserSchema,
|
|
16
|
+
UserCredential
|
|
17
|
+
> {
|
|
16
18
|
constructor(@inject(AppUserApi) protected appUserApi: AppUserApiInterface) {}
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
getUserInfo(_params?: unknown): Promise<UserSchema | null> {
|
|
21
|
+
if (_params && isWebUserSchema(_params).success) {
|
|
22
|
+
return Promise.resolve(omit(_params, 'credential_token') as UserSchema);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return Promise.resolve(null);
|
|
20
26
|
}
|
|
21
|
-
|
|
22
|
-
|
|
27
|
+
|
|
28
|
+
refreshUserInfo<Params>(
|
|
29
|
+
_params?: Params | undefined
|
|
30
|
+
): Promise<UserSchema | null> {
|
|
31
|
+
return this.getUserInfo(_params);
|
|
23
32
|
}
|
|
24
33
|
|
|
25
|
-
async login(params: {
|
|
26
|
-
email: string;
|
|
27
|
-
password: string;
|
|
28
|
-
}): Promise<LoginResponseData> {
|
|
34
|
+
async login(params: LoginValidatorData): Promise<UserCredential> {
|
|
29
35
|
const response = await this.appUserApi.login(params);
|
|
30
|
-
|
|
36
|
+
|
|
37
|
+
if (!response.data.success) {
|
|
38
|
+
throw response;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return response.data.data as UserCredential;
|
|
31
42
|
}
|
|
32
43
|
|
|
33
|
-
async register(params: {
|
|
34
|
-
email: string;
|
|
35
|
-
password: string;
|
|
36
|
-
}): Promise<LoginResponseData> {
|
|
44
|
+
async register(params: LoginValidatorData): Promise<UserSchema> {
|
|
37
45
|
const response = await this.appUserApi.register(params);
|
|
38
|
-
return (response as AppApiSuccessInterface).data as LoginResponseData;
|
|
39
|
-
}
|
|
40
46
|
|
|
41
|
-
|
|
42
|
-
|
|
47
|
+
if (!response.data.success) {
|
|
48
|
+
throw response;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return response.data.data as UserSchema;
|
|
43
52
|
}
|
|
44
53
|
|
|
45
|
-
|
|
46
|
-
|
|
54
|
+
async logout<P = unknown, Result = void>(params?: P): Promise<Result> {
|
|
55
|
+
const response = await this.appUserApi.logout(params);
|
|
56
|
+
|
|
57
|
+
if (!response.data.success) {
|
|
58
|
+
throw response;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return response.data.data as Result;
|
|
47
62
|
}
|
|
48
63
|
}
|
|
@@ -33,8 +33,7 @@ export const ZodType2RenderFormMap = {
|
|
|
33
33
|
export class ZodColumnBuilder<
|
|
34
34
|
Value extends ZodRawShape,
|
|
35
35
|
Input extends ZodObject<Value>
|
|
36
|
-
> implements ZodBuilderInterface<Input, ResourceTableOption<z.infer<Input>>>
|
|
37
|
-
{
|
|
36
|
+
> implements ZodBuilderInterface<Input, ResourceTableOption<z.infer<Input>>> {
|
|
38
37
|
protected optionMap: OptionMap<Value, Input>;
|
|
39
38
|
|
|
40
39
|
constructor(
|
|
@@ -1,15 +1,27 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { LoginValidatorData } from '@/server/validators/LoginValidator';
|
|
2
|
+
import type { UserSchema } from '@migrations/schema/UserSchema';
|
|
3
|
+
import type { AppApiTransaction } from '../services/appApi/AppApiRequester';
|
|
4
|
+
|
|
5
|
+
export type UserApiLoginTransaction = AppApiTransaction<
|
|
6
|
+
LoginValidatorData,
|
|
7
|
+
UserSchema
|
|
8
|
+
>;
|
|
9
|
+
|
|
10
|
+
export type UserApiRegisterTransaction = AppApiTransaction<
|
|
11
|
+
LoginValidatorData,
|
|
12
|
+
UserSchema
|
|
13
|
+
>;
|
|
14
|
+
|
|
15
|
+
export type UserApiLogoutTransaction = AppApiTransaction<unknown, void>;
|
|
2
16
|
|
|
3
17
|
export interface AppUserApiInterface {
|
|
4
|
-
login(
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}): Promise<AppApiResult<unknown>>;
|
|
18
|
+
login(
|
|
19
|
+
params: UserApiLoginTransaction['data']
|
|
20
|
+
): Promise<UserApiLoginTransaction['response']>;
|
|
8
21
|
|
|
9
|
-
register(
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}): Promise<AppApiResult<unknown>>;
|
|
22
|
+
register(
|
|
23
|
+
params: UserApiRegisterTransaction['data']
|
|
24
|
+
): Promise<UserApiRegisterTransaction['response']>;
|
|
13
25
|
|
|
14
|
-
logout(): Promise<
|
|
26
|
+
logout(params?: unknown): Promise<UserApiLogoutTransaction['response']>;
|
|
15
27
|
}
|
|
@@ -1,12 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type {
|
|
3
|
-
import type { ExecutorPlugin } from '@qlover/fe-corekit';
|
|
1
|
+
import type { UserCredential, UserSchema } from '@migrations/schema/UserSchema';
|
|
2
|
+
import type { UserService as CorekitBridgeUserServiceInterface } from '@qlover/corekit-bridge';
|
|
4
3
|
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
{
|
|
9
|
-
|
|
4
|
+
export interface UserServiceInterface extends CorekitBridgeUserServiceInterface<
|
|
5
|
+
UserSchema,
|
|
6
|
+
UserCredential
|
|
7
|
+
> {
|
|
8
|
+
// You can add your own methods here
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Get the user token
|
|
12
|
+
*
|
|
13
|
+
* This is a extends method from the corekit-bridge UserServiceInterface.
|
|
14
|
+
*/
|
|
15
|
+
getToken(): string;
|
|
16
|
+
|
|
17
|
+
isUserInfo(value: unknown): value is UserSchema;
|
|
18
|
+
|
|
19
|
+
isUserCredential(value: unknown): value is UserCredential;
|
|
12
20
|
}
|
|
@@ -11,10 +11,9 @@ import type { PaginationInterface } from '@/server/port/PaginationInterface';
|
|
|
11
11
|
|
|
12
12
|
export class ResourceService<
|
|
13
13
|
T,
|
|
14
|
-
Store extends
|
|
15
|
-
ResourceStore<ResourceStateInterface>
|
|
16
|
-
> implements ResourceServiceInterface<T>
|
|
17
|
-
{
|
|
14
|
+
Store extends ResourceStore<ResourceStateInterface> =
|
|
15
|
+
ResourceStore<ResourceStateInterface>
|
|
16
|
+
> implements ResourceServiceInterface<T> {
|
|
18
17
|
readonly unionKey: string = 'id';
|
|
19
18
|
|
|
20
19
|
constructor(
|
|
@@ -1,24 +1,48 @@
|
|
|
1
|
+
import { UserService as CorekitBridgeUserService } from '@qlover/corekit-bridge';
|
|
1
2
|
import { injectable, inject } from 'inversify';
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
3
|
+
import { isObject, isString } from 'lodash';
|
|
4
|
+
import {
|
|
5
|
+
userSchema,
|
|
6
|
+
type UserCredential,
|
|
7
|
+
type UserSchema
|
|
8
|
+
} from '@migrations/schema/UserSchema';
|
|
4
9
|
import { UserServiceApi } from '../cases/UserServiceApi';
|
|
5
|
-
import { UserServiceInterface } from '../port/UserServiceInterface';
|
|
6
|
-
import type {
|
|
10
|
+
import type { UserServiceInterface } from '../port/UserServiceInterface';
|
|
11
|
+
import type { UserServiceGateway } from '@qlover/corekit-bridge';
|
|
7
12
|
|
|
8
13
|
@injectable()
|
|
9
|
-
export class UserService
|
|
14
|
+
export class UserService
|
|
15
|
+
extends CorekitBridgeUserService<UserSchema, UserCredential>
|
|
16
|
+
implements UserServiceInterface
|
|
17
|
+
{
|
|
10
18
|
constructor(
|
|
11
|
-
@inject(
|
|
12
|
-
|
|
19
|
+
@inject(UserServiceApi)
|
|
20
|
+
userApi: UserServiceGateway<UserSchema, UserCredential>
|
|
13
21
|
) {
|
|
14
|
-
super(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
22
|
+
super({
|
|
23
|
+
gateway: userApi
|
|
24
|
+
// next-js ssr 将 credential 存储在 cookie 中无需存储用户信息到本地
|
|
25
|
+
// store: {
|
|
26
|
+
// storageKey: appConfig.userInfoKey,
|
|
27
|
+
// credentialStorageKey: appConfig.userTokenKey,
|
|
28
|
+
// persistUserInfo: true,
|
|
29
|
+
// }
|
|
18
30
|
});
|
|
19
31
|
}
|
|
20
32
|
|
|
21
|
-
getToken(): string
|
|
22
|
-
return this.store.getCredential();
|
|
33
|
+
getToken(): string {
|
|
34
|
+
return this.store.getCredential()?.credential_token ?? '';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
isUserInfo(value: unknown): value is UserSchema {
|
|
38
|
+
return userSchema.safeParse(value).success;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
isUserCredential(value: unknown): value is UserCredential {
|
|
42
|
+
return (
|
|
43
|
+
isObject(value) &&
|
|
44
|
+
'credential_token' in value &&
|
|
45
|
+
isString(value.credential_token)
|
|
46
|
+
);
|
|
23
47
|
}
|
|
24
48
|
}
|
|
@@ -13,8 +13,7 @@ import type {
|
|
|
13
13
|
} from '@qlover/fe-corekit';
|
|
14
14
|
|
|
15
15
|
export interface AppApiConfig<Request = unknown>
|
|
16
|
-
extends RequestAdapterConfig<Request>,
|
|
17
|
-
RequestEncryptPluginProps<Request> {}
|
|
16
|
+
extends RequestAdapterConfig<Request>, RequestEncryptPluginProps<Request> {}
|
|
18
17
|
|
|
19
18
|
/**
|
|
20
19
|
* UserApiResponse
|
|
@@ -33,11 +32,13 @@ export type AppApiResponse<
|
|
|
33
32
|
/**
|
|
34
33
|
* UserApi common transaction
|
|
35
34
|
*/
|
|
36
|
-
export interface AppApiTransaction<
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
export interface AppApiTransaction<
|
|
36
|
+
Request = unknown,
|
|
37
|
+
Response = unknown
|
|
38
|
+
> extends RequestTransactionInterface<
|
|
39
|
+
AppApiConfig<Request>,
|
|
40
|
+
AppApiResponse<Request, Response>
|
|
41
|
+
> {
|
|
41
42
|
data: AppApiConfig<Request>['data'];
|
|
42
43
|
}
|
|
43
44
|
|