raiton 1.0.0-alpha.3 → 1.0.0-alpha.4

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 CHANGED
@@ -1,3 +1,21 @@
1
+ # [1.0.0-alpha.4](https://github.com/protorians/raiton/compare/v1.0.0-alpha.3...v1.0.0-alpha.4) (2026-02-17)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * remove emojis from README section titles for consistency ([8d604ee](https://github.com/protorians/raiton/commit/8d604eec0825bfdf172988ee9fe662076b7e46be))
7
+ * remove unused Fastify dependencies and deprecate parameter handling utilities ([282db2c](https://github.com/protorians/raiton/commit/282db2cb4baeb52b816e1444f9d618570a073443))
8
+ * update `.releaserc.json` to refine branch configurations and format `assets` array ([0f803c0](https://github.com/protorians/raiton/commit/0f803c08d03549bd28ef9e61fe9c6c121d2f781d))
9
+ * update keywords in `package.json` and reset version to `0.0.0` ([44f7c85](https://github.com/protorians/raiton/commit/44f7c858330fc5455260d66d05b78a5a33d388f8))
10
+
11
+
12
+ ### Features
13
+
14
+ * add `NODE_AUTH_TOKEN` to `publish.yml` for semantic-release environment setup ([44a561b](https://github.com/protorians/raiton/commit/44a561b60bc3f35ae59bb404c343ef56baab4d26))
15
+ * enable provenance support in `package.json` and `.releaserc.json` ([b5db171](https://github.com/protorians/raiton/commit/b5db171a84150aefc2978b37c5d3544b5769b160))
16
+ * make package public and fix `publish.yml` token variable ([0293ee6](https://github.com/protorians/raiton/commit/0293ee629e444be0d90823896ea57212743d357d))
17
+ * remove redundant comments from `publish.yml` workflow ([37ddce9](https://github.com/protorians/raiton/commit/37ddce94356dba8f2c2d5e87af7fc3ade4ca3cf5))
18
+
1
19
  # [1.0.0-alpha.3](https://github.com/protorians/raiton/compare/v1.0.0-alpha.2...v1.0.0-alpha.3) (2026-02-17)
2
20
 
3
21
 
package/README.md CHANGED
@@ -82,7 +82,7 @@ bun raiton build
82
82
  bun raiton start
83
83
  ```
84
84
 
85
- ## 🛠 Runtimes supportés
85
+ ## Runtimes supportés
86
86
 
87
87
  Raiton détecte automatiquement l'environnement d'exécution et adapte son serveur :
88
88
 
@@ -90,7 +90,7 @@ Raiton détecte automatiquement l'environnement d'exécution et adapte son serve
90
90
  - **Node.js** : Adaptateur pour serveurs HTTP Node.
91
91
  - **Web** : Compatible avec les environnements basés sur les standards Web (Fetch API).
92
92
 
93
- ## 📄 Licence
93
+ ## Licence
94
94
 
95
95
  Ce projet est sous licence MIT. Voir le fichier [LICENSE](LICENSE) pour plus de détails.
96
96
 
@@ -4803,7 +4803,7 @@ var {
4803
4803
  Help
4804
4804
  } = import__.default;
4805
4805
  // package.json
4806
- var version = "1.0.0-alpha.3";
4806
+ var version = "1.0.0-alpha.4";
4807
4807
 
4808
4808
  // source/bin/cli.ts
4809
4809
  var CLI = new Command;
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "raiton",
3
- "version": "1.0.0-alpha.3",
3
+ "version": "1.0.0-alpha.4",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Protorians Raiton Development Kit",
@@ -0,0 +1,109 @@
1
+ import type {ArtifactEntry, ArtifactInterface, ArtifactOptions} from "@/types/artifact";
2
+ import {RaitonDirectories} from "@/core/directories";
3
+ import {Raiton} from "@/core/raiton";
4
+ import path from "node:path";
5
+ import fs from "node:fs";
6
+ import {LBadge, Logger} from "@protorians/logger";
7
+ import {ArtifactFactory} from "@/sdk/artifacts";
8
+ import {Throwable} from "@/sdk/throwable";
9
+
10
+ export class Artifact implements ArtifactInterface {
11
+ public readonly directory: string;
12
+ public readonly file: string;
13
+ public readonly workdir: string;
14
+
15
+ protected _files: string[] = [];
16
+
17
+ constructor(
18
+ public readonly options: ArtifactOptions,
19
+ ) {
20
+ this.options.verbose = typeof options.verbose === "undefined" ? false : options.verbose;
21
+
22
+ if (!Raiton.thread.builder?.source)
23
+ throw new Throwable("Artifact need project source");
24
+
25
+ this.directory = RaitonDirectories.artifacts(Raiton.thread.builder?.workdir)
26
+ this.workdir = Raiton.thread.builder.source;
27
+ this.file = path.join(this.directory, `${this.options.artifact}.d.ts`);
28
+ }
29
+
30
+ get files(): string[] {
31
+ return this._files;
32
+ }
33
+
34
+ get extensions(): string[] {
35
+ return [
36
+ `${this.options.artifact}.ts`,
37
+ `${this.options.artifact}.js`,
38
+ `${this.options.artifact}.mjs`,
39
+ `${this.options.artifact}.cjs`,
40
+ ]
41
+ }
42
+
43
+ /**
44
+ * Finds all files with end 'artifact.EXT'
45
+ */
46
+ scan(): string[] {
47
+ this._files = [];
48
+
49
+ fs.readdirSync(this.workdir, {recursive: true})
50
+ .forEach(f => {
51
+ this._files = [
52
+ ...this._files,
53
+ ...this.extensions.filter(ext => f.toString().endsWith(ext))
54
+ ];
55
+ })
56
+ ;
57
+
58
+ return this._files;
59
+ }
60
+
61
+ generate(): boolean {
62
+ try {
63
+ let mappings = "";
64
+
65
+ for (const file of this._files) {
66
+ const filename = path.join(this.workdir, file);
67
+ const content = fs.readFileSync(filename, "utf-8");
68
+ const match = content.match(this.options.decorator?.syntax);
69
+
70
+ if (!match) continue;
71
+
72
+ let name = match[3] || match[1] || "";
73
+ if (!name) {
74
+ const classMatch = content.match(/export\s+default\s+class\s+([A-Za-z0-9_]+)/);
75
+ name = classMatch?.[1] || path.parse(filename).name;
76
+ }
77
+
78
+ mappings += ` ${name}: InstanceType<typeof import("@/${file}").default>;\n`;
79
+
80
+ if (this.options.verbose) Logger.info(LBadge.debug(name), `artifact detected`);
81
+
82
+ ArtifactFactory.add(
83
+ this.options.artifact, {
84
+ file,
85
+ dir: this.workdir,
86
+ relative: file,
87
+ absolute: filename
88
+ }
89
+ )
90
+ }
91
+
92
+ const content = `// AUTO-GENERATED FILE — DO NOT EDIT MANUALLY
93
+ declare global {
94
+ interface ${this.options.provider} {
95
+ ${mappings} }
96
+ }
97
+ export {};`;
98
+ fs.writeFileSync(this.file, content, "utf-8");
99
+ if (!ArtifactFactory.save(this.options.artifact))
100
+ throw new Throwable(`Failed to save artifacts for ${this.options.artifact}`);
101
+
102
+ return true;
103
+ } catch (e: any) {
104
+ Logger.error(`Failed to resolve artifacts for ${this.options.artifact}`, e.message ?? e);
105
+ }
106
+ return false;
107
+ }
108
+
109
+ }
@@ -0,0 +1,10 @@
1
+ import {RaitonConfig} from "@/core";
2
+
3
+ export class Artifacts {
4
+
5
+ public static async load(workdir: string) {
6
+ await RaitonConfig.sync(workdir);
7
+ return RaitonConfig.get('artifacts');
8
+ }
9
+
10
+ }
@@ -0,0 +1 @@
1
+ export * from "./artifact";
@@ -0,0 +1,3 @@
1
+ export function artifactRunner () {
2
+
3
+ }
@@ -0,0 +1,106 @@
1
+ import {HmrInterface, HMRMetadataInterface} from "@/types";
2
+ import {Logger} from "@protorians/logger";
3
+
4
+
5
+ export class Hmr implements HmrInterface {
6
+ protected files: Map<string, HMRMetadataInterface> = new Map();
7
+
8
+ set(file: string, filename: string, size: number = 0) {
9
+
10
+ if(!filename.endsWith('.js')) return this;
11
+
12
+ this.files.set(file, {
13
+ filename,
14
+ size,
15
+ version: 1,
16
+ timestamp: Date.now(),
17
+ });
18
+ return this;
19
+ }
20
+
21
+ clear(): this {
22
+ this.files.clear();
23
+ return this;
24
+ }
25
+
26
+ entries(): Record<string, HMRMetadataInterface> {
27
+ return Object.fromEntries(this.files.entries());
28
+ }
29
+
30
+ has(key: string): boolean {
31
+ return this.files.has(key);
32
+ }
33
+
34
+ async refresh(): Promise<this> {
35
+ await this.each(async (file, key) => await this.upsert(key, file.filename));
36
+ return this;
37
+ }
38
+
39
+ async load<T>(key: string): Promise<T | undefined> {
40
+ const file = this.files.get(key);
41
+ Logger.log('HMR', file)
42
+
43
+ const mod = file ? await import(`${file.filename}?t=${file.timestamp}&v=${file.version}`) : undefined;
44
+ return mod as T | undefined;
45
+ }
46
+
47
+ async reload<T>(key: string): Promise<T | undefined> {
48
+ const file = this.files.get(key);
49
+
50
+ if (!file) return undefined;
51
+
52
+ file.version++
53
+ file.timestamp = Date.now();
54
+ this.files.set(key, file);
55
+
56
+ return await import(`${file.filename}?t=${file.timestamp}&v=${file.version}`);
57
+ }
58
+
59
+ unset(key: string): this {
60
+ this.files.delete(key);
61
+ return this;
62
+ }
63
+
64
+ size(): number {
65
+ return this.files.size;
66
+ }
67
+
68
+ async each(callable: (value: HMRMetadataInterface, key: string, map: Map<string, HMRMetadataInterface>) => void | Promise<void>): Promise<this> {
69
+ await Promise.all([...this.files.entries()].map(async ([key, value]) => await callable(value, key, this.files)));
70
+ return this;
71
+ }
72
+
73
+ get(key: string): HMRMetadataInterface | undefined {
74
+ return this.files.get(key);
75
+ }
76
+
77
+ getEntries(): Array<[string, HMRMetadataInterface]> {
78
+ return [...this.files.entries()];
79
+ }
80
+
81
+ getKeys(): string[] {
82
+ return [...this.files.keys()];
83
+ }
84
+
85
+ getValues(): Array<HMRMetadataInterface> {
86
+ return [...this.files.values()];
87
+ }
88
+
89
+ async upsert<T>(key: string, filename: string, size: number = 0): Promise<T | undefined> {
90
+ let file: HMRMetadataInterface | undefined = this.files.get(key);
91
+
92
+ if (!file) {
93
+ this.set(key, filename);
94
+ file = this.files.get(key);
95
+ }
96
+
97
+ if (!file) return undefined;
98
+ if (file.size === size) return undefined;
99
+
100
+ file.version++;
101
+ file.timestamp = Date.now();
102
+ file.size = size;
103
+
104
+ return await this.set(key, filename, size).load(key);
105
+ }
106
+ }
@@ -0,0 +1,22 @@
1
+ import {METADATA_KEYS} from "@/sdk/constants";
2
+ import type {ContainerDefinitionInterface} from "@/types";
3
+ import {LifetimeEnum} from "@protorians/core";
4
+ import "reflect-metadata";
5
+
6
+ export function getContainerMetadata(target: any): ContainerDefinitionInterface {
7
+ let metadata = Reflect.getMetadata(METADATA_KEYS.CONTAINER, target);
8
+
9
+ if (!metadata) {
10
+ metadata = {
11
+ name: `${target.name}`,
12
+ construct: target,
13
+ parameters: [],
14
+ lifetime: LifetimeEnum.TRANSIENT,
15
+ instance: undefined,
16
+ scope: undefined,
17
+ } as ContainerDefinitionInterface;
18
+ Reflect.defineMetadata(METADATA_KEYS.CONTAINER, metadata, target);
19
+ }
20
+
21
+ return metadata;
22
+ }
@@ -0,0 +1,77 @@
1
+ // import {IPayload} from "@/types";
2
+ // import {SYSTEM_DECORATORS_KEYS} from "@/sdk/constants";
3
+ //
4
+ // /**
5
+ // * A decorator function that combines and assigns schema-related metadata
6
+ // * to a specific property in the target constructor using reflective metadata.
7
+ // *
8
+ // * @param {IPayload} payload - The schema-related payload to be merged and assigned as metadata.
9
+ // * @return {Function} A decorator function that applies the merged metadata to the property.
10
+ // */
11
+ // export function Schemeable(payload: IPayload): (target: any, propertyKey: (string | symbol)) => void {
12
+ // return (target: any, propertyKey: string | symbol,) => {
13
+ // const current: IPayload = {...(Reflect.getMetadata(SYSTEM_DECORATORS_KEYS.ROUTES_SCHEMES, target.constructor, propertyKey) || {}), ...payload};
14
+ // Reflect.defineMetadata(SYSTEM_DECORATORS_KEYS.ROUTES_SCHEMES, current, target.constructor, propertyKey);
15
+ // };
16
+ // }
17
+ //
18
+ //
19
+ // /**
20
+ // * Constructs a schematizable object for the provided payload body.
21
+ // *
22
+ // * @param {IPayload['body']} payload - The body of the payload to be schematized.
23
+ // * @return {object} Returns a schematized object containing the provided payload body.
24
+ // */
25
+ // export function BodySchemeable(payload: IPayload['body']): (target: any, propertyKey: (string | symbol)) => void {
26
+ // return Schemeable({
27
+ // body: payload
28
+ // });
29
+ // }
30
+ //
31
+ // /**
32
+ // * Transforms the provided headers payload into a schematizable format.
33
+ // *
34
+ // * @param {IPayload['headers']} payload - The headers payload to be processed and transformed.
35
+ // * @return {object} The transformed schematizable object containing the headers.
36
+ // */
37
+ // export function HeadersSchemeable(payload: IPayload['headers']): (target: any, propertyKey: (string | symbol)) => void {
38
+ // return Schemeable({
39
+ // headers: payload
40
+ // });
41
+ // }
42
+ //
43
+ // /**
44
+ // * Constructs a schematizable object using the given query string payload.
45
+ // *
46
+ // * @param {IPayload['querystring']} payload - The query string object to be included in the schematizable configuration.
47
+ // * @return {object} The resulting schematizable object containing the query string.
48
+ // */
49
+ // export function QuerySchemeable(payload: IPayload['querystring']): (target: any, propertyKey: (string | symbol)) => void {
50
+ // return Schemeable({
51
+ // querystring: payload
52
+ // });
53
+ // }
54
+ //
55
+ // /**
56
+ // * Creates a schematizable object using the provided parameters.
57
+ // *
58
+ // * @param {IPayload['params']} payload - The parameters to be used for creating the schematizable object.
59
+ // * @return {Object} The resulting schematizable object containing the specified parameters.
60
+ // */
61
+ // export function ParamsSchemeable(payload: IPayload['params']): (target: any, propertyKey: (string | symbol)) => void {
62
+ // return Schemeable({
63
+ // params: payload
64
+ // });
65
+ // }
66
+ //
67
+ // /**
68
+ // * Constructs a schematized response payload.
69
+ // *
70
+ // * @param {IPayload['response']} payload - The response payload to be schematized.
71
+ // * @return {object} The schematized response object.
72
+ // */
73
+ // export function ResponseSchemeable(payload: IPayload['response']): (target: any, propertyKey: (string | symbol)) => void {
74
+ // return Schemeable({
75
+ // response: payload
76
+ // });
77
+ // }
@@ -0,0 +1,25 @@
1
+ import {getControllerMetadata} from "@/core";
2
+ import {HttpMethod} from "@/sdk";
3
+ import {ControllerMeta} from "@/types";
4
+
5
+ function createRoutableMethod(method: HttpMethod) {
6
+ return (path = '') =>
7
+ (target: any, propertyKey: string) => {
8
+ const meta: ControllerMeta = getControllerMetadata(target)
9
+ meta.routes.push({
10
+ method,
11
+ path,
12
+ propertyKey,
13
+ params: meta.params[propertyKey] || []
14
+ })
15
+ }
16
+ }
17
+
18
+ export const Get = createRoutableMethod(HttpMethod.GET)
19
+ export const Post = createRoutableMethod(HttpMethod.POST)
20
+ export const Put = createRoutableMethod(HttpMethod.PUT)
21
+ export const Patch = createRoutableMethod(HttpMethod.PATCH)
22
+ export const Options = createRoutableMethod(HttpMethod.OPTIONS)
23
+ export const Trace = createRoutableMethod(HttpMethod.TRACE)
24
+ export const Delete = createRoutableMethod(HttpMethod.DELETE)
25
+ export const Head = createRoutableMethod(HttpMethod.HEAD)
@@ -0,0 +1,10 @@
1
+ export enum HttpMethod {
2
+ GET = 'GET',
3
+ POST = 'POST',
4
+ PUT = 'PUT',
5
+ DELETE = 'DELETE',
6
+ PATCH = 'PATCH',
7
+ OPTIONS = 'OPTIONS',
8
+ HEAD = 'HEAD',
9
+ TRACE = 'TRACE',
10
+ }
@@ -0,0 +1,5 @@
1
+ import * as fastifyCore from 'fastify'
2
+ import fastifyPlugin from 'fastify-plugin'
3
+
4
+ export const FastifyPlugin = fastifyPlugin;
5
+ export default {...fastifyCore};
@@ -0,0 +1,55 @@
1
+ import {IParseableEntries, IParseablePrimitiveEntry} from "../types/parseable";
2
+ import {stabilizeJson} from "./utilities";
3
+
4
+
5
+ export class Json<T extends IParseableEntries> {
6
+
7
+ public readonly stack: Map<keyof T, T[keyof T]> = new Map();
8
+
9
+ constructor(json: IParseablePrimitiveEntry<T>) {
10
+ this.records(stabilizeJson<T>(json));
11
+ }
12
+
13
+ records(data: T): this {
14
+ for (const [key, value] of Object.entries(data))
15
+ this.stack.set(key as keyof T, value as T[keyof T]);
16
+ return this;
17
+ }
18
+
19
+ get<K extends keyof T>(key: K): T[K] {
20
+ return this.stack.get(key) as T[K];
21
+ }
22
+
23
+ set<K extends keyof T>(key: K, value: T[K]): this {
24
+ this.stack.set(key, value);
25
+ return this;
26
+ }
27
+
28
+ remove<K extends keyof T>(key: K): this {
29
+ this.stack.delete(key);
30
+ return this;
31
+ }
32
+
33
+ clear(): this {
34
+ this.stack.clear();
35
+ return this;
36
+ }
37
+
38
+ render(): T {
39
+ return Object.fromEntries(this.stack) as any as T;
40
+ }
41
+
42
+ static stabilize<T>(json: string | T | null): T {
43
+ return stabilizeJson<T>(json);
44
+ }
45
+
46
+ static from<T extends IParseableEntries>(data: T): Json<T> {
47
+ const json = new Json<T>(null);
48
+ json.records(data);
49
+ return json;
50
+ }
51
+
52
+ static records<T extends IParseableEntries>(support: Json<T>, data: IParseablePrimitiveEntry<T>): Json<T> {
53
+ return support.records(this.stabilize(data));
54
+ }
55
+ }
@@ -0,0 +1,3 @@
1
+ export class RaitonRequest {
2
+
3
+ }
@@ -1,6 +1,6 @@
1
1
  import {HttpResponseInterface} from "@/types";
2
2
  import {HttpStatus} from "@/sdk/enums";
3
- import {ThrowableResponse} from "@/sdk/responses";
3
+ import {ThrowableResponse} from "@/sdk";
4
4
 
5
5
 
6
6
  export class HttpResponse {
@@ -0,0 +1,31 @@
1
+ import type {IHttpResponse, IParseableEntry} from "@/types";
2
+
3
+ export function httpResponse<T extends IParseableEntry>(
4
+ statusCode: number,
5
+ message?: string,
6
+ data?: T,
7
+ error?: any,
8
+ ): IHttpResponse<T> {
9
+ return {
10
+ statusCode,
11
+ message,
12
+ data,
13
+ error,
14
+ }
15
+ }
16
+
17
+ export function successResponse<T extends IParseableEntry>(
18
+ message?: string,
19
+ data?: T,
20
+ error?: any,
21
+ ): IHttpResponse<T> {
22
+ return httpResponse<T>(200, message, data, error);
23
+ }
24
+
25
+ export function errorResponse<T extends IParseableEntry>(
26
+ message?: string,
27
+ data?: T,
28
+ error?: any,
29
+ ): IHttpResponse<T> {
30
+ return httpResponse<T>(500, message, data, error);
31
+ }
@@ -0,0 +1,21 @@
1
+ import path from "node:path";
2
+ import * as fs from "node:fs";
3
+ import {FastifyInstance} from "fastify";
4
+ import {aliasPath} from "./utilities";
5
+
6
+
7
+ export async function registryRoutes(app: FastifyInstance) {
8
+ const dir = aliasPath('@/routes');
9
+ if (!dir || !fs.existsSync(dir)) return app;
10
+
11
+ const files = fs.readdirSync(dir);
12
+
13
+ for (const file of files) {
14
+ if (file.endsWith(".route.ts")) {
15
+ const route = await import(path.join(dir, file));
16
+ route.default(app);
17
+ }
18
+ }
19
+
20
+ return app;
21
+ }
@@ -0,0 +1,178 @@
1
+ import {TSchema, Static, TProperties, Type} from "@sinclair/typebox";
2
+ import {ISchemeConfig, ISchemeOptions, IScheme} from "@/types";
3
+
4
+
5
+ export * from "@sinclair/typebox"
6
+
7
+ export function scheme() {
8
+ return new Scheme({});
9
+ }
10
+
11
+
12
+ /**
13
+ * A utility type for casting and inferring a type based on the provided `Schematic` generic structure.
14
+ * It checks if the given type `T` extends from the `Schematic` type and applies the inference logic
15
+ * defined by the `Schematic.infer` function. If the condition is not met, the type resolves to `never`.
16
+ *
17
+ * @template T - The generic type to evaluate and potentially infer from the `Schematic` structure.
18
+ *
19
+ * If `T` is an instance of `Schematic` with defined type parameters, this utility resolves to the
20
+ * result returned by the `Schematic.infer` method applied to `T`. Otherwise, it will resolve to `never`.
21
+ */
22
+ export type SchematicCast<T> = T extends Scheme<any, any, any, any>
23
+ ? ReturnType<typeof Scheme.infer<T>>
24
+ : never;
25
+
26
+ /**
27
+ * Represents a schema configuration that can be used with type-safe operations
28
+ * and is compatible with fastify route options.
29
+ *
30
+ * @template TBody - Optional schema type for the request body.
31
+ * @template TParams - Optional schema type for the route parameters.
32
+ * @template TQuery - Optional schema type for the query string parameters.
33
+ * @template TResponse - Optional schema type for the response, where each status code can have its own schema.
34
+ */
35
+ export class Scheme<
36
+ TBody extends TSchema | undefined = undefined,
37
+ TParams extends TSchema | undefined = undefined,
38
+ TQuery extends TSchema | undefined = undefined,
39
+ TResponse extends Record<number, TSchema> | undefined = undefined
40
+ > implements IScheme<TBody, TParams, TQuery, TResponse> {
41
+ protected _$body?: TBody;
42
+ protected _$params?: TParams;
43
+ protected _$querystring?: TQuery;
44
+ protected _$response?: TResponse;
45
+
46
+ constructor(config: ISchemeConfig<TBody, TParams, TQuery, TResponse>) {
47
+ this._$body = config.body;
48
+ // this._$body = config.body;
49
+ this._$params = config.params;
50
+ this._$querystring = config.querystring;
51
+ this._$response = config.response;
52
+ }
53
+
54
+ /**
55
+ * Retrieves the current value of the $body property.
56
+ *
57
+ * @return {TBody | undefined} The value of the $body property, or undefined if it is not set.
58
+ */
59
+ get $body(): TBody | undefined {
60
+ return this._$body;
61
+ }
62
+
63
+ /**
64
+ * Adds or updates a key-value pair in the body object.
65
+ *
66
+ * @param {string} key - The key to set or update in the body object.
67
+ * @param {TProperties} value - The value to associate with the specified key.
68
+ * @return {this} The current instance with the updated body object.
69
+ */
70
+ body(key: string, value: TProperties): this {
71
+ this._$body = {...(this._$body || {}), [key]: value} as TBody;
72
+ return this;
73
+ }
74
+
75
+ /**
76
+ * Retrieves the current value of the `$params` property.
77
+ *
78
+ * @return {TParams | undefined} The value of `$params` if set, otherwise undefined.
79
+ */
80
+ get $params(): TParams | undefined {
81
+ return this._$params;
82
+ }
83
+
84
+ /**
85
+ * Adds or updates a parameter with the specified key and value.
86
+ *
87
+ * @param {string} key - The key associated with the parameter to set or update.
88
+ * @param {TProperties} value - The value to associate with the specified key.
89
+ * @return {this} The current instance with the updated parameters.
90
+ */
91
+ params(key: string, value: TProperties): this {
92
+ this._$params = {...(this._$params || {}), [key]: value} as TParams;
93
+ return this;
94
+ }
95
+
96
+ /**
97
+ * Retrieves the current query string.
98
+ *
99
+ * @return {TQuery | undefined} The query string object if available, otherwise undefined.
100
+ */
101
+ get $querystring(): TQuery | undefined {
102
+ return this._$querystring;
103
+ }
104
+
105
+ /**
106
+ * Updates the query string parameters by setting the specified key-value pair.
107
+ *
108
+ * @param {string} key - The key of the query string parameter to set or update.
109
+ * @param {TProperties} value - The value associated with the specified key.
110
+ * @return {this} The current instance of the class for method chaining.
111
+ */
112
+ querystring(key: string, value: TProperties): this {
113
+ this._$querystring = {...(this._$querystring || {}), [key]: value} as TQuery;
114
+ return this;
115
+ }
116
+
117
+ /**
118
+ * Retrieves the current response object.
119
+ *
120
+ * @return {TResponse | undefined} The response object if available; otherwise, undefined.
121
+ */
122
+ get $response(): TResponse | undefined {
123
+ return this._$response;
124
+ }
125
+
126
+ /**
127
+ * Adds or updates a response key-value pair in the internal response object.
128
+ *
129
+ * @param {number} key - The key to be added or updated in the response object.
130
+ * @param {TProperties} value - The value associated with the given key.
131
+ * @return {this} The current instance to allow method chaining.
132
+ */
133
+ response(key: number, value: TProperties): this {
134
+ this._$response = {...(this._$response || {}), [key]: value} as TResponse;
135
+ return this;
136
+ }
137
+
138
+ /**
139
+ * Generates a schema object for validating different parts of an HTTP request.
140
+ *
141
+ * @return {Object} An object containing the schema definitions for `body`, `params`, `querystring`, and `response`. Each property returns a corresponding schema object.
142
+ */
143
+ schema(): ISchemeOptions<TBody, TParams, TQuery, TResponse> {
144
+ const schema: ISchemeOptions<TBody, TParams, TQuery, TResponse> = {}
145
+
146
+ if (this._$body) schema.body = Type.Object(this._$body);
147
+ if (this._$params) schema.params = Type.Object(this._$params);
148
+ if (this._$querystring) schema.querystring = Type.Object(this._$querystring);
149
+ if (this._$response) schema.response = Type.Object(this._$response);
150
+
151
+ return schema;
152
+ }
153
+
154
+ /**
155
+ * Infers and extracts static types from a given schema object.
156
+ *
157
+ * @param {T extends Schematic<any, any, any, any>} schema - The schema to infer types from. This should extend the Schematic type.
158
+ * @return {Object} An object containing inferred types including:
159
+ * - Body: The static type of the request body if defined in the schema, otherwise undefined.
160
+ * - Params: The static type of the request parameters if defined in the schema, otherwise undefined.
161
+ * - Query: The static type of the query string if defined in the schema, otherwise undefined.
162
+ * - Reply: The response type mappings if defined in the schema, otherwise undefined.
163
+ */
164
+ static infer<T extends Scheme<any, any, any, any>>(schema: T) {
165
+ return {
166
+ Body: schema._$body ? ({} as Static<NonNullable<T["$body"]>>) : undefined,
167
+ Params: schema._$params
168
+ ? ({} as Static<NonNullable<T["$params"]>>)
169
+ : undefined,
170
+ Query: schema._$querystring
171
+ ? ({} as Static<NonNullable<T["$querystring"]>>)
172
+ : undefined,
173
+ Reply: schema._$response
174
+ ? schema._$response as ({ [K in keyof NonNullable<T["$response"]>]: Static<NonNullable<T["$response"]>[K]> })
175
+ : undefined,
176
+ };
177
+ }
178
+ }
@@ -0,0 +1,101 @@
1
+ import {LBadge, Logger} from "@protorians/logger";
2
+ import {EventBus, EventBusEnum} from "@protorians/events-bus";
3
+
4
+ /**
5
+ * Represents a throwable error that extends the built-in JavaScript Error class.
6
+ * The Throwable class provides utility methods for triggering different levels
7
+ * of error notifications, including error, warning, and critical errors.
8
+ *
9
+ * The class dispatches error notifications via the EventBus and optionally
10
+ * throws an exception or exits the application depending on the severity level
11
+ * or the provided parameters.
12
+ */
13
+ export class Throwable extends Error {
14
+ constructor(message: string, protected statusCode: number = 500, label?: string) {
15
+ super(message);
16
+ this.name = 'Throwable';
17
+ if (label) Logger.debug(LBadge.debug(label), message);
18
+ EventBus.dispatch(EventBusEnum.SERVER_THROW, {error: this})
19
+ }
20
+
21
+ /**
22
+ * Dispatches a system server error event and optionally throws an error.
23
+ *
24
+ * @param {string} message - The error message to be dispatched and potentially thrown.
25
+ * @param {boolean} [soft=true] - Determines whether the error should be thrown. If true, the error is only dispatched. If false, the error is dispatched and then thrown.
26
+ * @param statusCode
27
+ * @return {void} This method does not return a value.
28
+ */
29
+ static error(message: string, soft: boolean = true, statusCode: number = 500): void {
30
+ EventBus.dispatch(EventBusEnum.SERVER_ERROR, {message, soft})
31
+ if (!soft) throw new Throwable(message, statusCode, 'ERR');
32
+ }
33
+
34
+ /**
35
+ * Emits a system server warning event and optionally throws an error based on the severity of the warning.
36
+ *
37
+ * @param {string} message - The warning message to be dispatched and possibly thrown as an error.
38
+ * @param {boolean} [soft=true] - Determines whether the warning should be treated as non-critical (soft). If false, an error is thrown.
39
+ * @param statusCode
40
+ * @return {void} This method does not return a value.
41
+ */
42
+ static warning(message: string, soft: boolean = true, statusCode: number = 500): void {
43
+ EventBus.dispatch(EventBusEnum.SERVER_WARNING, {message, soft})
44
+ if (!soft) throw new Throwable(message, statusCode, 'WRN');
45
+ }
46
+
47
+ /**
48
+ * Triggers a critical system event, dispatching an alert message and terminating the process.
49
+ *
50
+ * @param {string} message - The critical error message to be dispatched with the event.
51
+ * @return {void} This method does not return a value as it terminates the process.
52
+ */
53
+ static critical(message: string): void {
54
+ Logger.debug(LBadge.debug('CRITICAL'), message);
55
+ EventBus.dispatch(EventBusEnum.SERVER_CRITICAL, {message})
56
+ process.exit(1);
57
+ }
58
+ }
59
+
60
+ /**
61
+ * A function that throws an error with a provided message and a specified error type.
62
+ *
63
+ * @param {string} message - The error message to be used when throwing the error.
64
+ * @param {boolean} [soft=true] - Determines whether the error is categorized as "soft".
65
+ * If true, it will be treated as a soft error. Defaults to true.
66
+ * @param statusCode
67
+ * @returns {void}
68
+ */
69
+ export const throwError = (message: string, soft: boolean = true, statusCode: number = 500): void => Throwable.error(message, soft, statusCode);
70
+
71
+ /**
72
+ * Function to throw an error with a specified message.
73
+ *
74
+ * @param {string} message - The error message to be used in the thrown error.
75
+ * @param statusCode
76
+ * @throws {Throwable} always throw an error with the provided message.
77
+ */
78
+ export const throwException = (message: string, statusCode: number = 500): void => throwError(message, false, statusCode);
79
+
80
+ /**
81
+ * Emits a warning with the specified message and behavior.
82
+ *
83
+ * @param {string} message - The warning message to be displayed.
84
+ * @param {boolean} [soft=true] - Indicates whether the warning should be soft (true)
85
+ * or treated as a harder warning (false). Defaults to true.
86
+ * @param statusCode
87
+ * @returns {void} This function does not return any value.
88
+ */
89
+ export const throwWarning = (message: string, soft: boolean = true, statusCode: number = 500): void =>
90
+ Throwable.warning(message, soft, statusCode);
91
+
92
+ /**
93
+ * A variable representing a function that throws a critical error.
94
+ *
95
+ * This function is used to trigger a critical error by providing a specific message.
96
+ * It encapsulates the logic for generating a throwable critical error through the `Throwable.critical` method.
97
+ *
98
+ * @param {string} message - The error message describing the critical error to be thrown.
99
+ * @returns {Throwable} The critical throwable generated with the provided message.
100
+ */
101
+ export const throwCritical = (message: string): void => Throwable.critical(message);
@@ -0,0 +1,62 @@
1
+ import path from "node:path";
2
+ import fs from "fs";
3
+ import {LBadge, Logger} from "@protorians/logger";
4
+ import {RaitonDirectories} from "@/core";
5
+ import {Raiton} from "@/core/raiton";
6
+ import {ArtifactFactory} from "@/sdk/artifacts";
7
+
8
+
9
+ export function generateArtifacts(
10
+ artifact: string,
11
+ interfaceName: string,
12
+ decoratorSyntax: RegExp,
13
+ verbose: boolean = false,
14
+ ) {
15
+ const artifacts = RaitonDirectories.artifacts(Raiton.thread.builder.workdir)
16
+ const dir = Raiton.thread.builder.source;
17
+ const outputFile = path.join(artifacts, `${artifact}.d.ts`);
18
+
19
+ if (!dir) return;
20
+
21
+ const files = fs.readdirSync(dir, {recursive: true})
22
+ .filter(f => [`.ts`, `.js`, `.mjs`, `.cjs`,].some(ext => f.toString().endsWith(ext)))
23
+ .map(f => f.toString())
24
+ ;
25
+
26
+ let mappings = "";
27
+ for (const file of files) {
28
+
29
+ const filename = path.join(dir, file);
30
+ const content = fs.readFileSync(filename, "utf-8");
31
+ const match = content.match(decoratorSyntax);
32
+
33
+ if (!match) continue;
34
+
35
+ let name = match[3] || match[1] || "";
36
+ if (!name) {
37
+ const classMatch = content.match(/export\s+default\s+class\s+([A-Za-z0-9_]+)/);
38
+ name = classMatch?.[1] || path.parse(filename).name;
39
+ }
40
+
41
+ mappings += ` ${name}: InstanceType<typeof import("@/${file}").default>;\n`;
42
+
43
+ if (verbose) Logger.info(LBadge.debug(name), `artifact detected`);
44
+ ArtifactFactory.add(artifact, {
45
+ file,
46
+ dir,
47
+ relative: file,
48
+ absolute: filename
49
+ })
50
+ }
51
+
52
+ const content = `// AUTO-GENERATED FILE — DO NOT EDIT MANUALLY
53
+ declare global {
54
+ interface ${interfaceName} {
55
+ ${mappings} }
56
+ }
57
+ export {};`;
58
+ fs.writeFileSync(outputFile, content, "utf-8");
59
+ if (!ArtifactFactory.save(artifact)) Logger.error(`Failed to save artifacts for ${artifact}`);
60
+ }
61
+
62
+
@@ -0,0 +1,8 @@
1
+ export function isControllerFile(filename: string) {
2
+ return [
3
+ filename.endsWith(".controller.ts"),
4
+ filename.endsWith(".controller.js"),
5
+ filename.endsWith(".controller.mjs"),
6
+ filename.endsWith(".controller.cjs"),
7
+ ].some(Boolean)
8
+ }
@@ -0,0 +1,61 @@
1
+ // import {Parametrable} from "@/sdk/enums";
2
+ // import {FastifyReply, FastifyRequest} from "fastify";
3
+ // import {RouteParametersMetadataInterface} from "@/types/parameters";
4
+ // // import {MultipartFile} from "@fastify/multipart";
5
+ //
6
+ // export async function parseParametersArguments(
7
+ // req: FastifyRequest,
8
+ // res: FastifyReply,
9
+ // metadata: RouteParametersMetadataInterface[]
10
+ // ): Promise<any[]> {
11
+ // const args: any[] = [];
12
+ // const files: AsyncIterableIterator<any> | any[] = ('files' in req && typeof req.files === 'function') ? req.files() : [];
13
+ //
14
+ // for (const param of metadata) {
15
+ // switch (param.type) {
16
+ // // case Parametrable.APP:
17
+ // // args[param.index] = req.server as any;
18
+ // // break;
19
+ // case Parametrable.PARAM:
20
+ // args[param.index] = param.key ? (req.params as any)[param.key] : req.params;
21
+ // break;
22
+ // case Parametrable.BODY:
23
+ // args[param.index] = param.key ? (req.body as any)[param.key] : req.body;
24
+ // break;
25
+ // case Parametrable.QUERY:
26
+ // args[param.index] = param.key ? (req.query as any)[param.key] : req.query;
27
+ // break;
28
+ // case Parametrable.HEADER:
29
+ // args[param.index] = req.headers[param.key.toLowerCase()] as any;
30
+ // break;
31
+ // case Parametrable.REQ:
32
+ // args[param.index] = req as any;
33
+ // break;
34
+ // case Parametrable.REPLY:
35
+ // args[param.index] = res as any;
36
+ // break;
37
+ // case Parametrable.UPLOAD_FILE:
38
+ // let accumulate: any = param.multiple ? [] : null;
39
+ // for await (const part of files) {
40
+ // if (param.key === part.fieldname) {
41
+ // const packed = {
42
+ // filename: part.filename,
43
+ // mimetype: part.mimetype,
44
+ // encoding: part.encoding,
45
+ // toFile: () => part.file,
46
+ // toBuffer: async () => await part.toBuffer(),
47
+ // }
48
+ // accumulate = param.multiple ? [...accumulate, packed] : packed;
49
+ // }
50
+ // }
51
+ // args[param.index] = accumulate as any;
52
+ // break;
53
+ //
54
+ // case Parametrable.CUSTOM:
55
+ // args[param.index] = param.callable?.({request: req, reply: res, files}) ?? null;
56
+ // break;
57
+ // }
58
+ // }
59
+ //
60
+ // return args;
61
+ // }
@@ -0,0 +1,4 @@
1
+ import {type IDynamicProps} from "@protorians/parameters";
2
+
3
+
4
+ export type IDataTransferObject<T> = IDynamicProps<T>
@@ -0,0 +1,39 @@
1
+ export interface HMRMetadataInterface {
2
+ version: number;
3
+ timestamp: number;
4
+ filename: string;
5
+ size: number;
6
+ }
7
+
8
+ export interface HmrInterface {
9
+ entries(): Record<string, HMRMetadataInterface>;
10
+
11
+ set(key: string, filename: string, size: number): this;
12
+
13
+ get(key: string): HMRMetadataInterface | undefined;
14
+
15
+ getKeys(): string[];
16
+
17
+ getValues(): Array<HMRMetadataInterface>;
18
+
19
+ getEntries(): Array<[string, HMRMetadataInterface]>;
20
+
21
+ each(callable: (value: HMRMetadataInterface, key: string, map: Map<string, HMRMetadataInterface>) => void| Promise<void>): Promise<this>
22
+
23
+ unset(key: string): this;
24
+
25
+ clear(): this;
26
+
27
+ load<T>(key: string): Promise<T | undefined>;
28
+
29
+ reload<T>(key: string): Promise<T | undefined>;
30
+
31
+ has(key: string): boolean;
32
+
33
+ upsert<T>(key: string, filename: string, size: number): Promise<T | undefined>;
34
+
35
+ size(): number;
36
+
37
+ refresh(): Promise<this>;
38
+
39
+ }
@@ -0,0 +1,21 @@
1
+ import {Parametrable} from "@/sdk/enums/http-parameters.enum";
2
+ import {FastifyReply, FastifyRequest} from "fastify";
3
+ // import {MultipartFile} from "@fastify/multipart";
4
+
5
+
6
+ export interface RouteParametersMetadataPayload {
7
+ request: FastifyRequest;
8
+ reply: FastifyReply;
9
+ files: AsyncIterableIterator<any> | any[]
10
+ }
11
+
12
+ export type RouteParametersMetadataCallable = (payload: RouteParametersMetadataPayload) => any[];
13
+
14
+ export interface RouteParametersMetadataInterface {
15
+ index: number;
16
+ type: Parametrable;
17
+ key: string;
18
+ multiple: boolean;
19
+ optional: boolean;
20
+ callable?: RouteParametersMetadataCallable;
21
+ }
@@ -0,0 +1,5 @@
1
+ import {FastifySchema} from "fastify/types/schema";
2
+
3
+
4
+ export interface IPayload extends FastifySchema{
5
+ }
Binary file