apify-cli 0.19.3-beta.5 → 1.0.0-beta.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 (231) hide show
  1. package/README.md +73 -52
  2. package/bin/dev.cmd +3 -0
  3. package/bin/dev.js +16 -0
  4. package/bin/run.js +16 -0
  5. package/dist/.tsbuildinfo +1 -0
  6. package/dist/commands/actor/get-input.d.ts +6 -0
  7. package/dist/commands/actor/get-input.d.ts.map +1 -0
  8. package/dist/commands/actor/get-input.js +14 -0
  9. package/dist/commands/actor/get-input.js.map +1 -0
  10. package/dist/commands/actor/get-value.d.ts +9 -0
  11. package/dist/commands/actor/get-value.d.ts.map +1 -0
  12. package/dist/commands/actor/get-value.js +27 -0
  13. package/dist/commands/actor/get-value.js.map +1 -0
  14. package/dist/commands/actor/index.d.ts +6 -0
  15. package/dist/commands/actor/index.d.ts.map +1 -0
  16. package/dist/commands/actor/index.js +13 -0
  17. package/dist/commands/actor/index.js.map +1 -0
  18. package/dist/commands/actor/push-data.d.ts +11 -0
  19. package/dist/commands/actor/push-data.d.ts.map +1 -0
  20. package/dist/commands/actor/push-data.js +56 -0
  21. package/dist/commands/actor/push-data.js.map +1 -0
  22. package/dist/commands/actor/set-value.d.ts +15 -0
  23. package/dist/commands/actor/set-value.d.ts.map +1 -0
  24. package/dist/commands/actor/set-value.js +76 -0
  25. package/dist/commands/actor/set-value.js.map +1 -0
  26. package/dist/commands/call.d.ts +15 -0
  27. package/dist/commands/call.d.ts.map +1 -0
  28. package/dist/commands/call.js +142 -0
  29. package/dist/commands/call.js.map +1 -0
  30. package/dist/commands/check-version.d.ts +11 -0
  31. package/dist/commands/check-version.d.ts.map +1 -0
  32. package/dist/commands/check-version.js +39 -0
  33. package/dist/commands/check-version.js.map +1 -0
  34. package/dist/commands/create.d.ts +14 -0
  35. package/dist/commands/create.d.ts.map +1 -0
  36. package/dist/commands/create.js +181 -0
  37. package/dist/commands/create.js.map +1 -0
  38. package/dist/commands/edit-input-schema.d.ts +11 -0
  39. package/dist/commands/edit-input-schema.d.ts.map +1 -0
  40. package/{src → dist}/commands/edit-input-schema.js +81 -85
  41. package/dist/commands/edit-input-schema.js.map +1 -0
  42. package/dist/commands/info.d.ts +6 -0
  43. package/dist/commands/info.d.ts.map +1 -0
  44. package/dist/commands/info.js +26 -0
  45. package/dist/commands/info.js.map +1 -0
  46. package/dist/commands/init-wrap-scrapy.d.ts +10 -0
  47. package/dist/commands/init-wrap-scrapy.d.ts.map +1 -0
  48. package/dist/commands/init-wrap-scrapy.js +41 -0
  49. package/dist/commands/init-wrap-scrapy.js.map +1 -0
  50. package/dist/commands/init.d.ts +12 -0
  51. package/dist/commands/init.d.ts.map +1 -0
  52. package/dist/commands/init.js +88 -0
  53. package/dist/commands/init.js.map +1 -0
  54. package/dist/commands/login-new.d.ts +10 -0
  55. package/dist/commands/login-new.d.ts.map +1 -0
  56. package/{src → dist}/commands/login-new.js +79 -82
  57. package/dist/commands/login-new.js.map +1 -0
  58. package/dist/commands/login.d.ts +9 -0
  59. package/dist/commands/login.d.ts.map +1 -0
  60. package/dist/commands/login.js +43 -0
  61. package/dist/commands/login.js.map +1 -0
  62. package/dist/commands/logout.d.ts +6 -0
  63. package/dist/commands/logout.d.ts.map +1 -0
  64. package/dist/commands/logout.js +20 -0
  65. package/dist/commands/logout.js.map +1 -0
  66. package/dist/commands/pull.d.ts +12 -0
  67. package/dist/commands/pull.d.ts.map +1 -0
  68. package/dist/commands/pull.js +148 -0
  69. package/dist/commands/pull.js.map +1 -0
  70. package/dist/commands/push.d.ts +16 -0
  71. package/dist/commands/push.d.ts.map +1 -0
  72. package/dist/commands/push.js +242 -0
  73. package/dist/commands/push.js.map +1 -0
  74. package/dist/commands/run.d.ts +12 -0
  75. package/dist/commands/run.d.ts.map +1 -0
  76. package/{src → dist}/commands/run.js +96 -109
  77. package/dist/commands/run.js.map +1 -0
  78. package/dist/commands/secrets/add.d.ts +10 -0
  79. package/dist/commands/secrets/add.d.ts.map +1 -0
  80. package/dist/commands/secrets/add.js +31 -0
  81. package/dist/commands/secrets/add.js.map +1 -0
  82. package/dist/commands/secrets/index.d.ts +6 -0
  83. package/dist/commands/secrets/index.d.ts.map +1 -0
  84. package/dist/commands/secrets/index.js +24 -0
  85. package/dist/commands/secrets/index.js.map +1 -0
  86. package/dist/commands/secrets/rm.d.ts +9 -0
  87. package/dist/commands/secrets/rm.d.ts.map +1 -0
  88. package/dist/commands/secrets/rm.js +27 -0
  89. package/dist/commands/secrets/rm.js.map +1 -0
  90. package/dist/commands/vis.d.ts +9 -0
  91. package/dist/commands/vis.d.ts.map +1 -0
  92. package/dist/commands/vis.js +52 -0
  93. package/dist/commands/vis.js.map +1 -0
  94. package/dist/hooks/init.d.ts +7 -0
  95. package/dist/hooks/init.d.ts.map +1 -0
  96. package/dist/hooks/init.js +17 -0
  97. package/dist/hooks/init.js.map +1 -0
  98. package/dist/index.d.ts +2 -0
  99. package/dist/index.d.ts.map +1 -0
  100. package/dist/index.js +3 -0
  101. package/dist/index.js.map +1 -0
  102. package/dist/lib/actor.d.ts +27 -0
  103. package/dist/lib/actor.d.ts.map +1 -0
  104. package/{src → dist}/lib/actor.js +21 -44
  105. package/dist/lib/actor.js.map +1 -0
  106. package/dist/lib/apify-oclif-help.d.ts +15 -0
  107. package/dist/lib/apify-oclif-help.d.ts.map +1 -0
  108. package/dist/lib/apify-oclif-help.js +19 -0
  109. package/dist/lib/apify-oclif-help.js.map +1 -0
  110. package/dist/lib/apify_command.d.ts +22 -0
  111. package/dist/lib/apify_command.d.ts.map +1 -0
  112. package/dist/lib/apify_command.js +103 -0
  113. package/dist/lib/apify_command.js.map +1 -0
  114. package/dist/lib/community.d.ts +2 -0
  115. package/dist/lib/community.d.ts.map +1 -0
  116. package/dist/lib/community.js +4 -0
  117. package/dist/lib/community.js.map +1 -0
  118. package/dist/lib/consts.d.ts +45 -0
  119. package/dist/lib/consts.d.ts.map +1 -0
  120. package/dist/lib/consts.js +54 -0
  121. package/dist/lib/consts.js.map +1 -0
  122. package/dist/lib/create-utils.d.ts +8 -0
  123. package/dist/lib/create-utils.d.ts.map +1 -0
  124. package/{src → dist}/lib/create-utils.js +74 -113
  125. package/dist/lib/create-utils.js.map +1 -0
  126. package/dist/lib/exec.d.ts +4 -0
  127. package/dist/lib/exec.d.ts.map +1 -0
  128. package/{src → dist}/lib/exec.js +15 -16
  129. package/dist/lib/exec.js.map +1 -0
  130. package/dist/lib/files.d.ts +14 -0
  131. package/dist/lib/files.d.ts.map +1 -0
  132. package/dist/lib/files.js +58 -0
  133. package/dist/lib/files.js.map +1 -0
  134. package/dist/lib/input_schema.d.ts +26 -0
  135. package/dist/lib/input_schema.d.ts.map +1 -0
  136. package/{src → dist}/lib/input_schema.js +34 -55
  137. package/dist/lib/input_schema.js.map +1 -0
  138. package/dist/lib/local_state.d.ts +11 -0
  139. package/dist/lib/local_state.d.ts.map +1 -0
  140. package/dist/lib/local_state.js +27 -0
  141. package/dist/lib/local_state.js.map +1 -0
  142. package/dist/lib/outputs.d.ts +7 -0
  143. package/dist/lib/outputs.d.ts.map +1 -0
  144. package/{src → dist}/lib/outputs.js +8 -15
  145. package/dist/lib/outputs.js.map +1 -0
  146. package/dist/lib/project_analyzer.d.ts +4 -0
  147. package/dist/lib/project_analyzer.d.ts.map +1 -0
  148. package/{src → dist}/lib/project_analyzer.js +6 -11
  149. package/dist/lib/project_analyzer.js.map +1 -0
  150. package/dist/lib/projects/CrawleeAnalyzer.d.ts +4 -0
  151. package/dist/lib/projects/CrawleeAnalyzer.d.ts.map +1 -0
  152. package/{src → dist}/lib/projects/CrawleeAnalyzer.js +7 -24
  153. package/dist/lib/projects/CrawleeAnalyzer.js.map +1 -0
  154. package/dist/lib/projects/OldApifySDKAnalyzer.d.ts +4 -0
  155. package/dist/lib/projects/OldApifySDKAnalyzer.d.ts.map +1 -0
  156. package/{src → dist}/lib/projects/OldApifySDKAnalyzer.js +9 -32
  157. package/dist/lib/projects/OldApifySDKAnalyzer.js.map +1 -0
  158. package/dist/lib/projects/scrapy/ScrapyProjectAnalyzer.d.ts +17 -0
  159. package/dist/lib/projects/scrapy/ScrapyProjectAnalyzer.d.ts.map +1 -0
  160. package/{src/lib/scrapy-wrapper → dist/lib/projects/scrapy}/ScrapyProjectAnalyzer.js +33 -36
  161. package/dist/lib/projects/scrapy/ScrapyProjectAnalyzer.js.map +1 -0
  162. package/dist/lib/projects/scrapy/Spider.d.ts +14 -0
  163. package/dist/lib/projects/scrapy/Spider.d.ts.map +1 -0
  164. package/dist/lib/projects/scrapy/Spider.js +33 -0
  165. package/dist/lib/projects/scrapy/Spider.js.map +1 -0
  166. package/dist/lib/projects/scrapy/SpiderFileAnalyzer.d.ts +7 -0
  167. package/dist/lib/projects/scrapy/SpiderFileAnalyzer.d.ts.map +1 -0
  168. package/dist/lib/projects/scrapy/SpiderFileAnalyzer.js +25 -0
  169. package/dist/lib/projects/scrapy/SpiderFileAnalyzer.js.map +1 -0
  170. package/dist/lib/projects/scrapy/wrapScrapyProject.d.ts +4 -0
  171. package/dist/lib/projects/scrapy/wrapScrapyProject.d.ts.map +1 -0
  172. package/{src/lib/scrapy-wrapper/index.js → dist/lib/projects/scrapy/wrapScrapyProject.js} +43 -73
  173. package/dist/lib/projects/scrapy/wrapScrapyProject.js.map +1 -0
  174. package/dist/lib/projects/shared.d.ts +2 -0
  175. package/dist/lib/projects/shared.d.ts.map +1 -0
  176. package/dist/lib/projects/shared.js +13 -0
  177. package/dist/lib/projects/shared.js.map +1 -0
  178. package/dist/lib/secrets.d.ts +22 -0
  179. package/dist/lib/secrets.d.ts.map +1 -0
  180. package/{src → dist}/lib/secrets.js +32 -40
  181. package/dist/lib/secrets.js.map +1 -0
  182. package/dist/lib/telemetry.d.ts +21 -0
  183. package/dist/lib/telemetry.d.ts.map +1 -0
  184. package/dist/lib/telemetry.js +87 -0
  185. package/dist/lib/telemetry.js.map +1 -0
  186. package/dist/lib/types.d.ts +11 -0
  187. package/dist/lib/types.d.ts.map +1 -0
  188. package/dist/lib/types.js +2 -0
  189. package/dist/lib/types.js.map +1 -0
  190. package/dist/lib/utils.d.ts +106 -0
  191. package/dist/lib/utils.d.ts.map +1 -0
  192. package/{src → dist}/lib/utils.js +235 -347
  193. package/dist/lib/utils.js.map +1 -0
  194. package/dist/lib/version_check.d.ts +14 -0
  195. package/dist/lib/version_check.d.ts.map +1 -0
  196. package/{src → dist}/lib/version_check.js +25 -54
  197. package/dist/lib/version_check.js.map +1 -0
  198. package/oclif.manifest.json +722 -1
  199. package/package.json +137 -113
  200. package/index.js +0 -1
  201. package/src/bin/run +0 -16
  202. package/src/commands/actor/get-input.js +0 -12
  203. package/src/commands/actor/get-value.js +0 -23
  204. package/src/commands/actor/index.js +0 -13
  205. package/src/commands/actor/push-data.js +0 -44
  206. package/src/commands/actor/set-value.js +0 -63
  207. package/src/commands/call.js +0 -131
  208. package/src/commands/check-version.js +0 -28
  209. package/src/commands/create.js +0 -203
  210. package/src/commands/info.js +0 -24
  211. package/src/commands/init-wrap-scrapy.js +0 -34
  212. package/src/commands/init.js +0 -84
  213. package/src/commands/login.js +0 -40
  214. package/src/commands/logout.js +0 -18
  215. package/src/commands/pull.js +0 -154
  216. package/src/commands/push.js +0 -234
  217. package/src/commands/secrets/add.js +0 -28
  218. package/src/commands/secrets/index.js +0 -24
  219. package/src/commands/secrets/rm.js +0 -23
  220. package/src/commands/vis.js +0 -50
  221. package/src/hooks/init.js +0 -16
  222. package/src/lib/apify-oclif-help.js +0 -23
  223. package/src/lib/apify_command.js +0 -82
  224. package/src/lib/community.js +0 -3
  225. package/src/lib/consts.js +0 -69
  226. package/src/lib/files.js +0 -76
  227. package/src/lib/local_state.js +0 -39
  228. package/src/lib/scrapy-wrapper/Spider.js +0 -10
  229. package/src/lib/scrapy-wrapper/SpiderFileAnalyzer.js +0 -26
  230. package/src/lib/telemetry.js +0 -104
  231. /package/{src/bin → bin}/run.cmd +0 -0
