@seamapi/cli 0.7.0 → 0.9.0

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 (53) hide show
  1. package/bin/cli.js +11 -2
  2. package/bin/cli.js.map +1 -1
  3. package/lib/blueprint.d.ts +2 -1
  4. package/lib/blueprint.js +171 -26
  5. package/lib/blueprint.js.map +1 -1
  6. package/lib/config/config-store.d.ts +23 -0
  7. package/lib/config/config-store.js +113 -0
  8. package/lib/config/config-store.js.map +1 -0
  9. package/lib/config/index.d.ts +1 -0
  10. package/lib/config/index.js +2 -0
  11. package/lib/config/index.js.map +1 -0
  12. package/lib/config/migrate.d.ts +2 -0
  13. package/lib/config/migrate.js +21 -0
  14. package/lib/config/migrate.js.map +1 -0
  15. package/lib/get-api-blueprint.d.ts +4 -1
  16. package/lib/get-api-blueprint.js +3 -4
  17. package/lib/get-api-blueprint.js.map +1 -1
  18. package/lib/get-current-workspace-id.js +1 -1
  19. package/lib/get-current-workspace-id.js.map +1 -1
  20. package/lib/get-seam.js +1 -1
  21. package/lib/get-seam.js.map +1 -1
  22. package/lib/get-server.js +1 -1
  23. package/lib/get-server.js.map +1 -1
  24. package/lib/interact-for-login.js +1 -1
  25. package/lib/interact-for-login.js.map +1 -1
  26. package/lib/interact-for-server-selection.js +1 -1
  27. package/lib/interact-for-server-selection.js.map +1 -1
  28. package/lib/interact-for-use-remote-api-defs.js +1 -1
  29. package/lib/interact-for-use-remote-api-defs.js.map +1 -1
  30. package/lib/interact-for-workspace-id.js +1 -1
  31. package/lib/interact-for-workspace-id.js.map +1 -1
  32. package/lib/version.d.ts +3 -1
  33. package/lib/version.js +4 -1
  34. package/lib/version.js.map +1 -1
  35. package/package.json +5 -3
  36. package/src/bin/cli.ts +12 -2
  37. package/src/lib/blueprint.ts +228 -28
  38. package/src/lib/config/config-store.ts +158 -0
  39. package/src/lib/config/index.ts +1 -0
  40. package/src/lib/config/migrate.ts +39 -0
  41. package/src/lib/get-api-blueprint.ts +7 -3
  42. package/src/lib/get-current-workspace-id.ts +1 -1
  43. package/src/lib/get-seam.ts +1 -1
  44. package/src/lib/get-server.ts +1 -1
  45. package/src/lib/interact-for-login.ts +1 -1
  46. package/src/lib/interact-for-server-selection.ts +1 -1
  47. package/src/lib/interact-for-use-remote-api-defs.ts +1 -1
  48. package/src/lib/interact-for-workspace-id.ts +1 -1
  49. package/src/lib/version.ts +4 -1
  50. package/lib/get-config-store.d.ts +0 -2
  51. package/lib/get-config-store.js +0 -5
  52. package/lib/get-config-store.js.map +0 -1
  53. package/src/lib/get-config-store.ts +0 -5
