@platformatic/runtime 4.0.0-new-config.2 → 4.0.0-new-config.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config.d.ts +594 -596
- package/index.d.ts +11 -5
- package/index.js +161 -85
- package/lib/config.js +47 -251
- package/lib/errors.js +8 -0
- package/lib/generator.js +199 -35
- package/lib/logger.js +3 -3
- package/lib/management-api.js +4 -60
- package/lib/policies.js +27 -0
- package/lib/runtime.js +315 -239
- package/lib/schema.js +76 -0
- package/lib/worker/controller.js +54 -49
- package/lib/worker/interceptors.js +34 -34
- package/lib/worker/itc.js +49 -2
- package/lib/worker/main.js +28 -53
- package/lib/worker/symbols.js +1 -1
- package/package.json +18 -18
- package/schema.json +87 -44
package/index.d.ts
CHANGED
|
@@ -111,12 +111,19 @@ export interface InjectResponse {
|
|
|
111
111
|
rawPayload: ArrayBuffer
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
+
export type ServingState = 'listening' | 'mesh-only' | 'background' | 'inactive'
|
|
115
|
+
|
|
114
116
|
export interface ApplicationDetails {
|
|
115
117
|
id: string
|
|
116
118
|
type?: string
|
|
119
|
+
/** v3 only: the path to the application's configuration file. v4 reports configPath. */
|
|
117
120
|
config?: string
|
|
121
|
+
/** v4 only: the configuration file the loader decided on, absent for an inline definition. */
|
|
122
|
+
configPath?: string
|
|
118
123
|
path?: string
|
|
119
124
|
status?: string
|
|
125
|
+
/** How the application serves, as opposed to whether it runs. Absent when it is not started. */
|
|
126
|
+
servingState?: ServingState
|
|
120
127
|
dependencies?: string[]
|
|
121
128
|
version?: string
|
|
122
129
|
localUrl?: string
|
|
@@ -194,6 +201,10 @@ export interface RuntimeMetadata {
|
|
|
194
201
|
execPath: string
|
|
195
202
|
nodeVersion: string
|
|
196
203
|
projectDir: string
|
|
204
|
+
/** The configuration file the loader decided on. Null when the runtime was built from an object. */
|
|
205
|
+
configPath: string | null
|
|
206
|
+
/** The autoload declaration, with its path resolved. Null when the project does not autoload. */
|
|
207
|
+
autoload: { path: string, exclude?: string[], mappings?: Record<string, unknown> } | null
|
|
197
208
|
packageName: string | null
|
|
198
209
|
packageVersion: string | null
|
|
199
210
|
platformaticVersion: string
|
|
@@ -468,11 +479,6 @@ export declare class Runtime extends EventEmitter {
|
|
|
468
479
|
runApplicationScheduledTasks (id: string, scheduleId: string, scheduledTime: number): Promise<unknown>
|
|
469
480
|
}
|
|
470
481
|
|
|
471
|
-
export function wrapInRuntimeConfig (
|
|
472
|
-
config: Configuration<unknown>,
|
|
473
|
-
context?: ConfigurationOptions
|
|
474
|
-
): Promise<RuntimeConfiguration>
|
|
475
|
-
|
|
476
482
|
export declare const version: string
|
|
477
483
|
|
|
478
484
|
export declare function loadConfiguration (
|
package/index.js
CHANGED
|
@@ -1,28 +1,27 @@
|
|
|
1
|
-
import { importCapabilityPackage, resolve
|
|
1
|
+
import { importCapabilityPackage, resolve } from '@platformatic/basic'
|
|
2
2
|
import {
|
|
3
3
|
abstractLogger,
|
|
4
4
|
ensureLoggableError,
|
|
5
|
-
extractModuleFromSchemaUrl,
|
|
6
5
|
findRuntimeConfigurationFile,
|
|
7
6
|
kMetadata,
|
|
8
|
-
loadConfigurationModule
|
|
9
|
-
loadConfiguration as utilsLoadConfiguration
|
|
7
|
+
loadConfigurationModule
|
|
10
8
|
} from '@platformatic/foundation'
|
|
11
9
|
import {
|
|
12
|
-
isConfigurationFileName,
|
|
13
10
|
findDecidingFile,
|
|
11
|
+
isProductionCommand,
|
|
12
|
+
LegacyConfigurationFileError,
|
|
14
13
|
loadConfiguration as loadV4Configuration,
|
|
14
|
+
loadObjectConfiguration as loadV4ObjectConfiguration,
|
|
15
15
|
validateCapabilityConfiguration
|
|
16
16
|
} from '@platformatic/foundation/lib/v4/index.js'
|
|
17
17
|
import closeWithGrace from 'close-with-grace'
|
|
18
18
|
import { stat } from 'node:fs/promises'
|
|
19
19
|
import inspector from 'node:inspector'
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
20
|
+
import { dirname, resolve as resolvePath } from 'node:path'
|
|
21
|
+
import { transformV4 } from './lib/config.js'
|
|
22
22
|
import { NodeInspectorFlagsNotSupportedError } from './lib/errors.js'
|
|
23
23
|
import { Runtime } from './lib/runtime.js'
|
|
24
|
-
import {
|
|
25
|
-
import { upgrade } from './lib/upgrade.js'
|
|
24
|
+
import { v4Schema } from './lib/schema.js'
|
|
26
25
|
|
|
27
26
|
async function restartRuntime (runtime) {
|
|
28
27
|
runtime.logger.info('Received SIGUSR2, restarting all applications ...')
|
|
@@ -77,13 +76,15 @@ function handleSignal (runtime, config) {
|
|
|
77
76
|
v3 half is what a later commit deletes, not something this one has to keep working around.
|
|
78
77
|
*/
|
|
79
78
|
/*
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
`--config` names a configuration; it does not widen what a configuration may be called. The four
|
|
80
|
+
names are the format, and `resolveNamedConfigurationFile` is what refuses anything else -- it
|
|
81
|
+
separates a legacy name, which gets the migrate hint, from an unrecognised one, which gets told
|
|
82
|
+
what the four names are. Deciding here instead produced one of those answers for both.
|
|
83
|
+
|
|
84
|
+
What `--config` does change is *where*: a named file need not sit where discovery would look.
|
|
84
85
|
*/
|
|
85
|
-
function
|
|
86
|
-
return
|
|
86
|
+
function isNamedConfigurationPath (path) {
|
|
87
|
+
return /\.(json|json5|ya?ml|to?ml|js|mjs|ts|mts)$/.test(path)
|
|
87
88
|
}
|
|
88
89
|
|
|
89
90
|
async function findV4ConfigurationFile (configOrRoot, sourceOrConfig) {
|
|
@@ -96,14 +97,15 @@ async function findV4ConfigurationFile (configOrRoot, sourceOrConfig) {
|
|
|
96
97
|
if (typeof sourceOrConfig === 'string') {
|
|
97
98
|
const named = resolvePath(configOrRoot, sourceOrConfig)
|
|
98
99
|
|
|
99
|
-
|
|
100
|
+
// Named outright: the loader decides whether the name is one it accepts, and says which it is.
|
|
101
|
+
return isNamedConfigurationPath(named) ? named : null
|
|
100
102
|
}
|
|
101
103
|
|
|
102
104
|
if (typeof configOrRoot !== 'string') {
|
|
103
105
|
return null
|
|
104
106
|
}
|
|
105
107
|
|
|
106
|
-
if (
|
|
108
|
+
if (isNamedConfigurationPath(configOrRoot)) {
|
|
107
109
|
return configOrRoot
|
|
108
110
|
}
|
|
109
111
|
|
|
@@ -119,23 +121,14 @@ async function findV4ConfigurationFile (configOrRoot, sourceOrConfig) {
|
|
|
119
121
|
return null
|
|
120
122
|
}
|
|
121
123
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
The walk refuses a v3 configuration wherever it consults, which is right once v3 is gone and
|
|
129
|
-
wrong while it is still supported: here a v3 file means "this project is not v4", and the v3
|
|
130
|
-
loader below is the one that should answer. Deleting this catch is part of deleting the v3
|
|
131
|
-
path, and at that point the refusal becomes the correct answer again.
|
|
132
|
-
*/
|
|
133
|
-
if (error.code === 'PLT_LEGACY_CONFIGURATION_FILE') {
|
|
134
|
-
return null
|
|
135
|
-
}
|
|
124
|
+
/*
|
|
125
|
+
A v3 configuration found by the walk is refused, with the error that names migrate. It used to
|
|
126
|
+
be swallowed so the v3 loader below could answer instead; that loader is gone, and the refusal
|
|
127
|
+
is the correct answer again.
|
|
128
|
+
*/
|
|
129
|
+
const deciding = await findDecidingFile(configOrRoot, { throwOnMissing: false })
|
|
136
130
|
|
|
137
|
-
|
|
138
|
-
}
|
|
131
|
+
return deciding?.path ?? null
|
|
139
132
|
}
|
|
140
133
|
|
|
141
134
|
export async function loadConfiguration (configOrRoot, sourceOrConfig, context) {
|
|
@@ -147,37 +140,58 @@ export async function loadConfiguration (configOrRoot, sourceOrConfig, context)
|
|
|
147
140
|
return loadV4RuntimeConfiguration(v4ConfigurationFile, context)
|
|
148
141
|
}
|
|
149
142
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
143
|
+
/*
|
|
144
|
+
Level 0. A directory with no configuration file of any kind is not an error: the loader
|
|
145
|
+
synthesizes one in memory from what the directory contains. Reaching the v3 resolver instead
|
|
146
|
+
made a configless project fail to load, which is what the removed temporary-file fallback --
|
|
147
|
+
detect the type, write a watt.json into the user's tree, then load that -- existed to paper
|
|
148
|
+
over. Nothing is written to disk now.
|
|
149
|
+
*/
|
|
150
|
+
if (!sourceOrConfig && typeof configOrRoot === 'string' && !isNamedConfigurationPath(configOrRoot)) {
|
|
151
|
+
const stats = await stat(configOrRoot).catch(() => null)
|
|
157
152
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
context.envFile = config.envfile
|
|
153
|
+
if (stats?.isDirectory()) {
|
|
154
|
+
return loadV4RuntimeConfiguration({ cwd: configOrRoot }, context)
|
|
155
|
+
}
|
|
162
156
|
}
|
|
163
157
|
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
158
|
+
const { root, source } = await resolve(configOrRoot, sourceOrConfig, 'runtime')
|
|
159
|
+
|
|
160
|
+
/*
|
|
161
|
+
A configuration handed over as an object rather than named as a file: what an embedder builds in
|
|
162
|
+
memory, and what the ICC generates. There is nothing to evaluate, so it skips the root eval
|
|
163
|
+
worker and joins the v4 pipeline at validation.
|
|
164
|
+
*/
|
|
165
|
+
if (source && typeof source !== 'string') {
|
|
166
|
+
return loadV4RuntimeConfiguration({ root, source }, context)
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
})
|
|
169
|
+
/*
|
|
170
|
+
Everything above this point is v4. A path that reaches here named a file the v4 walk did not
|
|
171
|
+
recognise as configuration, so the walk's own refusal is the answer -- it names the file and
|
|
172
|
+
tells the reader to run migrate, which is more use than loading a v3 configuration into a
|
|
173
|
+
runtime that no longer implements what it says.
|
|
174
|
+
*/
|
|
175
|
+
throw new LegacyConfigurationFileError(source)
|
|
177
176
|
}
|
|
178
177
|
|
|
179
|
-
|
|
180
|
-
|
|
178
|
+
/*
|
|
179
|
+
`target` is either a configuration file to evaluate or `{ root, source }` for a configuration
|
|
180
|
+
handed over as an object -- what an embedder builds in memory and what the ICC generates. The two
|
|
181
|
+
differ only in where the configuration comes from: an object skips the root eval worker, since
|
|
182
|
+
there is nothing to evaluate, and everything after that is the same pipeline.
|
|
183
|
+
*/
|
|
184
|
+
async function loadV4RuntimeConfiguration (target, context) {
|
|
185
|
+
/*
|
|
186
|
+
The command decides `production` when the caller did not, rather than the other way round:
|
|
187
|
+
`build` produces production artifacts, so a build that evaluated as a development boot read the
|
|
188
|
+
development env files and gave every callback `production: false` while writing what `start`
|
|
189
|
+
would later run.
|
|
190
|
+
*/
|
|
191
|
+
const diagnostics = context?.logger ?? abstractLogger
|
|
192
|
+
const explicitProduction = context?.isProduction ?? context?.production
|
|
193
|
+
const command = context?.command ?? (explicitProduction ? 'start' : 'dev')
|
|
194
|
+
const production = explicitProduction ?? isProductionCommand(command)
|
|
181
195
|
|
|
182
196
|
/*
|
|
183
197
|
The environment the loader treats as real. An embedder can add to it, and can ask for a
|
|
@@ -186,14 +200,28 @@ async function loadV4RuntimeConfiguration (configurationFile, context) {
|
|
|
186
200
|
*/
|
|
187
201
|
const realEnv = context?.ignoreProcessEnv ? { ...context?.env } : { ...process.env, ...context?.env }
|
|
188
202
|
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
configPath: configurationFile,
|
|
203
|
+
const objectSource = typeof target !== 'string' && target.source !== undefined
|
|
204
|
+
const shared = {
|
|
192
205
|
realEnv,
|
|
193
|
-
command
|
|
206
|
+
command,
|
|
194
207
|
mode: context?.mode,
|
|
195
208
|
production,
|
|
196
209
|
customEnvFile: context?.envFile,
|
|
210
|
+
/*
|
|
211
|
+
Step 3 of the pipeline validates orchestration in the eval worker, before autoload expansion
|
|
212
|
+
acts on it -- without the schema that step is skipped, and a malformed `autoload` reaches the
|
|
213
|
+
filesystem walk as a raw TypeError instead of a validation error naming the property.
|
|
214
|
+
*/
|
|
215
|
+
schema: context?.schema ?? v4Schema,
|
|
216
|
+
/*
|
|
217
|
+
The evaluation deadline. A configuration that never resolves — an awaited fetch to a dead
|
|
218
|
+
host, a forgotten promise — otherwise hangs the boot rather than failing it, and the default
|
|
219
|
+
is a guess about how long a reasonable one takes. A deployment that knows better says so.
|
|
220
|
+
*/
|
|
221
|
+
timeout: context?.configTimeout,
|
|
222
|
+
// The one file --debug-config evaluates in this process when an inspector is attached, so a
|
|
223
|
+
// breakpoint in it is reachable at all: a throwaway worker dies before one can attach.
|
|
224
|
+
inProcessTarget: context?.inProcessTarget,
|
|
197
225
|
/*
|
|
198
226
|
Validation imports each capability's schema, so it needs the capability installed — not
|
|
199
227
|
merely declared, which is all the detector needs. That moves the moment a capability must be
|
|
@@ -207,9 +235,29 @@ async function loadV4RuntimeConfiguration (configurationFile, context) {
|
|
|
207
235
|
// both the schema import and the version stamp — the application's own dependencies still
|
|
208
236
|
// come first.
|
|
209
237
|
runtimeScope: import.meta.filename,
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
238
|
+
/*
|
|
239
|
+
These are the loader's user-facing diagnostics — the standalone-boot warning, the zero-config
|
|
240
|
+
inference notice, the capability the detector chose — and they were being handed to
|
|
241
|
+
abstractLogger, which is a no-op. Every one of them was discarded, including the warning the
|
|
242
|
+
format relies on to tell someone that nothing the root says is being applied.
|
|
243
|
+
|
|
244
|
+
A caller with a real logger passes it. The default stays silent because an embedder loading a
|
|
245
|
+
configuration has not asked for anything on its stderr.
|
|
246
|
+
*/
|
|
247
|
+
onWarning: warning => diagnostics.warn(warning.message),
|
|
248
|
+
onInfo: info => diagnostics.info(info.message)
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
let loaded
|
|
252
|
+
if (objectSource) {
|
|
253
|
+
loaded = await loadV4ObjectConfiguration({ root: target.root, source: target.source, ...shared })
|
|
254
|
+
} else if (typeof target === 'string') {
|
|
255
|
+
loaded = await loadV4Configuration({ cwd: dirname(target), configPath: target, ...shared })
|
|
256
|
+
} else {
|
|
257
|
+
// No file was named and none was found: the loader searches from this directory and, finding
|
|
258
|
+
// nothing, synthesizes.
|
|
259
|
+
loaded = await loadV4Configuration({ cwd: target.cwd, ...shared })
|
|
260
|
+
}
|
|
213
261
|
|
|
214
262
|
const config = loaded.config
|
|
215
263
|
|
|
@@ -219,19 +267,20 @@ async function loadV4RuntimeConfiguration (configurationFile, context) {
|
|
|
219
267
|
projection carries authored values — so this is where the runtime schema's defaults arrive, and
|
|
220
268
|
without it the runtime reaches for settings like gracefulShutdown that nothing supplied.
|
|
221
269
|
*/
|
|
222
|
-
validateCapabilityConfiguration(config, context?.schema ??
|
|
270
|
+
validateCapabilityConfiguration(config, context?.schema ?? v4Schema, {
|
|
223
271
|
id: 'runtime',
|
|
224
272
|
module: '@platformatic/runtime',
|
|
225
273
|
root: loaded.root
|
|
226
274
|
})
|
|
227
275
|
|
|
228
276
|
// kMetadata is symbol-keyed and cannot cross a worker boundary, so each worker rebuilds it; this
|
|
229
|
-
// is the main process's copy. env is the runtime's own view —
|
|
230
|
-
//
|
|
277
|
+
// is the main process's copy. env is the runtime's own view — the real environment under the root
|
|
278
|
+
// env block and the root's env files — and every application worker gets the per-application
|
|
279
|
+
// environment the loader resolved instead, which this one is not a substitute for.
|
|
231
280
|
config[kMetadata] = {
|
|
232
281
|
root: loaded.root,
|
|
233
282
|
path: loaded.configPath,
|
|
234
|
-
env: process.env,
|
|
283
|
+
env: loaded.env ?? process.env,
|
|
235
284
|
module: '@platformatic/runtime',
|
|
236
285
|
/*
|
|
237
286
|
The evaluation context, kept beside the envelope rather than inside it: applications added
|
|
@@ -240,9 +289,31 @@ async function loadV4RuntimeConfiguration (configurationFile, context) {
|
|
|
240
289
|
no such context and keeps resolving configuration files worker-side.
|
|
241
290
|
*/
|
|
242
291
|
v4: {
|
|
243
|
-
command
|
|
292
|
+
command,
|
|
244
293
|
mode: loaded.mode,
|
|
245
|
-
production: loaded.production
|
|
294
|
+
production: loaded.production,
|
|
295
|
+
/*
|
|
296
|
+
The environment contract of the boot, carried so an application added while the runtime
|
|
297
|
+
runs is enveloped under the same one: the realEnv the boot resolved ladders against
|
|
298
|
+
(hermetic under ignoreProcessEnv, augmented by context.env) and the --env file that
|
|
299
|
+
replaces every application's env-file rung. Without them the add path defaulted to
|
|
300
|
+
process.env and the conventional .env chain -- an environment the boot says cannot exist.
|
|
301
|
+
*/
|
|
302
|
+
realEnv,
|
|
303
|
+
customEnvFile: context?.envFile,
|
|
304
|
+
/*
|
|
305
|
+
Everything the evaluation actually read: the configuration files, their import graph minus
|
|
306
|
+
node_modules, the env files consulted, and the directories whose membership decides the
|
|
307
|
+
application list. `wattpm dev` reloads on any of it -- watching only the deciding file meant
|
|
308
|
+
a config split across a helper module reloaded for none of its own edits.
|
|
309
|
+
*/
|
|
310
|
+
watchTargets: loaded.watchTargets,
|
|
311
|
+
/*
|
|
312
|
+
Every entry carrying a `url`, recorded on the way past -- before the enabled filter, which
|
|
313
|
+
is the point. `enabled` is the supported way to keep an application out of a boot, and an
|
|
314
|
+
entry it hides from `resolve` is one whose clone never arrives.
|
|
315
|
+
*/
|
|
316
|
+
resolveCandidates: loaded.resolveCandidates
|
|
246
317
|
}
|
|
247
318
|
}
|
|
248
319
|
|
|
@@ -278,7 +349,13 @@ export async function loadApplicationsCommands (executableName = '', configurati
|
|
|
278
349
|
throw new Error('No runtime configuration file found.')
|
|
279
350
|
}
|
|
280
351
|
|
|
281
|
-
|
|
352
|
+
/*
|
|
353
|
+
'exec' is every non-boot evaluation, and enumerating a capability's commands is one: nothing
|
|
354
|
+
starts. Without it this evaluated as a development boot — development env files, and
|
|
355
|
+
`production: false` handed to every callback — which is a context no invocation of these
|
|
356
|
+
commands actually runs in.
|
|
357
|
+
*/
|
|
358
|
+
config = await loadConfiguration(file, null, { command: 'exec' })
|
|
282
359
|
|
|
283
360
|
/* c8 ignore next 3 - Hard to test */
|
|
284
361
|
if (!config) {
|
|
@@ -290,13 +367,9 @@ export async function loadApplicationsCommands (executableName = '', configurati
|
|
|
290
367
|
|
|
291
368
|
for (const application of config.applications) {
|
|
292
369
|
try {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
as a path threw into the catch below, which skipped the application silently -- the command
|
|
297
|
-
it contributes then simply did not exist, and the CLI said the command was unknown.
|
|
298
|
-
*/
|
|
299
|
-
const applicationConfig = application.resolvedConfig ?? (await utilsLoadConfiguration(application.config))
|
|
370
|
+
// A v4 application arrives with its configuration already evaluated and its capability
|
|
371
|
+
// already named, so there is nothing to read and nothing to infer.
|
|
372
|
+
const applicationConfig = application.resolvedConfig
|
|
300
373
|
const pkg = application.module
|
|
301
374
|
? await importCapabilityPackage(application.path, application.module)
|
|
302
375
|
: await loadConfigurationModule(application.path, applicationConfig)
|
|
@@ -350,16 +423,19 @@ export async function create (configOrRoot, sourceOrConfig, context) {
|
|
|
350
423
|
return runtime
|
|
351
424
|
}
|
|
352
425
|
|
|
353
|
-
export { prepareApplication, wrapInRuntimeConfig } from './lib/config.js'
|
|
354
|
-
|
|
355
426
|
/*
|
|
356
|
-
The
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
427
|
+
The one entry point for an application added while the runtime is running -- what an extension
|
|
428
|
+
calls before `addApplications`. It replaces the exported `prepareApplication`, which is the v3
|
|
429
|
+
half of the same job: under v4 an added application has to be evaluated the way boot evaluates
|
|
430
|
+
one, and an entry that skips that arrives without `resolvedConfig` and fails as an unhelpful
|
|
431
|
+
"unable to initialize the worker".
|
|
360
432
|
*/
|
|
433
|
+
export { prepareAddedApplications } from './lib/config.js'
|
|
434
|
+
|
|
435
|
+
// The one transform there is: the v3 one died with its last caller, the wizard's legacy-JSON
|
|
436
|
+
// branch, and the dispatch that told the two apart went with it.
|
|
361
437
|
export async function transform (config, schema, context) {
|
|
362
|
-
return
|
|
438
|
+
return transformV4(config, schema, context)
|
|
363
439
|
}
|
|
364
440
|
export * as errors from './lib/errors.js'
|
|
365
441
|
export { RuntimeGenerator as Generator, WrappedGenerator } from './lib/generator.js'
|