@akanjs/base 0.0.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/README.md ADDED
@@ -0,0 +1,11 @@
1
+ # akan
2
+
3
+ This library was generated with [Nx](https://nx.dev).
4
+
5
+ ## Building
6
+
7
+ Run `nx build akan` to build the library.
8
+
9
+ ## Running unit tests
10
+
11
+ Run `nx test akan` to execute the unit tests via [Jest](https://jestjs.io).
package/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./src";
package/package.json ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "@akanjs/base",
3
+ "version": "0.0.1",
4
+ "type": "module"
5
+ }
package/project.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@akanjs/base",
3
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
4
+ "sourceRoot": "pkgs/@akanjs/base",
5
+ "projectType": "application",
6
+ "tags": [],
7
+ "targets": {
8
+ "build": {
9
+ "executor": "@nx/esbuild:esbuild",
10
+ "outputs": ["{options.outputPath}"],
11
+ "options": {
12
+ "outputPath": "dist/{projectRoot}",
13
+ "main": "{projectRoot}/index.ts",
14
+ "tsConfig": "{projectRoot}/tsconfig.json",
15
+ "format": ["esm"],
16
+ "declaration": true,
17
+ "bundle": false,
18
+ "generatePackageJson": true
19
+ }
20
+ },
21
+ "lint": { "executor": "@nx/eslint:lint" }
22
+ }
23
+ }
package/src/base.ts ADDED
@@ -0,0 +1,145 @@
1
+ export class Enum<T> {
2
+ readonly value: T; // for type
3
+ readonly valueMap: Map<T, number>;
4
+ constructor(readonly values: T[]) {
5
+ this.valueMap = new Map(values.map((value, idx) => [value, idx] as [T, number]));
6
+ }
7
+ has(value: T): boolean {
8
+ return this.valueMap.has(value);
9
+ }
10
+ indexOf(value: T): number {
11
+ const idx = this.valueMap.get(value);
12
+ if (idx === undefined) throw new Error(`Value ${value} is not in enum`);
13
+ return idx;
14
+ }
15
+ find(callback: (value: T, index: number, array: T[]) => boolean): T {
16
+ const val = this.values.find(callback);
17
+ if (val === undefined) throw new Error(`Value not found in enum`);
18
+ return val;
19
+ }
20
+ findIndex(callback: (value: T, index: number, array: T[]) => boolean): number {
21
+ const idx = this.values.findIndex(callback);
22
+ if (idx === -1) throw new Error(`Value not found in enum`);
23
+ return idx;
24
+ }
25
+ filter(callback: (value: T, index: number, array: T[]) => boolean): T[] {
26
+ return this.values.filter(callback);
27
+ }
28
+ map<R>(callback: (value: T, index: number, array: T[]) => R): R[] {
29
+ return this.values.map(callback);
30
+ }
31
+ forEach(callback: (value: T, index: number, array: T[]) => void): void {
32
+ this.values.forEach(callback);
33
+ }
34
+ }
35
+ export const enumOf = <T>(values: T[]) => new Enum(values);
36
+ export type EnumType<E> = E extends Enum<infer T> ? T : never;
37
+
38
+ export class DataList<Light extends { id: string }> {
39
+ // [immerable] = true;
40
+ #idMap: Map<string, number>;
41
+ length: number;
42
+ values: Light[];
43
+ constructor(data: Light[] | DataList<Light> = []) {
44
+ this.values = Array.isArray(data) ? [...data] : [...data.values];
45
+ this.#idMap = new Map(this.values.map((value, idx) => [value.id, idx]));
46
+ this.length = this.values.length;
47
+ }
48
+ indexOf(id: string) {
49
+ const idx = this.#idMap.get(id);
50
+ if (idx === undefined) throw new Error(`Value ${id} is not in list`);
51
+ return idx;
52
+ }
53
+ set(value: Light) {
54
+ const idx = this.#idMap.get(value.id);
55
+ if (idx !== undefined) this.values = [...this.values.slice(0, idx), value, ...this.values.slice(idx + 1)];
56
+ else {
57
+ this.#idMap.set(value.id, this.length);
58
+ this.values = [...this.values, value];
59
+ this.length++;
60
+ }
61
+ return this;
62
+ }
63
+ delete(id: string) {
64
+ const idx = this.#idMap.get(id);
65
+ if (idx === undefined) return this;
66
+ this.#idMap.delete(id);
67
+ this.values.splice(idx, 1);
68
+ this.values.slice(idx).forEach((value, i) => this.#idMap.set(value.id, i + idx));
69
+ this.length--;
70
+ return this;
71
+ }
72
+ get(id: string) {
73
+ const idx = this.#idMap.get(id);
74
+ if (idx === undefined) return undefined;
75
+ return this.values[idx];
76
+ }
77
+ at(idx: number) {
78
+ return this.values.at(idx);
79
+ }
80
+ pickAt(idx: number) {
81
+ const value = this.values.at(idx);
82
+ if (value === undefined) throw new Error(`Value at ${idx} is undefined`);
83
+ return value;
84
+ }
85
+ pick(id: string) {
86
+ return this.values[this.indexOf(id)];
87
+ }
88
+ has(id: string) {
89
+ return this.#idMap.has(id);
90
+ }
91
+ find(fn: (value: Light, idx: number) => boolean) {
92
+ const val = this.values.find(fn);
93
+ return val;
94
+ }
95
+ findIndex(fn: (value: Light, idx: number) => boolean) {
96
+ const val = this.values.findIndex(fn);
97
+ return val;
98
+ }
99
+ some(fn: (value: Light, idx: number) => boolean) {
100
+ return this.values.some(fn);
101
+ }
102
+ every(fn: (value: Light, idx: number) => boolean) {
103
+ return this.values.every(fn);
104
+ }
105
+ forEach(fn: (value: Light, idx: number) => void) {
106
+ this.values.forEach(fn);
107
+ }
108
+ map<T>(fn: (value: Light, idx: number) => T) {
109
+ return this.values.map(fn);
110
+ }
111
+ flatMap<T>(fn: (value: Light, idx: number, array: Light[]) => T | readonly T[]) {
112
+ return this.values.flatMap(fn);
113
+ }
114
+ sort(fn: (a: Light, b: Light) => number) {
115
+ return new DataList(this.values.sort(fn));
116
+ }
117
+ filter(fn: (value: Light, idx: number) => boolean) {
118
+ return new DataList(this.values.filter(fn));
119
+ }
120
+ reduce<T>(fn: (acc: T, value: Light, idx: number) => T, initialValue: T) {
121
+ return this.values.reduce(fn, initialValue);
122
+ }
123
+ slice(start: number, end = this.length) {
124
+ return new DataList(this.values.slice(start, end));
125
+ }
126
+ save() {
127
+ return new DataList(this);
128
+ }
129
+ [Symbol.iterator]() {
130
+ return this.values[Symbol.iterator]();
131
+ }
132
+ }
133
+
134
+ export const version = "0.9.0";
135
+ export const logo = `
136
+ _ _ _
137
+ / \\ | | ____ _ _ __ (_)___
138
+ / _ \\ | |/ / _' | '_ \\ | / __|
139
+ / ___ \\| < (_| | | | |_ | \\__ \\
140
+ /_/ \\_\\_|\\_\\__,_|_| |_(_)/ |___/
141
+ |__/ ver ${version}
142
+ ? See more details on docs https://www.akanjs.com/docs
143
+ ★ Star Akanjs on GitHub https://github.com/aka-bassman/akanjs
144
+
145
+ `;
package/src/baseEnv.ts ADDED
@@ -0,0 +1,110 @@
1
+ export type Environment = "testing" | "debug" | "develop" | "main";
2
+ export interface BaseEnv {
3
+ appName: string;
4
+ environment: Environment;
5
+ operationType: "server" | "client";
6
+ operationMode: "local" | "edge" | "cloud" | "module";
7
+ networkType: "mainnet" | "testnet" | "debugnet";
8
+ }
9
+ export type BackendEnv = BaseEnv & {
10
+ hostname: string | null;
11
+ appCode: number;
12
+ mongo: { password?: string };
13
+ port?: number;
14
+ mongoUri?: string;
15
+ redisUri?: string;
16
+ meiliUri?: string;
17
+ onCleanup?: () => Promise<void>;
18
+ };
19
+
20
+ //! Nextjs는 환경변수를 build time에 그냥 하드코딩으로 값을 넣어버림. operationMode같은것들 잘 동작안할 수 있음. 추후 수정 필요.
21
+ // https://nextjs.org/docs/app/building-your-application/configuring/environment-variables#runtime-environment-variables
22
+ const appName = process.env.NEXT_PUBLIC_APP_NAME ?? process.env.NX_TASK_TARGET_PROJECT ?? "unknown";
23
+ if (appName === "unknown")
24
+ throw new Error("environment variable NEXT_PUBLIC_APP_NAME or NX_TASK_TARGET_PROJECT is required");
25
+ const environment = (process.env.NEXT_PUBLIC_ENV ?? "debug") as BaseEnv["environment"];
26
+ const operationType = typeof window !== "undefined" ? "client" : process.env.NEXT_RUNTIME ? "client" : "server";
27
+ const operationMode = (process.env.NEXT_PUBLIC_OPERATION_MODE ?? "cloud") as BaseEnv["operationMode"];
28
+ const networkType = (process.env.NEXT_PUBLIC_NETWORK_TYPE ??
29
+ (environment === "main" ? "mainnet" : environment === "develop" ? "testnet" : "debugnet")) as BaseEnv["networkType"];
30
+
31
+ export const baseEnv: BaseEnv = {
32
+ appName,
33
+ environment,
34
+ operationType,
35
+ operationMode,
36
+ networkType,
37
+ } as const;
38
+
39
+ export type BaseClientEnv = BaseEnv & {
40
+ side: "server" | "client";
41
+ renderMode: "ssr" | "csr";
42
+ websocket: boolean;
43
+ clientHost: string;
44
+ clientPort: number;
45
+ clientHttpProtocol: "http:" | "https:";
46
+ clientHttpUri: string;
47
+ serverHost: string;
48
+ serverPort: number;
49
+ serverHttpProtocol: "http:" | "https:";
50
+ serverHttpUri: string;
51
+ serverGraphqlUri: string;
52
+ serverWsProtocol: "ws:" | "wss:";
53
+ serverWsUri: string;
54
+ };
55
+
56
+ const side = typeof window === "undefined" ? "server" : "client";
57
+ const renderMode = (process.env.RENDER_ENV ?? "ssr") as BaseClientEnv["renderMode"];
58
+ const clientHost =
59
+ process.env.NEXT_PUBLIC_CLIENT_HOST ??
60
+ (operationMode === "local" || side === "server" ? "localhost" : window.location.hostname);
61
+ const clientPort = parseInt(
62
+ process.env.NEXT_PUBLIC_CLIENT_PORT ?? (operationMode === "local" ? (renderMode === "ssr" ? "4200" : "4201") : "443")
63
+ );
64
+ const clientHttpProtocol =
65
+ side === "client"
66
+ ? (window.location.protocol as "http:" | "https:")
67
+ : clientHost === "localhost"
68
+ ? "http:"
69
+ : "https:";
70
+ const clientHttpUri = `${clientHttpProtocol}//${clientHost}${clientPort === 443 ? "" : `:${clientPort}`}`;
71
+ const serverHost =
72
+ process.env.SERVER_HOST ??
73
+ (operationMode === "local"
74
+ ? typeof window === "undefined"
75
+ ? "localhost"
76
+ : window.location.host.split(":")[0]
77
+ : renderMode === "csr"
78
+ ? `${appName}-${environment}.akamir.com`
79
+ : side === "client"
80
+ ? window.location.host.split(":")[0]
81
+ : operationMode === "cloud"
82
+ ? `backend-svc.${appName}-${environment}.svc.cluster.local`
83
+ : "localhost");
84
+
85
+ const serverPort = parseInt(
86
+ process.env.SERVER_PORT ?? (operationMode === "local" || side === "server" ? "8080" : "443")
87
+ );
88
+ const serverHttpProtocol = side === "client" ? (window.location.protocol as "http:" | "https:") : "http:";
89
+ const serverHttpUri = `${serverHttpProtocol}//${serverHost}${serverPort === 443 ? "" : `:${serverPort}`}/backend`;
90
+ const serverGraphqlUri = `${serverHttpUri}/graphql`;
91
+ const serverWsProtocol = serverHttpProtocol === "http:" ? "ws:" : "wss:";
92
+ const serverWsUri = `${serverWsProtocol}//${serverHost}${serverPort === 443 ? "" : `:${serverPort}`}`;
93
+
94
+ export const baseClientEnv: BaseClientEnv = {
95
+ ...baseEnv,
96
+ side,
97
+ renderMode,
98
+ websocket: true,
99
+ clientHost,
100
+ clientPort,
101
+ clientHttpProtocol,
102
+ clientHttpUri,
103
+ serverHost,
104
+ serverPort,
105
+ serverHttpProtocol,
106
+ serverHttpUri,
107
+ serverGraphqlUri,
108
+ serverWsProtocol,
109
+ serverWsUri,
110
+ } as const;
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from "./base";
2
+ export * from "./baseEnv";
3
+ export * from "./scalar";
4
+ export * from "./types";
package/src/scalar.ts ADDED
@@ -0,0 +1,104 @@
1
+ import dayjsLib, { Dayjs } from "dayjs";
2
+ import type { ReadStream } from "fs";
3
+ import type { Readable } from "stream";
4
+
5
+ import type { GraphQLJSON, GraphQLUpload, Type } from "./types";
6
+
7
+ export { Dayjs };
8
+
9
+ export const dayjs = dayjsLib;
10
+ export class BaseObject {
11
+ id: string;
12
+ createdAt: Dayjs;
13
+ updatedAt: Dayjs;
14
+ removedAt: Dayjs | null;
15
+ }
16
+ export class Int {
17
+ __Scalar__: "int";
18
+ }
19
+ export class Upload {
20
+ __Scalar__: "upload";
21
+ filename: string;
22
+ mimetype: string;
23
+ encoding: string;
24
+ createReadStream: () => ReadStream | Readable;
25
+ }
26
+
27
+ export class Float {
28
+ __Scalar__: "float";
29
+ }
30
+ export class ID {
31
+ __Scalar__: "id";
32
+ }
33
+ export class JSON {
34
+ __Scalar__: "json";
35
+ }
36
+ export type SingleFieldType =
37
+ | Int
38
+ | Float
39
+ | StringConstructor
40
+ | BooleanConstructor
41
+ | ID
42
+ | DateConstructor
43
+ | JSON
44
+ | Type
45
+ | GraphQLJSON
46
+ | GraphQLUpload;
47
+
48
+ export const getNonArrayModel = <T = Type>(arraiedModel: T | T[]): [T, number] => {
49
+ let arrDepth = 0;
50
+ let target: T | T[] = arraiedModel;
51
+ while (Array.isArray(target)) {
52
+ target = target[0];
53
+ arrDepth++;
54
+ }
55
+ return [target, arrDepth];
56
+ };
57
+ export const arraiedModel = <T = any>(modelRef: T, arrDepth = 0) => {
58
+ let target: T | T[] | T[][] | T[][][] = modelRef;
59
+ for (let i = 0; i < arrDepth; i++) target = [target as T];
60
+ return target;
61
+ };
62
+ export const applyFnToArrayObjects = (arraiedData: any, fn: (arg: any) => any): any[] => {
63
+ if (Array.isArray(arraiedData)) return arraiedData.map((data) => applyFnToArrayObjects(data, fn) as unknown);
64
+ return fn(arraiedData) as unknown as any[];
65
+ };
66
+
67
+ export const gqlScalars = [String, Boolean, Date, ID, Int, Float, Upload, JSON, Map] as const;
68
+ export type GqlScalar = (typeof gqlScalars)[number];
69
+ export const gqlScalarNames = ["ID", "Int", "Float", "String", "Boolean", "Date", "Upload", "JSON", "Map"] as const;
70
+ export type GqlScalarName = (typeof gqlScalarNames)[number];
71
+ export const scalarSet = new Set<GqlScalar>([String, Boolean, Date, ID, Int, Float, Upload, JSON, Map]);
72
+ export const scalarNameMap = new Map<GqlScalar, GqlScalarName>([
73
+ [ID, "ID"],
74
+ [Int, "Int"],
75
+ [Float, "Float"],
76
+ [String, "String"],
77
+ [Boolean, "Boolean"],
78
+ [Date, "Date"],
79
+ [Upload, "Upload"],
80
+ [JSON, "JSON"],
81
+ [Map, "Map"],
82
+ ]);
83
+ export const scalarArgMap = new Map<GqlScalar, any>([
84
+ [ID, null],
85
+ [String, ""],
86
+ [Boolean, false],
87
+ [Date, dayjs(new Date(-1))],
88
+ [Int, 0],
89
+ [Float, 0],
90
+ [JSON, {}],
91
+ [Map, {}],
92
+ ]);
93
+ export const scalarDefaultMap = new Map<GqlScalar, any>([
94
+ [ID, null],
95
+ [String, ""],
96
+ [Boolean, false],
97
+ [Date, dayjs(new Date(-1))],
98
+ [Int, 0],
99
+ [Float, 0],
100
+ [JSON, {}],
101
+ ]);
102
+ export const isGqlClass = (modelRef: Type) => !scalarSet.has(modelRef);
103
+ export const isGqlScalar = (modelRef: Type) => scalarSet.has(modelRef);
104
+ export const isGqlMap = (modelRef: any) => modelRef === Map;
package/src/types.ts ADDED
@@ -0,0 +1,50 @@
1
+ export type Type<T = any> = new (...args: any[]) => T;
2
+
3
+ export type BufferLike =
4
+ | string
5
+ | Buffer
6
+ | DataView
7
+ | number
8
+ | ArrayBufferView
9
+ | Uint8Array
10
+ | ArrayBuffer
11
+ | SharedArrayBuffer
12
+ | readonly any[]
13
+ | readonly number[];
14
+
15
+ export type GetObject<T> = Omit<{ [K in keyof T]: T[K] }, "prototype">;
16
+ export type OptionOf<Obj> = {
17
+ [K in keyof Obj]?: Obj[K] | null;
18
+ };
19
+ export type UnType<T> = T extends new (...args: any) => infer U ? U : never;
20
+
21
+ export interface GraphQLUpload {
22
+ name: string;
23
+ description: string;
24
+ specifiedByUrl: string;
25
+ serialize: any;
26
+ parseValue: any;
27
+ parseLiteral: any;
28
+ extensions: any;
29
+ astNode: any;
30
+ extensionASTNodes: any;
31
+ toConfig(): any;
32
+ toString(): string;
33
+ toJSON(): string;
34
+ inspect(): string;
35
+ }
36
+ export interface GraphQLJSON<TInternal = unknown, TExternal = TInternal> {
37
+ name: string;
38
+ description: string;
39
+ specifiedByURL: string;
40
+ serialize: any;
41
+ parseValue: any;
42
+ parseLiteral: any;
43
+ extensions: any;
44
+ astNode: any;
45
+ extensionASTNodes: any;
46
+ get [Symbol.toStringTag](): string;
47
+ toConfig(): any;
48
+ toString(): string;
49
+ toJSON(): string;
50
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "extends": "../../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "jsx": "preserve"
5
+ },
6
+ "files": [],
7
+ "include": ["**/*.ts"],
8
+ "references": [
9
+ {
10
+ "path": "./tsconfig.spec.json"
11
+ }
12
+ ]
13
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "types": ["jest", "node"]
5
+ },
6
+ "include": ["jest.config.ts", "**/*.test.ts"]
7
+ }