@forgehive/hive-sdk 0.1.3 → 0.1.5
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/README.md +158 -19
- package/dist/index.d.ts +48 -1
- package/dist/index.js +312 -7
- package/dist/test/sendLogByUuid.test.d.ts +1 -0
- package/dist/test/sendLogByUuid.test.js +222 -0
- package/package.json +5 -3
- package/src/index.ts +396 -6
- package/src/test/sendLogByUuid.test.ts +272 -0
package/src/index.ts
CHANGED
|
@@ -1,9 +1,25 @@
|
|
|
1
1
|
import axios from 'axios'
|
|
2
2
|
import debug from 'debug'
|
|
3
|
+
import { v7 as uuidv7 } from 'uuid'
|
|
4
|
+
import fs from 'fs'
|
|
3
5
|
import type { ExecutionRecord } from '@forgehive/task'
|
|
4
6
|
|
|
5
7
|
const log = debug('hive-sdk')
|
|
6
8
|
|
|
9
|
+
interface ForgeConfig {
|
|
10
|
+
project: {
|
|
11
|
+
name: string
|
|
12
|
+
uuid: string
|
|
13
|
+
}
|
|
14
|
+
tasks: {
|
|
15
|
+
[taskName: string]: {
|
|
16
|
+
path: string
|
|
17
|
+
handler: string
|
|
18
|
+
uuid: string
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
7
23
|
// Metadata interface
|
|
8
24
|
export interface Metadata {
|
|
9
25
|
[key: string]: string
|
|
@@ -15,10 +31,12 @@ export type { ExecutionRecord } from '@forgehive/task'
|
|
|
15
31
|
// Configuration interface for HiveLogClient
|
|
16
32
|
export interface HiveLogClientConfig {
|
|
17
33
|
projectName: string
|
|
34
|
+
projectUuid?: string // Optional UUID for new endpoint
|
|
18
35
|
apiKey?: string
|
|
19
36
|
apiSecret?: string
|
|
20
37
|
host?: string
|
|
21
38
|
metadata?: Metadata
|
|
39
|
+
forgeConfigPath?: string // Optional path to forge.json file
|
|
22
40
|
}
|
|
23
41
|
|
|
24
42
|
// API Response Types
|
|
@@ -56,8 +74,10 @@ export class HiveLogClient {
|
|
|
56
74
|
private apiSecret: string | null
|
|
57
75
|
private host: string | null
|
|
58
76
|
private projectName: string
|
|
77
|
+
private projectUuid: string | null
|
|
59
78
|
private baseMetadata: Metadata
|
|
60
79
|
private isInitialized: boolean
|
|
80
|
+
private forgeConfig: ForgeConfig | null = null
|
|
61
81
|
|
|
62
82
|
constructor(config: HiveLogClientConfig) {
|
|
63
83
|
const apiKey = config.apiKey || process.env.HIVE_API_KEY
|
|
@@ -65,6 +85,7 @@ export class HiveLogClient {
|
|
|
65
85
|
const host = config.host || process.env.HIVE_HOST || 'https://www.forgehive.cloud'
|
|
66
86
|
|
|
67
87
|
this.projectName = config.projectName
|
|
88
|
+
this.projectUuid = config.projectUuid || null
|
|
68
89
|
this.baseMetadata = config.metadata || {}
|
|
69
90
|
|
|
70
91
|
if (!apiKey || !apiSecret) {
|
|
@@ -80,12 +101,145 @@ export class HiveLogClient {
|
|
|
80
101
|
this.isInitialized = true
|
|
81
102
|
log('HiveLogClient initialized for project "%s" with host "%s"', config.projectName, host)
|
|
82
103
|
}
|
|
104
|
+
|
|
105
|
+
// Load forge.json - use provided path or default to ./forge.json
|
|
106
|
+
const configPath = config.forgeConfigPath || './forge.json'
|
|
107
|
+
this.loadForgeConfig(configPath)
|
|
83
108
|
}
|
|
84
109
|
|
|
85
110
|
isActive(): boolean {
|
|
86
111
|
return this.isInitialized
|
|
87
112
|
}
|
|
88
113
|
|
|
114
|
+
private maskSecret(secret: string | null): string {
|
|
115
|
+
if (!secret || secret.length <= 8) {
|
|
116
|
+
return secret ? '****' : 'null'
|
|
117
|
+
}
|
|
118
|
+
const first4 = secret.slice(0, 4)
|
|
119
|
+
const last4 = secret.slice(-4)
|
|
120
|
+
const middle = '*'.repeat(secret.length - 8)
|
|
121
|
+
return `${first4}${middle}${last4}`
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
getConf(): Record<string, unknown> {
|
|
125
|
+
return {
|
|
126
|
+
projectName: this.projectName,
|
|
127
|
+
projectUuid: this.projectUuid,
|
|
128
|
+
host: this.host,
|
|
129
|
+
apiKey: this.maskSecret(this.apiKey),
|
|
130
|
+
apiSecret: this.maskSecret(this.apiSecret),
|
|
131
|
+
isInitialized: this.isInitialized,
|
|
132
|
+
baseMetadata: this.baseMetadata,
|
|
133
|
+
forgeConfig: this.forgeConfig
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async testConfig(): Promise<{
|
|
138
|
+
success: boolean
|
|
139
|
+
teamName?: string
|
|
140
|
+
teamUuid?: string
|
|
141
|
+
userName?: string
|
|
142
|
+
projectName?: string
|
|
143
|
+
projectExists?: boolean
|
|
144
|
+
tasksVerified?: {
|
|
145
|
+
total: number
|
|
146
|
+
found: number
|
|
147
|
+
missing: string[]
|
|
148
|
+
}
|
|
149
|
+
error?: string
|
|
150
|
+
}> {
|
|
151
|
+
if (!this.isInitialized) {
|
|
152
|
+
return {
|
|
153
|
+
success: false,
|
|
154
|
+
error: 'Client not initialized - missing API credentials'
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
try {
|
|
159
|
+
// First verify credentials with /api/me
|
|
160
|
+
const meResponse = await axios.get(`${this.host}/api/me`, {
|
|
161
|
+
headers: {
|
|
162
|
+
'Authorization': `Bearer ${this.apiKey}:${this.apiSecret}`,
|
|
163
|
+
'Content-Type': 'application/json'
|
|
164
|
+
}
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
if (meResponse.status !== 200) {
|
|
168
|
+
const error = `Credential verification failed: HTTP ${meResponse.status}`
|
|
169
|
+
log('Failed to verify credentials: %s', error)
|
|
170
|
+
return { success: false, error }
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const meData = meResponse.data
|
|
174
|
+
log('Successfully verified credentials for user "%s" in team "%s"', meData.user?.name, meData.team?.name)
|
|
175
|
+
|
|
176
|
+
// Then verify project exists if we have a projectUuid
|
|
177
|
+
let projectExists = false
|
|
178
|
+
let projectName: string | undefined
|
|
179
|
+
let tasksVerified: { total: number; found: number; missing: string[] } | undefined
|
|
180
|
+
|
|
181
|
+
if (this.projectUuid) {
|
|
182
|
+
try {
|
|
183
|
+
const projectResponse = await axios.get(`${this.host}/api/projects/${this.projectUuid}`, {
|
|
184
|
+
headers: {
|
|
185
|
+
'Authorization': `Bearer ${this.apiKey}:${this.apiSecret}`,
|
|
186
|
+
'Content-Type': 'application/json'
|
|
187
|
+
}
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
if (projectResponse.status === 200) {
|
|
191
|
+
projectExists = true
|
|
192
|
+
projectName = projectResponse.data.project?.projectName
|
|
193
|
+
log('Successfully verified project "%s" exists with UUID "%s"', projectName, this.projectUuid)
|
|
194
|
+
|
|
195
|
+
// Verify tasks if we have forge config
|
|
196
|
+
if (this.forgeConfig && this.forgeConfig.tasks) {
|
|
197
|
+
const localTasks = Object.keys(this.forgeConfig.tasks)
|
|
198
|
+
const remoteTasks = projectResponse.data.project?.tasks || []
|
|
199
|
+
const remoteTaskUuids = new Set(remoteTasks.map((task: { uuid: string }) => task.uuid))
|
|
200
|
+
|
|
201
|
+
const missing: string[] = []
|
|
202
|
+
let found = 0
|
|
203
|
+
|
|
204
|
+
for (const taskName of localTasks) {
|
|
205
|
+
const taskUuid = this.forgeConfig.tasks[taskName].uuid
|
|
206
|
+
if (remoteTaskUuids.has(taskUuid)) {
|
|
207
|
+
found++
|
|
208
|
+
} else {
|
|
209
|
+
missing.push(taskName)
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
tasksVerified = {
|
|
214
|
+
total: localTasks.length,
|
|
215
|
+
found,
|
|
216
|
+
missing
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
log('Task verification: %d/%d tasks found, missing: %s', found, localTasks.length, missing.join(', '))
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
} catch (projectError) {
|
|
223
|
+
log('Project verification failed for UUID "%s": %s', this.projectUuid, projectError instanceof Error ? projectError.message : String(projectError))
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return {
|
|
228
|
+
success: true,
|
|
229
|
+
teamName: meData.team?.name,
|
|
230
|
+
teamUuid: meData.team?.uuid,
|
|
231
|
+
userName: meData.user?.name,
|
|
232
|
+
projectName,
|
|
233
|
+
projectExists: this.projectUuid ? projectExists : undefined,
|
|
234
|
+
tasksVerified
|
|
235
|
+
}
|
|
236
|
+
} catch (e) {
|
|
237
|
+
const error = e instanceof Error ? e.message : 'Network error'
|
|
238
|
+
log('Error during config test: %s', error)
|
|
239
|
+
return { success: false, error }
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
89
243
|
private mergeMetadata(record: ExecutionRecord, sendLogMetadata?: Metadata): Metadata {
|
|
90
244
|
// Start with base metadata from client
|
|
91
245
|
let finalMetadata = { ...this.baseMetadata }
|
|
@@ -112,6 +266,9 @@ export class HiveLogClient {
|
|
|
112
266
|
return 'silent'
|
|
113
267
|
}
|
|
114
268
|
|
|
269
|
+
// Deprecation warning for legacy endpoint
|
|
270
|
+
log('DEPRECATION WARNING: sendLog() is deprecated. Use sendLogByUuid() with project and task UUIDs for enhanced features and better performance.')
|
|
271
|
+
|
|
115
272
|
try {
|
|
116
273
|
const logsUrl = `${this.host}/api/tasks/log-ingest`
|
|
117
274
|
log('Sending log for task "%s" to %s', taskName, logsUrl)
|
|
@@ -121,7 +278,7 @@ export class HiveLogClient {
|
|
|
121
278
|
// Merge metadata with priority: sendLog > record.metadata > client
|
|
122
279
|
const finalMetadata = this.mergeMetadata(record, metadata)
|
|
123
280
|
|
|
124
|
-
// Create logItem with merged metadata
|
|
281
|
+
// Create logItem with merged metadata (no UUID generation for legacy method)
|
|
125
282
|
const logItem = {
|
|
126
283
|
...record,
|
|
127
284
|
taskName,
|
|
@@ -154,6 +311,62 @@ export class HiveLogClient {
|
|
|
154
311
|
}
|
|
155
312
|
}
|
|
156
313
|
|
|
314
|
+
async sendLogByUuid(record: ExecutionRecord, taskUuid: string, metadata?: Metadata): Promise<'success' | 'error' | 'silent' | LogApiSuccess> {
|
|
315
|
+
if (!this.isInitialized) {
|
|
316
|
+
log('Silent mode: Skipping sendLogByUuid for task UUID "%s" - client not initialized', taskUuid)
|
|
317
|
+
return 'silent'
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (!this.projectUuid) {
|
|
321
|
+
log('Error: sendLogByUuid requires projectUuid to be set in client config')
|
|
322
|
+
return 'error'
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
try {
|
|
326
|
+
const logsUrl = `${this.host}/api/log-ingest`
|
|
327
|
+
log('Sending log for task UUID "%s" to %s', taskUuid, logsUrl)
|
|
328
|
+
|
|
329
|
+
const authToken = `${this.apiKey}:${this.apiSecret}`
|
|
330
|
+
|
|
331
|
+
// Merge metadata with priority: sendLog > record.metadata > client
|
|
332
|
+
const finalMetadata = this.mergeMetadata(record, metadata)
|
|
333
|
+
|
|
334
|
+
// Ensure execution record has a UUID - generate one if missing
|
|
335
|
+
const recordWithUuid = {
|
|
336
|
+
...record,
|
|
337
|
+
uuid: record.uuid || uuidv7(),
|
|
338
|
+
metadata: finalMetadata
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Create logItem with merged metadata and UUID
|
|
342
|
+
const logItem = recordWithUuid
|
|
343
|
+
|
|
344
|
+
const response = await axios.post(logsUrl, {
|
|
345
|
+
projectUuid: this.projectUuid,
|
|
346
|
+
taskUuid,
|
|
347
|
+
logItem: JSON.stringify(logItem)
|
|
348
|
+
}, {
|
|
349
|
+
headers: {
|
|
350
|
+
Authorization: `Bearer ${authToken}`,
|
|
351
|
+
'Content-Type': 'application/json'
|
|
352
|
+
}
|
|
353
|
+
})
|
|
354
|
+
|
|
355
|
+
log('Success: Sent log for task UUID "%s"', taskUuid)
|
|
356
|
+
|
|
357
|
+
// Return the full response data if available
|
|
358
|
+
if (response.data && typeof response.data === 'object' && 'uuid' in response.data) {
|
|
359
|
+
return response.data as LogApiSuccess
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
return 'success'
|
|
363
|
+
} catch (e) {
|
|
364
|
+
const error = e as Error
|
|
365
|
+
log('Error: Failed to send log for task UUID "%s": %s', taskUuid, error.message)
|
|
366
|
+
return 'error'
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
157
370
|
getListener(): (record: ExecutionRecord) => Promise<void> {
|
|
158
371
|
return async (record: ExecutionRecord) => {
|
|
159
372
|
await this.sendLog(record)
|
|
@@ -217,6 +430,58 @@ export class HiveLogClient {
|
|
|
217
430
|
return false
|
|
218
431
|
}
|
|
219
432
|
}
|
|
433
|
+
|
|
434
|
+
private loadForgeConfig(configPath: string): void {
|
|
435
|
+
try {
|
|
436
|
+
if (fs.existsSync(configPath)) {
|
|
437
|
+
const configContent = fs.readFileSync(configPath, 'utf8')
|
|
438
|
+
this.forgeConfig = JSON.parse(configContent) as ForgeConfig
|
|
439
|
+
log('Found forge.json configuration at %s', configPath)
|
|
440
|
+
} else {
|
|
441
|
+
log('No forge.json configuration found at %s', configPath)
|
|
442
|
+
}
|
|
443
|
+
} catch (error) {
|
|
444
|
+
log('Error loading forge.json: %s', error instanceof Error ? error.message : String(error))
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
private getTaskUUID(taskName: string): string | null {
|
|
449
|
+
if (!this.forgeConfig) {
|
|
450
|
+
log('No forge.json configuration loaded, cannot get UUID for task "%s"', taskName)
|
|
451
|
+
return null
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
const task = this.forgeConfig.tasks[taskName]
|
|
455
|
+
if (!task) {
|
|
456
|
+
log('Task "%s" not found in forge.json configuration', taskName)
|
|
457
|
+
return null
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
log('Found UUID "%s" for task "%s"', task.uuid, taskName)
|
|
461
|
+
return task.uuid
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
async sendLogByName(taskName: string, record: ExecutionRecord, metadata?: Metadata): Promise<'success' | 'error' | 'silent' | LogApiSuccess> {
|
|
465
|
+
if (!this.isInitialized) {
|
|
466
|
+
log('Silent mode: Skipping sendLogByName for task "%s" - client not initialized', taskName)
|
|
467
|
+
return 'silent'
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (!this.projectUuid) {
|
|
471
|
+
log('Error: sendLogByName requires projectUuid to be set in client config')
|
|
472
|
+
return 'error'
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
const taskUuid = this.getTaskUUID(taskName)
|
|
476
|
+
if (!taskUuid) {
|
|
477
|
+
log('Error: Cannot find UUID for task "%s" in forge.json', taskName)
|
|
478
|
+
return 'error'
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// Use the existing sendLogByUuid method
|
|
482
|
+
log('Sending log for task "%s" with uuid "%s"', taskName, taskUuid)
|
|
483
|
+
return await this.sendLogByUuid(record, taskUuid, metadata)
|
|
484
|
+
}
|
|
220
485
|
}
|
|
221
486
|
|
|
222
487
|
export const createHiveLogClient = (config: HiveLogClientConfig): HiveLogClient => {
|
|
@@ -271,10 +536,97 @@ export class HiveClient {
|
|
|
271
536
|
log('HiveClient initialized for project "%s" with host "%s"', config.projectUuid, host)
|
|
272
537
|
}
|
|
273
538
|
|
|
274
|
-
|
|
539
|
+
private maskSecret(secret: string): string {
|
|
540
|
+
if (secret.length <= 8) {
|
|
541
|
+
return '****'
|
|
542
|
+
}
|
|
543
|
+
const first4 = secret.slice(0, 4)
|
|
544
|
+
const last4 = secret.slice(-4)
|
|
545
|
+
const middle = '*'.repeat(secret.length - 8)
|
|
546
|
+
return `${first4}${middle}${last4}`
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
getConf(): Record<string, unknown> {
|
|
550
|
+
return {
|
|
551
|
+
projectUuid: this.projectUuid,
|
|
552
|
+
host: this.host,
|
|
553
|
+
apiKey: this.maskSecret(this.apiKey),
|
|
554
|
+
apiSecret: this.maskSecret(this.apiSecret)
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
async testConfig(): Promise<{
|
|
559
|
+
success: boolean
|
|
560
|
+
teamName?: string
|
|
561
|
+
teamUuid?: string
|
|
562
|
+
userName?: string
|
|
563
|
+
projectName?: string
|
|
564
|
+
projectExists?: boolean
|
|
565
|
+
tasksVerified?: {
|
|
566
|
+
total: number
|
|
567
|
+
found: number
|
|
568
|
+
missing: string[]
|
|
569
|
+
}
|
|
570
|
+
error?: string
|
|
571
|
+
}> {
|
|
275
572
|
try {
|
|
276
|
-
|
|
277
|
-
|
|
573
|
+
// First verify credentials with /api/me
|
|
574
|
+
const meResponse = await axios.get(`${this.host}/api/me`, {
|
|
575
|
+
headers: {
|
|
576
|
+
'Authorization': `Bearer ${this.apiKey}:${this.apiSecret}`,
|
|
577
|
+
'Content-Type': 'application/json'
|
|
578
|
+
}
|
|
579
|
+
})
|
|
580
|
+
|
|
581
|
+
if (meResponse.status !== 200) {
|
|
582
|
+
const error = `Credential verification failed: HTTP ${meResponse.status}`
|
|
583
|
+
log('Failed to verify credentials: %s', error)
|
|
584
|
+
return { success: false, error }
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
const meData = meResponse.data
|
|
588
|
+
log('Successfully verified credentials for user "%s" in team "%s"', meData.user?.name, meData.team?.name)
|
|
589
|
+
|
|
590
|
+
// Then verify project exists
|
|
591
|
+
let projectExists = false
|
|
592
|
+
let projectName: string | undefined
|
|
593
|
+
|
|
594
|
+
try {
|
|
595
|
+
const projectResponse = await axios.get(`${this.host}/api/projects/${this.projectUuid}`, {
|
|
596
|
+
headers: {
|
|
597
|
+
'Authorization': `Bearer ${this.apiKey}:${this.apiSecret}`,
|
|
598
|
+
'Content-Type': 'application/json'
|
|
599
|
+
}
|
|
600
|
+
})
|
|
601
|
+
|
|
602
|
+
if (projectResponse.status === 200) {
|
|
603
|
+
projectExists = true
|
|
604
|
+
projectName = projectResponse.data.project?.projectName
|
|
605
|
+
log('Successfully verified project "%s" exists with UUID "%s"', projectName, this.projectUuid)
|
|
606
|
+
}
|
|
607
|
+
} catch (projectError) {
|
|
608
|
+
log('Project verification failed for UUID "%s": %s', this.projectUuid, projectError instanceof Error ? projectError.message : String(projectError))
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
return {
|
|
612
|
+
success: true,
|
|
613
|
+
teamName: meData.team?.name,
|
|
614
|
+
teamUuid: meData.team?.uuid,
|
|
615
|
+
userName: meData.user?.name,
|
|
616
|
+
projectName,
|
|
617
|
+
projectExists
|
|
618
|
+
}
|
|
619
|
+
} catch (e) {
|
|
620
|
+
const error = e instanceof Error ? e.message : 'Network error'
|
|
621
|
+
log('Error during config test: %s', error)
|
|
622
|
+
return { success: false, error }
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
async invoke(taskUuid: string, payload: unknown): Promise<InvokeResult | null> {
|
|
627
|
+
try {
|
|
628
|
+
const invokeUrl = `${this.host}/api/projects/${this.projectUuid}/tasks/${taskUuid}/invoke`
|
|
629
|
+
log('Invoking task UUID "%s" at %s', taskUuid, invokeUrl)
|
|
278
630
|
|
|
279
631
|
const authToken = `${this.apiKey}:${this.apiSecret}`
|
|
280
632
|
|
|
@@ -287,11 +639,11 @@ export class HiveClient {
|
|
|
287
639
|
}
|
|
288
640
|
})
|
|
289
641
|
|
|
290
|
-
log('Success: Invoked task "%s"',
|
|
642
|
+
log('Success: Invoked task UUID "%s"', taskUuid)
|
|
291
643
|
return response.data as InvokeResult
|
|
292
644
|
} catch (e) {
|
|
293
645
|
const error = e as Error
|
|
294
|
-
log('Error: Failed to invoke task "%s": %s',
|
|
646
|
+
log('Error: Failed to invoke task UUID "%s": %s', taskUuid, error.message)
|
|
295
647
|
|
|
296
648
|
// Check if it's an axios error with response data
|
|
297
649
|
if (axios.isAxiosError(error) && error.response?.data) {
|
|
@@ -307,3 +659,41 @@ export const createHiveClient = (config: HiveClientConfig): HiveClient => {
|
|
|
307
659
|
log('Creating HiveClient for project "%s"', config.projectUuid)
|
|
308
660
|
return new HiveClient(config)
|
|
309
661
|
}
|
|
662
|
+
|
|
663
|
+
/**
|
|
664
|
+
* Create a HiveLogClient from forge.json configuration
|
|
665
|
+
* @param forgeConfigPath Path to forge.json file (defaults to './forge.json')
|
|
666
|
+
* @param additionalConfig Additional config options to override forge.json values
|
|
667
|
+
* @returns HiveLogClient configured from forge.json
|
|
668
|
+
*/
|
|
669
|
+
export const createClientFromForgeConf = (
|
|
670
|
+
forgeConfigPath: string = './forge.json',
|
|
671
|
+
additionalConfig: Partial<HiveLogClientConfig> = {}
|
|
672
|
+
): HiveLogClient => {
|
|
673
|
+
log('Creating HiveLogClient from forge.json at "%s"', forgeConfigPath)
|
|
674
|
+
|
|
675
|
+
let forgeConfig: ForgeConfig | null = null
|
|
676
|
+
|
|
677
|
+
try {
|
|
678
|
+
if (fs.existsSync(forgeConfigPath)) {
|
|
679
|
+
const configContent = fs.readFileSync(forgeConfigPath, 'utf8')
|
|
680
|
+
forgeConfig = JSON.parse(configContent) as ForgeConfig
|
|
681
|
+
log('Loaded forge.json configuration from %s', forgeConfigPath)
|
|
682
|
+
} else {
|
|
683
|
+
log('No forge.json found at %s', forgeConfigPath)
|
|
684
|
+
throw new Error(`forge.json not found at ${forgeConfigPath}`)
|
|
685
|
+
}
|
|
686
|
+
} catch (error) {
|
|
687
|
+
log('Error loading forge.json: %s', error instanceof Error ? error.message : String(error))
|
|
688
|
+
throw error
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
const config: HiveLogClientConfig = {
|
|
692
|
+
projectName: forgeConfig.project.name,
|
|
693
|
+
projectUuid: forgeConfig.project.uuid,
|
|
694
|
+
forgeConfigPath,
|
|
695
|
+
...additionalConfig // Allow overriding any config values
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
return new HiveLogClient(config)
|
|
699
|
+
}
|