@antelopejs/interface-core 0.2.4 → 0.2.6
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/dist/index.js +0 -13
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +14 -2
- package/dist/internal.js +17 -1
- package/dist/internal.js.map +1 -1
- package/dist/modules.d.ts +15 -0
- package/dist/modules.js +15 -0
- package/dist/modules.js.map +1 -1
- package/dist/proxies.d.ts +10 -6
- package/dist/proxies.js +74 -78
- package/dist/proxies.js.map +1 -1
- package/dist/tests/module-ownership-context.test.js +3 -3
- package/dist/tests/module-ownership-context.test.js.map +1 -1
- package/dist/tests/ownership-call-chain.test.js +261 -0
- package/dist/tests/ownership-call-chain.test.js.map +1 -0
- package/docs/1.introduction.md +29 -3
- package/docs/2.proxies.md +40 -20
- package/docs/3.decorators.md +25 -1
- package/docs/4.metadata.md +25 -1
- package/docs/5.modules.md +39 -2
- package/docs/6.logging.md +42 -20
- package/docs/7.configuration.md +31 -12
- package/docs/8.runtime.md +15 -0
- package/docs/assets/proxy-lifecycles.svg +21 -0
- package/package.json +1 -1
- package/skills/core-interface/SKILL.md +4 -5
- package/dist/caller-binding.d.ts +0 -12
- package/dist/caller-binding.js +0 -105
- package/dist/caller-binding.js.map +0 -1
- package/dist/responsible-module.d.ts +0 -23
- package/dist/responsible-module.js +0 -56
- package/dist/responsible-module.js.map +0 -1
- package/dist/tests/caller-context.test.js +0 -154
- package/dist/tests/caller-context.test.js.map +0 -1
- package/dist/tests/provider-context.test.d.ts +0 -1
- package/dist/tests/provider-context.test.js +0 -109
- package/dist/tests/provider-context.test.js.map +0 -1
- package/dist/tests/responsible-module.test.d.ts +0 -1
- package/dist/tests/responsible-module.test.js +0 -109
- package/dist/tests/responsible-module.test.js.map +0 -1
- /package/dist/tests/{caller-context.test.d.ts → ownership-call-chain.test.d.ts} +0 -0
package/docs/4.metadata.md
CHANGED
|
@@ -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`
|
|
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.
|
|
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
|
|
|
@@ -99,7 +116,27 @@ Events.ModuleDestroyed.register((moduleId: string) => {
|
|
|
99
116
|
});
|
|
100
117
|
```
|
|
101
118
|
|
|
102
|
-
The
|
|
119
|
+
The signature of these four events remains the module ID. When emitted inside `RunWithModuleContext`, cleanup targets that context's `owner`; without an explicit owner it retains the module-level behavior used by earlier releases.
|
|
120
|
+
|
|
121
|
+
### `Events.ModulesStarted`
|
|
122
|
+
|
|
123
|
+
Fires once every module the core was asked to start has started: the project as a whole is ready to serve. It does not fire when a module fails to start.
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
Events.ModulesStarted.register(() => {
|
|
127
|
+
console.log("All modules started");
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### `Events.ModulesStopping`
|
|
132
|
+
|
|
133
|
+
Fires before the first module stops, once per stop following `ModulesStarted`: stopping a project, or reloading one module, is a single "stopping".
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
Events.ModulesStopping.register(() => {
|
|
137
|
+
console.log("Modules are stopping");
|
|
138
|
+
});
|
|
139
|
+
```
|
|
103
140
|
|
|
104
141
|
## Management functions
|
|
105
142
|
|
package/docs/6.logging.md
CHANGED
|
@@ -2,14 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
|
-
|
|
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
|
-
##
|
|
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"
|
|
34
|
-
Logging.Warn("
|
|
35
|
-
Logging.Info("Server started on port",
|
|
36
|
-
Logging.Debug("Request
|
|
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("
|
|
53
|
-
dbLog.Error("Query failed
|
|
63
|
+
dbLog.Info("Connection established");
|
|
64
|
+
dbLog.Error("Query failed", { operation: "listUsers" });
|
|
54
65
|
|
|
55
|
-
httpLog.Info("GET /api/users",
|
|
56
|
-
httpLog.Debug("Response
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
108
|
+
function writeWarning(log: Log) {
|
|
109
|
+
if (log.levelId < Logging.Level.WARN) return;
|
|
95
110
|
const date = new Date(log.time).toISOString();
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
|
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
|
|
package/docs/7.configuration.md
CHANGED
|
@@ -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
|
-
|
|
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>` |
|
|
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*` |
|
|
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 |
|
|
@@ -171,7 +190,7 @@ This project-file contract also applies to `SaveModuleDeclaration`. It differs i
|
|
|
171
190
|
|
|
172
191
|
## `AntelopeLogging`
|
|
173
192
|
|
|
174
|
-
Logging configuration
|
|
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).
|
|
175
194
|
|
|
176
195
|
| Property | Type | Description |
|
|
177
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>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: core-interface
|
|
3
|
-
description: Provides the AntelopeJS core interface primitives - AsyncProxy/EventProxy/RegisteringProxy, InterfaceFunction, ImplementInterface, GetMetadata, decorator factories, module lifecycle events, structured Logging, and defineConfig. Use when importing from "@antelopejs/interface-core" (or its /decorators, /modules, /proxies, /runtime, /config, /logging subpaths), when declaring or implementing an AntelopeJS interface, wiring cross-module calls or events, building custom decorators, subscribing to ModuleStarted/ModuleDestroyed, writing logs via Logging.Info/Error, or authoring antelope.config with defineConfig.
|
|
3
|
+
description: Provides the AntelopeJS core interface primitives - AsyncProxy/EventProxy/RegisteringProxy, InterfaceFunction, ImplementInterface, GetMetadata, decorator factories, module lifecycle events, structured Logging, and defineConfig. Use when importing from "@antelopejs/interface-core" (or its /decorators, /modules, /proxies, /runtime, /config, /logging subpaths), when declaring or implementing an AntelopeJS interface, wiring cross-module calls or events, building custom decorators, subscribing to ModuleStarted/ModuleDestroyed or ModulesStarted/ModulesStopping, writing logs via Logging.Info/Error, or authoring antelope.config with defineConfig.
|
|
4
4
|
category: antelopejs-interface
|
|
5
5
|
tags: [antelopejs, interface, proxy, decorators, logging]
|
|
6
6
|
---
|
|
@@ -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`)
|
|
118
|
-
|
|
119
|
-
|
|
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`.
|
package/dist/caller-binding.d.ts
DELETED
|
@@ -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;
|
package/dist/caller-binding.js
DELETED
|
@@ -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":";;AA+HA,kDAMC;AAGD,gDAKC;AA7ID,yCAA+C;AAE/C,yCAAgF;AAOhF,MAAM,gBAAgB,GAAG,IAAI,OAAO,EAGjC,CAAC;AACJ,MAAM,WAAW,GAAG,IAAI,OAAO,EAAiB,CAAC;AACjD,MAAM,YAAY,GAAG,UAAU,CAAC;AAEhC,SAAS,OAAO,CAAC,KAAe;IAC9B,OAAO,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AACpE,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAc;IACxC,OAAO,OAAO,KAAK,KAAK,UAAU,IAAI,CAAC,OAAO,CAAC,KAAiB,CAAC,CAAC;AACpE,CAAC;AAED,SAAS,iBAAiB,CAAC,KAA2B;IACpD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,SAAS,GAAG,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;IAC/C,OAAO,SAAS,KAAK,MAAM,CAAC,SAAS,IAAI,SAAS,KAAK,IAAI,CAAC;AAC9D,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAc;IACzC,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,CAAC,iBAAS,CAAC,OAAO,CAAC,KAAK,CAAC;QACzB,iBAAiB,CAAC,KAAK,CAAC,CACzB,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,KAAc,EAAE,OAAoB;IACzD,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QACtD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACnB,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAC/E,CAAC;AAED,SAAS,YAAY,CAAC,KAAc;IAClC,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE,CAAC;QAChC,OAAO,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC9D,CAAC;IACD,OAAO,CACL,mBAAmB,CAAC,KAAK,CAAC;QAC1B,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC;QACvB,aAAa,CAAC,KAAK,EAAE,IAAI,GAAG,EAAE,CAAC,CAChC,CAAC;AACJ,CAAC;AAED,SAAS,qBAAqB,CAC5B,MAAgB,EAChB,OAAwB;IAExB,OAAO,IAAI,KAAK,CAAC,MAAM,EAAE;QACvB,KAAK,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,aAAwB,EAAE,EAAE,CACrD,IAAA,uCAA4B,EAAC,OAAO,EAAE,GAAG,EAAE,CACzC,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,aAAa,CAAC,CACvC;QACH,SAAS,EAAE,CAAC,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,EAAE,CAChD,IAAA,uCAA4B,EAAC,OAAO,EAAE,GAAG,EAAE,CACzC,OAAO,CAAC,SAAS,CAAC,QAAQ,EAAE,aAAa,EAAE,SAAS,CAAC,CACtD;KACJ,CAAC,CAAC;AACL,CAAC;AAED,SAAS,sBAAsB,CAC7B,MAAsB,EACtB,OAAwB;IAExB,OAAO,IAAI,KAAK,CAAC,MAAM,EAAE;QACvB,GAAG,EAAE,CAAC,SAAuC,EAAE,QAAQ,EAAE,EAAE;YACzD,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;YACnC,MAAM,UAAU,GAAG,OAAO,CAAC,wBAAwB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;YACzE,MAAM,OAAO,GACX,UAAU,KAAK,SAAS;gBACxB,CAAC,UAAU,CAAC,YAAY;gBACxB,OAAO,IAAI,UAAU;gBACrB,CAAC,UAAU,CAAC,QAAQ,CAAC;YACvB,OAAO,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACvD,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,SAAS,SAAS,CAAC,KAAc,EAAE,OAAwB;IACzD,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACzD,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,MAAM,KAAK,GACT,OAAO,KAAK,KAAK,UAAU;QACzB,CAAC,CAAC,qBAAqB,CAAC,KAAiB,EAAE,OAAO,CAAC;QACnD,CAAC,CAAC,sBAAsB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAC7C,MAAM,QAAQ,GACZ,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC;QAC3B,IAAI,OAAO,EAAkC,CAAC;IAChD,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC7B,gBAAgB,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IACtC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACvB,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,mBAAmB,CAAsB,IAAO;IAC9D,MAAM,OAAO,GAAG,IAAA,+BAAoB,GAAE,CAAC;IACvC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAM,CAAC;AACnE,CAAC;AAED,qEAAqE;AACrE,SAAgB,kBAAkB,CAChC,QAAW;IAEX,MAAM,OAAO,GAAG,IAAA,+BAAoB,GAAE,CAAC;IACvC,OAAO,OAAO,CAAC,CAAC,CAAE,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAO,CAAC,CAAC,CAAC,QAAQ,CAAC;AAClE,CAAC"}
|
|
@@ -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;
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.findResponsibleFile = findResponsibleFile;
|
|
4
|
-
const internal_1 = require("./internal");
|
|
5
|
-
function findMatchingEntry(fileName, entries) {
|
|
6
|
-
let best;
|
|
7
|
-
let bestLen = 0;
|
|
8
|
-
for (const entry of entries) {
|
|
9
|
-
if (fileName.startsWith(entry.dir) && entry.dir.length > bestLen) {
|
|
10
|
-
best = entry;
|
|
11
|
-
bestLen = entry.dir.length;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
return best;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Walk the trace to decide which module is responsible for the current call.
|
|
18
|
-
*
|
|
19
|
-
* Rules:
|
|
20
|
-
* 1. `node_modules` and generic `node:internal/` frames are skipped.
|
|
21
|
-
* 2. `node:internal/modules/...` (the require loader) is a hard boundary:
|
|
22
|
-
* frames above it belong to the module currently being loaded (owning
|
|
23
|
-
* the side effect); frames below it belong to whoever triggered the
|
|
24
|
-
* require and must not be credited.
|
|
25
|
-
* 3. The first non-implementor match wins — that is user code. If only
|
|
26
|
-
* implementor modules match, the first implementor is used as a
|
|
27
|
-
* fallback so framework-level registrations still have an owner.
|
|
28
|
-
*/
|
|
29
|
-
function findResponsibleFile(trace, entries = internal_1.internal.moduleByFolder) {
|
|
30
|
-
const lastInterface = "";
|
|
31
|
-
let implementorMatch;
|
|
32
|
-
for (const site of trace) {
|
|
33
|
-
const fileName = site.getFileName();
|
|
34
|
-
if (fileName?.startsWith("node:internal/modules/")) {
|
|
35
|
-
break;
|
|
36
|
-
}
|
|
37
|
-
if (!fileName ||
|
|
38
|
-
fileName.startsWith("node:internal/") ||
|
|
39
|
-
fileName.match(/[/\\]node_modules[/\\]/)) {
|
|
40
|
-
continue;
|
|
41
|
-
}
|
|
42
|
-
const match = findMatchingEntry(fileName, entries);
|
|
43
|
-
if (!match) {
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
if (!match.isImplementor) {
|
|
47
|
-
return { module: match.id, lastInterface };
|
|
48
|
-
}
|
|
49
|
-
implementorMatch = match.id;
|
|
50
|
-
}
|
|
51
|
-
if (implementorMatch) {
|
|
52
|
-
return { module: implementorMatch, lastInterface };
|
|
53
|
-
}
|
|
54
|
-
return { lastInterface };
|
|
55
|
-
}
|
|
56
|
-
//# sourceMappingURL=responsible-module.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"responsible-module.js","sourceRoot":"","sources":["../src/responsible-module.ts"],"names":[],"mappings":";;AAyCA,kDAiCC;AA1ED,yCAAsC;AAatC,SAAS,iBAAiB,CACxB,QAAgB,EAChB,OAA4B;IAE5B,IAAI,IAAmC,CAAC;IACxC,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,GAAG,OAAO,EAAE,CAAC;YACjE,IAAI,GAAG,KAAK,CAAC;YACb,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC;QAC7B,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAgB,mBAAmB,CACjC,KAAwB,EACxB,UAA+B,mBAAQ,CAAC,cAAc;IAEtD,MAAM,aAAa,GAAG,EAAE,CAAC;IACzB,IAAI,gBAAoC,CAAC;IAEzC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACpC,IAAI,QAAQ,EAAE,UAAU,CAAC,wBAAwB,CAAC,EAAE,CAAC;YACnD,MAAM;QACR,CAAC;QACD,IACE,CAAC,QAAQ;YACT,QAAQ,CAAC,UAAU,CAAC,gBAAgB,CAAC;YACrC,QAAQ,CAAC,KAAK,CAAC,wBAAwB,CAAC,EACxC,CAAC;YACD,SAAS;QACX,CAAC;QACD,MAAM,KAAK,GAAG,iBAAiB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACnD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,SAAS;QACX,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;YACzB,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,EAAE,aAAa,EAAE,CAAC;QAC7C,CAAC;QACD,gBAAgB,GAAG,KAAK,CAAC,EAAE,CAAC;IAC9B,CAAC;IAED,IAAI,gBAAgB,EAAE,CAAC;QACrB,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,aAAa,EAAE,CAAC;IACrD,CAAC;IACD,OAAO,EAAE,aAAa,EAAE,CAAC;AAC3B,CAAC"}
|