@antelopejs/interface-core 0.0.6 → 0.0.8

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.
@@ -0,0 +1,169 @@
1
+ # Decorators
2
+
3
+ ## Overview
4
+
5
+ The `@antelopejs/interface-core/decorators` module provides factory functions for creating type-safe TypeScript decorators. These factories handle the boilerplate of splitting decorator arguments from factory arguments, producing reusable, parameterized decorators for classes, properties, methods, and parameters.
6
+
7
+ ## Import
8
+
9
+ ```ts
10
+ import {
11
+ MakeClassDecorator,
12
+ MakePropertyDecorator,
13
+ MakeMethodDecorator,
14
+ MakeParameterDecorator,
15
+ } from "@antelopejs/interface-core/decorators";
16
+ ```
17
+
18
+ ## Types
19
+
20
+ The module exports several utility types used throughout the decorator system:
21
+
22
+ | Type | Description |
23
+ | -------------------- | ------------------------------------------------------------ |
24
+ | `Func<A, R>` | Generic function type with arguments `A` and return type `R` |
25
+ | `Class<T, A>` | Class constructor that creates instances of type `T` |
26
+ | `ClassDecorator<C>` | Decorator applied to class constructors |
27
+ | `PropertyDecorator` | Decorator applied to class properties |
28
+ | `MethodDecorator` | Decorator applied to class methods and accessors |
29
+ | `ParameterDecorator` | Decorator applied to method parameters |
30
+
31
+ ## Single-target decorator factories
32
+
33
+ ### `MakeClassDecorator`
34
+
35
+ Creates a decorator factory that targets classes. The handler receives the decorated class as its first argument, followed by any factory parameters.
36
+
37
+ ```ts
38
+ import { MakeClassDecorator } from "@antelopejs/interface-core/decorators";
39
+
40
+ const Entity = MakeClassDecorator((target: Function, tableName: string) => {
41
+ Reflect.defineMetadata("table", tableName, target);
42
+ });
43
+
44
+ @Entity("users")
45
+ class User {
46
+ name!: string;
47
+ }
48
+ ```
49
+
50
+ ### `MakePropertyDecorator`
51
+
52
+ Creates a decorator factory that targets properties. The handler receives the target object and property key, followed by factory parameters.
53
+
54
+ ```ts
55
+ import { MakePropertyDecorator } from "@antelopejs/interface-core/decorators";
56
+
57
+ const Column = MakePropertyDecorator((target: any, key: PropertyKey, columnName: string) => {
58
+ const columns = Reflect.getOwnMetadata("columns", target) || [];
59
+ columns.push({ key, columnName });
60
+ Reflect.defineMetadata("columns", columns, target);
61
+ });
62
+
63
+ class User {
64
+ @Column("user_name")
65
+ name!: string;
66
+ }
67
+ ```
68
+
69
+ ### `MakeMethodDecorator`
70
+
71
+ Creates a decorator factory that targets methods and accessors. The handler receives the target object, method key, and property descriptor, followed by factory parameters.
72
+
73
+ ```ts
74
+ import { MakeMethodDecorator } from "@antelopejs/interface-core/decorators";
75
+
76
+ const Log = MakeMethodDecorator(
77
+ (target: any, key: PropertyKey, descriptor: PropertyDescriptor, level: string) => {
78
+ const original = descriptor.value;
79
+ descriptor.value = function (...args: any[]) {
80
+ console.log(`[${level}] Calling ${String(key)}`);
81
+ return original.apply(this, args);
82
+ };
83
+ },
84
+ );
85
+
86
+ class Service {
87
+ @Log("info")
88
+ process() {
89
+ // ...
90
+ }
91
+ }
92
+ ```
93
+
94
+ ### `MakeParameterDecorator`
95
+
96
+ Creates a decorator factory that targets method parameters. The handler receives the target object, method key, and parameter index, followed by factory parameters.
97
+
98
+ ```ts
99
+ import { MakeParameterDecorator } from "@antelopejs/interface-core/decorators";
100
+
101
+ const Inject = MakeParameterDecorator(
102
+ (target: any, key: PropertyKey, index: number, token: string) => {
103
+ const injections = Reflect.getOwnMetadata("injections", target, key) || [];
104
+ injections[index] = token;
105
+ Reflect.defineMetadata("injections", injections, target, key);
106
+ },
107
+ );
108
+
109
+ class Controller {
110
+ handle(@Inject("db") db: any) {
111
+ // ...
112
+ }
113
+ }
114
+ ```
115
+
116
+ ## Multi-target decorator factories
117
+
118
+ For decorators that apply to multiple targets, the module provides combined factory functions. These detect the decorator context automatically based on the number and types of arguments received.
119
+
120
+ | Factory | Targets |
121
+ | -------------------------------------------------- | ----------------------------------------- |
122
+ | `MakePropertyAndClassDecorator` | Properties and classes |
123
+ | `MakeMethodAndClassDecorator` | Methods and classes |
124
+ | `MakeMethodAndPropertyDecorator` | Methods and properties |
125
+ | `MakeMethodAndPropertyAndClassDecorator` | Methods, properties, and classes |
126
+ | `MakeParameterAndClassDecorator` | Parameters and classes |
127
+ | `MakeParameterAndPropertyDecorator` | Parameters and properties |
128
+ | `MakeParameterAndPropertyAndClassDecorator` | Parameters, properties, and classes |
129
+ | `MakeParameterAndMethodDecorator` | Parameters and methods |
130
+ | `MakeParameterAndMethodAndClassDecorator` | Parameters, methods, and classes |
131
+ | `MakeParameterAndMethodAndPropertyDecorator` | Parameters, methods, and properties |
132
+ | `MakeParameterAndMethodAndPropertyAndClassDecorator`| Parameters, methods, properties, classes |
133
+
134
+ ### Example: method and class decorator
135
+
136
+ ```ts
137
+ import { MakeMethodAndClassDecorator } from "@antelopejs/interface-core/decorators";
138
+
139
+ const Track = MakeMethodAndClassDecorator(
140
+ (target: any, key: PropertyKey | undefined, descriptor: PropertyDescriptor | undefined, category: string) => {
141
+ if (descriptor) {
142
+ // Applied to a method
143
+ const original = descriptor.value;
144
+ descriptor.value = function (...args: any[]) {
145
+ console.log(`[${category}] ${String(key)} called`);
146
+ return original.apply(this, args);
147
+ };
148
+ } else {
149
+ // Applied to a class
150
+ Reflect.defineMetadata("trackCategory", category, target);
151
+ }
152
+ },
153
+ );
154
+
155
+ @Track("api")
156
+ class ApiController {
157
+ @Track("endpoint")
158
+ getUsers() {
159
+ // ...
160
+ }
161
+ }
162
+ ```
163
+
164
+ When applied to a class, the `key` and `descriptor` arguments are `undefined`. When applied to a method, all three arguments are provided.
165
+
166
+ ## Next steps
167
+
168
+ - [Metadata](./4.metadata.md) - Reflection-based metadata with `GetMetadata`
169
+ - [Proxies](./2.proxies.md) - Module-aware proxy classes
@@ -0,0 +1,107 @@
1
+ # Metadata
2
+
3
+ ## Overview
4
+
5
+ The `GetMetadata` function provides a reflection-based metadata system built on top of the `reflect-metadata` library. It retrieves or creates metadata instances associated with target objects, supporting inheritance through the prototype chain.
6
+
7
+ ## Import
8
+
9
+ ```ts
10
+ import { GetMetadata } from "@antelopejs/interface-core";
11
+ ```
12
+
13
+ ## `GetMetadata`
14
+
15
+ ```ts
16
+ function GetMetadata<T, U>(target: U, meta: Class<T, [U]> & { key: symbol }, inherit?: boolean): T
17
+ ```
18
+
19
+ ### Parameters
20
+
21
+ | Parameter | Type | Default | Description |
22
+ | --------- | -------------------------------- | ------- | ---------------------------------------------------- |
23
+ | `target` | `U` | - | The object to retrieve or create metadata for |
24
+ | `meta` | `Class<T, [U]> & { key: symbol }` | - | A metadata class with a static `key` symbol |
25
+ | `inherit` | `boolean` | `true` | Whether to inherit metadata from the prototype chain |
26
+
27
+ ### Return value
28
+
29
+ Returns the metadata instance of type `T` associated with the target.
30
+
31
+ ## Define a metadata class
32
+
33
+ A metadata class must have a static `key` property (a `Symbol`) and accept the target object as a constructor argument.
34
+
35
+ ```ts
36
+ class RouteMetadata {
37
+ static key = Symbol("RouteMetadata");
38
+
39
+ public routes: Map<string, string> = new Map();
40
+
41
+ constructor(_target: any) {
42
+ // Initialize metadata for the target
43
+ }
44
+ }
45
+ ```
46
+
47
+ ## Retrieve metadata
48
+
49
+ ```ts
50
+ import { GetMetadata } from "@antelopejs/interface-core";
51
+
52
+ class UserController {
53
+ getUser() {}
54
+ listUsers() {}
55
+ }
56
+
57
+ const meta = GetMetadata(UserController.prototype, RouteMetadata);
58
+ meta.routes.set("getUser", "/users/:id");
59
+ meta.routes.set("listUsers", "/users");
60
+ ```
61
+
62
+ Calling `GetMetadata` multiple times with the same target and metadata class returns the same instance. The metadata is stored on the target using `Reflect.defineMetadata`.
63
+
64
+ ## Inheritance
65
+
66
+ When `inherit` is `true` (the default), `GetMetadata` walks the prototype chain to find parent metadata. If the metadata class defines an `inherit` method, that method is called with the parent metadata. Otherwise, properties from the parent are copied to the child metadata where they do not already exist.
67
+
68
+ ```ts
69
+ class ControllerMeta {
70
+ static key = Symbol("ControllerMeta");
71
+
72
+ public middleware: string[] = [];
73
+
74
+ constructor(_target: any) {}
75
+
76
+ inherit(parent: ControllerMeta) {
77
+ this.middleware = [...parent.middleware];
78
+ }
79
+ }
80
+
81
+ class BaseController {}
82
+ const baseMeta = GetMetadata(BaseController.prototype, ControllerMeta);
83
+ baseMeta.middleware.push("auth");
84
+
85
+ class AdminController extends BaseController {}
86
+ const adminMeta = GetMetadata(AdminController.prototype, ControllerMeta);
87
+ // adminMeta.middleware contains ["auth"] (inherited from BaseController)
88
+
89
+ adminMeta.middleware.push("adminOnly");
90
+ // adminMeta.middleware is now ["auth", "adminOnly"]
91
+ // baseMeta.middleware remains ["auth"]
92
+ ```
93
+
94
+ Without a custom `inherit` method, properties are shallow-copied from parent to child using `Object.getOwnPropertyNames`, but only for keys that do not already exist on the child metadata instance.
95
+
96
+ ## Disable inheritance
97
+
98
+ Pass `false` as the third argument to prevent prototype chain traversal:
99
+
100
+ ```ts
101
+ const meta = GetMetadata(target, RouteMetadata, false);
102
+ ```
103
+
104
+ ## Next steps
105
+
106
+ - [Decorators](./3.decorators.md) - Combine metadata with decorator factories
107
+ - [Modules](./5.modules.md) - Module lifecycle events and management
@@ -0,0 +1,180 @@
1
+ # Modules
2
+
3
+ ## Overview
4
+
5
+ The `@antelopejs/interface-core/modules` module provides lifecycle events and management functions for AntelopeJS modules. Modules transition through a defined lifecycle, and each transition emits an event that other modules can observe.
6
+
7
+ ## Import
8
+
9
+ ```ts
10
+ import {
11
+ Events,
12
+ ListModules,
13
+ GetModuleInfo,
14
+ LoadModule,
15
+ StartModule,
16
+ StopModule,
17
+ DestroyModule,
18
+ ReloadModule,
19
+ } from "@antelopejs/interface-core/modules";
20
+ ```
21
+
22
+ ## Module lifecycle
23
+
24
+ A module moves through these states:
25
+
26
+ ```
27
+ loaded -> constructed -> active -> constructed -> loaded
28
+ (stopped) (destroyed)
29
+ ```
30
+
31
+ | State | Description |
32
+ | ------------- | ------------------------------------------------------------ |
33
+ | `loaded` | Module code is loaded but no instance exists |
34
+ | `constructed` | Module instance is created but not started |
35
+ | `active` | Module is fully started and providing services |
36
+ | `unknown` | Module status cannot be determined |
37
+
38
+ ## Lifecycle events
39
+
40
+ The `Events` namespace exposes four `EventProxy` instances that fire during module lifecycle transitions.
41
+
42
+ ### `Events.ModuleConstructed`
43
+
44
+ Fires after a module instance is created, before the module is started.
45
+
46
+ ```ts
47
+ import { Events } from "@antelopejs/interface-core/modules";
48
+
49
+ Events.ModuleConstructed.register((moduleId: string) => {
50
+ console.log(`Module constructed: ${moduleId}`);
51
+ });
52
+ ```
53
+
54
+ ### `Events.ModuleStarted`
55
+
56
+ Fires after a module has been started and is fully operational.
57
+
58
+ ```ts
59
+ Events.ModuleStarted.register((moduleId: string) => {
60
+ console.log(`Module started: ${moduleId}`);
61
+ });
62
+ ```
63
+
64
+ ### `Events.ModuleStopped`
65
+
66
+ Fires after a module has been stopped. The module instance still exists but is no longer active.
67
+
68
+ ```ts
69
+ Events.ModuleStopped.register((moduleId: string) => {
70
+ console.log(`Module stopped: ${moduleId}`);
71
+ });
72
+ ```
73
+
74
+ ### `Events.ModuleDestroyed`
75
+
76
+ Fires after a module instance has been destroyed and all its resources have been released. The system uses this event internally to clean up proxy attachments and event handlers associated with the destroyed module.
77
+
78
+ ```ts
79
+ Events.ModuleDestroyed.register((moduleId: string) => {
80
+ console.log(`Module destroyed: ${moduleId}`);
81
+ });
82
+ ```
83
+
84
+ ## Management functions
85
+
86
+ These functions are declared as `InterfaceFunction` proxies. They are available once the core runtime provides their implementation.
87
+
88
+ ### `ListModules`
89
+
90
+ Returns the identifiers of all loaded modules.
91
+
92
+ ```ts
93
+ const modules = await ListModules();
94
+ // ["auth-module", "database-module", "api-module"]
95
+ ```
96
+
97
+ ### `GetModuleInfo`
98
+
99
+ Returns detailed information about a specific module, including its configuration, status, and file system path.
100
+
101
+ ```ts
102
+ import type { ModuleInfo } from "@antelopejs/interface-core/modules";
103
+
104
+ const info: ModuleInfo = await GetModuleInfo("auth-module");
105
+ // info.status -> "active"
106
+ // info.localPath -> "/path/to/auth-module"
107
+ // info.source -> { type: "package", ... }
108
+ ```
109
+
110
+ ### `LoadModule`
111
+
112
+ Loads a new module with the given configuration. Set `autostart` to `true` to automatically start the module after loading.
113
+
114
+ ```ts
115
+ import type { ModuleDefinition } from "@antelopejs/interface-core/modules";
116
+
117
+ const definition: ModuleDefinition = {
118
+ source: { type: "package", package: "@my/module", version: "1.0.0" },
119
+ config: { key: "value" },
120
+ };
121
+
122
+ await LoadModule("my-module", definition, true);
123
+ ```
124
+
125
+ ### `StartModule`
126
+
127
+ Starts a loaded but inactive module.
128
+
129
+ ```ts
130
+ await StartModule("my-module");
131
+ ```
132
+
133
+ ### `StopModule`
134
+
135
+ Stops an active module. The module instance remains but stops providing services.
136
+
137
+ ```ts
138
+ await StopModule("my-module");
139
+ ```
140
+
141
+ ### `DestroyModule`
142
+
143
+ Destroys a stopped module instance. The module code remains loaded.
144
+
145
+ ```ts
146
+ await DestroyModule("my-module");
147
+ ```
148
+
149
+ ### `ReloadModule`
150
+
151
+ Stops, destroys, unloads, and reloads a module from its source. This is useful for applying updates without restarting the application.
152
+
153
+ ```ts
154
+ await ReloadModule("my-module");
155
+ ```
156
+
157
+ ## `ModuleDefinition`
158
+
159
+ The configuration object for defining a module.
160
+
161
+ | Property | Type | Description |
162
+ | ------------------ | --------------------------------- | -------------------------------------------------- |
163
+ | `source` | `{ type: string } & Record<...>` | Source location and loading mechanism |
164
+ | `config` | `unknown` | Optional configuration data for the module |
165
+ | `importOverrides` | `Record<string, string[]>` | Optional mapping of import paths to alternatives |
166
+ | `disabledExports` | `string[]` | Optional list of exports to hide from this module |
167
+
168
+ ## `ModuleInfo`
169
+
170
+ Extends `ModuleDefinition` with runtime information.
171
+
172
+ | Property | Type | Description |
173
+ | ----------- | -------- | ---------------------------------------- |
174
+ | `status` | `string` | Current lifecycle state of the module |
175
+ | `localPath` | `string` | File system path where the module exists |
176
+
177
+ ## Next steps
178
+
179
+ - [Logging](./6.logging.md) - Structured logging with channels and levels
180
+ - [Configuration](./7.configuration.md) - Project configuration types
@@ -0,0 +1,106 @@
1
+ # Logging
2
+
3
+ ## Overview
4
+
5
+ The `@antelopejs/interface-core/logging` module provides a structured logging system with multiple severity levels and named channels. Log entries are emitted as events through an `EventProxy`, allowing any part of the application to listen for and process log output.
6
+
7
+ ## Import
8
+
9
+ ```ts
10
+ import { Logging } from "@antelopejs/interface-core/logging";
11
+ ```
12
+
13
+ ## Severity levels
14
+
15
+ The `Logging.Level` enum defines the available severity levels:
16
+
17
+ | Level | Value | Purpose |
18
+ | ----------- | ----- | -------------------------------------------- |
19
+ | `ERROR` | 40 | Critical errors that may cause failure |
20
+ | `WARN` | 30 | Issues that do not prevent operation |
21
+ | `INFO` | 20 | General status updates and information |
22
+ | `DEBUG` | 10 | Detailed information for debugging |
23
+ | `TRACE` | 0 | Highly detailed tracing information |
24
+ | `NO_PREFIX` | -1 | Messages displayed without a level prefix |
25
+
26
+ ## Log to the main channel
27
+
28
+ The `Logging` namespace exposes convenience functions that write to the `"main"` channel:
29
+
30
+ ```ts
31
+ import { Logging } from "@antelopejs/interface-core/logging";
32
+
33
+ Logging.Error("Database connection failed", error);
34
+ Logging.Warn("Cache miss for key:", cacheKey);
35
+ Logging.Info("Server started on port", port);
36
+ Logging.Debug("Request payload:", payload);
37
+ Logging.Trace("Entering function processItem");
38
+ ```
39
+
40
+ Each function accepts any number of arguments of any type.
41
+
42
+ ## Use named channels
43
+
44
+ For categorized logging, create a `Logging.Channel` instance with a channel name:
45
+
46
+ ```ts
47
+ import { Logging } from "@antelopejs/interface-core/logging";
48
+
49
+ const dbLog = new Logging.Channel("database");
50
+ const httpLog = new Logging.Channel("http");
51
+
52
+ dbLog.Info("Connected to", dbHost);
53
+ dbLog.Error("Query failed:", query, error);
54
+
55
+ httpLog.Info("GET /api/users", statusCode);
56
+ httpLog.Debug("Response headers:", headers);
57
+ ```
58
+
59
+ Channels provide the same methods as the main logging functions: `Error`, `Warn`, `Info`, `Debug`, and `Trace`.
60
+
61
+ ## Write at a custom level
62
+
63
+ Use the `Write` function for logs at a custom severity level:
64
+
65
+ ```ts
66
+ // Static function on the Logging namespace
67
+ Logging.Write(25, "custom-channel", "Custom level message");
68
+
69
+ // Instance method on a channel
70
+ const channel = new Logging.Channel("metrics");
71
+ channel.Write(15, "Custom level within the metrics channel");
72
+ ```
73
+
74
+ ## Log entry structure
75
+
76
+ Each log entry emitted through the event system has the following structure:
77
+
78
+ ```ts
79
+ interface Log {
80
+ time: number; // Timestamp in milliseconds since epoch
81
+ channel: string; // Channel name (e.g., "main", "database")
82
+ levelId: number; // Numeric severity level
83
+ args: any[]; // The logged values
84
+ }
85
+ ```
86
+
87
+ ## Listen for log events
88
+
89
+ The logging system uses an `EventProxy` as its transport. Import the listener to register custom log handlers:
90
+
91
+ ```ts
92
+ import eventLog from "@antelopejs/interface-core/logging/listener";
93
+
94
+ eventLog.register((log) => {
95
+ const date = new Date(log.time).toISOString();
96
+ const level = log.levelId >= 40 ? "ERROR" : log.levelId >= 30 ? "WARN" : "INFO";
97
+ console.log(`[${date}] [${level}] [${log.channel}]`, ...log.args);
98
+ });
99
+ ```
100
+
101
+ The listener is module-aware. Handlers registered by a module are automatically removed when that module is unloaded.
102
+
103
+ ## Next steps
104
+
105
+ - [Configuration](./7.configuration.md) - Project configuration with logging settings
106
+ - [Proxies](./2.proxies.md) - Understand the `EventProxy` that powers the logging transport