@stepzen/sdk 0.9.41 → 0.9.44
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 +14 -14
- package/lib/commands/account.d.ts +9 -0
- package/lib/commands/account.js +39 -0
- package/lib/commands/account.js.map +1 -0
- package/lib/commands/authenticate.d.ts +2 -2
- package/lib/commands/authenticate.js +6 -5
- package/lib/commands/authenticate.js.map +1 -0
- package/lib/commands/deploy.d.ts +2 -2
- package/lib/commands/deploy.js +9 -8
- package/lib/commands/deploy.js.map +1 -0
- package/lib/commands/list.d.ts +2 -2
- package/lib/commands/list.js +7 -6
- package/lib/commands/list.js.map +1 -0
- package/lib/commands/upload.d.ts +2 -2
- package/lib/commands/upload.js +13 -12
- package/lib/commands/upload.js.map +1 -0
- package/lib/index.d.ts +22 -5
- package/lib/index.js +72 -35
- package/lib/index.js.map +1 -0
- package/lib/shared/constants.d.ts +1 -0
- package/lib/shared/constants.js +7 -5
- package/lib/shared/constants.js.map +1 -0
- package/lib/shared/payloads.d.ts +1 -1
- package/lib/shared/payloads.js +12 -11
- package/lib/shared/payloads.js.map +1 -0
- package/lib/shared/request.d.ts +2 -2
- package/lib/shared/request.js +13 -7
- package/lib/shared/request.js.map +1 -0
- package/lib/shared/transpiling.js +4 -3
- package/lib/shared/transpiling.js.map +1 -0
- package/lib/shared/types.d.ts +36 -3
- package/lib/shared/types.js +1 -0
- package/lib/shared/types.js.map +1 -0
- package/lib/shared/validation.js +9 -8
- package/lib/shared/validation.js.map +1 -0
- package/package.json +18 -9
- package/src/commands/account.ts +54 -0
- package/src/commands/authenticate.ts +30 -0
- package/src/commands/deploy.ts +72 -0
- package/src/commands/list.ts +50 -0
- package/src/commands/upload.ts +95 -0
- package/src/index.ts +121 -0
- package/src/shared/constants.ts +7 -0
- package/src/shared/payloads.ts +105 -0
- package/src/shared/request.ts +26 -0
- package/src/shared/transpiling.ts +36 -0
- package/src/shared/types.ts +75 -0
- package/src/shared/validation.ts +42 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// Copyright (c) 2020,2021,2022, StepZen, Inc.
|
|
2
|
+
|
|
3
|
+
// This file contains helpers that zip a file or directory
|
|
4
|
+
|
|
5
|
+
import * as archiver from 'archiver'
|
|
6
|
+
import * as debug from 'debug'
|
|
7
|
+
import * as FormData from 'form-data'
|
|
8
|
+
import * as fs from 'fs'
|
|
9
|
+
import * as glob from 'glob'
|
|
10
|
+
import * as os from 'os'
|
|
11
|
+
import * as path from 'path'
|
|
12
|
+
|
|
13
|
+
type YamlPayload = FormData
|
|
14
|
+
type ZipPayload = FormData
|
|
15
|
+
|
|
16
|
+
// This function takes a (yaml) file path
|
|
17
|
+
// and creates a FormData payload, containing the yaml content as 'yaml'
|
|
18
|
+
export const generateYamlPayload = async (
|
|
19
|
+
file: string | undefined,
|
|
20
|
+
): Promise<YamlPayload> => {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
const payload = new FormData()
|
|
23
|
+
|
|
24
|
+
if (file) {
|
|
25
|
+
if (!fs.existsSync(file)) {
|
|
26
|
+
reject(new Error(`File does not exist: ${file}`))
|
|
27
|
+
}
|
|
28
|
+
const content = fs.readFileSync(file, 'utf8')
|
|
29
|
+
debug('stepzen:generate-yaml-payload')(content)
|
|
30
|
+
payload.append('yaml', fs.readFileSync(file))
|
|
31
|
+
resolve(payload)
|
|
32
|
+
} else {
|
|
33
|
+
reject(new Error('File not specified'))
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// This function takes a directory path, and optional data object,
|
|
39
|
+
// and creates a FormData payload, containing the directory contents as 'zip',
|
|
40
|
+
// and any other items in the data object.
|
|
41
|
+
export const generateZipPayload = async (
|
|
42
|
+
directory: string | undefined,
|
|
43
|
+
data: object | undefined,
|
|
44
|
+
filters: RegExp[],
|
|
45
|
+
): Promise<ZipPayload> => {
|
|
46
|
+
return new Promise((resolve, reject) => {
|
|
47
|
+
const payload = new FormData()
|
|
48
|
+
|
|
49
|
+
if (data) {
|
|
50
|
+
for (const [key, value] of Object.entries(data)) {
|
|
51
|
+
payload.append(key, value)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Store it in /tmp. Create a WriteStream
|
|
56
|
+
const filepath = path.join(os.tmpdir(), `stepzen-payload-${Date.now()}.zip`)
|
|
57
|
+
const output = fs.createWriteStream(filepath)
|
|
58
|
+
|
|
59
|
+
// We're making a zip file
|
|
60
|
+
const archive = archiver('zip', {
|
|
61
|
+
zlib: {level: 9},
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
// We're piping it to the WriteStream
|
|
65
|
+
archive.pipe(output)
|
|
66
|
+
|
|
67
|
+
// If we've specified a directory, add it to the archive
|
|
68
|
+
if (directory) {
|
|
69
|
+
if (!fs.existsSync(directory)) {
|
|
70
|
+
reject(new Error(`Directory does not exist: ${directory}`))
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Get all the files in the directory (and all subdirectories).
|
|
74
|
+
const allFiles = glob.sync('**', {cwd: directory})
|
|
75
|
+
|
|
76
|
+
// Loop through each file, because we want to filter them
|
|
77
|
+
// We add them manually, because when we use glob, it embeds
|
|
78
|
+
// a full path, and we want everything to explicitly
|
|
79
|
+
// start at the root of the archive.
|
|
80
|
+
allFiles.forEach(file => {
|
|
81
|
+
const include = filters.some(filter => file.match(filter))
|
|
82
|
+
|
|
83
|
+
if (include) {
|
|
84
|
+
debug('stepzen:archive')(file)
|
|
85
|
+
archive.file(path.join(directory, file), {name: file})
|
|
86
|
+
}
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Once we're done, append a ReadStream to the tmp file
|
|
91
|
+
output.on('close', () => {
|
|
92
|
+
const stream = fs.createReadStream(filepath)
|
|
93
|
+
payload.append('zip', stream)
|
|
94
|
+
// Remove the temporary zip
|
|
95
|
+
stream.on('close', () => {
|
|
96
|
+
fs.unlinkSync(filepath)
|
|
97
|
+
})
|
|
98
|
+
// This is where we return the payload
|
|
99
|
+
resolve(payload)
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
// Archive the file or directory
|
|
103
|
+
archive.finalize()
|
|
104
|
+
})
|
|
105
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Copyright (c) 2020,2021,2022, StepZen, Inc.
|
|
2
|
+
|
|
3
|
+
import * as os from 'os'
|
|
4
|
+
import * as isWsl from 'is-wsl'
|
|
5
|
+
import {SDKConfiguration, StepZenAccount, ZenCtlRequestHeaders} from './types'
|
|
6
|
+
|
|
7
|
+
const {version} = require('../../package.json')
|
|
8
|
+
|
|
9
|
+
// mimics the logic from @oclif/config
|
|
10
|
+
// https://github.com/oclif/core/blob/d7067d13c7d80c9e0064455c27ac1ebb6ee53fd2/src/config/config.ts#L128
|
|
11
|
+
const arch = os.arch() === 'ia32' ? 'x86' : (os.arch() as any)
|
|
12
|
+
const platform = isWsl ? 'wsl' : (os.platform() as any)
|
|
13
|
+
|
|
14
|
+
export const getRequestHeaders = (
|
|
15
|
+
account: StepZenAccount,
|
|
16
|
+
sdkConfig: SDKConfiguration,
|
|
17
|
+
): ZenCtlRequestHeaders => {
|
|
18
|
+
const userAgent = `${sdkConfig.appName} stepzen-sdk/${version} (${platform}; ${arch}; node-${process.version})`
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
authorization: `Apikey ${account.adminkey}`,
|
|
22
|
+
host: `${account.account}.${account.domain}`,
|
|
23
|
+
'stepzen-cli-version': version,
|
|
24
|
+
'user-agent': userAgent,
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Copyright (c) 2020,2021,2022, StepZen, Inc.
|
|
2
|
+
|
|
3
|
+
import * as dotenv from 'dotenv'
|
|
4
|
+
import * as fs from 'fs-extra'
|
|
5
|
+
import * as os from 'os'
|
|
6
|
+
import * as path from 'path'
|
|
7
|
+
|
|
8
|
+
const {transpile} = require('@stepzen/transpiler')
|
|
9
|
+
|
|
10
|
+
export const transpileConfigurationset = async (
|
|
11
|
+
file: string | undefined,
|
|
12
|
+
): Promise<string | undefined> => {
|
|
13
|
+
if (!file) {
|
|
14
|
+
return
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const source = file.substring(0, file.lastIndexOf('/'))
|
|
18
|
+
dotenv.config({path: path.resolve(source, '.env')})
|
|
19
|
+
|
|
20
|
+
const tmp = path.join(os.tmpdir(), `stepzen-transpiler-${Date.now()}`)
|
|
21
|
+
const configPath = path.join(tmp, 'config.yaml')
|
|
22
|
+
|
|
23
|
+
fs.ensureDirSync(tmp)
|
|
24
|
+
fs.copyFileSync(file, configPath)
|
|
25
|
+
|
|
26
|
+
const result = await transpile(tmp)
|
|
27
|
+
|
|
28
|
+
if (result.transpiled) {
|
|
29
|
+
fs.emptyDirSync(tmp)
|
|
30
|
+
fs.writeFileSync(configPath, result.config)
|
|
31
|
+
return configPath
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
fs.removeSync(tmp)
|
|
35
|
+
return
|
|
36
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// Copyright (c) 2020,2021,2022, StepZen, Inc.
|
|
2
|
+
|
|
3
|
+
export interface StepZenAccount {
|
|
4
|
+
account: string
|
|
5
|
+
adminkey: string
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* ZenCtl base URL, e.g. `https://fakefish.stepzen.io` for production,
|
|
9
|
+
* or `http://localhost` for local tests.
|
|
10
|
+
*
|
|
11
|
+
* Determined by taking the first option that is defined:
|
|
12
|
+
* - the `server` config property explicily passed into the `init()` function
|
|
13
|
+
* - the `STEPZEN_SERVER_URL` environment variable
|
|
14
|
+
* - the `https://{account}.stepzen.io` default value
|
|
15
|
+
*
|
|
16
|
+
* The `{account}` placeholder (if present) is replaced by the provided account
|
|
17
|
+
* name
|
|
18
|
+
*/
|
|
19
|
+
server: string
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* ZenCtl domain, e.g. `stepzen.io`. This is only relevant for local testing
|
|
23
|
+
* when ZenCtl is running on localhost. In that case an additional `Host` HTTP
|
|
24
|
+
* header is added to requests, using a non-localhost host name constructed
|
|
25
|
+
* from this property.
|
|
26
|
+
*
|
|
27
|
+
* Determined by taking the first option that is defined:
|
|
28
|
+
* - the `domain` config property explicily passed into the `init()` function
|
|
29
|
+
* - the `STEPZEN_DOMAIN` environment variable
|
|
30
|
+
* - the `stepzen.io` default value
|
|
31
|
+
*/
|
|
32
|
+
domain: string
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface StepZenDeploy {
|
|
36
|
+
configurationsets?: string[]
|
|
37
|
+
destination: string
|
|
38
|
+
schema: string
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface StepZenList {
|
|
42
|
+
type: string
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface StepZenUpload {
|
|
46
|
+
destination: string
|
|
47
|
+
directory?: string
|
|
48
|
+
file?: string
|
|
49
|
+
type: string
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface ZenCtlRequestHeaders {
|
|
53
|
+
authorization: string
|
|
54
|
+
host: string
|
|
55
|
+
'stepzen-cli-version': string
|
|
56
|
+
'user-agent': string
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface ZenCtlResponse {
|
|
60
|
+
errors?: Array<string>
|
|
61
|
+
message?: string
|
|
62
|
+
results?: Array<string>
|
|
63
|
+
success: boolean
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface SDKConfiguration {
|
|
67
|
+
/**
|
|
68
|
+
* The name and version of that app that uses the SDK,
|
|
69
|
+
* e.g. `stepzen-cli/0.9.32`
|
|
70
|
+
*
|
|
71
|
+
* It is appended to the user-agent string in all requests made to StepZen
|
|
72
|
+
* through the SDK and becomes availabe in the log analytics.
|
|
73
|
+
*/
|
|
74
|
+
appName: string
|
|
75
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Copyright (c) 2020,2021,2022, StepZen, Inc.
|
|
2
|
+
|
|
3
|
+
import * as fs from 'fs'
|
|
4
|
+
import * as glob from 'glob'
|
|
5
|
+
import * as yaml from 'yaml'
|
|
6
|
+
|
|
7
|
+
// Validate the Configurationset file
|
|
8
|
+
export const validateConfigurationset = async (file: string | undefined) => {
|
|
9
|
+
if (!file) {
|
|
10
|
+
throw new Error('You must provide a file path')
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (!fs.existsSync(file)) {
|
|
14
|
+
throw new Error('The file does not exist')
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const content = fs.readFileSync(file, 'utf8')
|
|
18
|
+
|
|
19
|
+
// Ensure the file is valid YAML
|
|
20
|
+
try {
|
|
21
|
+
yaml.parse(content)
|
|
22
|
+
} catch {
|
|
23
|
+
throw new Error('The file is not valid YAML')
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Validate the Schema directory
|
|
28
|
+
export const validateSchema = async (directory: string | undefined) => {
|
|
29
|
+
if (!directory) {
|
|
30
|
+
throw new Error('You must provide a directory path')
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!fs.existsSync(directory)) {
|
|
34
|
+
throw new Error('The directory does not exist')
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Ensure there's a root `index.graphql` file
|
|
38
|
+
const allSchemaFiles = glob.sync('index.graphql', {cwd: directory})
|
|
39
|
+
if (allSchemaFiles.length === 0) {
|
|
40
|
+
throw new Error('Schemas must include an `index.graphql` file')
|
|
41
|
+
}
|
|
42
|
+
}
|