@kanjijs/core 0.2.0-beta.3 → 0.2.0-beta.30
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 +7 -2
- package/dist/context.d.ts +8 -0
- package/dist/contracts/src/index.d.ts +27 -0
- package/dist/core/src/context.d.ts +7 -0
- package/dist/core/src/decorators.d.ts +34 -0
- package/dist/core/src/di/container.d.ts +26 -0
- package/dist/core/src/di/module-compiler.d.ts +12 -0
- package/dist/core/src/exceptions/exception.filter.d.ts +3 -0
- package/dist/core/src/exceptions/http.exception.d.ts +7 -0
- package/dist/core/src/index.d.ts +9 -0
- package/dist/core/src/metadata.d.ts +64 -0
- package/dist/decorators.d.ts +36 -0
- package/dist/di/container.d.ts +31 -0
- package/dist/di/module-compiler.d.ts +11 -0
- package/dist/exceptions/exception.filter.d.ts +3 -0
- package/dist/exceptions/http.exception.d.ts +7 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +167 -108
- package/dist/metadata.d.ts +70 -0
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -14,8 +14,10 @@ It provides the decorators used to define APIs and the internal storage mechanis
|
|
|
14
14
|
- **`@Use(...middlewares)`**: Registers Hono-compatible middleware for a route or controller.
|
|
15
15
|
- **`@Module({ ... })`**: Defines a module with `imports`, `controllers`, and `providers`.
|
|
16
16
|
- **`@Inject(token)`**: Token-based dependency injection.
|
|
17
|
+
- **`@Body()`, `@Query()`, `@Param()`, `@Headers()`**: Parameter decorators for fine-grained metadata (used by platform adapters).
|
|
17
18
|
|
|
18
19
|
### Request Context (AsyncLocalStorage)
|
|
20
|
+
|
|
19
21
|
Kanjijs Core includes a built-in `kanjijsContext` (based on Node.js AsyncLocalStorage) to track request state globally without prop drilling. It enables access to `requestId` anywhere in the stack.
|
|
20
22
|
|
|
21
23
|
```typescript
|
|
@@ -24,8 +26,11 @@ const reqId = getRequestId();
|
|
|
24
26
|
```
|
|
25
27
|
|
|
26
28
|
### Dependency Injection
|
|
29
|
+
|
|
27
30
|
**KanjijsIoC**: A lightweight, platform-agnostic IoC container embedded in Core. It handles singleton resolution and dependency injection for your modules and controllers.
|
|
28
31
|
|
|
32
|
+
**Strict Mode Compatible**: The DI container now supports strict Token typing (`Token<T>`) and robustly handles `Function` vs `Constructor` type narrowing, ensuring compatibility with strict TypeScript configurations (`strict: true`).
|
|
33
|
+
|
|
29
34
|
### Metadata Storage
|
|
30
35
|
|
|
31
36
|
We use a `WeakMap`-based `MetadataStorage` singleton to keep the memory footprint minimal and ensure metadata is garbage collected if the controller class is no longer referenced.
|
|
@@ -39,8 +44,8 @@ const routes = MetadataStorage.getRoutes(ControllerClass.prototype);
|
|
|
39
44
|
|
|
40
45
|
Kanjijs Core defines the standard exceptions used across the framework.
|
|
41
46
|
|
|
42
|
-
-
|
|
43
|
-
-
|
|
47
|
+
- **`HttpException`**: Base class for HTTP errors.
|
|
48
|
+
- **`ExceptionFilter`**: Interface for implementing custom exception filters.
|
|
44
49
|
|
|
45
50
|
```typescript
|
|
46
51
|
import { HttpException } from "@kanjijs/core";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
export interface RequestContext {
|
|
3
|
+
requestId: string;
|
|
4
|
+
[key: string]// biome-ignore lint/suspicious/noExplicitAny: Suppressed
|
|
5
|
+
: any;
|
|
6
|
+
}
|
|
7
|
+
export declare const kanjijsContext: AsyncLocalStorage<RequestContext>;
|
|
8
|
+
export declare function getRequestId(): string | undefined;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type SchemaLike = unknown;
|
|
2
|
+
export interface ContractRequestSpec<T = SchemaLike> {
|
|
3
|
+
params?: T;
|
|
4
|
+
query?: T;
|
|
5
|
+
headers?: T;
|
|
6
|
+
cookies?: T;
|
|
7
|
+
body?: T;
|
|
8
|
+
}
|
|
9
|
+
export interface ContractResponseSpec<T = SchemaLike> {
|
|
10
|
+
[status: number]: T;
|
|
11
|
+
}
|
|
12
|
+
export interface ContractSpec<T = SchemaLike> {
|
|
13
|
+
request?: ContractRequestSpec<T>;
|
|
14
|
+
response?: ContractResponseSpec<T>;
|
|
15
|
+
}
|
|
16
|
+
export interface ValidatorAdapter<S = SchemaLike> {
|
|
17
|
+
parse<O = unknown>(schema: S, data: unknown): Promise<{
|
|
18
|
+
success: true;
|
|
19
|
+
data: O;
|
|
20
|
+
} | {
|
|
21
|
+
success: false;
|
|
22
|
+
issues: unknown[];
|
|
23
|
+
}>;
|
|
24
|
+
}
|
|
25
|
+
export declare class Contract {
|
|
26
|
+
static json<T = SchemaLike>(spec: ContractRequestSpec<T>): ContractSpec<T>;
|
|
27
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
export interface RequestContext {
|
|
3
|
+
requestId: string;
|
|
4
|
+
[key: string]: any;
|
|
5
|
+
}
|
|
6
|
+
export declare const kanjijsContext: AsyncLocalStorage<RequestContext>;
|
|
7
|
+
export declare function getRequestId(): string | undefined;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ContractSpec } from "@kanjijs/contracts";
|
|
2
|
+
import { type ModuleMetadata, type Token } from "./metadata";
|
|
3
|
+
/**
|
|
4
|
+
* @Module({ controllers: [...] })
|
|
5
|
+
*/
|
|
6
|
+
export declare function Module(metadata: ModuleMetadata): ClassDecorator;
|
|
7
|
+
/**
|
|
8
|
+
* @Contract({ ... })
|
|
9
|
+
*/
|
|
10
|
+
export declare function Contract(spec: ContractSpec): MethodDecorator;
|
|
11
|
+
/**
|
|
12
|
+
* @Controller('/users')
|
|
13
|
+
*/
|
|
14
|
+
export declare function Controller(prefix?: string): ClassDecorator;
|
|
15
|
+
export declare function Injectable(): ClassDecorator;
|
|
16
|
+
export declare const Get: (path?: string) => MethodDecorator;
|
|
17
|
+
export declare const Post: (path?: string) => MethodDecorator;
|
|
18
|
+
export declare const Put: (path?: string) => MethodDecorator;
|
|
19
|
+
export declare const Delete: (path?: string) => MethodDecorator;
|
|
20
|
+
export declare const Patch: (path?: string) => MethodDecorator;
|
|
21
|
+
/**
|
|
22
|
+
* @Inject("DATABASE_CLIENT")
|
|
23
|
+
*/
|
|
24
|
+
export declare function Inject(token: Token<unknown>): ParameterDecorator;
|
|
25
|
+
/**
|
|
26
|
+
* @Use(middleware1, middleware2)
|
|
27
|
+
* Attaches middlewares to a controller or method.
|
|
28
|
+
*/
|
|
29
|
+
export declare function Use(...middlewares: unknown[]): MethodDecorator & ClassDecorator;
|
|
30
|
+
export declare const Body: (data?: string) => ParameterDecorator;
|
|
31
|
+
export declare const Query: (data?: string) => ParameterDecorator;
|
|
32
|
+
export declare const Param: (data?: string) => ParameterDecorator;
|
|
33
|
+
export declare const Headers: (data?: string) => ParameterDecorator;
|
|
34
|
+
export declare const Ctx: (data?: string) => ParameterDecorator;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type Constructor, type Token } from "../metadata";
|
|
2
|
+
import "reflect-metadata";
|
|
3
|
+
export declare class KanjijsIoC {
|
|
4
|
+
private static providers;
|
|
5
|
+
static register<T>(target: Constructor<T>): void;
|
|
6
|
+
static register<T>(token: Token<T>, provider: {
|
|
7
|
+
useValue?: T;
|
|
8
|
+
useClass?: Constructor<T>;
|
|
9
|
+
}): void;
|
|
10
|
+
static resolve<T>(target: Token<T>): T;
|
|
11
|
+
static clear(): void;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* V2 STRICT CONTAINER
|
|
15
|
+
* Instance-based, no auto-registration, explicit visibility.
|
|
16
|
+
*/
|
|
17
|
+
export declare class Container {
|
|
18
|
+
private providers;
|
|
19
|
+
register<T>(token: Token<T>, provider: {
|
|
20
|
+
useValue?: T;
|
|
21
|
+
useClass?: Constructor<T>;
|
|
22
|
+
useFactory?: (...args: unknown[]) => T;
|
|
23
|
+
inject?: Array<Token<unknown>>;
|
|
24
|
+
}): void;
|
|
25
|
+
resolve<T>(token: Token<T>): T;
|
|
26
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type Constructor } from "../metadata";
|
|
2
|
+
import { Container } from "./container";
|
|
3
|
+
export declare class ModuleCompiler {
|
|
4
|
+
private nodes;
|
|
5
|
+
private globalExportedTokens;
|
|
6
|
+
compile(rootModule: Constructor): Container;
|
|
7
|
+
private scan;
|
|
8
|
+
private processProviders;
|
|
9
|
+
private validate;
|
|
10
|
+
private checkDependencies;
|
|
11
|
+
private registerProviders;
|
|
12
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type { ContractRequestSpec, ContractResponseSpec, ContractSpec, SchemaLike, ValidatorAdapter, } from "@kanjijs/contracts";
|
|
2
|
+
export * from "./context";
|
|
3
|
+
export * from "./decorators";
|
|
4
|
+
export * from "./di/container";
|
|
5
|
+
export * from "./di/module-compiler";
|
|
6
|
+
export * from "./exceptions/exception.filter";
|
|
7
|
+
export * from "./exceptions/http.exception";
|
|
8
|
+
export * from "./metadata";
|
|
9
|
+
export declare const GLOBAL_MIDDLEWARE_TOKEN: unique symbol;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { ContractSpec } from "@kanjijs/contracts";
|
|
2
|
+
import "reflect-metadata";
|
|
3
|
+
export type Constructor<T = unknown> = new (...args: unknown[]) => T;
|
|
4
|
+
export type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
|
|
5
|
+
export type RouteParamType = "BODY" | "QUERY" | "PARAM" | "HEADERS" | "CONTEXT";
|
|
6
|
+
export interface RouteParamMetadata {
|
|
7
|
+
index: number;
|
|
8
|
+
type: RouteParamType;
|
|
9
|
+
data?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface RouteMetadata {
|
|
12
|
+
method: HttpMethod;
|
|
13
|
+
path: string;
|
|
14
|
+
contract?: ContractSpec;
|
|
15
|
+
middlewares?: unknown[];
|
|
16
|
+
params?: RouteParamMetadata[];
|
|
17
|
+
}
|
|
18
|
+
export interface ControllerMetadata {
|
|
19
|
+
prefix: string;
|
|
20
|
+
middlewares?: unknown[];
|
|
21
|
+
}
|
|
22
|
+
export type Token<T = unknown> = string | symbol | Constructor<T>;
|
|
23
|
+
export type Provider<T = unknown> = Constructor<T> | {
|
|
24
|
+
provide: Token<T>;
|
|
25
|
+
useValue: T;
|
|
26
|
+
} | {
|
|
27
|
+
provide: Token<T>;
|
|
28
|
+
useClass: Constructor<T>;
|
|
29
|
+
} | {
|
|
30
|
+
provide: Token<T>;
|
|
31
|
+
useFactory: (...args: unknown[]) => T | Promise<T>;
|
|
32
|
+
inject?: Token[];
|
|
33
|
+
};
|
|
34
|
+
export interface DynamicModule {
|
|
35
|
+
module: Constructor;
|
|
36
|
+
providers?: Provider[];
|
|
37
|
+
imports?: Array<Constructor | DynamicModule>;
|
|
38
|
+
exports?: Token[];
|
|
39
|
+
global?: boolean;
|
|
40
|
+
}
|
|
41
|
+
export interface ModuleMetadata {
|
|
42
|
+
controllers?: Constructor[];
|
|
43
|
+
providers?: Provider[];
|
|
44
|
+
imports?: Array<Constructor | DynamicModule>;
|
|
45
|
+
exports?: Token[];
|
|
46
|
+
global?: boolean;
|
|
47
|
+
}
|
|
48
|
+
export interface IMetadataStorage {
|
|
49
|
+
addRoute(target: object, methodName: string, meta: RouteMetadata): void;
|
|
50
|
+
addContract(target: object, methodName: string, contract: ContractSpec): void;
|
|
51
|
+
addMiddleware(target: object, middleware: unknown, methodName?: string): void;
|
|
52
|
+
getRoutes(target: object): Map<string, RouteMetadata> | undefined;
|
|
53
|
+
setController(target: object, meta: ControllerMetadata): void;
|
|
54
|
+
getController(target: object): ControllerMetadata | undefined;
|
|
55
|
+
defineModule(target: object, meta: ModuleMetadata): void;
|
|
56
|
+
getModule(target: object): ModuleMetadata | undefined;
|
|
57
|
+
addInjection(target: object, index: number, token: Token<unknown>): void;
|
|
58
|
+
getInjections(target: object): Map<number, Token<unknown>> | undefined;
|
|
59
|
+
addRouteParam(target: object, methodName: string, param: RouteParamMetadata): void;
|
|
60
|
+
}
|
|
61
|
+
declare global {
|
|
62
|
+
var KANJI_METADATA_STORAGE: IMetadataStorage | undefined;
|
|
63
|
+
}
|
|
64
|
+
export declare const MetadataStorage: IMetadataStorage;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ContractSpec } from "@kanjijs/contracts";
|
|
2
|
+
import { type ModuleMetadata } from "./metadata";
|
|
3
|
+
/**
|
|
4
|
+
* @Module({ controllers: [...] })
|
|
5
|
+
*/
|
|
6
|
+
export declare function Module(metadata: ModuleMetadata): ClassDecorator;
|
|
7
|
+
/**
|
|
8
|
+
* @Contract({ ... })
|
|
9
|
+
*/
|
|
10
|
+
export declare function Contract(spec: ContractSpec): MethodDecorator;
|
|
11
|
+
/**
|
|
12
|
+
* @Controller('/users')
|
|
13
|
+
*/
|
|
14
|
+
export declare function Controller(prefix?: string): ClassDecorator;
|
|
15
|
+
export declare function Injectable(): ClassDecorator;
|
|
16
|
+
export declare const Get: (path?: string) => MethodDecorator;
|
|
17
|
+
export declare const Post: (path?: string) => MethodDecorator;
|
|
18
|
+
export declare const Put: (path?: string) => MethodDecorator;
|
|
19
|
+
export declare const Delete: (path?: string) => MethodDecorator;
|
|
20
|
+
export declare const Patch: (path?: string) => MethodDecorator;
|
|
21
|
+
/**
|
|
22
|
+
* @Inject("DATABASE_CLIENT")
|
|
23
|
+
*/
|
|
24
|
+
export declare function Inject(token// biome-ignore lint/suspicious/noExplicitAny: Suppressed
|
|
25
|
+
: any): ParameterDecorator;
|
|
26
|
+
/**
|
|
27
|
+
* @Use(middleware1, middleware2)
|
|
28
|
+
* Attaches middlewares to a controller or method.
|
|
29
|
+
*/
|
|
30
|
+
export declare function Use(...middlewares// biome-ignore lint/suspicious/noExplicitAny: Suppressed
|
|
31
|
+
: any[]): MethodDecorator & ClassDecorator;
|
|
32
|
+
export declare const Body: (data?: string) => ParameterDecorator;
|
|
33
|
+
export declare const Query: (data?: string) => ParameterDecorator;
|
|
34
|
+
export declare const Param: (data?: string) => ParameterDecorator;
|
|
35
|
+
export declare const Headers: (data?: string) => ParameterDecorator;
|
|
36
|
+
export declare const Ctx: (data?: string) => ParameterDecorator;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type Constructor } from "../metadata";
|
|
2
|
+
import "reflect-metadata";
|
|
3
|
+
export declare class KanjijsIoC {
|
|
4
|
+
private static providers;
|
|
5
|
+
static register<T>(target: Constructor<T>): void;
|
|
6
|
+
static register(token// biome-ignore lint/suspicious/noExplicitAny: Suppressed
|
|
7
|
+
: any, provider: {
|
|
8
|
+
useValue?// biome-ignore lint/suspicious/noExplicitAny: Suppressed
|
|
9
|
+
: any;
|
|
10
|
+
useClass?: Constructor;
|
|
11
|
+
}): void;
|
|
12
|
+
static resolve<T>(target: Constructor<T> | any): T;
|
|
13
|
+
static clear(): void;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* V2 STRICT CONTAINER
|
|
17
|
+
* Instance-based, no auto-registration, explicit visibility.
|
|
18
|
+
*/
|
|
19
|
+
export declare class Container {
|
|
20
|
+
private providers;
|
|
21
|
+
register(token// biome-ignore lint/suspicious/noExplicitAny: Suppressed
|
|
22
|
+
: any, provider: {
|
|
23
|
+
useValue?// biome-ignore lint/suspicious/noExplicitAny: Suppressed
|
|
24
|
+
: any;
|
|
25
|
+
useClass?: Constructor;
|
|
26
|
+
useFactory?: Function;
|
|
27
|
+
inject?// biome-ignore lint/suspicious/noExplicitAny: Suppressed
|
|
28
|
+
: any[];
|
|
29
|
+
}): void;
|
|
30
|
+
resolve<T>(token: Constructor<T> | any): T;
|
|
31
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type Constructor } from "../metadata";
|
|
2
|
+
import { Container } from "./container";
|
|
3
|
+
export declare class ModuleCompiler {
|
|
4
|
+
private nodes;
|
|
5
|
+
private globalExportedTokens;
|
|
6
|
+
compile(rootModule: Constructor): Container;
|
|
7
|
+
private scan;
|
|
8
|
+
private processProviders;
|
|
9
|
+
private validate;
|
|
10
|
+
private checkDependencies;
|
|
11
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from "./decorators";
|
|
2
|
+
export * from "./metadata";
|
|
3
|
+
export * from "./di/container";
|
|
4
|
+
export * from "./context";
|
|
5
|
+
export * from "./exceptions/http.exception";
|
|
6
|
+
export * from "./exceptions/exception.filter";
|
|
7
|
+
export * from "./di/module-compiler";
|
|
8
|
+
export * from "@kanjijs/contracts";
|
|
9
|
+
export declare const GLOBAL_MIDDLEWARE_TOKEN: unique symbol;
|
package/dist/index.js
CHANGED
|
@@ -1013,75 +1013,95 @@ var require_Reflect = __commonJS(() => {
|
|
|
1013
1013
|
})(Reflect2 || (Reflect2 = {}));
|
|
1014
1014
|
});
|
|
1015
1015
|
|
|
1016
|
+
// src/context.ts
|
|
1017
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
1018
|
+
var kanjijsContext = new AsyncLocalStorage;
|
|
1019
|
+
function getRequestId() {
|
|
1020
|
+
return kanjijsContext.getStore()?.requestId;
|
|
1021
|
+
}
|
|
1016
1022
|
// src/metadata.ts
|
|
1017
1023
|
var import_reflect_metadata = __toESM(require_Reflect(), 1);
|
|
1018
1024
|
var methodMetadataStore = new WeakMap;
|
|
1019
1025
|
var controllerMetadataStore = new WeakMap;
|
|
1020
1026
|
var moduleMetadataStore = new WeakMap;
|
|
1021
1027
|
var injectionMetadataStore = new WeakMap;
|
|
1022
|
-
var
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
methods = new Map;
|
|
1027
|
-
methodMetadataStore.set(target, methods);
|
|
1028
|
-
}
|
|
1029
|
-
const existing = methods.get(methodName) || {};
|
|
1030
|
-
methods.set(methodName, { ...existing, ...meta });
|
|
1031
|
-
},
|
|
1032
|
-
addContract(target, methodName, contract) {
|
|
1033
|
-
let methods = methodMetadataStore.get(target);
|
|
1034
|
-
if (!methods) {
|
|
1035
|
-
methods = new Map;
|
|
1036
|
-
methodMetadataStore.set(target, methods);
|
|
1037
|
-
}
|
|
1038
|
-
const existing = methods.get(methodName) || {};
|
|
1039
|
-
existing.contract = contract;
|
|
1040
|
-
methods.set(methodName, existing);
|
|
1041
|
-
},
|
|
1042
|
-
addMiddleware(target, middleware, methodName) {
|
|
1043
|
-
if (methodName) {
|
|
1028
|
+
var globalStore = globalThis;
|
|
1029
|
+
if (!globalStore.KANJI_METADATA_STORAGE) {
|
|
1030
|
+
globalStore.KANJI_METADATA_STORAGE = {
|
|
1031
|
+
addRoute(target, methodName, meta) {
|
|
1044
1032
|
let methods = methodMetadataStore.get(target);
|
|
1045
1033
|
if (!methods) {
|
|
1046
1034
|
methods = new Map;
|
|
1047
1035
|
methodMetadataStore.set(target, methods);
|
|
1048
1036
|
}
|
|
1049
1037
|
const existing = methods.get(methodName) || {};
|
|
1050
|
-
|
|
1038
|
+
methods.set(methodName, { ...existing, ...meta });
|
|
1039
|
+
},
|
|
1040
|
+
addContract(target, methodName, contract) {
|
|
1041
|
+
let methods = methodMetadataStore.get(target);
|
|
1042
|
+
if (!methods) {
|
|
1043
|
+
methods = new Map;
|
|
1044
|
+
methodMetadataStore.set(target, methods);
|
|
1045
|
+
}
|
|
1046
|
+
const existing = methods.get(methodName) || {};
|
|
1047
|
+
existing.contract = contract;
|
|
1051
1048
|
methods.set(methodName, existing);
|
|
1052
|
-
}
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1049
|
+
},
|
|
1050
|
+
addRouteParam(target, methodName, param) {
|
|
1051
|
+
let methods = methodMetadataStore.get(target);
|
|
1052
|
+
if (!methods) {
|
|
1053
|
+
methods = new Map;
|
|
1054
|
+
methodMetadataStore.set(target, methods);
|
|
1055
|
+
}
|
|
1056
|
+
const existing = methods.get(methodName) || {};
|
|
1057
|
+
existing.params = [...existing.params || [], param];
|
|
1058
|
+
methods.set(methodName, existing);
|
|
1059
|
+
},
|
|
1060
|
+
addMiddleware(target, middleware, methodName) {
|
|
1061
|
+
if (methodName) {
|
|
1062
|
+
let methods = methodMetadataStore.get(target);
|
|
1063
|
+
if (!methods) {
|
|
1064
|
+
methods = new Map;
|
|
1065
|
+
methodMetadataStore.set(target, methods);
|
|
1066
|
+
}
|
|
1067
|
+
const existing = methods.get(methodName) || {};
|
|
1068
|
+
existing.middlewares = [...existing.middlewares || [], middleware];
|
|
1069
|
+
methods.set(methodName, existing);
|
|
1070
|
+
} else {
|
|
1071
|
+
const existing = controllerMetadataStore.get(target) || { prefix: "/" };
|
|
1072
|
+
existing.middlewares = [...existing.middlewares || [], middleware];
|
|
1073
|
+
controllerMetadataStore.set(target, existing);
|
|
1074
|
+
}
|
|
1075
|
+
},
|
|
1076
|
+
getRoutes(target) {
|
|
1077
|
+
return methodMetadataStore.get(target);
|
|
1078
|
+
},
|
|
1079
|
+
setController(target, meta) {
|
|
1080
|
+
controllerMetadataStore.set(target, meta);
|
|
1081
|
+
},
|
|
1082
|
+
getController(target) {
|
|
1083
|
+
return controllerMetadataStore.get(target);
|
|
1084
|
+
},
|
|
1085
|
+
defineModule(target, meta) {
|
|
1086
|
+
moduleMetadataStore.set(target, meta);
|
|
1087
|
+
},
|
|
1088
|
+
getModule(target) {
|
|
1089
|
+
return moduleMetadataStore.get(target);
|
|
1090
|
+
},
|
|
1091
|
+
addInjection(target, index, token) {
|
|
1092
|
+
let injections = injectionMetadataStore.get(target);
|
|
1093
|
+
if (!injections) {
|
|
1094
|
+
injections = new Map;
|
|
1095
|
+
injectionMetadataStore.set(target, injections);
|
|
1096
|
+
}
|
|
1097
|
+
injections.set(index, token);
|
|
1098
|
+
},
|
|
1099
|
+
getInjections(target) {
|
|
1100
|
+
return injectionMetadataStore.get(target);
|
|
1078
1101
|
}
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
return injectionMetadataStore.get(target);
|
|
1083
|
-
}
|
|
1084
|
-
};
|
|
1102
|
+
};
|
|
1103
|
+
}
|
|
1104
|
+
var MetadataStorage = globalStore.KANJI_METADATA_STORAGE;
|
|
1085
1105
|
|
|
1086
1106
|
// src/decorators.ts
|
|
1087
1107
|
function Module(metadata) {
|
|
@@ -1100,7 +1120,7 @@ function Controller(prefix = "") {
|
|
|
1100
1120
|
};
|
|
1101
1121
|
}
|
|
1102
1122
|
function Injectable() {
|
|
1103
|
-
return (
|
|
1123
|
+
return (_target) => {};
|
|
1104
1124
|
}
|
|
1105
1125
|
function createMethodDecorator(method) {
|
|
1106
1126
|
return (path = "/") => {
|
|
@@ -1118,12 +1138,12 @@ var Put = createMethodDecorator("PUT");
|
|
|
1118
1138
|
var Delete = createMethodDecorator("DELETE");
|
|
1119
1139
|
var Patch = createMethodDecorator("PATCH");
|
|
1120
1140
|
function Inject(token) {
|
|
1121
|
-
return (target,
|
|
1141
|
+
return (target, _propertyKey, parameterIndex) => {
|
|
1122
1142
|
MetadataStorage.addInjection(target, parameterIndex, token);
|
|
1123
1143
|
};
|
|
1124
1144
|
}
|
|
1125
1145
|
function Use(...middlewares) {
|
|
1126
|
-
return (target, propertyKey,
|
|
1146
|
+
return (target, propertyKey, _descriptor) => {
|
|
1127
1147
|
if (propertyKey) {
|
|
1128
1148
|
for (const m of middlewares) {
|
|
1129
1149
|
MetadataStorage.addMiddleware(target, m, propertyKey);
|
|
@@ -1135,6 +1155,24 @@ function Use(...middlewares) {
|
|
|
1135
1155
|
}
|
|
1136
1156
|
};
|
|
1137
1157
|
}
|
|
1158
|
+
function createParamDecorator(type) {
|
|
1159
|
+
return (data) => {
|
|
1160
|
+
return (target, propertyKey, parameterIndex) => {
|
|
1161
|
+
if (propertyKey) {
|
|
1162
|
+
MetadataStorage.addRouteParam(target, propertyKey, {
|
|
1163
|
+
index: parameterIndex,
|
|
1164
|
+
type,
|
|
1165
|
+
data
|
|
1166
|
+
});
|
|
1167
|
+
}
|
|
1168
|
+
};
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
var Body = createParamDecorator("BODY");
|
|
1172
|
+
var Query = createParamDecorator("QUERY");
|
|
1173
|
+
var Param = createParamDecorator("PARAM");
|
|
1174
|
+
var Headers = createParamDecorator("HEADERS");
|
|
1175
|
+
var Ctx = createParamDecorator("CONTEXT");
|
|
1138
1176
|
// src/di/container.ts
|
|
1139
1177
|
var import_reflect_metadata2 = __toESM(require_Reflect(), 1);
|
|
1140
1178
|
|
|
@@ -1143,43 +1181,48 @@ class KanjijsIoC {
|
|
|
1143
1181
|
static register(tokenOrTarget, provider) {
|
|
1144
1182
|
if (provider) {
|
|
1145
1183
|
if ("useValue" in provider) {
|
|
1146
|
-
|
|
1184
|
+
KanjijsIoC.providers.set(tokenOrTarget, { useValue: provider.useValue });
|
|
1147
1185
|
} else if ("useClass" in provider) {
|
|
1148
|
-
|
|
1186
|
+
KanjijsIoC.providers.set(tokenOrTarget, { useClass: provider.useClass });
|
|
1149
1187
|
}
|
|
1150
1188
|
} else {
|
|
1151
|
-
|
|
1189
|
+
KanjijsIoC.providers.set(tokenOrTarget, {
|
|
1190
|
+
useClass: tokenOrTarget
|
|
1191
|
+
});
|
|
1152
1192
|
}
|
|
1153
1193
|
}
|
|
1154
1194
|
static resolve(target) {
|
|
1155
|
-
let provider =
|
|
1195
|
+
let provider = KanjijsIoC.providers.get(target);
|
|
1156
1196
|
if (!provider && typeof target === "function") {
|
|
1157
1197
|
provider = { useClass: target };
|
|
1158
|
-
|
|
1198
|
+
KanjijsIoC.providers.set(target, provider);
|
|
1159
1199
|
}
|
|
1160
1200
|
if (!provider) {
|
|
1161
|
-
|
|
1201
|
+
const targetName2 = typeof target === "function" ? target.name ?? "anonymous" : String(target);
|
|
1202
|
+
throw new Error(`Provider not found for token: ${targetName2}`);
|
|
1162
1203
|
}
|
|
1163
1204
|
if (provider.instance) {
|
|
1164
1205
|
return provider.instance;
|
|
1165
1206
|
}
|
|
1166
|
-
|
|
1207
|
+
const targetName = typeof target === "function" ? target.name ?? "anonymous" : String(target);
|
|
1208
|
+
console.log(`[DI] Creating NEW instance for ${targetName}`);
|
|
1167
1209
|
if (provider.useValue !== undefined) {
|
|
1168
1210
|
provider.instance = provider.useValue;
|
|
1169
1211
|
} else if (provider.useClass) {
|
|
1170
1212
|
const ConcreteClass = provider.useClass;
|
|
1171
1213
|
const paramTypes = Reflect.getMetadata("design:paramtypes", ConcreteClass) || [];
|
|
1172
1214
|
const injectionTokens = MetadataStorage.getInjections(ConcreteClass) || new Map;
|
|
1173
|
-
const injections = paramTypes.map((
|
|
1215
|
+
const injections = paramTypes.map((paramToken, index) => {
|
|
1174
1216
|
const overrideToken = injectionTokens.get(index);
|
|
1175
|
-
|
|
1217
|
+
const resolvedToken = overrideToken || paramToken;
|
|
1218
|
+
return KanjijsIoC.resolve(resolvedToken);
|
|
1176
1219
|
});
|
|
1177
1220
|
provider.instance = new ConcreteClass(...injections);
|
|
1178
1221
|
}
|
|
1179
1222
|
return provider.instance;
|
|
1180
1223
|
}
|
|
1181
1224
|
static clear() {
|
|
1182
|
-
|
|
1225
|
+
KanjijsIoC.providers.clear();
|
|
1183
1226
|
}
|
|
1184
1227
|
}
|
|
1185
1228
|
|
|
@@ -1191,7 +1234,8 @@ class Container {
|
|
|
1191
1234
|
resolve(token) {
|
|
1192
1235
|
const provider = this.providers.get(token);
|
|
1193
1236
|
if (!provider) {
|
|
1194
|
-
|
|
1237
|
+
const tokenName = typeof token === "function" ? token.name ?? "anonymous" : String(token);
|
|
1238
|
+
throw new Error(`[DI] Provider not found for token: ${tokenName}`);
|
|
1195
1239
|
}
|
|
1196
1240
|
if (provider.instance) {
|
|
1197
1241
|
return provider.instance;
|
|
@@ -1204,7 +1248,8 @@ class Container {
|
|
|
1204
1248
|
const injectionTokens = MetadataStorage.getInjections(ConcreteClass) || new Map;
|
|
1205
1249
|
const injections = paramTypes.map((paramToken, index) => {
|
|
1206
1250
|
const overrideToken = injectionTokens.get(index);
|
|
1207
|
-
|
|
1251
|
+
const resolvedToken = overrideToken || paramToken;
|
|
1252
|
+
return this.resolve(resolvedToken);
|
|
1208
1253
|
});
|
|
1209
1254
|
provider.instance = new ConcreteClass(...injections);
|
|
1210
1255
|
} else if (provider.useFactory) {
|
|
@@ -1214,29 +1259,6 @@ class Container {
|
|
|
1214
1259
|
return provider.instance;
|
|
1215
1260
|
}
|
|
1216
1261
|
}
|
|
1217
|
-
// src/context.ts
|
|
1218
|
-
import { AsyncLocalStorage } from "async_hooks";
|
|
1219
|
-
var kanjijsContext = new AsyncLocalStorage;
|
|
1220
|
-
function getRequestId() {
|
|
1221
|
-
return kanjijsContext.getStore()?.requestId;
|
|
1222
|
-
}
|
|
1223
|
-
// src/exceptions/http.exception.ts
|
|
1224
|
-
class HttpException extends Error {
|
|
1225
|
-
response;
|
|
1226
|
-
status;
|
|
1227
|
-
constructor(response, status) {
|
|
1228
|
-
super(typeof response === "string" ? response : JSON.stringify(response));
|
|
1229
|
-
this.response = response;
|
|
1230
|
-
this.status = status;
|
|
1231
|
-
this.name = "HttpException";
|
|
1232
|
-
}
|
|
1233
|
-
getResponse() {
|
|
1234
|
-
return this.response;
|
|
1235
|
-
}
|
|
1236
|
-
getStatus() {
|
|
1237
|
-
return this.status;
|
|
1238
|
-
}
|
|
1239
|
-
}
|
|
1240
1262
|
// src/di/module-compiler.ts
|
|
1241
1263
|
class ModuleCompiler {
|
|
1242
1264
|
nodes = new Map;
|
|
@@ -1245,11 +1267,11 @@ class ModuleCompiler {
|
|
|
1245
1267
|
this.scan(rootModule);
|
|
1246
1268
|
this.validate();
|
|
1247
1269
|
const container = new Container;
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
}
|
|
1270
|
+
const rootNode = this.nodes.get(rootModule);
|
|
1271
|
+
if (!rootNode) {
|
|
1272
|
+
return container;
|
|
1252
1273
|
}
|
|
1274
|
+
this.registerProviders(rootNode, container, new Set);
|
|
1253
1275
|
return container;
|
|
1254
1276
|
}
|
|
1255
1277
|
scan(target) {
|
|
@@ -1266,20 +1288,20 @@ class ModuleCompiler {
|
|
|
1266
1288
|
};
|
|
1267
1289
|
this.nodes.set(moduleClass, node);
|
|
1268
1290
|
const meta = MetadataStorage.getModule(moduleClass) || {};
|
|
1269
|
-
const dynamicMeta = "module" in target ? target :
|
|
1270
|
-
const allProviders = [...meta.providers || [], ...dynamicMeta
|
|
1291
|
+
const dynamicMeta = "module" in target ? target : undefined;
|
|
1292
|
+
const allProviders = [...meta.providers || [], ...dynamicMeta?.providers || []];
|
|
1271
1293
|
this.processProviders(node, allProviders);
|
|
1272
|
-
const allExports = [...meta.exports || [], ...dynamicMeta
|
|
1294
|
+
const allExports = [...meta.exports || [], ...dynamicMeta?.exports || []];
|
|
1273
1295
|
for (const token of allExports) {
|
|
1274
1296
|
node.exports.add(token);
|
|
1275
1297
|
}
|
|
1276
|
-
if (meta.global || dynamicMeta
|
|
1298
|
+
if (meta.global || dynamicMeta?.global) {
|
|
1277
1299
|
node.isGlobal = true;
|
|
1278
1300
|
for (const token of node.exports) {
|
|
1279
1301
|
this.globalExportedTokens.add(token);
|
|
1280
1302
|
}
|
|
1281
1303
|
}
|
|
1282
|
-
const allImports = [...meta.imports || [], ...dynamicMeta
|
|
1304
|
+
const allImports = [...meta.imports || [], ...dynamicMeta?.imports || []];
|
|
1283
1305
|
for (const imp of allImports) {
|
|
1284
1306
|
const importedNode = this.scan(imp);
|
|
1285
1307
|
node.imports.add(importedNode);
|
|
@@ -1318,7 +1340,7 @@ class ModuleCompiler {
|
|
|
1318
1340
|
for (const globalToken of this.globalExportedTokens) {
|
|
1319
1341
|
visibleTokens.add(globalToken);
|
|
1320
1342
|
}
|
|
1321
|
-
for (const [
|
|
1343
|
+
for (const [_token, provider] of node.providers) {
|
|
1322
1344
|
this.checkDependencies(provider, visibleTokens, node.module.name);
|
|
1323
1345
|
}
|
|
1324
1346
|
}
|
|
@@ -1331,18 +1353,50 @@ class ModuleCompiler {
|
|
|
1331
1353
|
targetName = clazz.name;
|
|
1332
1354
|
const paramTypes = Reflect.getMetadata("design:paramtypes", clazz) || [];
|
|
1333
1355
|
const injectionTokens = MetadataStorage.getInjections(clazz) || new Map;
|
|
1334
|
-
dependencies = paramTypes.map((
|
|
1335
|
-
|
|
1336
|
-
|
|
1356
|
+
dependencies = paramTypes.map((paramType, index) => {
|
|
1357
|
+
const overrideToken = injectionTokens.get(index);
|
|
1358
|
+
return overrideToken || paramType;
|
|
1359
|
+
});
|
|
1360
|
+
} else if ("useFactory" in provider) {
|
|
1361
|
+
targetName = typeof provider.provide === "function" ? provider.provide.name ?? "anonymous" : String(provider.provide);
|
|
1337
1362
|
dependencies = provider.inject || [];
|
|
1338
1363
|
}
|
|
1339
1364
|
for (const dep of dependencies) {
|
|
1340
1365
|
if (!visibleTokens.has(dep)) {
|
|
1341
|
-
const depName = dep
|
|
1366
|
+
const depName = typeof dep === "function" ? dep.name ?? "anonymous" : String(dep);
|
|
1342
1367
|
throw new Error(`[Kanjijs] strict-di-error: Provider '${targetName}' in Module '${moduleName}' ` + `depends on '${depName}', but it is not visible. ` + `Make sure it is imported and exported by the source module.`);
|
|
1343
1368
|
}
|
|
1344
1369
|
}
|
|
1345
1370
|
}
|
|
1371
|
+
registerProviders(node, container, visited) {
|
|
1372
|
+
if (visited.has(node))
|
|
1373
|
+
return;
|
|
1374
|
+
visited.add(node);
|
|
1375
|
+
for (const imp of node.imports) {
|
|
1376
|
+
this.registerProviders(imp, container, visited);
|
|
1377
|
+
}
|
|
1378
|
+
for (const [token, provider] of node.providers) {
|
|
1379
|
+
const { provide: _provide, ...definition } = provider;
|
|
1380
|
+
container.register(token, definition);
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
// src/exceptions/http.exception.ts
|
|
1385
|
+
class HttpException extends Error {
|
|
1386
|
+
response;
|
|
1387
|
+
status;
|
|
1388
|
+
constructor(response, status) {
|
|
1389
|
+
super(typeof response === "string" ? response : JSON.stringify(response));
|
|
1390
|
+
this.response = response;
|
|
1391
|
+
this.status = status;
|
|
1392
|
+
this.name = "HttpException";
|
|
1393
|
+
}
|
|
1394
|
+
getResponse() {
|
|
1395
|
+
return this.response;
|
|
1396
|
+
}
|
|
1397
|
+
getStatus() {
|
|
1398
|
+
return this.status;
|
|
1399
|
+
}
|
|
1346
1400
|
}
|
|
1347
1401
|
|
|
1348
1402
|
// src/index.ts
|
|
@@ -1351,9 +1405,11 @@ export {
|
|
|
1351
1405
|
kanjijsContext,
|
|
1352
1406
|
getRequestId,
|
|
1353
1407
|
Use,
|
|
1408
|
+
Query,
|
|
1354
1409
|
Put,
|
|
1355
1410
|
Post,
|
|
1356
1411
|
Patch,
|
|
1412
|
+
Param,
|
|
1357
1413
|
ModuleCompiler,
|
|
1358
1414
|
Module,
|
|
1359
1415
|
MetadataStorage,
|
|
@@ -1361,10 +1417,13 @@ export {
|
|
|
1361
1417
|
Injectable,
|
|
1362
1418
|
Inject,
|
|
1363
1419
|
HttpException,
|
|
1420
|
+
Headers,
|
|
1364
1421
|
Get,
|
|
1365
1422
|
GLOBAL_MIDDLEWARE_TOKEN,
|
|
1366
1423
|
Delete,
|
|
1424
|
+
Ctx,
|
|
1367
1425
|
Controller,
|
|
1368
1426
|
Contract,
|
|
1369
|
-
Container
|
|
1427
|
+
Container,
|
|
1428
|
+
Body
|
|
1370
1429
|
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { ContractSpec } from "@kanjijs/contracts";
|
|
2
|
+
import "reflect-metadata";
|
|
3
|
+
export type Constructor<T = any> = new (...args// biome-ignore lint/suspicious/noExplicitAny: Suppressed
|
|
4
|
+
: any[]) => T;
|
|
5
|
+
export type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
|
|
6
|
+
export type RouteParamType = "BODY" | "QUERY" | "PARAM" | "HEADERS" | "CONTEXT";
|
|
7
|
+
export interface RouteParamMetadata {
|
|
8
|
+
index: number;
|
|
9
|
+
type: RouteParamType;
|
|
10
|
+
data?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface RouteMetadata {
|
|
13
|
+
method: HttpMethod;
|
|
14
|
+
path: string;
|
|
15
|
+
contract?: ContractSpec;
|
|
16
|
+
middlewares?// biome-ignore lint/suspicious/noExplicitAny: Suppressed
|
|
17
|
+
: any[];
|
|
18
|
+
params?: RouteParamMetadata[];
|
|
19
|
+
}
|
|
20
|
+
export interface ControllerMetadata {
|
|
21
|
+
prefix: string;
|
|
22
|
+
middlewares?// biome-ignore lint/suspicious/noExplicitAny: Suppressed
|
|
23
|
+
: any[];
|
|
24
|
+
}
|
|
25
|
+
export type Token<T = any> = string | symbol | Constructor<T>;
|
|
26
|
+
export type Provider<T = any> = Constructor<T> | {
|
|
27
|
+
provide: Token<T>;
|
|
28
|
+
useValue: T;
|
|
29
|
+
} | {
|
|
30
|
+
provide: Token<T>;
|
|
31
|
+
useClass: Constructor<T>;
|
|
32
|
+
} | {
|
|
33
|
+
provide: Token<T>;
|
|
34
|
+
useFactory: (...args// biome-ignore lint/suspicious/noExplicitAny: Suppressed
|
|
35
|
+
: any[]) => T | Promise<T>;
|
|
36
|
+
inject?: Token[];
|
|
37
|
+
};
|
|
38
|
+
export interface DynamicModule {
|
|
39
|
+
module: Constructor;
|
|
40
|
+
providers?: Provider[];
|
|
41
|
+
imports?: Array<Constructor | DynamicModule>;
|
|
42
|
+
exports?: Token[];
|
|
43
|
+
global?: boolean;
|
|
44
|
+
}
|
|
45
|
+
export interface ModuleMetadata {
|
|
46
|
+
controllers?: Constructor[];
|
|
47
|
+
providers?: Provider[];
|
|
48
|
+
imports?: Array<Constructor | DynamicModule>;
|
|
49
|
+
exports?: Token[];
|
|
50
|
+
global?: boolean;
|
|
51
|
+
}
|
|
52
|
+
export interface IMetadataStorage {
|
|
53
|
+
addRoute(target: object, methodName: string, meta: RouteMetadata): void;
|
|
54
|
+
addContract(target: object, methodName: string, contract: ContractSpec): void;
|
|
55
|
+
addMiddleware(target: object, middleware// biome-ignore lint/suspicious/noExplicitAny: Suppressed
|
|
56
|
+
: any, methodName?: string): void;
|
|
57
|
+
getRoutes(target: object): Map<string, RouteMetadata> | undefined;
|
|
58
|
+
setController(target: object, meta: ControllerMetadata): void;
|
|
59
|
+
getController(target: object): ControllerMetadata | undefined;
|
|
60
|
+
defineModule(target: object, meta: ModuleMetadata): void;
|
|
61
|
+
getModule(target: object): ModuleMetadata | undefined;
|
|
62
|
+
addInjection(target: object, index: number, token// biome-ignore lint/suspicious/noExplicitAny: Suppressed
|
|
63
|
+
: any): void;
|
|
64
|
+
getInjections(target: object): Map<number, any> | undefined;
|
|
65
|
+
addRouteParam(target: object, methodName: string, param: RouteParamMetadata): void;
|
|
66
|
+
}
|
|
67
|
+
declare global {
|
|
68
|
+
var KANJI_METADATA_STORAGE: IMetadataStorage | undefined;
|
|
69
|
+
}
|
|
70
|
+
export declare const MetadataStorage: IMetadataStorage;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kanjijs/core",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.30",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -10,12 +10,12 @@
|
|
|
10
10
|
"LICENSE"
|
|
11
11
|
],
|
|
12
12
|
"scripts": {
|
|
13
|
-
"build": "bun build src/index.ts --outdir dist --target bun",
|
|
13
|
+
"build": "bun build src/index.ts --outdir dist --target bun && bunx tsc --emitDeclarationOnly --declaration --outDir dist",
|
|
14
14
|
"test": "bun test"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@kanjijs/common": "^0.2.0-beta.
|
|
18
|
-
"@kanjijs/contracts": "^0.2.0-beta.
|
|
17
|
+
"@kanjijs/common": "^0.2.0-beta.30",
|
|
18
|
+
"@kanjijs/contracts": "^0.2.0-beta.30",
|
|
19
19
|
"reflect-metadata": "^0.2.0"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|