@loutrejs/loutre 0.5.0 → 0.6.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/README.md +63 -32
- package/dist/adapters/aws-lambda.d.ts +5 -3
- package/dist/adapters/aws-lambda.js +53 -23
- package/dist/adapters/bun.d.ts +7 -4
- package/dist/adapters/bun.js +52 -42
- package/dist/adapters/cloudflare-workers.d.ts +5 -3
- package/dist/adapters/cloudflare-workers.js +23 -28
- package/dist/adapters/deno.d.ts +7 -4
- package/dist/adapters/deno.js +94 -57
- package/dist/adapters/electron.d.ts +13 -5
- package/dist/adapters/electron.js +76 -28
- package/dist/application/definition.d.ts +31 -0
- package/dist/application/definition.js +16 -0
- package/dist/application/index.d.ts +4 -63
- package/dist/application/index.js +2 -11
- package/dist/application/kernel-internal.d.ts +2 -0
- package/dist/application/kernel-internal.js +10 -0
- package/dist/application/kernel.d.ts +21 -0
- package/dist/application/kernel.js +65 -0
- package/dist/core/diagnostic.d.ts +9 -0
- package/dist/core/diagnostic.js +9 -0
- package/dist/core/extension.d.ts +107 -0
- package/dist/core/extension.js +73 -0
- package/dist/core/generic-layer.d.ts +26 -0
- package/dist/core/generic-layer.js +116 -0
- package/dist/core/index.d.ts +31 -15
- package/dist/core/index.js +15 -15
- package/dist/core/injection.d.ts +4 -13
- package/dist/core/injection.js +63 -0
- package/dist/core/model/context.d.ts +18 -0
- package/dist/core/model/context.js +34 -0
- package/dist/core/model/lifecycle.d.ts +5 -0
- package/dist/core/model/lifecycle.js +44 -0
- package/dist/core/model/modules.d.ts +2 -0
- package/dist/core/model/modules.js +101 -0
- package/dist/core/model/providers.d.ts +4 -0
- package/dist/core/model/providers.js +74 -0
- package/dist/core/model/snapshot.d.ts +6 -0
- package/dist/core/model/snapshot.js +31 -0
- package/dist/core/model/types.d.ts +78 -0
- package/dist/core/model/validation.d.ts +4 -0
- package/dist/core/model/validation.js +40 -0
- package/dist/core/model/visibility.d.ts +4 -0
- package/dist/core/model/visibility.js +20 -0
- package/dist/core/model.d.ts +10 -0
- package/dist/core/model.js +346 -0
- package/dist/core/module.d.ts +8 -13
- package/dist/core/source-location.d.ts +8 -0
- package/dist/core/source-location.js +31 -0
- package/dist/core/token-internal.d.ts +3 -0
- package/dist/core/token-internal.js +4 -0
- package/dist/core/type.d.ts +7 -0
- package/dist/core/type.js +4 -0
- package/dist/generated/version.d.ts +1 -1
- package/dist/generated/version.js +1 -1
- package/dist/graph/index.d.ts +2 -3
- package/dist/graph/index.js +1 -3
- package/dist/graph/model.d.ts +34 -0
- package/dist/graph/model.js +127 -0
- package/dist/http/auth.d.ts +46 -0
- package/dist/http/auth.js +96 -0
- package/dist/http/client.d.ts +28 -31
- package/dist/http/client.js +58 -44
- package/dist/http/cors-internal.d.ts +29 -0
- package/dist/http/cors-internal.js +160 -0
- package/dist/http/cors.d.ts +5 -8
- package/dist/http/cors.js +7 -165
- package/dist/http/extension.d.ts +348 -0
- package/dist/http/extension.js +947 -0
- package/dist/http/index.d.ts +9 -7
- package/dist/http/index.js +5 -7
- package/dist/{application → http}/openapi.d.ts +12 -3
- package/dist/{application → http}/openapi.js +164 -102
- package/dist/http/path.d.ts +1 -42
- package/dist/http/path.js +1 -2
- package/dist/http/runtime/request.d.ts +17 -0
- package/dist/http/runtime/request.js +109 -0
- package/dist/http/runtime/response.d.ts +18 -0
- package/dist/http/runtime/response.js +108 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2 -0
- package/dist/message-port/extension.d.ts +66 -0
- package/dist/message-port/extension.js +395 -0
- package/dist/message-port/index.d.ts +4 -73
- package/dist/message-port/index.js +2 -189
- package/dist/message-port/transport.d.ts +11 -0
- package/dist/message-port/transport.js +45 -0
- package/dist/runtime/async-iterator-lifecycle.d.ts +12 -0
- package/dist/runtime/async-iterator-lifecycle.js +95 -0
- package/dist/runtime/capability.d.ts +11 -11
- package/dist/runtime/capability.js +3 -3
- package/dist/runtime/di.d.ts +2 -22
- package/dist/runtime/di.js +8 -285
- package/dist/runtime/execution-tracker.d.ts +8 -0
- package/dist/runtime/execution-tracker.js +54 -0
- package/dist/runtime/index.d.ts +15 -9
- package/dist/runtime/index.js +9 -9
- package/dist/runtime/ingress-gate.d.ts +7 -0
- package/dist/runtime/ingress-gate.js +33 -0
- package/dist/runtime/kernel.d.ts +23 -0
- package/dist/runtime/kernel.js +354 -0
- package/dist/runtime/logger.d.ts +2 -0
- package/dist/runtime/logger.js +2 -0
- package/dist/runtime/node-capabilities.d.ts +1 -1
- package/dist/runtime/node-capabilities.js +1 -1
- package/dist/runtime/server-port.d.ts +2 -0
- package/dist/runtime/server-port.js +11 -0
- package/dist/tasks/extension.d.ts +144 -0
- package/dist/tasks/extension.js +499 -0
- package/dist/tasks/index.d.ts +2 -0
- package/dist/tasks/index.js +1 -0
- package/dist/tasks/runtime/cron.d.ts +6 -0
- package/dist/tasks/runtime/cron.js +89 -0
- package/dist/websocket/errors.d.ts +9 -0
- package/dist/websocket/errors.js +18 -0
- package/dist/websocket/extension.d.ts +154 -0
- package/dist/websocket/extension.js +524 -0
- package/dist/websocket/index.d.ts +3 -0
- package/dist/websocket/index.js +2 -0
- package/package.json +12 -16
- package/dist/application/binding.d.ts +0 -33
- package/dist/application/binding.js +0 -295
- package/dist/application/host.d.ts +0 -8
- package/dist/application/host.js +0 -14
- package/dist/application/queue.d.ts +0 -3
- package/dist/application/queue.js +0 -4
- package/dist/application/scheduler.d.ts +0 -2
- package/dist/application/scheduler.js +0 -45
- package/dist/core/context-key.d.ts +0 -16
- package/dist/core/context-key.js +0 -17
- package/dist/core/contract-internal.d.ts +0 -22
- package/dist/core/contract-internal.js +0 -61
- package/dist/core/contract.d.ts +0 -96
- package/dist/core/contract.js +0 -88
- package/dist/core/execution.d.ts +0 -78
- package/dist/core/execution.js +0 -61
- package/dist/core/implementation.d.ts +0 -44
- package/dist/core/implementation.js +0 -35
- package/dist/core/layer.d.ts +0 -137
- package/dist/core/layer.js +0 -81
- package/dist/graph/compiler.d.ts +0 -4
- package/dist/graph/compiler.js +0 -228
- package/dist/graph/graph.d.ts +0 -18
- package/dist/graph/graph.js +0 -1118
- package/dist/graph/ir.d.ts +0 -175
- package/dist/http/application.d.ts +0 -18
- package/dist/http/application.js +0 -515
- package/dist/http/basic-auth.d.ts +0 -37
- package/dist/http/basic-auth.js +0 -67
- package/dist/http/definitions.d.ts +0 -363
- package/dist/http/definitions.js +0 -310
- package/dist/http/hosted-protocol.d.ts +0 -4
- package/dist/http/hosted-protocol.js +0 -4
- package/dist/http/internal.d.ts +0 -8
- package/dist/http/internal.js +0 -1
- package/dist/http/params.d.ts +0 -2
- package/dist/http/params.js +0 -19
- package/dist/http/request-body.d.ts +0 -4
- package/dist/http/request-body.js +0 -6
- package/dist/http/validate.d.ts +0 -20
- package/dist/http/validate.js +0 -6
- package/dist/message-port/environment.d.ts +0 -2
- package/dist/message-port/environment.js +0 -4
- package/dist/runtime/application.d.ts +0 -38
- package/dist/runtime/application.js +0 -339
- package/dist/runtime/pipeline.d.ts +0 -11
- package/dist/runtime/pipeline.js +0 -161
- /package/dist/{graph/ir.js → core/model/types.js} +0 -0
package/dist/adapters/deno.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createKernelApplication, } from '../application/index.js';
|
|
2
|
+
import { bindApplicationCapability } from '../application/kernel-internal.js';
|
|
3
|
+
import { httpExecutionExtension } from '../http/index.js';
|
|
2
4
|
import { LOUTRE_VERSION, startStartupPresentation } from '../presentation.js';
|
|
3
5
|
import { assertRuntimeEngine } from '../runtime/engine.js';
|
|
4
6
|
import { serverUrl } from '../runtime/server-url.js';
|
|
7
|
+
import { canRetryOnNextPort, initialServerPort, } from '../runtime/server-port.js';
|
|
5
8
|
export const denoRuntime = {
|
|
6
9
|
runtime: 'deno',
|
|
7
10
|
capabilities: new Set([
|
|
@@ -20,18 +23,29 @@ export const denoRuntime = {
|
|
|
20
23
|
};
|
|
21
24
|
function bind(options) {
|
|
22
25
|
assertRuntimeEngine('deno');
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
: undefined;
|
|
27
|
-
if (!http) {
|
|
28
|
-
void invocation.application.close();
|
|
29
|
-
throw new Error('LUTRE_RUNTIME_HTTP_REQUIRED: denoRuntime.bind() requires an HTTP-capable Application.');
|
|
26
|
+
if (options.application.model.extensions.get(httpExecutionExtension) ===
|
|
27
|
+
undefined) {
|
|
28
|
+
throw new Error('LUTRE_RUNTIME_HTTP_REQUIRED: denoRuntime.bind() requires the HTTP Execution Extension.');
|
|
30
29
|
}
|
|
31
|
-
const
|
|
30
|
+
const application = createKernelApplication({
|
|
31
|
+
...options,
|
|
32
|
+
application: options.application,
|
|
33
|
+
capabilities: [
|
|
34
|
+
bindApplicationCapability(options.application.model, 'http.server', {
|
|
35
|
+
runtime: 'deno',
|
|
36
|
+
}),
|
|
37
|
+
...(options.capabilities ?? []),
|
|
38
|
+
],
|
|
39
|
+
environment: 'environment' in options ? options.environment : denoEnvironment(),
|
|
40
|
+
});
|
|
41
|
+
let initialization;
|
|
32
42
|
return {
|
|
33
|
-
fetch
|
|
34
|
-
|
|
43
|
+
async fetch(request) {
|
|
44
|
+
initialization ??= application.init();
|
|
45
|
+
await initialization;
|
|
46
|
+
return application.http.fetch(request);
|
|
47
|
+
},
|
|
48
|
+
close: (signal) => application.close(signal),
|
|
35
49
|
};
|
|
36
50
|
}
|
|
37
51
|
async function create(options) {
|
|
@@ -46,42 +60,83 @@ async function create(options) {
|
|
|
46
60
|
},
|
|
47
61
|
write: (value) => console.log(value),
|
|
48
62
|
});
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
await host.application.close();
|
|
53
|
-
throw new Error('LUTRE_RUNTIME_HTTP_REQUIRED: denoRuntime.create() requires an HTTP-capable Application.');
|
|
63
|
+
if (options.application.model.extensions.get(httpExecutionExtension) ===
|
|
64
|
+
undefined) {
|
|
65
|
+
throw new Error('LUTRE_RUNTIME_HTTP_REQUIRED: denoRuntime.create() requires the HTTP Execution Extension.');
|
|
54
66
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
67
|
+
const hosted = createKernelApplication({
|
|
68
|
+
...options,
|
|
69
|
+
application: options.application,
|
|
70
|
+
capabilities: [
|
|
71
|
+
bindApplicationCapability(options.application.model, 'http.server', {
|
|
72
|
+
runtime: 'deno',
|
|
73
|
+
}),
|
|
74
|
+
...(options.capabilities ?? []),
|
|
75
|
+
],
|
|
76
|
+
environment: 'environment' in options ? options.environment : denoEnvironment(),
|
|
77
|
+
});
|
|
78
|
+
await hosted.init();
|
|
79
|
+
const application = hosted;
|
|
80
|
+
const http = hosted
|
|
81
|
+
.http;
|
|
82
|
+
const closeApplication = application.close.bind(application);
|
|
58
83
|
let server;
|
|
59
84
|
let removeShutdownHooks;
|
|
60
85
|
let serving = false;
|
|
61
86
|
let closed = false;
|
|
62
|
-
|
|
87
|
+
let closingPromise;
|
|
88
|
+
let serverClosingPromise;
|
|
89
|
+
const beginServerClose = () => {
|
|
90
|
+
if (serverClosingPromise)
|
|
91
|
+
return serverClosingPromise;
|
|
92
|
+
if (!server)
|
|
93
|
+
return Promise.resolve();
|
|
94
|
+
const closingServer = server;
|
|
95
|
+
serverClosingPromise = Promise.resolve()
|
|
96
|
+
.then(() => closingServer.shutdown())
|
|
97
|
+
.then(() => {
|
|
98
|
+
if (server === closingServer)
|
|
99
|
+
server = undefined;
|
|
100
|
+
}, (error) => {
|
|
101
|
+
serverClosingPromise = undefined;
|
|
102
|
+
throw error;
|
|
103
|
+
});
|
|
104
|
+
void serverClosingPromise.catch(() => undefined);
|
|
105
|
+
return serverClosingPromise;
|
|
106
|
+
};
|
|
107
|
+
const close = (signal) => {
|
|
63
108
|
if (closed)
|
|
64
|
-
return;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
109
|
+
return Promise.resolve();
|
|
110
|
+
if (closingPromise)
|
|
111
|
+
return closingPromise;
|
|
112
|
+
closingPromise = (async () => {
|
|
113
|
+
removeShutdownHooks?.();
|
|
114
|
+
removeShutdownHooks = undefined;
|
|
115
|
+
const errors = [];
|
|
116
|
+
const serverClosing = beginServerClose();
|
|
70
117
|
try {
|
|
71
|
-
await
|
|
118
|
+
await closeApplication(signal);
|
|
72
119
|
}
|
|
73
120
|
catch (error) {
|
|
74
121
|
errors.push(error);
|
|
75
122
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
123
|
+
if (errors.length === 0) {
|
|
124
|
+
try {
|
|
125
|
+
await serverClosing;
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
errors.push(error);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (errors.length > 0) {
|
|
132
|
+
throw new AggregateError(errors, 'Deno runtime shutdown failed');
|
|
133
|
+
}
|
|
134
|
+
closed = true;
|
|
135
|
+
})().catch((error) => {
|
|
136
|
+
closingPromise = undefined;
|
|
137
|
+
throw error;
|
|
138
|
+
});
|
|
139
|
+
return closingPromise;
|
|
85
140
|
};
|
|
86
141
|
const serve = async (serveOptions = {}) => {
|
|
87
142
|
if (closed) {
|
|
@@ -96,10 +151,8 @@ async function create(options) {
|
|
|
96
151
|
}
|
|
97
152
|
serving = true;
|
|
98
153
|
try {
|
|
99
|
-
if ('triggers' in application)
|
|
100
|
-
await application.triggers.start();
|
|
101
154
|
const requestedPort = serveOptions.port;
|
|
102
|
-
let port = requestedPort
|
|
155
|
+
let port = initialServerPort(requestedPort);
|
|
103
156
|
while (true) {
|
|
104
157
|
try {
|
|
105
158
|
server = deno.serve({
|
|
@@ -161,28 +214,12 @@ function registerDenoShutdownHooks(deno, close) {
|
|
|
161
214
|
}
|
|
162
215
|
return remove;
|
|
163
216
|
}
|
|
164
|
-
function canRetryOnNextPort(error, port) {
|
|
165
|
-
return port < 65_535 && isAddressInUseError(error);
|
|
166
|
-
}
|
|
167
|
-
function isAddressInUseError(error) {
|
|
168
|
-
return (typeof error === 'object' &&
|
|
169
|
-
error !== null &&
|
|
170
|
-
'code' in error &&
|
|
171
|
-
error.code === 'EADDRINUSE');
|
|
172
|
-
}
|
|
173
217
|
function createDenoFetchDriver(application) {
|
|
174
218
|
let initialization;
|
|
175
219
|
return async (request) => {
|
|
176
|
-
initialization ??= application.initialize();
|
|
220
|
+
initialization ??= application.initialize?.() ?? Promise.resolve();
|
|
177
221
|
await initialization;
|
|
178
|
-
return application.
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
function bindingOptions(options, environment) {
|
|
182
|
-
return {
|
|
183
|
-
application: options.application,
|
|
184
|
-
environment: 'environment' in options ? options.environment : environment,
|
|
185
|
-
...('arguments' in options ? { arguments: options.arguments } : {}),
|
|
222
|
+
return application.fetch(request);
|
|
186
223
|
};
|
|
187
224
|
}
|
|
188
225
|
function denoEnvironment() {
|
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
import { type ApplicationDefinition, type BootstrapArguments, type
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
type MessagePortApplication<TDefinition extends ApplicationDefinition> =
|
|
1
|
+
import { type ApplicationDefinition, type BootstrapArguments, type KernelHostedApplication, type RequireApplicationExtension } from '../application/index.js';
|
|
2
|
+
import type { RuntimeCapabilityBinding } from '../core/index.js';
|
|
3
|
+
import { messagePortExtension } from '../message-port/index.js';
|
|
4
|
+
type MessagePortApplication<TDefinition extends ApplicationDefinition> = RequireApplicationExtension<TDefinition, typeof messagePortExtension>;
|
|
5
|
+
export interface MessagePortLike {
|
|
6
|
+
postMessage(value: unknown): void;
|
|
7
|
+
addEventListener(type: 'message', listener: (event: {
|
|
8
|
+
readonly data: unknown;
|
|
9
|
+
}) => void): void;
|
|
10
|
+
start?(): void;
|
|
11
|
+
}
|
|
5
12
|
export interface ElectronMessagePortMainLike {
|
|
6
13
|
postMessage(value: unknown): void;
|
|
7
14
|
on(type: 'message', listener: (event: {
|
|
@@ -13,9 +20,10 @@ export type ElectronAttachOptions<TDefinition extends ApplicationDefinition> = {
|
|
|
13
20
|
readonly application: MessagePortApplication<TDefinition>;
|
|
14
21
|
readonly port: MessagePortLike | ElectronMessagePortMainLike;
|
|
15
22
|
readonly environment?: unknown;
|
|
23
|
+
readonly capabilities?: readonly RuntimeCapabilityBinding[];
|
|
16
24
|
} & BootstrapArguments<TDefinition>;
|
|
17
25
|
export interface ElectronAttachment<TDefinition extends ApplicationDefinition = ApplicationDefinition> {
|
|
18
|
-
readonly application:
|
|
26
|
+
readonly application: KernelHostedApplication<TDefinition>;
|
|
19
27
|
close(signal?: string): Promise<void>;
|
|
20
28
|
}
|
|
21
29
|
export declare const electronRuntime: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { createKernelApplication, } from '../application/index.js';
|
|
2
|
+
import { messagePortExtension } from '../message-port/index.js';
|
|
3
3
|
import { assertRuntimeEngine } from '../runtime/engine.js';
|
|
4
4
|
export const electronRuntime = {
|
|
5
5
|
runtime: 'electron',
|
|
@@ -17,38 +17,86 @@ export const electronRuntime = {
|
|
|
17
17
|
};
|
|
18
18
|
function attach(options) {
|
|
19
19
|
assertRuntimeEngine('electron');
|
|
20
|
-
|
|
20
|
+
if (options.application.model.extensions.get(messagePortExtension) === undefined) {
|
|
21
|
+
throw new Error('LUTRE_RUNTIME_MESSAGE_PORT_REQUIRED: electronRuntime.attach() requires the MessagePort Execution Extension.');
|
|
22
|
+
}
|
|
23
|
+
const environment = 'environment' in options
|
|
24
|
+
? options.environment
|
|
25
|
+
: typeof process === 'undefined'
|
|
26
|
+
? undefined
|
|
27
|
+
: process.env;
|
|
28
|
+
const application = createKernelApplication({
|
|
29
|
+
...options,
|
|
21
30
|
application: options.application,
|
|
22
|
-
environment
|
|
23
|
-
? options.environment
|
|
24
|
-
: typeof process === 'undefined'
|
|
25
|
-
? undefined
|
|
26
|
-
: process.env,
|
|
27
|
-
...('arguments' in options ? { arguments: options.arguments } : {}),
|
|
31
|
+
environment,
|
|
28
32
|
});
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
attachElectronMessagePort(messagePort, options.port);
|
|
33
|
+
const initialization = application.init();
|
|
34
|
+
void initialization.catch(() => undefined);
|
|
35
|
+
attachElectronMessagePortInvocation(async (method, input) => {
|
|
36
|
+
await initialization;
|
|
37
|
+
const host = application.messagePort;
|
|
38
|
+
return host.invoke(method, input);
|
|
39
|
+
}, options.port);
|
|
37
40
|
return {
|
|
38
|
-
application
|
|
39
|
-
close: (signal) =>
|
|
41
|
+
application,
|
|
42
|
+
close: (signal) => application.close(signal),
|
|
40
43
|
};
|
|
41
44
|
}
|
|
42
|
-
function
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
function attachElectronMessagePortInvocation(invoke, port) {
|
|
46
|
+
const normalized = normalizeMessagePort(port);
|
|
47
|
+
normalized.addEventListener('message', async (event) => {
|
|
48
|
+
const request = event.data;
|
|
49
|
+
try {
|
|
50
|
+
const result = await invoke(request.procedure, request.input);
|
|
51
|
+
if (isAsyncIterable(result.value)) {
|
|
52
|
+
for await (const value of result.value) {
|
|
53
|
+
postToMessagePort(normalized, {
|
|
54
|
+
id: request.id,
|
|
55
|
+
response: result.response,
|
|
56
|
+
value,
|
|
57
|
+
done: false,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
postToMessagePort(normalized, {
|
|
61
|
+
id: request.id,
|
|
62
|
+
response: result.response,
|
|
63
|
+
done: true,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
postToMessagePort(normalized, {
|
|
68
|
+
id: request.id,
|
|
69
|
+
response: result.response,
|
|
70
|
+
value: result.value,
|
|
71
|
+
done: true,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
postToMessagePort(normalized, {
|
|
77
|
+
id: request.id,
|
|
78
|
+
error: error instanceof Error ? error.message : String(error),
|
|
79
|
+
done: true,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
normalized.start?.();
|
|
84
|
+
}
|
|
85
|
+
function postToMessagePort(port, value) {
|
|
86
|
+
port.postMessage(value);
|
|
87
|
+
}
|
|
88
|
+
function normalizeMessagePort(port) {
|
|
89
|
+
if ('addEventListener' in port)
|
|
90
|
+
return port;
|
|
91
|
+
return {
|
|
50
92
|
postMessage: (value) => port.postMessage(value),
|
|
51
93
|
addEventListener: (_type, listener) => port.on('message', listener),
|
|
52
94
|
start: () => port.start(),
|
|
53
|
-
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function isAsyncIterable(value) {
|
|
98
|
+
return (typeof value === 'object' &&
|
|
99
|
+
value !== null &&
|
|
100
|
+
Symbol.asyncIterator in value &&
|
|
101
|
+
typeof value[Symbol.asyncIterator] === 'function');
|
|
54
102
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/// <reference lib="esnext.disposable" preserve="true" />
|
|
2
|
+
import type { ArgsClass, ApplicationModel, ExecutionExtension, HostApiOfExtension, ModuleExtensions, ModuleInstance, SchemaInput } from '../core/index.js';
|
|
3
|
+
import type { Logger } from '../runtime/index.js';
|
|
4
|
+
export interface ApplicationDefinitionOptions<TModules extends readonly ModuleInstance[], TArguments extends ArgsClass | undefined> {
|
|
5
|
+
readonly modules: TModules;
|
|
6
|
+
readonly arguments?: TArguments;
|
|
7
|
+
readonly logger?: Logger;
|
|
8
|
+
}
|
|
9
|
+
export interface ApplicationDefinition<TModules extends readonly ModuleInstance[] = readonly ModuleInstance[], TArguments extends ArgsClass | undefined = ArgsClass | undefined> {
|
|
10
|
+
readonly kind: 'application-definition';
|
|
11
|
+
readonly model: ApplicationModel;
|
|
12
|
+
readonly modules: TModules;
|
|
13
|
+
readonly arguments: TArguments;
|
|
14
|
+
readonly logger?: Logger;
|
|
15
|
+
}
|
|
16
|
+
export declare function defineApplication<const TModules extends readonly ModuleInstance[], const TArguments extends ArgsClass | undefined = undefined>(options: ApplicationDefinitionOptions<TModules, TArguments>): ApplicationDefinition<TModules, TArguments>;
|
|
17
|
+
export type ApplicationArgumentsInput<TDefinition extends ApplicationDefinition> = TDefinition['arguments'] extends ArgsClass<infer TSchema> ? SchemaInput<TSchema> : never;
|
|
18
|
+
export type BootstrapArguments<TDefinition extends ApplicationDefinition> = TDefinition['arguments'] extends ArgsClass<infer TSchema> ? {} extends SchemaInput<TSchema> ? {
|
|
19
|
+
readonly arguments?: SchemaInput<TSchema>;
|
|
20
|
+
} : {
|
|
21
|
+
readonly arguments: SchemaInput<TSchema>;
|
|
22
|
+
} : {
|
|
23
|
+
readonly arguments?: never;
|
|
24
|
+
};
|
|
25
|
+
type UnionToIntersection<TUnion> = (TUnion extends unknown ? (value: TUnion) => void : never) extends (value: infer TIntersection) => void ? TIntersection : never;
|
|
26
|
+
export type ApplicationExtensions<TDefinition extends ApplicationDefinition> = ModuleExtensions<TDefinition['modules'][number]>;
|
|
27
|
+
export type ApplicationExtensionHostApis<TDefinition extends ApplicationDefinition> = UnionToIntersection<HostApiOfExtension<ApplicationExtensions<TDefinition>>>;
|
|
28
|
+
type IsAny<TValue> = 0 extends 1 & TValue ? true : false;
|
|
29
|
+
export type RequireApplicationHost<TDefinition extends ApplicationDefinition, TNamespace extends PropertyKey> = IsAny<TDefinition> extends true ? TDefinition : TNamespace extends keyof ApplicationExtensionHostApis<TDefinition> ? TDefinition : never;
|
|
30
|
+
export type RequireApplicationExtension<TDefinition extends ApplicationDefinition, TExtension extends ExecutionExtension> = IsAny<TDefinition> extends true ? TDefinition : [Extract<ApplicationExtensions<TDefinition>, TExtension>] extends [never] ? never : TDefinition;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/// <reference lib="esnext.disposable" preserve="true" />
|
|
2
|
+
import { buildApplicationModel } from '../core/index.js';
|
|
3
|
+
export function defineApplication(options) {
|
|
4
|
+
return Object.freeze({
|
|
5
|
+
kind: 'application-definition',
|
|
6
|
+
model: buildApplicationModel({
|
|
7
|
+
modules: options.modules,
|
|
8
|
+
...(options.arguments === undefined
|
|
9
|
+
? {}
|
|
10
|
+
: { arguments: options.arguments }),
|
|
11
|
+
}),
|
|
12
|
+
modules: options.modules,
|
|
13
|
+
arguments: options.arguments,
|
|
14
|
+
...(options.logger === undefined ? {} : { logger: options.logger }),
|
|
15
|
+
});
|
|
16
|
+
}
|
|
@@ -1,63 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export
|
|
5
|
-
readonly modules: TModules;
|
|
6
|
-
readonly arguments?: TArguments;
|
|
7
|
-
readonly tasks?: TTasks;
|
|
8
|
-
readonly triggers?: TTriggers;
|
|
9
|
-
readonly logger?: Logger;
|
|
10
|
-
}
|
|
11
|
-
export interface ApplicationDefinition<TModules extends readonly ModuleInstance[] = readonly ModuleInstance[], TArguments extends ArgsClass | undefined = ArgsClass | undefined, TTasks extends readonly TaskDescriptor<any, any>[] = readonly TaskDescriptor<any, any>[], TTriggers extends readonly TriggerDescriptor[] = readonly TriggerDescriptor[]> {
|
|
12
|
-
readonly kind: 'application-definition';
|
|
13
|
-
readonly modules: TModules;
|
|
14
|
-
readonly arguments: TArguments;
|
|
15
|
-
readonly tasks: TTasks;
|
|
16
|
-
readonly triggers: TTriggers;
|
|
17
|
-
readonly logger?: Logger;
|
|
18
|
-
}
|
|
19
|
-
export declare function defineApplication<const TModules extends readonly ModuleInstance[], const TArguments extends ArgsClass | undefined = undefined, const TTasks extends readonly TaskDescriptor<any, any>[] = readonly [], const TTriggers extends readonly TriggerDescriptor[] = readonly []>(options: ApplicationDefinitionOptions<TModules, TArguments, TTasks, TTriggers>): ApplicationDefinition<TModules, TArguments, TTasks, TTriggers>;
|
|
20
|
-
export type ApplicationArgumentsInput<TDefinition extends ApplicationDefinition> = TDefinition['arguments'] extends ArgsClass<infer TSchema> ? SchemaInput<TSchema> : never;
|
|
21
|
-
export type BootstrapArguments<TDefinition extends ApplicationDefinition> = TDefinition['arguments'] extends ArgsClass<infer TSchema> ? {} extends SchemaInput<TSchema> ? {
|
|
22
|
-
readonly arguments?: SchemaInput<TSchema>;
|
|
23
|
-
} : {
|
|
24
|
-
readonly arguments: SchemaInput<TSchema>;
|
|
25
|
-
} : {
|
|
26
|
-
readonly arguments?: never;
|
|
27
|
-
};
|
|
28
|
-
export interface BaseApplication {
|
|
29
|
-
readonly graph: ApplicationGraphIR;
|
|
30
|
-
get<TToken extends TokenLike>(token: TToken): TokenValue<TToken>;
|
|
31
|
-
init(): Promise<this>;
|
|
32
|
-
close(signal?: string): Promise<void>;
|
|
33
|
-
}
|
|
34
|
-
export interface TaskApplicationCapability<TTasks extends readonly TaskDescriptor<any, any>[]> {
|
|
35
|
-
run<TTask extends TTasks[number]>(task: TTask, ...args: TaskArguments<TTask>): Promise<TaskOutput<TTask>>;
|
|
36
|
-
}
|
|
37
|
-
export interface HttpApplicationCapability {
|
|
38
|
-
fetch(request: Request): Promise<Response>;
|
|
39
|
-
}
|
|
40
|
-
export interface TriggerApplicationCapability {
|
|
41
|
-
readonly triggers: {
|
|
42
|
-
start(): Promise<void>;
|
|
43
|
-
stop(): Promise<void>;
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
export interface QueueConsumerHandle {
|
|
47
|
-
stop(): Promise<void>;
|
|
48
|
-
}
|
|
49
|
-
export interface QueueConsumerDriver {
|
|
50
|
-
start(options: {
|
|
51
|
-
consume(payload: unknown): Promise<void>;
|
|
52
|
-
}): Promise<QueueConsumerHandle>;
|
|
53
|
-
}
|
|
54
|
-
export type HasProtocol<TDefinition extends ApplicationDefinition, TProtocol extends string> = Extract<ModuleProtocols<TDefinition['modules'][number]>, TProtocol> extends never ? false : true;
|
|
55
|
-
export type HasHttp<TDefinition extends ApplicationDefinition> = HasProtocol<TDefinition, 'http'>;
|
|
56
|
-
export type HasMessagePort<TDefinition extends ApplicationDefinition> = HasProtocol<TDefinition, 'messagePort'>;
|
|
57
|
-
export type HasTasks<TDefinition extends ApplicationDefinition> = TDefinition['tasks'] extends readonly [] ? false : true;
|
|
58
|
-
export type HasTriggers<TDefinition extends ApplicationDefinition> = TDefinition['triggers'] extends readonly [] ? false : true;
|
|
59
|
-
type TaskCapability<TDefinition extends ApplicationDefinition> = TDefinition['tasks'] extends readonly [] ? {} : TaskApplicationCapability<TDefinition['tasks']>;
|
|
60
|
-
export type HostedApplication<TDefinition extends ApplicationDefinition> = BaseApplication & TaskCapability<TDefinition> & (HasHttp<TDefinition> extends true ? HttpApplicationCapability : {}) & (HasTriggers<TDefinition> extends true ? TriggerApplicationCapability : {});
|
|
61
|
-
export type InvocationApplication<TDefinition extends ApplicationDefinition> = BaseApplication & TaskCapability<TDefinition>;
|
|
62
|
-
export { binding } from './binding.js';
|
|
63
|
-
export type { HostBinding, HostBindingApplication, InvocationBinding, InvocationBindingBaseOptions, InvocationBindingOptions, } from './binding.js';
|
|
1
|
+
export { defineApplication } from './definition.js';
|
|
2
|
+
export type { ApplicationArgumentsInput, ApplicationDefinition, ApplicationDefinitionOptions, ApplicationExtensionHostApis, ApplicationExtensions, BootstrapArguments, RequireApplicationExtension, RequireApplicationHost, } from './definition.js';
|
|
3
|
+
export { bootstrapApplication, createKernelApplication } from './kernel.js';
|
|
4
|
+
export type { KernelApplicationBase, KernelApplicationOptions, KernelHostedApplication, } from './kernel.js';
|
|
@@ -1,11 +1,2 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
kind: 'application-definition',
|
|
4
|
-
modules: options.modules,
|
|
5
|
-
arguments: options.arguments,
|
|
6
|
-
tasks: options.tasks ?? [],
|
|
7
|
-
triggers: options.triggers ?? [],
|
|
8
|
-
...(options.logger === undefined ? {} : { logger: options.logger }),
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
|
-
export { binding } from './binding.js';
|
|
1
|
+
export { defineApplication } from './definition.js';
|
|
2
|
+
export { bootstrapApplication, createKernelApplication } from './kernel.js';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { bindRuntimeCapability, } from '../core/index.js';
|
|
2
|
+
export function bindApplicationCapability(model, id, value) {
|
|
3
|
+
const capability = model.executions
|
|
4
|
+
.flatMap((execution) => execution.capabilities)
|
|
5
|
+
.find((candidate) => candidate.id === id);
|
|
6
|
+
if (!capability) {
|
|
7
|
+
throw new Error(`LUTRE_CAPABILITY_NOT_REQUIRED: ${id}`);
|
|
8
|
+
}
|
|
9
|
+
return bindRuntimeCapability(capability, value);
|
|
10
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/// <reference lib="esnext.disposable" preserve="true" />
|
|
2
|
+
import type { RuntimeCapabilityBinding, TokenLike, TokenValue } from '../core/index.js';
|
|
3
|
+
import { type ApplicationModelGraphIR } from '../graph/index.js';
|
|
4
|
+
import { type Logger } from '../runtime/index.js';
|
|
5
|
+
import type { ApplicationDefinition, ApplicationExtensionHostApis, BootstrapArguments } from './definition.js';
|
|
6
|
+
export interface KernelApplicationBase extends AsyncDisposable {
|
|
7
|
+
readonly graph: ApplicationModelGraphIR;
|
|
8
|
+
init(): Promise<this>;
|
|
9
|
+
get<TToken extends TokenLike>(token: TToken): TokenValue<TToken>;
|
|
10
|
+
close(signal?: string): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
export type KernelHostedApplication<TDefinition extends ApplicationDefinition> = KernelApplicationBase & ApplicationExtensionHostApis<TDefinition>;
|
|
13
|
+
export type KernelApplicationOptions<TDefinition extends ApplicationDefinition> = {
|
|
14
|
+
readonly application: TDefinition;
|
|
15
|
+
readonly capabilities?: readonly RuntimeCapabilityBinding[];
|
|
16
|
+
readonly environment?: unknown;
|
|
17
|
+
readonly logger?: Logger;
|
|
18
|
+
readonly forceShutdownTimeoutMs?: number;
|
|
19
|
+
} & BootstrapArguments<TDefinition>;
|
|
20
|
+
export declare function createKernelApplication<const TDefinition extends ApplicationDefinition>(options: KernelApplicationOptions<TDefinition>): KernelHostedApplication<TDefinition>;
|
|
21
|
+
export declare function bootstrapApplication<const TDefinition extends ApplicationDefinition>(options: KernelApplicationOptions<TDefinition>): Promise<KernelHostedApplication<TDefinition>>;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/// <reference lib="esnext.disposable" preserve="true" />
|
|
2
|
+
import { projectApplicationModel, } from '../graph/index.js';
|
|
3
|
+
import { ApplicationKernelRuntime } from '../runtime/index.js';
|
|
4
|
+
export function createKernelApplication(options) {
|
|
5
|
+
const logger = options.logger ?? options.application.logger;
|
|
6
|
+
const runtime = new ApplicationKernelRuntime(options.application.model, {
|
|
7
|
+
...options,
|
|
8
|
+
...(logger === undefined ? {} : { logger }),
|
|
9
|
+
...('environment' in options
|
|
10
|
+
? { environmentSource: options.environment }
|
|
11
|
+
: {}),
|
|
12
|
+
...('arguments' in options ? { argumentsSource: options.arguments } : {}),
|
|
13
|
+
});
|
|
14
|
+
let initialized = false;
|
|
15
|
+
const application = Object.assign(Object.create(null), {
|
|
16
|
+
graph: projectApplicationModel(options.application.model),
|
|
17
|
+
async init() {
|
|
18
|
+
await runtime.initialize();
|
|
19
|
+
if (initialized)
|
|
20
|
+
return application;
|
|
21
|
+
const createdNamespaces = [];
|
|
22
|
+
try {
|
|
23
|
+
for (const modelExtension of options.application.model.extensions) {
|
|
24
|
+
const host = modelExtension.extension.host;
|
|
25
|
+
if (!host)
|
|
26
|
+
continue;
|
|
27
|
+
application[host.namespace] = host.create({
|
|
28
|
+
executions: modelExtension.executions,
|
|
29
|
+
runtime: runtime.extensionRuntime(modelExtension.extension),
|
|
30
|
+
applicationRuntime: runtime,
|
|
31
|
+
});
|
|
32
|
+
createdNamespaces.push(host.namespace);
|
|
33
|
+
}
|
|
34
|
+
initialized = true;
|
|
35
|
+
return application;
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
for (const namespace of createdNamespaces)
|
|
39
|
+
delete application[namespace];
|
|
40
|
+
try {
|
|
41
|
+
await runtime.shutdown();
|
|
42
|
+
}
|
|
43
|
+
catch (cleanupError) {
|
|
44
|
+
throw new AggregateError([error, cleanupError], 'Host API creation failed and runtime rollback also failed.', { cause: cleanupError });
|
|
45
|
+
}
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
get(token) {
|
|
50
|
+
return runtime.get(token);
|
|
51
|
+
},
|
|
52
|
+
close(signal) {
|
|
53
|
+
return runtime.shutdown(signal);
|
|
54
|
+
},
|
|
55
|
+
[Symbol.asyncDispose]() {
|
|
56
|
+
return application.close();
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
return application;
|
|
60
|
+
}
|
|
61
|
+
export async function bootstrapApplication(options) {
|
|
62
|
+
const application = createKernelApplication(options);
|
|
63
|
+
await application.init();
|
|
64
|
+
return application;
|
|
65
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface Diagnostic {
|
|
2
|
+
readonly code: string;
|
|
3
|
+
readonly message: string;
|
|
4
|
+
readonly path: string;
|
|
5
|
+
readonly severity?: 'error' | 'warning';
|
|
6
|
+
}
|
|
7
|
+
export declare function isErrorDiagnostic(item: Diagnostic): boolean;
|
|
8
|
+
export declare function hasErrorDiagnostics(diagnostics: readonly Diagnostic[]): boolean;
|
|
9
|
+
export declare function diagnostic(code: string, message: string, path: string, severity?: Diagnostic['severity']): Diagnostic;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function isErrorDiagnostic(item) {
|
|
2
|
+
return (item.severity ?? 'error') === 'error';
|
|
3
|
+
}
|
|
4
|
+
export function hasErrorDiagnostics(diagnostics) {
|
|
5
|
+
return diagnostics.some(isErrorDiagnostic);
|
|
6
|
+
}
|
|
7
|
+
export function diagnostic(code, message, path, severity = 'error') {
|
|
8
|
+
return Object.freeze({ code, message, path, severity });
|
|
9
|
+
}
|