@factorialco/fcode-cli 1.1.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 (234) hide show
  1. package/README.md +1021 -0
  2. package/bin/dev +17 -0
  3. package/bin/dev.cmd +3 -0
  4. package/bin/run +7 -0
  5. package/bin/run.cmd +3 -0
  6. package/dist/commands/add.d.ts +6 -0
  7. package/dist/commands/add.js +22 -0
  8. package/dist/commands/clone.d.ts +26 -0
  9. package/dist/commands/clone.js +177 -0
  10. package/dist/commands/dependencies/add.d.ts +9 -0
  11. package/dist/commands/dependencies/add.js +13 -0
  12. package/dist/commands/dependencies/install.d.ts +14 -0
  13. package/dist/commands/dependencies/install.js +44 -0
  14. package/dist/commands/dependencies/pull.d.ts +12 -0
  15. package/dist/commands/dependencies/pull.js +14 -0
  16. package/dist/commands/dependencies/push.d.ts +12 -0
  17. package/dist/commands/dependencies/push.js +14 -0
  18. package/dist/commands/dependencies/reset.d.ts +9 -0
  19. package/dist/commands/dependencies/reset.js +13 -0
  20. package/dist/commands/dependencies/status.d.ts +9 -0
  21. package/dist/commands/dependencies/status.js +13 -0
  22. package/dist/commands/http.d.ts +22 -0
  23. package/dist/commands/http.js +272 -0
  24. package/dist/commands/login.d.ts +18 -0
  25. package/dist/commands/login.js +62 -0
  26. package/dist/commands/logout.d.ts +10 -0
  27. package/dist/commands/logout.js +34 -0
  28. package/dist/commands/modules/add.d.ts +9 -0
  29. package/dist/commands/modules/add.js +13 -0
  30. package/dist/commands/modules/pull.d.ts +13 -0
  31. package/dist/commands/modules/pull.js +43 -0
  32. package/dist/commands/modules/push.d.ts +13 -0
  33. package/dist/commands/modules/push.js +35 -0
  34. package/dist/commands/modules/remove.d.ts +9 -0
  35. package/dist/commands/modules/remove.js +19 -0
  36. package/dist/commands/modules/reset.d.ts +9 -0
  37. package/dist/commands/modules/reset.js +13 -0
  38. package/dist/commands/modules/status.d.ts +11 -0
  39. package/dist/commands/modules/status.js +40 -0
  40. package/dist/commands/pre-debug.d.ts +20 -0
  41. package/dist/commands/pre-debug.js +120 -0
  42. package/dist/commands/process-metadata.d.ts +18 -0
  43. package/dist/commands/process-metadata.js +63 -0
  44. package/dist/commands/processes/add.d.ts +9 -0
  45. package/dist/commands/processes/add.js +13 -0
  46. package/dist/commands/processes/install-dependencies.d.ts +14 -0
  47. package/dist/commands/processes/install-dependencies.js +30 -0
  48. package/dist/commands/processes/pull.d.ts +13 -0
  49. package/dist/commands/processes/pull.js +47 -0
  50. package/dist/commands/processes/push.d.ts +13 -0
  51. package/dist/commands/processes/push.js +39 -0
  52. package/dist/commands/processes/remove.d.ts +9 -0
  53. package/dist/commands/processes/remove.js +19 -0
  54. package/dist/commands/processes/reset.d.ts +9 -0
  55. package/dist/commands/processes/reset.js +13 -0
  56. package/dist/commands/processes/status.d.ts +11 -0
  57. package/dist/commands/processes/status.js +58 -0
  58. package/dist/commands/pull.d.ts +9 -0
  59. package/dist/commands/pull.js +32 -0
  60. package/dist/commands/push.d.ts +9 -0
  61. package/dist/commands/push.js +29 -0
  62. package/dist/commands/remote/add.d.ts +10 -0
  63. package/dist/commands/remote/add.js +32 -0
  64. package/dist/commands/remote/list.d.ts +7 -0
  65. package/dist/commands/remote/list.js +33 -0
  66. package/dist/commands/remote/set.d.ts +10 -0
  67. package/dist/commands/remote/set.js +28 -0
  68. package/dist/commands/reset.d.ts +6 -0
  69. package/dist/commands/reset.js +19 -0
  70. package/dist/commands/run.d.ts +16 -0
  71. package/dist/commands/run.js +56 -0
  72. package/dist/commands/runtime-env.d.ts +12 -0
  73. package/dist/commands/runtime-env.js +42 -0
  74. package/dist/commands/settings/get.d.ts +12 -0
  75. package/dist/commands/settings/get.js +67 -0
  76. package/dist/commands/settings/remove.d.ts +9 -0
  77. package/dist/commands/settings/remove.js +35 -0
  78. package/dist/commands/settings/set.d.ts +10 -0
  79. package/dist/commands/settings/set.js +39 -0
  80. package/dist/commands/setup-debug.d.ts +12 -0
  81. package/dist/commands/setup-debug.js +118 -0
  82. package/dist/commands/status.d.ts +6 -0
  83. package/dist/commands/status.js +22 -0
  84. package/dist/commands/team/pull.d.ts +8 -0
  85. package/dist/commands/team/pull.js +23 -0
  86. package/dist/commands/team/push.d.ts +11 -0
  87. package/dist/commands/team/push.js +41 -0
  88. package/dist/commands/team/status.d.ts +8 -0
  89. package/dist/commands/team/status.js +40 -0
  90. package/dist/commands/test/scaffold.d.ts +9 -0
  91. package/dist/commands/test/scaffold.js +61 -0
  92. package/dist/commands/test.d.ts +13 -0
  93. package/dist/commands/test.js +72 -0
  94. package/dist/commands/variables/add.d.ts +12 -0
  95. package/dist/commands/variables/add.js +21 -0
  96. package/dist/commands/variables/pull.d.ts +12 -0
  97. package/dist/commands/variables/pull.js +14 -0
  98. package/dist/commands/variables/push.d.ts +12 -0
  99. package/dist/commands/variables/push.js +14 -0
  100. package/dist/commands/variables/remove.d.ts +9 -0
  101. package/dist/commands/variables/remove.js +19 -0
  102. package/dist/commands/variables/reset.d.ts +9 -0
  103. package/dist/commands/variables/reset.js +13 -0
  104. package/dist/commands/variables/status.d.ts +12 -0
  105. package/dist/commands/variables/status.js +58 -0
  106. package/dist/config/global.d.ts +15 -0
  107. package/dist/config/global.js +77 -0
  108. package/dist/config/index.d.ts +14 -0
  109. package/dist/config/index.js +44 -0
  110. package/dist/config/remote.d.ts +15 -0
  111. package/dist/config/remote.js +60 -0
  112. package/dist/config/settings.d.ts +16 -0
  113. package/dist/config/settings.js +54 -0
  114. package/dist/config/workspace.d.ts +28 -0
  115. package/dist/config/workspace.js +158 -0
  116. package/dist/core/commands/api-client-command.d.ts +6 -0
  117. package/dist/core/commands/api-client-command.js +30 -0
  118. package/dist/core/commands/base-command.d.ts +11 -0
  119. package/dist/core/commands/base-command.js +61 -0
  120. package/dist/core/commands/dependency-command.d.ts +5 -0
  121. package/dist/core/commands/dependency-command.js +16 -0
  122. package/dist/core/commands/modules-command.d.ts +7 -0
  123. package/dist/core/commands/modules-command.js +18 -0
  124. package/dist/core/commands/processes-command.d.ts +8 -0
  125. package/dist/core/commands/processes-command.js +27 -0
  126. package/dist/core/commands/resource-command.d.ts +24 -0
  127. package/dist/core/commands/resource-command.js +92 -0
  128. package/dist/core/commands/variables-command.d.ts +5 -0
  129. package/dist/core/commands/variables-command.js +16 -0
  130. package/dist/core/dependencies/env-dependencies-command.d.ts +19 -0
  131. package/dist/core/dependencies/env-dependencies-command.js +70 -0
  132. package/dist/core/dependencies/env-process-dependencies-command.d.ts +15 -0
  133. package/dist/core/dependencies/env-process-dependencies-command.js +78 -0
  134. package/dist/core/dependencies/javascript-env-dependencies.d.ts +8 -0
  135. package/dist/core/dependencies/javascript-env-dependencies.js +77 -0
  136. package/dist/core/dependencies/python-env-dependencies.d.ts +9 -0
  137. package/dist/core/dependencies/python-env-dependencies.js +91 -0
  138. package/dist/core/errors.d.ts +55 -0
  139. package/dist/core/errors.js +144 -0
  140. package/dist/core/executors/execution-task.d.ts +29 -0
  141. package/dist/core/executors/execution-task.js +139 -0
  142. package/dist/core/executors/javascript-execution-task.d.ts +13 -0
  143. package/dist/core/executors/javascript-execution-task.js +618 -0
  144. package/dist/core/executors/python/context.d.ts +2 -0
  145. package/dist/core/executors/python/context.js +3 -0
  146. package/dist/core/executors/python/datastore.d.ts +2 -0
  147. package/dist/core/executors/python/datastore.js +4 -0
  148. package/dist/core/executors/python-execution-task.d.ts +11 -0
  149. package/dist/core/executors/python-execution-task.js +173 -0
  150. package/dist/core/executors/source-code-sanitizer.d.ts +4 -0
  151. package/dist/core/executors/source-code-sanitizer.js +45 -0
  152. package/dist/core/resource-merger.d.ts +14 -0
  153. package/dist/core/resource-merger.js +155 -0
  154. package/dist/core/resource-pusher.d.ts +12 -0
  155. package/dist/core/resource-pusher.js +133 -0
  156. package/dist/core/resource-repository.d.ts +8 -0
  157. package/dist/core/resource-repository.js +2 -0
  158. package/dist/core/types.d.ts +290 -0
  159. package/dist/core/types.js +238 -0
  160. package/dist/core/utils/dependencies.d.ts +5 -0
  161. package/dist/core/utils/dependencies.js +82 -0
  162. package/dist/core/utils/variables.d.ts +4 -0
  163. package/dist/core/utils/variables.js +10 -0
  164. package/dist/hooks/init/auth.d.ts +3 -0
  165. package/dist/hooks/init/auth.js +28 -0
  166. package/dist/hooks/init/update.d.ts +3 -0
  167. package/dist/hooks/init/update.js +42 -0
  168. package/dist/index.d.ts +1 -0
  169. package/dist/index.js +4 -0
  170. package/dist/repositories/process.d.ts +36 -0
  171. package/dist/repositories/process.js +339 -0
  172. package/dist/repositories/programming-language-manifest.d.ts +17 -0
  173. package/dist/repositories/programming-language-manifest.js +95 -0
  174. package/dist/repositories/resource.d.ts +29 -0
  175. package/dist/repositories/resource.js +79 -0
  176. package/dist/repositories/script-library.d.ts +28 -0
  177. package/dist/repositories/script-library.js +164 -0
  178. package/dist/repositories/team.d.ts +23 -0
  179. package/dist/repositories/team.js +74 -0
  180. package/dist/repositories/variable.d.ts +26 -0
  181. package/dist/repositories/variable.js +174 -0
  182. package/dist/runtime/executor.js +87 -0
  183. package/dist/runtime/executor.py +81 -0
  184. package/dist/runtime/libs/node/fcode/index.js +1 -0
  185. package/dist/runtime/libs/python/fcode/__init__.py +75 -0
  186. package/dist/runtime/libs/python/fcode/context.py +98 -0
  187. package/dist/runtime/libs/python/fcode/datastore.py +35 -0
  188. package/dist/runtime/libs/python/fcode/schedule.py +45 -0
  189. package/dist/runtime/libs/python/fcode/storage.py +271 -0
  190. package/dist/runtime/libs/python/fcode/variables.py +102 -0
  191. package/dist/services/auth-service.d.ts +12 -0
  192. package/dist/services/auth-service.js +114 -0
  193. package/dist/services/credential-prompter.d.ts +6 -0
  194. package/dist/services/credential-prompter.js +60 -0
  195. package/dist/services/fcode-graphql-client.d.ts +45 -0
  196. package/dist/services/fcode-graphql-client.js +721 -0
  197. package/dist/services/http-server.d.ts +3 -0
  198. package/dist/services/http-server.js +17 -0
  199. package/dist/services/oauth-browser-service.d.ts +9 -0
  200. package/dist/services/oauth-browser-service.js +164 -0
  201. package/dist/services/process-parameters-sampler.d.ts +2 -0
  202. package/dist/services/process-parameters-sampler.js +41 -0
  203. package/dist/services/process-runner.d.ts +22 -0
  204. package/dist/services/process-runner.js +97 -0
  205. package/dist/services/resource-checker.d.ts +8 -0
  206. package/dist/services/resource-checker.js +82 -0
  207. package/dist/services/test-runner.d.ts +17 -0
  208. package/dist/services/test-runner.js +228 -0
  209. package/dist/utils/canonical-hash.d.ts +9 -0
  210. package/dist/utils/canonical-hash.js +30 -0
  211. package/dist/utils/cli/index.d.ts +14 -0
  212. package/dist/utils/cli/index.js +50 -0
  213. package/dist/utils/cli/screen.d.ts +2 -0
  214. package/dist/utils/cli/screen.js +25 -0
  215. package/dist/utils/cli/styled/table.d.ts +23 -0
  216. package/dist/utils/cli/styled/table.js +272 -0
  217. package/dist/utils/colorize-resource.d.ts +1 -0
  218. package/dist/utils/colorize-resource.js +7 -0
  219. package/dist/utils/env-utils.d.ts +2 -0
  220. package/dist/utils/env-utils.js +16 -0
  221. package/dist/utils/file-utils.d.ts +11 -0
  222. package/dist/utils/file-utils.js +33 -0
  223. package/dist/utils/filenamify.d.ts +4 -0
  224. package/dist/utils/filenamify.js +73 -0
  225. package/dist/utils/gitignore.d.ts +17 -0
  226. package/dist/utils/gitignore.js +60 -0
  227. package/dist/utils/promise.d.ts +4 -0
  228. package/dist/utils/promise.js +38 -0
  229. package/dist/utils/url-utils.d.ts +2 -0
  230. package/dist/utils/url-utils.js +10 -0
  231. package/dist/utils/variable-warnings.d.ts +8 -0
  232. package/dist/utils/variable-warnings.js +38 -0
  233. package/oclif.manifest.json +1783 -0
  234. package/package.json +129 -0
