@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.
Files changed (48) hide show
  1. package/README.md +14 -14
  2. package/lib/commands/account.d.ts +9 -0
  3. package/lib/commands/account.js +39 -0
  4. package/lib/commands/account.js.map +1 -0
  5. package/lib/commands/authenticate.d.ts +2 -2
  6. package/lib/commands/authenticate.js +6 -5
  7. package/lib/commands/authenticate.js.map +1 -0
  8. package/lib/commands/deploy.d.ts +2 -2
  9. package/lib/commands/deploy.js +9 -8
  10. package/lib/commands/deploy.js.map +1 -0
  11. package/lib/commands/list.d.ts +2 -2
  12. package/lib/commands/list.js +7 -6
  13. package/lib/commands/list.js.map +1 -0
  14. package/lib/commands/upload.d.ts +2 -2
  15. package/lib/commands/upload.js +13 -12
  16. package/lib/commands/upload.js.map +1 -0
  17. package/lib/index.d.ts +22 -5
  18. package/lib/index.js +72 -35
  19. package/lib/index.js.map +1 -0
  20. package/lib/shared/constants.d.ts +1 -0
  21. package/lib/shared/constants.js +7 -5
  22. package/lib/shared/constants.js.map +1 -0
  23. package/lib/shared/payloads.d.ts +1 -1
  24. package/lib/shared/payloads.js +12 -11
  25. package/lib/shared/payloads.js.map +1 -0
  26. package/lib/shared/request.d.ts +2 -2
  27. package/lib/shared/request.js +13 -7
  28. package/lib/shared/request.js.map +1 -0
  29. package/lib/shared/transpiling.js +4 -3
  30. package/lib/shared/transpiling.js.map +1 -0
  31. package/lib/shared/types.d.ts +36 -3
  32. package/lib/shared/types.js +1 -0
  33. package/lib/shared/types.js.map +1 -0
  34. package/lib/shared/validation.js +9 -8
  35. package/lib/shared/validation.js.map +1 -0
  36. package/package.json +18 -9
  37. package/src/commands/account.ts +54 -0
  38. package/src/commands/authenticate.ts +30 -0
  39. package/src/commands/deploy.ts +72 -0
  40. package/src/commands/list.ts +50 -0
  41. package/src/commands/upload.ts +95 -0
  42. package/src/index.ts +121 -0
  43. package/src/shared/constants.ts +7 -0
  44. package/src/shared/payloads.ts +105 -0
  45. package/src/shared/request.ts +26 -0
  46. package/src/shared/transpiling.ts +36 -0
  47. package/src/shared/types.ts +75 -0
  48. 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
+ }