@toa.io/operations 0.20.0-dev.4 → 0.20.0-dev.40

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.
Files changed (32) hide show
  1. package/package.json +6 -5
  2. package/readme.md +14 -2
  3. package/src/deployment/.deployment/.describe/components.js +1 -0
  4. package/src/deployment/.deployment/.describe/compositions.js +26 -0
  5. package/src/deployment/.deployment/.describe/index.js +4 -0
  6. package/src/deployment/.deployment/.describe/services.js +9 -0
  7. package/src/deployment/.deployment/describe.js +9 -10
  8. package/src/deployment/chart/templates/compositions.yaml +7 -12
  9. package/src/deployment/chart/templates/services.yaml +2 -2
  10. package/src/deployment/chart/values.yaml +13 -13
  11. package/src/deployment/deployment.js +28 -25
  12. package/src/deployment/factory.js +2 -5
  13. package/src/deployment/images/composition.Dockerfile +8 -7
  14. package/src/deployment/images/service.Dockerfile +7 -5
  15. package/src/deployment/operator.js +0 -3
  16. package/types/_deployment/operator.d.ts +20 -0
  17. package/types/dependency.d.ts +36 -0
  18. package/types/index.d.ts +1 -0
  19. package/src/deployment/chart/templates/proxies.yaml +0 -10
  20. package/src/deployment/deployment.fixtures.js +0 -42
  21. package/src/deployment/deployment.test.js +0 -78
  22. package/types/deployment/operator.d.ts +0 -18
  23. package/types/process.d.ts +0 -13
  24. /package/types/{deployment → _deployment}/composition.d.ts +0 -0
  25. /package/types/{deployment → _deployment}/dependency.d.ts +0 -0
  26. /package/types/{deployment → _deployment}/deployment.d.ts +0 -0
  27. /package/types/{deployment → _deployment}/factory.d.ts +0 -0
  28. /package/types/{deployment → _deployment}/images/factory.d.ts +0 -0
  29. /package/types/{deployment → _deployment}/images/image.d.ts +0 -0
  30. /package/types/{deployment → _deployment}/images/registry.d.ts +0 -0
  31. /package/types/{deployment → _deployment}/registry.d.ts +0 -0
  32. /package/types/{deployment → _deployment}/service.d.ts +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toa.io/operations",
3
- "version": "0.20.0-dev.4",
3
+ "version": "0.20.0-dev.40",
4
4
  "description": "Toa Deployment",
5
5
  "homepage": "https://toa.io",
6
6
  "author": {
@@ -22,14 +22,15 @@
22
22
  "access": "public"
23
23
  },
24
24
  "main": "src/index.js",
25
+ "types": "types/index.d.ts",
25
26
  "scripts": {
26
27
  "test": "echo \"Error: run tests from root\" && exit 1"
27
28
  },
28
29
  "dependencies": {
29
- "@toa.io/filesystem": "0.20.0-dev.4",
30
- "@toa.io/generic": "0.20.0-dev.4",
31
- "@toa.io/yaml": "0.20.0-dev.4",
30
+ "@toa.io/filesystem": "0.20.0-dev.40",
31
+ "@toa.io/generic": "0.20.0-dev.40",
32
+ "@toa.io/yaml": "0.20.0-dev.40",
32
33
  "execa": "5.1.1"
33
34
  },
34
- "gitHead": "a62b12d77a405d18eb92e879672455b6fb2fd9f2"
35
+ "gitHead": "594543488de934deba3598ec5805744af1b3f4c0"
35
36
  }
package/readme.md CHANGED
@@ -11,8 +11,8 @@
11
11
 
12
12
  registry:
13
13
  build:
14
- arguments: [NPM_TOKEN]
15
- run: echo //npm.pkg.github.com/:_authToken=${NPM_TOKEN} > .npmrc
14
+ arguments: [GITHUB_TOKEN]
15
+ run: npm config set //npm.pkg.github.com/:_authToken ${GITHUB_TOKEN}
16
16
  ```
17
17
 
18
18
  `arguments` is a list of environemt varialbes to be passed to `docker build`.
@@ -28,3 +28,15 @@ registry:
28
28
  echo test > .test
29
29
  rm .test
30
30
  ```