@@ -1,241 +1,183 @@
1
- const {
2
- execSync,
3
- spawnSync,
4
- } = require('child_process');
5
- const fs = require('fs');
6
- const https = require('https');
7
- const path = require('path');
8
- const { finished } = require('stream');
9
- const { promisify } = require('util');
10
-
11
- const {
12
- ACT_JOB_TERMINAL_STATUSES,
13
- ACTOR_ENV_VARS,
14
- LOCAL_ACTOR_ENV_VARS,
15
- ACTOR_NAME,
16
- APIFY_ENV_VARS,
17
- KEY_VALUE_STORE_KEYS,
18
- LOCAL_STORAGE_SUBDIRS,
19
- SOURCE_FILE_FORMATS,
20
- } = require('@apify/consts');
21
- const AdmZip = require('adm-zip');
22
- const { ApifyClient } = require('apify-client');
23
- const archiver = require('archiver-promise');
24
- const axios = require('axios');
25
- const escapeStringRegexp = require('escape-string-regexp');
26
- const globby = require('globby');
27
- const inquirer = require('inquirer');
28
- const { getEncoding } = require('istextorbinary');
29
- const loadJson = require('load-json-file');
30
- const mime = require('mime');
31
- const semver = require('semver');
32
- const _ = require('underscore');
33
- const writeJson = require('write-json-file');
34
-
35
- const {
36
- GLOBAL_CONFIGS_FOLDER,
37
- AUTH_FILE_PATH,
38
- INPUT_FILE_REG_EXP,
39
- DEFAULT_LOCAL_STORAGE_DIR,
40
- LOCAL_CONFIG_PATH,
41
- DEPRECATED_LOCAL_CONFIG_NAME,
42
- ACTOR_SPECIFICATION_VERSION,
43
- APIFY_CLIENT_DEFAULT_HEADERS,
44
- SUPPORTED_NODEJS_VERSION,
45
- MINIMUM_SUPPORTED_PYTHON_VERSION,
46
- LANGUAGE,
47
- PROJECT_TYPES,
48
- } = require('./consts');
49
- const {
50
- ensureFolderExistsSync,
51
- rimrafPromised,
52
- deleteFile,
53
- } = require('./files');
54
- const {
55
- info,
56
- } = require('./outputs');
57
- const { ProjectAnalyzer } = require('./project_analyzer');
58
-
59
- /**
60
- * @param {string} url
61
- * @returns {Promise<unknown>}
62
- */
63
- const httpsGet = async (url) => {
1
+ import { spawnSync } from 'node:child_process';
2
+ import { createWriteStream, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, writeFileSync } from 'node:fs';
3
+ import { get } from 'node:https';
4
+ import { dirname, join } from 'node:path';
5
+ import process from 'node:process';
6
+ import { finished } from 'node:stream/promises';
7
+ import { ACTOR_ENV_VARS, ACTOR_JOB_TERMINAL_STATUSES, ACTOR_NAME, APIFY_ENV_VARS, KEY_VALUE_STORE_KEYS, LOCAL_ACTOR_ENV_VARS, LOCAL_STORAGE_SUBDIRS, SOURCE_FILE_FORMATS, } from '@apify/consts';
8
+ import AdmZip from 'adm-zip';
9
+ import _Ajv from 'ajv';
10
+ import { ApifyClient } from 'apify-client';
11
+ import archiver from 'archiver';
12
+ import { AxiosHeaders } from 'axios';
13
+ import escapeStringRegexp from 'escape-string-regexp';
14
+ import { globby } from 'globby';
15
+ import inquirer from 'inquirer';
16
+ import { getEncoding } from 'istextorbinary';
17
+ import { loadJsonFile, loadJsonFileSync } from 'load-json-file';
18
+ import { Mime } from 'mime';
19
+ import otherMimes from 'mime/types/other.js';
20
+ import standardMimes from 'mime/types/standard.js';
21
+ import { gte, minVersion, satisfies } from 'semver';
22
+ import _ from 'underscore';
23
+ import { writeJsonFile, writeJsonFileSync } from 'write-json-file';
24
+ import { ACTOR_SPECIFICATION_VERSION, APIFY_CLIENT_DEFAULT_HEADERS, AUTH_FILE_PATH, DEFAULT_LOCAL_STORAGE_DIR, DEPRECATED_LOCAL_CONFIG_NAME, GLOBAL_CONFIGS_FOLDER, INPUT_FILE_REG_EXP, LANGUAGE, LOCAL_CONFIG_PATH, MINIMUM_SUPPORTED_PYTHON_VERSION, PROJECT_TYPES, SUPPORTED_NODEJS_VERSION, } from './consts.js';
25
+ import { deleteFile, ensureFolderExistsSync, rimrafPromised } from './files.js';
26
+ import { info } from './outputs.js';
27
+ import { ProjectAnalyzer } from './project_analyzer.js';
28
+ // Export AJV properly: https://github.com/ajv-validator/ajv/issues/2132
29
+ // Welcome to the state of JavaScript/TypeScript and CJS/ESM interop.
30
+ export const Ajv = _Ajv;
31
+ export const httpsGet = async (url) => {
64
32
  return new Promise((resolve, reject) => {
65
- https.get(url, (response) => {
33
+ get(url, (response) => {
66
34
  // Handle redirects
67
35
  if (response.statusCode === 301 || response.statusCode === 302) {
68
36
  resolve(httpsGet(response.headers.location));
69
37
  // Destroy the response to close the HTTP connection, otherwise this hangs for a long time with Node 19+ (due to HTTP keep-alive).
70
38
  response.destroy();
71
- } else {
39
+ }
40
+ else {
72
41
  resolve(response);
73
42
  }
74
43
  }).on('error', reject);
75
44
  });
76
45
  };
77
-
78
46
  // Properties from apify.json file that will me migrated to actor specs in .actor/actor.json
79
47
  const MIGRATED_APIFY_JSON_PROPERTIES = ['name', 'version', 'buildTag'];
80
-
81
- const getLocalStorageDir = () => {
48
+ export const getLocalStorageDir = () => {
82
49
  const envVar = APIFY_ENV_VARS.LOCAL_STORAGE_DIR;
83
-
84
50
  return process.env[envVar] || process.env.CRAWLEE_STORAGE_DIR || DEFAULT_LOCAL_STORAGE_DIR;
85
51
  };
86
- const getLocalKeyValueStorePath = (storeId) => {
52
+ export const getLocalKeyValueStorePath = (storeId) => {
87
53
  const envVar = ACTOR_ENV_VARS.DEFAULT_KEY_VALUE_STORE_ID;
88
54
  const storeDir = storeId || process.env[envVar] || LOCAL_ACTOR_ENV_VARS[envVar];
89
-
90
- return path.join(getLocalStorageDir(), LOCAL_STORAGE_SUBDIRS.keyValueStores, storeDir);
55
+ return join(getLocalStorageDir(), LOCAL_STORAGE_SUBDIRS.keyValueStores, storeDir);
91
56
  };
92
- const getLocalDatasetPath = (storeId) => {
57
+ export const getLocalDatasetPath = (storeId) => {
93
58
  const envVar = ACTOR_ENV_VARS.DEFAULT_DATASET_ID;
94
59
  const storeDir = storeId || process.env[envVar] || LOCAL_ACTOR_ENV_VARS[envVar];
95
-
96
- return path.join(getLocalStorageDir(), LOCAL_STORAGE_SUBDIRS.datasets, storeDir);
60
+ return join(getLocalStorageDir(), LOCAL_STORAGE_SUBDIRS.datasets, storeDir);
97
61
  };
98
- const getLocalRequestQueuePath = (storeId) => {
62
+ export const getLocalRequestQueuePath = (storeId) => {
99
63
  const envVar = ACTOR_ENV_VARS.DEFAULT_REQUEST_QUEUE_ID;
100
64
  const storeDir = storeId || process.env[envVar] || LOCAL_ACTOR_ENV_VARS[envVar];
101
-
102
- return path.join(getLocalStorageDir(), LOCAL_STORAGE_SUBDIRS.requestQueues, storeDir);
65
+ return join(getLocalStorageDir(), LOCAL_STORAGE_SUBDIRS.requestQueues, storeDir);
103
66
  };
104
-
105
67
  /**
106
68
  * Returns object from auth file or empty object.
107
- * @return {*}
108
69
  */
109
- const getLocalUserInfo = () => {
70
+ export const getLocalUserInfo = async () => {
110
71
  try {
111
- return loadJson.sync(AUTH_FILE_PATH) || {};
112
- } catch (e) {
72
+ const result = await loadJsonFile(AUTH_FILE_PATH());
73
+ return (result || {});
74
+ }
75
+ catch {
113
76
  return {};
114
77
  }
115
78
  };
116
-
117
79
  /**
118
80
  * Gets instance of ApifyClient for user otherwise throws error
119
- * @return {Promise<boolean|*>}
120
81
  */
121
- const getLoggedClientOrThrow = async () => {
82
+ export const getLoggedClientOrThrow = async () => {
122
83
  const loggedClient = await getLoggedClient();
123
84
  if (!loggedClient) {
124
85
  throw new Error('You are not logged in with your Apify account. Call "apify login" to fix that.');
125
86
  }
126
87
  return loggedClient;
127
88
  };
128
-
89
+ const getTokenWithAuthFileFallback = (existingToken) => {
90
+ if (!existingToken && existsSync(GLOBAL_CONFIGS_FOLDER()) && existsSync(AUTH_FILE_PATH())) {
91
+ return loadJsonFileSync(AUTH_FILE_PATH()).token;
92
+ }
93
+ return existingToken;
94
+ };
129
95
  /**
130
96
  * Returns options for ApifyClient
131
- * @param {String|null|undefined} token
132
- * @returns {Object}
133
97
  */
134
- const getApifyClientOptions = (token, apiBaseUrl) => {
135
- if (!token && fs.existsSync(GLOBAL_CONFIGS_FOLDER) && fs.existsSync(AUTH_FILE_PATH)) {
136
- ({ token } = loadJson.sync(AUTH_FILE_PATH));
137
- }
138
-
98
+ export const getApifyClientOptions = (token, apiBaseUrl) => {
99
+ token = getTokenWithAuthFileFallback(token);
139
100
  return {
140
101
  token,
141
102
  baseUrl: apiBaseUrl || process.env.APIFY_CLIENT_BASE_URL,
142
103
  requestInterceptors: [(config) => {
143
- if (!config.headers) {
144
- config.headers = new axios.AxiosHeaders();
145
- }
146
-
147
- for (const [key, value] of Object.entries(APIFY_CLIENT_DEFAULT_HEADERS)) {
148
- config.headers[key] = value;
149
- }
150
-
151
- return config;
152
- }],
104
+ // @ts-expect-error CLI is ESM, client is CJS, the types "differ"
105
+ config.headers ?? (config.headers = new AxiosHeaders());
106
+ for (const [key, value] of Object.entries(APIFY_CLIENT_DEFAULT_HEADERS)) {
107
+ config.headers[key] = value;
108
+ }
109
+ return config;
110
+ }],
153
111
  };
154
112
  };
155
-
156
113
  /**
157
114
  * Gets instance of ApifyClient for token or for params from global auth file.
158
115
  * NOTE: It refreshes global auth file each run
159
116
  * @param [token]
160
- * @return {Promise<*>}
161
117
  */
162
- const getLoggedClient = async (token, apiBaseUrl) => {
163
- if (!token && fs.existsSync(GLOBAL_CONFIGS_FOLDER) && fs.existsSync(AUTH_FILE_PATH)) {
164
- ({ token } = loadJson.sync(AUTH_FILE_PATH));
165
- }
166
-
118
+ export const getLoggedClient = async (token, apiBaseUrl) => {
119
+ token = getTokenWithAuthFileFallback(token);
167
120
  const apifyClient = new ApifyClient(getApifyClientOptions(token, apiBaseUrl));
168
121
  let userInfo;
169
122
  try {
170
123
  userInfo = await apifyClient.user('me').get();
171
- } catch (e) {
172
- return false;
173
124
  }
174
-
125
+ catch (err) {
126
+ return null;
127
+ }
175
128
  // Always refresh Auth file
176
- if (!fs.existsSync(GLOBAL_CONFIGS_FOLDER)) fs.mkdirSync(GLOBAL_CONFIGS_FOLDER);
177
- writeJson.sync(AUTH_FILE_PATH, { token: apifyClient.token, ...userInfo });
129
+ ensureApifyDirectory(AUTH_FILE_PATH());
130
+ await writeJsonFile(AUTH_FILE_PATH(), { token: apifyClient.token, ...userInfo });
178
131
  return apifyClient;
179
132
  };
180
-
181
- const getLocalConfigPath = () => path.join(process.cwd(), LOCAL_CONFIG_PATH);
182
-
133
+ const getLocalConfigPath = (cwd) => join(cwd, LOCAL_CONFIG_PATH);
183
134
  /**
184
135
  * @deprecated Use getLocalConfigPath
185
- * @returns {string}
186
136
  */
187
- const getDeprecatedLocalConfigPath = () => path.join(process.cwd(), DEPRECATED_LOCAL_CONFIG_NAME);
188
-
189
- const getJsonFileContent = (filePath) => {
190
- if (!fs.existsSync(filePath)) {
137
+ const getDeprecatedLocalConfigPath = (cwd) => join(cwd, DEPRECATED_LOCAL_CONFIG_NAME);
138
+ export const getJsonFileContent = (filePath) => {
139
+ if (!existsSync(filePath)) {
191
140
  return;
192
141
  }
193
- return loadJson.sync(filePath);
142
+ return loadJsonFileSync(filePath);
194
143
  };
195
-
196
- const getLocalConfig = () => getJsonFileContent(getLocalConfigPath());
197
-
144
+ export const getLocalConfig = (cwd) => getJsonFileContent(getLocalConfigPath(cwd));
198
145
  /**
199
146
  * @deprecated Use getLocalConfig
200
- * @returns {string}
201
147
  */
202
- const getDeprecatedLocalConfig = () => getJsonFileContent(getDeprecatedLocalConfigPath());
203
-
204
- const getLocalConfigOrThrow = async () => {
205
- let localConfig = getLocalConfig();
206
- let deprecatedLocalConfig = getDeprecatedLocalConfig();
207
-
148
+ const getDeprecatedLocalConfig = (cwd) => getJsonFileContent(getDeprecatedLocalConfigPath(cwd));
149
+ export const getLocalConfigOrThrow = async (cwd) => {
150
+ let localConfig = getLocalConfig(cwd);
151
+ let deprecatedLocalConfig = getDeprecatedLocalConfig(cwd);
208
152
  if (localConfig && deprecatedLocalConfig) {
209
153
  const answer = await inquirer.prompt([{
210
- name: 'isConfirm',
211
- type: 'confirm',
212
-
213
- message: `The new version of Apify CLI uses the "${LOCAL_CONFIG_PATH}" instead of the "apify.json" file. Since we have found both files in your Actor directory, "apify.json" will be renamed to "apify.json.deprecated". Going forward, all commands will use "${LOCAL_CONFIG_PATH}". You can read about the differences between the old and the new config at https://github.com/apify/apify-cli/blob/master/MIGRATIONS.md. Do you want to continue?`,
214
- }]);
154
+ name: 'isConfirm',
155
+ type: 'confirm',
156
+ message: `The new version of Apify CLI uses the "${LOCAL_CONFIG_PATH}" instead of the "apify.json" file. Since we have found both files in your Actor directory, "apify.json" will be renamed to "apify.json.deprecated". Going forward, all commands will use "${LOCAL_CONFIG_PATH}". You can read about the differences between the old and the new config at https://github.com/apify/apify-cli/blob/master/MIGRATIONS.md. Do you want to continue?`,
157
+ }]);
215
158
  if (!answer.isConfirm) {
216
159
  throw new Error('Command can not run with old "apify.json" file present in your Actor directory., Please, either rename or remove it.');
217
160
  }
218
161
  try {
219
- fs.renameSync(getDeprecatedLocalConfigPath(), `${getDeprecatedLocalConfigPath()}.deprecated`);
162
+ renameSync(getDeprecatedLocalConfigPath(cwd), `${getDeprecatedLocalConfigPath(cwd)}.deprecated`);
220
163
  // eslint-disable-next-line max-len
221
164
  info(`The "apify.json" file has been renamed to "apify.json.deprecated". The deprecated file is no longer used by the CLI or Apify Console. If you do not need it for some specific purpose, it can be safely deleted.`);
222
- } catch (e) {
165
+ }
166
+ catch (e) {
223
167
  throw new Error('Failed to rename deprecated "apify.json".');
224
168
  }
225
169
  }
226
-
227
170
  if (!localConfig && !deprecatedLocalConfig) {
228
171
  return {};
229
172
  }
230
-
231
173
  // If apify.json exists migrate it to .actor/actor.json
232
174
  if (!localConfig && deprecatedLocalConfig) {
233
175
  const answer = await inquirer.prompt([{
234
- name: 'isConfirm',
235
- type: 'confirm',
236
- // eslint-disable-next-line max-len
237
- message: `The new version of Apify CLI uses the "${LOCAL_CONFIG_PATH}" instead of the "apify.json" file. Your "apify.json" file will be automatically updated to the new format under "${LOCAL_CONFIG_PATH}". The original file will be renamed by adding the ".deprecated" suffix. Do you want to continue?`,
238
- }]);
176
+ name: 'isConfirm',
177
+ type: 'confirm',
178
+ // eslint-disable-next-line max-len
179
+ message: `The new version of Apify CLI uses the "${LOCAL_CONFIG_PATH}" instead of the "apify.json" file. Your "apify.json" file will be automatically updated to the new format under "${LOCAL_CONFIG_PATH}". The original file will be renamed by adding the ".deprecated" suffix. Do you want to continue?`,
180
+ }]);
239
181
  if (!answer.isConfirm) {
240
182
  throw new Error('Command can not run with old apify.json structure. Either let the CLI auto-update it or follow the guide on https://github.com/apify/apify-cli/blob/master/MIGRATIONS.md and update it manually.');
241
183
  }
@@ -246,87 +188,77 @@ const getLocalConfigOrThrow = async () => {
246
188
  }
247
189
  localConfig = {
248
190
  actorSpecification: ACTOR_SPECIFICATION_VERSION,
249
- environmentVariables: deprecatedLocalConfig.env || undefined,
191
+ environmentVariables: deprecatedLocalConfig?.env || undefined,
250
192
  ..._.pick(deprecatedLocalConfig, MIGRATED_APIFY_JSON_PROPERTIES),
251
193
  };
252
-
253
- writeJson.sync(getLocalConfigPath(), localConfig);
254
- fs.renameSync(getDeprecatedLocalConfigPath(), `${getDeprecatedLocalConfigPath()}.deprecated`);
194
+ await writeJsonFile(getLocalConfigPath(cwd), localConfig);
195
+ renameSync(getDeprecatedLocalConfigPath(cwd), `${getDeprecatedLocalConfigPath(cwd)}.deprecated`);
255
196
  // eslint-disable-next-line max-len
256
197
  info(`The "apify.json" file has been migrated to "${LOCAL_CONFIG_PATH}" and the original file renamed to "apify.json.deprecated". The deprecated file is no longer used by the CLI or Apify Console. If you do not need it for some specific purpose, it can be safely deleted. Do not forget to commit the new file to your Git repository.`);
257
- } catch (e) {
198
+ }
199
+ catch (e) {
258
200
  throw new Error(`Can not update "${LOCAL_CONFIG_PATH}" structure. Follow guide on https://github.com/apify/apify-cli/blob/master/MIGRATIONS.md and update it manually.`);
259
201
  }
260
202
  }
261
-
262
203
  return localConfig;
263
204
  };
264
-
265
- const setLocalConfig = async (localConfig, actDir) => {
205
+ export const setLocalConfig = async (localConfig, actDir) => {
266
206
  actDir = actDir || process.cwd();
267
- writeJson.sync(path.join(actDir, LOCAL_CONFIG_PATH), localConfig);
207
+ writeJsonFileSync(join(actDir, LOCAL_CONFIG_PATH), localConfig);
268
208
  };
269
-
270
209
  const GITIGNORE_REQUIRED_CONTENTS = [getLocalStorageDir(), 'node_modules', '.venv'];
271
-
272
- const setLocalEnv = async (actDir) => {
210
+ export const setLocalEnv = async (actDir) => {
273
211
  // Create folders for emulation Apify stores
274
212
  const keyValueStorePath = getLocalKeyValueStorePath();
275
213
  ensureFolderExistsSync(actDir, getLocalDatasetPath());
276
214
  ensureFolderExistsSync(actDir, getLocalRequestQueuePath());
277
215
  ensureFolderExistsSync(actDir, keyValueStorePath);
278
-
279
216
  // Create or update gitignore
280
- const gitignorePath = path.join(actDir, '.gitignore');
217
+ const gitignorePath = join(actDir, '.gitignore');
281
218
  let gitignoreContents = '';
282
- if (fs.existsSync(gitignorePath)) {
283
- gitignoreContents = fs.readFileSync(gitignorePath, { encoding: 'utf-8' });
219
+ if (existsSync(gitignorePath)) {
220
+ gitignoreContents = readFileSync(gitignorePath, { encoding: 'utf-8' });
284
221
  }
285
-
286
222
  const gitignoreAdditions = [];
287
223
  for (const gitignoreRequirement of GITIGNORE_REQUIRED_CONTENTS) {
288
224
  if (!RegExp(`^${escapeStringRegexp(gitignoreRequirement)}$`, 'mg').test(gitignoreContents)) {
289
225
  gitignoreAdditions.push(gitignoreRequirement);
290
226
  }
291
227
  }
292
-
293
228
  if (gitignoreAdditions.length > 0) {
294
229
  if (gitignoreContents.length > 0) {
295
230
  gitignoreAdditions.unshift('# Added by Apify CLI');
296
- fs.writeFileSync(gitignorePath, `\n${gitignoreAdditions.join('\n')}\n`, { flag: 'a' });
297
- } else {
298
- fs.writeFileSync(gitignorePath, `${gitignoreAdditions.join('\n')}\n`, { flag: 'w' });
231
+ writeFileSync(gitignorePath, `\n${gitignoreAdditions.join('\n')}\n`, { flag: 'a' });
232
+ }
233
+ else {
234
+ writeFileSync(gitignorePath, `${gitignoreAdditions.join('\n')}\n`, { flag: 'w' });
299
235
  }
300
236
  }
301
237
  };
302
-
303
238
  /**
304
239
  * Convert Object with kebab-case keys to camelCased keys
305
- *
306
- * @param object
307
- * @return {{}}
308
240
  */
309
- const argsToCamelCase = (object) => {
241
+ export const argsToCamelCase = (object) => {
310
242
  const camelCasedObject = {};
311
243
  Object.keys(object).forEach((arg) => {
312
244
  const camelCasedArg = arg.replace(/-(.)/g, ($1) => $1.toUpperCase()).replace(/-/g, '');
245
+ // @ts-expect-error This is very hard to make stricter than it already will be at the top level
313
246
  camelCasedObject[camelCasedArg] = object[arg];
314
247
  });
315
248
  return camelCasedObject;
316
249
  };
317
-
250
+ const mime = new Mime(standardMimes, otherMimes).define({
251
+ // .tgz files don't have a MIME type defined, this fixes it
252
+ 'application/gzip': ['tgz'],
253
+ // Default mime-type for .ts(x) files is video/mp2t. But in our usecases they're almost always TypeScript, which we want to treat as text
254
+ 'text/typescript': ['ts', 'tsx', 'mts'],
255
+ }, true);
318
256
  // Detect whether file is binary from its MIME type, or if not available, contents
319
257
  const getSourceFileFormat = (filePath, fileContent) => {
320
258
  // Try to detect the MIME type from the file path
321
- // .tgz files don't have a MIME type defined, this fixes it
322
- mime.define({ 'application/gzip': ['tgz'] }, true);
323
- // Default mime-type for .ts(x) files is video/mp2t. But in our usecases they're almost always TypeScript, which we want to treat as text
324
- mime.define({ 'text/typescript': ['ts', 'tsx', 'mts'] }, true);
325
-
326
259
  const contentType = mime.getType(filePath);
327
260
  if (contentType) {
328
- const format = (
329
- contentType.startsWith('text/')
261
+ const format = (contentType.startsWith('text/')
330
262
  || contentType.includes('javascript')
331
263
  || contentType.includes('json')
332
264
  || contentType.includes('xml')
@@ -338,15 +270,13 @@ const getSourceFileFormat = (filePath, fileContent) => {
338
270
  : SOURCE_FILE_FORMATS.BASE64;
339
271
  return format;
340
272
  }
341
-
342
273
  // If the MIME type detection failed, try to detect the file encoding from the file content
343
274
  const encoding = getEncoding(fileContent);
344
275
  return encoding === 'binary' ? SOURCE_FILE_FORMATS.BASE64 : SOURCE_FILE_FORMATS.TEXT;
345
276
  };
346
-
347
- const createSourceFiles = async (paths) => {
277
+ export const createSourceFiles = async (paths, cwd) => {
348
278
  return paths.map((filePath) => {
349
- const file = fs.readFileSync(filePath);
279
+ const file = readFileSync(join(cwd, filePath));
350
280
  const format = getSourceFileFormat(filePath, file);
351
281
  return {
352
282
  name: filePath,
@@ -357,138 +287,144 @@ const createSourceFiles = async (paths) => {
357
287
  };
358
288
  });
359
289
  };
360
-
361
290
  /**
362
291
  * Get actor local files, omit files defined in .gitignore and .git folder
363
292
  * All dot files(.file) and folders(.folder/) are included.
364
293
  */
365
- const getActorLocalFilePaths = () => globby(['*', '**/**'], {
294
+ export const getActorLocalFilePaths = async (cwd) => globby(['*', '**/**'], {
366
295
  ignore: ['.git/**', 'apify_storage', 'node_modules', 'storage', 'crawlee_storage'],
367
296
  gitignore: true,
368
297
  dot: true,
298
+ cwd,
369
299
  });
370
-
371
300
  /**
372
301
  * Create zip file with all actor files specified with pathsToZip
373
- * @param zipName
374
- * @param pathsToZip
375
- * @return {Promise<void>}
376
302
  */
377
- const createActZip = async (zipName, pathsToZip) => {
303
+ export const createActZip = async (zipName, pathsToZip, cwd) => {
378
304
  // NOTE: There can be a zip from a previous unfinished operation.
379
- if (fs.existsSync(zipName)) await deleteFile(zipName);
380
-
381
- const archive = archiver(zipName);
382
-
383
- const archiveFilesPromises = [];
384
- pathsToZip.forEach((globPath) => archiveFilesPromises.push(archive.glob(globPath)));
385
- await Promise.all(archiveFilesPromises);
386
-
305
+ if (existsSync(zipName)) {
306
+ await deleteFile(zipName);
307
+ }
308
+ const writeStream = createWriteStream(zipName);
309
+ const archive = archiver('zip');
310
+ archive.pipe(writeStream);
311
+ pathsToZip.forEach((globPath) => archive.glob(globPath, { cwd }));
387
312
  await archive.finalize();
388
313
  };
389
-
390
314
  /**
391
315
  * Get actor input from local store
392
- * @return {{body: *, contentType: string}}
393
316
  */
394
- const getLocalInput = () => {
317
+ export const getLocalInput = (cwd) => {
395
318
  const defaultLocalStorePath = getLocalKeyValueStorePath();
396
- const files = fs.readdirSync(defaultLocalStorePath);
319
+ const files = readdirSync(join(cwd, defaultLocalStorePath));
397
320
  const inputName = files.find((file) => !!file.match(INPUT_FILE_REG_EXP));
398
-
399
321
  // No input file
400
- if (!inputName) return;
401
-
402
- const input = fs.readFileSync(path.join(defaultLocalStorePath, inputName));
322
+ if (!inputName)
323
+ return;
324
+ const input = readFileSync(join(cwd, defaultLocalStorePath, inputName));
403
325
  const contentType = mime.getType(inputName);
404
326
  return { body: input, contentType };
405
327
  };
406
-
407
- const purgeDefaultQueue = async () => {
328
+ export const purgeDefaultQueue = async () => {
408
329
  const defaultQueuesPath = getLocalRequestQueuePath();
409
- if (fs.existsSync(getLocalStorageDir()) && fs.existsSync(defaultQueuesPath)) {
330
+ if (existsSync(getLocalStorageDir()) && existsSync(defaultQueuesPath)) {
410
331
  await rimrafPromised(defaultQueuesPath);
411
332
  }
412
333
  };
413
-
414
- const purgeDefaultDataset = async () => {
334
+ export const purgeDefaultDataset = async () => {
415
335
  const defaultDatasetPath = getLocalDatasetPath();
416
- if (fs.existsSync(getLocalStorageDir()) && fs.existsSync(defaultDatasetPath)) {
336
+ if (existsSync(getLocalStorageDir()) && existsSync(defaultDatasetPath)) {
417
337
  await rimrafPromised(defaultDatasetPath);
418
338
  }
419
339
  };
420
-
421
- const purgeDefaultKeyValueStore = async () => {
340
+ export const purgeDefaultKeyValueStore = async () => {
422
341
  const defaultKeyValueStorePath = getLocalKeyValueStorePath();
423
- if (!fs.existsSync(getLocalStorageDir()) || !fs.existsSync(defaultKeyValueStorePath)) {
342
+ if (!existsSync(getLocalStorageDir()) || !existsSync(defaultKeyValueStorePath)) {
424
343
  return;
425
344
  }
426
- const filesToDelete = fs.readdirSync(defaultKeyValueStorePath);
427
-
345
+ const filesToDelete = readdirSync(defaultKeyValueStorePath);
428
346
  const deletePromises = [];
429
347
  filesToDelete.forEach((file) => {
430
- if (!file.match(INPUT_FILE_REG_EXP)) deletePromises.push(deleteFile(path.join(defaultKeyValueStorePath, file)));
348
+ if (!file.match(INPUT_FILE_REG_EXP)) {
349
+ deletePromises.push(deleteFile(join(defaultKeyValueStorePath, file)));
350
+ }
431
351
  });
432
-
433
352
  await Promise.all(deletePromises);
434
353
  };
435
-
436
- const outputJobLog = async (job, timeout) => {
354
+ export const outputJobLog = async (job, timeout) => {
437
355
  const { id: logId, status } = job;
356
+ const apifyClient = new ApifyClient({ baseUrl: process.env.APIFY_CLIENT_BASE_URL });
438
357
  // In case job was already done just output log
439
- if (ACT_JOB_TERMINAL_STATUSES.includes(status)) {
440
- const apifyClient = new ApifyClient({ baseUrl: process.env.APIFY_CLIENT_BASE_URL });
358
+ if (ACTOR_JOB_TERMINAL_STATUSES.includes(status)) {
441
359
  const log = await apifyClient.log(logId).get();
442
360
  process.stdout.write(log);
361
+ return;
443
362
  }
444
-
445
363
  // In other case stream it to stdout
446
- // TODO: Use apifyClient.log(logId).stream() instead of http request stream.
447
- return new Promise((resolve, reject) => {
448
- const req = https.get(`https://api.apify.com/v2/logs/${logId}?stream=1`);
449
- let res;
450
-
451
- req.on('response', (response) => {
452
- res = response;
453
- response.on('data', (chunk) => process.stdout.write(chunk.toString()));
454
- response.on('error', (err) => {
455
- reject(err);
456
- });
457
- });
458
- req.on('error', (err) => {
459
- reject(err);
364
+ // eslint-disable-next-line no-async-promise-executor
365
+ return new Promise(async (resolve) => {
366
+ const stream = await apifyClient.log(logId).stream();
367
+ if (!stream) {
368
+ resolve('no-logs');
369
+ return;
370
+ }
371
+ let nodeTimeout = null;
372
+ stream.on('data', (chunk) => {
373
+ process.stdout.write(chunk.toString());
460
374
  });
461
- req.on('close', () => {
375
+ stream.once('end', () => {
462
376
  resolve('finished');
377
+ if (nodeTimeout) {
378
+ clearTimeout(nodeTimeout);
379
+ }
463
380
  });
464
-
465
381
  if (timeout) {
466
- setTimeout(() => {
467
- if (res) res.removeAllListeners();
468
- if (req) {
469
- req.removeAllListeners();
470
- req.abort();
471
- }
382
+ nodeTimeout = setTimeout(() => {
383
+ stream.destroy();
472
384
  resolve('timeouts');
473
385
  }, timeout);
474
386
  }
475
387
  });
388
+ // return new Promise((resolve, reject) => {
389
+ // const req = get(`https://api.apify.com/v2/logs/${logId}?stream=1`);
390
+ // let res: IncomingMessage;
391
+ // req.on('response', (response) => {
392
+ // res = response;
393
+ // response.on('data', (chunk) => process.stdout.write(chunk.toString()));
394
+ // response.on('error', (err) => {
395
+ // reject(err);
396
+ // });
397
+ // });
398
+ // req.on('error', (err) => {
399
+ // reject(err);
400
+ // });
401
+ // req.on('close', () => {
402
+ // resolve('finished');
403
+ // });
404
+ // if (timeout) {
405
+ // setTimeout(() => {
406
+ // if (res) res.removeAllListeners();
407
+ // if (req) {
408
+ // req.removeAllListeners();
409
+ // req.destroy();
410
+ // }
411
+ // resolve('timeouts');
412
+ // }, timeout);
413
+ // }
414
+ // });
476
415
  };
477
-
478
416
  /**
479
417
  * Returns npm command for current os
480
418
  * NOTE: For window we have to returns npm.cmd instead of npm, otherwise it doesn't work
481
419
  * @return {string}
482
420
  */
483
- const getNpmCmd = () => {
421
+ export const getNpmCmd = () => {
484
422
  return /^win/.test(process.platform) ? 'npm.cmd' : 'npm';
485
423
  };
486
-
487
424
  /**
488
425
  * Returns true if apify storage is empty (expect INPUT.*)
489
- * @return {Promise<boolean>}
490
426
  */
491
- const checkIfStorageIsEmpty = async () => {
427
+ export const checkIfStorageIsEmpty = async () => {
492
428
  const filesWithoutInput = await globby([
493
429
  `${getLocalStorageDir()}/**`,
494
430
  // Omit INPUT.* file
@@ -496,20 +432,10 @@ const checkIfStorageIsEmpty = async () => {
496
432
  ]);
497
433
  return filesWithoutInput.length === 0;
498
434
  };
499
-
500
- /**
501
- * Show help for command
502
- * NOTE: This is not nice, but I can not find other way..
503
- * @param command
504
- */
505
- const showHelpForCommand = (command) => {
506
- execSync(`apify ${command} --help`, { stdio: [0, 1, 2] });
507
- };
508
-
509
435
  /**
510
436
  * Migration for deprecated structure of apify.json to latest.
511
- * @param localConfig
512
437
  */
438
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
513
439
  const updateLocalConfigStructure = (localConfig) => {
514
440
  const updatedLocalConfig = {
515
441
  name: localConfig.name,
@@ -521,18 +447,18 @@ const updateLocalConfigStructure = (localConfig) => {
521
447
  if (localConfig.version.envVars && localConfig.version.envVars.length) {
522
448
  const env = {};
523
449
  localConfig.version.envVars.forEach((envVar) => {
524
- if (envVar.name && envVar.value) env[envVar.name] = envVar.value;
450
+ if (envVar.name && envVar.value)
451
+ env[envVar.name] = envVar.value;
525
452
  });
526
453
  updatedLocalConfig.env = env;
527
454
  }
528
455
  return updatedLocalConfig;
529
456
  };
530
-
531
457
  /**
532
458
  * Validates actor name, if finds issue throws error.
533
459
  * @param actorName
534
460
  */
535
- const validateActorName = (actorName) => {
461
+ export const validateActorName = (actorName) => {
536
462
  if (!ACTOR_NAME.REGEX.test(actorName)) {
537
463
  throw new Error('The Actor name must be a DNS hostname-friendly string (e.g. my-newest-actor).');
538
464
  }
@@ -543,148 +469,110 @@ const validateActorName = (actorName) => {
543
469
  throw new Error('The Actor name must be a maximum of 30 characters long.');
544
470
  }
545
471
  };
546
-
547
- const sanitizeActorName = (actorName) => {
472
+ export const sanitizeActorName = (actorName) => {
548
473
  let sanitizedName = actorName
549
474
  .replaceAll(/[^a-zA-Z0-9-]/g, '-');
550
-
551
475
  if (sanitizedName.length < ACTOR_NAME.MIN_LENGTH) {
552
476
  sanitizedName = `${sanitizedName}-apify-actor`;
553
477
  }
554
-
555
478
  sanitizedName = sanitizedName.replaceAll(/^-+/g, '').replaceAll(/-+$/g, '');
556
-
557
479
  return sanitizedName.slice(0, ACTOR_NAME.MAX_LENGTH);
558
480
  };
559
-
560
- const getPythonCommand = (directory) => {
481
+ export const getPythonCommand = (directory) => {
561
482
  const pythonVenvPath = /^win/.test(process.platform)
562
483
  ? 'Scripts/python.exe'
563
484
  : 'bin/python3';
564
-
565
485
  let fullPythonVenvPath;
566
486
  if (process.env.VIRTUAL_ENV) {
567
- fullPythonVenvPath = path.join(process.env.VIRTUAL_ENV, pythonVenvPath);
568
- } else {
569
- fullPythonVenvPath = path.join(directory, '.venv', pythonVenvPath);
487
+ fullPythonVenvPath = join(process.env.VIRTUAL_ENV, pythonVenvPath);
488
+ }
489
+ else {
490
+ fullPythonVenvPath = join(directory, '.venv', pythonVenvPath);
570
491
  }
571
-
572
- if (fs.existsSync(fullPythonVenvPath)) {
492
+ if (existsSync(fullPythonVenvPath)) {
573
493
  return fullPythonVenvPath;
574
494
  }
575
-
576
495
  return /^win/.test(process.platform)
577
496
  ? 'python'
578
497
  : 'python3';
579
498
  };
580
-
581
- const detectPythonVersion = (directory) => {
499
+ export const detectPythonVersion = (directory) => {
582
500
  const pythonCommand = getPythonCommand(directory);
583
501
  try {
584
502
  const spawnResult = spawnSync(pythonCommand, ['-c', 'import platform; print(platform.python_version())'], { encoding: 'utf-8' });
585
503
  if (!spawnResult.error && spawnResult.stdout) {
586
504
  return spawnResult.stdout.trim();
587
505
  }
588
- } catch {
506
+ return undefined;
507
+ }
508
+ catch {
589
509
  return undefined;
590
510
  }
591
511
  };
592
-
593
- const isPythonVersionSupported = (installedPythonVersion) => {
594
- return semver.satisfies(installedPythonVersion, `^${MINIMUM_SUPPORTED_PYTHON_VERSION}`);
512
+ export const isPythonVersionSupported = (installedPythonVersion) => {
513
+ return satisfies(installedPythonVersion, `^${MINIMUM_SUPPORTED_PYTHON_VERSION}`);
595
514
  };
596
-
597
- const detectNodeVersion = () => {
515
+ export const detectNodeVersion = () => {
598
516
  try {
599
517
  const spawnResult = spawnSync('node', ['--version'], { encoding: 'utf-8' });
600
518
  if (!spawnResult.error && spawnResult.stdout) {
601
519
  return spawnResult.stdout.trim().replace(/^v/, '');
602
520
  }
603
- } catch {
521
+ return undefined;
522
+ }
523
+ catch {
604
524
  return undefined;
605
525
  }
606
526
  };
607
-
608
- const isNodeVersionSupported = (installedNodeVersion) => {
527
+ export const isNodeVersionSupported = (installedNodeVersion) => {
609
528
  // SUPPORTED_NODEJS_VERSION can be a version range,
610
529
  // we need to get the minimum supported version from that range to be able to compare them
611
- const minimumSupportedNodeVersion = semver.minVersion(SUPPORTED_NODEJS_VERSION);
612
- return semver.gte(installedNodeVersion, minimumSupportedNodeVersion);
530
+ const minimumSupportedNodeVersion = minVersion(SUPPORTED_NODEJS_VERSION);
531
+ return gte(installedNodeVersion, minimumSupportedNodeVersion);
613
532
  };
614
-
615
- const detectNpmVersion = () => {
533
+ export const detectNpmVersion = () => {
616
534
  const npmCommand = getNpmCmd();
617
535
  try {
618
536
  const spawnResult = spawnSync(npmCommand, ['--version'], { encoding: 'utf-8' });
619
537
  if (!spawnResult.error && spawnResult.stdout) {
620
538
  return spawnResult.stdout.trim().replace(/^v/, '');
621
539
  }
622
- } catch {
540
+ return undefined;
541
+ }
542
+ catch {
623
543
  return undefined;
624
544
  }
625
545
  };
626
-
627
- const detectLocalActorLanguage = () => {
628
- const cwd = process.cwd();
629
- const isActorInNode = fs.existsSync(path.join(cwd, 'package.json'));
630
- const isActorInPython = fs.existsSync(path.join(cwd, 'src/__main__.py')) || ProjectAnalyzer.getProjectType(cwd) === PROJECT_TYPES.SCRAPY;
546
+ export const detectLocalActorLanguage = (cwd) => {
547
+ const isActorInNode = existsSync(join(cwd, 'package.json'));
548
+ const isActorInPython = existsSync(join(cwd, 'src/__main__.py')) || ProjectAnalyzer.getProjectType(cwd) === PROJECT_TYPES.SCRAPY;
631
549
  const result = {};
632
550
  if (isActorInNode) {
633
551
  result.language = LANGUAGE.NODEJS;
634
552
  result.languageVersion = detectNodeVersion();
635
- } else if (isActorInPython) {
553
+ }
554
+ else if (isActorInPython) {
636
555
  result.language = LANGUAGE.PYTHON;
637
556
  result.languageVersion = detectPythonVersion(cwd);
638
- } else {
557
+ }
558
+ else {
639
559
  result.language = LANGUAGE.UNKNOWN;
640
560
  }
641
561
  return result;
642
562
  };
643
-
644
- const downloadAndUnzip = async ({ url, pathTo }) => {
563
+ export const downloadAndUnzip = async ({ url, pathTo }) => {
645
564
  const zipStream = await httpsGet(url);
646
565
  const chunks = [];
647
566
  zipStream.on('data', (chunk) => chunks.push(chunk));
648
- await promisify(finished)(zipStream);
567
+ await finished(zipStream);
649
568
  const zip = new AdmZip(Buffer.concat(chunks));
650
569
  zip.extractAllTo(pathTo, true);
651
570
  };
652
-
653
- module.exports = {
654
- httpsGet,
655
- getLoggedClientOrThrow,
656
- getLocalConfig,
657
- setLocalConfig,
658
- setLocalEnv,
659
- argsToCamelCase,
660
- getLoggedClient,
661
- createActZip,
662
- getLocalUserInfo,
663
- getLocalConfigOrThrow,
664
- getLocalInput,
665
- purgeDefaultQueue,
666
- purgeDefaultDataset,
667
- purgeDefaultKeyValueStore,
668
- outputJobLog,
669
- getLocalKeyValueStorePath,
670
- getLocalDatasetPath,
671
- getLocalRequestQueuePath,
672
- getNpmCmd,
673
- checkIfStorageIsEmpty,
674
- getLocalStorageDir,
675
- showHelpForCommand,
676
- getActorLocalFilePaths,
677
- createSourceFiles,
678
- validateActorName,
679
- getJsonFileContent,
680
- getApifyClientOptions,
681
- detectPythonVersion,
682
- isPythonVersionSupported,
683
- getPythonCommand,
684
- detectNodeVersion,
685
- isNodeVersionSupported,
686
- detectNpmVersion,
687
- detectLocalActorLanguage,
688
- downloadAndUnzip,
689
- sanitizeActorName,
571
+ /**
572
+ * Ensures the Apify directory exists, as well as nested folders (for tests)
573
+ */
574
+ export const ensureApifyDirectory = (file) => {
575
+ const path = dirname(file);
576
+ mkdirSync(path, { recursive: true });
690
577
  };
578
+ //# sourceMappingURL=utils.js.map