@scarletgeek/web-kernel 1.0.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/LICENSE +21 -0
- package/babel.config.js +3 -0
- package/dist/BootHandler.d.ts +0 -0
- package/dist/KernelEvents.d.ts +9 -0
- package/dist/ProgramHandler.d.ts +14 -0
- package/dist/RequestHandler.d.ts +7 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +1 -0
- package/dist/kernel.d.ts +24 -0
- package/dist/mix-manifest.json +3 -0
- package/dist/request/DataTransformer.d.ts +5 -0
- package/dist/request/Request.d.ts +16 -0
- package/dist/request/adapters.d.ts +2 -0
- package/dist/request/interfaces.d.ts +18 -0
- package/dist/types/IKernel.d.ts +27 -0
- package/dist/utils.d.ts +6 -0
- package/example/index.html +739 -0
- package/example/programs/myprogram.js +9 -0
- package/example/programs/register.js +7 -0
- package/example/requests/getposts.js +23 -0
- package/example/requests/register.js +7 -0
- package/example/script.js +50 -0
- package/mix-manifest.json +3 -0
- package/package.json +43 -0
- package/readme.md +221 -0
- package/src/BootHandler.ts +0 -0
- package/src/KernelEvents.ts +42 -0
- package/src/ProgramHandler.ts +106 -0
- package/src/RequestHandler.ts +31 -0
- package/src/index.ts +10 -0
- package/src/kernel.ts +94 -0
- package/src/request/DataTransformer.ts +19 -0
- package/src/request/Request.ts +70 -0
- package/src/request/adapters.ts +10 -0
- package/src/request/interfaces.ts +21 -0
- package/src/types/IKernel.ts +35 -0
- package/src/utils.ts +15 -0
- package/tsconfig.json +13 -0
- package/webpack.mix.js +14 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Request } from "/dist/index.js";
|
|
2
|
+
|
|
3
|
+
export default class GetPosts extends Request {
|
|
4
|
+
get url() {
|
|
5
|
+
return "https://jsonplaceholder.typicode.com/posts";
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
get method() {
|
|
9
|
+
return "GET";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
onProcessing() {
|
|
13
|
+
console.log("Get posts is processing");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
onSuccess(response) {
|
|
17
|
+
console.log("Get posts is success :: ", response);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
onError(error) {
|
|
21
|
+
console.error("Get Posts is error :: ", error);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { registerPrograms } from "./programs/register.js";
|
|
2
|
+
import { registerRequests } from "./requests/register.js";
|
|
3
|
+
import { Kernel } from "/dist/index.js";
|
|
4
|
+
|
|
5
|
+
// Initiate kernel
|
|
6
|
+
window.kernel = new Kernel();
|
|
7
|
+
|
|
8
|
+
// Programs
|
|
9
|
+
registerPrograms(window.kernel);
|
|
10
|
+
|
|
11
|
+
window.kernel.onBoot((k) => {
|
|
12
|
+
k.start("my-program", {
|
|
13
|
+
message: "Kernel is booted.",
|
|
14
|
+
});
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
// window.kernel.start("my-program", {
|
|
18
|
+
// message: "Message is registered."
|
|
19
|
+
// });
|
|
20
|
+
|
|
21
|
+
document.getElementById("link-button").addEventListener("click", () => window.kernel.destroy("my-program"));
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
// Events
|
|
25
|
+
window.kernel.on("kernel:test", (e) => {
|
|
26
|
+
console.log("Kernel test event fired :: ", e.detail);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
document.getElementById("second-link-button").addEventListener("click", () => {
|
|
30
|
+
window.kernel.emit("kernel:test", {
|
|
31
|
+
name: "Naruto Uzumaki",
|
|
32
|
+
age: 18,
|
|
33
|
+
residence: "Konoha village"
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Requests
|
|
38
|
+
registerRequests(window.kernel);
|
|
39
|
+
|
|
40
|
+
document.getElementById("trail-button").addEventListener("click", () => {
|
|
41
|
+
window.kernel.send("getposts");
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
document.getElementById("metrics-button").addEventListener("click", () => {
|
|
45
|
+
window.kernel.metrics();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
document.addEventListener("DOMContentLoaded", () => {
|
|
49
|
+
window.kernel.boot();
|
|
50
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@scarletgeek/web-kernel",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A kernel for web to handle scripting",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"directories": {
|
|
8
|
+
"example": "example"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/thescarletgeek/web-kernel"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"dev": "npm run development",
|
|
16
|
+
"development": "mix",
|
|
17
|
+
"watch": "mix watch",
|
|
18
|
+
"watch-poll": "mix watch -- --watch-options-poll=1000",
|
|
19
|
+
"hot": "mix watch --hot",
|
|
20
|
+
"prod": "npm run production",
|
|
21
|
+
"production": "mix --production"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"kernel",
|
|
25
|
+
"web-kernel",
|
|
26
|
+
"opensource",
|
|
27
|
+
"webjs"
|
|
28
|
+
],
|
|
29
|
+
"author": "",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"laravel-mix": "^6.0.49",
|
|
33
|
+
"ts-loader": "^9.5.4",
|
|
34
|
+
"typescript": "^5.9.3"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://github.com/thescarletgeek/web-kernel",
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/thescarletgeek/web-kernel/issues"
|
|
39
|
+
},
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
42
|
+
}
|
|
43
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# Web Kernel
|
|
2
|
+
Web Kernel is an experimental runtime layer inspired by the core concepts of operating system kernels. While it is not a real kernel, it is designed to feel like one, focusing on structure, control and clarity without relying on shiny frameworks.
|
|
3
|
+
|
|
4
|
+
The idea originated while I am studying how OS kernels manage processes, states and system coordination.
|
|
5
|
+
|
|
6
|
+
As applications grow, scripting often becomes duplicated, tightly coupled, and hard to reason about. Web kernel explores whether a central control layer can manage programs, events and requests in a structured and predictable manner, while keeping the system minimal and extensible.
|
|
7
|
+
|
|
8
|
+
## Philosophy
|
|
9
|
+
- Structure programs, events, and requests without relying on frameworks.
|
|
10
|
+
- Enable scripting using Javascript/Typescript.
|
|
11
|
+
- Reduce duplication in execution and orchestration logic.
|
|
12
|
+
- Follow lifecycle-based design for programs and requests.
|
|
13
|
+
|
|
14
|
+
## What web kernel is (and isn't)
|
|
15
|
+
### What it is
|
|
16
|
+
- A runtime coordination layer.
|
|
17
|
+
- A structured way to manage programs.
|
|
18
|
+
- A state-aware execution controller.
|
|
19
|
+
- A foundation for custom architecture.
|
|
20
|
+
|
|
21
|
+
### What it is not
|
|
22
|
+
- A web framework.
|
|
23
|
+
- A replacement for React, Vue, Express, etc.
|
|
24
|
+
- A dependency-heavy abstraction layer.
|
|
25
|
+
- A magic solution for bad architecture.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
## Quickstart
|
|
29
|
+
To install web kernel, either install through npm or directly incldue the script.
|
|
30
|
+
|
|
31
|
+
Install through **npm** :
|
|
32
|
+
```
|
|
33
|
+
npm install @scarletgeek/web-kernel
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
To initialize the kernel :
|
|
37
|
+
|
|
38
|
+
```js
|
|
39
|
+
import { Kernel } from "@scarletgeek/web-kernel";
|
|
40
|
+
|
|
41
|
+
// Initialize the kernel
|
|
42
|
+
window.kernel = new Kernel();
|
|
43
|
+
|
|
44
|
+
// Run programs on boot
|
|
45
|
+
window.kernel.onBoot((k) => {
|
|
46
|
+
k.start("program-name");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Run boot() method to boot the kernel
|
|
50
|
+
document.addEventListener("DOMContentLoaded", () => {
|
|
51
|
+
window.kernel.boot();
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
## Programs
|
|
57
|
+
Programs are first-class execution units, similar to processes in an OS.
|
|
58
|
+
|
|
59
|
+
**Each Program :**
|
|
60
|
+
- Has a defined lifecycle.
|
|
61
|
+
- Can be executed, tracked and observed.
|
|
62
|
+
- Exists independently of framework logic.
|
|
63
|
+
|
|
64
|
+
To create and initialize programs :
|
|
65
|
+
|
|
66
|
+
```js
|
|
67
|
+
export default class MyProgram {
|
|
68
|
+
onStart(args) {
|
|
69
|
+
console.log("My Program is started :: ", args);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
onDestroy() {
|
|
73
|
+
console.log("My Program is destroyed");
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
// Register programs by passing program object and a name.
|
|
80
|
+
window.kernel.registerPrograms({
|
|
81
|
+
"program-name": MyProgram
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Run programs from kernel :
|
|
86
|
+
|
|
87
|
+
```js
|
|
88
|
+
// Run program using kernel
|
|
89
|
+
// Arguments can be passed in start() method.
|
|
90
|
+
// Arguments are optional
|
|
91
|
+
window.kernel.start("program-name", {})
|
|
92
|
+
```
|
|
93
|
+
Run programs on kernel startup :
|
|
94
|
+
|
|
95
|
+
```js
|
|
96
|
+
// Run programs on startup using onBoot() method
|
|
97
|
+
window.kernel.onBoot((k) => {
|
|
98
|
+
k.start("program--name");
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Events
|
|
105
|
+
|
|
106
|
+
- Events represent signals within the system.
|
|
107
|
+
- Used to communicate between programs without tight coupling.
|
|
108
|
+
- Help reduce duplication in cross-program communication.
|
|
109
|
+
|
|
110
|
+
Fire events from kernel :
|
|
111
|
+
```js
|
|
112
|
+
// Fire events using kernel
|
|
113
|
+
window.kernel.emit("kernel:test", {
|
|
114
|
+
name: "Naruto Uzumaki",
|
|
115
|
+
age: 18,
|
|
116
|
+
residence: "Konoha village"
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
To listen to events from kernel :
|
|
121
|
+
```js
|
|
122
|
+
// Add event listener
|
|
123
|
+
const listener = window.kernel.on("kernel:test", (e) => {
|
|
124
|
+
console.log("Kernel test event fired :: ", e.detail);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Remove the defined listener
|
|
128
|
+
listener();
|
|
129
|
+
|
|
130
|
+
// To listen to event only once
|
|
131
|
+
window.kernel.once("kernel:test", (e) => {
|
|
132
|
+
console.log("Kernel test event fired :: ", e.detail);
|
|
133
|
+
});
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Request
|
|
139
|
+
Requests can be used for API calls.
|
|
140
|
+
|
|
141
|
+
**Request Types** :
|
|
142
|
+
|
|
143
|
+
- GET
|
|
144
|
+
- POST
|
|
145
|
+
- PUT
|
|
146
|
+
- PATCH
|
|
147
|
+
- DELETE
|
|
148
|
+
|
|
149
|
+
Create Request :
|
|
150
|
+
|
|
151
|
+
```js
|
|
152
|
+
import { Request } from "/dist/index.js";
|
|
153
|
+
|
|
154
|
+
export default class GetPosts extends Request {
|
|
155
|
+
get url() {
|
|
156
|
+
return "https://jsonplaceholder.typicode.com/posts";
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
get method() {
|
|
160
|
+
return "GET";
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
get headers() {
|
|
164
|
+
// Headers can be defined here
|
|
165
|
+
return {}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
get payload() {
|
|
169
|
+
// Request payload can be defined here
|
|
170
|
+
return {}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
onProcessing() {
|
|
174
|
+
// Runs while request is running
|
|
175
|
+
console.log("Get posts is processing");
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
onSuccess(response) {
|
|
179
|
+
// When request is succeeded
|
|
180
|
+
console.log("Get posts is success :: ", response);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
onError(error) {
|
|
184
|
+
// When request is error
|
|
185
|
+
console.error("Get Posts is error :: ", error);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Register request on kernel :
|
|
192
|
+
|
|
193
|
+
```js
|
|
194
|
+
window.kernel.registerRequest({
|
|
195
|
+
"get-posts": GetPosts
|
|
196
|
+
});
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Run request using kernel :
|
|
200
|
+
|
|
201
|
+
```js
|
|
202
|
+
window.kernel.send("get-posts");
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## Contributing
|
|
208
|
+
|
|
209
|
+
Web kernel is an experimental project. Contributions are welcome for experimentation, improvements, and exploration of ideas.
|
|
210
|
+
|
|
211
|
+
1. Fork the repository
|
|
212
|
+
2. Create a new branch from **develop**.
|
|
213
|
+
3. Make your changes with clear, focused commits.
|
|
214
|
+
4. Ensure existing functionality is not broken.
|
|
215
|
+
5. Submit a pull request to the **develop** branch.
|
|
216
|
+
6. Describe what has changed and why.
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
## License
|
|
220
|
+
|
|
221
|
+
[MIT License](https://opensource.org/license/MIT)
|
|
File without changes
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { IEventMap, IEventHandler, IUnsubscribeEvent } from "./types/IKernel";
|
|
2
|
+
|
|
3
|
+
class KernelEvents extends EventTarget {
|
|
4
|
+
on<K extends keyof IEventMap>(
|
|
5
|
+
type: K,
|
|
6
|
+
handler: IEventHandler<IEventMap[K]>,
|
|
7
|
+
options?: AddEventListenerOptions
|
|
8
|
+
): IUnsubscribeEvent {
|
|
9
|
+
this.addEventListener(type, handler, options);
|
|
10
|
+
|
|
11
|
+
return () => this.off(type, handler);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
once<K extends keyof IEventMap>(
|
|
15
|
+
type: K,
|
|
16
|
+
handler: IEventHandler<IEventMap[K]>
|
|
17
|
+
) {
|
|
18
|
+
this.addEventListener(type, handler, {
|
|
19
|
+
once: true
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
off<K extends keyof IEventMap>(
|
|
24
|
+
type: K,
|
|
25
|
+
handler: IEventHandler<IEventMap[K]>
|
|
26
|
+
) {
|
|
27
|
+
this.removeEventListener(type, handler);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
emit<K extends keyof IEventMap>(
|
|
31
|
+
type: K,
|
|
32
|
+
detail: IEventMap[K] = {}
|
|
33
|
+
) {
|
|
34
|
+
return this.dispatchEvent(new CustomEvent(type, { detail }));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
destroy() {
|
|
38
|
+
// this.replaceWith?.(null);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default KernelEvents;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { ProgramState } from "./types/IKernel";
|
|
2
|
+
import { logger, LoggerLevel } from "./utils";
|
|
3
|
+
|
|
4
|
+
class ProgramHandler {
|
|
5
|
+
private programs = new Map();
|
|
6
|
+
private programState = new Map();
|
|
7
|
+
|
|
8
|
+
constructor() {
|
|
9
|
+
//
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
isProgramExists(key: string) {
|
|
13
|
+
return (this.programs.has(key) && this.programState.has(key));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
addProgram(key: string, program: any) {
|
|
17
|
+
if(this.programs.has(key)) {
|
|
18
|
+
logger(LoggerLevel.WARNING, `Program ${key} already exists.`);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
this.programs.set(key, new program());
|
|
23
|
+
this.programState.set(key, ProgramState.IDLE);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
startProgram(key: string, args: any = null) {
|
|
27
|
+
const program = this.programs.get(key);
|
|
28
|
+
if(!program) {
|
|
29
|
+
logger(LoggerLevel.WARNING, `Program ${key} not found.`);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const status = this.programState.get(key);
|
|
34
|
+
if(status === ProgramState.RUNNING) {
|
|
35
|
+
logger(LoggerLevel.WARNING, `Program ${key} is already running.`);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if(typeof program.onStart !== "function") {
|
|
40
|
+
logger(LoggerLevel.ERROR, `onStart method is not defined in the program ${key}.`);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
program.onStart(args);
|
|
46
|
+
this.programState.set(key, ProgramState.RUNNING);
|
|
47
|
+
} catch(error) {
|
|
48
|
+
this.programState.set(key, ProgramState.ERROR);
|
|
49
|
+
logger(LoggerLevel.ERROR, `Error occured in program ${key} - `, error);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
endProgram(key: string) {
|
|
54
|
+
const program = this.programs.get(key);
|
|
55
|
+
if(!program) {
|
|
56
|
+
logger(LoggerLevel.WARNING, `Program ${key} not found.`);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if(this.programState.get(key) !== ProgramState.RUNNING) {
|
|
61
|
+
logger(LoggerLevel.WARNING, `Program ${key} is not running.`);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if(typeof program.onDestroy !== "function") {
|
|
66
|
+
logger(LoggerLevel.ERROR, `onDestroy method is not defined in the program ${key}.`);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
program.onDestroy();
|
|
72
|
+
this.programState.set(key, ProgramState.STOPPED);
|
|
73
|
+
} catch(error) {
|
|
74
|
+
this.programState.set(key, ProgramState.ERROR);
|
|
75
|
+
logger(LoggerLevel.ERROR, `Error occured in program ${key} - `, error);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
getProgramsByState(programState: ProgramState) {
|
|
80
|
+
const status: any = {};
|
|
81
|
+
|
|
82
|
+
for(const [key, state] of this.programState) {
|
|
83
|
+
if(state === programState) {
|
|
84
|
+
status[key] = state;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return status;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
getAllProgramStatus() {
|
|
92
|
+
const status: any = {};
|
|
93
|
+
|
|
94
|
+
for(const [key, state] of this.programState) {
|
|
95
|
+
status[key] = state;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return status;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
getProgramStatus(key: string) {
|
|
102
|
+
return this.programs.get(key);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export default ProgramHandler;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { fetchAdapter } from "./request/adapters";
|
|
2
|
+
import Request from "./request/Request";
|
|
3
|
+
import { IKernelRequest } from "./types/IKernel";
|
|
4
|
+
import { logger, LoggerLevel } from "./utils";
|
|
5
|
+
|
|
6
|
+
class RequestHandler {
|
|
7
|
+
requests: IKernelRequest = {};
|
|
8
|
+
|
|
9
|
+
addRequest(key: string, RequestClass: any) {
|
|
10
|
+
const instance = new RequestClass(fetchAdapter);
|
|
11
|
+
if(!(instance instanceof Request)) {
|
|
12
|
+
throw new Error(`Invalid request "${key}". It must extend kernel Request class.`);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
this.requests[key] = instance;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
startRequest(key: string) {
|
|
19
|
+
if(!this.requests[key]) {
|
|
20
|
+
logger(LoggerLevel.WARNING, "Request not found.");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if(typeof this.requests[key].send !== "function") {
|
|
24
|
+
logger(LoggerLevel.ERROR, "Send method not available for the request.");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
this.requests[key].send();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default RequestHandler;
|
package/src/index.ts
ADDED
package/src/kernel.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import ProgramHandler from "./ProgramHandler";
|
|
2
|
+
import { IKernelProgram, IEventMap, IEventHandler, IUnsubscribeEvent, IKernelRequest, KernelState } from "./types/IKernel";
|
|
3
|
+
import KernelEvents from "./KernelEvents";
|
|
4
|
+
import RequestHandler from "./RequestHandler";
|
|
5
|
+
|
|
6
|
+
class Kernel {
|
|
7
|
+
programHandler;
|
|
8
|
+
eventHandler;
|
|
9
|
+
requestHandler;
|
|
10
|
+
state: KernelState;
|
|
11
|
+
bootHandlers: any[];
|
|
12
|
+
|
|
13
|
+
constructor() {
|
|
14
|
+
this.programHandler = new ProgramHandler();
|
|
15
|
+
this.eventHandler = new KernelEvents();
|
|
16
|
+
this.requestHandler = new RequestHandler();
|
|
17
|
+
this.state = KernelState.CREATED;
|
|
18
|
+
this.bootHandlers = [];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
onBoot(callback: any) {
|
|
22
|
+
if(this.state == KernelState.BOOTED) {
|
|
23
|
+
callback(this);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
this.bootHandlers.push(callback);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
boot() {
|
|
31
|
+
if(this.state !== KernelState.CREATED) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
this.state = KernelState.BOOTING;
|
|
36
|
+
|
|
37
|
+
for(const handler of this.bootHandlers) {
|
|
38
|
+
handler(this);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
this.bootHandlers.length = 0;
|
|
42
|
+
this.state = KernelState.BOOTED;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
registerPrograms(programs: IKernelProgram) {
|
|
46
|
+
if(Object.keys(programs).length) {
|
|
47
|
+
Object.keys(programs).forEach(key => {
|
|
48
|
+
this.programHandler.addProgram(key, programs[key]);
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
start(programName: string, args: any = null) {
|
|
54
|
+
this.programHandler.startProgram(programName, args);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
destroy(programName: string) {
|
|
58
|
+
this.programHandler.endProgram(programName);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
emit<K extends keyof IEventMap>(type: K, detail: IEventMap[K] = {}) {
|
|
62
|
+
this.eventHandler.emit(type, detail);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
on<K extends keyof IEventMap>(type: K, handler: IEventHandler<IEventMap[K]>, options?: AddEventListenerOptions) {
|
|
66
|
+
return this.eventHandler.on(type, handler, options);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
once<K extends keyof IEventMap>(type: K, handler: IEventHandler<IEventMap[K]>) {
|
|
70
|
+
this.eventHandler.once(type, handler);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
registerRequests(requests: IKernelRequest) {
|
|
74
|
+
if(Object.keys(requests).length) {
|
|
75
|
+
Object.keys(requests).forEach(key => {
|
|
76
|
+
this.requestHandler.addRequest(key, requests[key]);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
send(key: string) {
|
|
82
|
+
this.requestHandler.startRequest(key);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
status() {
|
|
86
|
+
const data: any = {};
|
|
87
|
+
|
|
88
|
+
data["programs"] = this.programHandler.getAllProgramStatus();
|
|
89
|
+
|
|
90
|
+
console.log(data);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export default Kernel;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ResponseTransformer } from "./interfaces";
|
|
2
|
+
|
|
3
|
+
class DataTransformer<T = Response> implements ResponseTransformer<T> {
|
|
4
|
+
async transform(response: Response): Promise<T> {
|
|
5
|
+
const contentType = response.headers.get("content-type") || "";
|
|
6
|
+
|
|
7
|
+
if(contentType.includes("application/json")) {
|
|
8
|
+
return await response.json();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if(contentType.includes("text/")) {
|
|
12
|
+
return await response.text() as unknown as T;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return await response.blob() as unknown as T;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default DataTransformer;
|