31
+
32
+ #### Registry Credentials
33
+
34
+ When using private container registry,
35
+ a secret containing required credentials can be specified using `registry.credentials` option.
36
+
37
+ ```yaml
38
+ # context.toa.yaml
39
+
40
+ registry:
41
+ credentials: docker-credentials-secret-name
42
+ ```
@@ -16,4 +16,5 @@ const components = (compositions) => {
16
16
 
17
17
  return Array.from(components)
18
18
  }
19
+
19
20
  exports.components = components
@@ -0,0 +1,26 @@
1
+ 'use strict'
2
+
3
+ function compositions (compositions, variables) {
4
+ for (const composition of compositions) {
5
+ addVariables(composition, variables)
6
+ }
7
+ }
8
+
9
+ function addVariables (composition, variables) {
10
+ const used = new Set()
11
+
12
+ composition.variables ??= []
13
+
14
+ for (const [key, set] of Object.entries(variables)) {
15
+ if (key !== 'global' && !composition.components.includes(key)) continue
16
+
17
+ for (const variable of set) {
18
+ if (used.has(variable.name)) continue
19
+
20
+ composition.variables.push(variable)
21
+ used.add(variable.name)
22
+ }
23
+ }
24
+ }
25
+
26
+ exports.compositions = compositions
@@ -2,8 +2,12 @@
2
2
 
3
3
  const { dependencies } = require('./dependencies')
4
4
  const { components } = require('./components')
5
+ const { compositions } = require('./compositions')
5
6
  const { variables } = require('./variables')
7
+ const { services } = require('./services')
6
8
 
7
9
  exports.dependencies = dependencies
8
10
  exports.components = components
11
+ exports.compositions = compositions
9
12
  exports.variables = variables
13
+ exports.services = services
@@ -0,0 +1,9 @@
1
+ 'use strict'
2
+
3
+ function services (services, variables) {
4
+ for (const service of services) {
5
+ service.variables = variables.global
6
+ }
7
+ }
8
+
9
+ exports.services = services
@@ -2,25 +2,24 @@
2
2
 
3
3
  const get = require('./.describe')
4
4
 
5
- /**
6
- * @param {toa.norm.Context} context
7
- * @param {toa.deployment.Composition[]} compositions
8
- * @param {toa.deployment.Dependency} dependency
9
- * @returns {toa.deployment.Contents}
10
- */
11
5
  const describe = (context, compositions, dependency) => {
12
- const { references, services, proxies } = dependency
6
+ const { references, services } = dependency
7
+
8
+ dependency.variables.global ??= []
9
+ dependency.variables.global.unshift({ name: 'TOA_ENV', value: context.environment })
13
10
 
14
11
  const components = get.components(compositions)
15
12
  const dependencies = get.dependencies(references)
16
- const variables = get.variables(context, dependency.variables)
13
+ const credentials = context.registry?.credentials
14
+
15
+ get.compositions(compositions, dependency.variables, context.environment)
16
+ get.services(services, dependency.variables)
17
17
 
18
18
  return {
19
19
  compositions,
20
20
  components,
21
21
  services,
22
- proxies,
23
- variables,
22
+ credentials,
24
23
  ...dependencies
25
24
  }
26
25
  }
@@ -2,7 +2,7 @@
2
2
  apiVersion: apps/v1
3
3
  kind: Deployment
4
4
  metadata:
5
- name: composition-{{ required "deployment name is required" .name }}
5
+ name: composition-{{ required "composition name is required" .name }}
6
6
  spec:
7
7
  replicas: {{ .replicas | default 2 }}
8
8
  selector:
@@ -19,20 +19,15 @@ spec:
19
19
  containers:
20
20
  - name: {{ .name }}
21
21
  image: {{ .image }}
22
- {{- if $.Values.variables }}
22
+ {{- if .variables }}
23
23
  env:
24
- {{- range $component := .components }}
25
- {{- range $key, $vars := $.Values.variables }}
26
- {{- if eq $component $key }}
27
- {{- range $vars }}
28
- {{- include "env.var" . | indent 12 }}
29
- {{- end }}
30
- {{- end }}
31
- {{- end }}
32
- {{- end }}
33
- {{- range $.Values.variables.global }}
24
+ {{- range .variables }}
34
25
  {{- include "env.var" . | indent 12 }}
