@corva/create-app 0.0.0-2576df8

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 (204) hide show
  1. package/README.md +218 -0
  2. package/bin/cca.js +5 -0
  3. package/bin/create-corva-app.cjs +25 -0
  4. package/common/node/.env +15 -0
  5. package/common/node/.env.sample +26 -0
  6. package/common/node/gitignore +130 -0
  7. package/common/package.json +3 -0
  8. package/common/python/.env +5 -0
  9. package/common/python/.env.sample +7 -0
  10. package/common/python/Makefile +15 -0
  11. package/common/python/gitignore +161 -0
  12. package/common/python/requirements.txt +2 -0
  13. package/lib/commands/attach.js +28 -0
  14. package/lib/commands/create.js +463 -0
  15. package/lib/commands/release.js +58 -0
  16. package/lib/commands/rerun.js +34 -0
  17. package/lib/commands/zip.js +39 -0
  18. package/lib/constants/cache.js +5 -0
  19. package/lib/constants/cli.js +35 -0
  20. package/lib/constants/manifest.js +263 -0
  21. package/lib/constants/messages.js +15 -0
  22. package/lib/constants/package.js +288 -0
  23. package/lib/flow.js +53 -0
  24. package/lib/flows/attach.js +8 -0
  25. package/lib/flows/lib/api.js +385 -0
  26. package/lib/flows/lib/create-zip-archive.js +83 -0
  27. package/lib/flows/lib/json.js +30 -0
  28. package/lib/flows/lib/manifest.js +81 -0
  29. package/lib/flows/lib/notification.js +142 -0
  30. package/lib/flows/lib/step-error.js +10 -0
  31. package/lib/flows/lib/waitForMs.js +3 -0
  32. package/lib/flows/prepare.js +6 -0
  33. package/lib/flows/release.js +26 -0
  34. package/lib/flows/rerun.js +8 -0
  35. package/lib/flows/steps/attach/add-app-to-stream.js +23 -0
  36. package/lib/flows/steps/attach/get-all-live-assets.js +135 -0
  37. package/lib/flows/steps/attach/index.js +5 -0
  38. package/lib/flows/steps/attach/prepare-data.js +19 -0
  39. package/lib/flows/steps/prepare-load-app-files.js +12 -0
  40. package/lib/flows/steps/release/add-label.js +10 -0
  41. package/lib/flows/steps/release/add-notes.js +10 -0
  42. package/lib/flows/steps/release/get-config.js +41 -0
  43. package/lib/flows/steps/release/prepare-data.js +12 -0
  44. package/lib/flows/steps/release/publish.js +11 -0
  45. package/lib/flows/steps/release/remove-failed-upload.js +21 -0
  46. package/lib/flows/steps/release/upload-zip-to-corva.js +136 -0
  47. package/lib/flows/steps/release/wait-for-build.js +36 -0
  48. package/lib/flows/steps/rerun/create-task.js +77 -0
  49. package/lib/flows/steps/rerun/ensure-that-app-in-stream.js +68 -0
  50. package/lib/flows/steps/rerun/get-app-version.js +111 -0
  51. package/lib/flows/steps/rerun/prepare-data.js +162 -0
  52. package/lib/flows/steps/rerun/prepare-well-and-stream-data.js +188 -0
  53. package/lib/flows/steps/rerun/rerun.js +13 -0
  54. package/lib/flows/steps/zip-cleanup.js +17 -0
  55. package/lib/flows/steps/zip-create-archive.js +15 -0
  56. package/lib/flows/steps/zip-file-list-resolve.js +266 -0
  57. package/lib/flows/steps/zip-prepare.js +20 -0
  58. package/lib/flows/steps/zip.js +6 -0
  59. package/lib/flows/zip-simple.js +6 -0
  60. package/lib/flows/zip.js +7 -0
  61. package/lib/helpers/cli-version.js +150 -0
  62. package/lib/helpers/commands.js +13 -0
  63. package/lib/helpers/logger.js +35 -0
  64. package/lib/helpers/manifest.js +82 -0
  65. package/lib/helpers/resolve-app-runtime.js +132 -0
  66. package/lib/helpers/utils.js +97 -0
  67. package/lib/helpers/versioning.js +94 -0
  68. package/lib/main.js +64 -0
  69. package/lib/options/api-key.js +6 -0
  70. package/lib/options/app-key.js +6 -0
  71. package/lib/options/app-version.js +3 -0
  72. package/lib/options/bump-version.js +19 -0
  73. package/lib/options/cache.js +11 -0
  74. package/lib/options/env.js +3 -0
  75. package/lib/options/original-cwd.js +3 -0
  76. package/lib/options/silent.js +3 -0
  77. package/package.json +1 -0
  78. package/template_extensions/corva/.commitlintrc.json +6 -0
  79. package/template_extensions/corva/.eslintrc +32 -0
  80. package/template_extensions/corva/.github/pull_request_template.md +14 -0
  81. package/template_extensions/corva/.github/workflows/code-checks.yml +15 -0
  82. package/template_extensions/corva/.github/workflows/develop.yml +19 -0
  83. package/template_extensions/corva/.github/workflows/feat-fix-delete.yml +14 -0
  84. package/template_extensions/corva/.github/workflows/feat-fix.yml +23 -0
  85. package/template_extensions/corva/.github/workflows/release-fix-X.X.X.yml +16 -0
  86. package/template_extensions/corva/.github/workflows/validate-pr-title.yml +19 -0
  87. package/template_extensions/corva/.husky/commit-msg +5 -0
  88. package/template_extensions/corva/.husky/pre-commit +4 -0
  89. package/template_extensions/corva/.release-please-manifest.json +3 -0
  90. package/template_extensions/corva/release-please-config.json +10 -0
  91. package/templates/scheduler_data-time/javascript/README.md +19 -0
  92. package/templates/scheduler_data-time/javascript/__tests__/processor.spec.js +15 -0
  93. package/templates/scheduler_data-time/javascript/index.js +15 -0
  94. package/templates/scheduler_data-time/python/README.md +31 -0
  95. package/templates/scheduler_data-time/python/lambda_function.py +7 -0
  96. package/templates/scheduler_data-time/python/test/__init__.py +0 -0
  97. package/templates/scheduler_data-time/python/test/app_test.py +10 -0
  98. package/templates/scheduler_data-time/typescript/README.md +25 -0
  99. package/templates/scheduler_data-time/typescript/__tests__/processor.spec.ts +15 -0
  100. package/templates/scheduler_data-time/typescript/index.ts +8 -0
  101. package/templates/scheduler_depth/javascript/README.md +19 -0
  102. package/templates/scheduler_depth/javascript/__tests__/processor.spec.js +17 -0
  103. package/templates/scheduler_depth/javascript/index.js +15 -0
  104. package/templates/scheduler_depth/python/README.md +31 -0
  105. package/templates/scheduler_depth/python/lambda_function.py +7 -0
  106. package/templates/scheduler_depth/python/test/__init__.py +0 -0
  107. package/templates/scheduler_depth/python/test/app_test.py +10 -0
  108. package/templates/scheduler_depth/typescript/README.md +25 -0
  109. package/templates/scheduler_depth/typescript/__tests__/processor.spec.ts +17 -0
  110. package/templates/scheduler_depth/typescript/index.ts +8 -0
  111. package/templates/scheduler_natural-time/javascript/README.md +19 -0
  112. package/templates/scheduler_natural-time/javascript/__tests__/processor.spec.js +15 -0
  113. package/templates/scheduler_natural-time/javascript/index.js +15 -0
  114. package/templates/scheduler_natural-time/python/README.md +31 -0
  115. package/templates/scheduler_natural-time/python/lambda_function.py +7 -0
  116. package/templates/scheduler_natural-time/python/test/__init__.py +0 -0
  117. package/templates/scheduler_natural-time/python/test/app_test.py +10 -0
  118. package/templates/scheduler_natural-time/typescript/README.md +25 -0
  119. package/templates/scheduler_natural-time/typescript/__tests__/processor.spec.ts +15 -0
  120. package/templates/scheduler_natural-time/typescript/index.ts +8 -0
  121. package/templates/stream_depth/javascript/README.md +19 -0
  122. package/templates/stream_depth/javascript/__tests__/processor.spec.js +20 -0
  123. package/templates/stream_depth/javascript/index.js +14 -0
  124. package/templates/stream_depth/python/README.md +31 -0
  125. package/templates/stream_depth/python/lambda_function.py +7 -0
  126. package/templates/stream_depth/python/test/__init__.py +0 -0
  127. package/templates/stream_depth/python/test/app_test.py +16 -0
  128. package/templates/stream_depth/typescript/README.md +25 -0
  129. package/templates/stream_depth/typescript/__tests__/processor.spec.ts +20 -0
  130. package/templates/stream_depth/typescript/index.ts +8 -0
  131. package/templates/stream_time/javascript/README.md +19 -0
  132. package/templates/stream_time/javascript/__tests__/processor.spec.js +14 -0
  133. package/templates/stream_time/javascript/index.js +14 -0
  134. package/templates/stream_time/python/README.md +31 -0
  135. package/templates/stream_time/python/lambda_function.py +7 -0
  136. package/templates/stream_time/python/test/__init__.py +0 -0
  137. package/templates/stream_time/python/test/app_test.py +16 -0
  138. package/templates/stream_time/typescript/README.md +25 -0
  139. package/templates/stream_time/typescript/__tests__/processor.spec.ts +14 -0
  140. package/templates/stream_time/typescript/index.ts +8 -0
  141. package/templates/task/javascript/README.md +19 -0
  142. package/templates/task/javascript/__tests__/processor.spec.js +16 -0
  143. package/templates/task/javascript/index.js +15 -0
  144. package/templates/task/python/README.md +31 -0
  145. package/templates/task/python/lambda_function.py +7 -0
  146. package/templates/task/python/test/__init__.py +0 -0
  147. package/templates/task/python/test/app_test.py +8 -0
  148. package/templates/task/typescript/README.md +25 -0
  149. package/templates/task/typescript/__tests__/processor.spec.ts +16 -0
  150. package/templates/task/typescript/index.ts +8 -0
  151. package/templates/ui/javascript/.codex/config.toml +3 -0
  152. package/templates/ui/javascript/.cursor/mcp.json +8 -0
  153. package/templates/ui/javascript/.eslintrc +11 -0
  154. package/templates/ui/javascript/.mcp.json +8 -0
  155. package/templates/ui/javascript/.prettierrc +1 -0
  156. package/templates/ui/javascript/AGENTS.md +304 -0
  157. package/templates/ui/javascript/CLAUDE.md +1 -0
  158. package/templates/ui/javascript/README.md +31 -0
  159. package/templates/ui/javascript/config/jest/babelTransform.js +16 -0
  160. package/templates/ui/javascript/config/jest/cssTransform.js +16 -0
  161. package/templates/ui/javascript/config/jest/fileTransform.js +48 -0
  162. package/templates/ui/javascript/config/jest/globalSetup.js +5 -0
  163. package/templates/ui/javascript/config/jest/setupTests.js +30 -0
  164. package/templates/ui/javascript/config-overrides.js +10 -0
  165. package/templates/ui/javascript/gitignore +27 -0
  166. package/templates/ui/javascript/src/App.completion.js +52 -0
  167. package/templates/ui/javascript/src/App.drilling.js +49 -0
  168. package/templates/ui/javascript/src/App.scss +17 -0
  169. package/templates/ui/javascript/src/AppSettings.js +28 -0
  170. package/templates/ui/javascript/src/__tests__/App.test.js +26 -0
  171. package/templates/ui/javascript/src/__tests__/AppSettings.test.js +28 -0
  172. package/templates/ui/javascript/src/__tests__/TestsExample.test.js +37 -0
  173. package/templates/ui/javascript/src/assets/logo.svg +7 -0
  174. package/templates/ui/javascript/src/constants.js +3 -0
  175. package/templates/ui/javascript/src/index.js +8 -0
  176. package/templates/ui/typescript/.codex/config.toml +3 -0
  177. package/templates/ui/typescript/.cursor/mcp.json +8 -0
  178. package/templates/ui/typescript/.eslintrc +28 -0
  179. package/templates/ui/typescript/.mcp.json +8 -0
  180. package/templates/ui/typescript/.prettierrc +1 -0
  181. package/templates/ui/typescript/AGENTS.md +344 -0
  182. package/templates/ui/typescript/CLAUDE.md +1 -0
  183. package/templates/ui/typescript/README.md +31 -0
  184. package/templates/ui/typescript/config/jest/babelTransform.js +16 -0
  185. package/templates/ui/typescript/config/jest/cssTransform.js +16 -0
  186. package/templates/ui/typescript/config/jest/fileTransform.js +48 -0
  187. package/templates/ui/typescript/config/jest/globalSetup.js +5 -0
  188. package/templates/ui/typescript/config/jest/setupTests.js +30 -0
  189. package/templates/ui/typescript/config-overrides.js +10 -0
  190. package/templates/ui/typescript/gitignore +27 -0
  191. package/templates/ui/typescript/src/App.completion.tsx +52 -0
  192. package/templates/ui/typescript/src/App.drilling.tsx +49 -0
  193. package/templates/ui/typescript/src/App.scss +17 -0
  194. package/templates/ui/typescript/src/AppSettings.tsx +28 -0
  195. package/templates/ui/typescript/src/__mocks__/mockData.ts +22 -0
  196. package/templates/ui/typescript/src/__tests__/App.test.tsx +27 -0
  197. package/templates/ui/typescript/src/__tests__/AppSettings.test.tsx +28 -0
  198. package/templates/ui/typescript/src/__tests__/TestsExample.test.tsx +37 -0
  199. package/templates/ui/typescript/src/assets/logo.svg +7 -0
  200. package/templates/ui/typescript/src/constants.ts +3 -0
  201. package/templates/ui/typescript/src/custom.d.ts +19 -0
  202. package/templates/ui/typescript/src/index.js +8 -0
  203. package/templates/ui/typescript/src/types.ts +3 -0
  204. package/templates/ui/typescript/tsconfig.json +7 -0