@@ -0,0 +1,618 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const node_child_process_1 = require("node:child_process");
4
+ const errors_1 = require("../errors");
5
+ const fs = require("node:fs");
6
+ const path = require("node:path");
7
+ const execution_task_1 = require("./execution-task");
8
+ const source_code_sanitizer_1 = require("./source-code-sanitizer");
9
+ /**
10
+ * Task which handles native executions using child_process.
11
+ */
12
+ class JavaScriptExecutionTask extends execution_task_1.default {
13
+ async run() {
14
+ if (!this._execFilePath) {
15
+ this.prepare();
16
+ }
17
+ const nodePath = process.env.NODE_PATH;
18
+ const fcodeLibPath = path.join(__dirname, '..', '..', 'runtime', 'libs', 'node');
19
+ const nodeModulesPath = path.join(this._dependenciesPath, 'node_modules');
20
+ const forked = (0, node_child_process_1.fork)(path.resolve(this._execFilePath), {
21
+ env: {
22
+ FORCE_COLOR: 'true',
23
+ NODE_PATH: [nodeModulesPath, nodePath, fcodeLibPath].filter((p) => p).join(':'),
24
+ PATH: process.env.PATH,
25
+ },
26
+ silent: false,
27
+ });
28
+ return new Promise((resolve, reject) => {
29
+ forked.on('exit', (code) => {
30
+ if (code) {
31
+ reject(new errors_1.ErrorExecutingProcess(`Process exited with code ${code}`));
32
+ }
33
+ else {
34
+ resolve(undefined);
35
+ }
36
+ });
37
+ });
38
+ }
39
+ _getLegacyBlock() {
40
+ const sourceCode = this.getExecutionSourceCode();
41
+ return `const main = async () => { ${sourceCode}
42
+ };`;
43
+ }
44
+ _getNewBlock() {
45
+ if (this._options.hookFilePath) {
46
+ const fn = this._options.hookFunction ?? 'main';
47
+ return `
48
+ const _hooksModule = require('${this._options.hookFilePath}')
49
+ const main = typeof _hooksModule['${fn}'] === 'function'
50
+ ? _hooksModule['${fn}']
51
+ : async () => undefined`;
52
+ }
53
+ const processPath = [process.cwd(), 'processes', this._process.slug];
54
+ if (this._options.version) {
55
+ processPath.push('versions', this._options.version);
56
+ }
57
+ processPath.push('index.js');
58
+ const fullPath = path.join(...processPath);
59
+ return `const { main }= require('${fullPath}')`;
60
+ }
61
+ async _createExecutionFiles(tempDir) {
62
+ if (!this._options.silent) {
63
+ this._options.jsonLogs
64
+ ? process.stdout.write(JSON.stringify({ timestamp: new Date().toISOString(), level: 'DEBUG', message: `Creating execution files for '${this._process.slug}' in ${tempDir}` }) + '\n')
65
+ : console.debug(`Creating execution files for '${this._process.slug}' in ${tempDir}`);
66
+ }
67
+ const execFilePath = `${tempDir}/${this._process.slug}.js`;
68
+ const metadata = this.getMetadata();
69
+ const execution = metadata.execution;
70
+ execution.id = '00000000-0000-0000-0000-000000000000';
71
+ execution.process = {
72
+ id: execution.process?.id || '00000000-0000-0000-0000-000000000000',
73
+ name: execution.process?.name || 'Process not yet pushed to cloud',
74
+ };
75
+ execution.timeout = 86400000;
76
+ const isLegacy = !this._options.hookFilePath && (0, source_code_sanitizer_1.isLegacySourceCode)(this.getExecutionSourceCode(), 'JAVASCRIPT');
77
+ fs.writeFileSync(execFilePath, `${isLegacy ? this._getLegacyBlock() : ''}
78
+
79
+ global.logLevel = "` +
80
+ this._options.logLevel +
81
+ `";
82
+ const logLevels = ["DEBUG", "INFO", "WARNING", "ERROR"];
83
+ const shouldLog = (level) => {
84
+ return logLevels.indexOf(level) >= logLevels.indexOf(global.logLevel);
85
+ };
86
+ const _console = console
87
+ ${this._options.jsonLogs ? `
88
+ const _ts = () => new Date().toISOString();
89
+ const _fmt = (level, msg, rest) => JSON.stringify({timestamp:_ts(),level,message:[msg,...rest].map(p=>typeof p==='string'?p:JSON.stringify(p)).join(' ')});
90
+ global.console = {
91
+ ...global.console,
92
+ log: (msg, ...rest) => { shouldLog("INFO") && _console.log(_fmt("INFO", msg, rest)); },
93
+ warn: (msg, ...rest) => { shouldLog("WARNING") && _console.warn(_fmt("WARNING",msg, rest)); },
94
+ error: (msg, ...rest) => { shouldLog("ERROR") && _console.error(_fmt("ERROR", msg, rest)); },
95
+ debug: (msg, ...rest) => { shouldLog("DEBUG") && _console.debug(_fmt("DEBUG", msg, rest)); },
96
+ };` : `
97
+ global.console = {
98
+ ...global.console,
99
+ log: (message, ...optionalParams) => {
100
+ shouldLog("INFO") && _console.log(message, ...optionalParams);
101
+ },
102
+ warn: (message, ...optionalParams) => {
103
+ shouldLog("WARNING") && _console.warn(message, ...optionalParams);
104
+ },
105
+ error: (message, ...optionalParams) => {
106
+ shouldLog("ERROR") && _console.error(message, ...optionalParams);
107
+ },
108
+ debug: (message, ...optionalParams) => {
109
+ shouldLog("DEBUG") && _console.debug(message, ...optionalParams);
110
+ },
111
+ };`}
112
+
113
+ global.fcode = {
114
+ import: (moduleName, version) => {
115
+ let modulePath = require('path').join('${process.cwd()}', 'modules', moduleName);
116
+ if(version) {
117
+ modulePath = require('path').join(modulePath, 'versions', version)
118
+ }
119
+ modulePath = require('path').join(modulePath, moduleName + '.js')
120
+ return require(modulePath)
121
+ },
122
+ env: ${JSON.stringify(metadata.variables, null, 2)},
123
+ context: {
124
+ parameters: ${JSON.stringify(metadata.parameters, null, 2)},
125
+ request: ${JSON.stringify(metadata.request)}
126
+ },
127
+ execution: ${JSON.stringify(metadata.execution, null, 2)},
128
+ team: {
129
+ "timezone": "UTC"
130
+ },
131
+ processes: {
132
+ run: (processIdentifier, options) => {
133
+ const { exec } = require('child_process');
134
+ const tag = options.tag ? " -v " + options.tag : ''
135
+ const parameters = options.parameters ? " -p '" + JSON.stringify(options.parameters) + "'" : ''
136
+ const command = "fcode run " + processIdentifier + tag + parameters
137
+ exec(command, {}, (error, stdout, stderr) => {
138
+ if (error) {
139
+ console.error(error)
140
+ }
141
+ console.log(stdout)
142
+ console.error(stderr)
143
+ })
144
+ }
145
+ },
146
+ datastore: {
147
+ async save(datastore) {
148
+ return new Promise((resolve, reject) => {
149
+ require('fs').writeFile(require('path').join('${process.cwd()}', 'datastore.json'), JSON.stringify(datastore, null, 2), (err) => {
150
+ if (err) {
151
+ reject(err)
152
+ }
153
+ resolve(undefined)
154
+ })
155
+ })
156
+ },
157
+ getAll() {
158
+ try {
159
+ return require(require('path').join('${process.cwd()}', 'datastore.json'));
160
+ } catch (e) {
161
+ return {}
162
+ }
163
+ },
164
+ async get(key) {
165
+ if ((typeof key === 'string' || typeof key === 'number')) {
166
+ return this.getAll()[key] || null
167
+ }
168
+ throw new Error('Invalid argument type')
169
+ },
170
+ async set(key, value) {
171
+ if ((typeof key === 'string' || typeof key === 'number') && (typeof value === 'string' || typeof value === 'number')) {
172
+ const datastore = this.getAll()
173
+ datastore[key] = value
174
+ return this.save(datastore)
175
+ }
176
+ throw new Error('Invalid argument type')
177
+ },
178
+ async del(key) {
179
+ const datastore = this.getAll()
180
+ delete datastore[key]
181
+ return this.save(datastore)
182
+ }
183
+ },
184
+ storage: {
185
+ async upload(filename, file) {
186
+ return new Promise((resolve, reject) => {
187
+ const fs = require('fs')
188
+ const path = require('path')
189
+ const crypto = require('crypto')
190
+
191
+ const createResponse = (filePath, hash) => {
192
+ try {
193
+ const stats = fs.statSync(filePath)
194
+ const currentTime = new Date().toISOString()
195
+
196
+ return {
197
+ name: filename,
198
+ size: stats.size,
199
+ link: filePath,
200
+ md5_hash: hash.digest('hex'),
201
+ content_type: 'application/octet-stream',
202
+ created_at: currentTime,
203
+ updated_at: currentTime
204
+ }
205
+ } catch (error) {
206
+ throw new Error(\`Storage upload failed: unable to process file - \${error.message}\`)
207
+ }
208
+ }
209
+
210
+ if (typeof filename !== 'string') {
211
+ return reject(new Error('Storage upload failed: filename must be a string'))
212
+ }
213
+
214
+ if (!filename.trim()) {
215
+ return reject(new Error('Storage upload failed: filename cannot be empty'))
216
+ }
217
+
218
+ if (!file) {
219
+ return reject(new Error('Storage upload failed: file parameter is required'))
220
+ }
221
+
222
+ const isReadable = typeof file?.pipe === 'function'
223
+ const isFile = typeof File !== 'undefined' && file instanceof File
224
+ const isBlob = typeof Blob !== 'undefined' && file instanceof Blob
225
+ const isBuffer = Buffer.isBuffer(file)
226
+ const isString = typeof file === 'string'
227
+
228
+ if (!isReadable && !isFile && !isBlob && !isBuffer && !isString) {
229
+ return reject(new Error('Storage upload failed: file must be File, Blob, Readable stream, Buffer, or string'))
230
+ }
231
+
232
+ try {
233
+ const storageDir = path.join('${process.cwd()}', 'storage')
234
+ if (!fs.existsSync(storageDir)) {
235
+ fs.mkdirSync(storageDir)
236
+ }
237
+
238
+ const filePath = path.join(storageDir, filename)
239
+ const fileDir = path.dirname(filePath)
240
+
241
+ if (!fs.existsSync(fileDir)) {
242
+ fs.mkdirSync(fileDir, { recursive: true })
243
+ }
244
+
245
+ const hash = crypto.createHash('md5')
246
+
247
+ if (isFile || isBlob) {
248
+ file.arrayBuffer().then(arrayBuffer => {
249
+ const buffer = Buffer.from(arrayBuffer)
250
+ hash.update(buffer)
251
+
252
+ fs.writeFile(filePath, buffer, (err) => {
253
+ if (err) {
254
+ return reject(new Error(\`Storage upload failed: write error - \${err.message}\`))
255
+ }
256
+
257
+ try {
258
+ resolve(createResponse(filePath, hash))
259
+ } catch (error) {
260
+ reject(error)
261
+ }
262
+ })
263
+ }).catch(error => {
264
+ reject(new Error(\`Storage upload failed: unable to read file content - \${error.message}\`))
265
+ })
266
+ } else if (isReadable) {
267
+ const writeStream = fs.createWriteStream(filePath)
268
+
269
+ file.on('data', (chunk) => {
270
+ hash.update(chunk)
271
+ })
272
+
273
+ file.pipe(writeStream)
274
+
275
+ writeStream.on('finish', () => {
276
+ try {
277
+ resolve(createResponse(filePath, hash))
278
+ } catch (error) {
279
+ reject(error)
280
+ }
281
+ })
282
+
283
+ writeStream.on('error', (error) => {
284
+ reject(new Error(\`Storage upload failed: write error - \${error.message}\`))
285
+ })
286
+
287
+ file.on('error', (error) => {
288
+ reject(new Error(\`Storage upload failed: stream error - \${error.message}\`))
289
+ })
290
+ } else if (isBuffer) {
291
+ hash.update(file)
292
+
293
+ fs.writeFile(filePath, file, (err) => {
294
+ if (err) {
295
+ return reject(new Error(\`Storage upload failed: write error - \${err.message}\`))
296
+ }
297
+
298
+ try {
299
+ resolve(createResponse(filePath, hash))
300
+ } catch (error) {
301
+ reject(error)
302
+ }
303
+ })
304
+ } else if (isString) {
305
+ const buffer = Buffer.from(file, 'utf8')
306
+ hash.update(buffer)
307
+
308
+ fs.writeFile(filePath, buffer, (err) => {
309
+ if (err) {
310
+ return reject(new Error(\`Storage upload failed: write error - \${err.message}\`))
311
+ }
312
+
313
+ try {
314
+ resolve(createResponse(filePath, hash))
315
+ } catch (error) {
316
+ reject(error)
317
+ }
318
+ })
319
+ }
320
+
321
+ } catch (error) {
322
+ reject(new Error(\`Storage upload failed: \${error.message}\`))
323
+ }
324
+ })
325
+ },
326
+
327
+ list(prefix = '') {
328
+ const fs = require('fs')
329
+ const path = require('path')
330
+ const crypto = require('crypto')
331
+
332
+ if (typeof prefix !== 'string') {
333
+ throw new Error('Storage list failed: prefix must be a string')
334
+ }
335
+
336
+ const storageDir = path.join('${process.cwd()}', 'storage')
337
+
338
+ if (!fs.existsSync(storageDir)) {
339
+ return []
340
+ }
341
+
342
+ const files = []
343
+
344
+ const walkDir = (dir, relativePath = '') => {
345
+ try {
346
+ const items = fs.readdirSync(dir)
347
+
348
+ for (const item of items) {
349
+ const fullPath = path.join(dir, item)
350
+ const itemRelativePath = path.join(relativePath, item)
351
+
352
+ try {
353
+ const stats = fs.statSync(fullPath)
354
+
355
+ if (stats.isDirectory()) {
356
+ walkDir(fullPath, itemRelativePath)
357
+ } else if (stats.isFile()) {
358
+ const normalizedPath = itemRelativePath.replace(/\\\\/g, '/')
359
+ if (!prefix || normalizedPath.startsWith(prefix)) {
360
+ try {
361
+ const content = fs.readFileSync(fullPath)
362
+ const hash = crypto.createHash('md5').update(content).digest('hex')
363
+
364
+ files.push({
365
+ name: normalizedPath,
366
+ size: stats.size,
367
+ link: fullPath,
368
+ md5_hash: hash,
369
+ content_type: 'application/octet-stream',
370
+ created_at: stats.birthtime.toISOString(),
371
+ updated_at: stats.mtime.toISOString()
372
+ })
373
+ } catch (error) {
374
+ console.warn(\`Storage list warning: unable to process file \${normalizedPath}: \${error.message}\`)
375
+ }
376
+ }
377
+ }
378
+ } catch (error) {
379
+ console.warn(\`Storage list warning: unable to access \${itemRelativePath}: \${error.message}\`)
380
+ }
381
+ }
382
+ } catch (error) {
383
+ throw new Error(\`Storage list failed: unable to read directory \${dir}: \${error.message}\`)
384
+ }
385
+ }
386
+
387
+ try {
388
+ walkDir(storageDir)
389
+ return files
390
+ } catch (error) {
391
+ throw new Error(\`Storage list failed: \${error.message}\`)
392
+ }
393
+ },
394
+
395
+ async download(filename) {
396
+ return new Promise((resolve, reject) => {
397
+ const fs = require('fs')
398
+ const path = require('path')
399
+
400
+ if (typeof filename !== 'string') {
401
+ return reject(new Error('Storage download failed: filename must be a string'))
402
+ }
403
+
404
+ if (!filename.trim()) {
405
+ return reject(new Error('Storage download failed: filename cannot be empty'))
406
+ }
407
+
408
+ const filePath = path.join('${process.cwd()}', 'storage', filename)
409
+
410
+ if (!fs.existsSync(filePath)) {
411
+ return reject(new Error(\`Storage download failed: file not found - \${filename}\`))
412
+ }
413
+
414
+ try {
415
+ const stats = fs.statSync(filePath)
416
+ if (!stats.isFile()) {
417
+ return reject(new Error(\`Storage download failed: \${filename} is not a file\`))
418
+ }
419
+
420
+ const readStream = fs.createReadStream(filePath)
421
+
422
+ readStream.on('error', (error) => {
423
+ reject(new Error(\`Storage download failed: unable to read file - \${error.message}\`))
424
+ })
425
+
426
+ resolve(readStream)
427
+ } catch (error) {
428
+ reject(new Error(\`Storage download failed: \${error.message}\`))
429
+ }
430
+ })
431
+ },
432
+
433
+ async delete(filename) {
434
+ return new Promise((resolve, reject) => {
435
+ const fs = require('fs')
436
+ const path = require('path')
437
+
438
+ if (typeof filename !== 'string') {
439
+ return reject(new Error('Storage delete failed: filename must be a string'))
440
+ }
441
+
442
+ if (!filename.trim()) {
443
+ return reject(new Error('Storage delete failed: filename cannot be empty'))
444
+ }
445
+
446
+ const filePath = path.join('${process.cwd()}', 'storage', filename)
447
+
448
+ if (!fs.existsSync(filePath)) {
449
+ return reject(new Error(\`Storage delete failed: file not found - \${filename}\`))
450
+ }
451
+
452
+ try {
453
+ const stats = fs.statSync(filePath)
454
+ if (!stats.isFile()) {
455
+ return reject(new Error(\`Storage delete failed: \${filename} is not a file\`))
456
+ }
457
+
458
+ fs.unlinkSync(filePath)
459
+
460
+ let dir = path.dirname(filePath)
461
+ const storageDir = path.join('${process.cwd()}', 'storage')
462
+
463
+ while (dir !== storageDir && dir !== path.dirname(dir)) {
464
+ try {
465
+ const items = fs.readdirSync(dir)
466
+ if (items.length === 0) {
467
+ fs.rmdirSync(dir)
468
+ dir = path.dirname(dir)
469
+ } else {
470
+ break
471
+ }
472
+ } catch (error) {
473
+ console.warn(\`Storage delete warning: unable to clean up directory \${dir}: \${error.message}\`)
474
+ break
475
+ }
476
+ }
477
+
478
+ resolve(undefined)
479
+ } catch (error) {
480
+ reject(new Error(\`Storage delete failed: \${error.message}\`))
481
+ }
482
+ })
483
+ },
484
+
485
+ async createSignedUrl(filename, options = {}) {
486
+ const fs = require('fs')
487
+ const path = require('path')
488
+ const url = require('url')
489
+
490
+ if (typeof filename !== 'string' || !filename.trim()) {
491
+ throw new Error('Storage createSignedUrl failed: filename must be a non-empty string')
492
+ }
493
+
494
+ const expiresInSeconds = options.expiresInSeconds ?? 3600
495
+ if (!Number.isInteger(expiresInSeconds) || expiresInSeconds < 1 || expiresInSeconds > 604800) {
496
+ throw new Error('Storage createSignedUrl failed: expiresInSeconds must be an integer between 1 and 604800')
497
+ }
498
+
499
+ const filePath = path.join('${process.cwd()}', 'storage', filename)
500
+
501
+ if (!fs.existsSync(filePath)) {
502
+ throw new Error(\`Storage createSignedUrl failed: file not found - \${filename}\`)
503
+ }
504
+
505
+ // Local runtime has no object store to sign against, so return a
506
+ // file:// URL to the file on disk. Mirrors the cloud { url, path,
507
+ // expiresAt } contract so process code needs no local-vs-cloud guard.
508
+ console.warn('Storage createSignedUrl: no object store in local runtime; returning a file:// URL to the local file (mock).')
509
+
510
+ return {
511
+ url: url.pathToFileURL(filePath).href,
512
+ path: filename,
513
+ expiresAt: new Date(Date.now() + expiresInSeconds * 1000).toISOString()
514
+ }
515
+ }
516
+ },
517
+ schedule: {
518
+ // Scheduling is cloud-only; every method is a logged no-op during local \`fcode run\`.
519
+ create: async () => { console.warn('[fcode] schedule.create only runs in the cloud; no-op during local run.'); return null },
520
+ list: async () => { console.warn('[fcode] schedule.list only runs in the cloud; no-op during local run.'); return [] },
521
+ get: async () => { console.warn('[fcode] schedule.get only runs in the cloud; no-op during local run.'); return null },
522
+ update: async () => { console.warn('[fcode] schedule.update only runs in the cloud; no-op during local run.'); return null },
523
+ delete: async () => { console.warn('[fcode] schedule.delete only runs in the cloud; no-op during local run.') },
524
+ deleteForProcess: async () => { console.warn('[fcode] schedule.deleteForProcess only runs in the cloud; no-op during local run.'); return 0 },
525
+ pause: async () => { console.warn('[fcode] schedule.pause only runs in the cloud; no-op during local run.') },
526
+ resume: async () => { console.warn('[fcode] schedule.resume only runs in the cloud; no-op during local run.') }
527
+ },
528
+ variables: (() => {
529
+ const fs = require('fs');
530
+ const localEnvPath = require('path').join('${process.cwd()}', 'variables.local.env');
531
+ const baseVars = ${JSON.stringify(metadata.variables, null, 2)};
532
+ const readLocal = () => { try { return fs.readFileSync(localEnvPath, 'utf8') } catch { return '' } };
533
+ const parseEnv = (text) => {
534
+ const map = {};
535
+ for (const raw of text.split('\\n')) {
536
+ const line = raw.trim();
537
+ if (!line || line.startsWith('#')) continue;
538
+ const eq = line.indexOf('=');
539
+ if (eq === -1) continue;
540
+ map[line.slice(0, eq).trim()] = line.slice(eq + 1);
541
+ }
542
+ return map;
543
+ };
544
+ // Merged view: team + local file loaded at start, overlaid with the current
545
+ // variables.local.env so same-run writes are reflected.
546
+ const merged = () => {
547
+ const base = {};
548
+ if (Array.isArray(baseVars)) { for (const v of baseVars) base[v.key] = v.value; }
549
+ else { Object.assign(base, baseVars); }
550
+ return { ...base, ...parseEnv(readLocal()) };
551
+ };
552
+ return {
553
+ list: async () => Object.entries(merged()).map(([key, value]) => ({ key, value })),
554
+ get: async (key) => merged()[key],
555
+ // Writes affect only variables.local.env (never the shared variables.env).
556
+ set: async (key, value) => {
557
+ const lines = readLocal().split('\\n');
558
+ const out = [];
559
+ let replaced = false;
560
+ for (const line of lines) {
561
+ const t = line.trim();
562
+ const eq = t.indexOf('=');
563
+ if (t && !t.startsWith('#') && eq !== -1 && t.slice(0, eq).trim() === key) {
564
+ out.push(key + '=' + String(value));
565
+ replaced = true;
566
+ } else {
567
+ out.push(line);
568
+ }
569
+ }
570
+ while (out.length && out[out.length - 1].trim() === '') out.pop();
571
+ if (!replaced) out.push(key + '=' + String(value));
572
+ fs.writeFileSync(localEnvPath, out.join('\\n') + '\\n');
573
+ console.log('[fcode] variables.set wrote ' + key + ' to variables.local.env (local run).');
574
+ },
575
+ delete: async (key) => {
576
+ const text = readLocal();
577
+ if (!text) return;
578
+ const out = [];
579
+ for (const line of text.split('\\n')) {
580
+ const t = line.trim();
581
+ const eq = t.indexOf('=');
582
+ if (t && !t.startsWith('#') && eq !== -1 && t.slice(0, eq).trim() === key) continue;
583
+ out.push(line);
584
+ }
585
+ while (out.length && out[out.length - 1].trim() === '') out.pop();
586
+ fs.writeFileSync(localEnvPath, out.length ? out.join('\\n') + '\\n' : '');
587
+ console.log('[fcode] variables.delete removed ' + key + ' from variables.local.env (local run).');
588
+ }
589
+ };
590
+ })()
591
+ };
592
+ ${Object.entries(this.getVariablesObject())
593
+ .map(([key, value]) => `process.env['${key}'] = process.env['${key}'] ?? ${JSON.stringify(value)}`)
594
+ .join('\n')}
595
+
596
+ require("module").Module._initPaths();
597
+ ${!isLegacy && this._getNewBlock()}
598
+
599
+ main().then((r) => {
600
+ if (r !== null && r !== undefined) {
601
+ ${this._options.jsonLogs
602
+ ? `_console.log(JSON.stringify({timestamp:new Date().toISOString(),level:"INFO",message:"Return",data:r}));`
603
+ : `console.log('Return: ', r);`}
604
+ try { require('fs').writeFileSync(${JSON.stringify(this.returnValueFilePath)}, JSON.stringify(r)); } catch(e) {}
605
+ }
606
+ }).catch((e) => {
607
+ console.error(e);
608
+ try { require('fs').writeFileSync(${JSON.stringify(this.errorValueFilePath)}, JSON.stringify({ message: e?.message ?? String(e) })); } catch(_) {}
609
+ process.exit(1);
610
+ })
611
+ `);
612
+ return {
613
+ FCODE_EXECUTION_FILE: execFilePath,
614
+ FCODE_TMP_PATH: tempDir,
615
+ };
616
+ }
617
+ }
618
+ exports.default = JavaScriptExecutionTask;
@@ -0,0 +1,2 @@
1
+ declare const _default: "";
2
+ export default _default;
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = ``;
@@ -0,0 +1,2 @@
1
+ declare const _default: "\n";
2
+ export default _default;
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = `
4
+ `;
@@ -0,0 +1,11 @@
1
+ import ExecutionTask from './execution-task';
2
+ declare class PythonExecutionTask extends ExecutionTask {
3
+ run(): Promise<unknown>;
4
+ _getJsonLogsSetup(): string;
5
+ _getReturnBlock(result: string): string;
6
+ _getMainBlock(): string;
7
+ _createExecutionFiles(tempDir: string): Promise<{
8
+ [name: string]: string;
9
+ }>;
10
+ }
11
+ export default PythonExecutionTask;