35
26
  {{- end }}
36
27
  {{- end }}
28
+ {{- if $.Values.credentials }}
29
+ imagePullSecrets:
30
+ - name: {{ $.Values.credentials }}
31
+ {{- end }}
37
32
  ---
38
33
  {{- end }}
@@ -16,9 +16,9 @@ spec:
16
16
  containers:
17
17
  - name: {{ .name }}
18
18
  image: {{ .image }}
19
- {{- if $.Values.variables }}
19
+ {{- if .variables }}
20
20
  env:
21
- {{- range $.Values.variables.global }}
21
+ {{- range .variables }}
22
22
  {{- include "env.var" . | indent 12 }}
23
23
  {{- end }}
24
24
  {{- end }}
@@ -6,6 +6,12 @@ compositions:
6
6
  components:
7
7
  - todos-tasks
8
8
  - todos-stats
9
+ variables:
10
+ - name: TOA_CONFIGURATION_TODOS_TASKS
11
+ value: foo
12
+ secret:
13
+ name: secret-name
14
+ key: secret-key
9
15
  - name: users
10
16
  image: localhost:5000/composition-users:0.0.0
11
17
  replicas: 3
@@ -16,19 +22,6 @@ components:
16
22
  - todos-tasks
17
23
  - todos-stats
18
24
  - users-users
19
- variables:
20
- global:
21
- - name: TOA_BINDINGS_AMQP_SYSTEM_USERNAME
22
- value: foo
23
- secret:
24
- name: secret-name
25
- key: secret-key
26
- todos-tasks:
27
- - name: TOA_CONFIGURATION_TODOS_TASKS
28
- value: foo
29
- secret:
30
- name: secret-name
31
- key: secret-key
32
25
  services:
33
26
  - name: resources-gateway
34
27
  image: localhost:5000/resources-gateway:0.0.0
@@ -41,7 +34,14 @@ services:
41
34
  alb.ingress.kubernetes.io/scheme: internet-facing
42
35
  alb.ingress.kubernetes.io/target-type: ip
43
36
  alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS": 443}]'
37
+ variables:
38
+ - name: TOA_CONFIGURATION_TODOS_TASKS
39
+ value: foo
40
+ secret:
41
+ name: secret-name
42
+ key: secret-key
44
43
  proxies:
45
44
  - name: storage-proxy
46
45
  target: host.docker.internal
47
46
  environment: development
47
+ credentials: docker-credentials
@@ -7,39 +7,23 @@ const { dump } = require('@toa.io/yaml')
7
7
 
8
8
  const { merge, declare, describe } = require('./.deployment')
9
9
 
