diff --git a/assets/discord_white.png b/assets/discord_white.png new file mode 100644 index 0000000..a7e1715 Binary files /dev/null and b/assets/discord_white.png differ diff --git a/assets/electron/template/app/package.json b/assets/electron/template/app/package.json index 5bce80f..8d091a4 100644 --- a/assets/electron/template/app/package.json +++ b/assets/electron/template/app/package.json @@ -22,7 +22,7 @@ "@electron-forge/plugin-auto-unpack-natives": "7.4.0", "@electron-forge/plugin-fuses": "7.4.0", "@electron/fuses": "1.8.0", - "@pipelab/core": "1.3.0", + "@pipelab/core": "1.3.2", "electron": "32.1.2" }, "keywords": [], diff --git a/assets/electron/template/app/src/handlers/fs/list.js b/assets/electron/template/app/src/handlers/fs/list.js index 10a95e3..1cdd588 100644 --- a/assets/electron/template/app/src/handlers/fs/list.js +++ b/assets/electron/template/app/src/handlers/fs/list.js @@ -1,6 +1,7 @@ // @ts-check import { readdir } from 'node:fs/promises' +import { join } from 'node:path' /** * @param {import('@pipelab/core').MakeInputOutput} json @@ -9,9 +10,12 @@ import { readdir } from 'node:fs/promises' */ export default async (json, ws, mainWindow) => { const file = await readdir(json.body.path, { - withFileTypes: true + withFileTypes: true, + recursive: json.body.recursive }) + console.log('file', file) + /** * @type {import('@pipelab/core').MakeInputOutput} */ @@ -22,7 +26,9 @@ export default async (json, ws, mainWindow) => { success: true, list: file.map((x) => ({ type: x.isDirectory() ? 'folder' : 'file', - name: x.name + name: x.name, + parent: x.parentPath, + path: join(x.parentPath, x.name) })) } } diff --git a/assets/electron/template/app/src/handlers/fs/read.js b/assets/electron/template/app/src/handlers/fs/read.js index fb5869a..35d78f8 100644 --- a/assets/electron/template/app/src/handlers/fs/read.js +++ b/assets/electron/template/app/src/handlers/fs/read.js @@ -8,21 +8,38 @@ import { readFile } from 'node:fs/promises' * @param {import('electron').BrowserWindow} mainWindow */ export default async (json, ws, mainWindow) => { - const file = await readFile(json.body.path, { - encoding: json.body.encoding - }) + try { + const file = await readFile(json.body.path, { + encoding: json.body.encoding + }) - /** - * @type {import('@pipelab/core').MakeInputOutput} - */ - const readFileResult = { - correlationId: json.correlationId, - url: json.url, - body: { - success: true, - content: file, + /** + * @type {import('@pipelab/core').MakeInputOutput} + */ + const readFileResult = { + correlationId: json.correlationId, + url: json.url, + body: { + success: true, + content: file, + } } + console.log('result', readFileResult) + ws.send(JSON.stringify(readFileResult)) + } catch (e) { + console.error('e', e) + /** + * @type {import('@pipelab/core').MakeInputOutput} + */ + const readFileResult = { + correlationId: json.correlationId, + url: json.url, + body: { + success: false, + error: e.message, + } + } + console.log('result', readFileResult) + ws.send(JSON.stringify(readFileResult)) } - console.log('result', readFileResult) - ws.send(JSON.stringify(readFileResult)) } diff --git a/assets/electron/template/app/src/handlers/user/folder.js b/assets/electron/template/app/src/handlers/user/folder.js index 699d1e8..8ecebf7 100644 --- a/assets/electron/template/app/src/handlers/user/folder.js +++ b/assets/electron/template/app/src/handlers/user/folder.js @@ -6,17 +6,43 @@ import { app } from 'electron' * @param {import('electron').BrowserWindow} mainWindow */ export default (json, ws, mainWindow) => { - const userFolder = app.getPath(json.body.name); - /** - * @type {import('@pipelab/core').MakeInputOutput} - */ - const userFolderResult = { - url: json.url, - correlationId: json.correlationId, - body: { - data: userFolder + try { + /** @type {Parameters[0] | 'app'} */ + const name = json.body.name; + + let folder; + + if (name === 'app') { + folder = app.getAppPath(); + } else { + folder = app.getPath(name); } - }; - console.log('result', userFolderResult) - ws.send(JSON.stringify(userFolderResult)); + + /** + * @type {import('@pipelab/core').MakeInputOutput} + */ + const userFolderResult = { + url: json.url, + correlationId: json.correlationId, + body: { + data: folder + } + }; + console.log('result', userFolderResult) + ws.send(JSON.stringify(userFolderResult)); + } catch (e) { + console.error('e', e) + /** + * @type {import('@pipelab/core').MakeInputOutput} + */ + const userFolderResult = { + url: json.url, + correlationId: json.correlationId, + body: { + error: e.message + } + }; + console.log('result', userFolderResult) + ws.send(JSON.stringify(userFolderResult)); + } } diff --git a/assets/electron/template/app/src/index.js b/assets/electron/template/app/src/index.js index a698bc3..4828931 100644 --- a/assets/electron/template/app/src/index.js +++ b/assets/electron/template/app/src/index.js @@ -91,6 +91,7 @@ if (config.enableDisableRendererBackgrounding) { //region Steam +/** @type {import('steamworks.js').Client} */ let client console.log('config.enableSteamSupport', config.enableSteamSupport) if (config.enableSteamSupport) { @@ -138,118 +139,131 @@ const createAppServer = (mainWindow) => { const json = JSON.parse(data.toString()) console.log('received:', json) - switch (json.url) { - case '/paths': - await userFolder(json, ws, mainWindow) - break - - case '/fs/file/write': - await fsWrite(json, ws, mainWindow) - break - - case '/fs/file/read': - await fsRead(json, ws, mainWindow) - break - - case '/fs/file/read/binary': - await fsReadBinary(json, ws, mainWindow) - break - - case '/fs/folder/create': - await fsFolderCreate(json, ws, mainWindow) - break - - case '/window/maximize': - await windowMaximize(json, ws, mainWindow) - break - - case '/window/minimize': - await windowMinimize(json, ws, mainWindow) - break - case '/window/request-attention': - await windowRequestAttention(json, ws, mainWindow) - break - case '/window/restore': - await windowRestore(json, ws, mainWindow) - break - case '/dialog/folder': - await dialogFolder(json, ws, mainWindow) - break - case '/dialog/open': - await dialogOpen(json, ws, mainWindow) - break - case '/dialog/save': - await dialogSave(json, ws, mainWindow) - break - case '/window/set-always-on-top': - await windowSetAlwaysOnTop(json, ws, mainWindow) - break - case '/window/set-height': - await windowSetHeight(json, ws, mainWindow) - break - case '/window/set-maximum-size': - await windowSetMaximumSize(json, ws, mainWindow) - break - case '/window/set-minimum-size': - await windowSetMinimumSize(json, ws, mainWindow) - break - case '/window/set-resizable': - await windowSetResizable(json, ws, mainWindow) - break - case '/window/set-title': - await windowSetTitle(json, ws, mainWindow) - break - case '/window/set-width': - await windowSetWidth(json, ws, mainWindow) - break - case '/window/set-x': - await windowSetX(json, ws, mainWindow) - break - case '/window/set-y': - await windowSetY(json, ws, mainWindow) - break - case '/window/show-dev-tools': - await windowShowDevTools(json, ws, mainWindow) - break - case '/window/unmaximize': - await windowUnmaximize(json, ws, mainWindow) - break - case '/engine': - await engine(json, ws, mainWindow) - break - case '/open': - await open(json, ws, mainWindow) - break - case '/show-in-explorer': - await showInExplorer(json, ws, mainWindow) - break - case '/run': - await run(json, ws, mainWindow) - break - case '/fs/copy': - throw new Error('Not implemented') - case '/fs/delete': - throw new Error('Not implemented') - case '/fs/exist': - throw new Error('Not implemented') - case '/fs/file/append': - throw new Error('Not implemented') - case '/fs/list': - await fsList(json, ws, mainWindow) - break - case '/fs/file/size': - await fsFileSize(json, ws, mainWindow) - break - case '/fs/move': - throw new Error('Not implemented') - case '/steam/raw': - await steamRaw(json, ws, client) - break - - default: - console.log('unsupported', data) - assertUnreachable(json) - break + try { + switch (json.url) { + case '/paths': + await userFolder(json, ws, mainWindow) + break + + case '/fs/file/write': + await fsWrite(json, ws, mainWindow) + break + + case '/fs/file/read': + await fsRead(json, ws, mainWindow) + break + + case '/fs/file/read/binary': + await fsReadBinary(json, ws, mainWindow) + break + + case '/fs/folder/create': + await fsFolderCreate(json, ws, mainWindow) + break + + case '/window/maximize': + await windowMaximize(json, ws, mainWindow) + break + + case '/window/minimize': + await windowMinimize(json, ws, mainWindow) + break + case '/window/request-attention': + await windowRequestAttention(json, ws, mainWindow) + break + case '/window/restore': + await windowRestore(json, ws, mainWindow) + break + case '/dialog/folder': + await dialogFolder(json, ws, mainWindow) + break + case '/dialog/open': + await dialogOpen(json, ws, mainWindow) + break + case '/dialog/save': + await dialogSave(json, ws, mainWindow) + break + case '/window/set-always-on-top': + await windowSetAlwaysOnTop(json, ws, mainWindow) + break + case '/window/set-height': + await windowSetHeight(json, ws, mainWindow) + break + case '/window/set-maximum-size': + await windowSetMaximumSize(json, ws, mainWindow) + break + case '/window/set-minimum-size': + await windowSetMinimumSize(json, ws, mainWindow) + break + case '/window/set-resizable': + await windowSetResizable(json, ws, mainWindow) + break + case '/window/set-title': + await windowSetTitle(json, ws, mainWindow) + break + case '/window/set-width': + await windowSetWidth(json, ws, mainWindow) + break + case '/window/set-x': + await windowSetX(json, ws, mainWindow) + break + case '/window/set-y': + await windowSetY(json, ws, mainWindow) + break + case '/window/show-dev-tools': + await windowShowDevTools(json, ws, mainWindow) + break + case '/window/unmaximize': + await windowUnmaximize(json, ws, mainWindow) + break + case '/engine': + await engine(json, ws, mainWindow) + break + case '/open': + await open(json, ws, mainWindow) + break + case '/show-in-explorer': + await showInExplorer(json, ws, mainWindow) + break + case '/run': + await run(json, ws, mainWindow) + break + case '/fs/copy': + throw new Error('Not implemented') + case '/fs/delete': + throw new Error('Not implemented') + case '/fs/exist': + throw new Error('Not implemented') + case '/fs/file/append': + throw new Error('Not implemented') + case '/fs/list': + await fsList(json, ws, mainWindow) + break + case '/fs/file/size': + await fsFileSize(json, ws, mainWindow) + break + case '/fs/move': + throw new Error('Not implemented') + case '/steam/raw': + await steamRaw(json, ws, client) + break + + default: + console.log('unsupported', data) + assertUnreachable(json) + break + } + } catch (e) { + console.error('e', e) + ws.send( + JSON.stringify({ + url: json.url, + correlationId: json.correlationId, + body: { + error: e.message + } + }) + ) } }) }) @@ -296,6 +310,10 @@ const createWindow = async () => { if (argUrl) { console.log('argUrl', argUrl) + const port = await createAppServer(mainWindow) + + console.log('port', port) + await mainWindow?.loadURL(argUrl) } else { const port = await createAppServer(mainWindow) diff --git a/package.json b/package.json index b50578b..bd3fe74 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "@electron-toolkit/utils": "3.0.0", "@floating-ui/vue": "1.1.5", "@jitl/quickjs-wasmfile-release-sync": "0.31.0", - "@pipelab/core": "1.3.0", + "@pipelab/core": "1.3.2", "@primevue/themes": "4.1.1", "@sentry/electron": "5.4.0", "@sentry/vue": "8.32.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 178608f..cf94d28 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -46,8 +46,8 @@ importers: specifier: 0.31.0 version: 0.31.0 '@pipelab/core': - specifier: 1.3.0 - version: 1.3.0 + specifier: 1.3.2 + version: 1.3.2 '@primevue/themes': specifier: 4.1.1 version: 4.1.1 @@ -1653,8 +1653,8 @@ packages: resolution: {integrity: sha512-HNjmfLQEVRZmHRET336f20H/8kOozUGwk7yajvsonjNxbj2wBTK1WsQuHkD5yYh9RxFGL2EyDHryOihOwUoKDA==} engines: {node: '>= 10.0.0'} - '@pipelab/core@1.3.0': - resolution: {integrity: sha512-f5e6rT8mAAb5aZxUc+5WMcfYB5XMhFvvhqvwdcDuKsxHU5AzvTED9oqiOhYdU5DT7IQkrpi95GkhqcQNkuYVQg==} + '@pipelab/core@1.3.2': + resolution: {integrity: sha512-WH7M4GU9yqp3/jW/7kpAmJtMsjajuEu0BH6wc6SXDthw+kH00BmkG5V3K4eHB5vMCuw2ZL5B6hVPz+rbCPtj/g==} '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} @@ -8895,7 +8895,7 @@ snapshots: '@parcel/watcher-win32-ia32': 2.4.1 '@parcel/watcher-win32-x64': 2.4.1 - '@pipelab/core@1.3.0': {} + '@pipelab/core@1.3.2': {} '@pkgjs/parseargs@0.11.0': optional: true diff --git a/src/main.ts b/src/main.ts index c415509..d2f5729 100644 --- a/src/main.ts +++ b/src/main.ts @@ -8,7 +8,6 @@ import { registerIPCHandlers } from './main/handlers' import { usePlugins } from '@@/plugins' import { parseArgs, ParseArgsConfig } from 'node:util' import { processGraph } from '@@/graph' -import { Tray, Menu, nativeImage } from 'electron' import { readFile, writeFile, mkdir } from 'fs/promises' import { getFinalPlugins } from '@main/utils' import { SavedFile } from '@@/model' @@ -18,7 +17,7 @@ import * as Sentry from '@sentry/electron/main' import { assetsPath } from '@main/paths' const isLinux = platform() === 'linux' -let tray +// let tray let isReadyToShow = false const { logger, setMainWindow } = useLogger() @@ -37,7 +36,7 @@ if (app.isPackaged && process.env.TEST !== 'true' && !isWine) { }) } -const imagePath = join('./assets', 'icon.png') +const imagePath = join('./assets', 'discord_white.png') // let isQuiting = false if (!isLinux && process.env.TEST !== 'true' && require('electron-squirrel-startup')) app.quit() @@ -70,19 +69,16 @@ function createWindow(): void { isReadyToShow = true }) - mainWindow.on('minimize', function (event: Event) { - event.preventDefault() - mainWindow.hide() - }) + // TODO: only if minimize to tray enabled + // mainWindow.on('minimize', function (event: Event) { + // event.preventDefault() + // mainWindow.hide() + // }) mainWindow.on('close', function () { app.quit() }) - mainWindow.on('minimize', function () { - mainWindow.hide() - }) - mainWindow.webContents.setWindowOpenHandler((details) => { shell.openExternal(details.url) return { action: 'deny' } @@ -285,33 +281,33 @@ exec "${process.execPath}" "$@" process.exit(0) } - const icon = nativeImage.createFromPath(imagePath) - tray = new Tray(icon) - const contextMenu = Menu.buildFromTemplate([ - { - label: 'Open', - type: 'normal', - click: () => { - if (mainWindow) { - mainWindow.show() - } - } - }, - { type: 'separator' }, - { - label: 'Exit', - type: 'normal', - click: () => { - // isQuiting = true - app.quit() - } - } - ]) - - tray.setContextMenu(contextMenu) - tray.on('click', () => { - mainWindow.show() - }) + // const icon = nativeImage.createFromPath(imagePath) + // tray = new Tray(icon) + // const contextMenu = Menu.buildFromTemplate([ + // { + // label: 'Open', + // type: 'normal', + // click: () => { + // if (mainWindow) { + // mainWindow.show() + // } + // } + // }, + // { type: 'separator' }, + // { + // label: 'Exit', + // type: 'normal', + // click: () => { + // // isQuiting = true + // app.quit() + // } + // } + // ]) + + // tray.setContextMenu(contextMenu) + // tray.on('click', () => { + // mainWindow.show() + // }) mainWindow.on('ready-to-show', () => { mainWindow.show() diff --git a/src/renderer/components/nodes/EditorNodeAction.vue b/src/renderer/components/nodes/EditorNodeAction.vue index dbe3cef..461ec8b 100644 --- a/src/renderer/components/nodes/EditorNodeAction.vue +++ b/src/renderer/components/nodes/EditorNodeAction.vue @@ -115,6 +115,7 @@ :steps="steps" :variables="variables" @update:model-value="onValueChanged($event, key.toString())" + :vm="vm" > diff --git a/src/renderer/components/nodes/ParamEditor.vue b/src/renderer/components/nodes/ParamEditor.vue index d4e47b5..d46026d 100644 --- a/src/renderer/components/nodes/ParamEditor.vue +++ b/src/renderer/components/nodes/ParamEditor.vue @@ -196,7 +196,7 @@ import { computed, ref, toRefs, watch } from 'vue' import type { ValueOf } from 'type-fest' import { Action, Condition, Event } from '@pipelab/plugin-core' import { createCodeEditor } from '@renderer/utils/code-editor' -import { createQuickJs } from '@renderer/utils/quickjs' +import { CreateQuickJSFn } from '@renderer/utils/quickjs' import { BlockAction, BlockCondition, BlockEvent, BlockLoop, Steps } from '@@/model' import { controlsToIcon, controlsToType } from '@renderer/models/controls' import { Completion, CompletionContext } from '@codemirror/autocomplete' @@ -216,8 +216,6 @@ import { klona } from 'klona' import { stepsPlaceholders } from '@renderer/utils/code-editor/step-plugin' // @ts-expect-error tsconfig -const vm = await createQuickJs() - type Params = (Action | Condition | Event)['params'] type Param = ValueOf @@ -229,6 +227,7 @@ const props = defineProps<{ value: BlockAction | BlockEvent | BlockCondition | BlockLoop steps: Steps variables: Variable[] + vm: Awaited }>() // const props = defineProps({ @@ -260,7 +259,7 @@ const props = defineProps<{ // } // }) -const { paramKey, paramDefinition, steps, variables, param } = toRefs(props) +const { paramKey, paramDefinition, steps, variables, param, vm } = toRefs(props) const confirm = useConfirm() @@ -326,7 +325,7 @@ const $arrow = ref() const { logger } = useLogger() const formattedVariables = () => { - return variableToFormattedVariable(vm, variables.value) + return variableToFormattedVariable(vm.value, variables.value) } function myCompletions(context: CompletionContext) { @@ -390,7 +389,7 @@ const doCodeEditorUpdate = throttle(async (newValue) => { const variables = await formattedVariables() console.log('displayString', displayString) console.log('variables', variables) - const result = await vm.run(displayString, { + const result = await vm.value.run(displayString, { params: {}, // params: resolvedParams.value, steps: steps.value, diff --git a/src/renderer/pages/index.vue b/src/renderer/pages/index.vue index f2b3b72..be08f81 100644 --- a/src/renderer/pages/index.vue +++ b/src/renderer/pages/index.vue @@ -367,10 +367,12 @@ watchEffect(async () => { for (const [id, file] of entries) { let fileContent: string if (file.type === 'external') { + console.log('loading file', file.path) const resultLoad = await loadExternalFile(file.path) if (resultLoad.type === 'error') { - throw new Error(resultLoad.ipcError) + console.error('Unable to load file', resultLoad.ipcError) + continue } const result = resultLoad.result diff --git a/src/shared/graph.ts b/src/shared/graph.ts index 0980530..253c237 100644 --- a/src/shared/graph.ts +++ b/src/shared/graph.ts @@ -9,6 +9,26 @@ import { useLogger } from './logger' import { variableToFormattedVariable } from '@renderer/composables/variables' import { createQuickJs } from '@renderer/utils/quickjs' +const getPluginDefinition = (pluginId: string, definitions: Array) => { + const result = definitions.find((nodeDef) => { + return nodeDef.id === pluginId + }) + return result +} + +const getNodeDefinition = ( + nodeId: string, + pluginId: string, + definitions: Array +) => { + // const getNodeDefinition = (node: T extends Block ? T : never) => { + const plugin = getPluginDefinition(pluginId, definitions) + if (plugin) { + return plugin.nodes.find((pluginNode) => pluginNode.node.id === nodeId) + } + return undefined +} + export const processGraph = async (options: { graph: Array definitions: Array @@ -31,6 +51,13 @@ export const processGraph = async (options: { for (const node of options.graph) { const rawNode = node + const pluginDefinition = getPluginDefinition(node.origin.pluginId, options.definitions) + const nodeDefinition = getNodeDefinition( + node.origin.nodeId, + node.origin.pluginId, + options.definitions + ) + /* if (rawNode.type === 'condition') { options.onNodeEnter(rawNode) @@ -84,12 +111,16 @@ export const processGraph = async (options: { const variables = await variableToFormattedVariable(vm, options.variables) console.log('variables', variables) - const newParams = await makeResolvedParams({ - params: rawNode.params, - variables, - steps: options.steps, - context: options.context - }) + const newParams = await makeResolvedParams( + { + params: rawNode.params, + variables, + steps: options.steps, + context: options.context + }, + undefined, + vm + ) const result = (await options.onExecuteItem( node, @@ -100,7 +131,7 @@ export const processGraph = async (options: { if (result.type === 'error') { logger().error(result.ipcError) options.onNodeExit(rawNode) - throw new Error('Action error: ' + result.ipcError) + throw new Error(`"${nodeDefinition.node.name}" action error: ${result.ipcError}`) } if (result.type === 'success') { diff --git a/src/shared/libs/plugin-construct/export-shared.ts b/src/shared/libs/plugin-construct/export-shared.ts index 927b9fc..631927d 100644 --- a/src/shared/libs/plugin-construct/export-shared.ts +++ b/src/shared/libs/plugin-construct/export-shared.ts @@ -25,7 +25,8 @@ export const sharedParams = { } }, password: { - description: 'Your Construct password', + description: + 'Your Construct password. Will only be used locally to automate the export on Construct website via a local browser. Will not be sent to any server.', control: { type: 'input', options: { diff --git a/src/shared/libs/plugin-electron/forge.ts b/src/shared/libs/plugin-electron/forge.ts index 77796da..195de1f 100644 --- a/src/shared/libs/plugin-electron/forge.ts +++ b/src/shared/libs/plugin-electron/forge.ts @@ -213,6 +213,10 @@ export const forge = async ( const { assets, unpack } = paths + if (!inputs.configuration) { + throw new Error('Missing electron configuration') + } + const { join, basename, delimiter } = await import('node:path') const { cp } = await import('node:fs/promises') const { arch, platform } = await import('os') diff --git a/src/shared/libs/plugin-filesystem/copy.ts b/src/shared/libs/plugin-filesystem/copy.ts index 2795a2d..d1f72e0 100644 --- a/src/shared/libs/plugin-filesystem/copy.ts +++ b/src/shared/libs/plugin-filesystem/copy.ts @@ -4,7 +4,7 @@ export const ID = 'fs:copy' export const copy = createAction({ id: ID, - name: 'Copy file', + name: 'Copy file/folder', displayString: '`Copy ${fmt.param(params.from, "primary")} to ${fmt.param(params.to, "primary")}`', params: { @@ -34,6 +34,13 @@ export const copy = createAction({ control: { type: 'boolean' } + }, + overwrite: { + label: 'Overwrite', + value: true, + control: { + type: 'boolean' + } } }, @@ -51,17 +58,20 @@ export const copyRunner = createActionRunner(async ({ log, inputs } const to = inputs.to if (!from) { + log('From', from) throw new Error('Missing source') } if (!to) { + log('To', to) throw new Error('Missing destination') } try { process.noAsar = true await cp(from, to, { - recursive: inputs.recursive + recursive: inputs.recursive, + force: inputs.overwrite, }) process.noAsar = false } catch (e) { diff --git a/src/shared/libs/plugin-steam/upload-to-steam.ts b/src/shared/libs/plugin-steam/upload-to-steam.ts index 59e40ad..d7bc5ac 100644 --- a/src/shared/libs/plugin-steam/upload-to-steam.ts +++ b/src/shared/libs/plugin-steam/upload-to-steam.ts @@ -185,21 +185,50 @@ export const uploadToSteamRunner = createActionRunner( log('Executing steamcmd') - await runWithLiveLogs( - steamcmdPath, - ['+login', username, '+run_app_build', scriptPath, '+quit'], - {}, - log, - { - onStdout: (data, subprocess) => { - log('data stdout', data) - if (data.includes('Cached credentials not found')) { - log('You are not logged in to Steam') - subprocess.kill() + let error: string = '' + + try { + await runWithLiveLogs( + steamcmdPath, + ['+login', username, '+run_app_build', scriptPath, '+quit'], + {}, + log, + { + onStdout: (data, subprocess) => { + log('data stdout', data) + + // TODO: handle password input dynamically + if (data.includes('Cached credentials not found')) { + error = 'LOGGED_OUT' + + subprocess.kill() + } } } + ) + } catch (e) { + console.error(e) + if (!error) { + error = 'UNKNOWN' } - ) + } + + console.warn('error', error) + + if (error) { + if (error === 'LOGGED_OUT') { + log('You are not logged in to Steam') + log('To log in, run command below:') + log(`"${steamcmdPath}" +login ${username} +quit`) + throw new Error( + 'You are not logged in to Steam\nTo log in, run command below:\n' + + `"${steamcmdPath}" +login ${username} +quit` + ) + } else { + throw new Error('Unknown error') + } + } + // // must keep that to not be interactive // await execa(steamcmdPath, ['+login', username, '+run_app_build', scriptPath, '+quit'], { // stdout: 'inherit',