@@ -0,0 +1,158 @@
1
+ import { join } from 'node:path'
2
+
3
+ import Configstore from 'configstore'
4
+ import envPaths from 'env-paths'
5
+
6
+ import { migrateConfigStore } from './migrate.js'
7
+
8
+ const configFileName = 'cli.json'
9
+ const legacyConfigStoreId = 'seam-cli'
10
+ const currentWorkspaceIdKey = 'current_workspace_id'
11
+ const patKey = 'pat'
12
+ const paths = envPaths('seam', { suffix: '' })
13
+
14
+ export const getConfigStore = () => {
15
+ const settingsStore = new Configstore(legacyConfigStoreId, undefined, {
16
+ configPath: getConfigPath(),
17
+ })
18
+ const stateStore = new Configstore(legacyConfigStoreId, undefined, {
19
+ configPath: getStateConfigPath(),
20
+ })
21
+
22
+ migrateConfigStore(
23
+ settingsStore,
24
+ stateStore,
25
+ new Configstore(legacyConfigStoreId),
26
+ )
27
+
28
+ return new SeamConfigStore(settingsStore, stateStore)
29
+ }
30
+
31
+ export const mergeConfig = (
32
+ baseConfig: Record<string, unknown>,
33
+ overrideConfig: Record<string, unknown>,
34
+ ): Record<string, unknown> => {
35
+ const mergedConfig = { ...baseConfig }
36
+
37
+ for (const [key, value] of Object.entries(overrideConfig)) {
38
+ const baseValue = mergedConfig[key]
39
+ mergedConfig[key] =
40
+ isRecord(baseValue) && isRecord(value)
41
+ ? mergeConfig(baseValue, value)
42
+ : value
43
+ }
44
+
45
+ return mergedConfig
46
+ }
47
+
48
+ export const splitConfig = (
49
+ config: Record<string, unknown>,
50
+ ): {
51
+ settings: Record<string, unknown>
52
+ state: Record<string, unknown>
53
+ } => {
54
+ const settings: Record<string, unknown> = {}
55
+ const state: Record<string, unknown> = {}
56
+
57
+ for (const [key, value] of Object.entries(config)) {
58
+ if (isStateKey(key)) {
59
+ state[key] = value
60
+ continue
61
+ }
62
+
63
+ if (isRecord(value)) {
64
+ const splitValue = splitConfig(value)
65
+ if (Object.keys(splitValue.settings).length > 0) {
66
+ settings[key] = splitValue.settings
67
+ }
68
+
69
+ if (Object.keys(splitValue.state).length > 0) {
70
+ state[key] = splitValue.state
71
+ }
72
+
73
+ continue
74
+ }
75
+
76
+ settings[key] = value
77
+ }
78
+
79
+ return { settings, state }
80
+ }
81
+
82
+ class SeamConfigStore {
83
+ readonly path: string
84
+
85
+ constructor(
86
+ private readonly settingsStore: Configstore,
87
+ private readonly stateStore: Configstore,
88
+ ) {
89
+ this.path = settingsStore.path
90
+ }
91
+
92
+ get all(): Record<string, unknown> {
93
+ return mergeConfig(this.settingsStore.all, this.stateStore.all)
94
+ }
95
+
96
+ set all(value: Record<string, unknown>) {
97
+ const { settings, state } = splitConfig(value)
98
+ this.settingsStore.all = settings
99
+ this.stateStore.all = state
100
+ }
101
+
102
+ get size(): number {
103
+ return Object.keys(this.all).length
104
+ }
105
+
106
+ get(key: string): unknown {
107
+ return this.getStore(key).get(key)
108
+ }
109
+
110
+ set(key: string | Record<string, unknown>, value?: unknown): void {
111
+ if (isRecord(key)) {
112
+ for (const [configKey, configValue] of Object.entries(key)) {
113
+ this.set(configKey, configValue)
114
+ }
115
+
116
+ return
117
+ }
118
+
119
+ this.getStore(key).set(key, value)
120
+ }
121
+
122
+ has(key: string): boolean {
123
+ return this.getStore(key).has(key)
124
+ }
125
+
126
+ delete(key: string): void {
127
+ this.getStore(key).delete(key)
128
+ }
129
+
130
+ clear(): void {
131
+ this.settingsStore.clear()
132
+ this.stateStore.clear()
133
+ }
134
+
135
+ private getStore(key: string): Configstore {
136
+ return isStateKey(key) ? this.stateStore : this.settingsStore
137
+ }
138
+ }
139
+
140
+ const getConfigPath = (): string => {
141
+ return join(paths.config, configFileName)
142
+ }
143
+
144
+ const getStateConfigPath = (): string => {
145
+ return join(paths.log, configFileName)
146
+ }
147
+
148
+ const isStateKey = (key: string): boolean => {
149
+ return (
150
+ key === currentWorkspaceIdKey ||
151
+ key === patKey ||
152
+ key.endsWith(`.${patKey}`)
153
+ )
154
+ }
155
+
156
+ const isRecord = (value: unknown): value is Record<string, unknown> => {
157
+ return value != null && typeof value === 'object' && !Array.isArray(value)
158
+ }
@@ -0,0 +1 @@
1
+ export { getConfigStore } from './config-store.js'
@@ -0,0 +1,39 @@
1
+ import { existsSync, rmSync } from 'node:fs'
2
+
3
+ import type Configstore from 'configstore'
4
+
5
+ import { mergeConfig, splitConfig } from './config-store.js'
6
+
7
+ export const migrateConfigStore = (
8
+ settingsStore: Configstore,
9
+ stateStore: Configstore,
10
+ legacyStore: Configstore,
11
+ ): void => {
12
+ if (!existsSync(legacyStore.path)) return
13
+
14
+ migrateLegacyConfig(settingsStore, stateStore, legacyStore.all)
15
+
16
+ rmSync(legacyStore.path, { force: true })
17
+ }
18
+
19
+ const migrateLegacyConfig = (
20
+ settingsStore: Configstore,
21
+ stateStore: Configstore,
22
+ legacyConfig: Record<string, unknown>,
23
+ ): void => {
24
+ if (Object.keys(legacyConfig).length === 0) return
25
+
26
+ const { settings, state } = splitConfig(legacyConfig)
27
+
28
+ writeIfChanged(settingsStore, mergeConfig(settings, settingsStore.all))
29
+ writeIfChanged(stateStore, mergeConfig(state, stateStore.all))
30
+ }
31
+
32
+ const writeIfChanged = (
33
+ store: Configstore,
34
+ nextConfig: Record<string, unknown>,
35
+ ): void => {
36
+ if (JSON.stringify(store.all) !== JSON.stringify(nextConfig)) {
37
+ store.all = nextConfig
38
+ }
39
+ }
@@ -5,15 +5,19 @@ import { getServer } from './get-server.js'
5
5
 
