yinzerflow 0.2.10 → 0.3.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/docs/core/context.md +138 -0
- package/docs/core/examples.md +259 -10
- package/docs/core/routes.md +190 -27
- package/index.d.ts +1675 -27
- package/index.js +12 -12
- package/index.js.map +9 -7
- package/package.json +1 -1
- package/example/README.md +0 -11
- package/example/app/handlers/example.ts +0 -27
- package/example/app/index.ts +0 -107
- package/example/app/routes/example.ts +0 -18
- package/example/app/routes/group-example.ts +0 -13
- package/example/app/util/customLogger.ts +0 -166
- package/example/docker-compose.yml +0 -28
- package/example/package.json +0 -16
- package/example/tsconfig.json +0 -54
package/package.json
CHANGED
package/example/README.md
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
For the types to work, you need to connect to the docker container using the IDE
|
|
2
|
-
|
|
3
|
-
1. Ensure the [Dev Containers](https://marketplace.cursorapi.com/items?itemName=ms-vscode-remote.remote-containers) extension is installed in IDE
|
|
4
|
-
2. Start this image using `docker compose up -d`
|
|
5
|
-
3. To start the test server run `bun start`
|
|
6
|
-
4. Use `Ctrl + Shift + P`
|
|
7
|
-
5. Select "Dev Containers: Attach to Running Container ..."
|
|
8
|
-
6. Select this container which should be something like `yinzerflow-testing-app...`
|
|
9
|
-
7. In the IDE that just opened, select folder `/app/yinzerflow-local`
|
|
10
|
-
|
|
11
|
-
To aid in development, you can use the `bun run build:watch` command in the yinzerflow (the actual module) terminal
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import type { HandlerCallback } from 'yinzerflow';
|
|
3
|
-
|
|
4
|
-
export const exampleHandler: HandlerCallback<{
|
|
5
|
-
body: {
|
|
6
|
-
something: string;
|
|
7
|
-
};
|
|
8
|
-
response: {
|
|
9
|
-
message: string;
|
|
10
|
-
success: boolean;
|
|
11
|
-
data: {
|
|
12
|
-
something: string;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
}> = async ({ request }) => {
|
|
16
|
-
const { something } = request.body;
|
|
17
|
-
|
|
18
|
-
throw new Error("test");
|
|
19
|
-
|
|
20
|
-
return {
|
|
21
|
-
success: true,
|
|
22
|
-
message: "Hello World",
|
|
23
|
-
data: {
|
|
24
|
-
something
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
};
|
package/example/app/index.ts
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { registerExampleRoutes } from "@app/routes/example.ts";
|
|
2
|
-
import { registerGroupExampleRoutes } from "@app/routes/group-example.ts";
|
|
3
|
-
import log from "app/util/customLogger.ts";
|
|
4
|
-
import { YinzerFlow, type HandlerCallback } from "yinzerflow";
|
|
5
|
-
|
|
6
|
-
const app = new YinzerFlow({
|
|
7
|
-
cors: {
|
|
8
|
-
enabled: true,
|
|
9
|
-
origin: "http://localhost:8085",
|
|
10
|
-
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
|
|
11
|
-
allowedHeaders: ["Content-Type", "Authorization", "x-session-id"],
|
|
12
|
-
preflightContinue: false,
|
|
13
|
-
},
|
|
14
|
-
logLevel: "info",
|
|
15
|
-
networkLogs: true,
|
|
16
|
-
// logger: log,
|
|
17
|
-
// networkLogger: log,
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
// app.onError((ctx) => {
|
|
23
|
-
// ctx.response.setStatusCode(500);
|
|
24
|
-
// return {
|
|
25
|
-
// success: false,
|
|
26
|
-
// message: "Something went wrong",
|
|
27
|
-
// };
|
|
28
|
-
// });
|
|
29
|
-
|
|
30
|
-
app.onNotFound((ctx) => {
|
|
31
|
-
ctx.response.setStatusCode(404);
|
|
32
|
-
return {
|
|
33
|
-
success: false,
|
|
34
|
-
message: "Not Found",
|
|
35
|
-
};
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
app.beforeAll([
|
|
39
|
-
(_) => {
|
|
40
|
-
console.log("======== beforeAll ========");
|
|
41
|
-
},
|
|
42
|
-
]);
|
|
43
|
-
|
|
44
|
-
app.afterAll([
|
|
45
|
-
(ctx) => {
|
|
46
|
-
// ctx.response.setStatusCode(202);
|
|
47
|
-
console.log("afterAll");
|
|
48
|
-
},
|
|
49
|
-
]);
|
|
50
|
-
|
|
51
|
-
const login: HandlerCallback<{
|
|
52
|
-
response: {
|
|
53
|
-
success: boolean;
|
|
54
|
-
message: string;
|
|
55
|
-
};
|
|
56
|
-
body: {
|
|
57
|
-
email: string;
|
|
58
|
-
password: string;
|
|
59
|
-
};
|
|
60
|
-
}> = (({ request }) => {
|
|
61
|
-
const { email, password } = request.body;
|
|
62
|
-
console.log("========================");
|
|
63
|
-
console.log(email, password);
|
|
64
|
-
console.log("========================");
|
|
65
|
-
|
|
66
|
-
return {
|
|
67
|
-
success: true,
|
|
68
|
-
message: "Login successful",
|
|
69
|
-
};
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
app.post("/login", login);
|
|
73
|
-
|
|
74
|
-
app.group("/api", (app) => {
|
|
75
|
-
app.post(
|
|
76
|
-
"/get/:id",
|
|
77
|
-
((ctx) => {
|
|
78
|
-
console.log("route handler");
|
|
79
|
-
console.log(ctx.request);
|
|
80
|
-
|
|
81
|
-
return {
|
|
82
|
-
message: false
|
|
83
|
-
};
|
|
84
|
-
}),
|
|
85
|
-
{
|
|
86
|
-
beforeHooks: [
|
|
87
|
-
(ctx) => {
|
|
88
|
-
ctx.response.setStatusCode(200);
|
|
89
|
-
console.log("beforeRoute");
|
|
90
|
-
},
|
|
91
|
-
],
|
|
92
|
-
afterHooks: [
|
|
93
|
-
() => {
|
|
94
|
-
console.log("afterRoute");
|
|
95
|
-
},
|
|
96
|
-
],
|
|
97
|
-
}
|
|
98
|
-
);
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
// Register example routes
|
|
102
|
-
registerExampleRoutes(app);
|
|
103
|
-
registerGroupExampleRoutes(app);
|
|
104
|
-
|
|
105
|
-
// Start the server AFTER defining all routes
|
|
106
|
-
await app.listen();
|
|
107
|
-
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { exampleHandler } from '@app/handlers/example.ts';
|
|
2
|
-
import type { YinzerFlow } from 'yinzerflow';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Register example routes on the main app instance
|
|
6
|
-
*/
|
|
7
|
-
export const registerExampleRoutes = (app: YinzerFlow) => {
|
|
8
|
-
/**
|
|
9
|
-
* Get all users
|
|
10
|
-
*/
|
|
11
|
-
app.post('/get-users', exampleHandler);
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Add an override reason for a user to be able to add a payout method
|
|
15
|
-
* This is used to remove all requirements bypassing any checks such as the $20 minimum balance
|
|
16
|
-
*/
|
|
17
|
-
// app.post('/user/update', updateUserController);
|
|
18
|
-
};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { exampleHandler } from '@app/handlers/example.ts';
|
|
2
|
-
import type { YinzerFlow } from 'yinzerflow';
|
|
3
|
-
|
|
4
|
-
export const registerGroupExampleRoutes = (app: YinzerFlow): void => {
|
|
5
|
-
app.group('/admin', (group) => {
|
|
6
|
-
/**
|
|
7
|
-
* Get all users
|
|
8
|
-
*/
|
|
9
|
-
group.post('/get-users', exampleHandler);
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
});
|
|
13
|
-
};
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import type { TransformableInfo } from 'logform';
|
|
3
|
-
import { addColors, createLogger, format, transports } from 'winston';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Logging levels in winston conform to the severity ordering specified by RFC5424: severity of all levels is assumed to
|
|
7
|
-
* be numerically ascending from most important to least important.
|
|
8
|
-
*/
|
|
9
|
-
enum LogLevel {
|
|
10
|
-
CRITICAL = 0,
|
|
11
|
-
ERROR = 1,
|
|
12
|
-
WARN = 2,
|
|
13
|
-
INFO = 3,
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
enum LogColor {
|
|
17
|
-
CRITICAL = 'bold white redBG',
|
|
18
|
-
ERROR = 'bold red',
|
|
19
|
-
WARN = 'bold yellow',
|
|
20
|
-
INFO = 'bold cyan',
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
interface Transports {
|
|
24
|
-
console: transports.ConsoleTransportInstance;
|
|
25
|
-
file: transports.FileTransportInstance;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Define the levels that winston will use. This is used later on
|
|
30
|
-
* when we create the logger
|
|
31
|
-
*/
|
|
32
|
-
const logLevels = {
|
|
33
|
-
critical: LogLevel.CRITICAL,
|
|
34
|
-
error: LogLevel.ERROR,
|
|
35
|
-
warn: LogLevel.WARN,
|
|
36
|
-
info: LogLevel.INFO,
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* This lets us add custom logging levels and colors so that
|
|
43
|
-
* winston recognizes them
|
|
44
|
-
*/
|
|
45
|
-
addColors({
|
|
46
|
-
critical: LogColor.CRITICAL,
|
|
47
|
-
error: LogColor.ERROR,
|
|
48
|
-
warn: LogColor.WARN,
|
|
49
|
-
info: LogColor.INFO,
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Safely formats a message for logging, handling different types appropriately
|
|
54
|
-
*/
|
|
55
|
-
const formatLogMessage = (message: unknown, meta: Record<string, unknown> = {}): string => {
|
|
56
|
-
let formattedMessage = '';
|
|
57
|
-
|
|
58
|
-
if (typeof message === 'string') {
|
|
59
|
-
formattedMessage = message;
|
|
60
|
-
} else if (typeof message === 'object' && message !== null) {
|
|
61
|
-
formattedMessage = JSON.stringify(message);
|
|
62
|
-
} else {
|
|
63
|
-
formattedMessage = String(message);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const metaKeys = Object.keys(meta);
|
|
67
|
-
if (metaKeys.length === 0) {
|
|
68
|
-
return formattedMessage;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const formattedMeta = JSON.stringify(meta, null, 2);
|
|
72
|
-
|
|
73
|
-
return `${formattedMessage}\n${formattedMeta}`;
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* This is the format that will be used for all logs except File logs
|
|
78
|
-
*/
|
|
79
|
-
const formatter = format.combine(
|
|
80
|
-
/** Adds color to the format */
|
|
81
|
-
format.colorize(),
|
|
82
|
-
|
|
83
|
-
/** Adds timestamp to the format */
|
|
84
|
-
format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
|
|
85
|
-
|
|
86
|
-
/** Format the way the log is output to the console */
|
|
87
|
-
format.printf((info: TransformableInfo) => {
|
|
88
|
-
const { timestamp, level, message, ...meta } = info;
|
|
89
|
-
const formattedMessage = formatLogMessage(message, Object.keys(meta).length > 0 ? meta : undefined);
|
|
90
|
-
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
91
|
-
return `${timestamp} [${level}]: ${formattedMessage}`;
|
|
92
|
-
}),
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* This is the format that will be used for all File logs
|
|
97
|
-
* The only difference is that we don't want to add color because it will mess up the log file
|
|
98
|
-
*/
|
|
99
|
-
const fileFormatter = format.combine(
|
|
100
|
-
/** Adds timestamp to the format */
|
|
101
|
-
format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
|
|
102
|
-
|
|
103
|
-
/** Format the way the log is output to the console */
|
|
104
|
-
format.printf((info: TransformableInfo) => {
|
|
105
|
-
const { timestamp, level, message, ...meta } = info;
|
|
106
|
-
const formattedMessage = formatLogMessage(message, Object.keys(meta).length > 0 ? meta : undefined);
|
|
107
|
-
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
108
|
-
return `${timestamp} [${level}]: ${formattedMessage}`;
|
|
109
|
-
}),
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
/** ======================================== Defineing Transports ============================================ */
|
|
113
|
-
const transporters: Transports = {
|
|
114
|
-
console: new transports.Console({
|
|
115
|
-
format: formatter,
|
|
116
|
-
}),
|
|
117
|
-
file: new transports.File({
|
|
118
|
-
filename: 'storage/logs/info.log',
|
|
119
|
-
format: fileFormatter,
|
|
120
|
-
}),
|
|
121
|
-
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Creates and configures the logger based on the current configuration
|
|
126
|
-
*/
|
|
127
|
-
const createConfiguredLogger = (): ReturnType<typeof createLogger> => {
|
|
128
|
-
const transportsToUse = [];
|
|
129
|
-
for (const transport of ['console', 'file']) {
|
|
130
|
-
switch (transport) {
|
|
131
|
-
case 'console':
|
|
132
|
-
transportsToUse.push(transporters.console);
|
|
133
|
-
break;
|
|
134
|
-
case 'file':
|
|
135
|
-
transportsToUse.push(transporters.file);
|
|
136
|
-
break;
|
|
137
|
-
default:
|
|
138
|
-
transportsToUse.push(transporters.console);
|
|
139
|
-
break;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return createLogger({
|
|
144
|
-
level: 'info',
|
|
145
|
-
transports: transportsToUse,
|
|
146
|
-
levels: logLevels,
|
|
147
|
-
});
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
// Create the logger with the configured settings
|
|
151
|
-
const log = createConfiguredLogger();
|
|
152
|
-
|
|
153
|
-
export default log;
|
|
154
|
-
export const networkLog = createLogger({
|
|
155
|
-
level: 'info',
|
|
156
|
-
transports: [
|
|
157
|
-
new transports.Console({
|
|
158
|
-
format: formatter,
|
|
159
|
-
}),
|
|
160
|
-
new transports.File({
|
|
161
|
-
filename: 'storage/logs/info.log',
|
|
162
|
-
format: fileFormatter,
|
|
163
|
-
}),
|
|
164
|
-
],
|
|
165
|
-
levels: logLevels,
|
|
166
|
-
});
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
services:
|
|
2
|
-
app:
|
|
3
|
-
user: bun
|
|
4
|
-
image: oven/bun:1.2.17
|
|
5
|
-
working_dir: /app/yinzerflow-local
|
|
6
|
-
volumes:
|
|
7
|
-
- .:/app/yinzerflow-local
|
|
8
|
-
- ../yinzerflow/lib:/app/yinzerflow/lib
|
|
9
|
-
ports:
|
|
10
|
-
- "3000:5000"
|
|
11
|
-
command: sh -c "bun install && tail -f /dev/null"
|
|
12
|
-
tty: true
|
|
13
|
-
stdin_open: true
|
|
14
|
-
networks:
|
|
15
|
-
- yinzerflow-network
|
|
16
|
-
|
|
17
|
-
benchmark:
|
|
18
|
-
image: williamyeh/wrk
|
|
19
|
-
restart: no
|
|
20
|
-
command: ["-t20", "-c400", "-d10s", "http://api:5000/status"]
|
|
21
|
-
depends_on:
|
|
22
|
-
- app
|
|
23
|
-
networks:
|
|
24
|
-
- yinzerflow-network
|
|
25
|
-
|
|
26
|
-
networks:
|
|
27
|
-
yinzerflow-network:
|
|
28
|
-
driver: bridge
|
package/example/package.json
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "yinzerflow-local",
|
|
3
|
-
"type": "module",
|
|
4
|
-
"scripts": {
|
|
5
|
-
"start": "bun --watch app/index.ts"
|
|
6
|
-
},
|
|
7
|
-
"dependencies": {
|
|
8
|
-
"logform": "^2.7.0",
|
|
9
|
-
"winston": "^3.17.0",
|
|
10
|
-
"yinzerflow": "file:../yinzerflow/lib"
|
|
11
|
-
},
|
|
12
|
-
"devDependencies": {
|
|
13
|
-
"bun-types": "1.2.17",
|
|
14
|
-
"typescript": "^5.8.2"
|
|
15
|
-
}
|
|
16
|
-
}
|
package/example/tsconfig.json
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"composite": true,
|
|
4
|
-
"target": "ESNext",
|
|
5
|
-
"useDefineForClassFields": true,
|
|
6
|
-
"module": "NodeNext",
|
|
7
|
-
"lib": ["ESNext"],
|
|
8
|
-
"skipLibCheck": true,
|
|
9
|
-
"types": ["bun-types"],
|
|
10
|
-
|
|
11
|
-
/* Bundler mode */
|
|
12
|
-
"moduleResolution": "NodeNext",
|
|
13
|
-
"moduleDetection": "force",
|
|
14
|
-
"allowImportingTsExtensions": true,
|
|
15
|
-
"resolveJsonModule": true,
|
|
16
|
-
"isolatedModules": true,
|
|
17
|
-
"noEmit": true,
|
|
18
|
-
"jsx": "preserve",
|
|
19
|
-
"alwaysStrict": true,
|
|
20
|
-
"declaration": true,
|
|
21
|
-
"outDir": "lib",
|
|
22
|
-
"declarationDir": "lib",
|
|
23
|
-
"verbatimModuleSyntax": true,
|
|
24
|
-
"baseUrl": ".",
|
|
25
|
-
"paths": {
|
|
26
|
-
"@app/*": ["./app/*"]
|
|
27
|
-
},
|
|
28
|
-
"sourceMap": false,
|
|
29
|
-
"removeComments": true,
|
|
30
|
-
"declarationMap": true,
|
|
31
|
-
|
|
32
|
-
/* Linting */
|
|
33
|
-
"strict": true,
|
|
34
|
-
"noUnusedLocals": true,
|
|
35
|
-
"noUnusedParameters": true,
|
|
36
|
-
"noFallthroughCasesInSwitch": true,
|
|
37
|
-
"allowSyntheticDefaultImports": true,
|
|
38
|
-
"allowJs": false,
|
|
39
|
-
"forceConsistentCasingInFileNames": true,
|
|
40
|
-
"noImplicitAny": true,
|
|
41
|
-
"noImplicitReturns": true,
|
|
42
|
-
"noImplicitThis": true,
|
|
43
|
-
"noImplicitOverride": true,
|
|
44
|
-
"strictFunctionTypes": true,
|
|
45
|
-
"strictNullChecks": true,
|
|
46
|
-
"strictPropertyInitialization": true,
|
|
47
|
-
"allowUnreachableCode": false,
|
|
48
|
-
"allowUnusedLabels": false,
|
|
49
|
-
"exactOptionalPropertyTypes": true,
|
|
50
|
-
"noUncheckedIndexedAccess": true,
|
|
51
|
-
"strictBindCallApply": true
|
|
52
|
-
},
|
|
53
|
-
"include": ["app/**/*"]
|
|
54
|
-
}
|