fakelab 0.0.8 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -8
- package/lib/cli.js +2 -2
- package/lib/main.d.ts +1 -6
- package/lib/main.js +1 -1
- package/lib/public/css/style.css +6 -2
- package/lib/public/favicon.ico +0 -0
- package/lib/public/icons/logo.svg +7 -0
- package/lib/public/icons/logo24.svg +9 -0
- package/lib/public/js/fakelab.min.js +2 -1
- package/lib/views/components/sidebar.ejs +1 -1
- package/package.json +1 -1
- package/lib/views/error.ejs +0 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Fakelab
|
|
1
|
+
#  Fakelab
|
|
2
2
|
|
|
3
3
|
⚡ A fast, easy-config mock API server for frontend developers.
|
|
4
4
|
|
|
@@ -21,13 +21,13 @@ yarn add -D fakelab
|
|
|
21
21
|
|
|
22
22
|
## Usage/Examples
|
|
23
23
|
|
|
24
|
-
create `fakelab.config.ts` file in the project root. and reference your
|
|
24
|
+
create `fakelab.config.ts` file in the project root. and reference your typescript files.
|
|
25
25
|
|
|
26
26
|
```typescript
|
|
27
27
|
import { defineConfig } from "fakelab";
|
|
28
28
|
|
|
29
29
|
export default defineConfig({
|
|
30
|
-
sourcePath: "./
|
|
30
|
+
sourcePath: "./types", // can set one/multiple directory(s) or typescript file(s).
|
|
31
31
|
faker: { locale: "en" }, // optional
|
|
32
32
|
server: { pathPrefix: "api/v1", port: 8080 }, // optional
|
|
33
33
|
});
|
|
@@ -37,9 +37,29 @@ Fakelab allows you to control generated mock data using JSDoc tags.
|
|
|
37
37
|
You simply annotate your TypeScript interfaces with the @faker tag, and Fakelab uses the corresponding [faker](https://fakerjs.dev/)
|
|
38
38
|
method when generating mock values.
|
|
39
39
|
|
|
40
|
-
`/
|
|
40
|
+
`/other/post.ts`:
|
|
41
41
|
|
|
42
42
|
```typescript
|
|
43
|
+
export type Post = {
|
|
44
|
+
id: string;
|
|
45
|
+
title: string;
|
|
46
|
+
};
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`/other/profile.ts`:
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
export type Profile = {
|
|
53
|
+
id: string;
|
|
54
|
+
};
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`/types/user.ts`:
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
export { type Profile } from "../other/profile";
|
|
61
|
+
import { type Post } from "../other/post";
|
|
62
|
+
|
|
43
63
|
export interface User {
|
|
44
64
|
/** @faker string.uuid */
|
|
45
65
|
id: string;
|
|
@@ -47,7 +67,8 @@ export interface User {
|
|
|
47
67
|
/** @faker person.fullName */
|
|
48
68
|
name: string;
|
|
49
69
|
|
|
50
|
-
|
|
70
|
+
// Use it as a function to pass the arguments.
|
|
71
|
+
/** @faker number.int({ max: 10 }) */
|
|
51
72
|
age: number;
|
|
52
73
|
|
|
53
74
|
/** @faker datatype.boolean */
|
|
@@ -56,17 +77,40 @@ export interface User {
|
|
|
56
77
|
/** @faker location.streetAddress */
|
|
57
78
|
address: string;
|
|
58
79
|
|
|
59
|
-
|
|
60
|
-
tags: string[];
|
|
80
|
+
posts: Post[];
|
|
61
81
|
}
|
|
62
82
|
```
|
|
63
83
|
|
|
64
|
-
|
|
84
|
+
**NOTE:** Fakelab only supports `interfaces`, `types`, `named export declarations`.
|
|
85
|
+
|
|
86
|
+
## Server Command
|
|
65
87
|
|
|
66
88
|
Run:
|
|
67
89
|
|
|
68
90
|
```bash
|
|
91
|
+
npx fakelab serve [options]
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Options
|
|
95
|
+
|
|
96
|
+
| Option | Alias | Description |
|
|
97
|
+
| ----------------------- | ----- | ----------------------------------------------------- |
|
|
98
|
+
| `--source` | `-s` | Path to the source typescript file(s) or directory(s) |
|
|
99
|
+
| `--pathPrefix <prefix>` | `-x` | Prefix for all generated API routes |
|
|
100
|
+
| `--locale <locale>` | `-l` | Locale used for fake data generation |
|
|
101
|
+
| `--port <number>` | `-p` | Port to run the server on |
|
|
102
|
+
|
|
103
|
+
### Examples
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# Basic usage
|
|
69
107
|
npx fakelab serve
|
|
108
|
+
|
|
109
|
+
# Custom source and port
|
|
110
|
+
npx fakelab serve -s ./types -p 4000
|
|
111
|
+
|
|
112
|
+
# Custom API prefix and locale
|
|
113
|
+
npx fakelab serve --pathPrefix /v1 --locale fr
|
|
70
114
|
```
|
|
71
115
|
|
|
72
116
|
## Related
|
package/lib/cli.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import P from'path';import {fileURLToPath}from'url';import
|
|
2
|
-
`)),process.exit(1));let r=await
|
|
1
|
+
import P from'path';import {fileURLToPath}from'url';import M from'fs-extra';import m from'zod';import {Command}from'commander';import k from'express';import J from'cors';import K from'express-ejs-layouts';import q from'http';import'ejs';import $ from'qs';import {Project}from'ts-morph';import {v4}from'uuid';import u from'picocolors';import Q from'figlet';import {bundleRequire}from'bundle-require';import ee from'joycon';var c=class o{static prefix(e){let r=new Date().toLocaleTimeString();return {info:u.blue,warn:u.yellow,error:u.red,success:u.green,debug:u.magenta}[e](`[${r}] FAKELAB_${e.toUpperCase()}`)}static log(e,r,...n){let t=u.white,s=o.prefix(e);(e==="error"?console.error:e==="warn"?console.warn:console.log)(s,t(r),...n);}static info(e,...r){this.log("info",e,...r);}static warn(e,...r){this.log("warn",e,...r);}static error(e,...r){this.log("error",e,...r);}static success(e,...r){this.log("success",e,...r);}};var y=class{constructor(e){this.faker=e;}JSDOC_FAKER_FIELD="faker";FAKER_TAG_REGEX=/^([a-zA-Z0-9._]+)(?:\((.*)\))?$/;boolMapping={true:true,false:false};string(e){return this.execute(e,this.faker.word.noun)}int(e){return this.execute(e,this.faker.number.int)}bool(e){return this.execute(e,this.faker.datatype.boolean)}bigInt(e){return this.execute(e,this.faker.number.bigInt)}litbool(e){return this.boolMapping[e]}async object(e,r){let n={};return await Promise.all(e.map(async t=>{let s=t.getTypeAtLocation(t.getValueDeclarationOrThrow());n[t.getName()]=await r(s,this,this.readJSDocTags(t));})),n}async union(e){let r=await Promise.all(e);return r[Math.floor(Math.random()*r.length)]}async intersection(e){let r=await Promise.all(e);return r[Math.floor(Math.random()*r.length)]}evalArgs(e){if(!(!e||!e.trim()))return Function(`"use strict"; return (${e});`)()}readJSDocTags(e){let r=e.getJsDocTags().filter(n=>n.getName()===this.JSDOC_FAKER_FIELD);return r.length===0?[]:r.map(n=>{let[t]=n.getText();if(!t)return;let s=t.text.trim().match(this.FAKER_TAG_REGEX);if(!s)return;let[,i,a]=s,p=this.evalArgs(a);return {path:i,args:p}})}execute(e,r){if(!e)return r();let n=e.path.split("."),t=this.faker;for(let s of n)t=t[s],t||(c.error("Invalid faker module path:",e.path),process.exit(1));typeof t!="function"&&(c.error("Unresolvable faker function.",e.path),process.exit(1));try{return e.args?t(e.args):t()}catch{return c.error("Passed invalid arguments to faker function."),t()}}};var d=class{constructor(e){this.files=e;let n=new Project({tsConfigFilePath:"tsconfig.json"}).addSourceFilesAtPaths(e);this.__targets=n.flatMap(t=>{let s=t.getInterfaces(),i=t.getTypeAliases(),a=t.getExportDeclarations().flatMap(p=>p.getNamedExports().flatMap(f=>f.getLocalTargetDeclarations()));return [...s,...i,...a]});}__targets;async run(e){return await e()}normalizePath(e){return e.split(P.sep).join(P.posix.sep)}entities(){let e=this.__targets.map(r=>{let n=r.getName().toLowerCase(),t=r.getType(),s=this.normalizePath(process.cwd()),a=this.normalizePath(r.getSourceFile().getDirectoryPath()).replace(s,""),p=r.getSourceFile().getBaseName(),f=`${a}/${p}`;return [n,{type:t,filepath:f}]});return new Map(e)}async loadFaker(e,r){let{faker:n}=await import(`@faker-js/faker/locale/${r||e.locale}`);return n}};async function l(o,e,r=[],n=0){if(o.isString())return e.string(r[n]);if(o.isNumber())return e.int(r[n]);if(o.isBoolean())return e.bool(r[n]);if(o.isBigInt())return e.bigInt(r[n]);if(o.isBooleanLiteral())return e.litbool(o.getText());if(o.isLiteral())return o.getLiteralValue();if(!o.isUndefined()){if(o.isUnion()){let t=o.getUnionTypes();return await e.union(t.map((s,i)=>l(s,e,r,i)))}if(o.isIntersection()){let t=o.getIntersectionTypes();return await e.intersection(t.map((s,i)=>l(s,e,r,i)))}if(o.isArray()){let t=o.getArrayElementTypeOrThrow();return [await l(t,e,r,n)]}if(o.isObject()){let t=o.getProperties();return await e.object(t,(s,i,a)=>l(s,i,a,n))}return null}}function D({each:o}){return {resolve:async r=>await Promise.all(Array.from({length:r},(n,t)=>o(t)))}}function R(o,e){return o==="uuid"?v4():e+1}function N(o,e,r){return async n=>{let t=await l(o,e);return r.uid&&typeof t=="object"?{[r.uid]:R(r.strategy,n),...t}:t}}async function L(o,e){let r=await o.files(e.source),n=new d(r),t=await n.loadFaker(o.fakerOpts(e.locale)),s=new y(t),i=n.entities();async function a(p,f){let g=D({each:N(p,s,f)}),h=await(f.count?g.resolve(parseInt(f.count)):l(p,s)),x=JSON.stringify(h,null,2);return {data:h,json:x}}return {entities:i,forge:a}}var U=fileURLToPath(import.meta.url),B=P.dirname(U),A=M.readJSONSync(P.join(B,"../package.json")),v=class{constructor(e,r,n){this.router=e;this.config=r;this.opts=n;let{pathPrefix:t}=this.config.serverOpts(this.opts.pathPrefix);this.prefix=t;}prefix;get querySchema(){return m.object({count:m.string().optional(),uid:m.string().optional(),strategy:m.string().optional()})}async handleQueries(e){let{success:r,data:n,error:t}=await this.querySchema.safeParseAsync(e.query);return r?n:(c.warn(t.message),{})}async register(){let{entities:e,forge:r}=await L(this.config,this.opts);this.router.get("/",(n,t)=>{let s=n.path;t.render("index",{currentPath:s,entities:e,version:A.version});}),this.router.get("/:name",async(n,t)=>{let s=`${n.protocol}://${n.host}/`,i=n.path,a=n.params.name,p=await this.handleQueries(n),f=$.stringify(p,{addQueryPrefix:true}),g=e.get(a.toLowerCase());if(g){let{json:h}=await r(g.type,p),x=g.filepath;t.render("preview",{name:a,filepath:x,currentPath:i,address:s,search:f,json:h,entities:e,version:A.version,prefix:this.prefix});}else t.redirect("/");}),this.router.get(`/${this.prefix}/:name`,async(n,t)=>{try{let s=n.params.name,i=await this.handleQueries(n),a=e.get(s.toLowerCase());if(a){let{data:p}=await r(a.type,i);t.status(200).json(p);}else t.status(400).json({message:"The requested interface is not found"});}catch(s){t.status(500).send(s);}});}};var V=fileURLToPath(import.meta.url),C=P.dirname(V);function X(o,e,r){let{port:n}=e.serverOpts(r.pathPrefix,r.port);o.listen(n,"localhost",async()=>{c.info(`Server: http://localhost:${n}`),console.log(await Q.text("FAKELAB"));});}function H(o,e,r){e.setHeader("x-powered-by","fakelab"),r();}function Z(o){o.disable("x-powered-by"),o.use(k.json()),o.use(J({methods:"GET"})),o.use(k.static(C+"/public")),o.use(H);}function W(o){o.set("views",P.join(C,"views")),o.set("view engine","ejs"),o.use(K),o.set("layout","layouts/main");}async function E(o,e){let r=k(),n=k.Router(),t=q.createServer(r);Z(r),W(r),await new v(n,o,e).register(),r.use(n),X(t,o,e);}async function _(){try{let e=await new ee().resolve({files:["fakelab.config.ts"]});return e||(c.error("No fakelab config file is detected."),process.exit(1)),(await bundleRequire({filepath:e})).mod.default}catch{c.error("Could not load the config file."),process.exit(1);}}var b=new Command,ne=fileURLToPath(import.meta.url),se=P.dirname(ne),T=M.readJSONSync(P.join(se,"../package.json"));b.name(T.name).description(T.description).version(T.version);var ie=m.object({source:m.string().optional(),pathPrefix:m.string().optional(),port:m.number().int().optional(),locale:m.string().optional()});b.command("serve").description("start server").option("-s, --source <char>","config source path").option("-x, --pathPrefix <char>","server url path prefix").option("-p, --port <number>","server port number",parseInt).option("-l, --locale <char>","faker custom locale").action(async o=>{let e=await ie.safeParseAsync(o);e.error&&(c.error(m.treeifyError(e.error).errors.join(`
|
|
2
|
+
`)),process.exit(1));let r=await _();E(r,e.data);});b.parse();
|
package/lib/main.d.ts
CHANGED
|
@@ -16,11 +16,6 @@ type ConfigOptions = {
|
|
|
16
16
|
server?: ServerOptions;
|
|
17
17
|
faker?: FakerEngineOptions;
|
|
18
18
|
};
|
|
19
|
-
type UserConfig = {
|
|
20
|
-
files: string[];
|
|
21
|
-
serverOptions: Required<ServerOptions>;
|
|
22
|
-
fakerOptions: Required<FakerEngineOptions>;
|
|
23
|
-
};
|
|
24
19
|
type FakerLocale = "af" | "ar" | "az" | "bn" | "cs" | "cy" | "da" | "de" | "dv" | "el" | "en" | "eo" | "es" | "fa" | "fi" | "fr" | "he" | "hr" | "hu" | "hy" | "id" | "it" | "ja" | "ka" | "ko" | "ku" | "lv" | "mk" | "nb" | "ne" | "nl" | "pl" | "pt" | "ro";
|
|
25
20
|
|
|
26
21
|
declare class Config {
|
|
@@ -37,4 +32,4 @@ declare class Config {
|
|
|
37
32
|
|
|
38
33
|
declare function defineConfig(options: ConfigOptions): Config;
|
|
39
34
|
|
|
40
|
-
export {
|
|
35
|
+
export { defineConfig };
|
package/lib/main.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import g from'fast-glob';import l from'path';import {stat,access,constants}from'fs/promises';import i from'picocolors';var s=class o{static prefix(t){let r=new Date().toLocaleTimeString();return {info:i.blue,warn:i.yellow,error:i.red,success:i.green,debug:i.magenta}[t](`[${r}] FAKELAB_${t.toUpperCase()}`)}static log(t,r,...e){let n=i.white,c=o.prefix(t);(t==="error"?console.error:t==="warn"?console.warn:console.log)(c,n(r),...e);}static info(t,...r){this.log("info",t,...r);}static warn(t,...r){this.log("warn",t,...r);}static error(t,...r){this.log("error",t,...r);}static success(t,...r){this.log("success",t,...r);}};function p(){let o=Intl.DateTimeFormat().resolvedOptions().locale;if(!o)return "en";let[t]=o.split("-");return t.toLowerCase()}var a=class{constructor(t){this.opts=t;this.files=this.files.bind(this),this.serverOpts=this.serverOpts.bind(this),this.fakerOpts=this.fakerOpts.bind(this);}async files(t){let r=this.resolveSourcePath(t||this.opts.sourcePath),e=Array.from(new Set((await Promise.all(r.map(n=>this.resolveTSFiles(n)))).flat()));return e.length===0&&(s.error(`No Typescript files found in:
|
|
2
2
|
%s`,r.join(`
|
|
3
|
-
`)),process.exit(1)),e}serverOpts(t,r){return {pathPrefix:t||this.opts.server?.pathPrefix||"api",port:r||this.opts.server?.port||5200}}fakerOpts(t){return {locale:t||this.opts.faker?.locale||p()}}async tryStat(t){try{return await stat(t)}catch{return null}}async isReadable(t){try{return await access(t,constants.R_OK),!0}catch{return false}}resolveSourcePath(t){return (Array.isArray(t)?t:[t]).map(e=>l.resolve(e))}async resolveTSFiles(t){let r=l.resolve(t),e=r.endsWith(".ts")?r:r+".ts";if((await this.tryStat(e))?.isFile()){if(!await this.isReadable(e))throw new Error(`Cannot read file: ${e}`);return s.info("Source:",e),[e]}if((await this.tryStat(r))?.isDirectory())return s.info("Source:",r),g("**/*.ts",{cwd:r,absolute:true,ignore:["**/*.d.ts"]});s.error(`Invalid source path: ${t}`),process.exit(1);}};function
|
|
3
|
+
`)),process.exit(1)),e}serverOpts(t,r){return {pathPrefix:t||this.opts.server?.pathPrefix||"api",port:r||this.opts.server?.port||5200}}fakerOpts(t){return {locale:t||this.opts.faker?.locale||p()}}async tryStat(t){try{return await stat(t)}catch{return null}}async isReadable(t){try{return await access(t,constants.R_OK),!0}catch{return false}}resolveSourcePath(t){return (Array.isArray(t)?t:[t]).map(e=>l.resolve(e))}async resolveTSFiles(t){let r=l.resolve(t),e=r.endsWith(".ts")?r:r+".ts";if((await this.tryStat(e))?.isFile()){if(!await this.isReadable(e))throw new Error(`Cannot read file: ${e}`);return s.info("Source:",e),[e]}if((await this.tryStat(r))?.isDirectory())return s.info("Source:",r),g("**/*.ts",{cwd:r,absolute:true,ignore:["**/*.d.ts"]});s.error(`Invalid source path: ${t}`),process.exit(1);}};function y(o){return new a(o)}export{y as defineConfig};
|
package/lib/public/css/style.css
CHANGED
|
@@ -41,11 +41,15 @@ pre {
|
|
|
41
41
|
|
|
42
42
|
.sidebar .logo {
|
|
43
43
|
height: 65px;
|
|
44
|
+
text-decoration: none;
|
|
44
45
|
padding-inline: 16px;
|
|
45
46
|
display: flex;
|
|
46
47
|
align-items: center;
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
gap: 6px;
|
|
49
|
+
|
|
50
|
+
> span {
|
|
51
|
+
color: oklch(98.5% 0.002 247.839);
|
|
52
|
+
}
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
.sidebar .sidebar_docs {
|
|
Binary file
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24px" height="24px" viewBox="0 0 24 24" version="1.1">
|
|
3
|
+
<g id="surface1">
|
|
4
|
+
<path style="fill-rule:nonzero;fill:rgb(27.450982%,98.431373%,90.196079%);fill-opacity:1;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(27.450982%,98.431373%,90.196079%);stroke-opacity:1;stroke-miterlimit:4;" d="M 460.583333 412.833333 L 326 179.666667 L 326 65.666667 L 334.75 65.666667 C 342 65.666667 347.916667 59.833333 347.916667 52.583333 C 347.916667 45.333333 342 39.416667 334.75 39.416667 L 177.25 39.416667 C 160.083333 39.75 160 65.416667 177.25 65.666667 L 186 65.666667 L 186 179.666667 L 51.416667 412.833333 C 36.083333 439.333333 55.25 472.583333 85.916667 472.583333 L 426.083333 472.583333 C 456.75 472.583333 475.916667 439.333333 460.583333 412.833333 Z M 437.833333 439.5 C 435.5 443.75 431 446.333333 426.083333 446.333333 L 85.916667 446.333333 C 81.083333 446.333333 76.583333 443.75 74.166667 439.5 C 71.666667 435.333333 71.666667 430.166667 74.166667 425.916667 L 151.666667 291.666667 C 162.083333 295.583333 174.666667 298.333333 192 298.333333 C 224 298.333333 240 289.166667 256 280.083333 C 272 270.916667 288 261.833333 320 261.833333 C 328.166667 261.75 336.333333 262.5 344.416667 264 L 437.833333 425.916667 C 440.333333 430.083333 440.333333 435.333333 437.833333 439.5 Z M 437.833333 439.5 " transform="matrix(0.046875,0,0,0.046875,0,0)"/>
|
|
5
|
+
<path style="fill-rule:nonzero;fill:rgb(27.450982%,98.431373%,90.196079%);fill-opacity:1;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(27.450982%,98.431373%,90.196079%);stroke-opacity:1;stroke-miterlimit:4;" d="M 218 406.916667 C 218.416667 429.916667 252.666667 429.916667 253 406.916667 C 252.666667 383.916667 218.416667 383.916667 218 406.916667 Z M 218 406.916667 " transform="matrix(0.046875,0,0,0.046875,0,0)"/>
|
|
6
|
+
<path style="fill-rule:nonzero;fill:rgb(27.450982%,98.431373%,90.196079%);fill-opacity:1;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(27.450982%,98.431373%,90.196079%);stroke-opacity:1;stroke-miterlimit:4;" d="M 148 354.416667 C 148.416667 377.416667 182.666667 377.416667 183 354.416667 C 182.666667 331.416667 148.416667 331.416667 148 354.416667 Z M 148 354.416667 " transform="matrix(0.046875,0,0,0.046875,0,0)"/>
|
|
7
|
+
<path style="fill-rule:nonzero;fill:rgb(27.450982%,98.431373%,90.196079%);fill-opacity:1;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(27.450982%,98.431373%,90.196079%);stroke-opacity:1;stroke-miterlimit:4;" d="M 312.833333 328.166667 C 313.25 351.166667 347.5 351.166667 347.833333 328.166667 C 347.5 305.166667 313.25 305.166667 312.833333 328.166667 Z M 312.833333 328.166667 " transform="matrix(0.046875,0,0,0.046875,0,0)"/>
|
|
8
|
+
</g>
|
|
9
|
+
</svg>
|
|
@@ -78,5 +78,6 @@ window.addEventListener("click", handleCloseSetting),
|
|
|
78
78
|
a = new URLSearchParams(window.location.search),
|
|
79
79
|
c = a.get("count"),
|
|
80
80
|
r = a.get("uid");
|
|
81
|
-
c && (e.value = c),
|
|
81
|
+
c && (e.value = c),
|
|
82
|
+
r && ((t.checked = !0), (d.value = r), o.setAttribute("data-visible", "true"), i.setAttribute("data-visible", "true"), a.has("strategy")) && (n.checked = !0);
|
|
82
83
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<aside class="sidebar">
|
|
2
|
-
<a class="logo" href="/">Fakelab</a>
|
|
2
|
+
<a class="logo" href="/"><img src="/icons/logo.svg" width="20px" height="20px" /><span>Fakelab</span></a>
|
|
3
3
|
<div class="sidebar_content">
|
|
4
4
|
<div class="sidebar_content_leading">
|
|
5
5
|
<div class="sidebar_content_indicator_icon"></div>
|
package/package.json
CHANGED
package/lib/views/error.ejs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<h1>ERROR <%= name %> data not found!</h1>
|