@@ -0,0 +1,385 @@
1
+ import debugFn from 'debug';
2
+ import got from 'got';
3
+ import { StepError } from './step-error.js';
4
+ import { OVERRIDE_CACHE_BEHAVIOR, DELETE_CACHE_BEHAVIOR } from './../../constants/cache.js';
5
+
6
+ const debug = debugFn('cca:api');
7
+
8
+ /**
9
+ * Connect to Corva API
10
+ *
11
+ */
12
+ export class Api {
13
+ /**
14
+ * @type {import('got').Got}
15
+ */
16
+ #api;
17
+
18
+ constructor(envName, apiKey, authToken = null) {
19
+ const prefixUrl = `https://api${envName === 'production' ? '' : `.${envName}`}.corva.ai`;
20
+
21
+ this.#api = got.extend({
22
+ prefixUrl,
23
+ retry: { limit: 0 },
24
+ headers: {
25
+ 'Authorization': authToken ? `Bearer ${authToken}` : `API ${apiKey}`,
26
+ 'Content-Type': 'application/json',
27
+ 'Accept': 'application/json',
28
+ },
29
+ hooks: {
30
+ beforeRequest: [debug],
31
+ },
32
+ });
33
+ }
34
+
35
+ /**
36
+ * Get app by appKey
37
+ *
38
+ * @public
39
+ *
40
+ * @param {string} appKey
41
+ *
42
+ * @returns {object}
43
+ */
44
+ async getAppByKey(appKey) {
45
+ try {
46
+ const { data } = await this.#api.get(`v2/apps/${appKey}`).json();
47
+
48
+ if (!data) {
49
+ throw new StepError(
50
+ `App with key - ${appKey}, does not exist.\nThe key search is case-sensitive. You might need to update the app key in your app to exactly match the key.`,
51
+ );
52
+ }
53
+
54
+ return data;
55
+ } catch (error) {
56
+ if (error?.response?.statusCode === 404) {
57
+ throw new StepError(
58
+ `App with key - ${appKey}, does not exist.\nThe key search is case-sensitive. You might need to update the app key in your app to exactly match the key.`,
59
+ { cause: error },
60
+ );
61
+ }
62
+ // If error has a response, it's an API exception
63
+ else if (error?.response) {
64
+ throw new StepError(`getAppByKey request failed, code:${error?.response?.statusCode}`);
65
+ }
66
+
67
+ throw error;
68
+ }
69
+ }
70
+
71
+ /**
72
+ * Get app datasets
73
+ *
74
+ * @public
75
+ *
76
+ * @param {string} appId
77
+ *
78
+ * @returns {object}
79
+ */
80
+ async getAppDatasetsOperationWrite(appId) {
81
+ const { data } = await this.#api
82
+ .get(`v2/apps/${appId}/app_datasets?dataset_operation=write&fields[]=app_dataset.dataset_name`)
83
+ .json();
84
+
85
+ return data;
86
+ }
87
+
88
+ /**
89
+ * Get asset details
90
+ *
91
+ * @public
92
+ *
93
+ * @param {string} assetId
94
+ *
95
+ * @returns {Promise<object[]>}
96
+ */
97
+ async getAssetById(assetId) {
98
+ const { data } = await this.#api.get(`v2/assets/${assetId}`).json();
99
+
100
+ return data;
101
+ }
102
+
103
+ /**
104
+ * Get assets streams by ids
105
+ *
106
+ * @public
107
+ *
108
+ * @param {string[]} assetIds
109
+ * @param {string[]} segments
110
+ * @param {string[]} statuses
111
+ *
112
+ * @returns {Promise<object[]>}
113
+ */
114
+ async getStreamsByAssetIds(assetIds, segments, statuses = ['complete']) {
115
+ const searchParams = new URLSearchParams([
116
+ ...assetIds.map((assetId) => ['asset_id[]', assetId]),
117
+ ...segments.map((segment) => ['segment[]', segment]),
118
+ ...statuses.map((status) => ['status[]', status]),
119
+ ]);
120
+
121
+ return this.#api.get(`v1/app_streams`, { searchParams }).json();
122
+ }
123
+
124
+ /**
125
+ * Get all assets
126
+ *
127
+ * @public
128
+ *
129
+ * @param {string[]} statuses
130
+ * @param {number} companyId
131
+ * @param {number} perPage
132
+ *
133
+ * @returns {Promise<object[]>}
134
+ */
135
+ async getAllAssets(statuses = ['active'], companyId = null, perPage = 2000) {
136
+ const searchParams = [['per_page', perPage]];
137
+
138
+ if (companyId) {
139
+ searchParams.push(['company_id', companyId]);
140
+ }
141
+
142
+ if (statuses?.length) {
143
+ searchParams.push(...statuses.map((status) => ['status[]', status]));
144
+ }
145
+
146
+ const { data } = await this.#api.get(`v2/assets`, { searchParams: new URLSearchParams(searchParams) }).json();
147
+
148
+ return data;
149
+ }
150
+
151
+ /**
152
+ * Get wells data by asset id
153
+ *
154
+ * @public
155
+ *
156
+ * @param {string} assetId
157
+ *
158
+ * @returns {object[]}
159
+ */
160
+ async getWellByAssetId(assetId) {
161
+ const { wells } = await this.#api
162
+ .post('v2/assets/resolve', {
163
+ json: { assets: [assetId] },
164
+ })
165
+ .json();
166
+
167
+ if (!wells || !wells.length) {
168
+ throw new StepError(`Could not find wells by asset ID - ${assetId}`);
169
+ }
170
+
171
+ return wells;
172
+ }
173
+
174
+ /**
175
+ * Queue app run for create new task
176
+ *
177
+ * @public
178
+ *
179
+ * @param {string} appId
180
+ * @param {string} version
181
+ * @param {number} interval
182
+ * @param {string} wellId
183
+ * @param {string[]} appDatasetsNames
184
+ * @param {string} streamId
185
+ * @param {number} appConnectionId
186
+ *
187
+ * @returns {object}
188
+ */
189
+ async queueAppRun(appId, version, interval, wellId, appDatasetsNames, streamId, appConnectionId, cache) {
190
+ const json = {
191
+ cache_behavior: cache ? OVERRIDE_CACHE_BEHAVIOR : DELETE_CACHE_BEHAVIOR,
192
+ cache_override: cache,
193
+ app_run: {
194
+ app_stream_id: streamId,
195
+ well_id: wellId,
196
+ app_version: version,
197
+ datasets: appDatasetsNames,
198
+ settings: {
199
+ end: 0,
200
+ invokes: null,
201
+ records_per_event: 300,
202
+ start: 0,
203
+ },
204
+ },
205
+ app_connection_id: appConnectionId,
206
+ };
207
+
208
+ if (interval) {
209
+ json.app_run.settings.interval = interval;
210
+ }
211
+
212
+ const { data } = await this.#api.post(`v2/apps/${appId}/app_runs`, { json }).json();
213
+
214
+ return data;
215
+ }
216
+
217
+ /**
218
+ * Get all active(status - pending or in_progress or running) runs by app ID
219
+ *
220
+ * @public
221
+ *
222
+ * @param {string} appId
223
+ *
224
+ * @returns {object[]}
225
+ */
226
+ async getAppRuns(appId) {
227
+ const { data } = await this.#api
228
+ .get(`v2/apps/${appId}/app_runs?page=1&per_page=500&status[]=pending&status[]=in_progress&status[]=running`)
229
+ .json();
230
+
231
+ return data;
232
+ }
233
+
234
+ /**
235
+ * Upload packages
236
+ *
237
+ * @public
238
+ *
239
+ * @param {string} appKey
240
+ * @param {object} formData
241
+ *
242
+ * @returns
243
+ */
244
+ async uploadPackages(appKey, formData) {
245
+ const uploadURL = `v2/apps/${appKey}/packages/upload`;
246
+
247
+ try {
248
+ const { data } = await this.#api
249
+ .post(uploadURL, {
250
+ headers: formData.getHeaders(),
251
+ body: formData,
252
+ })
253
+ .json();
254
+
255
+ return {
256
+ id: data.id,
257
+ status: data.attributes.status,
258
+ isDeletedDueToLimit: data.attributes.deleted_due_to_limit,
259
+ };
260
+ } catch (e) {
261
+ throw new StepError(`${JSON.parse(e.response.body).message || ''} \nPOST: ${uploadURL} failed.`, { cause: e });
262
+ }
263
+ }
264
+
265
+ /**
266
+ * @param {string} appId
267
+ * @param {string} id
268
+ * @param {string} notes
269
+ *
270
+ * @returns { Promise<{id: number, status: string}>}
271
+ */
272
+ async addNotes(appId, id, notes) {
273
+ const { data } = await this.#api
274
+ .patch(`v2/apps/${appId}/packages/${id}`, {
275
+ json: { package: { notes } },
276
+ })
277
+ .json();
278
+
279
+ return {
280
+ id: data.id,
281
+ status: data.attributes.status,
282
+ };
283
+ }
284
+
285
+ /**
286
+ * @param {string} appId
287
+ * @param {string} uploadId
288
+ *
289
+ * @returns { Promise<{id: number, status: string, notes: string}>}
290
+ */
291
+ async checkApp(appId, uploadId) {
292
+ const { data } = await this.#api.get(`v2/apps/${appId}/packages/${uploadId}`).json();
293
+
294
+ return {
295
+ id: data.id,
296
+ status: data.attributes.status,
297
+ notes: data.attributes.notes ?? '',
298
+ };
299
+ }
300
+
301
+ /**
302
+ * @param {string} appId
303
+ * @param {string} uploadId
304
+ *
305
+ * @returns { Promise<void>}
306
+ */
307
+ deleteAppUpload(appId, uploadId) {
308
+ return this.#api.delete(`v2/apps/${appId}/packages/${uploadId}`).json();
309
+ }
310
+
311
+ /**
312
+ * @param {string} appId
313
+ * @param {string} id
314
+ *
315
+ * @returns { Promise<{id: number, status: string}>}
316
+ */
317
+ async publishApp(appId, id) {
318
+ console.log(`v2/apps/${appId}/packages/${id}`, {
319
+ json: { package: { status: 'published' } },
320
+ });
321
+
322
+ const { data } = await this.#api
323
+ .patch(`v2/apps/${appId}/packages/${id}`, {
324
+ json: { package: { status: 'published' } },
325
+ })
326
+ .json();
327
+
328
+ console.log('done');
329
+
330
+ return {
331
+ id: data.id,
332
+ status: data.attributes.status,
333
+ };
334
+ }
335
+
336
+ /**
337
+ * Get app packages
338
+ *
339
+ * @param {string} appId
340
+ *
341
+ * @returns { Promise<object[]>}
342
+ */
343
+ async getAppPackages(appId) {
344
+ const { data } = await this.#api.get(`v2/apps/${appId}/packages`).json();
345
+
346
+ return data;
347
+ }
348
+
349
+ /**
350
+ * Connect app to the stream
351
+ *
352
+ * @public
353
+ *
354
+ * @param {string} appId
355
+ * @param {string} streamId
356
+ * @param {object} settings
357
+ * @param {string} status
358
+ *
359
+ * @returns { Promise<object> }
360
+ */
361
+ async connectAppToStream(appId, streamId, settings, status = 'active') {
362
+ const json = {
363
+ app_stream_id: streamId,
364
+ app_id: appId,
365
+ status,
366
+ settings,
367
+ scheduler_type: settings.scheduler_type,
368
+ };
369
+
370
+ return this.#api.post('v1/app_connections', { json }).json();
371
+ }
372
+
373
+ /**
374
+ * @param {string} appId
375
+ * @param {string} id
376
+ * @param {'DEV' | 'BETA' | 'PROD'} label
377
+ *
378
+ * @returns { Promise<{id: number, status: string}>}
379
+ */
380
+ async putLabel(appId, id, label) {
381
+ await this.#api.patch(`v2/apps/${appId}/packages/${id}`, {
382
+ json: { package: { label } },
383
+ });
384
+ }
385
+ }
@@ -0,0 +1,83 @@
1
+ import archiver from 'archiver';
2
+ import debugFn from 'debug';
3
+
4
+ const debug = debugFn('cca:zip');
5
+
6
+ import { createWriteStream, promises as fs } from 'node:fs';
7
+ import path from 'node:path';
8
+
9
+ export const createZipArchive = async (dirName, zipName, itemsToZip = []) => {
10
+ const filePath = path.resolve(dirName, zipName);
11
+ const archive = archiver.create('zip', {});
12
+ const output = createWriteStream(filePath);
13
+
14
+ // pipe archive data to the file
15
+ archive.pipe(output);
16
+
17
+ // eslint-disable-next-line no-async-promise-executor
18
+ await new Promise(async (resolve, reject) => {
19
+ output.once('close', resolve).once('end', function () {
20
+ debug('Data has been drained');
21
+ });
22
+
23
+ archive.on('warning', function (err) {
24
+ if (err.code === 'ENOENT') {
25
+ console.warn(err.message);
26
+
27
+ return;
28
+ }
29
+
30
+ throw err;
31
+ });
32
+
33
+ archive.once('error', reject);
34
+
35
+ const dataToZip = await getDataToZip(itemsToZip, dirName);
36
+
37
+ for (const item of dataToZip) {
38
+ if (item.isDir) {
39
+ debug(`Adding directory %s -> %s`, item.path, item.name);
40
+ archive.directory(item.path, item.name);
41
+
42
+ continue;
43
+ }
44
+
45
+ debug(`Adding file %s -> %s`, item.path, item.name);
46
+ archive.file(item.path, { name: item.name });
47
+ }
48
+
49
+ archive.finalize();
50
+ });
51
+
52
+ return archive.pointer();
53
+ };
54
+
55
+ const getDataToZip = async (itemsToZip, dirName) => {
56
+ const promises = itemsToZip.map(async (name) => {
57
+ const nameWasProvided = typeof name === 'string';
58
+ const filePath = nameWasProvided ? path.resolve(dirName, name) : name.path;
59
+ const fileName = nameWasProvided ? name : name.name;
60
+
61
+ const { exists, isDir } = await fs
62
+ .lstat(filePath)
63
+ .then((stat) => ({
64
+ exists: true,
65
+ isDir: stat.isDirectory(),
66
+ }))
67
+ .catch(() => {
68
+ debug(`%s location not exist, filtering it out`, filePath);
69
+
70
+ return { exists: false, isDir: false };
71
+ });
72
+
73
+ return {
74
+ name: fileName,
75
+ path: filePath,
76
+ exists,
77
+ isDir,
78
+ };
79
+ });
80
+ const allData = await Promise.all(promises);
81
+
82
+ return allData.filter((f) => f.exists);
83
+ };
@@ -0,0 +1,30 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import os from 'node:os';
3
+ import { resolve } from 'node:path';
4
+
5
+ import debugFn from 'debug';
6
+ import { StepError } from './step-error.js';
7
+
8
+ const debug = debugFn('cca:json');
9
+
10
+ export const loadJson = async (dirName, fileName) => {
11
+ const fullPath = resolve(dirName, fileName);
12
+
13
+ try {
14
+ debug('Loading file %s', fullPath);
15
+
16
+ const manifest = await fs.readFile(fullPath, 'utf8');
17
+
18
+ return JSON.parse(manifest);
19
+ } catch (e) {
20
+ if (e.code === 'ENOENT') {
21
+ throw new StepError(`${fileName} was not found in ${resolve(dirName)}`, { cause: e });
22
+ }
23
+
24
+ throw e;
25
+ }
26
+ };
27
+
28
+ export const saveJson = async (dirName, fileName, data) => {
29
+ return fs.writeFile(resolve(dirName, fileName), JSON.stringify(data, null, 2) + os.EOL);
30
+ };
@@ -0,0 +1,81 @@
1
+ import set from 'lodash/set.js';
2
+ import { APP_TYPES, APP_RUNTIMES } from '../../constants/cli.js';
3
+ import {
4
+ SCHEDULER_TYPE_DATA_TIME,
5
+ SCHEDULER_TYPE_DEPTH,
6
+ SCHEDULER_TYPE_NATURAL_TIME,
7
+ } from '../../constants/manifest.js';
8
+
9
+ const SCHEDULER_MAPPING = [SCHEDULER_TYPE_DATA_TIME, SCHEDULER_TYPE_DEPTH, SCHEDULER_TYPE_NATURAL_TIME].reduce(
10
+ (acc, type) => set(acc, type.value, type.name.toLowerCase().replace(/ /, '-')),
11
+ {},
12
+ );
13
+
14
+ const NODE_RUNTIMES = [APP_RUNTIMES.NODE18, APP_RUNTIMES.NODE20, APP_RUNTIMES.NODE22, APP_RUNTIMES.NODE24];
15
+
16
+ export class Manifest {
17
+ constructor(manifest) {
18
+ this.manifest = manifest;
19
+ }
20
+
21
+ get runtime() {
22
+ return this.manifest.settings.runtime;
23
+ }
24
+
25
+ get type() {
26
+ return this.manifest.application.type;
27
+ }
28
+
29
+ get subtype() {
30
+ if (this.isScheduler()) {
31
+ return SCHEDULER_MAPPING[this.manifest.settings.app.scheduler_type];
32
+ }
33
+
34
+ if (this.isStream()) {
35
+ return this.manifest.settings.app.log_type;
36
+ }
37
+
38
+ return '';
39
+ }
40
+
41
+ get templateName() {
42
+ return this.type + (this.isScheduler() || this.isStream() ? `_${this.subtype}` : '');
43
+ }
44
+
45
+ get name() {
46
+ return this.manifest.application.name;
47
+ }
48
+
49
+ get unix_name() {
50
+ // todo: npm scopes?
51
+ return this.manifest.application.key.replace(/\W+/gi, '_').toLowerCase();
52
+ }
53
+
54
+ get description() {
55
+ return this.manifest.application.description;
56
+ }
57
+
58
+ isNode() {
59
+ return NODE_RUNTIMES.includes(this.manifest.settings.runtime);
60
+ }
61
+
62
+ isUi() {
63
+ return this.manifest.application.type === APP_TYPES.UI;
64
+ }
65
+
66
+ isJs() {
67
+ return this.isUi() || this.isNode();
68
+ }
69
+
70
+ isPython() {
71
+ return this.manifest.settings.runtime.startsWith('python');
72
+ }
73
+
74
+ isScheduler() {
75
+ return this.manifest.application.type === APP_TYPES.SCHEDULER;
76
+ }
77
+
78
+ isStream() {
79
+ return this.manifest.application.type === APP_TYPES.STREAM;
80
+ }
81
+ }
@@ -0,0 +1,142 @@
1
+ import chalk from 'chalk';
2
+ import terminalLink from 'terminal-link';
3
+
4
+ import { logger } from '../../helpers/logger.js';
5
+
6
+ /**
7
+ * Console notification
8
+ *
9
+ */
10
+ export class Notification {
11
+ #prefixUrl;
12
+
13
+ constructor(envName) {
14
+ this.#prefixUrl = `https://app${envName === 'production' ? '.' : `.${envName}.`}corva.ai`;
15
+ }
16
+
17
+ /**
18
+ * Create link
19
+ *
20
+ * @private
21
+ *
22
+ * @param {string} title
23
+ * @param {string} url
24
+ *
25
+ * @returns {string}
26
+ */
27
+ _createLink(title, url) {
28
+ return this._addLinkDecoration(terminalLink(title, url));
29
+ }
30
+
31
+ /**
32
+ * Print to console line break
33
+ *
34
+ * @public
35
+ *
36
+ * @returns {void}
37
+ */
38
+ printLineBreak() {
39
+ logger.write('\n');
40
+ }
41
+
42
+ /**
43
+ * Print to console text
44
+ *
45
+ * @public
46
+ *
47
+ * @param {string} text
48
+ *
49
+ * @returns {void}
50
+ */
51
+ print(text) {
52
+ this.printLineBreak();
53
+ logger.write(text);
54
+ }
55
+
56
+ /**
57
+ * Add a link styles
58
+ *
59
+ * @private
60
+ *
61
+ * @param {string} context
62
+ *
63
+ * @returns {string}
64
+ */
65
+ _addLinkDecoration(context) {
66
+ return chalk.blue.underline(context);
67
+ }
68
+
69
+ /**
70
+ * Add an error styles
71
+ *
72
+ * @private
73
+ *
74
+ * @param {string} context
75
+ *
76
+ * @returns {string}
77
+ */
78
+ _addErrorDecoration(context) {
79
+ return chalk.red.bold(context);
80
+ }
81
+
82
+ /**
83
+ * Get stream link
84
+ *
85
+ * @public
86
+ *
87
+ * @param {string} title
88
+ * @param {string} streamId
89
+ *
90
+ * @returns {string}
91
+ */
92
+ getStreamLink(title, streamId) {
93
+ const streamUrl = `${this.#prefixUrl}/config/streams/${streamId}`;
94
+
95
+ return this._createLink(title, streamUrl);
96
+ }
97
+
98
+ /**
99
+ * Print stream link
100
+ *
101
+ * @public
102
+ *
103
+ * @param {string} title
104
+ * @param {string} streamId
105
+ *
106
+ * @returns {avoid}
107
+ */
108
+ printStreamLink(title, streamId) {
109
+ const link = this.getStreamLink(title, streamId);
110
+
111
+ this.print(link);
112
+ }
113
+
114
+ /**
115
+ * Get asset link
116
+ *
117
+ * @public
118
+ *
119
+ * @param {string} title
120
+ * @param {string} assetId
121
+ *
122
+ * @returns {string}
123
+ */
124
+ getAssetLink(title, assetId) {
125
+ const assetUrl = `${this.#prefixUrl}/assets/${assetId}`;
126
+
127
+ return this._createLink(title, assetUrl);
128
+ }
129
+
130
+ /**
131
+ * Print an error
132
+ *
133
+ * @public
134
+ *
135
+ * @param {string} error
136
+ *
137
+ * @returns {void}
138
+ */
139
+ printError(error) {
140
+ this.print(this._addErrorDecoration(error));
141
+ }
142
+ }