@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,3 @@
1
+ import * as http from 'node:http';
2
+ export declare function startServer(port: number, host: string, handler: http.RequestListener): Promise<http.Server>;
3
+ export declare function stopServer(server: http.Server): Promise<void>;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.startServer = startServer;
4
+ exports.stopServer = stopServer;
5
+ const http = require("node:http");
6
+ async function startServer(port, host, handler) {
7
+ const server = http.createServer(handler);
8
+ await new Promise((resolve) => {
9
+ server.listen(port, host, () => resolve());
10
+ });
11
+ return server;
12
+ }
13
+ async function stopServer(server) {
14
+ await new Promise((resolve, reject) => {
15
+ server.close((err) => (err ? reject(err) : resolve()));
16
+ });
17
+ }
@@ -0,0 +1,9 @@
1
+ import type { AuthInfo } from '../core/types';
2
+ /**
3
+ * OAuth 2.0 Authorization Code flow with PKCE.
4
+ * Starts a local HTTP server to receive the redirect after the user logs in via browser.
5
+ * Requires the IdP (Keycloak) to have the CLI client configured with:
6
+ * - Access type: public
7
+ * - Valid redirect URI: http://127.0.0.1:6363/callback
8
+ */
9
+ export declare function loginViaBrowser(url: string, authUrl: string, clientId?: string): Promise<AuthInfo>;
@@ -0,0 +1,164 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loginViaBrowser = loginViaBrowser;
4
+ const openidClient = require("openid-client");
5
+ const open = require('open');
6
+ const { Issuer, generators } = openidClient;
7
+ const global_1 = require("../config/global");
8
+ const cli_1 = require("../utils/cli");
9
+ const auth_service_1 = require("./auth-service");
10
+ const http_server_1 = require("./http-server");
11
+ const OAUTH_CALLBACK_PORT = 6363;
12
+ const REDIRECT_URI = `http://127.0.0.1:${OAUTH_CALLBACK_PORT}/callback`;
13
+ const OAUTH_SCOPE = 'openid profile email offline_access';
14
+ const LOGIN_COMPLETED_HTML = `<!DOCTYPE html>
15
+ <html lang="en">
16
+ <head>
17
+ <meta charset="utf-8" />
18
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
19
+ <title>Login completed - Factorial Code</title>
20
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
21
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
22
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" />
23
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css" integrity="sha512-MV7K8+y+gLIBoVD59lQIYicR65iaqukzvf/nwasF0nqhPay5w/9lJmVM2hMDcnK1OnMGCdVK+iQrJ7lzPJQd1w==" crossorigin="anonymous" referrerpolicy="no-referrer" />
24
+ <style>
25
+ /* f0 design system tokens (light mode) */
26
+ :root {
27
+ --f1-foreground: hsl(218 48% 10%);
28
+ --f1-foreground-secondary: hsl(217 96% 11% / 0.61);
29
+ --f1-background: hsl(0 0% 100%);
30
+ --f1-border: hsl(213 87% 15% / 0.20);
31
+ --f1-positive: hsl(160 84% 39%);
32
+ --shadow: 218 48% 10%;
33
+ }
34
+ * { box-sizing: border-box; }
35
+ body {
36
+ margin: 0;
37
+ min-height: 100vh;
38
+ font-family: 'Inter', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
39
+ font-size: 0.875rem;
40
+ letter-spacing: -0.005em;
41
+ line-height: 1.25rem;
42
+ -webkit-font-smoothing: antialiased;
43
+ -moz-osx-font-smoothing: grayscale;
44
+ background: hsl(210 20% 98%);
45
+ display: flex;
46
+ flex-direction: column;
47
+ align-items: center;
48
+ justify-content: center;
49
+ padding: 1.5rem;
50
+ color: var(--f1-foreground);
51
+ }
52
+ .card {
53
+ background: var(--f1-background);
54
+ border-radius: 1rem;
55
+ padding: 2rem;
56
+ max-width: 24rem;
57
+ width: 100%;
58
+ text-align: center;
59
+ box-shadow: 0 2px 20px 0 hsl(var(--shadow) / 0.08);
60
+ border: 1px solid var(--f1-border);
61
+ }
62
+ .logo { width: 140px; height: auto; margin-bottom: 1.5rem; }
63
+ .icon {
64
+ width: 3rem;
65
+ height: 3rem;
66
+ margin: 0 auto 1rem;
67
+ border-radius: 50%;
68
+ background: hsl(160 84% 39% / 0.1);
69
+ color: var(--f1-positive);
70
+ display: flex;
71
+ align-items: center;
72
+ justify-content: center;
73
+ font-size: 1.25rem;
74
+ }
75
+ h1 { font-size: 1.125rem; font-weight: 600; margin: 0 0 0.5rem; color: var(--f1-foreground); }
76
+ p { margin: 0; font-size: 0.875rem; color: var(--f1-foreground-secondary); line-height: 1.5; }
77
+ .hint { margin-top: 1rem; font-size: 0.75rem; color: var(--f1-foreground-secondary); }
78
+ </style>
79
+ </head>
80
+ <body>
81
+ <div class="card">
82
+ <img src="https://code.factorialhr.com/images/factorial-code-logo-red.svg" alt="Factorial Code" class="logo" />
83
+ <div class="icon"><i class="fa-solid fa-circle-check"></i></div>
84
+ <h1>You’re signed in</h1>
85
+ <p>Login completed successfully. You can close this window and return to the terminal.</p>
86
+ </div>
87
+ </body>
88
+ </html>`;
89
+ /**
90
+ * OAuth 2.0 Authorization Code flow with PKCE.
91
+ * Starts a local HTTP server to receive the redirect after the user logs in via browser.
92
+ * Requires the IdP (Keycloak) to have the CLI client configured with:
93
+ * - Access type: public
94
+ * - Valid redirect URI: http://127.0.0.1:6363/callback
95
+ */
96
+ async function loginViaBrowser(url, authUrl, clientId) {
97
+ const normalizedAuthUrl = authUrl.endsWith('/') ? authUrl.slice(0, -1) : authUrl;
98
+ const resolvedClientId = clientId || process.env.FCODE_CLIENT_ID || 'cli';
99
+ const issuer = await Issuer.discover(normalizedAuthUrl);
100
+ const client = new issuer.Client({
101
+ client_id: resolvedClientId,
102
+ redirect_uris: [REDIRECT_URI],
103
+ token_endpoint_auth_method: 'none',
104
+ });
105
+ const codeVerifier = generators.codeVerifier();
106
+ const codeChallenge = generators.codeChallenge(codeVerifier);
107
+ const state = generators.state();
108
+ const authorizationUrl = client.authorizationUrl({
109
+ scope: OAUTH_SCOPE,
110
+ code_challenge: codeChallenge,
111
+ code_challenge_method: 'S256',
112
+ state,
113
+ });
114
+ let callbackUrl;
115
+ const server = await (0, http_server_1.startServer)(OAUTH_CALLBACK_PORT, '127.0.0.1', (req, res) => {
116
+ if (!req.url) {
117
+ res.statusCode = 400;
118
+ res.end();
119
+ return;
120
+ }
121
+ if (req.url.startsWith('/callback') || req.url.startsWith('/?')) {
122
+ callbackUrl = `http://127.0.0.1:${OAUTH_CALLBACK_PORT}${req.url}`;
123
+ res.statusCode = 200;
124
+ res.setHeader('Content-Type', 'text/html; charset=utf-8');
125
+ res.end(LOGIN_COMPLETED_HTML);
126
+ }
127
+ else {
128
+ res.statusCode = 404;
129
+ res.end('Not found');
130
+ }
131
+ });
132
+ cli_1.default.log('🌐 Opening browser for login...');
133
+ await open(authorizationUrl);
134
+ while (callbackUrl === undefined) {
135
+ await new Promise((r) => setTimeout(r, 200));
136
+ }
137
+ const callbackUrlObj = new URL(callbackUrl);
138
+ const callbackParams = {};
139
+ callbackUrlObj.searchParams.forEach((value, key) => {
140
+ callbackParams[key] = value;
141
+ });
142
+ try {
143
+ const tokenSet = await client.callback(REDIRECT_URI, callbackParams, { state, code_verifier: codeVerifier });
144
+ const token = {
145
+ access_token: tokenSet.access_token ?? '',
146
+ refresh_token: tokenSet.refresh_token ?? '',
147
+ };
148
+ const userInfo = await auth_service_1.default.getUserInfo(normalizedAuthUrl, token);
149
+ const authInfo = {
150
+ authUrl: normalizedAuthUrl,
151
+ token,
152
+ userInfo,
153
+ };
154
+ await new global_1.default().setAuthInfo(url, authInfo);
155
+ return authInfo;
156
+ }
157
+ catch (error) {
158
+ cli_1.default.error('Error logging in via browser: ' + error);
159
+ throw error;
160
+ }
161
+ finally {
162
+ await (0, http_server_1.stopServer)(server);
163
+ }
164
+ }
@@ -0,0 +1,2 @@
1
+ import type { Process } from '../core/types';
2
+ export declare const generateParametersSample: (process: Process) => any;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateParametersSample = void 0;
4
+ const processHasParametersSchema = (process) => {
5
+ const processParameters = process.script.parametersSchema;
6
+ return Boolean(processParameters && Object.keys(processParameters).length > 0);
7
+ };
8
+ const jsonSchemaPropertyToSampleValue = (property) => {
9
+ if (['password', 'string'].includes(property.type)) {
10
+ return '';
11
+ }
12
+ if (['integer', 'number'].includes(property.type)) {
13
+ return 0;
14
+ }
15
+ if (property.type === 'boolean') {
16
+ return true;
17
+ }
18
+ if (property.type === 'array') {
19
+ return [jsonSchemaPropertyToSampleValue(property.items)];
20
+ }
21
+ if (property.type === 'object') {
22
+ return {
23
+ ...jsonSchemaPropertiesToSampleObject(property.properties),
24
+ };
25
+ }
26
+ return null;
27
+ };
28
+ const jsonSchemaPropertiesToSampleObject = (properties) => {
29
+ if (!properties) {
30
+ return {};
31
+ }
32
+ const entries = Object.entries(properties).map(([key, property]) => [key, jsonSchemaPropertyToSampleValue(property)]);
33
+ return Object.fromEntries(entries);
34
+ };
35
+ const generateParametersSample = (process) => {
36
+ if (!processHasParametersSchema(process)) {
37
+ return {};
38
+ }
39
+ return jsonSchemaPropertiesToSampleObject(process.script.parametersSchema.properties);
40
+ };
41
+ exports.generateParametersSample = generateParametersSample;
@@ -0,0 +1,22 @@
1
+ import { Process, Variable } from '../core/types';
2
+ import type { WebhookRequest } from '../core/types';
3
+ export type RunProcessOptions = {
4
+ slug: string;
5
+ parameters?: Record<string, unknown>;
6
+ version?: string;
7
+ logLevel?: string;
8
+ request?: WebhookRequest;
9
+ jsonLogs?: boolean;
10
+ variablesOverride?: Variable[];
11
+ extraVariablesFile?: string;
12
+ suppressElapsedLog?: boolean;
13
+ };
14
+ export type RunHookOptions = {
15
+ logLevel?: string;
16
+ jsonLogs?: boolean;
17
+ hookFunction?: string;
18
+ };
19
+ export declare function loadVariablesFromFile(filePath: string): Variable[];
20
+ export declare function mergeVariables(base: Variable[], ...overrides: Variable[][]): Variable[];
21
+ export declare function runProcess(options: RunProcessOptions): Promise<unknown>;
22
+ export declare function runHook(hookFilePath: string, fcodeProcess: Process, variables: Variable[], options?: RunHookOptions): Promise<void>;
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadVariablesFromFile = loadVariablesFromFile;
4
+ exports.mergeVariables = mergeVariables;
5
+ exports.runProcess = runProcess;
6
+ exports.runHook = runHook;
7
+ const dotenv_1 = require("dotenv");
8
+ const fs = require("node:fs");
9
+ const javascript_execution_task_1 = require("../core/executors/javascript-execution-task");
10
+ const python_execution_task_1 = require("../core/executors/python-execution-task");
11
+ const process_1 = require("../repositories/process");
12
+ const variable_1 = require("../repositories/variable");
13
+ const types_1 = require("../core/types");
14
+ const errors_1 = require("../core/errors");
15
+ const env_utils_1 = require("../utils/env-utils");
16
+ function loadVariablesFromFile(filePath) {
17
+ try {
18
+ const content = fs.readFileSync(filePath, 'utf8');
19
+ const parsed = (0, dotenv_1.parse)(content);
20
+ return Object.entries(parsed).map(([key, value]) => new types_1.Variable(undefined, key, (0, env_utils_1.unescapeEnvValue)(value), false));
21
+ }
22
+ catch {
23
+ return [];
24
+ }
25
+ }
26
+ function mergeVariables(base, ...overrides) {
27
+ const map = new Map();
28
+ for (const v of base)
29
+ map.set(v.key, v);
30
+ for (const override of overrides) {
31
+ for (const v of override)
32
+ map.set(v.key, v);
33
+ }
34
+ return [...map.values()];
35
+ }
36
+ async function runProcess(options) {
37
+ const { slug, version, logLevel = 'DEBUG', request, jsonLogs = false, suppressElapsedLog = false } = options;
38
+ const processRepository = new process_1.default();
39
+ const variableRepository = new variable_1.default();
40
+ const fcodeProcess = await processRepository.find(slug, version);
41
+ const parameters = options.parameters ?? (await processRepository.findParameters(slug));
42
+ let variables;
43
+ if (options.variablesOverride) {
44
+ variables = options.variablesOverride;
45
+ }
46
+ else {
47
+ variables = await variableRepository.findAllForExecution();
48
+ if (options.extraVariablesFile) {
49
+ variables = mergeVariables(variables, loadVariablesFromFile(options.extraVariablesFile));
50
+ }
51
+ }
52
+ const ExecutionTask = fcodeProcess.script.programmingLanguage === 'PYTHON' ? python_execution_task_1.default : javascript_execution_task_1.default;
53
+ const executor = new ExecutionTask(fcodeProcess.script.programmingLanguage, fcodeProcess, { version, parameters, variables, logLevel, request, jsonLogs });
54
+ const start = Date.now();
55
+ try {
56
+ await executor.prepare();
57
+ await executor.run();
58
+ return executor.readReturnValue();
59
+ }
60
+ catch (runError) {
61
+ const errorValue = executor.readErrorValue();
62
+ throw new errors_1.ErrorExecutingProcess(errorValue?.message ?? (runError instanceof Error ? runError.message : String(runError)));
63
+ }
64
+ finally {
65
+ executor.cleanup();
66
+ if (!suppressElapsedLog) {
67
+ const elapsed = Date.now() - start;
68
+ if (jsonLogs) {
69
+ process.stdout.write(JSON.stringify({ timestamp: new Date().toISOString(), level: 'INFO', message: `Elapsed time: ${elapsed}ms` }) + '\n');
70
+ }
71
+ else {
72
+ console.log(`Elapsed time: ${elapsed}ms`);
73
+ }
74
+ }
75
+ }
76
+ }
77
+ async function runHook(hookFilePath, fcodeProcess, variables, options = {}) {
78
+ const { logLevel = 'ERROR', jsonLogs = false, hookFunction } = options;
79
+ const ExecutionTask = fcodeProcess.script.programmingLanguage === 'PYTHON' ? python_execution_task_1.default : javascript_execution_task_1.default;
80
+ const executor = new ExecutionTask(fcodeProcess.script.programmingLanguage, fcodeProcess, {
81
+ version: undefined,
82
+ parameters: {},
83
+ variables,
84
+ logLevel,
85
+ jsonLogs,
86
+ hookFilePath,
87
+ hookFunction,
88
+ silent: true,
89
+ });
90
+ try {
91
+ await executor.prepare();
92
+ await executor.run();
93
+ }
94
+ finally {
95
+ executor.cleanup();
96
+ }
97
+ }
@@ -0,0 +1,8 @@
1
+ import { OnConflictResolution, type Resource } from '../core/types';
2
+ declare const _default: {
3
+ localResourceHasBeenModified(remoteResource?: Resource, localResource?: Resource): Promise<boolean>;
4
+ remoteResourceHasBeenModified(remoteResource?: Resource, localResource?: Resource): Promise<boolean>;
5
+ sameContent(resourceA: Resource, resourceB: Resource): boolean;
6
+ categorizeResources(localResources: Array<Resource>, remoteResources: Array<Resource>, onConflictResolution: OnConflictResolution, existsMetadata: (slug: string) => Promise<boolean>): Promise<any>;
7
+ };
8
+ export default _default;
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const workspace_1 = require("../config/workspace");
4
+ const types_1 = require("../core/types");
5
+ const resource_merger_1 = require("../core/resource-merger");
6
+ exports.default = {
7
+ async localResourceHasBeenModified(remoteResource, localResource) {
8
+ if (!localResource) {
9
+ return false;
10
+ }
11
+ if (remoteResource && this.sameContent(remoteResource, localResource)) {
12
+ return false;
13
+ }
14
+ if (localResource.contentHash === (await new workspace_1.default().getStoredHash(localResource))) {
15
+ return false;
16
+ }
17
+ return true;
18
+ },
19
+ async remoteResourceHasBeenModified(remoteResource, localResource) {
20
+ if (localResource && remoteResource && this.sameContent(remoteResource, localResource)) {
21
+ return false;
22
+ }
23
+ if (remoteResource && remoteResource.contentHash === (await new workspace_1.default().getStoredHash(remoteResource))) {
24
+ return false;
25
+ }
26
+ return true;
27
+ },
28
+ sameContent(resourceA, resourceB) {
29
+ return resourceA.contentHash === resourceB.contentHash;
30
+ },
31
+ async categorizeResources(localResources, remoteResources, onConflictResolution, existsMetadata) {
32
+ let newRemoteResources = [];
33
+ let newLocalResources = [];
34
+ let upToDateResources = [];
35
+ let conflictResources = [];
36
+ let modifiedResources = [];
37
+ let outOfDateResources = [];
38
+ let remoteRemovedResources = [];
39
+ let localRemovedResources = [];
40
+ const allResourceSlugs = [...new Set([...localResources, ...remoteResources].map((resource) => resource.slug))];
41
+ for (const resourceSlug of allResourceSlugs) {
42
+ const remoteResource = remoteResources.find((resource) => resource.slug === resourceSlug);
43
+ const localResource = localResources.find((resource) => resource.slug === resourceSlug);
44
+ switch (await (0, resource_merger_1.mapResourceStatus)(remoteResource, localResource, await existsMetadata(resourceSlug))) {
45
+ case types_1.ResourceStatus.REMOTE_NEW:
46
+ newRemoteResources.push(remoteResource);
47
+ break;
48
+ case types_1.ResourceStatus.LOCAL_NEW:
49
+ newLocalResources.push(localResource);
50
+ break;
51
+ case types_1.ResourceStatus.UP_TO_DATE:
52
+ upToDateResources.push(localResource);
53
+ break;
54
+ case types_1.ResourceStatus.CONFLICT:
55
+ conflictResources.push(onConflictResolution === types_1.OnConflictResolution.KEEP_REMOTE ? remoteResource : localResource);
56
+ break;
57
+ case types_1.ResourceStatus.MODIFIED:
58
+ modifiedResources.push(localResource);
59
+ break;
60
+ case types_1.ResourceStatus.OUT_OF_DATE:
61
+ outOfDateResources.push(remoteResource);
62
+ break;
63
+ case types_1.ResourceStatus.REMOTE_REMOVED:
64
+ remoteRemovedResources.push(localResource);
65
+ break;
66
+ case types_1.ResourceStatus.LOCAL_REMOVED:
67
+ localRemovedResources.push(remoteResource);
68
+ break;
69
+ }
70
+ }
71
+ return {
72
+ newRemoteResources,
73
+ newLocalResources,
74
+ upToDateResources,
75
+ conflictResources,
76
+ modifiedResources,
77
+ outOfDateResources,
78
+ remoteRemovedResources,
79
+ localRemovedResources,
80
+ };
81
+ },
82
+ };
@@ -0,0 +1,17 @@
1
+ import { Process } from '../core/types';
2
+ export type TestOptions = {
3
+ logLevel?: string;
4
+ jsonLogs?: boolean;
5
+ };
6
+ export type TestResult = {
7
+ name: string;
8
+ passed: boolean;
9
+ error?: string;
10
+ durationMs: number;
11
+ };
12
+ export type TestSuiteResult = {
13
+ processSlug: string;
14
+ results: TestResult[];
15
+ };
16
+ export declare function runProcessTests(fcodeProcess: Process, options?: TestOptions): Promise<TestSuiteResult>;
17
+ export declare function printTestResults(suiteResults: TestSuiteResult[]): void;