10
- /**
11
- * @implements {toa.deployment.Deployment}
12
- */
13
10
  class Deployment {
14
- /** @type {toa.deployment.Declaration} */
15
- #declaration
16
-
17
- /** @type {toa.deployment.Contents} */
18
- #contents
19
-
20
- /** @type {toa.operations.Process} */
11
+ #chart
12
+ #values
21
13
  #process
22
-
23
- /** @type {string} */
24
14
  #target
25
15
 
26
- /**
27
- * @param context {toa.norm.Context}
28
- * @param compositions {toa.deployment.Composition[]}
29
- * @param dependencies {toa.deployment.Dependency[]}
30
- * @param process {toa.operations.Process}
31
- */
32
16
  constructor (context, compositions, dependencies, process) {
33
17
  const dependency = merge(dependencies)
34
18
 
35
- this.#declaration = declare(context, dependency)
36
- this.#contents = describe(context, compositions, dependency)
19
+ this.#chart = declare(context, dependency)
20
+ this.#values = describe(context, compositions, dependency)
37
21
  this.#process = process
38
22
  }
39
23
 
40
24
  async export (target) {
41
- const chart = dump(this.#declaration)
42
- const values = dump(this.#contents)
25
+ const chart = dump(this.#chart)
26
+ const values = dump(this.#values)
43
27
 
44
28
  await Promise.all([
45
29
  write(join(target, 'Chart.yaml'), chart),
@@ -60,7 +44,7 @@ class Deployment {
60
44
  if (options.wait === true) args.push('--wait')
61
45
 
62
46
  await this.#process.execute('helm', ['dependency', 'update', this.#target])
63
- await this.#process.execute('helm', ['upgrade', this.#declaration.name, '-i', ...args, this.#target])
47
+ await this.#process.execute('helm', ['upgrade', this.#chart.name, '-i', ...args, this.#target])
64
48
  }
65
49
 
66
50
  async template (options) {
@@ -73,12 +57,31 @@ class Deployment {
73
57
  if (options.namespace !== undefined) args.push('-n', options.namespace)
74
58
 
75
59
  return await this.#process.execute('helm',
76
- ['template', this.#declaration.name, ...args, this.#target],
60
+ ['template', this.#chart.name, ...args, this.#target],
77
61
  { silently: true })
78
62
  }
79
63
 
80
64
  variables () {
81
- return this.#contents.variables
65
+ const variables = []
66
+ const used = new Set()
67
+
68
+ addVariables(this.#values.compositions, variables, used)
69
+ addVariables(this.#values.services, variables, used)
70
+
71
+ return variables
72
+ }
73
+ }
74
+
75
+ function addVariables (list, variables, used = new Set()) {
76
+ for (const item of list) {
77
+ if (item.variables === undefined) continue
78
+
79
+ for (const variable of item.variables) {
80
+ if (used.has(variable.name)) continue
81
+
82
+ variables.push(variable)
83
+ used.add(variable.name)
84
+ }
82
85
  }
83
86
  }
84
87
 
@@ -8,9 +8,6 @@ const { Registry } = require('./registry')
8
8
  const { Composition } = require('./composition')
9
9
  const { Service } = require('./service')
10
10
 
11
- /**
12
- * @implements {toa.deployment.Factory}
13
- */
14
11
  class Factory {
15
12
  /** @type {toa.norm.Context} */
16
13
  #context
@@ -90,10 +87,10 @@ class Factory {
90
87
 
91
88
  if (module.deployment === undefined) return
92
89
 
93
- const annotations = this.#context.annotations?.[pkg.name]
90
+ const annotation = this.#context.annotations?.[pkg.name]
94
91
 
95
92
  /** @type {toa.deployment.dependency.Declaration} */
96
- const dependency = module.deployment(instances, annotations)
93
+ const dependency = module.deployment(instances, annotation)
97
94
 
98
95
  /** @type {toa.deployment.Service[]} */
99
96
  const services = dependency.services?.map((service) => this.#service(path, service))
@@ -3,16 +3,17 @@ FROM node:18.16.0-alpine3.17
3
3
  {{build.arguments}}
4
4
 
5
5
  ENV NODE_ENV=production
6
- RUN if [ {{runtime.registry}} != undefined ]; then npm set registry {{runtime.registry}}; fi
7
- RUN if [ {{runtime.proxy}} != undefined ]; then npm set proxy {{runtime.proxy}}; fi
8
- RUN npm i -g @toa.io/runtime@{{runtime.version}}
6
+ RUN if [ "{{runtime.registry}}" != "" ]; then npm set registry {{runtime.registry}}; fi
7
+ RUN if [ "{{runtime.proxy}}" != "" ]; then npm set proxy {{runtime.proxy}}; fi
8
+ RUN npm i -g @toa.io/runtime@{{runtime.version}} --omit=dev
9
9
 
10
10
  WORKDIR /composition
11
- ADD . .
12
-
13
- # run 'npm i' in each component
14
- RUN find . -maxdepth 1 -type d \( ! -name . \) -exec /bin/sh -c "cd '{}' && if [ -f package.json ]; then npm i; fi" \;
11
+ COPY --chown=node:node . /composition
15
12
 
16
13
  {{build.run}}
17
14
 
15
+ # run 'npm i' in each component
16
+ RUN for entry in *; do if [ -f "$entry/package.json" ]; then (cd $entry && npm i --omit=dev); fi; done
17
+
18
+ USER node
18
19
  CMD toa compose *
@@ -1,12 +1,14 @@
1
1
  FROM node:18.16.0-alpine3.17
2
2
 
3
3
  ENV NODE_ENV=production
4
- RUN if [ {{runtime.registry}} != undefined ]; then npm set registry {{runtime.registry}}; fi
5
- RUN if [ {{runtime.proxy}} != undefined ]; then npm set proxy {{runtime.proxy}}; fi
6
- RUN npm i -g @toa.io/runtime@{{runtime.version}}
4
+ RUN if [ "{{runtime.registry}}" != "" ]; then npm set registry {{runtime.registry}}; fi
5
+ RUN if [ "{{runtime.proxy}}" != "" ]; then npm set proxy {{runtime.proxy}}; fi
6
+ RUN npm i -g @toa.io/runtime@{{runtime.version}} --omit=dev
7
7
 
8
8
  WORKDIR /service
9
- ADD . .
10
- RUN npm i
9
+ COPY --chown=node:node . /service
11
10
 
11
+ RUN npm i --omit=dev
12
+
13
+ USER node
12
14
  CMD toa serve .
@@ -2,9 +2,6 @@
2
2
 
3
3
  const workspace = require('./workspace')
4
4
 
5
- /**
6
- * @implements {toa.deployment.Operator}
7
- */
8
5
  class Operator {
9
6
  /** @type {toa.deployment.Deployment} */
10
7
  #deployment
@@ -0,0 +1,20 @@
1
+ import * as _deployment from './deployment'
2
+ import * as _dependency from './dependency'
3
+
4
+ declare namespace toa.deployment {
5
+
6
+ interface Operator {
7
+ export (path?: string): Promise<string>
8
+
9
+ install (options?: _deployment.installation.Options): Promise<void>
10
+
11
+ template (options?: _deployment.template.Options): Promise<string>
12
+
13
+ variables (): _dependency.Variables
14
+
15
+ listVariables (): _dependency.Variable[]
16
+ }
17
+
18
+ }
19
+
20
+ export type Operator = toa.deployment.Operator
@@ -0,0 +1,36 @@
1
+ type Reference = {
2
+ name: string
3
+ version: string
4
+ repository?: string
5
+ alias?: string
6
+ values?: Object
7
+ }
8
+
9
+ type Service = {
10
+ group: string
11
+ name: string
12
+ version: string
13
+ port: number
14
+ ingress?: {
15
+ host: string
16
+ class: string
17
+ annotations?: object
18
+ }
19
+ }
20
+
21
+ export type Variable = {
22
+ name: string
23
+ value?: string
24
+ secret?: {
25
+ name: string,
26
+ key: string
27
+ }
28
+ }
29
+
30
+ export type Variables = Record<string, Variable[]>
31
+
32
+ export type Dependency = {
33
+ references?: Reference[]
34
+ services?: Service[]
35
+ variables?: Variables
36
+ }
@@ -0,0 +1 @@
1
+ export * from './dependency'
@@ -1,10 +0,0 @@
1
- {{- range .Values.proxies }}
2
- apiVersion: v1
3
- kind: Service
4
- metadata:
5
- name: {{ .name }}
6
- spec:
7
- type: ExternalName
8
- externalName: {{ .target }}
9
- ---
10
- {{- end }}
@@ -1,42 +0,0 @@
1
- 'use strict'
2
-
3
- const { generate } = require('randomstring')
4
-
5
- const context = /** @type {toa.norm.Context} */ { name: generate() }
6
- const compositions = []
7
- /** @type {toa.deployment.Dependency[]} */
8
-
9
- /** @type {toa.deployment.dependency.Variable} */
10
- const bindingVariable = {
11
- name: 'TOA_BINDINGS_AMQP_POINTER',
12
- value: 'eyJkZWZhdWx0IjoiYW1xcDovL3doYXRldmVyIiwic3lzdGVtIjoiYW1xcDovL2hvc3QwIn0='
13
- }
14
-
15
- /** @type {toa.deployment.dependency.Variable} */
16
- const secretVariable = {
17
- name: 'TOA_BINDINGS_AMQP_DEFAULT_USERNAME',
18
- secret: {
19
- name: 'toa-bindings-amqp-default',
20
- key: 'username'
21
- }
22
- }
23
-
24
- /** @type {toa.deployment.Dependency[]} */
25
- const dependencies = [{
26
- variables: { global: [bindingVariable, secretVariable] }
27
- }]
28
-
29
- const process = /** @type {toa.operations.Process} */ { execute: jest.fn() }
30
-
31
- const options = /** @type {toa.deployment.installation.Options} */ {
32
- namespace: generate(),
33
- target: generate()
34
- }
35
-
36
- exports.context = context
37
- exports.compositions = compositions
38
- exports.dependencies = dependencies
39
- exports.process = process
40
- exports.options = options
41
- exports.bindingVariable = bindingVariable
42
- exports.secretVariable = secretVariable
@@ -1,78 +0,0 @@
1
- 'use strict'
2
-
3
- const clone = require('clone-deep')
4
-
5
- const fixtures = require('./deployment.fixtures')
6
- const { Deployment } = require('../../src/deployment/deployment')
7
-
8
- /** @type {toa.deployment.Deployment} */
9
- let deployment
10
- /** @type {toa.deployment.installation.Options} */
11
- let options
12
-
13
- beforeEach(() => {
14
- deployment = new Deployment(fixtures.context, fixtures.compositions, fixtures.dependencies, fixtures.process)
15
- options = clone(fixtures.options)
16
- })
17
-
18
- it('should pass -n argument if options.namespace is set', async () => {
19
- await deployment.install(options)
20
-
21
- const call = fixtures.process.execute.mock.calls.find((call) => call[0] === 'helm' && call[1][0] === 'upgrade')
22
-
23
- expect(call).toBeDefined()
24
-
25
- const args = call[1]
26
- const index = args.findIndex((value) => value === '-n')
27
- const namespace = args[index + 1]
28
-
29
- expect(index).not.toStrictEqual(-1)
30
- expect(namespace).toStrictEqual(fixtures.options.namespace)
31
- })
32
-
33
- describe('variables', () => {
34
- let deployment /** @type {toa.deployment.Deployment} */
35
-
36
- it('should be define', () => {
37
- const context = clone(fixtures.context)
38
-
39
- deployment = new Deployment(context, fixtures.compositions, fixtures.dependencies, fixtures.process)
40
-
41
- expect(typeof deployment.variables).toBe('function')
42
- })
43
-
44
- it('should return variables', () => {
45
- const context = clone(fixtures.context)
46
- const [{ variables }] = fixtures.dependencies
47
-
48
- deployment = new Deployment(context, fixtures.compositions, fixtures.dependencies, fixtures.process)
49
- expect(deployment.variables()).toEqual(variables)
50
- })
51
-
52
- it('should return variables', () => {
53
- const context = clone(fixtures.context)
54
- const [{ variables }] = fixtures.dependencies
55
-
56
- deployment = new Deployment(context, fixtures.compositions, fixtures.dependencies, fixtures.process)
57
-
58
- expect(deployment.variables()).toEqual(variables)
59
- })
60
-
61
- it('should merge all variables', () => {
62
- const context = clone(fixtures.context)
63
-
64
- /** @type {toa.deployment.Dependency} */
65
- const dep1 = { variables: { global: [fixtures.secretVariable] } }
66
-
67
- /** @type {toa.deployment.Dependency} */
68
- const dep2 = { variables: { global: [fixtures.bindingVariable] } }
69
-
70
- deployment = new Deployment(context, fixtures.compositions, [dep1, dep2], fixtures.process)
71
-
72
- const result = deployment.variables()
73
- const expectedVariables = [fixtures.bindingVariable, fixtures.secretVariable]
74
-
75
- expect(result.global.length).toBe(expectedVariables.length)
76
- expect(result.global).toStrictEqual(expect.arrayContaining(expectedVariables))
77
- })
78
- })
@@ -1,18 +0,0 @@
1
- import * as _deployment from './deployment'
2
- import * as _dependency from './dependency'
3
-
4
- declare namespace toa.deployment {
5
-
6
- interface Operator {
7
- export(path?: string): Promise<string>
8
-
9
- install(options?: _deployment.installation.Options): Promise<void>
10
-
11
- template(options?: _deployment.template.Options): Promise<string>
12
-
13
- variables(): _dependency.Variables
14
- }
15
-
16
- }
17
-
18
- export type Operator = toa.deployment.Operator
@@ -1,13 +0,0 @@
1
- declare namespace toa.operations {
2
-
3
- namespace process {
4
- interface Options {
5
- silently?: boolean
6
- }
7
- }
8
-
9
- interface Process {
10
- execute(cmd: string, args: Array<string>, options?: process.Options): Promise<string>
11
- }
12
-
13
- }
File without changes
File without changes
File without changes