@pikku/core 0.12.13 → 0.12.15

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 (150) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/dist/errors/errors.d.ts +18 -0
  3. package/dist/errors/errors.js +33 -0
  4. package/dist/function/function-runner.d.ts +1 -1
  5. package/dist/function/function-runner.js +10 -5
  6. package/dist/function/functions.types.js +1 -0
  7. package/dist/function/index.d.ts +2 -1
  8. package/dist/function/index.js +1 -0
  9. package/dist/handle-error.d.ts +2 -2
  10. package/dist/handle-error.js +8 -8
  11. package/dist/index.d.ts +1 -2
  12. package/dist/index.js +1 -2
  13. package/dist/middleware/index.d.ts +2 -0
  14. package/dist/middleware/index.js +2 -0
  15. package/dist/middleware/remote-auth.js +5 -2
  16. package/dist/permissions.d.ts +13 -1
  17. package/dist/permissions.js +51 -0
  18. package/dist/pikku-state.d.ts +0 -1
  19. package/dist/pikku-state.js +2 -4
  20. package/dist/remote.d.ts +10 -0
  21. package/dist/remote.js +32 -0
  22. package/dist/schema.js +2 -0
  23. package/dist/services/credential-service.d.ts +11 -0
  24. package/dist/services/credential-wire-service.d.ts +14 -3
  25. package/dist/services/credential-wire-service.js +49 -6
  26. package/dist/services/deployment-service.d.ts +12 -1
  27. package/dist/services/in-memory-queue-service.d.ts +7 -0
  28. package/dist/services/in-memory-queue-service.js +28 -0
  29. package/dist/services/index.d.ts +4 -1
  30. package/dist/services/index.js +2 -1
  31. package/dist/services/local-credential-service.d.ts +2 -0
  32. package/dist/services/local-credential-service.js +20 -0
  33. package/dist/services/logger-console.d.ts +26 -40
  34. package/dist/services/logger-console.js +102 -46
  35. package/dist/services/logger.d.ts +5 -0
  36. package/dist/services/meta-service.d.ts +175 -0
  37. package/dist/services/meta-service.js +310 -0
  38. package/dist/services/pikku-user-id.d.ts +3 -0
  39. package/dist/services/pikku-user-id.js +16 -0
  40. package/dist/services/typed-credential-service.d.ts +2 -0
  41. package/dist/services/typed-credential-service.js +6 -0
  42. package/dist/services/workflow-service.d.ts +6 -1
  43. package/dist/testing/service-tests.js +0 -8
  44. package/dist/types/core.types.d.ts +14 -2
  45. package/dist/types/state.types.d.ts +9 -2
  46. package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +21 -0
  47. package/dist/wirings/ai-agent/ai-agent-prepare.js +90 -21
  48. package/dist/wirings/ai-agent/ai-agent-registry.js +2 -2
  49. package/dist/wirings/ai-agent/ai-agent-runner.js +24 -2
  50. package/dist/wirings/ai-agent/ai-agent-stream.d.ts +2 -1
  51. package/dist/wirings/ai-agent/ai-agent-stream.js +61 -3
  52. package/dist/wirings/ai-agent/ai-agent.types.d.ts +25 -4
  53. package/dist/wirings/ai-agent/index.d.ts +1 -1
  54. package/dist/wirings/ai-agent/index.js +1 -1
  55. package/dist/wirings/channel/channel-runner.js +3 -3
  56. package/dist/wirings/cli/cli-runner.js +4 -3
  57. package/dist/wirings/cli/command-parser.js +7 -3
  58. package/dist/wirings/http/http-runner.d.ts +1 -1
  59. package/dist/wirings/http/http-runner.js +23 -15
  60. package/dist/wirings/http/http.types.d.ts +2 -0
  61. package/dist/wirings/mcp/mcp-runner.js +5 -3
  62. package/dist/wirings/queue/queue-runner.d.ts +3 -1
  63. package/dist/wirings/queue/queue-runner.js +8 -3
  64. package/dist/wirings/queue/queue.types.d.ts +6 -0
  65. package/dist/wirings/rpc/rpc-runner.js +57 -90
  66. package/dist/wirings/scheduler/scheduler-runner.d.ts +3 -1
  67. package/dist/wirings/scheduler/scheduler-runner.js +9 -5
  68. package/dist/wirings/trigger/trigger-runner.js +4 -2
  69. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +2 -0
  70. package/dist/wirings/workflow/dsl/workflow-runner.d.ts +1 -1
  71. package/dist/wirings/workflow/dsl/workflow-runner.js +6 -9
  72. package/dist/wirings/workflow/graph/graph-runner.d.ts +1 -1
  73. package/dist/wirings/workflow/graph/graph-runner.js +18 -4
  74. package/dist/wirings/workflow/index.d.ts +4 -2
  75. package/dist/wirings/workflow/index.js +4 -2
  76. package/dist/wirings/workflow/pikku-workflow-service.d.ts +16 -4
  77. package/dist/wirings/workflow/pikku-workflow-service.js +218 -24
  78. package/dist/wirings/workflow/workflow-queue-workers.d.ts +40 -0
  79. package/dist/wirings/workflow/workflow-queue-workers.js +41 -0
  80. package/dist/wirings/workflow/workflow.types.d.ts +19 -1
  81. package/package.json +4 -1
  82. package/src/errors/errors.ts +44 -0
  83. package/src/function/function-runner.ts +24 -13
  84. package/src/function/functions.types.ts +1 -0
  85. package/src/function/index.ts +10 -0
  86. package/src/handle-error.test.ts +2 -2
  87. package/src/handle-error.ts +8 -8
  88. package/src/index.ts +1 -2
  89. package/src/middleware/index.ts +2 -0
  90. package/src/middleware/remote-auth.test.ts +4 -4
  91. package/src/middleware/remote-auth.ts +7 -2
  92. package/src/permissions.ts +70 -0
  93. package/src/pikku-state.test.ts +0 -26
  94. package/src/pikku-state.ts +2 -5
  95. package/src/remote.ts +46 -0
  96. package/src/schema.ts +1 -0
  97. package/src/services/credential-service.ts +13 -0
  98. package/src/services/credential-wire-service.test.ts +174 -0
  99. package/src/services/credential-wire-service.ts +52 -8
  100. package/src/services/deployment-service.ts +17 -1
  101. package/src/services/in-memory-queue-service.ts +46 -0
  102. package/src/services/index.ts +21 -1
  103. package/src/services/local-credential-service.ts +22 -0
  104. package/src/services/logger-console.ts +127 -47
  105. package/src/services/logger.ts +6 -0
  106. package/src/services/meta-service.ts +523 -0
  107. package/src/services/pikku-user-id.test.ts +62 -0
  108. package/src/services/pikku-user-id.ts +17 -0
  109. package/src/services/typed-credential-service.ts +8 -0
  110. package/src/services/workflow-service.ts +8 -0
  111. package/src/testing/service-tests.ts +0 -10
  112. package/src/types/core.types.ts +16 -2
  113. package/src/types/state.types.ts +7 -2
  114. package/src/wirings/ai-agent/ai-agent-prepare.ts +122 -41
  115. package/src/wirings/ai-agent/ai-agent-registry.ts +3 -3
  116. package/src/wirings/ai-agent/ai-agent-runner.ts +22 -3
  117. package/src/wirings/ai-agent/ai-agent-stream.ts +115 -3
  118. package/src/wirings/ai-agent/ai-agent.types.ts +27 -4
  119. package/src/wirings/ai-agent/index.ts +1 -0
  120. package/src/wirings/channel/channel-handler.ts +0 -1
  121. package/src/wirings/channel/channel-runner.ts +4 -5
  122. package/src/wirings/cli/cli-runner.test.ts +8 -7
  123. package/src/wirings/cli/cli-runner.ts +5 -4
  124. package/src/wirings/cli/command-parser.ts +8 -3
  125. package/src/wirings/http/http-runner.ts +27 -18
  126. package/src/wirings/http/http.types.ts +2 -0
  127. package/src/wirings/mcp/mcp-runner.ts +7 -10
  128. package/src/wirings/queue/queue-runner.test.ts +5 -11
  129. package/src/wirings/queue/queue-runner.ts +12 -4
  130. package/src/wirings/queue/queue.types.ts +6 -0
  131. package/src/wirings/rpc/rpc-runner.ts +91 -118
  132. package/src/wirings/scheduler/scheduler-runner.test.ts +5 -11
  133. package/src/wirings/scheduler/scheduler-runner.ts +13 -5
  134. package/src/wirings/trigger/trigger-runner.test.ts +10 -11
  135. package/src/wirings/trigger/trigger-runner.ts +6 -4
  136. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +2 -0
  137. package/src/wirings/workflow/dsl/workflow-runner.ts +11 -10
  138. package/src/wirings/workflow/graph/graph-runner.ts +19 -4
  139. package/src/wirings/workflow/index.ts +17 -6
  140. package/src/wirings/workflow/pikku-workflow-service.ts +286 -24
  141. package/src/wirings/workflow/workflow-queue-workers.ts +85 -0
  142. package/src/wirings/workflow/workflow.types.ts +18 -1
  143. package/tsconfig.tsbuildinfo +1 -1
  144. package/dist/wirings/ai-agent/agent-dynamic-workflow.d.ts +0 -6
  145. package/dist/wirings/ai-agent/agent-dynamic-workflow.js +0 -468
  146. package/dist/wirings/workflow/workflow-helpers.d.ts +0 -36
  147. package/dist/wirings/workflow/workflow-helpers.js +0 -38
  148. package/src/wirings/ai-agent/agent-dynamic-workflow.ts +0 -610
  149. package/src/wirings/workflow/workflow-helpers.test.ts +0 -129
  150. package/src/wirings/workflow/workflow-helpers.ts +0 -79
