@antelopejs/interface-core 0.2.3 → 0.2.5

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.
Files changed (43) hide show
  1. package/README.md +86 -17
  2. package/dist/index.d.ts +4 -1
  3. package/dist/index.js +0 -13
  4. package/dist/index.js.map +1 -1
  5. package/dist/internal.d.ts +14 -2
  6. package/dist/internal.js +17 -1
  7. package/dist/internal.js.map +1 -1
  8. package/dist/modules.d.ts +3 -2
  9. package/dist/modules.js.map +1 -1
  10. package/dist/proxies.d.ts +25 -7
  11. package/dist/proxies.js +89 -79
  12. package/dist/proxies.js.map +1 -1
  13. package/dist/tests/module-ownership-context.test.js +3 -3
  14. package/dist/tests/module-ownership-context.test.js.map +1 -1
  15. package/dist/tests/ownership-call-chain.test.js +261 -0
  16. package/dist/tests/ownership-call-chain.test.js.map +1 -0
  17. package/docs/1.introduction.md +29 -3
  18. package/docs/2.proxies.md +101 -36
  19. package/docs/3.decorators.md +25 -1
  20. package/docs/4.metadata.md +25 -1
  21. package/docs/5.modules.md +26 -7
  22. package/docs/6.logging.md +42 -20
  23. package/docs/7.configuration.md +33 -12
  24. package/docs/8.runtime.md +15 -0
  25. package/docs/assets/proxy-lifecycles.svg +21 -0
  26. package/docs/tsconfig.json +16 -0
  27. package/package.json +11 -4
  28. package/skills/core-interface/SKILL.md +3 -4
  29. package/dist/caller-binding.d.ts +0 -12
  30. package/dist/caller-binding.js +0 -105
  31. package/dist/caller-binding.js.map +0 -1
  32. package/dist/responsible-module.d.ts +0 -23
  33. package/dist/responsible-module.js +0 -56
  34. package/dist/responsible-module.js.map +0 -1
  35. package/dist/tests/caller-context.test.js +0 -154
  36. package/dist/tests/caller-context.test.js.map +0 -1
  37. package/dist/tests/provider-context.test.d.ts +0 -1
  38. package/dist/tests/provider-context.test.js +0 -109
  39. package/dist/tests/provider-context.test.js.map +0 -1
  40. package/dist/tests/responsible-module.test.d.ts +0 -1
  41. package/dist/tests/responsible-module.test.js +0 -109
  42. package/dist/tests/responsible-module.test.js.map +0 -1
  43. /package/dist/tests/{caller-context.test.d.ts → ownership-call-chain.test.d.ts} +0 -0
@@ -2,7 +2,31 @@
2
2
 
3
3
  ## Overview
