@loutrejs/loutre 0.9.2 → 0.10.0
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/adapters/aws-lambda.d.ts +1 -1
- package/dist/adapters/aws-lambda.js +8 -2
- package/dist/adapters/bun.d.ts +3 -2
- package/dist/adapters/bun.js +12 -6
- package/dist/adapters/cloudflare-workers.d.ts +1 -1
- package/dist/adapters/cloudflare-workers.js +2 -1
- package/dist/adapters/electron.d.ts +1 -1
- package/dist/adapters/electron.js +8 -51
- package/dist/adapters/server-transports.js +2 -2
- package/dist/adapters/websocket-native.js +4 -1
- package/dist/application/definition.d.ts +4 -7
- package/dist/application/definition.js +3 -1
- package/dist/application/kernel.d.ts +0 -2
- package/dist/application/kernel.js +1 -3
- package/dist/core/args.d.ts +1 -0
- package/dist/core/args.js +2 -1
- package/dist/core/env.d.ts +1 -0
- package/dist/core/env.js +2 -1
- package/dist/core/extension.d.ts +23 -13
- package/dist/core/extension.js +3 -1
- package/dist/core/generic-layer.d.ts +9 -2
- package/dist/core/generic-layer.js +2 -1
- package/dist/core/identity.d.ts +18 -0
- package/dist/core/identity.js +5 -0
- package/dist/core/index.d.ts +13 -5
- package/dist/core/index.js +7 -1
- package/dist/core/injection.d.ts +2 -1
- package/dist/core/instrumentation.d.ts +7 -5
- package/dist/core/lifecycle.d.ts +4 -0
- package/dist/core/logger-identity.d.ts +4 -0
- package/dist/core/logger-identity.js +9 -0
- package/dist/core/logger-internal.d.ts +5 -0
- package/dist/core/logger-internal.js +27 -0
- package/dist/core/logger-module.d.ts +5 -0
- package/dist/core/logger-module.js +8 -0
- package/dist/core/logger.d.ts +42 -0
- package/dist/core/logger.js +221 -0
- package/dist/core/model/context.d.ts +6 -3
- package/dist/core/model/context.js +17 -17
- package/dist/core/model/identity.d.ts +19 -0
- package/dist/core/model/identity.js +8 -0
- package/dist/core/model/lifecycle.d.ts +3 -2
- package/dist/core/model/lifecycle.js +7 -3
- package/dist/core/model/logger.d.ts +3 -0
- package/dist/core/model/logger.js +59 -0
- package/dist/core/model/modules.d.ts +4 -1
- package/dist/core/model/modules.js +6 -4
- package/dist/core/model/providers.d.ts +1 -1
- package/dist/core/model/providers.js +8 -8
- package/dist/core/model/types.d.ts +25 -18
- package/dist/core/model/validation.js +3 -2
- package/dist/core/model/visibility.js +7 -2
- package/dist/core/model.js +15 -7
- package/dist/core/module.d.ts +7 -7
- package/dist/core/module.js +0 -3
- package/dist/core/runtime-input.d.ts +2 -1
- package/dist/core/source-location.d.ts +14 -2
- package/dist/core/source-location.js +8 -3
- package/dist/core/token-internal.js +3 -1
- package/dist/core/token.d.ts +4 -2
- package/dist/core/token.js +3 -0
- package/dist/core/units.d.ts +22 -0
- package/dist/core/units.js +14 -0
- package/dist/devtools/capsule.d.ts +17 -13
- package/dist/devtools/capsule.js +14 -10
- package/dist/devtools/decoder.d.ts +15 -0
- package/dist/devtools/decoder.js +179 -0
- package/dist/devtools/identity-internal.d.ts +6 -0
- package/dist/devtools/identity-internal.js +5 -0
- package/dist/devtools/identity.d.ts +21 -0
- package/dist/devtools/identity.js +7 -0
- package/dist/devtools/index.d.ts +3 -0
- package/dist/devtools/index.js +2 -0
- package/dist/devtools/inspector.d.ts +18 -16
- package/dist/devtools/observer.d.ts +32 -28
- package/dist/devtools/runtime.js +34 -30
- package/dist/devtools/values.js +3 -5
- package/dist/generated/version.d.ts +1 -1
- package/dist/generated/version.js +1 -1
- package/dist/graph/model.d.ts +25 -14
- package/dist/http/auth.d.ts +4 -2
- package/dist/http/client.d.ts +6 -3
- package/dist/http/client.js +8 -9
- package/dist/http/cors-internal.d.ts +7 -5
- package/dist/http/cors-internal.js +8 -6
- package/dist/http/extension.d.ts +60 -21
- package/dist/http/extension.js +91 -20
- package/dist/http/identity.d.ts +20 -0
- package/dist/http/identity.js +10 -0
- package/dist/http/index.d.ts +6 -2
- package/dist/http/index.js +3 -1
- package/dist/http/openapi-identity.d.ts +9 -0
- package/dist/http/openapi-identity.js +4 -0
- package/dist/http/openapi.d.ts +1 -1
- package/dist/http/openapi.js +10 -7
- package/dist/http/path.d.ts +8 -5
- package/dist/http/route-validation.js +2 -1
- package/dist/http/runtime/request.d.ts +3 -2
- package/dist/http/runtime/request.js +1 -4
- package/dist/http/websocket-upgrade.d.ts +2 -0
- package/dist/http/websocket-upgrade.js +4 -0
- package/dist/internal/brand.d.ts +8 -0
- package/dist/internal/brand.js +1 -0
- package/dist/message-port/extension.d.ts +4 -2
- package/dist/message-port/extension.js +15 -8
- package/dist/message-port/identity.d.ts +9 -0
- package/dist/message-port/identity.js +16 -0
- package/dist/message-port/index.d.ts +2 -0
- package/dist/message-port/index.js +1 -0
- package/dist/message-port/transport.d.ts +4 -2
- package/dist/message-port/transport.js +6 -1
- package/dist/runtime/async-iterator-lifecycle.d.ts +2 -1
- package/dist/runtime/async-iterator-lifecycle.js +2 -1
- package/dist/runtime/capability.d.ts +6 -2
- package/dist/runtime/capability.js +3 -1
- package/dist/runtime/di.d.ts +1 -3
- package/dist/runtime/di.js +62 -35
- package/dist/runtime/error.d.ts +3 -1
- package/dist/runtime/index.d.ts +6 -2
- package/dist/runtime/index.js +3 -1
- package/dist/runtime/kernel.d.ts +0 -2
- package/dist/runtime/kernel.js +68 -30
- package/dist/runtime/logger-source.d.ts +4 -0
- package/dist/runtime/logger-source.js +47 -0
- package/dist/runtime/logger.d.ts +2 -38
- package/dist/runtime/logger.js +1 -209
- package/dist/runtime/node-capabilities.d.ts +1 -1
- package/dist/runtime/node-capabilities.js +2 -1
- package/dist/runtime/server-port.d.ts +5 -1
- package/dist/runtime/server-port.js +2 -1
- package/dist/runtime/shutdown-hooks.d.ts +1 -1
- package/dist/runtime/shutdown-hooks.js +5 -4
- package/dist/tasks/extension.d.ts +18 -16
- package/dist/tasks/extension.js +28 -23
- package/dist/tasks/identity.d.ts +9 -0
- package/dist/tasks/identity.js +4 -0
- package/dist/tasks/index.d.ts +1 -0
- package/dist/tasks/runtime/cron.d.ts +6 -2
- package/dist/tasks/runtime/cron.js +9 -0
- package/dist/websocket/extension.d.ts +19 -9
- package/dist/websocket/extension.js +103 -30
- package/dist/websocket/identity.d.ts +9 -0
- package/dist/websocket/identity.js +4 -0
- package/dist/websocket/index.d.ts +1 -0
- package/package.json +1 -1
|
@@ -2,3 +2,5 @@ export { defineMessagePortContract, defineMessagePortImplementation, messagePort
|
|
|
2
2
|
export { attachMessagePort } from './transport.js';
|
|
3
3
|
export type { MessagePortContext, MessagePortContract, MessagePortExecutionDefinition, MessagePortExtensionRuntime, MessagePortHandlers, MessagePortHostApi, MessagePortImplementationData, MessagePortResponseDefinition, MessagePortResult, MessagePortRouteDefinition, MessagePortServerStreamResponseDefinition, } from './extension.js';
|
|
4
4
|
export type { MessagePortHost, MessagePortLike } from './transport.js';
|
|
5
|
+
export { decodeMessagePortRequest, messagePortProcedureName, } from './identity.js';
|
|
6
|
+
export type { MessagePortRequestId, MessagePortProcedureName, } from './identity.js';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { type MessagePortProcedureName } from './identity.js';
|
|
1
2
|
export interface MessagePortHost {
|
|
2
|
-
invoke(method:
|
|
3
|
+
invoke(method: MessagePortProcedureName, input?: unknown): Promise<{
|
|
3
4
|
readonly response: string;
|
|
4
5
|
readonly value: unknown;
|
|
5
6
|
}>;
|
|
@@ -7,5 +8,6 @@ export interface MessagePortHost {
|
|
|
7
8
|
export type MessagePortLike = {
|
|
8
9
|
postMessage(value: unknown): void;
|
|
9
10
|
start?(): void;
|
|
10
|
-
|
|
11
|
+
addEventListener(type: 'message', listener: (event: unknown) => void): void;
|
|
12
|
+
};
|
|
11
13
|
export declare function attachMessagePort(host: MessagePortHost, port: MessagePortLike): void;
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import { decodeMessagePortRequest, } from './identity.js';
|
|
1
2
|
export function attachMessagePort(host, port) {
|
|
2
3
|
port.addEventListener('message', async (event) => {
|
|
3
|
-
|
|
4
|
+
if (typeof event !== 'object' || event === null || !('data' in event))
|
|
5
|
+
return;
|
|
6
|
+
const request = decodeMessagePortRequest(event.data);
|
|
7
|
+
if (!request)
|
|
8
|
+
return;
|
|
4
9
|
try {
|
|
5
10
|
const result = await host.invoke(request.procedure, request.input);
|
|
6
11
|
if (isAsyncIterable(result.value)) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type EpochMs } from '../core/units.js';
|
|
1
2
|
export declare class AsyncIteratorCleanupDeadlineError extends Error {
|
|
2
3
|
constructor(message: string);
|
|
3
4
|
}
|
|
@@ -8,5 +9,5 @@ export declare class AsyncIteratorLifecycle<T> {
|
|
|
8
9
|
next(): Promise<IteratorResult<T>>;
|
|
9
10
|
return(reason?: unknown): Promise<IteratorResult<T>>;
|
|
10
11
|
throw(error?: unknown): Promise<IteratorResult<T>>;
|
|
11
|
-
drain(reason: unknown, deadline: () =>
|
|
12
|
+
drain(reason: unknown, deadline: () => EpochMs | undefined, timeoutMessage: string): Promise<void>;
|
|
12
13
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { epochNow } from '../core/units.js';
|
|
1
2
|
const cleanupYieldInterval = 32;
|
|
2
3
|
export class AsyncIteratorCleanupDeadlineError extends Error {
|
|
3
4
|
constructor(message) {
|
|
@@ -56,7 +57,7 @@ export class AsyncIteratorLifecycle {
|
|
|
56
57
|
let continuationSteps = 0;
|
|
57
58
|
while (!this.#done) {
|
|
58
59
|
const currentDeadline = deadline();
|
|
59
|
-
if (currentDeadline !== undefined &&
|
|
60
|
+
if (currentDeadline !== undefined && epochNow() >= currentDeadline) {
|
|
60
61
|
throw new AsyncIteratorCleanupDeadlineError(timeoutMessage);
|
|
61
62
|
}
|
|
62
63
|
await this.next();
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
import type { Brand } from '../internal/brand.js';
|
|
2
|
+
export type RuntimeSupportFeature = Brand<string, 'runtime.support-feature'>;
|
|
3
|
+
export declare const runtimeSupportFeature: (value: string) => RuntimeSupportFeature;
|
|
4
|
+
export declare const runtimeSupportFeatures: (values: Iterable<string>) => ReadonlySet<RuntimeSupportFeature>;
|
|
5
|
+
export type RuntimeCapabilityId = RuntimeSupportFeature;
|
|
2
6
|
export interface RuntimeSupportProfile {
|
|
3
7
|
readonly runtime: string;
|
|
4
8
|
readonly capabilities: ReadonlySet<RuntimeCapabilityId>;
|
|
@@ -9,7 +13,7 @@ export interface RuntimeSupportCheck {
|
|
|
9
13
|
readonly supported: readonly RuntimeCapabilityId[];
|
|
10
14
|
readonly missing: readonly RuntimeCapabilityId[];
|
|
11
15
|
}
|
|
12
|
-
export declare function checkRuntimeSupport(required: Iterable<
|
|
16
|
+
export declare function checkRuntimeSupport(required: Iterable<string>, runtime: RuntimeSupportProfile): RuntimeSupportCheck;
|
|
13
17
|
export declare class MissingRuntimeSupportError extends Error {
|
|
14
18
|
readonly check: RuntimeSupportCheck;
|
|
15
19
|
constructor(check: RuntimeSupportCheck);
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
export const runtimeSupportFeature = (value) => value;
|
|
2
|
+
export const runtimeSupportFeatures = (values) => new Set([...values].map(runtimeSupportFeature));
|
|
1
3
|
export function checkRuntimeSupport(required, runtime) {
|
|
2
|
-
const requirements = [...
|
|
4
|
+
const requirements = [...runtimeSupportFeatures(required)];
|
|
3
5
|
const missing = requirements.filter((capability) => !runtime.capabilities.has(capability));
|
|
4
6
|
return {
|
|
5
7
|
ok: missing.length === 0,
|
package/dist/runtime/di.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { type ArgsClass, type EnvClass, type DependencyResolutionContext, type ProviderDescriptor, type TokenLike } from '../core/index.js';
|
|
2
|
-
import { Logger } from './logger.js';
|
|
3
2
|
export declare class DependencyResolutionError extends Error {
|
|
4
3
|
constructor(message: string);
|
|
5
4
|
}
|
|
@@ -7,7 +6,6 @@ export interface ContainerHooks {
|
|
|
7
6
|
created?(provider: ProviderDescriptor, value: unknown): void;
|
|
8
7
|
}
|
|
9
8
|
export interface ContainerOptions {
|
|
10
|
-
readonly logger?: Logger;
|
|
11
9
|
readonly dependencies?: ReadonlyMap<TokenLike, readonly TokenLike[]>;
|
|
12
10
|
readonly hooks?: ContainerHooks;
|
|
13
11
|
readonly environment?: ReadonlyMap<EnvClass, object>;
|
|
@@ -15,7 +13,7 @@ export interface ContainerOptions {
|
|
|
15
13
|
}
|
|
16
14
|
export declare class Container {
|
|
17
15
|
#private;
|
|
18
|
-
constructor(providers: readonly ProviderDescriptor[], options?:
|
|
16
|
+
constructor(providers: readonly ProviderDescriptor[], options?: ContainerOptions);
|
|
19
17
|
bindEnvironment(environment: EnvClass, value: object): void;
|
|
20
18
|
bindArguments(argumentsContract: ArgsClass, value: object): void;
|
|
21
19
|
resolve<T>(token: TokenLike<T>, context?: string | DependencyResolutionContext): T;
|
package/dist/runtime/di.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { isArgsClass, isEnvClass, runInInjectionContext, tokenName, } from '../core/index.js';
|
|
2
|
-
import {
|
|
2
|
+
import { LoggerToken } from './logger.js';
|
|
3
|
+
import { defaultLoggerProviders, isLogger, isLoggerToken, } from '../core/logger-internal.js';
|
|
4
|
+
import { bindLoggerSource } from './logger-source.js';
|
|
3
5
|
import { match } from 'ts-pattern';
|
|
4
6
|
export class DependencyResolutionError extends Error {
|
|
5
7
|
constructor(message) {
|
|
@@ -10,27 +12,39 @@ export class DependencyResolutionError extends Error {
|
|
|
10
12
|
export class Container {
|
|
11
13
|
#providers = new Map();
|
|
12
14
|
#applicationCache = new Map();
|
|
13
|
-
#
|
|
15
|
+
#loggerToken;
|
|
14
16
|
#dependencies;
|
|
15
17
|
#hooks;
|
|
16
18
|
#environment = new Map();
|
|
17
19
|
#arguments = new Map();
|
|
18
20
|
constructor(providers, options = {}) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
this.#
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
if (isLogger(options) || 'logger' in options) {
|
|
22
|
+
throw new DependencyResolutionError('LUTRE_LOGGER_CONFIGURATION: Register provide(LoggerToken).useClass(LoggerService) in providers.');
|
|
23
|
+
}
|
|
24
|
+
const configured = providers.find((provider) => isLoggerToken(provider.provide));
|
|
25
|
+
this.#loggerToken =
|
|
26
|
+
configured && isLoggerToken(configured.provide)
|
|
27
|
+
? configured.provide
|
|
28
|
+
: LoggerToken;
|
|
29
|
+
this.#dependencies = options.dependencies;
|
|
30
|
+
this.#hooks = options.hooks ?? {};
|
|
31
|
+
for (const [environment, value] of options.environment ?? []) {
|
|
32
|
+
this.#environment.set(environment, value);
|
|
33
|
+
}
|
|
34
|
+
for (const [argumentsContract, value] of options.arguments ?? []) {
|
|
35
|
+
this.#arguments.set(argumentsContract, value);
|
|
36
|
+
}
|
|
37
|
+
const declarations = configured
|
|
38
|
+
? providers
|
|
39
|
+
: [...providers, ...defaultLoggerProviders()];
|
|
40
|
+
for (const provider of declarations) {
|
|
41
|
+
if (isLoggerToken(provider.provide) && provider.scope !== 'application') {
|
|
42
|
+
throw new DependencyResolutionError('LUTRE_LOGGER_SCOPE: LoggerToken must have application scope.');
|
|
27
43
|
}
|
|
28
|
-
|
|
29
|
-
this.#
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
for (const provider of providers) {
|
|
33
|
-
const existing = this.#providers.get(provider.provide);
|
|
44
|
+
const key = isLoggerToken(provider.provide)
|
|
45
|
+
? this.#loggerToken
|
|
46
|
+
: provider.provide;
|
|
47
|
+
const existing = this.#providers.get(key);
|
|
34
48
|
if (existing) {
|
|
35
49
|
if (existing.kind === provider.kind &&
|
|
36
50
|
isRuntimeInputProvider(provider)) {
|
|
@@ -46,7 +60,7 @@ export class Container {
|
|
|
46
60
|
}
|
|
47
61
|
throw new DependencyResolutionError(`LUTRE_DI_DUPLICATE: Duplicate provider for ${tokenName(provider.provide)}`);
|
|
48
62
|
}
|
|
49
|
-
this.#providers.set(
|
|
63
|
+
this.#providers.set(key, provider);
|
|
50
64
|
}
|
|
51
65
|
}
|
|
52
66
|
bindEnvironment(environment, value) {
|
|
@@ -74,7 +88,8 @@ export class Container {
|
|
|
74
88
|
return this.#resolve(token, resolution?.source, [], resolution?.consumer);
|
|
75
89
|
}
|
|
76
90
|
get(token) {
|
|
77
|
-
const
|
|
91
|
+
const requested = isLoggerToken(token) ? this.#loggerToken : token;
|
|
92
|
+
const provider = this.#providers.get(requested);
|
|
78
93
|
if (!provider) {
|
|
79
94
|
if (isEnvClass(token)) {
|
|
80
95
|
throw new DependencyResolutionError(`LUTRE_ENV_002: ${token.name} is not declared by any Module.environment.`);
|
|
@@ -99,24 +114,23 @@ export class Container {
|
|
|
99
114
|
}
|
|
100
115
|
throw new DependencyResolutionError(`LUTRE_ARGS_005: Arguments ${provider.provide.name} requires runtime Arguments before Application initialization.`);
|
|
101
116
|
}
|
|
102
|
-
if (this.#applicationCache.has(
|
|
103
|
-
|
|
117
|
+
if (this.#applicationCache.has(requested)) {
|
|
118
|
+
const value = this.#applicationCache.get(requested);
|
|
119
|
+
return (isLoggerToken(requested) ? requireLogger(value) : value);
|
|
104
120
|
}
|
|
105
121
|
throw new DependencyResolutionError(`LUTRE_DI_NOT_INITIALIZED: ${tokenName(token)} has not been constructed by Application initialization.`);
|
|
106
122
|
}
|
|
107
123
|
#resolve(token, source, lineage = [], inquirer) {
|
|
108
|
-
const
|
|
124
|
+
const requested = isLoggerToken(token) ? this.#loggerToken : token;
|
|
125
|
+
const cycleStart = lineage.indexOf(requested);
|
|
109
126
|
if (cycleStart >= 0) {
|
|
110
|
-
const cycle = [...lineage.slice(cycleStart),
|
|
127
|
+
const cycle = [...lineage.slice(cycleStart), requested]
|
|
111
128
|
.map(tokenName)
|
|
112
129
|
.join(' -> ');
|
|
113
130
|
throw new DependencyResolutionError(`LUTRE_DI_CYCLE: Circular dependency detected: ${cycle}`);
|
|
114
131
|
}
|
|
115
|
-
const provider = this.#providers.get(
|
|
132
|
+
const provider = this.#providers.get(requested);
|
|
116
133
|
if (!provider) {
|
|
117
|
-
if (token === Logger) {
|
|
118
|
-
return this.#logger.child(source === undefined ? {} : { source });
|
|
119
|
-
}
|
|
120
134
|
if (isEnvClass(token)) {
|
|
121
135
|
throw new DependencyResolutionError(`LUTRE_ENV_002: ${token.name} is injected by ${source ?? 'Application'} but is not declared by any Module.environment.`);
|
|
122
136
|
}
|
|
@@ -125,16 +139,22 @@ export class Container {
|
|
|
125
139
|
}
|
|
126
140
|
throw new DependencyResolutionError(`LUTRE_DI_UNRESOLVED: ${source ?? 'Application'} requires ${tokenName(token)}, but no provider is declared for ${tokenName(token)}.`);
|
|
127
141
|
}
|
|
128
|
-
const nextLineage = [...lineage,
|
|
129
|
-
|
|
130
|
-
|
|
142
|
+
const nextLineage = [...lineage, requested];
|
|
143
|
+
let value;
|
|
144
|
+
if (provider.scope === 'application' &&
|
|
145
|
+
this.#applicationCache.has(requested)) {
|
|
146
|
+
value = this.#applicationCache.get(requested);
|
|
131
147
|
}
|
|
132
|
-
|
|
133
|
-
|
|
148
|
+
else {
|
|
149
|
+
value = this.#create(provider, nextLineage, inquirer);
|
|
150
|
+
if (provider.scope === 'application')
|
|
151
|
+
this.#applicationCache.set(requested, value);
|
|
134
152
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
153
|
+
if (isLoggerToken(requested)) {
|
|
154
|
+
const root = requireLogger(value);
|
|
155
|
+
return (source === undefined ? root : bindLoggerSource(root, source));
|
|
156
|
+
}
|
|
157
|
+
return value;
|
|
138
158
|
}
|
|
139
159
|
#create(provider, lineage, inquirer) {
|
|
140
160
|
try {
|
|
@@ -212,6 +232,12 @@ export class Container {
|
|
|
212
232
|
function isRuntimeInputProvider(provider) {
|
|
213
233
|
return provider.kind === 'environment' || provider.kind === 'arguments';
|
|
214
234
|
}
|
|
235
|
+
function requireLogger(value) {
|
|
236
|
+
if (!isLogger(value)) {
|
|
237
|
+
throw new DependencyResolutionError('LUTRE_LOGGER_VALUE: The root Logger Provider must return a LoggerService instance.');
|
|
238
|
+
}
|
|
239
|
+
return value;
|
|
240
|
+
}
|
|
215
241
|
function isThenable(value) {
|
|
216
242
|
return (((typeof value === 'object' && value !== null) ||
|
|
217
243
|
typeof value === 'function') &&
|
|
@@ -219,7 +245,8 @@ function isThenable(value) {
|
|
|
219
245
|
typeof value.then === 'function');
|
|
220
246
|
}
|
|
221
247
|
export function assertDeclaredDependency(consumer, token, dependencies) {
|
|
222
|
-
if (!dependencies.includes(token)
|
|
248
|
+
if (!dependencies.includes(token) &&
|
|
249
|
+
!(isLoggerToken(token) && dependencies.some(isLoggerToken))) {
|
|
223
250
|
throw new DependencyResolutionError(`LUTRE_DI_UNDECLARED_DEPENDENCY: ${consumer} requested ${tokenName(token)}, but it is not declared in the canonical Application Model. Declare dependencies unconditionally; construction metadata and runtime values must not add dependencies.`);
|
|
224
251
|
}
|
|
225
252
|
}
|
package/dist/runtime/error.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import type { Brand } from '../internal/brand.js';
|
|
2
|
+
export type ApplicationErrorId = Brand<string, 'runtime.application-error-id'>;
|
|
1
3
|
export interface NormalizedApplicationError {
|
|
2
4
|
readonly code: 'INTERNAL_ERROR';
|
|
3
|
-
readonly errorId:
|
|
5
|
+
readonly errorId: ApplicationErrorId;
|
|
4
6
|
readonly message: string;
|
|
5
7
|
readonly stack?: string;
|
|
6
8
|
readonly cause?: unknown;
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -3,10 +3,10 @@ export type { RuntimeCapabilityId, RuntimeSupportCheck, RuntimeSupportProfile, }
|
|
|
3
3
|
export { Container, DependencyResolutionError } from './di.js';
|
|
4
4
|
export type { ContainerOptions } from './di.js';
|
|
5
5
|
export { normalizeUnknownError } from './error.js';
|
|
6
|
-
export type { NormalizedApplicationError } from './error.js';
|
|
6
|
+
export type { NormalizedApplicationError, ApplicationErrorId } from './error.js';
|
|
7
7
|
export { assertRuntimeEngine, assertSupportedBunVersion, detectRuntimeEngine, } from './engine.js';
|
|
8
8
|
export type { RuntimeEngine } from './engine.js';
|
|
9
|
-
export { ConsoleLoggerBackend, JsonConsoleLoggerBackend,
|
|
9
|
+
export { ConsoleLoggerBackend, JsonConsoleLoggerBackend, LoggerService, LoggerToken, SilentLogger, } from './logger.js';
|
|
10
10
|
export type { ConsoleLoggerBackendOptions, LoggerBackend, LogLevel, LogRecord, } from './logger.js';
|
|
11
11
|
export { ApplicationKernelRuntime } from './kernel.js';
|
|
12
12
|
export type { ApplicationKernelRuntimeOptions } from './kernel.js';
|
|
@@ -17,3 +17,7 @@ export { ProcessShutdownHooks } from './shutdown-hooks.js';
|
|
|
17
17
|
export type { ProcessShutdownHooksOptions, ProcessSignalSource, ShutdownSignal, } from './shutdown-hooks.js';
|
|
18
18
|
export { ApplicationShutdownError, RuntimeShutdown } from './shutdown.js';
|
|
19
19
|
export type { RuntimeShutdownOptions } from './shutdown.js';
|
|
20
|
+
export { runtimeSupportFeature, runtimeSupportFeatures } from './capability.js';
|
|
21
|
+
export type { RuntimeSupportFeature } from './capability.js';
|
|
22
|
+
export { boundPort } from './server-port.js';
|
|
23
|
+
export type { RequestedPort, BoundPort } from './server-port.js';
|
package/dist/runtime/index.js
CHANGED
|
@@ -2,10 +2,12 @@ export { checkRuntimeSupport, MissingRuntimeSupportError, } from './capability.j
|
|
|
2
2
|
export { Container, DependencyResolutionError } from './di.js';
|
|
3
3
|
export { normalizeUnknownError } from './error.js';
|
|
4
4
|
export { assertRuntimeEngine, assertSupportedBunVersion, detectRuntimeEngine, } from './engine.js';
|
|
5
|
-
export { ConsoleLoggerBackend, JsonConsoleLoggerBackend,
|
|
5
|
+
export { ConsoleLoggerBackend, JsonConsoleLoggerBackend, LoggerService, LoggerToken, SilentLogger, } from './logger.js';
|
|
6
6
|
export { ApplicationKernelRuntime } from './kernel.js';
|
|
7
7
|
export { nodeRuntimeSupport } from './node-capabilities.js';
|
|
8
8
|
export { canRetryOnNextPort, initialServerPort } from './server-port.js';
|
|
9
9
|
export { serverUrl } from './server-url.js';
|
|
10
10
|
export { ProcessShutdownHooks } from './shutdown-hooks.js';
|
|
11
11
|
export { ApplicationShutdownError, RuntimeShutdown } from './shutdown.js';
|
|
12
|
+
export { runtimeSupportFeature, runtimeSupportFeatures } from './capability.js';
|
|
13
|
+
export { boundPort } from './server-port.js';
|
package/dist/runtime/kernel.d.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { RuntimeCapabilityRegistry, type ApplicationModel, type ExecutionExtension, type ExecutionExtensionRuntime, type ExecutionKernelRuntime, type ExecutionRuntimeBinding, type ExecutionLease, type ExecutionOperationLease, type RuntimeCapabilityBinding, type RuntimeExecutionMetadata, type RuntimeInstrumentation, type RuntimeInvocationRegistration, type RuntimeOperationMetadata, type TokenLike } from '../core/index.js';
|
|
2
2
|
import { Container } from './di.js';
|
|
3
|
-
import { Logger } from './logger.js';
|
|
4
3
|
export interface ApplicationKernelRuntimeOptions {
|
|
5
4
|
readonly capabilities?: readonly RuntimeCapabilityBinding[];
|
|
6
|
-
readonly logger?: Logger;
|
|
7
5
|
readonly environmentSource?: unknown;
|
|
8
6
|
readonly argumentsSource?: unknown;
|
|
9
7
|
readonly forceShutdownTimeoutMs?: number;
|
package/dist/runtime/kernel.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { milliseconds } from '../core/units.js';
|
|
1
2
|
import { ApplicationShutdownError } from './shutdown.js';
|
|
2
3
|
import { assertValidApplicationModel, loadArgs, loadEnv, RuntimeCapabilityRegistry, tokenName, } from '../core/index.js';
|
|
3
4
|
import { Container, assertDeclaredDependency } from './di.js';
|
|
4
5
|
import { ExecutionTracker } from './execution-tracker.js';
|
|
5
|
-
import {
|
|
6
|
+
import { LoggerToken } from './logger.js';
|
|
7
|
+
import { loggerLifecycleOwner } from './logger-source.js';
|
|
6
8
|
const defaultForceShutdownTimeoutMs = 5_000;
|
|
7
9
|
export class ApplicationKernelRuntime {
|
|
8
10
|
model;
|
|
@@ -10,6 +12,9 @@ export class ApplicationKernelRuntime {
|
|
|
10
12
|
capabilities;
|
|
11
13
|
#extensionRuntimes = new Map();
|
|
12
14
|
#providerInstances = new Map();
|
|
15
|
+
#createdInstances = [];
|
|
16
|
+
#trackedInstances = new Set();
|
|
17
|
+
#initializedInstanceCount = 0;
|
|
13
18
|
#providerNodes = new Map();
|
|
14
19
|
#executionBindings = new Map();
|
|
15
20
|
#initializedModuleIds = new Set();
|
|
@@ -23,6 +28,9 @@ export class ApplicationKernelRuntime {
|
|
|
23
28
|
#initialization;
|
|
24
29
|
#shutdown;
|
|
25
30
|
constructor(model, options = {}) {
|
|
31
|
+
if ('logger' in options) {
|
|
32
|
+
throw new TypeError('LUTRE_LOGGER_CONFIGURATION: Register provide(LoggerToken).useClass(LoggerService) in Module.providers; runtime Logger overrides are not supported.');
|
|
33
|
+
}
|
|
26
34
|
this.model = assertValidApplicationModel(model);
|
|
27
35
|
for (const node of this.model.nodes) {
|
|
28
36
|
if (node.kind === 'provider')
|
|
@@ -32,21 +40,19 @@ export class ApplicationKernelRuntime {
|
|
|
32
40
|
this.#environmentSource = options.environmentSource;
|
|
33
41
|
this.#argumentsSource =
|
|
34
42
|
'argumentsSource' in options ? options.argumentsSource : Object.freeze({});
|
|
35
|
-
this.#forceShutdownTimeoutMs =
|
|
36
|
-
options.forceShutdownTimeoutMs ?? defaultForceShutdownTimeoutMs;
|
|
43
|
+
this.#forceShutdownTimeoutMs = milliseconds(options.forceShutdownTimeoutMs ?? defaultForceShutdownTimeoutMs);
|
|
37
44
|
this.#instrumentation = options.instrumentation;
|
|
38
45
|
if (!Number.isFinite(this.#forceShutdownTimeoutMs) ||
|
|
39
46
|
this.#forceShutdownTimeoutMs < 0) {
|
|
40
47
|
throw new TypeError('LUTRE_FORCE_SHUTDOWN_TIMEOUT: forceShutdownTimeoutMs must be a non-negative finite number.');
|
|
41
48
|
}
|
|
42
49
|
this.container = new Container(model.providers, {
|
|
43
|
-
logger: options.logger ?? new Logger(),
|
|
44
50
|
dependencies: new Map([...this.#providerNodes.values()].map((node) => [
|
|
45
51
|
node.token,
|
|
46
52
|
node.dependencies,
|
|
47
53
|
])),
|
|
48
54
|
hooks: {
|
|
49
|
-
created: (provider, value) => this.#
|
|
55
|
+
created: (provider, value) => this.#onProviderCreated(provider, value),
|
|
50
56
|
},
|
|
51
57
|
});
|
|
52
58
|
for (const { extension, executions } of this.model.extensions) {
|
|
@@ -88,6 +94,8 @@ export class ApplicationKernelRuntime {
|
|
|
88
94
|
try {
|
|
89
95
|
this.#validateCapabilities();
|
|
90
96
|
await this.#bindRuntimeInputs();
|
|
97
|
+
this.container.resolve(LoggerToken);
|
|
98
|
+
await this.#initializeConstructedProviders();
|
|
91
99
|
await this.#initializeProviders();
|
|
92
100
|
for (const modelExtension of this.model.extensions) {
|
|
93
101
|
const runtime = await modelExtension.extension.createRuntime({
|
|
@@ -141,8 +149,6 @@ export class ApplicationKernelRuntime {
|
|
|
141
149
|
}
|
|
142
150
|
async #initializeProviders() {
|
|
143
151
|
for (const module of moduleNodes(this.model)) {
|
|
144
|
-
const instances = [];
|
|
145
|
-
this.#providerInstances.set(module.id, instances);
|
|
146
152
|
for (const providerNode of providerNodesOfModule(this.model, module.id)) {
|
|
147
153
|
const provider = providerNode.provider;
|
|
148
154
|
if (provider.scope !== 'application' ||
|
|
@@ -150,13 +156,15 @@ export class ApplicationKernelRuntime {
|
|
|
150
156
|
provider.kind === 'arguments') {
|
|
151
157
|
continue;
|
|
152
158
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
await callLifecycle(instance, 'onModuleInit');
|
|
159
|
+
this.container.resolve(provider.provide);
|
|
160
|
+
await this.#initializeConstructedProviders();
|
|
156
161
|
}
|
|
157
162
|
this.#initializedModuleIds.add(module.id);
|
|
158
163
|
await this.#runHook(lifecycleHookOf(this.model, module.id, 'onModuleInit'));
|
|
159
164
|
}
|
|
165
|
+
for (const instance of this.#providerInstances.get('application') ?? []) {
|
|
166
|
+
await callLifecycle(instance, 'onApplicationBootstrap');
|
|
167
|
+
}
|
|
160
168
|
for (const module of moduleNodes(this.model)) {
|
|
161
169
|
for (const instance of this.#providerInstances.get(module.id) ?? []) {
|
|
162
170
|
await callLifecycle(instance, 'onApplicationBootstrap');
|
|
@@ -164,6 +172,12 @@ export class ApplicationKernelRuntime {
|
|
|
164
172
|
await this.#runHook(lifecycleHookOf(this.model, module.id, 'onApplicationBootstrap'));
|
|
165
173
|
}
|
|
166
174
|
}
|
|
175
|
+
async #initializeConstructedProviders() {
|
|
176
|
+
while (this.#initializedInstanceCount < this.#createdInstances.length) {
|
|
177
|
+
const instance = this.#createdInstances[this.#initializedInstanceCount++];
|
|
178
|
+
await callLifecycle(instance, 'onModuleInit');
|
|
179
|
+
}
|
|
180
|
+
}
|
|
167
181
|
executionBindings(extension) {
|
|
168
182
|
const bindings = this.#executionBindings.get(extension.identity);
|
|
169
183
|
if (!bindings) {
|
|
@@ -211,7 +225,18 @@ export class ApplicationKernelRuntime {
|
|
|
211
225
|
beginOperation(metadata, invocation) {
|
|
212
226
|
return instrumentationLease(safely(() => this.#instrumentation?.beginOperation?.(metadata, invocation)));
|
|
213
227
|
}
|
|
214
|
-
#
|
|
228
|
+
#onProviderCreated(provider, value) {
|
|
229
|
+
const node = this.#providerNodes.get(provider);
|
|
230
|
+
const owner = loggerLifecycleOwner(value);
|
|
231
|
+
if (node &&
|
|
232
|
+
provider.scope === 'application' &&
|
|
233
|
+
!this.#trackedInstances.has(owner)) {
|
|
234
|
+
this.#trackedInstances.add(owner);
|
|
235
|
+
this.#createdInstances.push(owner);
|
|
236
|
+
const instances = this.#providerInstances.get(node.moduleId) ?? [];
|
|
237
|
+
instances.push(owner);
|
|
238
|
+
this.#providerInstances.set(node.moduleId, instances);
|
|
239
|
+
}
|
|
215
240
|
const instrumentation = this.#instrumentation;
|
|
216
241
|
if (!instrumentation?.providerCreated)
|
|
217
242
|
return;
|
|
@@ -305,6 +330,7 @@ export class ApplicationKernelRuntime {
|
|
|
305
330
|
}
|
|
306
331
|
this.#extensionDrainOperations.clear();
|
|
307
332
|
await this.#cleanupProviders(signal, errors);
|
|
333
|
+
await this.#disposeProviders(errors);
|
|
308
334
|
this.#state = 'stopped';
|
|
309
335
|
await closeInstrumentation(this.#instrumentation);
|
|
310
336
|
if (errors.length > 0) {
|
|
@@ -338,23 +364,28 @@ export class ApplicationKernelRuntime {
|
|
|
338
364
|
}
|
|
339
365
|
async #cleanupProviders(signal, errors) {
|
|
340
366
|
const modules = moduleNodes(this.model).toReversed();
|
|
341
|
-
for (const
|
|
342
|
-
|
|
343
|
-
|
|
367
|
+
for (const phase of [
|
|
368
|
+
'onModuleDestroy',
|
|
369
|
+
'beforeApplicationShutdown',
|
|
370
|
+
'onApplicationShutdown',
|
|
371
|
+
]) {
|
|
372
|
+
for (const module of modules) {
|
|
373
|
+
for (const instance of (this.#providerInstances.get(module.id) ?? []).toReversed()) {
|
|
374
|
+
await collectError(() => callLifecycle(instance, phase, phase === 'onModuleDestroy' ? undefined : signal), errors);
|
|
375
|
+
}
|
|
376
|
+
await collectError(() => this.#runCleanupHook(module.id, phase), errors);
|
|
344
377
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
for (const module of modules) {
|
|
348
|
-
for (const instance of (this.#providerInstances.get(module.id) ?? []).toReversed()) {
|
|
349
|
-
await collectError(() => callLifecycle(instance, 'beforeApplicationShutdown', signal), errors);
|
|
378
|
+
for (const instance of (this.#providerInstances.get('application') ?? []).toReversed()) {
|
|
379
|
+
await collectError(() => callLifecycle(instance, phase, phase === 'onModuleDestroy' ? undefined : signal), errors);
|
|
350
380
|
}
|
|
351
|
-
await collectError(() => this.#runCleanupHook(module.id, 'beforeApplicationShutdown'), errors);
|
|
352
381
|
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
382
|
+
}
|
|
383
|
+
async #disposeProviders(errors) {
|
|
384
|
+
for (const module of moduleNodes(this.model).toReversed()) {
|
|
385
|
+
await collectError(() => this.#runCleanupHook(module.id, 'onApplicationDispose'), errors);
|
|
386
|
+
}
|
|
387
|
+
for (const instance of this.#createdInstances.toReversed()) {
|
|
388
|
+
await collectError(() => callLifecycle(instance, 'onApplicationDispose'), errors);
|
|
358
389
|
}
|
|
359
390
|
}
|
|
360
391
|
async #rollbackInitialization() {
|
|
@@ -369,14 +400,21 @@ export class ApplicationKernelRuntime {
|
|
|
369
400
|
await collectError(() => callLifecycle(instance, 'onModuleDestroy'), errors);
|
|
370
401
|
}
|
|
371
402
|
}
|
|
403
|
+
for (const instance of (this.#providerInstances.get('application') ?? []).toReversed()) {
|
|
404
|
+
await collectError(() => callLifecycle(instance, 'onModuleDestroy'), errors);
|
|
405
|
+
}
|
|
406
|
+
await this.#disposeProviders(errors);
|
|
372
407
|
await closeInstrumentation(this.#instrumentation);
|
|
373
408
|
return errors;
|
|
374
409
|
}
|
|
375
|
-
async #runHook(
|
|
376
|
-
if (!
|
|
410
|
+
async #runHook(node) {
|
|
411
|
+
if (!node)
|
|
377
412
|
return;
|
|
378
|
-
const dependencies = hook.inject.map((token) => this.container.resolve(token
|
|
379
|
-
|
|
413
|
+
const dependencies = node.hook.inject.map((token) => this.container.resolve(token, {
|
|
414
|
+
source: node.id,
|
|
415
|
+
consumer: { id: node.id, name: node.phase, kind: 'lifecycle' },
|
|
416
|
+
}));
|
|
417
|
+
await node.hook.run(...dependencies);
|
|
380
418
|
}
|
|
381
419
|
async #runCleanupHook(moduleId, phase) {
|
|
382
420
|
if (!this.#initializedModuleIds.has(moduleId))
|
|
@@ -393,7 +431,7 @@ function providerNodesOfModule(model, moduleId) {
|
|
|
393
431
|
function lifecycleHookOf(model, moduleId, phase) {
|
|
394
432
|
return model.nodes.find((node) => node.kind === 'lifecycle' &&
|
|
395
433
|
node.moduleId === moduleId &&
|
|
396
|
-
node.phase === phase)
|
|
434
|
+
node.phase === phase);
|
|
397
435
|
}
|
|
398
436
|
function instrumentationLease(scope) {
|
|
399
437
|
return {
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { LoggerService } from './logger.js';
|
|
2
|
+
export declare function loggerLifecycleOwner(value: LoggerService): LoggerService;
|
|
3
|
+
export declare function loggerLifecycleOwner(value: unknown): unknown;
|
|
4
|
+
export declare function bindLoggerSource(logger: LoggerService, source: string): LoggerService;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { isLogger } from '../core/logger-internal.js';
|
|
2
|
+
import { loggerInstanceBrand, loggerSourceRoot, } from '../core/logger-identity.js';
|
|
3
|
+
export function loggerLifecycleOwner(value) {
|
|
4
|
+
if (!isLogger(value) || !(loggerSourceRoot in value))
|
|
5
|
+
return value;
|
|
6
|
+
let owner = value;
|
|
7
|
+
const visited = new Set();
|
|
8
|
+
while (loggerSourceRoot in owner && !visited.has(owner)) {
|
|
9
|
+
visited.add(owner);
|
|
10
|
+
const root = owner[loggerSourceRoot];
|
|
11
|
+
if (!isLogger(root))
|
|
12
|
+
break;
|
|
13
|
+
owner = root;
|
|
14
|
+
}
|
|
15
|
+
return owner;
|
|
16
|
+
}
|
|
17
|
+
export function bindLoggerSource(logger, source) {
|
|
18
|
+
const context = { ...logger.context, source };
|
|
19
|
+
const bind = (level) => (message, fields = {}) => logger[level](message, { source, ...fields });
|
|
20
|
+
const methods = {
|
|
21
|
+
debug: bind('debug'),
|
|
22
|
+
info: bind('info'),
|
|
23
|
+
warn: bind('warn'),
|
|
24
|
+
error: bind('error'),
|
|
25
|
+
};
|
|
26
|
+
const reference = {
|
|
27
|
+
[loggerInstanceBrand]: true,
|
|
28
|
+
[loggerSourceRoot]: loggerLifecycleOwner(logger),
|
|
29
|
+
backend: logger.backend,
|
|
30
|
+
context,
|
|
31
|
+
...methods,
|
|
32
|
+
onApplicationDispose: () => logger.onApplicationDispose(),
|
|
33
|
+
};
|
|
34
|
+
Object.setPrototypeOf(reference, Reflect.getPrototypeOf(logger));
|
|
35
|
+
// 凍結した元の実体を対象にすると、出力メソッドとcontextを委譲用に置き換えられない。
|
|
36
|
+
return new Proxy(reference, {
|
|
37
|
+
get(target, property) {
|
|
38
|
+
if (Object.hasOwn(target, property))
|
|
39
|
+
return Reflect.get(target, property);
|
|
40
|
+
// private fieldを持つ実装のreceiverをproxyへ置き換えない。
|
|
41
|
+
const value = Reflect.get(logger, property, logger);
|
|
42
|
+
return typeof value === 'function' && property !== 'constructor'
|
|
43
|
+
? value.bind(logger)
|
|
44
|
+
: value;
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
}
|