@qlover/create-app 0.4.6 → 0.5.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/CHANGELOG.md +15 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/templates/react-app/config/Identifier/index.ts +1 -1
- package/dist/templates/react-app/config/feapi.mock.json +6 -0
- package/dist/templates/react-app/package.json +2 -2
- package/dist/templates/react-app/src/base/apis/userApi/UserApi.ts +84 -6
- package/dist/templates/react-app/src/base/apis/userApi/UserApiType.ts +11 -0
- package/dist/templates/react-app/src/base/cases/AppConfig.ts +11 -0
- package/dist/templates/react-app/src/base/services/UserService.ts +68 -82
- package/dist/templates/react-app/src/core/IOC.ts +11 -6
- package/dist/templates/react-app/src/core/bootstrap.ts +2 -2
- package/dist/templates/react-app/src/core/globals.ts +23 -7
- package/dist/templates/react-app/src/core/registers/RegisterApi.ts +1 -1
- package/dist/templates/react-app/src/core/registers/RegisterCommon.ts +10 -11
- package/dist/templates/react-app/src/core/registers/RegisterControllers.ts +2 -2
- package/dist/templates/react-app/src/core/registers/RegisterGlobals.ts +12 -4
- package/dist/templates/react-app/src/pages/404.tsx +1 -1
- package/dist/templates/react-app/src/pages/auth/Layout.tsx +1 -1
- package/dist/templates/react-app/src/pages/auth/LoginPage.tsx +0 -2
- package/dist/templates/react-app/src/pages/auth/RegisterPage.tsx +0 -2
- package/dist/templates/react-app/src/pages/base/ErrorIdentifierPage.tsx +1 -1
- package/dist/templates/react-app/src/pages/base/JSONStoragePage.tsx +1 -1
- package/dist/templates/react-app/src/uikit/contexts/BaseRouteContext.ts +1 -1
- package/dist/templates/react-app/src/uikit/controllers/JSONStorageController.ts +3 -3
- package/dist/templates/react-app/src/uikit/providers/UserAuthProvider.tsx +1 -1
- package/package.json +1 -1
- /package/dist/templates/react-app/config/Identifier/{Error.ts → common.error.ts} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @qlover/create-app
|
|
2
2
|
|
|
3
|
+
## 0.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
#### ✨ Features
|
|
8
|
+
|
|
9
|
+
- **react-app:** enhance user authentication and error handling ([ee00e24](https://github.com/qlover/fe-base/commit/ee00e24ce1c713aff91100ff30f9c84d8b523c80)) ([#458](https://github.com/qlover/fe-base/pull/458))
|
|
10
|
+
- Updated package.json to reference local corekit dependencies for improved development.
|
|
11
|
+
- Added new error identifiers in common.error.ts for better error management.
|
|
12
|
+
- Refactored UserApi to implement registration and improved login handling with token validation.
|
|
13
|
+
- Introduced common error handling in UserService and updated related components to utilize new error identifiers.
|
|
14
|
+
- Enhanced storage management by integrating new storage interfaces and updating related services.
|
|
15
|
+
|
|
16
|
+
These changes aim to streamline user authentication processes and improve error reporting across the application.
|
|
17
|
+
|
|
3
18
|
## 0.4.6
|
|
4
19
|
|
|
5
20
|
### Patch Changes
|
package/dist/index.cjs
CHANGED
|
@@ -8,4 +8,4 @@ ${t}`,dn=Object.getOwnPropertyDescriptor(Function.prototype,"toString"),_n=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,f=this.#g(a," "),p=u+i+s+f+`
|
|
10
10
|
`;return this.stop(),this.#u.write(p),this}};function tr(e){return new Ze(e)}async function rr(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=tr(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 HD=require("fs");var P=require("path"),me=require("fs"),cr=h(lr(),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:rs,stat:us}=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,cr.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 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}){X.ensureDir(r);let i=this.getIg();return this.copyFiles(t,r,i,u)}};var L=require("fs"),kD=h(LD(),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,kD.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 $D=["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,HD.existsSync)(r))throw new Error("template path not exit");this.ora=rr,this.context=new UD.FeScriptContext(t),this.subPackages=["node-lib","react-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 WD.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 $D.includes(t)}async getGeneratorContext(){let t=Ot(this.subPackages,$D),r=await this.steps(t);if(this.isPackageTemplate(r.template)){let u=wt(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=(s,a)=>(this.logger.debug("copyCallback",s,a),this.compose.composeConfigFile(t,s,a)),{configsRootPath:D,config:o}=this.context.options;if(!o){this.logger.debug("no copy config files");return}await this.copyer.copyPaths({sourcePath:(0,v.join)(D,u),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 bt={name:"@qlover/create-app",version:"0.
|
|
11
|
+
`).map(o=>o.trim()).filter(o=>o&&!o.startsWith("#"));return(0,cr.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 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}){X.ensureDir(r);let i=this.getIg();return this.copyFiles(t,r,i,u)}};var L=require("fs"),kD=h(LD(),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,kD.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 $D=["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,HD.existsSync)(r))throw new Error("template path not exit");this.ora=rr,this.context=new UD.FeScriptContext(t),this.subPackages=["node-lib","react-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 WD.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 $D.includes(t)}async getGeneratorContext(){let t=Ot(this.subPackages,$D),r=await this.steps(t);if(this.isPackageTemplate(r.template)){let u=wt(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=(s,a)=>(this.logger.debug("copyCallback",s,a),this.compose.composeConfigFile(t,s,a)),{configsRootPath:D,config:o}=this.context.options;if(!o){this.logger.debug("no copy config files");return}await this.copyer.copyPaths({sourcePath:(0,v.join)(D,u),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 bt={name:"@qlover/create-app",version:"0.5.0",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:{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 Ul(){let e=new YD.Command;return e.version(bt.version,"-v, --version","Show version").description(bt.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 Wl(){let{dryRun:e,verbose:t,...r}=Ul(),u=(0,vt.resolve)("./templates"),i=(0,vt.resolve)("./configs");(0,xt.existsSync)(u)||(console.error("Template is empty!"),process.exit(1)),(0,xt.existsSync)(i)||(console.error("Configs is empty!"),process.exit(1)),await new ye({dryRun:e,verbose:t,options:{...r,templateRootPath:u,configsRootPath:i}}).generate()}Wl().catch(e=>{console.error(e),process.exit(1)});
|
package/dist/index.js
CHANGED
|
@@ -8,4 +8,4 @@ ${t}`,cn=Object.getOwnPropertyDescriptor(Function.prototype,"toString"),fn=Objec
|
|
|
8
8
|
`))this.#e+=Math.max(1,Math.ceil(Le(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=E[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&&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??" ",D=t.text??this.text,s=typeof D=="string"?(i?" ":"")+D:"",a=t.suffixText??this.#o,f=this.#g(a," "),p=u+i+s+f+`
|
|
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:D}=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(D===void 0?void 0:typeof D=="string"?D:D(s)),s}}import{existsSync as Hl}from"fs";var Dr=ue(ir(),1);import{dirname as Jn,join as Ze}from"path";import{existsSync as Zn,readFileSync as Qn}from"fs";import{promises as nr}from"fs";import{existsSync as Kn,mkdirSync as Xn}from"fs";var H=class{static ensureDir(t){Kn(t)||Xn(t,{recursive:!0})}};var{copyFile:es,stat:ts}=nr,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(!Zn(r))return;let D=Qn(r,"utf8").split(`
|
|
11
|
-
`).map(o=>o.trim()).filter(o=>o&&!o.startsWith("#"));return(0,Dr.default)().add(D)}async copyFiles(t,r,u,i){let D=await nr.readdir(t);await Promise.all(D.map(async o=>{let s=Ze(t,o),a=Ze(r,o);if(u&&u.ignores(o))return;if(H.ensureDir(Jn(a)),(await ts(s)).isDirectory())await this.copyFiles(s,a,u,i);else{if(i&&await i(s,a))return;await es(s,a)}}))}copyPaths({sourcePath:t,targetPath:r,copyCallback:u}){H.ensureDir(r);let i=this.getIg();return this.copyFiles(t,r,i,u)}};var ID=ue(qD(),1);import{readFileSync as Ll,writeFileSync as kl,existsSync as $l}from"fs";var me=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 Ll(t,"utf-8")}readJSONFile(t){return JSON.parse(this.readFile(t))}writeFile(t,r){kl(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,ID.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 $l(D)?(this.mergeJSONFile(D,JSON.parse(i)),!0):(this.writeFile(D,i),!0)}return this.writeFile(u,i),!0}return!1}};var jD=["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(!Hl(r))throw new Error("template path not exit");this.ora=Kt,this.context=new Ul(t),this.subPackages=["node-lib","react-app"],this.copyer=new Ce(N(this.context.options.configsRootPath,"_common")),this.compose=new me}get logger(){return this.context.logger}async steps(t){try{return await Wl.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 jD.includes(t)}async getGeneratorContext(){let t=_t(this.subPackages,jD),r=await this.steps(t);if(this.isPackageTemplate(r.template)){let u=mt(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=(s,a)=>(this.logger.debug("copyCallback",s,a),this.compose.composeConfigFile(t,s,a)),{configsRootPath:D,config:o}=this.context.options;if(!o){this.logger.debug("no copy config files");return}await this.copyer.copyPaths({sourcePath:N(D,u),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:D}=this.context.options;for(let o of u){let s=N(D,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,Dr.default)().add(D)}async copyFiles(t,r,u,i){let D=await nr.readdir(t);await Promise.all(D.map(async o=>{let s=Ze(t,o),a=Ze(r,o);if(u&&u.ignores(o))return;if(H.ensureDir(Jn(a)),(await ts(s)).isDirectory())await this.copyFiles(s,a,u,i);else{if(i&&await i(s,a))return;await es(s,a)}}))}copyPaths({sourcePath:t,targetPath:r,copyCallback:u}){H.ensureDir(r);let i=this.getIg();return this.copyFiles(t,r,i,u)}};var ID=ue(qD(),1);import{readFileSync as Ll,writeFileSync as kl,existsSync as $l}from"fs";var me=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 Ll(t,"utf-8")}readJSONFile(t){return JSON.parse(this.readFile(t))}writeFile(t,r){kl(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,ID.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 $l(D)?(this.mergeJSONFile(D,JSON.parse(i)),!0):(this.writeFile(D,i),!0)}return this.writeFile(u,i),!0}return!1}};var jD=["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(!Hl(r))throw new Error("template path not exit");this.ora=Kt,this.context=new Ul(t),this.subPackages=["node-lib","react-app"],this.copyer=new Ce(N(this.context.options.configsRootPath,"_common")),this.compose=new me}get logger(){return this.context.logger}async steps(t){try{return await Wl.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 jD.includes(t)}async getGeneratorContext(){let t=_t(this.subPackages,jD),r=await this.steps(t);if(this.isPackageTemplate(r.template)){let u=mt(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=(s,a)=>(this.logger.debug("copyCallback",s,a),this.compose.composeConfigFile(t,s,a)),{configsRootPath:D,config:o}=this.context.options;if(!o){this.logger.debug("no copy config files");return}await this.copyer.copyPaths({sourcePath:N(D,u),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:D}=this.context.options;for(let o of u){let s=N(D,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.5.0",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:{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 zl(){let e=new Vl;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 Kl(){let{dryRun:e,verbose:t,...r}=zl(),u=ND("./templates"),i=ND("./configs");GD(u)||(console.error("Template is empty!"),process.exit(1)),GD(i)||(console.error("Configs is empty!"),process.exit(1)),await new Be({dryRun:e,verbose:t,options:{...r,templateRootPath:u,configsRootPath:i}}).generate()}Kl().catch(e=>{console.error(e),process.exit(1)});
|
|
@@ -19,6 +19,12 @@
|
|
|
19
19
|
"POST /api/login": {
|
|
20
20
|
"token": "/api/login-token-adfasdfasdf"
|
|
21
21
|
},
|
|
22
|
+
"POST https://feapi.example.com/api/register": {
|
|
23
|
+
"token": "asdfasdf123123asdfasdf"
|
|
24
|
+
},
|
|
25
|
+
"POST /api/register": {
|
|
26
|
+
"token": "asdfasdf123123asdfasdf"
|
|
27
|
+
},
|
|
22
28
|
"POST https://api.openai.com/v1/chat/completions": {
|
|
23
29
|
"id": "chatcmpl-1234567890",
|
|
24
30
|
"object": "chat.completion",
|
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@brain-toolkit/antd-theme-override": "^0.0.3",
|
|
57
|
-
"@qlover/corekit-bridge": "
|
|
58
|
-
"@qlover/fe-corekit": "
|
|
57
|
+
"@qlover/corekit-bridge": "file:../../../corekit-bridge",
|
|
58
|
+
"@qlover/fe-corekit": "file:../../../fe-corekit",
|
|
59
59
|
"@qlover/logger": "^0.1.1",
|
|
60
60
|
"@qlover/slice-store-react": "^1.0.8",
|
|
61
61
|
"@tailwindcss/postcss": "^4.1.8",
|
|
@@ -12,6 +12,17 @@ import {
|
|
|
12
12
|
import { inject, injectable } from 'inversify';
|
|
13
13
|
import { UserApiAdapter } from './UserApiAdapter';
|
|
14
14
|
import { UserApiConfig } from './UserApiBootstarp';
|
|
15
|
+
import {
|
|
16
|
+
LoginResponseData,
|
|
17
|
+
UserAuthApiInterface,
|
|
18
|
+
UserAuthStoreInterface
|
|
19
|
+
} from '@qlover/corekit-bridge';
|
|
20
|
+
import {
|
|
21
|
+
RegisterFormData,
|
|
22
|
+
UserServiceUserInfo
|
|
23
|
+
} from '@/base/services/UserService';
|
|
24
|
+
import { RES_NO_TOKEN } from '@config/Identifier';
|
|
25
|
+
import { AppError } from '@/base/cases/AppError';
|
|
15
26
|
|
|
16
27
|
/**
|
|
17
28
|
* UserApi
|
|
@@ -21,7 +32,12 @@ import { UserApiConfig } from './UserApiBootstarp';
|
|
|
21
32
|
*
|
|
22
33
|
*/
|
|
23
34
|
@injectable()
|
|
24
|
-
export class UserApi
|
|
35
|
+
export class UserApi
|
|
36
|
+
extends RequestTransaction<UserApiConfig>
|
|
37
|
+
implements UserAuthApiInterface<UserServiceUserInfo>
|
|
38
|
+
{
|
|
39
|
+
protected store: UserAuthStoreInterface<UserServiceUserInfo> | null = null;
|
|
40
|
+
|
|
25
41
|
constructor(
|
|
26
42
|
@inject(FetchAbortPlugin) private abortPlugin: FetchAbortPlugin,
|
|
27
43
|
@inject(UserApiAdapter) adapter: RequestAdapterFetch
|
|
@@ -29,6 +45,18 @@ export class UserApi extends RequestTransaction<UserApiConfig> {
|
|
|
29
45
|
super(adapter);
|
|
30
46
|
}
|
|
31
47
|
|
|
48
|
+
getStore(): UserAuthStoreInterface<UserServiceUserInfo> | null {
|
|
49
|
+
return this.store;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @override
|
|
54
|
+
* @param store
|
|
55
|
+
*/
|
|
56
|
+
setStore(store: UserAuthStoreInterface<UserServiceUserInfo>): void {
|
|
57
|
+
this.store = store;
|
|
58
|
+
}
|
|
59
|
+
|
|
32
60
|
stop(request: UserApiConfig): Promise<void> | void {
|
|
33
61
|
this.abortPlugin.abort(request);
|
|
34
62
|
}
|
|
@@ -52,13 +80,63 @@ export class UserApi extends RequestTransaction<UserApiConfig> {
|
|
|
52
80
|
});
|
|
53
81
|
}
|
|
54
82
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
83
|
+
/**
|
|
84
|
+
* @override
|
|
85
|
+
* @param params
|
|
86
|
+
* @returns
|
|
87
|
+
*/
|
|
59
88
|
async login(
|
|
60
89
|
params: UserApiLoginTransaction['data']
|
|
90
|
+
): Promise<LoginResponseData> {
|
|
91
|
+
const response = await this.post<UserApiLoginTransaction>(
|
|
92
|
+
'/api/login',
|
|
93
|
+
params
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
if (response.apiCatchResult) {
|
|
97
|
+
throw response.apiCatchResult;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (!response.data.token) {
|
|
101
|
+
throw new AppError(RES_NO_TOKEN);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return response.data;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* @override
|
|
109
|
+
* @param params
|
|
110
|
+
* @returns
|
|
111
|
+
*/
|
|
112
|
+
register(
|
|
113
|
+
params: RegisterFormData
|
|
61
114
|
): Promise<UserApiLoginTransaction['response']> {
|
|
62
|
-
return this.post<UserApiLoginTransaction>('/api/
|
|
115
|
+
return this.post<UserApiLoginTransaction>('/api/register', params);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* @override
|
|
120
|
+
* @returns
|
|
121
|
+
*/
|
|
122
|
+
logout(): Promise<void> {
|
|
123
|
+
return Promise.resolve();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* @override
|
|
128
|
+
* @returns
|
|
129
|
+
*/
|
|
130
|
+
async getUserInfo(): Promise<
|
|
131
|
+
UserApiGetUserInfoTransaction['response']['data']
|
|
132
|
+
> {
|
|
133
|
+
const response =
|
|
134
|
+
await this.get<UserApiGetUserInfoTransaction>('/api/userinfo');
|
|
135
|
+
|
|
136
|
+
if (response.apiCatchResult) {
|
|
137
|
+
throw response.apiCatchResult;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return response.data;
|
|
63
141
|
}
|
|
64
142
|
}
|
|
@@ -50,3 +50,14 @@ export type UserApiLoginTransaction = UserApiTransaction<
|
|
|
50
50
|
>;
|
|
51
51
|
|
|
52
52
|
export type UserApiTestApiCatchResultTransaction = UserApiGetRandomUser;
|
|
53
|
+
|
|
54
|
+
export type UserApiRegisterTransaction = UserApiTransaction<
|
|
55
|
+
{
|
|
56
|
+
username: string;
|
|
57
|
+
email: string;
|
|
58
|
+
password: string;
|
|
59
|
+
confirmPassword: string;
|
|
60
|
+
agreeToTerms: boolean;
|
|
61
|
+
},
|
|
62
|
+
UserApiTransaction['response']['data']
|
|
63
|
+
>;
|
|
@@ -55,6 +55,12 @@ export class AppConfig implements EnvConfigInterface {
|
|
|
55
55
|
*/
|
|
56
56
|
readonly userTokenStorageKey = '__fe_user_token__';
|
|
57
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Storage key for user information
|
|
60
|
+
* @description Injected from VITE_USER_INFO_STORAGE_KEY environment variable
|
|
61
|
+
*/
|
|
62
|
+
readonly userInfoStorageKey = '__fe_user_info__';
|
|
63
|
+
|
|
58
64
|
/**
|
|
59
65
|
* Available OpenAI model configurations
|
|
60
66
|
* @description List of supported OpenAI models for the application
|
|
@@ -102,4 +108,9 @@ export class AppConfig implements EnvConfigInterface {
|
|
|
102
108
|
|
|
103
109
|
/** Flag indicating if AI service token is required */
|
|
104
110
|
readonly aiApiRequireToken = true;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Project startup href, usually from window.location.href
|
|
114
|
+
*/
|
|
115
|
+
readonly bootHref = '';
|
|
105
116
|
}
|
|
@@ -1,19 +1,21 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { ExecutorPlugin, type SyncStorageInterface } from '@qlover/fe-corekit';
|
|
2
2
|
import type {
|
|
3
3
|
UserApiGetUserInfoTransaction,
|
|
4
4
|
UserApiLoginTransaction
|
|
5
5
|
} from '@/base/apis/userApi/UserApiType';
|
|
6
6
|
import { RouteService } from './RouteService';
|
|
7
7
|
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
LoginResponseData,
|
|
9
|
+
type UserAuthApiInterface,
|
|
10
|
+
UserAuthService,
|
|
11
|
+
UserAuthStore
|
|
11
12
|
} from '@qlover/corekit-bridge';
|
|
12
13
|
import { inject, injectable } from 'inversify';
|
|
13
|
-
import { IOCIdentifier } from '@/core/IOC';
|
|
14
14
|
import { UserApi } from '@/base/apis/userApi/UserApi';
|
|
15
15
|
import { AppError } from '@/base/cases/AppError';
|
|
16
|
-
import * as errKeys from '@config/Identifier/error';
|
|
16
|
+
import * as errKeys from '@config/Identifier/common.error';
|
|
17
|
+
import { IOCIdentifier } from '@/core/IOC';
|
|
18
|
+
import { AppConfig } from '../cases/AppConfig';
|
|
17
19
|
|
|
18
20
|
export type UserServiceUserInfo =
|
|
19
21
|
UserApiGetUserInfoTransaction['response']['data'];
|
|
@@ -26,34 +28,47 @@ export interface RegisterFormData {
|
|
|
26
28
|
agreeToTerms: boolean;
|
|
27
29
|
}
|
|
28
30
|
|
|
29
|
-
class UserServiceState implements StoreStateInterface {
|
|
30
|
-
success: boolean = false;
|
|
31
|
-
userInfo: UserServiceUserInfo = {
|
|
32
|
-
name: '',
|
|
33
|
-
email: '',
|
|
34
|
-
picture: ''
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
31
|
@injectable()
|
|
39
32
|
export class UserService
|
|
40
|
-
extends
|
|
33
|
+
extends UserAuthService<UserServiceUserInfo>
|
|
41
34
|
implements ExecutorPlugin
|
|
42
35
|
{
|
|
43
36
|
readonly pluginName = 'UserService';
|
|
44
37
|
|
|
45
38
|
constructor(
|
|
46
|
-
@inject(
|
|
47
|
-
@inject(
|
|
48
|
-
@inject(IOCIdentifier.
|
|
49
|
-
|
|
39
|
+
@inject(RouteService) protected routerService: RouteService,
|
|
40
|
+
@inject(UserApi) userApi: UserAuthApiInterface<UserServiceUserInfo>,
|
|
41
|
+
@inject(IOCIdentifier.AppConfig) appConfig: AppConfig,
|
|
42
|
+
@inject(IOCIdentifier.LocalStorageEncrypt)
|
|
43
|
+
storage: SyncStorageInterface<string, string>
|
|
50
44
|
) {
|
|
51
|
-
super(
|
|
45
|
+
super({
|
|
46
|
+
api: userApi,
|
|
47
|
+
userStorage: {
|
|
48
|
+
key: appConfig.userInfoStorageKey,
|
|
49
|
+
storage: storage
|
|
50
|
+
},
|
|
51
|
+
credentialStorage: {
|
|
52
|
+
key: appConfig.userTokenStorageKey,
|
|
53
|
+
storage: storage
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// FIXME:
|
|
58
|
+
// load credential from storage
|
|
59
|
+
// this.store.setCredential(this.store.getCredentialStorage()?.get() ?? '');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @override
|
|
64
|
+
*/
|
|
65
|
+
override get store(): UserAuthStore<UserServiceUserInfo> {
|
|
66
|
+
return super.store as UserAuthStore<UserServiceUserInfo>;
|
|
52
67
|
}
|
|
53
68
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
69
|
+
getToken(): string | null {
|
|
70
|
+
return this.store.getCredential();
|
|
71
|
+
}
|
|
57
72
|
|
|
58
73
|
/**
|
|
59
74
|
* @override
|
|
@@ -63,84 +78,55 @@ export class UserService
|
|
|
63
78
|
return;
|
|
64
79
|
}
|
|
65
80
|
|
|
66
|
-
const userToken = this.
|
|
81
|
+
const userToken = this.getToken();
|
|
67
82
|
|
|
68
83
|
if (!userToken) {
|
|
69
84
|
throw new AppError(errKeys.LOCAL_NO_USER_TOKEN);
|
|
70
85
|
}
|
|
71
86
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
this.emit({
|
|
75
|
-
success: true,
|
|
76
|
-
userInfo: userInfo.data
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
onSuccess(): void | Promise<void> {
|
|
81
|
-
if (this.isAuthenticated()) {
|
|
82
|
-
this.emit({ ...this.state, success: true });
|
|
83
|
-
} else {
|
|
84
|
-
this.logout();
|
|
87
|
+
if (userToken) {
|
|
88
|
+
this.store.authSuccess();
|
|
85
89
|
}
|
|
90
|
+
|
|
91
|
+
await this.userInfo();
|
|
92
|
+
this.store.authSuccess();
|
|
86
93
|
}
|
|
87
94
|
|
|
88
95
|
/**
|
|
89
96
|
* @override
|
|
90
97
|
*/
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
throw response.apiCatchResult;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (!response.data.token) {
|
|
101
|
-
throw new AppError(errKeys.RES_NO_TOKEN);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
this.userToken.setToken(response.data.token);
|
|
105
|
-
|
|
106
|
-
const userInfo = await this.userApi.getUserInfo();
|
|
107
|
-
|
|
108
|
-
this.emit({
|
|
109
|
-
success: true,
|
|
110
|
-
userInfo: userInfo.data
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
return userInfo;
|
|
98
|
+
onSuccess(): void {
|
|
99
|
+
// if (this.isAuthenticated()) {
|
|
100
|
+
// this.store.authSuccess();
|
|
101
|
+
// } else {
|
|
102
|
+
// this.logout();
|
|
103
|
+
// }
|
|
114
104
|
}
|
|
115
105
|
|
|
116
106
|
/**
|
|
117
107
|
* @override
|
|
118
108
|
*/
|
|
119
|
-
logout(): void {
|
|
120
|
-
|
|
109
|
+
override async logout(): Promise<void> {
|
|
110
|
+
await super.logout();
|
|
111
|
+
|
|
121
112
|
this.routerService.reset();
|
|
122
113
|
this.routerService.gotoLogin();
|
|
123
114
|
}
|
|
124
115
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
116
|
+
async register(params: RegisterFormData): Promise<LoginResponseData> {
|
|
117
|
+
const response = (await this.api.register(
|
|
118
|
+
params
|
|
119
|
+
)) as UserApiLoginTransaction['response'];
|
|
120
|
+
|
|
121
|
+
if (response.data?.token) {
|
|
122
|
+
try {
|
|
123
|
+
await this.userInfo({ token: response.data?.token });
|
|
124
|
+
this.store.authSuccess();
|
|
125
|
+
} catch (error) {
|
|
126
|
+
this.store.authFailed(error);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
136
129
|
|
|
137
|
-
|
|
138
|
-
* @override
|
|
139
|
-
*/
|
|
140
|
-
async register(params: RegisterFormData): Promise<unknown> {
|
|
141
|
-
return this.login({
|
|
142
|
-
username: params.username,
|
|
143
|
-
password: params.password
|
|
144
|
-
});
|
|
130
|
+
throw new AppError(errKeys.LOCAL_NO_USER_TOKEN);
|
|
145
131
|
}
|
|
146
132
|
}
|
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
import {
|
|
3
3
|
ApiMockPlugin,
|
|
4
4
|
EnvConfigInterface,
|
|
5
|
-
StorageTokenInterface,
|
|
6
5
|
RequestCommonPlugin,
|
|
7
6
|
ApiCatchPlugin,
|
|
8
7
|
IOCContainerInterface,
|
|
9
8
|
createIOCFunction,
|
|
10
|
-
ServiceIdentifier
|
|
9
|
+
ServiceIdentifier,
|
|
10
|
+
TokenStorage,
|
|
11
|
+
CookieStorage
|
|
11
12
|
} from '@qlover/corekit-bridge';
|
|
12
|
-
import type { JSONSerializer,
|
|
13
|
+
import type { JSONSerializer, ObjectStorage } from '@qlover/fe-corekit';
|
|
13
14
|
import type { LoggerInterface } from '@qlover/logger';
|
|
14
15
|
import type { AppConfig } from '@/base/cases/AppConfig';
|
|
15
16
|
import { Container } from 'inversify';
|
|
@@ -69,7 +70,9 @@ export class InversifyContainer implements IOCContainerInterface {
|
|
|
69
70
|
*/
|
|
70
71
|
export const IOCIdentifier = Object.freeze({
|
|
71
72
|
JSON: 'JSON',
|
|
72
|
-
|
|
73
|
+
LocalStorage: 'LocalStorage',
|
|
74
|
+
LocalStorageEncrypt: 'LocalStorageEncrypt',
|
|
75
|
+
CookieStorage: 'CookieStorage',
|
|
73
76
|
Logger: 'Logger',
|
|
74
77
|
FeApiToken: 'FeApiToken',
|
|
75
78
|
FeApiCommonPlugin: 'FeApiCommonPlugin',
|
|
@@ -84,9 +87,11 @@ export const IOCIdentifier = Object.freeze({
|
|
|
84
87
|
*/
|
|
85
88
|
export interface IOCIdentifierMap {
|
|
86
89
|
[IOCIdentifier.JSON]: JSONSerializer;
|
|
87
|
-
[IOCIdentifier.
|
|
90
|
+
[IOCIdentifier.LocalStorage]: ObjectStorage<string, string>;
|
|
91
|
+
[IOCIdentifier.LocalStorageEncrypt]: ObjectStorage<string, string>;
|
|
92
|
+
[IOCIdentifier.CookieStorage]: CookieStorage;
|
|
88
93
|
[IOCIdentifier.Logger]: LoggerInterface;
|
|
89
|
-
[IOCIdentifier.FeApiToken]:
|
|
94
|
+
[IOCIdentifier.FeApiToken]: TokenStorage<string>;
|
|
90
95
|
[IOCIdentifier.FeApiCommonPlugin]: RequestCommonPlugin;
|
|
91
96
|
[IOCIdentifier.AppConfig]: EnvConfigInterface;
|
|
92
97
|
[IOCIdentifier.ApiMockPlugin]: ApiMockPlugin;
|
|
@@ -4,7 +4,7 @@ import { IOC } from './IOC';
|
|
|
4
4
|
import * as globals from '@/core/globals';
|
|
5
5
|
import { IocRegister } from './registers';
|
|
6
6
|
import { BootstrapsRegistry } from './bootstraps';
|
|
7
|
-
import { GLOBAL_NO_WINDOW } from '@config/Identifier/error';
|
|
7
|
+
import { GLOBAL_NO_WINDOW } from '@config/Identifier/common.error';
|
|
8
8
|
|
|
9
9
|
export default async function startup({
|
|
10
10
|
root,
|
|
@@ -33,7 +33,7 @@ export default async function startup({
|
|
|
33
33
|
},
|
|
34
34
|
envOptions: {
|
|
35
35
|
target: appConfig,
|
|
36
|
-
source: envSource,
|
|
36
|
+
source: { ...envSource, [envPrefix + 'BOOT_HREF']: root.location.href },
|
|
37
37
|
prefix: envPrefix,
|
|
38
38
|
blackList: envBlackList
|
|
39
39
|
},
|
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
// ! global variables, don't import any dependencies and don't have side effects
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
Base64Serializer,
|
|
4
|
+
JSONSerializer,
|
|
5
|
+
ObjectStorage,
|
|
6
|
+
SyncStorage,
|
|
7
|
+
SyncStorageInterface
|
|
8
|
+
} from '@qlover/fe-corekit';
|
|
9
|
+
import {
|
|
10
|
+
ColorFormatter,
|
|
11
|
+
ConsoleHandler,
|
|
12
|
+
CookieStorage,
|
|
13
|
+
Logger
|
|
14
|
+
} from '@qlover/corekit-bridge';
|
|
4
15
|
import { DialogHandler } from '@/base/cases/DialogHandler';
|
|
5
16
|
import { loggerStyles } from '@config/common';
|
|
6
17
|
import { AppConfig } from '@/base/cases/AppConfig';
|
|
@@ -26,9 +37,14 @@ export const logger = new Logger({
|
|
|
26
37
|
export const JSON = new JSONSerializer();
|
|
27
38
|
|
|
28
39
|
/**
|
|
29
|
-
* Override
|
|
40
|
+
* Override localStorage to use the global local storage
|
|
30
41
|
*/
|
|
31
|
-
export const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
42
|
+
export const localStorage = new SyncStorage(new ObjectStorage(), [
|
|
43
|
+
JSON,
|
|
44
|
+
new Base64Serializer(),
|
|
45
|
+
window.localStorage as unknown as SyncStorageInterface<string>
|
|
46
|
+
]);
|
|
47
|
+
|
|
48
|
+
export const localStorageEncrypt = localStorage;
|
|
49
|
+
|
|
50
|
+
export const cookieStorage = new CookieStorage();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { InversifyContainer, InversifyRegisterInterface } from '../IOC';
|
|
1
|
+
import type { InversifyContainer, InversifyRegisterInterface } from '../IOC';
|
|
2
2
|
|
|
3
3
|
export class RegisterApi implements InversifyRegisterInterface {
|
|
4
4
|
register(_container: InversifyContainer): void {}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FetchAbortPlugin
|
|
1
|
+
import { FetchAbortPlugin } from '@qlover/fe-corekit';
|
|
2
2
|
import { Logger } from '@qlover/logger';
|
|
3
3
|
import {
|
|
4
4
|
InversifyContainer,
|
|
@@ -7,20 +7,21 @@ import {
|
|
|
7
7
|
IocRegisterOptions
|
|
8
8
|
} from '@/core/IOC';
|
|
9
9
|
import {
|
|
10
|
-
UserToken,
|
|
11
10
|
RequestCommonPlugin,
|
|
12
11
|
ApiMockPlugin,
|
|
13
12
|
ApiCatchPlugin,
|
|
14
13
|
ThemeService,
|
|
15
|
-
IOCManagerInterface
|
|
14
|
+
IOCManagerInterface,
|
|
15
|
+
TokenStorage
|
|
16
16
|
} from '@qlover/corekit-bridge';
|
|
17
17
|
import mockDataJson from '@config/feapi.mock.json';
|
|
18
18
|
import { RequestStatusCatcher } from '@/base/cases/RequestStatusCatcher';
|
|
19
19
|
import { themeConfig } from '@config/theme';
|
|
20
|
-
import {
|
|
20
|
+
import { localStorage, logger } from '../globals';
|
|
21
21
|
import { I18nService } from '@/base/services/I18nService';
|
|
22
22
|
import { RouteService } from '@/base/services/RouteService';
|
|
23
23
|
import { baseRoutes } from '@config/app.router';
|
|
24
|
+
import { UserService } from '@/base/services/UserService';
|
|
24
25
|
|
|
25
26
|
export class RegisterCommon implements InversifyRegisterInterface {
|
|
26
27
|
register(
|
|
@@ -30,21 +31,19 @@ export class RegisterCommon implements InversifyRegisterInterface {
|
|
|
30
31
|
): void {
|
|
31
32
|
const AppConfig = container.get(IOCIdentifier.AppConfig);
|
|
32
33
|
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
storage: container.get(JSONStorage)
|
|
34
|
+
const feApiToken = new TokenStorage(AppConfig.userTokenStorageKey, {
|
|
35
|
+
storage: container.get(IOCIdentifier.LocalStorageEncrypt)
|
|
36
36
|
});
|
|
37
37
|
const feApiAbort = new FetchAbortPlugin();
|
|
38
38
|
const feApiRequestCommonPlugin = new RequestCommonPlugin({
|
|
39
39
|
tokenPrefix: AppConfig.openAiTokenPrefix,
|
|
40
40
|
requiredToken: true,
|
|
41
|
-
token: () =>
|
|
41
|
+
token: () => container.get(UserService).getToken()
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
container.bind(FetchAbortPlugin, feApiAbort);
|
|
45
|
-
container.bind(UserToken, userToken);
|
|
46
45
|
|
|
47
|
-
container.bind(IOCIdentifier.FeApiToken,
|
|
46
|
+
container.bind(IOCIdentifier.FeApiToken, feApiToken);
|
|
48
47
|
container.bind(IOCIdentifier.FeApiCommonPlugin, feApiRequestCommonPlugin);
|
|
49
48
|
container.bind(
|
|
50
49
|
IOCIdentifier.ApiMockPlugin,
|
|
@@ -62,7 +61,7 @@ export class RegisterCommon implements InversifyRegisterInterface {
|
|
|
62
61
|
ThemeService,
|
|
63
62
|
new ThemeService({
|
|
64
63
|
...themeConfig,
|
|
65
|
-
storage:
|
|
64
|
+
storage: localStorage
|
|
66
65
|
})
|
|
67
66
|
);
|
|
68
67
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { localStorage } from '../globals';
|
|
2
2
|
import { JSONStorageController } from '@/uikit/controllers/JSONStorageController';
|
|
3
3
|
import { ProcesserExecutor } from '@/base/services/ProcesserExecutor';
|
|
4
4
|
import { UserService } from '@/base/services/UserService';
|
|
@@ -8,7 +8,7 @@ import { I18nKeyErrorPlugin } from '@/base/cases/I18nKeyErrorPlugin';
|
|
|
8
8
|
|
|
9
9
|
export class RegisterControllers implements InversifyRegisterInterface {
|
|
10
10
|
register(container: InversifyContainer): void {
|
|
11
|
-
const jsonStorageController = new JSONStorageController(
|
|
11
|
+
const jsonStorageController = new JSONStorageController(localStorage);
|
|
12
12
|
|
|
13
13
|
container.bind(JSONStorageController, jsonStorageController);
|
|
14
14
|
|
|
@@ -1,6 +1,13 @@
|
|
|
1
|
-
import { JSONSerializer
|
|
1
|
+
import { JSONSerializer } from '@qlover/fe-corekit';
|
|
2
2
|
import type { IOCManagerInterface } from '@qlover/corekit-bridge';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
cookieStorage,
|
|
5
|
+
dialogHandler,
|
|
6
|
+
JSON,
|
|
7
|
+
localStorage,
|
|
8
|
+
localStorageEncrypt,
|
|
9
|
+
logger
|
|
10
|
+
} from '../globals';
|
|
4
11
|
import {
|
|
5
12
|
type InversifyContainer,
|
|
6
13
|
type InversifyRegisterInterface,
|
|
@@ -25,7 +32,8 @@ export class RegisterGlobals implements InversifyRegisterInterface {
|
|
|
25
32
|
container.bind(Logger, logger);
|
|
26
33
|
container.bind(IOCIdentifier.Logger, logger);
|
|
27
34
|
|
|
28
|
-
container.bind(
|
|
29
|
-
container.bind(IOCIdentifier.
|
|
35
|
+
container.bind(IOCIdentifier.LocalStorage, localStorage);
|
|
36
|
+
container.bind(IOCIdentifier.LocalStorageEncrypt, localStorageEncrypt);
|
|
37
|
+
container.bind(IOCIdentifier.CookieStorage, cookieStorage);
|
|
30
38
|
}
|
|
31
39
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useBaseRoutePage } from '@/uikit/contexts/BaseRouteContext';
|
|
2
2
|
import { PAGE_404_TITLE } from '@config/Identifier/common';
|
|
3
|
-
import { NOT_FOUND_COMPONENT } from '@config/Identifier/error';
|
|
3
|
+
import { NOT_FOUND_COMPONENT } from '@config/Identifier/common.error';
|
|
4
4
|
|
|
5
5
|
export default function NotFound({ route }: { route?: string }) {
|
|
6
6
|
const { t } = useBaseRoutePage();
|
|
@@ -6,7 +6,7 @@ import BaseHeader from '../../uikit/components/BaseHeader';
|
|
|
6
6
|
|
|
7
7
|
export default function Layout() {
|
|
8
8
|
const userService = IOC(UserService);
|
|
9
|
-
useStore(userService
|
|
9
|
+
useStore(userService.store);
|
|
10
10
|
|
|
11
11
|
// If user is authenticated, redirect to home page
|
|
12
12
|
if (userService.isAuthenticated()) {
|
|
@@ -5,7 +5,6 @@ import { IOC } from '@/core/IOC';
|
|
|
5
5
|
import { useBaseRoutePage } from '@/uikit/contexts/BaseRouteContext';
|
|
6
6
|
import { RouteService } from '@/base/services/RouteService';
|
|
7
7
|
import { UserService } from '@/base/services/UserService';
|
|
8
|
-
import { useStore } from '@/uikit/hooks/useStore';
|
|
9
8
|
import * as i18nKeys from '@config/Identifier/page.login';
|
|
10
9
|
import LocaleLink from '@/uikit/components/LocaleLink';
|
|
11
10
|
|
|
@@ -18,7 +17,6 @@ export default function LoginPage() {
|
|
|
18
17
|
const { t } = useBaseRoutePage();
|
|
19
18
|
const userService = IOC(UserService);
|
|
20
19
|
const AppConfig = IOC('AppConfig');
|
|
21
|
-
useStore(userService);
|
|
22
20
|
const [loading, setLoading] = useState(false);
|
|
23
21
|
|
|
24
22
|
const handleLogin = async (values: LoginFormData) => {
|
|
@@ -5,14 +5,12 @@ import { IOC } from '@/core/IOC';
|
|
|
5
5
|
import { useBaseRoutePage } from '@/uikit/contexts/BaseRouteContext';
|
|
6
6
|
import { RouteService } from '@/base/services/RouteService';
|
|
7
7
|
import { RegisterFormData, UserService } from '@/base/services/UserService';
|
|
8
|
-
import { useStore } from '@/uikit/hooks/useStore';
|
|
9
8
|
import * as i18nKeys from '@config/Identifier/page.register';
|
|
10
9
|
|
|
11
10
|
export default function RegisterPage() {
|
|
12
11
|
const { t } = useBaseRoutePage();
|
|
13
12
|
const userService = IOC(UserService);
|
|
14
13
|
const AppConfig = IOC('AppConfig');
|
|
15
|
-
useStore(userService);
|
|
16
14
|
const [loading, setLoading] = useState(false);
|
|
17
15
|
const [form] = Form.useForm();
|
|
18
16
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Button } from 'antd';
|
|
2
2
|
import { useBaseRoutePage } from '@/uikit/contexts/BaseRouteContext';
|
|
3
|
-
import * as ErrorIdentifierList from '@config/Identifier/error';
|
|
3
|
+
import * as ErrorIdentifierList from '@config/Identifier/common.error';
|
|
4
4
|
import * as i18nKeys from '@config/Identifier/page.identifiter';
|
|
5
5
|
|
|
6
6
|
export default function ErrorIdentifierPage() {
|
|
@@ -46,7 +46,7 @@ export default function JSONStoragePage() {
|
|
|
46
46
|
{t(i18nKeys.PAGE_JSONSTORAGE_CURRENT_VALUE)}:{' '}
|
|
47
47
|
</span>
|
|
48
48
|
<span className="font-semibold text-text">
|
|
49
|
-
{controllerState.testKey1}
|
|
49
|
+
{JSON.stringify(controllerState.testKey1)}
|
|
50
50
|
</span>
|
|
51
51
|
</div>
|
|
52
52
|
</div>
|
|
@@ -5,7 +5,7 @@ import { RouteMeta } from '@/base/types/Page';
|
|
|
5
5
|
import { createContext } from 'react';
|
|
6
6
|
import merge from 'lodash/merge';
|
|
7
7
|
import i18nConfig from '@config/i18n';
|
|
8
|
-
import { WITHIN_PAGE_PROVIDER } from '@config/Identifier/error';
|
|
8
|
+
import { WITHIN_PAGE_PROVIDER } from '@config/Identifier/common.error';
|
|
9
9
|
|
|
10
10
|
const { defaultNS } = i18nConfig;
|
|
11
11
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { JSONStorage } from '@qlover/fe-corekit';
|
|
2
1
|
import {
|
|
3
2
|
StoreInterface,
|
|
4
3
|
type StoreStateInterface
|
|
5
4
|
} from '@qlover/corekit-bridge';
|
|
6
|
-
import {
|
|
5
|
+
import { SyncStorageInterface } from '@qlover/fe-corekit';
|
|
6
|
+
import random from 'lodash/random';
|
|
7
7
|
|
|
8
8
|
interface JSONStoragePageState extends StoreStateInterface {
|
|
9
9
|
testKey1?: number;
|
|
@@ -17,7 +17,7 @@ export class JSONStorageController extends StoreInterface<JSONStoragePageState>
|
|
|
17
17
|
requestTimeout: (state: JSONStoragePageState) => state.requestTimeout
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
-
constructor(private storage:
|
|
20
|
+
constructor(private storage: SyncStorageInterface<string, number>) {
|
|
21
21
|
super(() => ({
|
|
22
22
|
testKey1: storage.getItem('testKey1') ?? 0,
|
|
23
23
|
testKey2: storage.getItem('testKey2') ?? 0,
|
|
@@ -6,7 +6,7 @@ import { useStore } from '../hooks/useStore';
|
|
|
6
6
|
export function UserAuthProvider({ children }: { children: React.ReactNode }) {
|
|
7
7
|
const userService = IOC(UserService);
|
|
8
8
|
|
|
9
|
-
useStore(userService);
|
|
9
|
+
useStore(userService.store);
|
|
10
10
|
|
|
11
11
|
if (!userService.isAuthenticated()) {
|
|
12
12
|
return <Loading fullscreen />;
|
package/package.json
CHANGED
|
File without changes
|