@loutrejs/loutre 0.5.0 → 0.7.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 +22 -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 +118 -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 +32 -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/instrumentation.d.ts +36 -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/types.js +1 -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/devtools/capsule.d.ts +51 -0
- package/dist/devtools/capsule.js +245 -0
- package/dist/devtools/index.d.ts +11 -0
- package/dist/devtools/index.js +6 -0
- package/dist/devtools/inspector.d.ts +57 -0
- package/dist/devtools/inspector.js +1 -0
- package/dist/devtools/module.d.ts +18 -0
- package/dist/devtools/module.js +26 -0
- package/dist/devtools/observer.d.ts +77 -0
- package/dist/devtools/observer.js +10 -0
- package/dist/devtools/protocol.d.ts +1 -0
- package/dist/devtools/protocol.js +1 -0
- package/dist/devtools/provider-instrumentation.d.ts +14 -0
- package/dist/devtools/provider-instrumentation.js +117 -0
- package/dist/devtools/runtime.d.ts +20 -0
- package/dist/devtools/runtime.js +519 -0
- package/dist/devtools/values.d.ts +35 -0
- package/dist/devtools/values.js +175 -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 +1061 -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 +411 -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 +5 -21
- package/dist/runtime/di.js +22 -289
- 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 +25 -0
- package/dist/runtime/kernel.js +447 -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 +525 -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 +533 -0
- package/dist/websocket/index.d.ts +3 -0
- package/dist/websocket/index.js +2 -0
- package/package.json +16 -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/instrumentation.js} +0 -0
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { diagnostic, isErrorDiagnostic } from './diagnostic.js';
|
|
2
|
+
import { isExecutionDefinition, } from './extension.js';
|
|
3
|
+
import { isFrameworkProvidedToken } from './token-internal.js';
|
|
4
|
+
import { tokenName } from './token.js';
|
|
5
|
+
import { createModelBuildContext } from './model/context.js';
|
|
6
|
+
import { resolveLifecycleDependencies } from './model/lifecycle.js';
|
|
7
|
+
import { collectModuleDeclarations } from './model/modules.js';
|
|
8
|
+
import { compileArgumentsProvider, resolveModuleExports, resolveProviderDependencies, } from './model/providers.js';
|
|
9
|
+
import { snapshotExecutionExtension } from './model/snapshot.js';
|
|
10
|
+
import { validateHostNamespaces, validateNodeIds } from './model/validation.js';
|
|
11
|
+
import { getSourceLocation } from './source-location.js';
|
|
12
|
+
import { isTokenVisible, moduleDeclaresToken } from './model/visibility.js';
|
|
13
|
+
class ApplicationModelExtensionRegistry {
|
|
14
|
+
#ordered;
|
|
15
|
+
#groups;
|
|
16
|
+
constructor(groups) {
|
|
17
|
+
this.#ordered = Object.freeze([...groups]);
|
|
18
|
+
this.#groups = new Map(groups.map((group) => [group.extension.identity, group]));
|
|
19
|
+
}
|
|
20
|
+
get(extension) {
|
|
21
|
+
return this.#groups.get(extension.identity);
|
|
22
|
+
}
|
|
23
|
+
values() {
|
|
24
|
+
return this.#ordered;
|
|
25
|
+
}
|
|
26
|
+
[Symbol.iterator]() {
|
|
27
|
+
return this.#ordered[Symbol.iterator]();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export class ApplicationModelError extends Error {
|
|
31
|
+
diagnostics;
|
|
32
|
+
code = 'LUTRE_APPLICATION_MODEL_INVALID';
|
|
33
|
+
constructor(diagnostics) {
|
|
34
|
+
super(`Application Model is invalid:\n${diagnostics
|
|
35
|
+
.map((item) => `${item.code} at ${item.path}: ${item.message}`)
|
|
36
|
+
.join('\n')}`);
|
|
37
|
+
this.diagnostics = diagnostics;
|
|
38
|
+
this.name = 'ApplicationModelError';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export function assertValidApplicationModel(model) {
|
|
42
|
+
const errors = model.diagnostics.filter(isErrorDiagnostic);
|
|
43
|
+
if (errors.length > 0)
|
|
44
|
+
throw new ApplicationModelError(errors);
|
|
45
|
+
return model;
|
|
46
|
+
}
|
|
47
|
+
export function buildApplicationModel(options) {
|
|
48
|
+
const context = createModelBuildContext(options);
|
|
49
|
+
collectModuleDeclarations(context);
|
|
50
|
+
resolveModuleExports(context);
|
|
51
|
+
compileArgumentsProvider(context);
|
|
52
|
+
resolveProviderDependencies(context);
|
|
53
|
+
resolveLifecycleDependencies(context);
|
|
54
|
+
const { modules, moduleIds, nodes, edges, diagnostics, providers, executions, providerNodes, } = context;
|
|
55
|
+
const extensionExecutions = new Map();
|
|
56
|
+
const extensionNames = new Map();
|
|
57
|
+
const extensionIdentities = new Map();
|
|
58
|
+
const executionIds = new Set();
|
|
59
|
+
const capabilityNodeIds = new Set();
|
|
60
|
+
const visitedDefinitions = new Set();
|
|
61
|
+
const compiledDefinitions = new Map();
|
|
62
|
+
const executionReferences = [];
|
|
63
|
+
const executionReferenceResults = new Map();
|
|
64
|
+
const getExecutionReferences = (definition) => {
|
|
65
|
+
const cached = executionReferenceResults.get(definition);
|
|
66
|
+
if (cached)
|
|
67
|
+
return cached;
|
|
68
|
+
const references = definition.extension.references;
|
|
69
|
+
if (!references) {
|
|
70
|
+
const result = { references: Object.freeze([]) };
|
|
71
|
+
executionReferenceResults.set(definition, result);
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
const result = {
|
|
76
|
+
references: references(definition),
|
|
77
|
+
};
|
|
78
|
+
executionReferenceResults.set(definition, result);
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
const result = { error };
|
|
83
|
+
executionReferenceResults.set(definition, result);
|
|
84
|
+
return result;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
const rootDefinitionOwners = new Map();
|
|
88
|
+
for (const module of modules) {
|
|
89
|
+
for (const value of module.definition.executions ?? []) {
|
|
90
|
+
if (!isExecutionDefinition(value))
|
|
91
|
+
continue;
|
|
92
|
+
const owners = rootDefinitionOwners.get(value) ?? new Set();
|
|
93
|
+
owners.add(module);
|
|
94
|
+
rootDefinitionOwners.set(value, owners);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const reachableDefinitionModules = new Map();
|
|
98
|
+
for (const module of modules) {
|
|
99
|
+
const queue = (module.definition.executions ?? []).filter(isExecutionDefinition);
|
|
100
|
+
const seen = new Set();
|
|
101
|
+
let queueIndex = 0;
|
|
102
|
+
while (queueIndex < queue.length) {
|
|
103
|
+
const value = queue[queueIndex++];
|
|
104
|
+
if (seen.has(value))
|
|
105
|
+
continue;
|
|
106
|
+
seen.add(value);
|
|
107
|
+
const explicitOwners = rootDefinitionOwners.get(value);
|
|
108
|
+
if (explicitOwners && !explicitOwners.has(module))
|
|
109
|
+
continue;
|
|
110
|
+
const reachableModules = reachableDefinitionModules.get(value) ?? new Set();
|
|
111
|
+
reachableModules.add(module);
|
|
112
|
+
reachableDefinitionModules.set(value, reachableModules);
|
|
113
|
+
const referenceResult = getExecutionReferences(value);
|
|
114
|
+
if ('error' in referenceResult)
|
|
115
|
+
continue;
|
|
116
|
+
for (const reference of referenceResult.references) {
|
|
117
|
+
if (!isExecutionDefinition(reference))
|
|
118
|
+
continue;
|
|
119
|
+
if (reference.extension.identity !== value.extension.identity)
|
|
120
|
+
continue;
|
|
121
|
+
queue.push(reference);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const definitionOwners = new Map();
|
|
126
|
+
const ambiguousDefinitions = new Set();
|
|
127
|
+
for (const [definition, explicitOwners] of rootDefinitionOwners) {
|
|
128
|
+
if (explicitOwners.size === 1) {
|
|
129
|
+
definitionOwners.set(definition, [...explicitOwners][0]);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
ambiguousDefinitions.add(definition);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
for (const [definition, reachableModules] of reachableDefinitionModules) {
|
|
136
|
+
if (rootDefinitionOwners.has(definition))
|
|
137
|
+
continue;
|
|
138
|
+
if (reachableModules.size === 1) {
|
|
139
|
+
definitionOwners.set(definition, [...reachableModules][0]);
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
ambiguousDefinitions.add(definition);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (ambiguousDefinitions.size > 0) {
|
|
146
|
+
diagnostics.push(diagnostic('LUTRE_EXECUTION_OWNER_AMBIGUOUS', 'Execution Definition ownership is ambiguous across multiple Modules. Register each shared Definition in exactly one Module.executions; other Modules may reference it.', 'application.executions'));
|
|
147
|
+
}
|
|
148
|
+
for (const module of modules) {
|
|
149
|
+
const moduleId = moduleIds.get(module);
|
|
150
|
+
const rootDefinitions = module.definition.executions ?? [];
|
|
151
|
+
const rootDefinitionIndexes = new Map();
|
|
152
|
+
for (const [definitionIndex, value] of rootDefinitions.entries()) {
|
|
153
|
+
if (isExecutionDefinition(value) && !rootDefinitionIndexes.has(value)) {
|
|
154
|
+
rootDefinitionIndexes.set(value, definitionIndex);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
const discoveredDefinitionIndexes = new Map();
|
|
158
|
+
const queue = rootDefinitions.map((value, definitionIndex) => ({
|
|
159
|
+
value,
|
|
160
|
+
definitionIndex,
|
|
161
|
+
path: `${moduleId}.executions.${definitionIndex}`,
|
|
162
|
+
}));
|
|
163
|
+
let nextDiscoveredDefinitionIndex = rootDefinitions.length;
|
|
164
|
+
let queueIndex = 0;
|
|
165
|
+
while (queueIndex < queue.length) {
|
|
166
|
+
const { value, definitionIndex, path } = queue[queueIndex++];
|
|
167
|
+
if (!isExecutionDefinition(value)) {
|
|
168
|
+
diagnostics.push(diagnostic('LUTRE_EXECUTION_DEFINITION_INVALID', 'Module executions and referenced executions accept only branded Execution Definitions.', path));
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
if (ambiguousDefinitions.has(value))
|
|
172
|
+
continue;
|
|
173
|
+
if (definitionOwners.get(value) !== module)
|
|
174
|
+
continue;
|
|
175
|
+
if (visitedDefinitions.has(value))
|
|
176
|
+
continue;
|
|
177
|
+
visitedDefinitions.add(value);
|
|
178
|
+
const extension = value.extension;
|
|
179
|
+
const namedIdentity = extensionNames.get(extension.name);
|
|
180
|
+
if (namedIdentity && namedIdentity.identity !== extension.identity) {
|
|
181
|
+
diagnostics.push(diagnostic('LUTRE_EXTENSION_ABI_MISMATCH', `Extension ${extension.name} mixes incompatible ABI versions ${namedIdentity.abiVersion} and ${extension.abiVersion}.`, path));
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
const identityOwner = extensionIdentities.get(extension.identity);
|
|
185
|
+
if (identityOwner && identityOwner.name !== extension.name) {
|
|
186
|
+
diagnostics.push(diagnostic('LUTRE_EXTENSION_IDENTITY_COLLISION', `Extension identity is shared by ${identityOwner.name} and ${extension.name}.`, path));
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
const canonicalExtension = identityOwner?.extension ?? snapshotExecutionExtension(extension);
|
|
190
|
+
extensionNames.set(extension.name, {
|
|
191
|
+
identity: extension.identity,
|
|
192
|
+
abiVersion: extension.abiVersion,
|
|
193
|
+
});
|
|
194
|
+
extensionIdentities.set(extension.identity, {
|
|
195
|
+
name: extension.name,
|
|
196
|
+
extension: canonicalExtension,
|
|
197
|
+
});
|
|
198
|
+
let contribution;
|
|
199
|
+
try {
|
|
200
|
+
contribution = extension.compile(value, {
|
|
201
|
+
moduleId,
|
|
202
|
+
definitionIndex,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
diagnostics.push(diagnostic('LUTRE_EXTENSION_COMPILE', describeError(error), path));
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
if (executionIds.has(contribution.id)) {
|
|
210
|
+
diagnostics.push(diagnostic('LUTRE_EXECUTION_ID_COLLISION', `Execution id ${contribution.id} is already registered.`, path));
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
executionIds.add(contribution.id);
|
|
214
|
+
const executionSource = getSourceLocation(value);
|
|
215
|
+
const execution = Object.freeze({
|
|
216
|
+
...contribution,
|
|
217
|
+
dependencies: Object.freeze([...contribution.dependencies]),
|
|
218
|
+
capabilities: Object.freeze([...contribution.capabilities]),
|
|
219
|
+
moduleId,
|
|
220
|
+
...(executionSource === undefined ? {} : { source: executionSource }),
|
|
221
|
+
});
|
|
222
|
+
compiledDefinitions.set(value, execution);
|
|
223
|
+
executions.push(execution);
|
|
224
|
+
nodes.push(execution);
|
|
225
|
+
edges.push({ from: moduleId, to: execution.id, kind: 'owns' });
|
|
226
|
+
const grouped = extensionExecutions.get(extension.identity) ?? {
|
|
227
|
+
extension: canonicalExtension,
|
|
228
|
+
executions: [],
|
|
229
|
+
};
|
|
230
|
+
grouped.executions.push(execution);
|
|
231
|
+
extensionExecutions.set(extension.identity, grouped);
|
|
232
|
+
for (const dependency of execution.dependencies) {
|
|
233
|
+
const provider = providerNodes.get(dependency);
|
|
234
|
+
if (provider) {
|
|
235
|
+
edges.push({ from: execution.id, to: provider.id, kind: 'injects' });
|
|
236
|
+
const providerModule = modules.find((candidate) => moduleIds.get(candidate) === provider.moduleId);
|
|
237
|
+
if (providerModule &&
|
|
238
|
+
provider.moduleId !== moduleId &&
|
|
239
|
+
!moduleDeclaresToken(module, dependency) &&
|
|
240
|
+
!isTokenVisible(module, providerModule, dependency)) {
|
|
241
|
+
diagnostics.push(diagnostic('LUTRE_MODULE_VISIBILITY', `Execution ${execution.id} depends on private ${tokenName(dependency)} from another Module.`, execution.id));
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
else if (!isFrameworkProvidedToken(dependency)) {
|
|
245
|
+
diagnostics.push(diagnostic('LUTRE_EXECUTION_DEPENDENCY_MISSING', `Execution ${execution.id} requires ${tokenName(dependency)}, but no provider is declared.`, execution.id));
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
for (const capability of execution.capabilities) {
|
|
249
|
+
const capabilityId = `capability:${capability.id}`;
|
|
250
|
+
if (!capabilityNodeIds.has(capabilityId)) {
|
|
251
|
+
capabilityNodeIds.add(capabilityId);
|
|
252
|
+
nodes.push({
|
|
253
|
+
kind: 'framework',
|
|
254
|
+
id: capabilityId,
|
|
255
|
+
frameworkKind: 'runtime-capability',
|
|
256
|
+
name: capability.id,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
edges.push({
|
|
260
|
+
from: execution.id,
|
|
261
|
+
to: capabilityId,
|
|
262
|
+
kind: 'requires',
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
const referenceResult = getExecutionReferences(value);
|
|
266
|
+
if ('error' in referenceResult) {
|
|
267
|
+
diagnostics.push(diagnostic('LUTRE_EXTENSION_REFERENCES', describeError(referenceResult.error), path));
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
for (const [referenceIndex, reference,] of referenceResult.references.entries()) {
|
|
271
|
+
const referencePath = `${path}.references.${referenceIndex}`;
|
|
272
|
+
if (!isExecutionDefinition(reference)) {
|
|
273
|
+
diagnostics.push(diagnostic('LUTRE_EXECUTION_REFERENCE_INVALID', 'Execution references accept only branded Execution Definitions.', referencePath));
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
if (reference.extension.identity !== extension.identity) {
|
|
277
|
+
diagnostics.push(diagnostic('LUTRE_EXECUTION_REFERENCE_EXTENSION', `Execution ${execution.id} cannot reference an execution owned by ${reference.extension.name}.`, referencePath));
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
executionReferences.push({ from: value, to: reference });
|
|
281
|
+
let referencedDefinitionIndex = rootDefinitionIndexes.get(reference);
|
|
282
|
+
if (referencedDefinitionIndex === undefined) {
|
|
283
|
+
referencedDefinitionIndex = discoveredDefinitionIndexes.get(reference);
|
|
284
|
+
if (referencedDefinitionIndex === undefined) {
|
|
285
|
+
referencedDefinitionIndex = nextDiscoveredDefinitionIndex++;
|
|
286
|
+
discoveredDefinitionIndexes.set(reference, referencedDefinitionIndex);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
queue.push({
|
|
290
|
+
value: reference,
|
|
291
|
+
definitionIndex: referencedDefinitionIndex,
|
|
292
|
+
path: referencePath,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
for (const reference of executionReferences) {
|
|
298
|
+
const from = compiledDefinitions.get(reference.from);
|
|
299
|
+
const to = compiledDefinitions.get(reference.to);
|
|
300
|
+
if (!from || !to)
|
|
301
|
+
continue;
|
|
302
|
+
edges.push({ from: from.id, to: to.id, kind: 'references' });
|
|
303
|
+
}
|
|
304
|
+
const extensionGroups = [...extensionExecutions.values()].map(({ extension, executions: ownedExecutions }) => {
|
|
305
|
+
const extensionId = `extension:${extension.name}`;
|
|
306
|
+
nodes.push({
|
|
307
|
+
kind: 'framework',
|
|
308
|
+
id: extensionId,
|
|
309
|
+
frameworkKind: 'execution-extension',
|
|
310
|
+
name: extension.name,
|
|
311
|
+
});
|
|
312
|
+
for (const execution of ownedExecutions) {
|
|
313
|
+
edges.push({ from: extensionId, to: execution.id, kind: 'starts' });
|
|
314
|
+
}
|
|
315
|
+
if (extension.validate) {
|
|
316
|
+
try {
|
|
317
|
+
diagnostics.push(...extension.validate({ executions: ownedExecutions }));
|
|
318
|
+
}
|
|
319
|
+
catch (error) {
|
|
320
|
+
diagnostics.push(diagnostic('LUTRE_EXTENSION_VALIDATE', describeError(error), extensionId));
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return Object.freeze({
|
|
324
|
+
extension,
|
|
325
|
+
executions: Object.freeze([...ownedExecutions]),
|
|
326
|
+
});
|
|
327
|
+
});
|
|
328
|
+
const extensions = new ApplicationModelExtensionRegistry(extensionGroups);
|
|
329
|
+
validateHostNamespaces(extensionGroups, diagnostics);
|
|
330
|
+
validateNodeIds(nodes, diagnostics);
|
|
331
|
+
return Object.freeze({
|
|
332
|
+
kind: 'application-model',
|
|
333
|
+
...(options.arguments === undefined
|
|
334
|
+
? {}
|
|
335
|
+
: { arguments: options.arguments }),
|
|
336
|
+
providers: Object.freeze(providers),
|
|
337
|
+
nodes: Object.freeze(nodes.map((node) => Object.freeze(node))),
|
|
338
|
+
edges: Object.freeze(edges.map((edge) => Object.freeze(edge))),
|
|
339
|
+
executions: Object.freeze(executions),
|
|
340
|
+
extensions,
|
|
341
|
+
diagnostics: Object.freeze(diagnostics.map((item) => Object.freeze({ ...item }))),
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
function describeError(error) {
|
|
345
|
+
return error instanceof Error ? error.message : String(error);
|
|
346
|
+
}
|
package/dist/core/module.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { EnvClass } from './env.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type { ExecutionDefinition, ExtensionOfDefinition, HostApiOfExtension } from './extension.js';
|
|
3
3
|
import type { ModuleLifecycle } from './lifecycle.js';
|
|
4
4
|
import { type ProviderDeclaration } from './provider.js';
|
|
5
5
|
export interface ModuleDefinition {
|
|
@@ -8,24 +8,19 @@ export interface ModuleDefinition {
|
|
|
8
8
|
readonly imports?: readonly ModuleInstance[];
|
|
9
9
|
readonly environment?: readonly EnvClass[];
|
|
10
10
|
readonly providers?: readonly ProviderDeclaration[];
|
|
11
|
-
readonly
|
|
11
|
+
readonly executions?: readonly ExecutionDefinition[];
|
|
12
12
|
readonly exports?: readonly unknown[];
|
|
13
13
|
readonly lifecycle?: ModuleLifecycle;
|
|
14
|
-
readonly requires?: readonly string[];
|
|
15
14
|
}
|
|
16
15
|
export declare const moduleTypeInfo: unique symbol;
|
|
17
16
|
export interface ModuleTypeInfo<TDefinition extends ModuleDefinition = ModuleDefinition> {
|
|
18
|
-
readonly
|
|
19
|
-
readonly capabilities: CapabilitiesOfModuleDefinition<TDefinition>;
|
|
17
|
+
readonly extensions: ExtensionsOfModuleDefinition<TDefinition>;
|
|
20
18
|
}
|
|
21
|
-
type
|
|
22
|
-
type
|
|
23
|
-
export type
|
|
24
|
-
type
|
|
25
|
-
type
|
|
26
|
-
export type CapabilitiesOfModuleDefinition<TDefinition extends ModuleDefinition> = DirectCapabilities<TDefinition> | ImportedCapabilities<TDefinition>;
|
|
27
|
-
export type ModuleProtocols<TModule> = TModule extends ModuleInstance<infer TDefinition> ? ProtocolsOfModuleDefinition<TDefinition> : never;
|
|
28
|
-
export type ModuleCapabilities<TModule> = TModule extends ModuleInstance<infer TDefinition> ? CapabilitiesOfModuleDefinition<TDefinition> : never;
|
|
19
|
+
type DirectExtensions<TDefinition extends ModuleDefinition> = TDefinition['executions'] extends readonly ExecutionDefinition[] ? ExtensionOfDefinition<TDefinition['executions'][number]> : never;
|
|
20
|
+
type ImportedExtensions<TDefinition extends ModuleDefinition> = TDefinition['imports'] extends readonly ModuleInstance[] ? ModuleExtensions<TDefinition['imports'][number]> : never;
|
|
21
|
+
export type ExtensionsOfModuleDefinition<TDefinition extends ModuleDefinition> = DirectExtensions<TDefinition> | ImportedExtensions<TDefinition>;
|
|
22
|
+
export type ModuleExtensions<TModule> = TModule extends ModuleInstance<infer TDefinition> ? ExtensionsOfModuleDefinition<TDefinition> : never;
|
|
23
|
+
export type ModuleHostApis<TModule> = HostApiOfExtension<ModuleExtensions<TModule>>;
|
|
29
24
|
export interface ModuleInstance<TDefinition extends ModuleDefinition = ModuleDefinition> {
|
|
30
25
|
readonly kind: 'module-instance';
|
|
31
26
|
readonly template: AnyModuleTemplate;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface SourceLocation {
|
|
2
|
+
readonly file: string;
|
|
3
|
+
readonly line?: number;
|
|
4
|
+
readonly column?: number;
|
|
5
|
+
}
|
|
6
|
+
export declare function registerSourceLocation<T>(value: T, source: SourceLocation): T;
|
|
7
|
+
export declare function getSourceLocation(value: unknown): SourceLocation | undefined;
|
|
8
|
+
export declare function inheritSourceLocation<T>(target: T, source: unknown): T;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const sourceMetadata = new WeakMap();
|
|
2
|
+
function asObject(value) {
|
|
3
|
+
return (typeof value === 'object' && value !== null) ||
|
|
4
|
+
typeof value === 'function'
|
|
5
|
+
? value
|
|
6
|
+
: undefined;
|
|
7
|
+
}
|
|
8
|
+
function snapshotSourceLocation(source) {
|
|
9
|
+
return Object.freeze({
|
|
10
|
+
file: source.file,
|
|
11
|
+
...(source.line === undefined ? {} : { line: source.line }),
|
|
12
|
+
...(source.column === undefined ? {} : { column: source.column }),
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
export function registerSourceLocation(value, source) {
|
|
16
|
+
const target = asObject(value);
|
|
17
|
+
if (!target || sourceMetadata.has(target))
|
|
18
|
+
return value;
|
|
19
|
+
sourceMetadata.set(target, snapshotSourceLocation(source));
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
export function getSourceLocation(value) {
|
|
23
|
+
const target = asObject(value);
|
|
24
|
+
return target ? sourceMetadata.get(target) : undefined;
|
|
25
|
+
}
|
|
26
|
+
export function inheritSourceLocation(target, source) {
|
|
27
|
+
const location = getSourceLocation(source);
|
|
28
|
+
return location === undefined
|
|
29
|
+
? target
|
|
30
|
+
: registerSourceLocation(target, location);
|
|
31
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { RuntimeExecutionMetadata } from '../core/instrumentation.js';
|
|
2
|
+
import type { DevtoolsModuleOptions } from './module.js';
|
|
3
|
+
import type { ReplayCapsuleRequest, ReplayExecutionContext, RuntimeInvocationResult } from './inspector.js';
|
|
4
|
+
import { type DevtoolsValuePreview } from './values.js';
|
|
5
|
+
export interface ReplayRegistration {
|
|
6
|
+
readonly input: unknown;
|
|
7
|
+
replay(input: unknown, context: ReplayExecutionContext): unknown | Promise<unknown>;
|
|
8
|
+
}
|
|
9
|
+
export type CapturedValue = {
|
|
10
|
+
readonly mode: 'snapshot';
|
|
11
|
+
readonly value: unknown;
|
|
12
|
+
} | {
|
|
13
|
+
readonly mode: 'reference';
|
|
14
|
+
readonly handleId: string;
|
|
15
|
+
} | {
|
|
16
|
+
readonly mode: 'unavailable';
|
|
17
|
+
readonly reason: string;
|
|
18
|
+
};
|
|
19
|
+
export interface ExecutionReplayCapsulePreview {
|
|
20
|
+
readonly id: string;
|
|
21
|
+
readonly kind: 'execution';
|
|
22
|
+
readonly runId: string;
|
|
23
|
+
readonly traceId: string;
|
|
24
|
+
readonly spanId: string;
|
|
25
|
+
readonly createdAt: number;
|
|
26
|
+
readonly expiresAt: number;
|
|
27
|
+
readonly execution: {
|
|
28
|
+
readonly executionId: string;
|
|
29
|
+
readonly executionKind: string;
|
|
30
|
+
readonly graphNodeId?: string;
|
|
31
|
+
readonly name: string;
|
|
32
|
+
};
|
|
33
|
+
readonly input: DevtoolsValuePreview;
|
|
34
|
+
readonly fidelity: 'snapshot' | 'reference' | 'unavailable';
|
|
35
|
+
readonly replayModes: readonly ['direct'];
|
|
36
|
+
}
|
|
37
|
+
export interface ReplayCapsuleStoreOptions {
|
|
38
|
+
readonly ttlMs?: number;
|
|
39
|
+
readonly maxCapsules?: number;
|
|
40
|
+
readonly capture?: DevtoolsModuleOptions['capture'];
|
|
41
|
+
readonly redact?: readonly string[];
|
|
42
|
+
}
|
|
43
|
+
export declare class ReplayCapsuleStore {
|
|
44
|
+
#private;
|
|
45
|
+
constructor(runId: string, options?: ReplayCapsuleStoreOptions);
|
|
46
|
+
createExecution(traceId: string, spanId: string, observation: RuntimeExecutionMetadata, registration: ReplayRegistration): ExecutionReplayCapsulePreview;
|
|
47
|
+
preview(capsuleId: string): ExecutionReplayCapsulePreview | undefined;
|
|
48
|
+
replay(request: ReplayCapsuleRequest): Promise<RuntimeInvocationResult>;
|
|
49
|
+
discard(capsuleId: string): void;
|
|
50
|
+
clear(): void;
|
|
51
|
+
}
|