@@ -1,22 +1,65 @@
1
+ import type { CredentialService } from './credential-service.js'
2
+ import { defaultPikkuUserIdResolver } from './pikku-user-id.js'
3
+ import type { PikkuWire } from '../types/core.types.js'
4
+
1
5
  export class PikkuCredentialWireService {
2
6
  private credentials: Record<string, unknown> = {}
7
+ private loaded = false
8
+ private loadPromise: Promise<void> | undefined
9
+
10
+ constructor(
11
+ private credentialService?: CredentialService,
12
+ private wire?: PikkuWire
13
+ ) {}
3
14
 
4
15
  set(name: string, value: unknown): void {
5
16
  this.credentials[name] = value
6
17
  }
7
18
 
8
- getAll(): Record<string, unknown> {
9
- return this.credentials
19
+ get<T = unknown>(name: string): T | null | Promise<T | null> {
20
+ if (this.loaded) return (this.credentials[name] as T) ?? null
21
+ return this.lazyLoad().then(() => (this.credentials[name] as T) ?? null)
22
+ }
23
+
24
+ getAll(): Record<string, unknown> | Promise<Record<string, unknown>> {
25
+ if (this.loaded) return this.credentials
26
+ return this.lazyLoad().then(() => this.credentials)
27
+ }
28
+
29
+ getScoped(
30
+ allowedNames: string[]
31
+ ): Record<string, unknown> | Promise<Record<string, unknown>> {
32
+ const buildScoped = () => {
33
+ const scoped: Record<string, unknown> = {}
34
+ for (const name of allowedNames) {
35
+ if (name in this.credentials) {
36
+ scoped[name] = this.credentials[name]
37
+ }
38
+ }
39
+ return scoped
40
+ }
41
+ if (this.loaded) return buildScoped()
42
+ return this.lazyLoad().then(buildScoped)
43
+ }
44
+
45
+ private lazyLoad(): Promise<void> {
46
+ if (this.loadPromise) return this.loadPromise
47
+ this.loadPromise = this.doLoad()
48
+ return this.loadPromise
10
49
  }
11
50
 
12
- getScoped(allowedNames: string[]): Record<string, unknown> {
13
- const scoped: Record<string, unknown> = {}
14
- for (const name of allowedNames) {
15
- if (name in this.credentials) {
16
- scoped[name] = this.credentials[name]
51
+ private async doLoad(): Promise<void> {
52
+ this.loaded = true
53
+ if (!this.credentialService || !this.wire) return
54
+ const userId = defaultPikkuUserIdResolver(this.wire)
55
+ if (!userId) return
56
+ this.wire.pikkuUserId = userId
57
+ const allCreds = await this.credentialService.getAll(userId)
58
+ for (const [name, value] of Object.entries(allCreds)) {
59
+ if (!(name in this.credentials)) {
60
+ this.credentials[name] = value
17
61
  }
18
62
  }
19
- return scoped
20
63
  }
21
64
  }
22
65
 
@@ -36,6 +79,7 @@ export function createWireServicesCredentialWireProps(
36
79
  return {
37
80
  setCredential: (name: string, value: unknown) =>
38
81
  credentialWire.set(name, value),
82
+ getCredential: <T = unknown>(name: string) => credentialWire.get<T>(name),
39
83
  getCredentials: () =>
40
84
  allowedNames
41
85
  ? credentialWire.getScoped(allowedNames)
@@ -18,5 +18,21 @@ export interface DeploymentService {
18
18
  init(): Promise<void>
19
19
  start(config: DeploymentConfig): Promise<void>
20
20
  stop(): Promise<void>
21
- findFunction(name: string): Promise<DeploymentInfo[]>
21
+ /**
22
+ * Dispatch a remote RPC call to a function.
23
+ * The deployment service owns the full transport:
24
+ * - Resolving the target (endpoint, service binding, etc.)
25
+ * - Session propagation (JWT signing, headers)
26
+ * - The actual network call
27
+ *
28
+ * @param funcName - The function to invoke
29
+ * @param data - Input data for the function
30
+ * @param session - User session to propagate (optional)
31
+ */
32
+ invoke(
33
+ funcName: string,
34
+ data: unknown,
35
+ session?: unknown,
36
+ traceId?: string
37
+ ): Promise<unknown>
22
38
  }
@@ -0,0 +1,46 @@
1
+ import type {
2
+ QueueService,
3
+ QueueJob,
4
+ JobOptions,
5
+ } from '../wirings/queue/queue.types.js'
6
+ import { runQueueJob } from '../wirings/queue/queue-runner.js'
7
+
8
+ export class InMemoryQueueService implements QueueService {
9
+ readonly supportsResults = false
10
+ private jobCounter = 0
11
+
12
+ async add<T>(
13
+ queueName: string,
14
+ data: T,
15
+ options?: JobOptions
16
+ ): Promise<string> {
17
+ const jobId = `inmem-${++this.jobCounter}`
18
+
19
+ const job: QueueJob<T> = {
20
+ id: jobId,
21
+ queueName,
22
+ data,
23
+ status: () => 'active',
24
+ pikkuUserId: options?.pikkuUserId,
25
+ }
26
+
27
+ const delay = options?.delay ?? 0
28
+
29
+ setTimeout(async () => {
30
+ try {
31
+ await runQueueJob({ job })
32
+ } catch (e: any) {
33
+ console.error(
34
+ `[InMemoryQueue] Job ${jobId} on ${queueName} failed:`,
35
+ e.message
36
+ )
37
+ }
38
+ }, delay)
39
+
40
+ return jobId
41
+ }
42
+
43
+ async getJob(): Promise<null> {
44
+ return null
45
+ }
46
+ }
@@ -19,8 +19,9 @@ export { TypedVariablesService } from './typed-variables-service.js'
19
19
  export { LocalSecretService } from './local-secrets.js'
20
20
  export { LocalCredentialService } from './local-credential-service.js'
21
21
  export { LocalVariablesService } from './local-variables.js'
22
- export { ConsoleLogger } from './logger-console.js'
22
+ export { ConsoleLogger, JsonConsoleLogger } from './logger-console.js'
23
23
  export { InMemoryWorkflowService } from './in-memory-workflow-service.js'
24
+ export { InMemoryQueueService } from './in-memory-queue-service.js'
24
25
  export { InMemoryTriggerService } from './in-memory-trigger-service.js'
25
26
  export { InMemoryAIRunStateService } from './in-memory-ai-run-state-service.js'
26
27
  export { LocalGatewayService } from './local-gateway-service.js'
@@ -66,3 +67,22 @@ export type {
66
67
  CredentialMetaInfo,
67
68
  } from './typed-credential-service.js'
68
69
  export type { VariableStatus, VariableMeta } from './typed-variables-service.js'
70
+ export type { MetaService } from './meta-service.js'
71
+ export type {
72
+ MCPMeta,
73
+ RPCMetaRecord,
74
+ ServiceMeta,
75
+ ServicesMetaRecord,
76
+ MiddlewareDefinitionMeta,
77
+ MiddlewareInstanceMeta,
78
+ GroupMeta,
79
+ MiddlewareGroupsMeta,
80
+ PermissionDefinitionMeta,
81
+ PermissionsGroupsMeta,
82
+ FunctionsMeta,
83
+ FunctionMeta,
84
+ MiddlewareMeta,
85
+ PermissionMeta,
86
+ AgentsMeta,
87
+ AgentMeta,
88
+ } from './meta-service.js'
@@ -38,4 +38,26 @@ export class LocalCredentialService implements CredentialService {
38
38
  }
39
39
  return result
40
40
  }
41
+
42
+ async getUsersWithCredential(name: string): Promise<string[]> {
43
+ const suffix = `:${name}`
44
+ const users: string[] = []
45
+ for (const key of this.store.keys()) {
46
+ if (key.endsWith(suffix)) {
47
+ users.push(key.slice(0, -suffix.length))
48
+ }
49
+ }
50
+ return users
51
+ }
52
+
53
+ async getAllUsers(): Promise<string[]> {
54
+ const users = new Set<string>()
55
+ for (const key of this.store.keys()) {
56
+ const colonIndex = key.indexOf(':')
57
+ if (colonIndex > 0) {
58
+ users.add(key.slice(0, colonIndex))
59
+ }
60
+ }
61
+ return [...users]
62
+ }
41
63
  }
@@ -2,97 +2,177 @@ import type { Logger } from './logger.js'
2
2
  import { LogLevel } from './logger.js'
3
3
 
4
4
  /**
5
- * A logger implementation that logs messages to the console.
5
+ * Text-mode console logger.
6
+ * Output: `INFO: message` or `[traceId] INFO: message`
6
7
  */
7
8
  export class ConsoleLogger implements Logger {
8
- /**
9
- * The current logging level.
10
- */
11
9
  private level: LogLevel = LogLevel.info
10
+ private prefix: string
11
+
12
+ constructor(traceId?: string) {
13
+ this.prefix = traceId ? `[${traceId}]` : ''
14
+ }
12
15
 
13
- /**
14
- * Sets the logging level.
15
- * @param level - The logging level to set.
16
- */
17
16
  setLevel(level: LogLevel): void {
18
17
  this.level = level
19
18
  }
20
19
 
21
- /**
22
- * Logs a trace message.
23
- * @param message - The message to log.
24
- * @param meta - Additional metadata to log.
25
- */
26
- trace?(message: string, ...meta: any[]): void {
20
+ scope(traceId: string): Logger {
21
+ const scoped = new ConsoleLogger(traceId)
22
+ scoped.level = this.level
23
+ return scoped
24
+ }
25
+
26
+ private log_(
27
+ fn: (...args: unknown[]) => void,
28
+ label: string,
29
+ ...args: unknown[]
30
+ ): void {
31
+ if (this.prefix) {
32
+ fn(this.prefix, label, ...args)
33
+ } else {
34
+ fn(label, ...args)
35
+ }
36
+ }
37
+
38
+ trace(message: string, ...meta: any[]): void {
27
39
  if (this.level <= LogLevel.trace) {
28
- console.trace('TRACE:', message, ...meta)
40
+ this.log_(console.trace, 'TRACE:', message, ...meta)
29
41
  }
30
42
  }
31
43
 
32
- /**
33
- * Logs a debug message.
34
- * @param message - The message to log.
35
- * @param meta - Additional metadata to log.
36
- */
37
44
  debug(message: string, ...meta: any[]): void {
38
45
  if (this.level <= LogLevel.debug) {
39
- console.debug('DEBUG:', message, ...meta)
46
+ this.log_(console.debug, 'DEBUG:', message, ...meta)
40
47
  }
41
48
  }
42
49
 
43
- /**
44
- * Logs an informational message.
45
- * @param messageOrObj - The message or object to log.
46
- * @param meta - Additional metadata to log.
47
- */
48
50
  info(messageOrObj: string | Record<string, any>, ...meta: any[]): void {
49
51
  if (this.level <= LogLevel.info) {
50
- console.info('INFO:', messageOrObj, ...meta)
52
+ this.log_(console.info, 'INFO:', messageOrObj, ...meta)
51
53
  }
52
54
  }
53
55
 
54
- /**
55
- * Logs a warning message.
56
- * @param messageOrObj - The message or object to log.
57
- * @param meta - Additional metadata to log.
58
- */
59
56
  warn(messageOrObj: string | Record<string, any>, ...meta: any[]): void {
60
57
  if (this.level <= LogLevel.warn) {
61
- console.warn('WARN:', messageOrObj, ...meta)
58
+ this.log_(console.warn, 'WARN:', messageOrObj, ...meta)
62
59
  }
63
60
  }
64
61
 
65
- /**
66
- * Logs an error message.
67
- * @param messageOrObj - The message, object, or error to log.
68
- * @param meta - Additional metadata to log.
69
- */
70
62
  error(
71
63
  messageOrObj: string | Record<string, any> | Error,
72
64
  ...meta: any[]
73
65
  ): void {
74
66
  if (this.level <= LogLevel.error) {
75
- console.error(
67
+ this.log_(
68
+ console.error,
76
69
  'ERROR:',
77
70
  messageOrObj instanceof Error ? messageOrObj.message : messageOrObj,
78
71
  ...meta
79
72
  )
80
73
  if (messageOrObj instanceof Error) {
81
- console.error('STACK:', messageOrObj.stack)
74
+ this.log_(console.error, 'STACK:', messageOrObj.stack)
75
+ }
76
+ }
77
+ }
78
+
79
+ log(level: string, message: string, ...meta: any[]): void {
80
+ const logLevel = LogLevel[level as keyof typeof LogLevel]
81
+ if (this.level <= logLevel) {
82
+ this.log_(console.log, `${level.toUpperCase()}:`, message, ...meta)
83
+ }
84
+ }
85
+ }
86
+
87
+ /**
88
+ * JSON-mode console logger.
89
+ * Output: `{"level":"info","message":"...","traceId":"..."}`
90
+ * CF Workers Logs auto-indexes JSON keys for filtering.
91
+ */
92
+ export class JsonConsoleLogger implements Logger {
93
+ private level: LogLevel = LogLevel.info
94
+ private traceId: string | undefined
95
+
96
+ constructor(traceId?: string) {
97
+ this.traceId = traceId
98
+ }
99
+
100
+ setLevel(level: LogLevel): void {
101
+ this.level = level
102
+ }
103
+
104
+ scope(traceId: string): Logger {
105
+ const scoped = new JsonConsoleLogger(traceId)
106
+ scoped.level = this.level
107
+ return scoped
108
+ }
109
+
110
+ trace(message: string, ...meta: any[]): void {
111
+ if (this.level <= LogLevel.trace) {
112
+ this.emit(console.debug, 'trace', message, meta)
113
+ }
114
+ }
115
+
116
+ debug(message: string, ...meta: any[]): void {
117
+ if (this.level <= LogLevel.debug) {
118
+ this.emit(console.debug, 'debug', message, meta)
119
+ }
120
+ }
121
+
122
+ info(messageOrObj: string | Record<string, any>, ...meta: any[]): void {
123
+ if (this.level <= LogLevel.info) {
124
+ this.emit(console.info, 'info', messageOrObj, meta)
125
+ }
126
+ }
127
+
128
+ warn(messageOrObj: string | Record<string, any>, ...meta: any[]): void {
129
+ if (this.level <= LogLevel.warn) {
130
+ this.emit(console.warn, 'warn', messageOrObj, meta)
131
+ }
132
+ }
133
+
134
+ error(
135
+ messageOrObj: string | Record<string, any> | Error,
136
+ ...meta: any[]
137
+ ): void {
138
+ if (this.level <= LogLevel.error) {
139
+ if (messageOrObj instanceof Error) {
140
+ this.emit(console.error, 'error', messageOrObj.message, meta)
141
+ console.error(
142
+ JSON.stringify({
143
+ level: 'error',
144
+ message: 'stack',
145
+ stack: messageOrObj.stack,
146
+ ...(this.traceId ? { traceId: this.traceId } : {}),
147
+ })
148
+ )
149
+ } else {
150
+ this.emit(console.error, 'error', messageOrObj, meta)
82
151
  }
83
152
  }
84
153
  }
85
154
 
86
- /**
87
- * Logs a message at a specified level.
88
- * @param level - The logging level.
89
- * @param message - The message to log.
90
- * @param meta - Additional metadata to log.
91
- */
92
155
  log(level: string, message: string, ...meta: any[]): void {
93
156
  const logLevel = LogLevel[level as keyof typeof LogLevel]
94
157
  if (this.level <= logLevel) {
95
- console.log(`${level.toUpperCase()}:`, message, ...meta)
158
+ this.emit(console.log, level, message, meta)
159
+ }
160
+ }
161
+
162
+ private emit(
163
+ fn: (...args: any[]) => void,
164
+ level: string,
165
+ messageOrObj: string | Record<string, any>,
166
+ meta: any[]
167
+ ): void {
168
+ const entry: Record<string, unknown> = { level }
169
+ if (this.traceId) entry.traceId = this.traceId
170
+ if (typeof messageOrObj === 'string') {
171
+ entry.message = messageOrObj
172
+ } else {
173
+ Object.assign(entry, messageOrObj)
96
174
  }
175
+ if (meta.length > 0) entry.meta = meta
176
+ fn(JSON.stringify(entry))
97
177
  }
98
178
  }
@@ -54,4 +54,10 @@ export interface Logger {
54
54
  * @param level - The logging level to set.
55
55
  */
56
56
  setLevel(level: LogLevel): void
57
+
58
+ /**
59
+ * Creates a scoped logger with a traceId included in every log entry.
60
+ * Used per-request to correlate logs across function calls.
61
+ */
62
+ scope?(traceId: string): Logger
57
63
  }