@membranehq/cli 0.1.1 → 0.1.3
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/dist/index.js +140 -140
- package/package.json +16 -4
- package/.turbo/turbo-build.log +0 -9
- package/CHANGELOG.md +0 -7
- package/scripts/add-shebang.sh +0 -6
- package/scripts/prepare-package-json.ts +0 -29
- package/src/agent.tsx +0 -50
- package/src/cli.ts +0 -72
- package/src/commands/open.command.ts +0 -51
- package/src/commands/pull.command.ts +0 -75
- package/src/commands/push.command.ts +0 -79
- package/src/commands/test.command.ts +0 -99
- package/src/components/AddMcpServerScreen.tsx +0 -215
- package/src/components/AgentStatus.tsx +0 -15
- package/src/components/Main.tsx +0 -64
- package/src/components/OverviewSection.tsx +0 -24
- package/src/components/PersonalAccessTokenInput.tsx +0 -56
- package/src/components/RecentChanges.tsx +0 -65
- package/src/components/SelectWorkspace.tsx +0 -112
- package/src/components/Setup.tsx +0 -121
- package/src/components/WorkspaceStatus.tsx +0 -61
- package/src/contexts/FileWatcherContext.tsx +0 -81
- package/src/index.ts +0 -27
- package/src/legacy/commands/pullWorkspace.ts +0 -70
- package/src/legacy/commands/pushWorkspace.ts +0 -246
- package/src/legacy/integrationElements.ts +0 -78
- package/src/legacy/push/types.ts +0 -17
- package/src/legacy/reader/index.ts +0 -113
- package/src/legacy/types.ts +0 -17
- package/src/legacy/util.ts +0 -149
- package/src/legacy/workspace-elements/connectors.ts +0 -397
- package/src/legacy/workspace-elements/index.ts +0 -27
- package/src/legacy/workspace-tools/commands/pullWorkspace.ts +0 -70
- package/src/legacy/workspace-tools/integrationElements.ts +0 -78
- package/src/legacy/workspace-tools/util.ts +0 -149
- package/src/mcp/server-status.ts +0 -27
- package/src/mcp/server.ts +0 -36
- package/src/mcp/tools/getTestAccessToken.ts +0 -32
- package/src/modules/api/account-api-client.ts +0 -89
- package/src/modules/api/index.ts +0 -3
- package/src/modules/api/membrane-api-client.ts +0 -116
- package/src/modules/api/workspace-api-client.ts +0 -11
- package/src/modules/config/cwd-context.tsx +0 -11
- package/src/modules/config/project/getAgentVersion.ts +0 -16
- package/src/modules/config/project/index.ts +0 -8
- package/src/modules/config/project/paths.ts +0 -25
- package/src/modules/config/project/readProjectConfig.ts +0 -27
- package/src/modules/config/project/useProjectConfig.tsx +0 -103
- package/src/modules/config/system/index.ts +0 -35
- package/src/modules/file-watcher/index.ts +0 -166
- package/src/modules/file-watcher/types.ts +0 -14
- package/src/modules/setup/steps.ts +0 -9
- package/src/modules/setup/useSetup.ts +0 -16
- package/src/modules/status/useStatus.ts +0 -16
- package/src/modules/workspace-element-service/constants.ts +0 -121
- package/src/modules/workspace-element-service/getTypeAndKeyFromPath.ts +0 -69
- package/src/modules/workspace-element-service/index.ts +0 -304
- package/src/testing/environment.ts +0 -172
- package/src/testing/runners/base.runner.ts +0 -27
- package/src/testing/runners/test.runner.ts +0 -123
- package/src/testing/scripts/generate-test-report.ts +0 -757
- package/src/testing/test-suites/base.ts +0 -92
- package/src/testing/test-suites/data-collection.ts +0 -128
- package/src/testing/testers/base.ts +0 -115
- package/src/testing/testers/create.ts +0 -273
- package/src/testing/testers/delete.ts +0 -155
- package/src/testing/testers/find-by-id.ts +0 -135
- package/src/testing/testers/list.ts +0 -110
- package/src/testing/testers/match.ts +0 -149
- package/src/testing/testers/search.ts +0 -148
- package/src/testing/testers/spec.ts +0 -30
- package/src/testing/testers/update.ts +0 -284
- package/src/utils/auth.ts +0 -19
- package/src/utils/constants.ts +0 -27
- package/src/utils/fields.ts +0 -83
- package/src/utils/logger.ts +0 -106
- package/src/utils/templating.ts +0 -50
- package/tsconfig.json +0 -21
package/src/legacy/types.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { WorkspaceElementType } from '@integration-app/sdk'
|
|
2
|
-
|
|
3
|
-
export type ConnectorsMapping = Record<string, string>
|
|
4
|
-
|
|
5
|
-
export interface PushContext {
|
|
6
|
-
connectorsMapping: ConnectorsMapping
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
interface WorkspaceElement {
|
|
10
|
-
key: string
|
|
11
|
-
integration?: {
|
|
12
|
-
key: string
|
|
13
|
-
}
|
|
14
|
-
integrationKey?: string
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export type WorkspaceData = Partial<Record<WorkspaceElementType, WorkspaceElement[]>>
|
package/src/legacy/util.ts
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
import { INTEGRATION_ELEMENTS, baseExportCleanup } from './integrationElements'
|
|
2
|
-
import { WorkspaceData } from './push/types'
|
|
3
|
-
import { Logger } from '../utils/logger'
|
|
4
|
-
|
|
5
|
-
async function getWorkspaceData(iApp, logs = 'full'): Promise<WorkspaceData> {
|
|
6
|
-
const workspaceData: any = {}
|
|
7
|
-
|
|
8
|
-
Logger.info('Getting remote workspace data')
|
|
9
|
-
|
|
10
|
-
const integrations = await iApp.integrations.findAll()
|
|
11
|
-
workspaceData.integration = integrations.map((item) => cleanUpForExport('integration', item))
|
|
12
|
-
|
|
13
|
-
for (const elementType of Object.keys(INTEGRATION_ELEMENTS) as any[]) {
|
|
14
|
-
const element = INTEGRATION_ELEMENTS[elementType]
|
|
15
|
-
if (element.exportable === false) continue
|
|
16
|
-
|
|
17
|
-
const elementEnteties = []
|
|
18
|
-
Logger.info(`Reading ${element.elements} from remote workspace`)
|
|
19
|
-
// Get all universal elements
|
|
20
|
-
const elements = await iApp[element.elements].findAll()
|
|
21
|
-
|
|
22
|
-
elementEnteties.push(
|
|
23
|
-
...elements.map((item) => {
|
|
24
|
-
return cleanUpForExport(elementType, item)
|
|
25
|
-
}),
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
// Get all integration specific elements
|
|
29
|
-
if (element.integrationSpecific) {
|
|
30
|
-
for (const integration of integrations) {
|
|
31
|
-
const integrationElements = await iApp[element.elements].findAll({
|
|
32
|
-
integrationId: integration.id,
|
|
33
|
-
})
|
|
34
|
-
elementEnteties.push(
|
|
35
|
-
...integrationElements.map((item) => {
|
|
36
|
-
item.integrationKey = integration.key
|
|
37
|
-
return cleanUpForExport(elementType, item)
|
|
38
|
-
}),
|
|
39
|
-
)
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (elementEnteties.length > 0) {
|
|
44
|
-
if (logs == 'full') {
|
|
45
|
-
// eslint-disable-next-line no-console
|
|
46
|
-
console.table(
|
|
47
|
-
elementEnteties
|
|
48
|
-
.map((item) => {
|
|
49
|
-
return {
|
|
50
|
-
key: item.key,
|
|
51
|
-
integrationKey: item.integrationKey,
|
|
52
|
-
universal: !item.integrationKey,
|
|
53
|
-
}
|
|
54
|
-
})
|
|
55
|
-
.reduce((acc, item) => {
|
|
56
|
-
if (!acc) {
|
|
57
|
-
acc = {}
|
|
58
|
-
}
|
|
59
|
-
if (!acc[item.key]) {
|
|
60
|
-
acc[item.key] = {}
|
|
61
|
-
}
|
|
62
|
-
if (item.universal) {
|
|
63
|
-
acc[item.key].universal = true
|
|
64
|
-
}
|
|
65
|
-
if (item.integrationKey) {
|
|
66
|
-
if (!acc[item.key].integration) {
|
|
67
|
-
acc[item.key].integration = item.integrationKey
|
|
68
|
-
} else {
|
|
69
|
-
acc[item.key].integration += ` ${item.integrationKey}`
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return acc
|
|
73
|
-
}, {}),
|
|
74
|
-
)
|
|
75
|
-
// eslint-disable-next-line no-console
|
|
76
|
-
console.groupEnd()
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
workspaceData[elementType] = elementEnteties
|
|
80
|
-
}
|
|
81
|
-
Logger.success('Remote workspace data retrieved successfully')
|
|
82
|
-
return workspaceData
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function splitWorkspaceData(data: WorkspaceData) {
|
|
86
|
-
const universalElements: any = {}
|
|
87
|
-
const integrationSpecificElements: any = {}
|
|
88
|
-
for (const elementType of Object.keys(data)) {
|
|
89
|
-
universalElements[elementType] = []
|
|
90
|
-
integrationSpecificElements[elementType] = []
|
|
91
|
-
|
|
92
|
-
const isIntegrationSpecific = INTEGRATION_ELEMENTS[elementType]?.integrationSpecific
|
|
93
|
-
|
|
94
|
-
if (isIntegrationSpecific) {
|
|
95
|
-
for (const element of data[elementType]) {
|
|
96
|
-
if (element.integrationKey || element.integration || element.integrationId) {
|
|
97
|
-
integrationSpecificElements[elementType].push(element)
|
|
98
|
-
} else {
|
|
99
|
-
universalElements[elementType].push(element)
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
} else {
|
|
103
|
-
universalElements[elementType].push(...data[elementType])
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
return { universalElements, integrationSpecificElements }
|
|
107
|
-
}
|
|
108
|
-
function cleanUpForExport(elementType, element) {
|
|
109
|
-
element = baseExportCleanup(element)
|
|
110
|
-
return INTEGRATION_ELEMENTS[elementType].exportCleanup
|
|
111
|
-
? INTEGRATION_ELEMENTS[elementType].exportCleanup(element)
|
|
112
|
-
: element
|
|
113
|
-
}
|
|
114
|
-
function hasParent(element) {
|
|
115
|
-
return Object.keys(element).some((key) => /universal.*Id/g.test(key) || /parentId/g.test(key))
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function coloredLog(message, color) {
|
|
119
|
-
const colors = {
|
|
120
|
-
Reset: '\x1b[0m',
|
|
121
|
-
Bright: '\x1b[1m',
|
|
122
|
-
Dim: '\x1b[2m',
|
|
123
|
-
Underscore: '\x1b[4m',
|
|
124
|
-
Blink: '\x1b[5m',
|
|
125
|
-
Reverse: '\x1b[7m',
|
|
126
|
-
Hidden: '\x1b[8m',
|
|
127
|
-
Black: '\x1b[30m',
|
|
128
|
-
Red: '\x1b[31m',
|
|
129
|
-
Green: '\x1b[32m',
|
|
130
|
-
Yellow: '\x1b[33m',
|
|
131
|
-
Blue: '\x1b[34m',
|
|
132
|
-
Magenta: '\x1b[35m',
|
|
133
|
-
Cyan: '\x1b[36m',
|
|
134
|
-
White: '\x1b[37m',
|
|
135
|
-
Gray: '\x1b[90m',
|
|
136
|
-
BgBlack: '\x1b[40m',
|
|
137
|
-
BgRed: '\x1b[41m',
|
|
138
|
-
BgGreen: '\x1b[42m',
|
|
139
|
-
BgYellow: '\x1b[43m',
|
|
140
|
-
BgBlue: '\x1b[44m',
|
|
141
|
-
BgMagenta: '\x1b[45m',
|
|
142
|
-
BgCyan: '\x1b[46m',
|
|
143
|
-
BgWhite: '\x1b[47m',
|
|
144
|
-
BgGray: '\x1b[100m',
|
|
145
|
-
}
|
|
146
|
-
console.debug('\x1b[0m', `\x1b[${colors[color]}`, message, '\x1b[0m')
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
export { getWorkspaceData, splitWorkspaceData, hasParent, coloredLog }
|
|
@@ -1,397 +0,0 @@
|
|
|
1
|
-
import fs from 'fs'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
|
|
4
|
-
import { Connector, IntegrationAppClient } from '@integration-app/sdk'
|
|
5
|
-
import archiver from 'archiver'
|
|
6
|
-
import FormData from 'form-data'
|
|
7
|
-
import yaml from 'js-yaml'
|
|
8
|
-
import unzipper from 'unzipper'
|
|
9
|
-
|
|
10
|
-
import { getPaths } from '../../utils/constants'
|
|
11
|
-
import { Logger } from '../../utils/logger'
|
|
12
|
-
import { ConnectorsMapping, PushContext, WorkspaceData } from '../push/types'
|
|
13
|
-
import { coloredLog } from '../util'
|
|
14
|
-
|
|
15
|
-
const CONNECTORS_DIR = 'connectors'
|
|
16
|
-
const CONNECTOR_DEVELOPMENT_VERSION_NAME = 'development'
|
|
17
|
-
const connectorsCache: Record<string, Connector> = {}
|
|
18
|
-
|
|
19
|
-
export async function pullConnectors({
|
|
20
|
-
client,
|
|
21
|
-
basePath,
|
|
22
|
-
allConnectors = false,
|
|
23
|
-
}: {
|
|
24
|
-
client: IntegrationAppClient
|
|
25
|
-
basePath: string
|
|
26
|
-
allConnectors?: boolean
|
|
27
|
-
}) {
|
|
28
|
-
// We only pull connectors used in integrations.
|
|
29
|
-
const integrations = await client.integrations.findAll()
|
|
30
|
-
|
|
31
|
-
const pulledConnectors: Set<string> = new Set()
|
|
32
|
-
const pulledConnectorVersions: Record<string, Set<string>> = {}
|
|
33
|
-
|
|
34
|
-
for (const integration of integrations) {
|
|
35
|
-
const connectorId = integration.connectorId
|
|
36
|
-
const connectorVersion = integration.connectorVersion
|
|
37
|
-
|
|
38
|
-
if (!pulledConnectorVersions[connectorId]?.has(integration.connectorVersion)) {
|
|
39
|
-
let connector: Connector
|
|
40
|
-
try {
|
|
41
|
-
connector = await getConnector({ client, connectorId })
|
|
42
|
-
} catch (error) {
|
|
43
|
-
console.error(`Failed to pull connector ${connectorId}. Skipping...`)
|
|
44
|
-
continue
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const isConnectorCustom = !!connector.workspaceId
|
|
48
|
-
const shouldPullConnector = isConnectorCustom || allConnectors
|
|
49
|
-
|
|
50
|
-
if (shouldPullConnector) {
|
|
51
|
-
if (!pulledConnectors.has(connectorId)) {
|
|
52
|
-
await pullConnector({ basePath, client, connector })
|
|
53
|
-
pulledConnectors.add(connectorId)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (!pulledConnectorVersions[connectorId]) {
|
|
57
|
-
pulledConnectorVersions[connectorId] = new Set()
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (!pulledConnectorVersions[connectorId].has(connectorVersion)) {
|
|
61
|
-
await pullConnectorVersion({
|
|
62
|
-
client,
|
|
63
|
-
connector,
|
|
64
|
-
connectorVersion,
|
|
65
|
-
basePath,
|
|
66
|
-
})
|
|
67
|
-
pulledConnectorVersions[connectorId].add(connectorVersion)
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export async function pushConnectors({
|
|
75
|
-
client,
|
|
76
|
-
basePath,
|
|
77
|
-
workspaceData,
|
|
78
|
-
pushContext,
|
|
79
|
-
workspaceId,
|
|
80
|
-
}: {
|
|
81
|
-
client: IntegrationAppClient
|
|
82
|
-
basePath: string
|
|
83
|
-
workspaceData: WorkspaceData
|
|
84
|
-
pushContext: PushContext
|
|
85
|
-
workspaceId: string
|
|
86
|
-
}) {
|
|
87
|
-
const connectorsMapping: ConnectorsMapping = {}
|
|
88
|
-
|
|
89
|
-
console.debug('[Push] Loading custom connectors')
|
|
90
|
-
// Get Connectors
|
|
91
|
-
const iApp = client
|
|
92
|
-
const customConnectors = await iApp.get(`/connectors?workspaceId=${workspaceId}`)
|
|
93
|
-
console.debug('[Push] Loading public connectors')
|
|
94
|
-
workspaceData.connector = customConnectors
|
|
95
|
-
|
|
96
|
-
const connectorsPath = getConnectorsPath()
|
|
97
|
-
|
|
98
|
-
const connectorDirs = fs.existsSync(connectorsPath) ? fs.readdirSync(connectorsPath) : []
|
|
99
|
-
|
|
100
|
-
for (const connectorDir of connectorDirs) {
|
|
101
|
-
console.debug(`[Push] Loading connector from: ${connectorDir}`)
|
|
102
|
-
|
|
103
|
-
const pathsInsideConnectorDir = fs.readdirSync(path.join(connectorsPath, connectorDir))
|
|
104
|
-
|
|
105
|
-
const connector = await readConnector(connectorDir)
|
|
106
|
-
|
|
107
|
-
delete connector.baseUri
|
|
108
|
-
|
|
109
|
-
if (connector.uuid && workspaceData.connector?.find((item: any) => item.uuid == connector.uuid)) {
|
|
110
|
-
connectorsMapping[connector.id] = (workspaceData.connector as any).find((item) => item.uuid == connector.uuid).id
|
|
111
|
-
coloredLog(`Matched ${connector.name} uuid: ${connector.uuid}`, 'Blue')
|
|
112
|
-
} else if (!connectorsMapping[connector.id]) {
|
|
113
|
-
console.debug(`Creating connector ${connector.name} (${connector.key})`)
|
|
114
|
-
const resp = await iApp.post('connectors', {
|
|
115
|
-
...connector,
|
|
116
|
-
workspaceId,
|
|
117
|
-
})
|
|
118
|
-
connectorsMapping[connector.id] = resp.id
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const connectorVersions = pathsInsideConnectorDir.filter((item) =>
|
|
122
|
-
fs.statSync(path.join(connectorsPath, connectorDir, item)).isDirectory(),
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
for (const version of connectorVersions) {
|
|
126
|
-
await pushConnectorVersion({
|
|
127
|
-
client,
|
|
128
|
-
connector,
|
|
129
|
-
version,
|
|
130
|
-
basePath,
|
|
131
|
-
connectorId: connectorsMapping[connector.id],
|
|
132
|
-
})
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
pushContext.connectorsMapping = connectorsMapping
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
export async function handleConnectorFileChange(
|
|
140
|
-
filename: string,
|
|
141
|
-
config: any,
|
|
142
|
-
pushContext: PushContext,
|
|
143
|
-
): Promise<void> {
|
|
144
|
-
// Extract connector name from path
|
|
145
|
-
const match = filename.match(/connectors\/([^/]+)\/([^/]+)\/src\/(.*)/)
|
|
146
|
-
|
|
147
|
-
if (!match) return
|
|
148
|
-
|
|
149
|
-
const connectorFolderName = match[1]
|
|
150
|
-
const connectorVersion = match[2]
|
|
151
|
-
|
|
152
|
-
if (connectorVersion != CONNECTOR_DEVELOPMENT_VERSION_NAME) {
|
|
153
|
-
Logger.warning(
|
|
154
|
-
`Detected change in non-development version of connector ${connectorFolderName}. This change will be ignored.`,
|
|
155
|
-
)
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const relativeFilename = match[3]
|
|
159
|
-
|
|
160
|
-
const paths = getPaths()
|
|
161
|
-
const fullPath = path.join(paths.membraneDirPath, filename)
|
|
162
|
-
|
|
163
|
-
const connector = await readConnector(connectorFolderName)
|
|
164
|
-
|
|
165
|
-
const connectorId = connector?.id
|
|
166
|
-
|
|
167
|
-
if (!connectorId) {
|
|
168
|
-
Logger.warning(`Connector ${connectorFolderName} has no id. Ignoring file change`)
|
|
169
|
-
return
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const pushConnectorId = pushContext.connectorsMapping[connectorId]
|
|
173
|
-
|
|
174
|
-
if (!pushConnectorId) {
|
|
175
|
-
Logger.warning(`Connector ${connectorFolderName} not found in target workspace. Ignoring file change.`)
|
|
176
|
-
return
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
if (fs.existsSync(fullPath)) {
|
|
180
|
-
Logger.info(`Pushing updated file ${relativeFilename} for connector ${connectorFolderName}`)
|
|
181
|
-
await config.client.put(
|
|
182
|
-
`connectors/${pushConnectorId}/files/${relativeFilename}`,
|
|
183
|
-
fs.readFileSync(fullPath, 'utf-8'),
|
|
184
|
-
{
|
|
185
|
-
headers: {
|
|
186
|
-
'Content-Type': 'text/plain',
|
|
187
|
-
},
|
|
188
|
-
},
|
|
189
|
-
)
|
|
190
|
-
} else {
|
|
191
|
-
Logger.info(`Deleting file ${relativeFilename} for connector ${connectorFolderName}`)
|
|
192
|
-
await config.client.delete(`connectors/${pushConnectorId}/files/${relativeFilename}`)
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
function getConnectorsPath(): string {
|
|
197
|
-
const paths = getPaths()
|
|
198
|
-
return path.join(paths.membraneDirPath, CONNECTORS_DIR)
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
async function readConnector(connectorDir: string): Promise<Connector> {
|
|
202
|
-
return yaml.load(
|
|
203
|
-
fs.readFileSync(path.join(getConnectorsPath(), connectorDir, `${connectorDir}.yml`), 'utf8'),
|
|
204
|
-
) as Connector
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
async function createZipArchive(srcDirPath: string, zipFilePath: string): Promise<void> {
|
|
208
|
-
console.debug(`Zipping ${srcDirPath} into ${zipFilePath}`)
|
|
209
|
-
|
|
210
|
-
return new Promise((resolve, reject) => {
|
|
211
|
-
const output = fs.createWriteStream(zipFilePath)
|
|
212
|
-
const archive = archiver('zip', {
|
|
213
|
-
zlib: { level: 9 }, // Sets the compression level
|
|
214
|
-
})
|
|
215
|
-
|
|
216
|
-
output.on('close', () => {
|
|
217
|
-
coloredLog(`Successfully created ${zipFilePath}`, 'Green')
|
|
218
|
-
resolve()
|
|
219
|
-
})
|
|
220
|
-
|
|
221
|
-
output.on('end', () => {
|
|
222
|
-
console.debug('Data has been drained')
|
|
223
|
-
})
|
|
224
|
-
|
|
225
|
-
archive.on('warning', (err) => {
|
|
226
|
-
if (err.code === 'ENOENT') {
|
|
227
|
-
console.warn(err)
|
|
228
|
-
} else {
|
|
229
|
-
reject(err)
|
|
230
|
-
}
|
|
231
|
-
})
|
|
232
|
-
|
|
233
|
-
archive.on('error', (err) => {
|
|
234
|
-
reject(err)
|
|
235
|
-
})
|
|
236
|
-
|
|
237
|
-
archive.pipe(output)
|
|
238
|
-
|
|
239
|
-
// Add all files from src directory to the archive
|
|
240
|
-
const files = fs.readdirSync(srcDirPath)
|
|
241
|
-
for (const file of files) {
|
|
242
|
-
const filePath = path.join(srcDirPath, file)
|
|
243
|
-
const stats = fs.statSync(filePath)
|
|
244
|
-
if (stats.isFile()) {
|
|
245
|
-
archive.file(filePath, { name: file })
|
|
246
|
-
} else if (stats.isDirectory()) {
|
|
247
|
-
archive.directory(filePath, file)
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
archive.finalize()
|
|
252
|
-
})
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
async function extractZipArchive(zipData: Buffer, destDirPath: string): Promise<void> {
|
|
256
|
-
console.debug(`Unzipping into ${destDirPath}`)
|
|
257
|
-
|
|
258
|
-
return new Promise((resolve, reject) => {
|
|
259
|
-
const stream = unzipper.Parse()
|
|
260
|
-
stream.on('entry', (entry) => {
|
|
261
|
-
const fileName = entry.path
|
|
262
|
-
const type = entry.type // 'Directory' or 'File'
|
|
263
|
-
const size = entry.vars.uncompressedSize // There is also compressedSize;
|
|
264
|
-
|
|
265
|
-
if (type === 'Directory') {
|
|
266
|
-
const dirPath = path.join(destDirPath, fileName)
|
|
267
|
-
fs.mkdirSync(dirPath, { recursive: true })
|
|
268
|
-
entry.autodrain()
|
|
269
|
-
} else {
|
|
270
|
-
const filePath = path.join(destDirPath, fileName)
|
|
271
|
-
const dirPath = path.dirname(filePath)
|
|
272
|
-
fs.mkdirSync(dirPath, { recursive: true })
|
|
273
|
-
|
|
274
|
-
const writeStream = fs.createWriteStream(filePath)
|
|
275
|
-
entry.pipe(writeStream)
|
|
276
|
-
writeStream.on('finish', () => {
|
|
277
|
-
console.debug(`Extracted: ${fileName}`)
|
|
278
|
-
})
|
|
279
|
-
}
|
|
280
|
-
})
|
|
281
|
-
|
|
282
|
-
stream.on('end', () => {
|
|
283
|
-
coloredLog(`Successfully extracted to ${destDirPath}`, 'Green')
|
|
284
|
-
resolve()
|
|
285
|
-
})
|
|
286
|
-
|
|
287
|
-
stream.on('error', (err) => {
|
|
288
|
-
reject(err)
|
|
289
|
-
})
|
|
290
|
-
|
|
291
|
-
stream.write(zipData)
|
|
292
|
-
stream.end()
|
|
293
|
-
})
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
async function pushConnectorVersion({
|
|
297
|
-
client,
|
|
298
|
-
connector,
|
|
299
|
-
version,
|
|
300
|
-
connectorId,
|
|
301
|
-
basePath,
|
|
302
|
-
}: {
|
|
303
|
-
client: IntegrationAppClient
|
|
304
|
-
connector: Connector
|
|
305
|
-
connectorId: string
|
|
306
|
-
version: string
|
|
307
|
-
basePath: string
|
|
308
|
-
}) {
|
|
309
|
-
const versionDir = path.join(getConnectorsPath(), getConnectorDirName(connector), version)
|
|
310
|
-
const srcDir = path.join(versionDir, 'src')
|
|
311
|
-
|
|
312
|
-
if (!fs.existsSync(srcDir)) {
|
|
313
|
-
console.debug(`No src directory found for ${connector.name} version ${version}`)
|
|
314
|
-
return
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
const zipFilePath = path.join(versionDir, `${version}.zip`)
|
|
318
|
-
|
|
319
|
-
try {
|
|
320
|
-
await createZipArchive(srcDir, zipFilePath)
|
|
321
|
-
|
|
322
|
-
const form = new FormData()
|
|
323
|
-
form.append('file', fs.createReadStream(zipFilePath))
|
|
324
|
-
|
|
325
|
-
console.debug(`Pushing connector version ${version} for ${connector.name}`)
|
|
326
|
-
await client.put(`connectors/${connectorId}/versions/${version}`, form, {
|
|
327
|
-
headers: form.getHeaders(),
|
|
328
|
-
})
|
|
329
|
-
|
|
330
|
-
coloredLog(`Successfully pushed connector version ${version} for ${connector.name}`, 'Green')
|
|
331
|
-
} finally {
|
|
332
|
-
// Clean up the temporary zip file
|
|
333
|
-
if (fs.existsSync(zipFilePath)) {
|
|
334
|
-
fs.unlinkSync(zipFilePath)
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
async function getConnector({ client, connectorId }: { client: IntegrationAppClient; connectorId: string }) {
|
|
340
|
-
if (connectorsCache[connectorId]) {
|
|
341
|
-
return connectorsCache[connectorId]
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
const connector = await client.get(`connectors/${connectorId}`)
|
|
345
|
-
connectorsCache[connectorId] = connector
|
|
346
|
-
return connector
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
async function pullConnector({
|
|
350
|
-
basePath,
|
|
351
|
-
connector,
|
|
352
|
-
}: {
|
|
353
|
-
basePath: string
|
|
354
|
-
client: IntegrationAppClient
|
|
355
|
-
connector: Connector
|
|
356
|
-
}) {
|
|
357
|
-
const connectorDir = path.join(basePath, getConnectorDirName(connector))
|
|
358
|
-
fs.mkdirSync(connectorDir, { recursive: true })
|
|
359
|
-
|
|
360
|
-
const connectorFilePath = path.join(connectorDir, `${getConnectorDirName(connector)}.yml`)
|
|
361
|
-
fs.writeFileSync(connectorFilePath, yaml.dump(connector))
|
|
362
|
-
|
|
363
|
-
coloredLog(`Pulled connector ${connector.name}`, 'Green')
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
async function pullConnectorVersion({
|
|
367
|
-
client,
|
|
368
|
-
connector,
|
|
369
|
-
connectorVersion,
|
|
370
|
-
basePath,
|
|
371
|
-
}: {
|
|
372
|
-
client: IntegrationAppClient
|
|
373
|
-
connector: Connector
|
|
374
|
-
connectorVersion: string
|
|
375
|
-
basePath: string
|
|
376
|
-
}) {
|
|
377
|
-
const connectorDir = path.join(basePath, getConnectorDirName(connector))
|
|
378
|
-
const versionDir = path.join(connectorDir, getConnectorVersionDirName(connectorVersion))
|
|
379
|
-
|
|
380
|
-
try {
|
|
381
|
-
const response = await client.get(`connectors/${connector.id}/versions/${connectorVersion}`)
|
|
382
|
-
const zipData = Buffer.from(response, 'base64')
|
|
383
|
-
|
|
384
|
-
await extractZipArchive(zipData, versionDir)
|
|
385
|
-
coloredLog(`Pulled connector version ${connectorVersion} for ${connector.name}`, 'Green')
|
|
386
|
-
} catch (error) {
|
|
387
|
-
console.debug(`Failed to pull connector version ${connectorVersion} for ${connector.name}:`, error)
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
function getConnectorDirName(connector: Connector) {
|
|
392
|
-
return connector.key
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
function getConnectorVersionDirName(connectorVersion: string) {
|
|
396
|
-
return connectorVersion
|
|
397
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { WorkspaceElementSpecs, WorkspaceElementType } from '@integration-app/sdk'
|
|
2
|
-
|
|
3
|
-
import { WorkspaceData } from '../push/types'
|
|
4
|
-
|
|
5
|
-
export function getWorkspaceElementTypePath(type: WorkspaceElementType): string {
|
|
6
|
-
return WorkspaceElementSpecs[type].apiPath
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function mergeWorkspaceData(data: WorkspaceData, otherData: WorkspaceData): WorkspaceData {
|
|
10
|
-
for (const elementType of Object.keys(otherData)) {
|
|
11
|
-
data[elementType] = [...(data[elementType] || []), ...otherData[elementType]]
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
return data
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export const PUSHABLE_ELEMENT_TYPES: WorkspaceElementType[] = [
|
|
18
|
-
WorkspaceElementType.Integration,
|
|
19
|
-
WorkspaceElementType.Scenario,
|
|
20
|
-
WorkspaceElementType.Action,
|
|
21
|
-
WorkspaceElementType.Flow,
|
|
22
|
-
WorkspaceElementType.AppDataSchema,
|
|
23
|
-
WorkspaceElementType.AppEventType,
|
|
24
|
-
WorkspaceElementType.DataLinkTable,
|
|
25
|
-
WorkspaceElementType.DataSource,
|
|
26
|
-
WorkspaceElementType.FieldMapping,
|
|
27
|
-
]
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import fs from 'fs'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
|
|
4
|
-
import { IntegrationAppClient, WorkspaceElementType } from '@integration-app/sdk'
|
|
5
|
-
import YAML from 'js-yaml'
|
|
6
|
-
|
|
7
|
-
import { coloredLog, getWorkspaceData } from '../../util'
|
|
8
|
-
import { getWorkspaceElementTypePath } from '../../workspace-elements'
|
|
9
|
-
import { pullConnectors } from '../../workspace-elements/connectors'
|
|
10
|
-
|
|
11
|
-
interface ExportPackageOptions {
|
|
12
|
-
outputPath?: string
|
|
13
|
-
allConnectors?: boolean
|
|
14
|
-
client?: IntegrationAppClient
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export async function pullWorkspace(options: ExportPackageOptions): Promise<void> {
|
|
18
|
-
const { outputPath, allConnectors, client } = options
|
|
19
|
-
|
|
20
|
-
await pullConnectors({
|
|
21
|
-
client,
|
|
22
|
-
basePath: outputPath,
|
|
23
|
-
allConnectors,
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
const workspaceData = await getWorkspaceData(client)
|
|
27
|
-
|
|
28
|
-
for (const elementType of Object.keys(workspaceData)) {
|
|
29
|
-
if (workspaceData[elementType].length > 0) {
|
|
30
|
-
try {
|
|
31
|
-
fs.readdirSync(outputPath)
|
|
32
|
-
} catch (_err) {
|
|
33
|
-
fs.mkdirSync(outputPath, { recursive: true })
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const elementTypePath = getWorkspaceElementTypePath(elementType as WorkspaceElementType)
|
|
37
|
-
|
|
38
|
-
for (const element of workspaceData[elementType]) {
|
|
39
|
-
try {
|
|
40
|
-
fs.readdirSync(path.join(outputPath, elementTypePath, `${element.key}`))
|
|
41
|
-
} catch (_err) {
|
|
42
|
-
fs.mkdirSync(path.join(outputPath, elementTypePath, `${element.key}`), {
|
|
43
|
-
recursive: true,
|
|
44
|
-
})
|
|
45
|
-
}
|
|
46
|
-
if (element.integration || element.integrationKey) {
|
|
47
|
-
const integrationKey = element.integration ? element.integration.key : element.integrationKey
|
|
48
|
-
try {
|
|
49
|
-
fs.readdirSync(path.join(outputPath, elementTypePath, `${element.key}`, `${integrationKey}`))
|
|
50
|
-
} catch (_err) {
|
|
51
|
-
fs.mkdirSync(path.join(outputPath, elementTypePath, `${element.key}`, `${integrationKey}`), {
|
|
52
|
-
recursive: true,
|
|
53
|
-
})
|
|
54
|
-
}
|
|
55
|
-
fs.writeFileSync(
|
|
56
|
-
path.join(outputPath, elementTypePath, `${element.key}`, `${integrationKey}`, `${integrationKey}.yaml`),
|
|
57
|
-
YAML.dump(element),
|
|
58
|
-
)
|
|
59
|
-
} else {
|
|
60
|
-
fs.writeFileSync(
|
|
61
|
-
path.join(outputPath, elementTypePath, element.key, `${element.key}.yaml`),
|
|
62
|
-
YAML.dump(element),
|
|
63
|
-
)
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
coloredLog(`Data written to ${outputPath} successfully.`, 'BgGreen')
|
|
70
|
-
}
|