@toa.io/boot 1.0.0-alpha.28 → 1.0.0-alpha.283
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/CHANGELOG.md +188 -0
- package/package.json +10 -8
- package/src/atom.js +37 -0
- package/src/atomicity.js +11 -0
- package/src/bindings/broadcast.js +3 -6
- package/src/bindings/constants.js +1 -3
- package/src/bindings/consume.js +5 -8
- package/src/bindings/emit.js +3 -6
- package/src/bindings/factory.js +5 -9
- package/src/bindings/index.js +5 -13
- package/src/bindings/produce.js +32 -19
- package/src/bindings/receive.js +3 -6
- package/src/bridge.js +23 -16
- package/src/call.js +6 -9
- package/src/cascade.js +6 -10
- package/src/component.js +56 -32
- package/src/composition.js +81 -16
- package/src/context.js +7 -8
- package/src/contract.js +12 -12
- package/src/discovery.js +7 -11
- package/src/emission.js +10 -14
- package/src/env.js +15 -15
- package/src/events.js +25 -0
- package/src/exposition.js +3 -7
- package/src/extensions/aspects.js +3 -7
- package/src/extensions/component.js +2 -6
- package/src/extensions/context.js +2 -6
- package/src/extensions/emitter.js +4 -7
- package/src/extensions/index.js +9 -19
- package/src/extensions/instances.js +1 -3
- package/src/extensions/load.js +6 -8
- package/src/extensions/manage.js +16 -0
- package/src/extensions/receiver.js +4 -7
- package/src/extensions/resolve.js +36 -11
- package/src/extensions/storage.js +2 -6
- package/src/extensions/tenants.js +4 -8
- package/src/guards.js +19 -0
- package/src/host.js +15 -0
- package/src/index.js +28 -32
- package/src/manifest.js +19 -14
- package/src/manifest.test.js +7 -7
- package/src/operation.js +8 -10
- package/src/outbox.js +17 -0
- package/src/rc.js +5 -0
- package/src/receivers.js +21 -18
- package/src/remote.js +28 -10
- package/src/span.js +17 -0
- package/src/storage.js +19 -13
- package/types/index.d.ts +7 -5
- package/types/manifest.d.ts +1 -1
package/src/guards.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Guard } from '@toa.io/core'
|
|
2
|
+
import * as boot from './index.js'
|
|
3
|
+
|
|
4
|
+
export async function guards(manifest, context) {
|
|
5
|
+
if (manifest.guards === undefined)
|
|
6
|
+
return
|
|
7
|
+
|
|
8
|
+
const entries = Object.entries(manifest.guards)
|
|
9
|
+
|
|
10
|
+
return await Promise.all(entries.map(async ([name, guard]) => {
|
|
11
|
+
const bridge = await load(guard, name, context)
|
|
12
|
+
|
|
13
|
+
return new Guard(name, bridge)
|
|
14
|
+
}))
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function load(guard, name, context) {
|
|
18
|
+
return await boot.bridge.guard(guard.bridge, guard.path, name, context)
|
|
19
|
+
}
|
package/src/host.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as boot from './index.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* What the process hosting an extension provides to it. The counterpart of a component's
|
|
5
|
+
* context: an extension reaches the core through this and through nothing else.
|
|
6
|
+
*
|
|
7
|
+
* @returns {toa.core.extensions.Host}
|
|
8
|
+
*/
|
|
9
|
+
export const host = () => ({
|
|
10
|
+
remote: boot.remote,
|
|
11
|
+
broadcast: boot.bindings.broadcast,
|
|
12
|
+
composition: boot.composition,
|
|
13
|
+
receive: boot.receive,
|
|
14
|
+
atom: boot.atomicity
|
|
15
|
+
})
|
package/src/index.js
CHANGED
|
@@ -1,36 +1,32 @@
|
|
|
1
|
-
|
|
1
|
+
// the environment is read at module scope elsewhere, so it is loaded first
|
|
2
|
+
import './env.js'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
import * as bindings from './bindings/index.js'
|
|
5
|
+
import * as bridge from './bridge.js'
|
|
6
|
+
import * as contract from './contract.js'
|
|
7
|
+
import * as discovery from './discovery.js'
|
|
8
|
+
import * as extensions from './extensions/index.js'
|
|
4
9
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
import { call } from './call.js'
|
|
11
|
+
import { cascade } from './cascade.js'
|
|
12
|
+
import { component } from './component.js'
|
|
13
|
+
import { composition } from './composition.js'
|
|
14
|
+
import { context } from './context.js'
|
|
15
|
+
import { emission } from './emission.js'
|
|
16
|
+
import { events } from './events.js'
|
|
17
|
+
import { outbox } from './outbox.js'
|
|
18
|
+
import { atomicity } from './atomicity.js'
|
|
19
|
+
import { atom } from './atom.js'
|
|
20
|
+
import { exposition } from './exposition.js'
|
|
21
|
+
import { manifest } from './manifest.js'
|
|
22
|
+
import { operation } from './operation.js'
|
|
23
|
+
import { receivers, receive } from './receivers.js'
|
|
24
|
+
import { remote } from './remote.js'
|
|
25
|
+
import { storage } from './storage.js'
|
|
26
|
+
import { guards } from './guards.js'
|
|
27
|
+
import { host } from './host.js'
|
|
28
|
+
import { rc } from './rc.js'
|
|
17
29
|
|
|
18
|
-
|
|
19
|
-
exports.bridge = require('./bridge')
|
|
20
|
-
exports.contract = require('./contract')
|
|
21
|
-
exports.discovery = require('./discovery')
|
|
22
|
-
exports.extensions = require('./extensions')
|
|
30
|
+
export { call, cascade, component, composition, context, emission, events, outbox, atomicity, atom, exposition, host, manifest, operation, receivers, receive, remote, storage, guards, rc }
|
|
23
31
|
|
|
24
|
-
|
|
25
|
-
exports.cascade = cascade
|
|
26
|
-
exports.component = component
|
|
27
|
-
exports.composition = composition
|
|
28
|
-
exports.context = context
|
|
29
|
-
exports.emission = emission
|
|
30
|
-
exports.exposition = exposition
|
|
31
|
-
exports.manifest = manifest
|
|
32
|
-
exports.operation = operation
|
|
33
|
-
exports.receivers = receivers
|
|
34
|
-
exports.receive = receive
|
|
35
|
-
exports.remote = remote
|
|
36
|
-
exports.storage = storage
|
|
32
|
+
export { bindings, bridge, contract, discovery, extensions }
|
package/src/manifest.js
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
import clone from 'clone-deep'
|
|
2
|
+
import { basename } from 'node:path'
|
|
3
|
+
import { merge } from '@toa.io/generic'
|
|
4
|
+
import { component as load } from '@toa.io/norm'
|
|
5
|
+
import { Locator } from '@toa.io/core'
|
|
2
6
|
|
|
3
|
-
|
|
4
|
-
const { merge } = require('@toa.io/generic')
|
|
5
|
-
const { component: load } = require('@toa.io/norm')
|
|
6
|
-
const { Locator } = require('@toa.io/core')
|
|
7
|
+
import { span } from './span.js'
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
* @type {toa.boot.Manifest}
|
|
10
|
-
*/
|
|
11
|
-
const manifest = async (path, options = {}) => {
|
|
9
|
+
export const manifest = async (path, options = {}) => {
|
|
12
10
|
options = merge(clone(options), DEFAULTS)
|
|
13
11
|
|
|
14
|
-
const manifest = await
|
|
12
|
+
const manifest = await span({ name: `manifest ${basename(path)}`, attributes: { path } },
|
|
13
|
+
async () => await load(path))
|
|
15
14
|
|
|
16
15
|
if (options?.bindings !== undefined) {
|
|
17
16
|
if ('operations' in manifest) {
|
|
@@ -20,8 +19,16 @@ const manifest = async (path, options = {}) => {
|
|
|
20
19
|
}
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
let asyncBinding
|
|
23
|
+
|
|
24
|
+
for (const binding of options.bindings) {
|
|
25
|
+
const { properties } = await import(binding)
|
|
26
|
+
|
|
27
|
+
if (properties?.async === true) {
|
|
28
|
+
asyncBinding = binding
|
|
29
|
+
break
|
|
30
|
+
}
|
|
31
|
+
}
|
|
25
32
|
|
|
26
33
|
if (asyncBinding === undefined) throw new Error('Bindings override must contain at least one async binding')
|
|
27
34
|
|
|
@@ -52,5 +59,3 @@ const manifest = async (path, options = {}) => {
|
|
|
52
59
|
}
|
|
53
60
|
|
|
54
61
|
const DEFAULTS = {}
|
|
55
|
-
|
|
56
|
-
exports.manifest = manifest
|
package/src/manifest.test.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
import { it, mock } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
import { generate } from 'randomstring'
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
})
|
|
6
|
+
mock.module('@toa.io/norm', { namedExports: { component: () => mockComponent() } })
|
|
7
|
+
|
|
8
|
+
const { manifest } = await import('./manifest.js')
|
|
8
9
|
|
|
9
|
-
const { manifest } = require('./manifest')
|
|
10
10
|
|
|
11
11
|
const path = generate()
|
|
12
12
|
|
|
@@ -15,7 +15,7 @@ it('should not modify options', async () => {
|
|
|
15
15
|
|
|
16
16
|
await manifest(path, options)
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
assert.deepStrictEqual(options.extensions.length, 2)
|
|
19
19
|
})
|
|
20
20
|
|
|
21
21
|
function mockComponent () {
|
package/src/operation.js
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
import { Transition, Observation, Assignment, Operation, Query, Effect, Unmanaged } from '@toa.io/core'
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import * as boot from './index.js'
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
const cascade = boot.cascade(manifest, endpoint, definition, context)
|
|
9
|
-
const reply = boot.contract.reply(definition.output, definition.error)
|
|
5
|
+
export async function operation (manifest, endpoint, definition, context, scope, preflight) {
|
|
6
|
+
const cascade = await boot.cascade(manifest, endpoint, definition, context, preflight)
|
|
7
|
+
const reply = boot.contract.reply(definition.output, definition.errors)
|
|
10
8
|
const input = definition.input
|
|
11
9
|
const request = boot.contract.request({ input }, manifest.entity)
|
|
12
10
|
const contracts = { reply, request }
|
|
11
|
+
|
|
13
12
|
const query = manifest.entity === undefined
|
|
14
13
|
? undefined
|
|
15
14
|
: new Query(manifest.entity.schema.properties)
|
|
@@ -24,7 +23,6 @@ const TYPES = {
|
|
|
24
23
|
observation: Observation,
|
|
25
24
|
assignment: Assignment,
|
|
26
25
|
computation: Operation,
|
|
27
|
-
effect:
|
|
26
|
+
effect: Effect,
|
|
27
|
+
unmanaged: Unmanaged
|
|
28
28
|
}
|
|
29
|
-
|
|
30
|
-
exports.operation = operation
|
package/src/outbox.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Outbox } from '@toa.io/core'
|
|
2
|
+
|
|
3
|
+
import * as boot from './index.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A component with no declared events has nothing to publish and therefore no outbox — the
|
|
7
|
+
* static check that keeps the common case free of a transaction.
|
|
8
|
+
*
|
|
9
|
+
* @param {toa.norm.Component} manifest
|
|
10
|
+
* @param {toa.core.Storage} [storage]
|
|
11
|
+
* @param {toa.core.Emission} [emission]
|
|
12
|
+
*/
|
|
13
|
+
export const outbox = (manifest, storage, emission) => {
|
|
14
|
+
if (emission === undefined) return
|
|
15
|
+
|
|
16
|
+
return new Outbox(emission, storage, boot.atomicity(manifest.locator.id), {})
|
|
17
|
+
}
|
package/src/rc.js
ADDED
package/src/receivers.js
CHANGED
|
@@ -1,34 +1,40 @@
|
|
|
1
|
-
|
|
1
|
+
import { Receiver, Locator } from '@toa.io/core'
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import * as boot from './index.js'
|
|
4
|
+
import * as extensions from './extensions/index.js'
|
|
4
5
|
|
|
5
|
-
const
|
|
6
|
-
const extensions = require('./extensions')
|
|
7
|
-
|
|
8
|
-
const receivers = async (manifest, runtime) => {
|
|
6
|
+
export const receivers = async (manifest, component) => {
|
|
9
7
|
if (manifest.receivers === undefined) return []
|
|
10
8
|
|
|
11
9
|
const receivers = []
|
|
12
|
-
const local = await boot.remote(manifest.locator, manifest)
|
|
10
|
+
const local = await boot.remote(manifest.locator, undefined, manifest)
|
|
13
11
|
|
|
14
12
|
for (const [label, definition] of Object.entries(manifest.receivers)) {
|
|
15
|
-
const
|
|
16
|
-
const
|
|
13
|
+
const locator = Locator.parse(label)
|
|
14
|
+
const source = definition.source ? Locator.parse(definition.source) : locator
|
|
15
|
+
const event = label.split('.').pop()
|
|
16
|
+
const destination = `${source.id}.${event}`
|
|
17
|
+
|
|
18
|
+
// the origin of the calls this receiver makes to its local operation
|
|
19
|
+
const origin = { namespace: source.namespace, component: source.name, event }
|
|
20
|
+
|
|
21
|
+
const bridge = definition.bridge !== undefined
|
|
22
|
+
? await boot.bridge.receiver(definition.bridge, manifest.path, label)
|
|
23
|
+
: undefined
|
|
24
|
+
const receiver = new Receiver({ ...definition, label, destination, origin }, local, bridge)
|
|
17
25
|
const decorator = extensions.receiver(receiver, manifest.locator)
|
|
18
26
|
|
|
19
|
-
const locator = Locator.parse(label)
|
|
20
27
|
const transport = definition.binding ?? await resolveBinding(locator, label)
|
|
21
|
-
const
|
|
22
|
-
const binding = boot.bindings.receive(transport, source, label, manifest.locator.id, decorator)
|
|
28
|
+
const binding = await boot.bindings.receive(transport, source, label, manifest.locator.id, decorator)
|
|
23
29
|
|
|
24
|
-
binding.depends(
|
|
30
|
+
binding.depends(component)
|
|
25
31
|
receivers.push(binding)
|
|
26
32
|
}
|
|
27
33
|
|
|
28
34
|
return receivers
|
|
29
35
|
}
|
|
30
36
|
|
|
31
|
-
async function receive (label, group, callback) {
|
|
37
|
+
export async function receive (label, group, callback) {
|
|
32
38
|
if (callback === undefined) {
|
|
33
39
|
callback = group
|
|
34
40
|
group = undefined
|
|
@@ -37,7 +43,7 @@ async function receive (label, group, callback) {
|
|
|
37
43
|
const locator = Locator.parse(label)
|
|
38
44
|
const transport = await resolveBinding(locator, label)
|
|
39
45
|
|
|
40
|
-
return boot.bindings.receive(transport, locator, label, group, callback)
|
|
46
|
+
return await boot.bindings.receive(transport, locator, label, group, callback)
|
|
41
47
|
}
|
|
42
48
|
|
|
43
49
|
/**
|
|
@@ -52,6 +58,3 @@ async function resolveBinding (locator, label) {
|
|
|
52
58
|
|
|
53
59
|
return events[event].binding
|
|
54
60
|
}
|
|
55
|
-
|
|
56
|
-
exports.receivers = receivers
|
|
57
|
-
exports.receive = receive
|
package/src/remote.js
CHANGED
|
@@ -1,25 +1,43 @@
|
|
|
1
|
-
|
|
1
|
+
import { console } from 'openspan'
|
|
2
|
+
import { Remote } from '@toa.io/core'
|
|
3
|
+
import { remap } from '@toa.io/generic'
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
const { remap } = require('@toa.io/generic')
|
|
5
|
+
import * as boot from './index.js'
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
/**
|
|
8
|
+
* @param {toa.core.Locator} locator
|
|
9
|
+
* @param {toa.core.Source} [source] the origin stamped on every call made through this remote
|
|
10
|
+
* @param {toa.norm.Component} [manifest] skips discovery when the manifest is already known
|
|
11
|
+
*/
|
|
12
|
+
export const remote = async (locator, source, manifest) => {
|
|
13
|
+
let discovery
|
|
7
14
|
|
|
8
|
-
|
|
9
|
-
|
|
15
|
+
if (manifest === undefined) {
|
|
16
|
+
console.debug('Lookup', { locator: locator.id })
|
|
10
17
|
|
|
11
|
-
|
|
18
|
+
discovery = await boot.discovery.discovery(locator)
|
|
19
|
+
manifest = await discovery.lookup(locator)
|
|
20
|
+
}
|
|
12
21
|
|
|
22
|
+
// a call binds its consumers, which are loaded rather than required
|
|
13
23
|
const calls = manifest.operations === undefined
|
|
14
24
|
? {}
|
|
15
|
-
: remap(manifest.operations,
|
|
25
|
+
: await settle(remap(manifest.operations,
|
|
26
|
+
(definition, endpoint) => boot.call(locator, endpoint, definition, manifest.entity, source)))
|
|
16
27
|
|
|
17
28
|
const remote = new Remote(locator, calls)
|
|
18
29
|
|
|
19
30
|
// ensure discovery shutdown
|
|
20
|
-
|
|
31
|
+
if (discovery !== undefined)
|
|
32
|
+
remote.depends(discovery)
|
|
21
33
|
|
|
22
34
|
return remote
|
|
23
35
|
}
|
|
24
36
|
|
|
25
|
-
|
|
37
|
+
/** An object whose values are promises, as an object of what they resolve to. */
|
|
38
|
+
async function settle (object) {
|
|
39
|
+
const entries = Object.entries(object)
|
|
40
|
+
const values = await Promise.all(entries.map(([, promise]) => promise))
|
|
41
|
+
|
|
42
|
+
return Object.fromEntries(entries.map(([key], index) => [key, values[index]]))
|
|
43
|
+
}
|
package/src/span.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { console, traces } from 'openspan'
|
|
2
|
+
|
|
3
|
+
const enabled = process.env.TOA_BOOT_TRACE === '1'
|
|
4
|
+
|
|
5
|
+
// Tracing is off until an exporter is configured, and the CLI opens its own span before
|
|
6
|
+
// any extension gets to configure one — so asking for a boot trace turns the console
|
|
7
|
+
// exporter on here. Extensions keep it: see `development()` in the telemetry factory.
|
|
8
|
+
if (enabled) traces({ exporters: { console: {} } })
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Creates a span if boot tracing is enabled (TOA_BOOT_TRACE=1), otherwise just runs the task
|
|
12
|
+
*
|
|
13
|
+
* @param {string | object} options
|
|
14
|
+
* @param {() => Promise<any>} task
|
|
15
|
+
* @returns {Promise<any>}
|
|
16
|
+
*/
|
|
17
|
+
export const span = async (options, task) => enabled ? console.span(options, task) : task()
|
package/src/storage.js
CHANGED
|
@@ -1,26 +1,32 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { createRequire } from 'node:module'
|
|
2
|
+
import { pathToFileURL } from 'node:url'
|
|
3
|
+
import * as extensions from './extensions/index.js'
|
|
4
|
+
|
|
5
|
+
// import.meta.resolve takes no paths, and the connector is resolved against the
|
|
6
|
+
// component that names it
|
|
7
|
+
const require = createRequire(import.meta.url)
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @param {toa.norm.Component} manifest
|
|
11
|
+
* @param {boolean} outbox whether this component publishes anything, and so needs a place to
|
|
12
|
+
* commit it with the entity
|
|
13
|
+
*/
|
|
14
|
+
export const storage = async (manifest, outbox) => {
|
|
7
15
|
if (manifest.entity === undefined) return
|
|
8
16
|
|
|
9
|
-
const Factory = load(manifest)
|
|
17
|
+
const Factory = await load(manifest)
|
|
10
18
|
|
|
11
19
|
/** @type {toa.core.storages.Factory} */
|
|
12
20
|
const factory = new Factory()
|
|
13
|
-
const storage = factory.storage(manifest.locator, manifest.entity)
|
|
21
|
+
const storage = factory.storage(manifest.locator, manifest.entity, { outbox })
|
|
14
22
|
|
|
15
23
|
return extensions.storage(storage)
|
|
16
24
|
}
|
|
17
25
|
|
|
18
|
-
function load (component) {
|
|
26
|
+
async function load (component) {
|
|
19
27
|
const reference = component.entity.storage
|
|
20
|
-
const path = require.resolve(reference, { paths: [component.path,
|
|
21
|
-
const { Factory } =
|
|
28
|
+
const path = require.resolve(reference, { paths: [component.path, import.meta.dirname] })
|
|
29
|
+
const { Factory } = await import(pathToFileURL(path).href)
|
|
22
30
|
|
|
23
31
|
return Factory
|
|
24
32
|
}
|
|
25
|
-
|
|
26
|
-
exports.storage = storage
|
package/types/index.d.ts
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
import * as core from '@toa.io/core'
|
|
2
|
-
import * as composition from './composition'
|
|
2
|
+
import * as composition from './composition.js'
|
|
3
3
|
|
|
4
|
-
export * as bindings from './bindings'
|
|
4
|
+
export * as bindings from './bindings.js'
|
|
5
5
|
|
|
6
6
|
export async function composition (paths: string[], options?: composition.Options): Promise<core.Connector>
|
|
7
7
|
|
|
8
|
-
export async function remote (locator: core.Locator): Promise<core.
|
|
8
|
+
export async function remote (locator: core.Locator, source?: core.Source): Promise<core.Remote>
|
|
9
9
|
|
|
10
10
|
export async function receive<T = any> (
|
|
11
11
|
label: string,
|
|
12
|
-
receiver: Receiver
|
|
12
|
+
receiver: Receiver
|
|
13
13
|
): Promise<core.Connector>
|
|
14
14
|
|
|
15
15
|
export async function receive<T = any> (
|
|
16
16
|
label: string,
|
|
17
17
|
group: string | undefined,
|
|
18
|
-
receiver: Receiver
|
|
18
|
+
receiver: Receiver
|
|
19
19
|
): Promise<core.Connector>
|
|
20
20
|
|
|
21
21
|
type Receiver = { receive: (message: core.Message<T>) => void | Promise<void> }
|
|
22
|
+
|
|
23
|
+
export function host (): core.extensions.Host
|
package/types/manifest.d.ts
CHANGED