4
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.
5
+ Use these factories when you are building a decorator, rather than using an existing one such as `@Get`. Your callback receives the decorated target first and the arguments from the decorator call afterwards.
6
+
7
+ These are TypeScript legacy decorators: enable `experimentalDecorators`. They do not implement the standard JavaScript decorator context API. Examples that call `Reflect.defineMetadata` also need `import "reflect-metadata"` before use; importing the package root already loads it.
8
+
9
+ Start with [`MakeClassDecorator`](#makeclassdecorator) for a one-target example. Consult the combined factory table only when the same decorator must support several targets.
10
+
11
+ ## Name a class with a decorator
12
+
13
+ This decorator stores a label when the class is declared. `target` is the class constructor; `name` is the value passed to `@Label`.
14
+
15
+ ```ts docs-check
16
+ import { MakeClassDecorator } from "@antelopejs/interface-core/decorators";
17
+
18
+ const labels = new WeakMap<Function, string>();
19
+ const Label = MakeClassDecorator((target: Function, name: string) => {
20
+ labels.set(target, name);
21
+ });
22
+
23
+ @Label("users")
24
+ class UserController {}
25
+
26
+ const label = labels.get(UserController); // "users"
27
+ ```
28
+
29
+ The factories do not run request-time behavior by themselves. Your integration decides when to read stored values or invoke a decorated method.
6
30
 
7
31
  ## Import
8
32
 
@@ -4,6 +4,28 @@
4
4
 
5
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
6
 
7
+ ## Store a value on a target
8
+
9
+ Give your metadata class a unique symbol, then retrieve its instance for the target. Subsequent calls for that target return the same object; no separate save step is needed.
10
+
11
+ ```ts docs-check
12
+ import { GetMetadata } from "@antelopejs/interface-core";
13
+
14
+ class LabelMetadata {
15
+ static key = Symbol("LabelMetadata");
16
+ label = "";
17
+ constructor(_target: object) {}
18
+ }
19
+
20
+ class UserController {}
21
+ const metadata = GetMetadata(UserController.prototype, LabelMetadata);
22
+ metadata.label = "users";
23
+ const same = GetMetadata(UserController.prototype, LabelMetadata);
24
+ // same === metadata; same.label === "users"
25
+ ```
26
+
27
+ Use the constructor or its prototype consistently: they are different targets. The [inheritance example](#inheritance) shows how to copy a parent's collection without sharing mutable state.
28
+
7
29
  ## Import
8
30
 
9
31
  ```ts
@@ -67,7 +89,7 @@ Calling `GetMetadata` multiple times with the same target and metadata class ret
67
89
 
68
90
  ## Inheritance
69
91
 
70
- 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.
92
+ When first creating metadata and `inherit` is `true` (the default), `GetMetadata` recursively gets or creates metadata on the prototype chain. If the metadata class defines an `inherit` method, that method receives the parent metadata. Otherwise, properties from the parent are copied only where the child has no such key. In particular, an initialized empty child array prevents the default fallback from copying the parent's array.
71
93
 
72
94
  ```ts
73
95
  class ControllerMeta {
@@ -105,6 +127,8 @@ Pass `false` as the third argument to prevent prototype chain traversal:
105
127
  const meta = GetMetadata(target, RouteMetadata, false);
106
128
  ```
107
129
 
130
+ The flag affects creation only. It does not remove inherited values from an instance that was already created, and changing it on a later call does not rebuild the metadata.
131
+
108
132
  ## Next steps
109
133
 
110
134
  - [Decorators](./3.decorators.md) - Combine metadata with decorator factories
package/docs/5.modules.md CHANGED
@@ -4,6 +4,21 @@
4
4
 
5
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
6
 
7
+ ## Inspect the running modules
8
+
9
+ Call these functions from a running AntelopeJS module, where the core has attached their implementations. This example reads status without changing the project.
10
+
11
+ ```ts docs-check
12
+ import { ListModules, GetModuleInfo } from "@antelopejs/interface-core/modules";
13
+
14
+ for (const id of await ListModules()) {
15
+ const info = await GetModuleInfo(id);
16
+ console.log(id, info.status);
17
+ }
18
+ ```
19
+
20
+ Use [management functions](#management-functions) to change what is running now. Use [declaration functions](#declaration-functions) to edit what the project loads on its next start. Neither action automatically performs the other.
21
+
7
22
  ## Import
8
23
 
9
24
  ```ts
@@ -37,6 +52,8 @@ loaded -> constructed -> active -> constructed -> loaded
37
52
 
38
53
  ## Module execution context
39
54
 
55
+ This is a loader concern. Application modules normally receive their context from the runtime and do not invent their own owner IDs.
56
+
40
57
  `RunWithModuleContext` propagates module ownership through synchronous and asynchronous work:
41
58
 
42
59
  ```ts
@@ -51,7 +68,7 @@ await RunWithModuleContext(
51
68
  );
52
69
  ```
53
70
 
54
- `module` remains the stable public module ID. `owner` identifies one lifecycle generation and should be unique when old and replacement instances can overlap. Providers capture this full context when attaching callbacks. `GetModuleContext` returns the active context and throws `ModuleContextInvalidatedError` after its owner is destroyed.
71
+ `module` remains the stable public module ID. `owner` identifies one lifecycle generation and should be unique when old and replacement instances can overlap. `kind` is `"module"` by default; the core sets `"interface"` for the context it evaluates an interface package in. A provider callback runs in the context it was attached in, unless that context is of kind `"interface"`. `GetModuleContext` returns the active context, or `undefined` when there is none, and throws `ModuleContextInvalidatedError` after its owner is destroyed.
55
72
 
56
73
  ## Lifecycle events
57
74
 
@@ -209,12 +226,14 @@ await RemoveModuleDeclaration("@acme/reports");
209
226
 
210
227
  The configuration object for defining a module.
211
228
 
212
- | Property | Type | Description |
213
- | ----------------- | -------------------------------- | ------------------------------------------------- |
214
- | `source` | `{ type: string } & Record<...>` | Source location and loading mechanism |
215
- | `config` | `unknown` | Optional configuration data for the module |
216
- | `importOverrides` | `Record<string, string[]>` | Optional mapping of import paths to alternatives |
217
- | `disabledExports` | `string[]` | Optional list of exports to hide from this module |
229
+ | Property | Type | Description |
230
+ | ----------------- | -------------------------------- | ------------------------------------------------------ |
231
+ | `source` | `{ type: string } & Record<...>` | Source location and loading mechanism |
232
+ | `config` | `unknown` | Optional configuration data for the module |
233
+ | `importOverrides` | `Record<string, string[]>` | Optional runtime import override map with array values |
234
+ | `disabledExports` | `string[]` | Optional list of exports to hide from this module |
235
+
236
+ `ModuleDefinition` is the runtime management contract used by `LoadModule` and `GetModuleInfo`. It is not the project-file `AntelopeModuleConfig`: that type uses `ImportOverride[] | Record<string, string>` for declarative provider bindings and named connections. The different `importOverrides` shapes are intentional; do not copy one into the other or cast between them. `SaveModuleDeclaration` uses the project-file shape. See [project configuration](./7.configuration.md#antelopemoduleconfig) for that contract.
218
237
 
219
238
  ## `ModuleInfo`
220
239
 
package/docs/6.logging.md CHANGED
@@ -2,14 +2,25 @@
2
2
 
3
3
  ## Overview
4
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.
5
+ Use `Logging.Info` for a status message, or a named channel when you want to distinguish one part of the application. These calls emit structured events. The runtime's listener decides how to display them; the interface does not itself write a file or send logs to a service.
6
6
 
7
- ## Import
7
+ ## Write your first message
8
8
 
9
- ```ts
9
+ ```ts docs-check
10
10
  import { Logging } from "@antelopejs/interface-core/logging";
11
+
12
+ Logging.Info("Worker started");
13
+
14
+ const jobs = new Logging.Channel("jobs");
15
+ jobs.Info("Job completed", { jobId: "job-42", durationMs: 120 });
11
16
  ```
12
17
 
18
+ The first event uses channel `main`; the second uses `jobs`. Both have level `INFO` (`20`). Inside an AntelopeJS project, the runtime's logging configuration determines whether they appear in the output. Without a registered listener, events are not retained for later display.
19
+
20
+ Log identifiers and outcomes rather than credentials, tokens, or complete request bodies. Arguments reach listeners unchanged; this interface does not redact secrets or serialize arbitrary objects for you.
21
+
22
+ For ordinary application code, the level and channel methods below are enough. [Custom listeners](#listen-for-log-events) are for integrations that need their own output destination or formatting.
23
+
13
24
  ## Severity levels
14
25
 
15
26
  The `Logging.Level` enum defines the available severity levels:
@@ -30,10 +41,10 @@ The `Logging` namespace exposes convenience functions that write to the `"main"`
30
41
  ```ts
31
42
  import { Logging } from "@antelopejs/interface-core/logging";
32
43
 
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);
44
+ Logging.Error("Database connection failed");
45
+ Logging.Warn("Retrying database connection");
46
+ Logging.Info("Server started on port", 5011);
47
+ Logging.Debug("Request completed", { requestId: "req-42", status: 200 });
37
48
  Logging.Trace("Entering function processItem");
38
49
  ```
39
50
 
@@ -49,11 +60,11 @@ import { Logging } from "@antelopejs/interface-core/logging";
49
60
  const dbLog = new Logging.Channel("database");
50
61
  const httpLog = new Logging.Channel("http");
51
62
 
52
- dbLog.Info("Connected to", dbHost);
53
- dbLog.Error("Query failed:", query, error);
63
+ dbLog.Info("Connection established");
64
+ dbLog.Error("Query failed", { operation: "listUsers" });
54
65
 
55
- httpLog.Info("GET /api/users", statusCode);
56
- httpLog.Debug("Response headers:", headers);
66
+ httpLog.Info("GET /api/users", 200);
67
+ httpLog.Debug("Response sent", { requestId: "req-42" });
57
68
  ```
58
69
 
59
70
  Channels provide the same methods as the main logging functions: `Error`, `Warn`, `Info`, `Debug`, and `Trace`.
@@ -86,20 +97,31 @@ interface Log {
86
97
 
87
98
  ## Listen for log events
88
99
 
89
- The logging system uses an `EventProxy` as its transport. Import the listener to register custom log handlers:
100
+ Register a listener before emitting the messages you want to receive. This example selects warning and error events for console output; it leaves other levels alone.
90
101
 
91
- ```ts
92
- import eventLog from "@antelopejs/interface-core/logging/listener";
102
+ ```ts docs-check
103
+ import { Logging } from "@antelopejs/interface-core/logging";
104
+ import eventLog, {
105
+ type Log,
106
+ } from "@antelopejs/interface-core/logging/listener";
93
107
 
94
- eventLog.register((log) => {
108
+ function writeWarning(log: Log) {
109
+ if (log.levelId < Logging.Level.WARN) return;
95
110
  const date = new Date(log.time).toISOString();
96
- const level =
97
- log.levelId >= 40 ? "ERROR" : log.levelId >= 30 ? "WARN" : "INFO";
98
- console.log(`[${date}] [${level}] [${log.channel}]`, ...log.args);
99
- });
111
+ console.warn(`[${date}] [${log.levelId}] [${log.channel}]`, ...log.args);
112
+ }
113
+
114
+ eventLog.register(writeWarning);
115
+ Logging.Warn("Retry scheduled");
116
+ // When this subscription is no longer needed:
117
+ eventLog.unregister(writeWarning);
100
118
  ```
101
119
 
102
- The listener is module-aware. Handlers registered by a module are automatically removed when that module is unloaded.
120
+ Keep the same function reference to unsubscribe. The runtime also removes module-owned listeners when their owner is destroyed. A second console listener may duplicate output already written by the runtime.
121
+
122
+ Listeners run synchronously. A slow listener delays the logging call, and `emit` does not await promises from asynchronous listeners. Handle asynchronous failures inside your listener. Do not call `Logging.*` from a log listener: that emits another log event and can recurse indefinitely.
123
+
124
+ Project logging filters belong to the runtime's output listener. A custom listener receives raw events and must apply its own filtering and redaction. `NO_PREFIX` is a level convention for formatters, not a bypass for these responsibilities.
103
125
 
104
126
  ## Next steps
105
127
 
@@ -4,6 +4,25 @@
4
4
 
5
5
  The `@antelopejs/interface-core/config` module exports TypeScript types and the `defineConfig` helper for defining AntelopeJS project configurations. These types describe module sources, logging settings, environment overrides, and test configurations.
6
6
 
7
+ ## Start with one local module
8
+
9
+ Put this in `antelope.config.ts`, replacing the source path with your module's directory. The module itself must already exist; `defineConfig` does not generate it.
10
+
11
+ ```ts docs-check
12
+ import { defineConfig } from "@antelopejs/interface-core/config";
13
+
14
+ export default defineConfig({
15
+ name: "my-project",
16
+ modules: {
17
+ app: {
18
+ source: { type: "local", path: "./modules/app" },
19
+ },
20
+ },
21
+ });
22
+ ```
23
+
24
+ `defineConfig` returns its input unchanged. It supplies TypeScript checking, not runtime validation or module loading. Use the source and field reference below as you add modules; config variables and provider overrides are optional advanced features.
25
+
7
26
  ## Import
8
27
 
9
28
  ```ts
@@ -39,7 +58,7 @@ export default defineConfig({
39
58
  package: "@antelopejs/auth",
40
59
  version: "1.0.0",
41
60
  },
42
- config: { secret: "my-secret" },
61
+ // Supply provider-specific configuration through your deployment's secret handling.
43
62
  },
44
63
  },
45
64
  });
@@ -70,15 +89,15 @@ export default defineConfig((ctx) => {
70
89
 
71
90
  The root configuration object for an AntelopeJS project.
72
91
 
73
- | Property | Type | Description |
74
- | -------------- | ------------------------------------------------ | ----------------------------------------- |
75
- | `name` | `string` | Project name |
76
- | `cacheFolder` | `string` | Optional custom cache directory |
77
- | `modules` | `Record<string, string \| AntelopeModuleConfig>` | Module definitions (shorthand or full) |
78
- | `logging` | `AntelopeLogging` | Optional logging configuration |
79
- | `envOverrides` | `Record<string, string \| string[]>` | Optional environment variable overrides |
80
- | `environments` | `Record<string, Partial<AntelopeConfig>>` | Optional per-environment config overrides |
81
- | `test` | `AntelopeTestConfig` | Optional test configuration |
92
+ | Property | Type | Description |
93
+ | -------------- | ------------------------------------------------ | ----------------------------------------------- |
94
+ | `name` | `string` | Project name |
95
+ | `cacheFolder` | `string` | Optional custom cache directory |
96
+ | `modules` | `Record<string, string \| AntelopeModuleConfig>` | Optional module definitions (shorthand or full) |
97
+ | `logging` | `AntelopeLogging` | Optional logging configuration |
98
+ | `envOverrides` | `Record<string, string \| string[]>` | Optional environment variable overrides |
99
+ | `environments` | `Record<string, Partial<AntelopeConfig>>` | Optional per-environment config overrides |
100
+ | `test` | `AntelopeTestConfig` | Optional test configuration |
82
101
 
83
102
  ## Module sources
84
103
 
@@ -157,7 +176,7 @@ Full module configuration within the project config.
157
176
  | Property | Type | Description |
158
177
  | ----------------- | -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
159
178
  | `version` | `string` | Optional version constraint |
160
- | `source` | `ModuleSource*` | Source definition (local, git, package, local-folder) |
179
+ | `source` | `ModuleSource*` | Optional source definition (local, git, package, local-folder) |
161
180
  | `config` | `unknown` | Optional runtime configuration |
162
181
  | `importOverrides` | `ImportOverride[] \| Record<string, string>` | Optional providers pinned for the interfaces the module uses, and named connections |
163
182
  | `disabledExports` | `string[]` | Optional list of exports to disable |
@@ -167,9 +186,11 @@ Full module configuration within the project config.
167
186
 
168
187
  An `ImportOverride` is `{ interface, source?, id? }`. The first entry for an interface pins it to the `source` module; further entries are connections reached through `GetInterfaceInstance(interface, id)`. An entry for a standalone interface may omit `source`, declaring a connection to that self-hosted interface.
169
188
 
189
+ This project-file contract also applies to `SaveModuleDeclaration`. It differs intentionally from the runtime `ModuleDefinition.importOverrides: Record<string, string[]>` accepted by `LoadModule`; the two types are not interchangeable. Use the type of the API you are calling rather than changing or casting the override shape.
190
+
170
191
  ## `AntelopeLogging`
171
192
 
172
- Logging configuration within the project config.
193
+ Logging configuration interpreted by the core runtime. All fields are optional. These settings configure the runtime's output; they do not change the raw events sent to a [custom logging listener](./6.logging.md#listen-for-log-events).
173
194
 
174
195
  | Property | Type | Description |
175
196
  | ---------------- | ---------------------------------- | ------------------------------------------------- |
package/docs/8.runtime.md CHANGED
@@ -4,6 +4,21 @@
4
4
 
5
5
  The `@antelopejs/interface-core/runtime` module exposes information about the runtime environment of the running project and a registry for development servers. The implementation is provided by the AntelopeJS core: `ajs project dev` reports development mode, while `ajs project start` and `ajs project run` report production mode.
6
6
 
7
+ ## Check the current mode
8
+
9
+ Use this inside a running module when behavior genuinely depends on development mode. The selected configuration environment (`env`) is separate from the command's development mode (`dev`).
10
+
11
+ ```ts docs-check
12
+ import { GetRuntimeInfo } from "@antelopejs/interface-core/runtime";
13
+
14
+ const { dev, env } = await GetRuntimeInfo();
15
+ if (dev) {
16
+ console.log(`Development helpers enabled for environment ${env}`);
17
+ }
18
+ ```
19
+
20
+ Most consumers need only `GetRuntimeInfo`. The server registry below is for modules that open listening ports and tooling that discovers them; registering an endpoint does not start a server.
21
+
7
22
  ## Import
8
23
 
9
24
  ```ts
@@ -0,0 +1,21 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 480 438" role="img" aria-labelledby="title desc">
2
+ <title id="title">Three proxy lifecycles</title>
3
+ <desc id="desc">Async proxies queue calls until attachment. Event proxies notify current listeners without replay. Registering proxies retain entries and replay them to replacement providers.</desc>
4
+ <rect width="480" height="438" rx="16" fill="#f5f7fb"/>
5
+ <g font-family="system-ui, sans-serif" fill="#172b45">
6
+ <text x="24" y="36" font-size="20" font-weight="700">What survives a missing attachment?</text>
7
+ <rect x="24" y="58" width="432" height="102" rx="10" fill="#e1ecfa"/>
8
+ <text x="42" y="88" font-size="18" font-weight="700">AsyncProxy · ask for a result</text>
9
+ <text x="42" y="119" font-size="16">Call → bounded queue → provider attaches</text>
10
+ <text x="42" y="144" font-size="16">Pending calls run and resolve or reject.</text>
11
+ <rect x="24" y="178" width="432" height="102" rx="10" fill="#eee6fb"/>
12
+ <text x="42" y="208" font-size="18" font-weight="700">EventProxy · notify now</text>
13
+ <text x="42" y="239" font-size="16">Emit → current listeners</text>
14
+ <text x="42" y="264" font-size="16">No queue. New listeners do not receive history.</text>
15
+ <rect x="24" y="298" width="432" height="102" rx="10" fill="#d9eee8"/>
16
+ <text x="42" y="328" font-size="18" font-weight="700">RegisteringProxy · retain declarations</text>
17
+ <text x="42" y="359" font-size="16">Register → stored entry → attach → replay</text>
18
+ <text x="42" y="384" font-size="16">Provider replacement can replay entries again.</text>
19
+ <text x="24" y="424" font-size="13">Normal runtime behavior; test stub mode rejects missing providers.</text>
20
+ </g>
21
+ </svg>
@@ -0,0 +1,16 @@
1
+ {
2
+ "extends": "../tsconfig.json",
3
+ "compilerOptions": {
4
+ "module": "ESNext",
5
+ "moduleResolution": "node",
6
+ "rootDir": "..",
7
+ "composite": false,
8
+ "incremental": false,
9
+ "noEmit": true,
10
+ "paths": {
11
+ "@antelopejs/interface-core": ["../src/index.ts"],
12
+ "@antelopejs/interface-core/*": ["../src/*"]
13
+ }
14
+ },
15
+ "include": ["../src", "./**/*.ts"]
16
+ }
package/package.json CHANGED
@@ -1,12 +1,19 @@
1
1
  {
2
2
  "name": "@antelopejs/interface-core",
3
- "version": "0.2.3",
4
- "description": "AntelopeJS core interface primitives - proxies, decorators, interface functions, and logging",
3
+ "version": "0.2.5",
4
+ "description": "AntelopeJS core interface primitives: proxies, interface functions, decorators, module lifecycle, logging and configuration",
5
5
  "keywords": [
6
6
  "antelopejs",
7
7
  "core",
8
- "interface"
8
+ "decorators",
9
+ "interface",
10
+ "logging",
11
+ "proxy"
9
12
  ],
13
+ "homepage": "https://interfaces.antelopejs.com/docs/core",
14
+ "bugs": {
15
+ "url": "https://github.com/AntelopeJS/interface-core/issues"
16
+ },
10
17
  "license": "Apache-2.0",
11
18
  "repository": {
12
19
  "type": "git",
@@ -90,7 +97,7 @@
90
97
  "reflect-metadata": "^0.2.2"
91
98
  },
92
99
  "devDependencies": {
93
- "@antelopejs/tooling-configs": "^0.0.8",
100
+ "@antelopejs/tooling-configs": "^0.0.9",
94
101
  "@types/chai": "^4.3.20",
95
102
  "@types/mocha": "^10.0.10",
96
103
  "@types/node": "^22.19.15",
@@ -114,10 +114,9 @@ ch.Debug("query", { ms: 12 });
114
114
  implementation in test environment. Ensure the required module is loaded in your test config.".
115
115
  - Prefer the synchronous `ImplementInterface(decl, impl)`; the Promise-accepting overload is
116
116
  deprecated. Implementations may be partial - unmatched keys keep queuing.
117
- - Module attribution (`GetResponsibleModule`) works by call-stack analysis. Attach implementations
118
- and register handlers synchronously during module load; doing it from a setTimeout/setInterval
119
- callback logs "this will break hot reloading!", and other async contexts break attribution
120
- silently - both defeat automatic cleanup on module unload.
117
+ - Module attribution (`GetResponsibleModule`) reads the async module context the core enters for
118
+ each module. Provider callbacks run in the provider's context and event handlers in their
119
+ registrant's; a function passed as an argument runs in whichever context invokes it.
121
120
  - `RegisteringProxy` replays existing registrations to a newly attached provider (hot reload safe);
122
121
  `EventProxy.register` deduplicates by function identity; both auto-clean handlers of destroyed
123
122
  modules via `Events.ModuleDestroyed`.
@@ -1,12 +0,0 @@
1
- /**
2
- * Binds the functions a caller hands to an interface proxy to the caller's
3
- * module context, so they run as the caller's work whoever invokes them.
4
- *
5
- * Functions, and functions held in plain objects and arrays, are bound; plain
6
- * data, classes, class instances and proxies cross unchanged, so a class keeps
7
- * the identity its metadata and registries are keyed by. A value is bound once per
8
- * context, and a value that is already bound keeps its original context.
9
- */
10
- export declare function bindCallerArguments<T extends unknown[]>(args: T): T;
11
- /** Binds a single caller function to the caller's module context. */
12
- export declare function bindCallerFunction<T extends (...args: any[]) => unknown>(callback: T): T;
@@ -1,105 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.bindCallerArguments = bindCallerArguments;
4
- exports.bindCallerFunction = bindCallerFunction;
5
- const node_util_1 = require("node:util");
6
- const internal_1 = require("./internal");
7
- const bindingsBySource = new WeakMap();
8
- const boundValues = new WeakSet();
9
- const CLASS_SOURCE = /^class\b/;
10
- function isClass(value) {
11
- return CLASS_SOURCE.test(Function.prototype.toString.call(value));
12
- }
13
- function isBindableFunction(value) {
14
- return typeof value === "function" && !isClass(value);
15
- }
16
- function hasPlainPrototype(value) {
17
- if (Array.isArray(value)) {
18
- return true;
19
- }
20
- const prototype = Object.getPrototypeOf(value);
21
- return prototype === Object.prototype || prototype === null;
22
- }
23
- function isBindableContainer(value) {
24
- return (typeof value === "object" &&
25
- value !== null &&
26
- !node_util_1.types.isProxy(value) &&
27
- hasPlainPrototype(value));
28
- }
29
- function holdsFunction(value, visited) {
30
- if (isBindableFunction(value)) {
31
- return true;
32
- }
33
- if (!isBindableContainer(value) || visited.has(value)) {
34
- return false;
35
- }
36
- visited.add(value);
37
- return Object.values(value).some((member) => holdsFunction(member, visited));
38
- }
39
- function needsBinding(value) {
40
- if (typeof value === "function") {
41
- return isBindableFunction(value) && !boundValues.has(value);
42
- }
43
- return (isBindableContainer(value) &&
44
- !boundValues.has(value) &&
45
- holdsFunction(value, new Set()));
46
- }
47
- function createFunctionBinding(target, context) {
48
- return new Proxy(target, {
49
- apply: (callable, thisArg, argumentsList) => (0, internal_1.runWithCapturedModuleContext)(context, () => callable.apply(thisArg, argumentsList)),
50
- construct: (callable, argumentsList, newTarget) => (0, internal_1.runWithCapturedModuleContext)(context, () => Reflect.construct(callable, argumentsList, newTarget)),
51
- });
52
- }
53
- function createContainerBinding(target, context) {
54
- return new Proxy(target, {
55
- get: (container, property) => {
56
- const member = container[property];
57
- const descriptor = Reflect.getOwnPropertyDescriptor(container, property);
58
- const isFixed = descriptor !== undefined &&
59
- !descriptor.configurable &&
60
- "value" in descriptor &&
61
- !descriptor.writable;
62
- return isFixed ? member : bindValue(member, context);
63
- },
64
- });
65
- }
66
- function bindValue(value, context) {
67
- if (!needsBinding(value)) {
68
- return value;
69
- }
70
- const cached = bindingsBySource.get(value)?.get(context);
71
- if (cached) {
72
- return cached;
73
- }
74
- const bound = typeof value === "function"
75
- ? createFunctionBinding(value, context)
76
- : createContainerBinding(value, context);
77
- const contexts = bindingsBySource.get(value) ??
78
- new WeakMap();
79
- contexts.set(context, bound);
80
- bindingsBySource.set(value, contexts);
81
- boundValues.add(bound);
82
- return bound;
83
- }
84
- /**
85
- * Binds the functions a caller hands to an interface proxy to the caller's
86
- * module context, so they run as the caller's work whoever invokes them.
87
- *
88
- * Functions, and functions held in plain objects and arrays, are bound; plain
89
- * data, classes, class instances and proxies cross unchanged, so a class keeps
90
- * the identity its metadata and registries are keyed by. A value is bound once per
91
- * context, and a value that is already bound keeps its original context.
92
- */
93
- function bindCallerArguments(args) {
94
- const context = (0, internal_1.captureModuleContext)();
95
- if (!context) {
96
- return args;
97
- }
98
- return args.map((argument) => bindValue(argument, context));
99
- }
100
- /** Binds a single caller function to the caller's module context. */
101
- function bindCallerFunction(callback) {
102
- const context = (0, internal_1.captureModuleContext)();
103
- return context ? bindValue(callback, context) : callback;
104
- }
105
- //# sourceMappingURL=caller-binding.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"caller-binding.js","sourceRoot":"","sources":["../src/caller-binding.ts"],"names":[],"mappings":"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"}
@@ -1,23 +0,0 @@
1
- export interface ModuleFolderEntry {
2
- dir: string;
3
- id: string;
4
- isImplementor?: boolean;
5
- }
6
- export interface ResponsibleModuleResult {
7
- module?: string;
8
- lastInterface: string;
9
- }
10
- /**
11
- * Walk the trace to decide which module is responsible for the current call.
12
- *
13
- * Rules:
14
- * 1. `node_modules` and generic `node:internal/` frames are skipped.
15
- * 2. `node:internal/modules/...` (the require loader) is a hard boundary:
16
- * frames above it belong to the module currently being loaded (owning
17
- * the side effect); frames below it belong to whoever triggered the
18
- * require and must not be credited.
19
- * 3. The first non-implementor match wins — that is user code. If only
20
- * implementor modules match, the first implementor is used as a
21
- * fallback so framework-level registrations still have an owner.
22
- */
23
- export declare function findResponsibleFile(trace: NodeJS.CallSite[], entries?: ModuleFolderEntry[]): ResponsibleModuleResult;