@forgehive/forge-cli 0.2.3 → 0.2.4

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.
package/dist/runner.js CHANGED
@@ -26,7 +26,7 @@ const runner = new runner_1.Runner((data) => {
26
26
  const { _, ...filteredObj } = data;
27
27
  return {
28
28
  taskName: String(_[0]),
29
- action: String(_[1]),
29
+ action: _[1] ?? '',
30
30
  args: filteredObj
31
31
  };
32
32
  });
@@ -53,7 +53,7 @@ runner.setHandler(async (data) => {
53
53
  const parsedArgs = runner.parseArguments(data);
54
54
  const { taskName, action, args } = parsedArgs;
55
55
  console.log('========================================');
56
- console.log('Running:', taskName, action, args);
56
+ console.log(`Running: ${taskName} ${action ? action : ''} ${JSON.stringify(args)}`);
57
57
  console.log('========================================');
58
58
  const task = runner.getTask(taskName);
59
59
  if (!task) {
@@ -3,11 +3,7 @@ export declare const info: import("@forgehive/task").TaskInstanceType<(argv: {},
3
3
  loadCurrentProfile: (args: {}) => Promise<Promise<import("../types").Profile>>;
4
4
  }>) => Promise<{
5
5
  version: any;
6
- profile: {
7
- name: string;
8
- url: string;
9
- apiKey: string;
10
- };
6
+ profile: {};
11
7
  }>, {
12
8
  readFile: (filePath: string) => Promise<string>;
13
9
  loadCurrentProfile: (args: {}) => Promise<Promise<import("../types").Profile>>;
@@ -51,13 +51,21 @@ exports.info = (0, task_1.createTask)(schema, boundaries, async function (_argv,
51
51
  const packageJsonPath = path.join(__dirname, '../../../package.json');
52
52
  const packageJsonContent = await readFile(packageJsonPath);
53
53
  const packageJson = JSON.parse(packageJsonContent);
54
- const profile = await loadCurrentProfile({});
55
- return {
54
+ const info = {
56
55
  version: packageJson.version,
57
- profile: {
56
+ profile: {}
57
+ };
58
+ let profile;
59
+ try {
60
+ profile = await loadCurrentProfile({});
61
+ info.profile = {
58
62
  name: profile.name,
59
63
  url: profile.url,
60
64
  apiKey: profile.apiKey
61
- }
62
- };
65
+ };
66
+ }
67
+ catch (error) {
68
+ console.log('No default profile set. Please run forge task:run auth:add to create a profile.');
69
+ }
70
+ return info;
63
71
  });
@@ -17,10 +17,11 @@ export declare const publish: import("@forgehive/task").TaskInstanceType<(argv:
17
17
  readFileUtf8: (filePath: string) => Promise<string>;
18
18
  readFileBinary: (filePath: string) => Promise<Buffer>;
19
19
  publishTask: (data: any, profile: Profile) => Promise<any>;
20
+ uploadBundleWithPresignedUrl: (presignedUrl: string, bundleContent: Buffer) => Promise<any>;
20
21
  ensureBuildsFolder: () => Promise<string>;
21
22
  }>) => Promise<{
22
23
  descriptor: import("../types").TaskDescriptor;
23
- publishResponse: any;
24
+ publish: boolean;
24
25
  }>, {
25
26
  getCwd: () => Promise<string>;
26
27
  loadConf: (args: {}) => Promise<Promise<import("../types").ForgeConf>>;
@@ -37,5 +38,6 @@ export declare const publish: import("@forgehive/task").TaskInstanceType<(argv:
37
38
  readFileUtf8: (filePath: string) => Promise<string>;
38
39
  readFileBinary: (filePath: string) => Promise<Buffer>;
39
40
  publishTask: (data: any, profile: Profile) => Promise<any>;
41
+ uploadBundleWithPresignedUrl: (presignedUrl: string, bundleContent: Buffer) => Promise<any>;
40
42
  ensureBuildsFolder: () => Promise<string>;
41
43
  }>;
@@ -37,15 +37,32 @@ const boundaries = {
37
37
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
38
38
  publishTask: async (data, profile) => {
39
39
  const publishUrl = `${profile.url}/api/tasks/publish`;
40
- console.log(`Publishing task to ${publishUrl}...`);
41
40
  const authToken = `${profile.apiKey}:${profile.apiSecret}`;
42
- const response = await axios_1.default.post(publishUrl, data, {
41
+ try {
42
+ const response = await axios_1.default.post(publishUrl, data, {
43
+ headers: {
44
+ Authorization: `Bearer ${authToken}`,
45
+ 'Content-Type': 'application/json'
46
+ }
47
+ });
48
+ return response.data;
49
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
50
+ }
51
+ catch (error) {
52
+ if (error.response?.data?.error.includes('Bundle size')) {
53
+ throw new Error('Bundle size exceeds the maximum allowed size of 25MB');
54
+ }
55
+ throw new Error('Failed to publish task source code and metadata');
56
+ }
57
+ },
58
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
59
+ uploadBundleWithPresignedUrl: async (presignedUrl, bundleContent) => {
60
+ const response = await axios_1.default.put(presignedUrl, bundleContent, {
43
61
  headers: {
44
- Authorization: `Bearer ${authToken}`,
45
- 'Content-Type': 'application/json'
62
+ 'Content-Type': 'application/octet-stream'
46
63
  }
47
64
  });
48
- return response.data;
65
+ return response.status === 200;
49
66
  },
50
67
  ensureBuildsFolder: async () => {
51
68
  const buildsPath = path_1.default.join(os_1.default.homedir(), '.forge', 'builds');
@@ -58,7 +75,7 @@ const boundaries = {
58
75
  return buildsPath;
59
76
  }
60
77
  };
61
- exports.publish = (0, task_1.createTask)(schema, boundaries, async function ({ descriptorName }, { getCwd, ensureBuildsFolder, loadConf, bundleCreate, bundleLoad, readFileUtf8, readFileBinary, publishTask, loadCurrentProfile }) {
78
+ exports.publish = (0, task_1.createTask)(schema, boundaries, async function ({ descriptorName }, { getCwd, ensureBuildsFolder, loadConf, bundleCreate, bundleLoad, readFileUtf8, readFileBinary, publishTask, loadCurrentProfile, uploadBundleWithPresignedUrl }) {
62
79
  const cwd = await getCwd();
63
80
  const forgeJson = await loadConf({});
64
81
  const profile = await loadCurrentProfile({});
@@ -70,14 +87,12 @@ exports.publish = (0, task_1.createTask)(schema, boundaries, async function ({ d
70
87
  const entryPoint = path_1.default.join(cwd, taskDescriptor.path);
71
88
  const buildsPath = await ensureBuildsFolder();
72
89
  const outputFile = path_1.default.join(buildsPath, `${descriptorName}.js`);
73
- console.log('entryPoint:', entryPoint);
74
- console.log('buildsPath:', buildsPath);
75
- console.log('outputFile:', outputFile);
76
90
  // Bundle the task
77
91
  await bundleCreate({
78
92
  entryPoint,
79
93
  outputFile
80
94
  });
95
+ console.log('Bundle created...');
81
96
  // Load the bundled task
82
97
  const bundle = await bundleLoad({
83
98
  bundlePath: outputFile
@@ -87,9 +102,12 @@ exports.publish = (0, task_1.createTask)(schema, boundaries, async function ({ d
87
102
  const description = task.getDescription() ?? '';
88
103
  const schema = task.getSchema() || new schema_1.Schema({});
89
104
  const schemaDescriptor = schema.describe();
90
- // Read the task file content and bundle
105
+ // Read the task file content
91
106
  const sourceCode = await readFileUtf8(entryPoint);
92
107
  const bundleContent = await readFileBinary(outputFile);
108
+ // Get bundle size
109
+ const bundleSize = bundleContent.length;
110
+ // First, publish task metadata and get presigned URL for bundle upload
93
111
  const data = {
94
112
  ...taskDescriptor,
95
113
  taskName: descriptorName,
@@ -97,10 +115,21 @@ exports.publish = (0, task_1.createTask)(schema, boundaries, async function ({ d
97
115
  description,
98
116
  schemaDescriptor: JSON.stringify(schemaDescriptor),
99
117
  sourceCode,
100
- bundle: bundleContent.toString('base64')
118
+ bundleSize
101
119
  };
102
- // Publish to hive api server
103
- const response = await publishTask(data, profile);
104
- console.log('Publish response:', response);
105
- return { descriptor: taskDescriptor, publishResponse: response };
120
+ // Publish metadata to hive api server
121
+ console.log(`Publishing metadata and source code to ${profile.url}...`);
122
+ const publishResponse = await publishTask(data, profile);
123
+ // Upload bundle using the presigned URL
124
+ if (publishResponse.bundleUploadUrl) {
125
+ console.log('Uploading bundle...');
126
+ await uploadBundleWithPresignedUrl(publishResponse.bundleUploadUrl, bundleContent);
127
+ return {
128
+ descriptor: taskDescriptor,
129
+ publish: true
130
+ };
131
+ }
132
+ else {
133
+ throw new Error('Bundle upload failed');
134
+ }
106
135
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forgehive/forge-cli",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "TypeScript CLI application",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -25,9 +25,9 @@
25
25
  "esbuild": "^0.25.0",
26
26
  "handlebars": "^4.7.8",
27
27
  "minimist": "^1.2.8",
28
+ "@forgehive/task": "0.1.5",
28
29
  "@forgehive/record-tape": "0.0.2",
29
30
  "@forgehive/runner": "0.1.5",
30
- "@forgehive/task": "0.1.5",
31
31
  "@forgehive/schema": "0.1.4"
32
32
  },
33
33
  "devDependencies": {
package/src/runner.ts CHANGED
@@ -33,7 +33,7 @@ const runner = new Runner((data: ParsedArgs): CliParsedArguments => {
33
33
 
34
34
  return {
35
35
  taskName: String(_[0]),
36
- action: String(_[1]),
36
+ action: _[1] ?? '',
37
37
  args: filteredObj
38
38
  }
39
39
  })
@@ -66,7 +66,7 @@ runner.setHandler(async (data: ParsedArgs): Promise<unknown> => {
66
66
  const { taskName, action, args } = parsedArgs
67
67
 
68
68
  console.log('========================================')
69
- console.log('Running:', taskName, action, args)
69
+ console.log(`Running: ${taskName} ${action ? action : ''} ${JSON.stringify(args)}`)
70
70
  console.log('========================================')
71
71
 
72
72
  const task = runner.getTask(taskName)
@@ -22,19 +22,27 @@ export const info = createTask(
22
22
  async function (_argv, { loadCurrentProfile, readFile }) {
23
23
  const packageJsonPath = path.join(__dirname, '../../../package.json')
24
24
 
25
-
26
25
  const packageJsonContent = await readFile(packageJsonPath)
27
26
  const packageJson = JSON.parse(packageJsonContent)
28
27
 
29
- const profile = await loadCurrentProfile({})
30
-
31
- return {
28
+ const info = {
32
29
  version: packageJson.version,
33
- profile: {
30
+ profile: {}
31
+ }
32
+
33
+ let profile
34
+ try {
35
+ profile = await loadCurrentProfile({})
36
+
37
+ info.profile = {
34
38
  name: profile.name,
35
39
  url: profile.url,
36
40
  apiKey: profile.apiKey
37
41
  }
42
+ } catch (error) {
43
+ console.log('No default profile set. Please run forge task:run auth:add to create a profile.')
38
44
  }
45
+
46
+ return info
39
47
  }
40
48
  )
@@ -37,17 +37,34 @@ const boundaries = {
37
37
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
38
38
  publishTask: async (data: any, profile: Profile): Promise<any> => {
39
39
  const publishUrl = `${profile.url}/api/tasks/publish`
40
-
41
- console.log(`Publishing task to ${publishUrl}...`)
42
40
  const authToken = `${profile.apiKey}:${profile.apiSecret}`
43
- const response = await axios.post(publishUrl, data, {
41
+
42
+ try {
43
+ const response = await axios.post(publishUrl, data, {
44
+ headers: {
45
+ Authorization: `Bearer ${authToken}`,
46
+ 'Content-Type': 'application/json'
47
+ }
48
+ })
49
+
50
+ return response.data
51
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
52
+ } catch (error: any) {
53
+ if (error.response?.data?.error.includes('Bundle size')) {
54
+ throw new Error('Bundle size exceeds the maximum allowed size of 25MB')
55
+ }
56
+
57
+ throw new Error('Failed to publish task source code and metadata')
58
+ }
59
+ },
60
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
61
+ uploadBundleWithPresignedUrl: async (presignedUrl: string, bundleContent: Buffer): Promise<any> => {
62
+ const response = await axios.put(presignedUrl, bundleContent, {
44
63
  headers: {
45
- Authorization: `Bearer ${authToken}`,
46
- 'Content-Type': 'application/json'
64
+ 'Content-Type': 'application/octet-stream'
47
65
  }
48
66
  })
49
-
50
- return response.data
67
+ return response.status === 200
51
68
  },
52
69
 
53
70
  ensureBuildsFolder: async (): Promise<string> => {
@@ -74,7 +91,8 @@ export const publish = createTask(
74
91
  readFileUtf8,
75
92
  readFileBinary,
76
93
  publishTask,
77
- loadCurrentProfile
94
+ loadCurrentProfile,
95
+ uploadBundleWithPresignedUrl
78
96
  }) {
79
97
  const cwd = await getCwd()
80
98
  const forgeJson = await loadConf({})
@@ -91,16 +109,14 @@ export const publish = createTask(
91
109
  const buildsPath = await ensureBuildsFolder()
92
110
  const outputFile = path.join(buildsPath, `${descriptorName}.js`)
93
111
 
94
- console.log('entryPoint:', entryPoint)
95
- console.log('buildsPath:', buildsPath)
96
- console.log('outputFile:', outputFile)
97
-
98
112
  // Bundle the task
99
113
  await bundleCreate({
100
114
  entryPoint,
101
115
  outputFile
102
116
  })
103
117
 
118
+ console.log('Bundle created...')
119
+
104
120
  // Load the bundled task
105
121
  const bundle = await bundleLoad({
106
122
  bundlePath: outputFile
@@ -112,10 +128,14 @@ export const publish = createTask(
112
128
  const schema = task.getSchema() || new Schema({})
113
129
  const schemaDescriptor = schema.describe()
114
130
 
115
- // Read the task file content and bundle
131
+ // Read the task file content
116
132
  const sourceCode = await readFileUtf8(entryPoint)
117
133
  const bundleContent = await readFileBinary(outputFile)
118
134
 
135
+ // Get bundle size
136
+ const bundleSize = bundleContent.length
137
+
138
+ // First, publish task metadata and get presigned URL for bundle upload
119
139
  const data = {
120
140
  ...taskDescriptor,
121
141
  taskName: descriptorName,
@@ -123,13 +143,27 @@ export const publish = createTask(
123
143
  description,
124
144
  schemaDescriptor: JSON.stringify(schemaDescriptor),
125
145
  sourceCode,
126
- bundle: bundleContent.toString('base64')
146
+ bundleSize
127
147
  }
128
148
 
129
- // Publish to hive api server
130
- const response = await publishTask(data, profile)
131
-
132
- console.log('Publish response:', response)
133
- return { descriptor: taskDescriptor, publishResponse: response }
149
+ // Publish metadata to hive api server
150
+ console.log(`Publishing metadata and source code to ${profile.url}...`)
151
+ const publishResponse = await publishTask(data, profile)
152
+
153
+ // Upload bundle using the presigned URL
154
+ if (publishResponse.bundleUploadUrl) {
155
+ console.log('Uploading bundle...')
156
+ await uploadBundleWithPresignedUrl(
157
+ publishResponse.bundleUploadUrl,
158
+ bundleContent
159
+ )
160
+
161
+ return {
162
+ descriptor: taskDescriptor,
163
+ publish: true
164
+ }
165
+ } else {
166
+ throw new Error('Bundle upload failed')
167
+ }
134
168
  }
135
169
  )