6
6
  export type ApiBlueprint = Blueprint
7
7
 
8
+ export interface GetApiBlueprintOptions {
9
+ update?: boolean
10
+ }
11
+
8
12
  export const getApiBlueprint = async (
9
13
  useRemoteDefinitions: boolean,
14
+ options: GetApiBlueprintOptions = {},
10
15
  ): Promise<ApiBlueprint> => {
11
16
  // Remote definitions describe whatever the server is currently running, so
12
- // build them directly from the server's OpenAPI document. This runtime path
13
- // does not load @seamapi/types.
17
+ // build them directly from the server's OpenAPI document.
14
18
  if (useRemoteDefinitions) return await createRemoteBlueprint()
15
19
 
16
- return await getBlueprint()
20
+ return await getBlueprint(options)
17
21
  }
18
22
 
19
23
  const createRemoteBlueprint = async (): Promise<Blueprint> => {
@@ -1,4 +1,4 @@
1
- import { getConfigStore } from './get-config-store.js'
1
+ import { getConfigStore } from './config/index.js'
2
2
  import { interactForWorkspaceId } from './interact-for-workspace-id.js'
3
3
 
4
4
  export const getCurrentWorkspaceId = async (): Promise<string> => {
@@ -5,7 +5,7 @@ import {
5
5
  SeamHttpWithoutWorkspace,
6
6
  } from '@seamapi/http/connect'
7
7
 
8
- import { getConfigStore } from './get-config-store.js'
8
+ import { getConfigStore } from './config/index.js'
9
9
  import { getServer } from './get-server.js'
10
10
 
11
11
  export const getSeam = async (): Promise<SeamHttp> => {
@@ -1,4 +1,4 @@
1
- import { getConfigStore } from './get-config-store.js'
1
+ import { getConfigStore } from './config/index.js'
2
2
 
3
3
  export const getServer = (): string => {
4
4
  const config = getConfigStore()
@@ -2,7 +2,7 @@ import { isApiKey, isPersonalAccessToken } from '@seamapi/http/connect'
2
2
  import chalk from 'chalk'
3
3
  import prompts from 'prompts'
4
4
 
5
- import { getConfigStore } from './get-config-store.js'
5
+ import { getConfigStore } from './config/index.js'
6
6
  import { getServer } from './get-server.js'
7
7
  import { interactForWorkspaceId } from './interact-for-workspace-id.js'
8
8
  import { withLoading } from './util/with-loading.js'
@@ -2,7 +2,7 @@ import { randomBytes } from 'node:crypto'
2
2
 
3
3
  import prompts from 'prompts'
4
4
 
5
- import { getConfigStore } from './get-config-store.js'
5
+ import { getConfigStore } from './config/index.js'
6
6
  import { getServer } from './get-server.js'
7
7
 
8
8
  export async function interactForServerSelection() {
@@ -1,6 +1,6 @@
1
1
  import prompts from 'prompts'
2
2
 
3
- import { getConfigStore } from './get-config-store.js'
3
+ import { getConfigStore } from './config/index.js'
4
4
 
5
5
  export async function interactForUseRemoteApiDefs() {
6
6
  const { use_remote_api_defs } = await prompts([
@@ -1,7 +1,7 @@
1
1
  import { SeamHttpWithoutWorkspace } from '@seamapi/http/connect'
2
2
  import prompts from 'prompts'
3
3
 
4
- import { getConfigStore } from './get-config-store.js'
4
+ import { getConfigStore } from './config/index.js'
5
5
  import { getSeamMultiWorkspace } from './get-seam.js'
6
6
  import { getServer } from './get-server.js'
7
7
  import { withLoading } from './util/with-loading.js'
@@ -1,3 +1,6 @@
1
- const seamapiCliVersion = '0.7.0'
1
+ // Versions are replaced with generated values when the package is packed.
2
+ const seamapiCliVersion = '0.9.0'
3
+ const seamapiBlueprintVersion = '1.2.0'
2
4
 
5
+ export { seamapiBlueprintVersion }
3
6
  export default seamapiCliVersion
@@ -1,2 +0,0 @@
1
- import Configstore from 'configstore';
2
- export declare const getConfigStore: () => Configstore;
@@ -1,5 +0,0 @@
1
- import Configstore from 'configstore';
2
- export const getConfigStore = () => {
3
- return new Configstore('seam-cli', {});
4
- };
5
- //# sourceMappingURL=get-config-store.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"get-config-store.js","sourceRoot":"","sources":["../src/lib/get-config-store.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,MAAM,aAAa,CAAA;AAErC,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,EAAE;IACjC,OAAO,IAAI,WAAW,CAAC,UAAU,EAAE,EAAE,CAAC,CAAA;AACxC,CAAC,CAAA"}
@@ -1,5 +0,0 @@
1
- import Configstore from 'configstore'
2
-
3
- export const getConfigStore = () => {
4
- return new Configstore('seam-cli', {})
5
- }