@pikku/core 0.12.14 → 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.
- package/CHANGELOG.md +30 -0
- package/dist/errors/errors.d.ts +4 -0
- package/dist/errors/errors.js +12 -0
- package/dist/function/function-runner.js +2 -1
- package/dist/function/functions.types.js +1 -0
- package/dist/function/index.d.ts +2 -1
- package/dist/function/index.js +1 -0
- package/dist/handle-error.d.ts +2 -2
- package/dist/handle-error.js +8 -8
- package/dist/index.d.ts +1 -2
- package/dist/index.js +1 -2
- package/dist/middleware/index.d.ts +2 -0
- package/dist/middleware/index.js +2 -0
- package/dist/middleware/remote-auth.js +5 -2
- package/dist/permissions.d.ts +13 -1
- package/dist/permissions.js +51 -0
- package/dist/pikku-state.d.ts +0 -1
- package/dist/pikku-state.js +1 -4
- package/dist/remote.d.ts +10 -0
- package/dist/remote.js +32 -0
- package/dist/schema.js +2 -0
- package/dist/services/deployment-service.d.ts +12 -1
- package/dist/services/in-memory-queue-service.d.ts +7 -0
- package/dist/services/in-memory-queue-service.js +28 -0
- package/dist/services/index.d.ts +4 -1
- package/dist/services/index.js +2 -1
- package/dist/services/logger-console.d.ts +26 -40
- package/dist/services/logger-console.js +102 -46
- package/dist/services/logger.d.ts +5 -0
- package/dist/services/meta-service.d.ts +175 -0
- package/dist/services/meta-service.js +310 -0
- package/dist/services/workflow-service.d.ts +6 -1
- package/dist/testing/service-tests.js +0 -8
- package/dist/types/core.types.d.ts +8 -0
- package/dist/types/state.types.d.ts +2 -2
- package/dist/wirings/ai-agent/ai-agent-prepare.js +42 -21
- package/dist/wirings/ai-agent/ai-agent-registry.js +2 -2
- package/dist/wirings/ai-agent/ai-agent-runner.js +18 -1
- package/dist/wirings/ai-agent/ai-agent-stream.js +1 -0
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +5 -3
- package/dist/wirings/channel/channel-runner.js +3 -3
- package/dist/wirings/cli/cli-runner.js +3 -2
- package/dist/wirings/cli/command-parser.js +7 -3
- package/dist/wirings/http/http-runner.d.ts +1 -1
- package/dist/wirings/http/http-runner.js +23 -11
- package/dist/wirings/http/http.types.d.ts +2 -0
- package/dist/wirings/mcp/mcp-runner.js +5 -3
- package/dist/wirings/queue/queue-runner.d.ts +3 -1
- package/dist/wirings/queue/queue-runner.js +7 -3
- package/dist/wirings/rpc/rpc-runner.js +56 -90
- package/dist/wirings/scheduler/scheduler-runner.d.ts +3 -1
- package/dist/wirings/scheduler/scheduler-runner.js +9 -5
- package/dist/wirings/trigger/trigger-runner.js +4 -2
- package/dist/wirings/workflow/dsl/workflow-runner.d.ts +1 -1
- package/dist/wirings/workflow/dsl/workflow-runner.js +6 -9
- package/dist/wirings/workflow/graph/graph-runner.d.ts +1 -1
- package/dist/wirings/workflow/graph/graph-runner.js +18 -4
- package/dist/wirings/workflow/index.d.ts +4 -2
- package/dist/wirings/workflow/index.js +4 -2
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +16 -4
- package/dist/wirings/workflow/pikku-workflow-service.js +216 -24
- package/dist/wirings/workflow/workflow-queue-workers.d.ts +40 -0
- package/dist/wirings/workflow/workflow-queue-workers.js +41 -0
- package/dist/wirings/workflow/workflow.types.d.ts +17 -1
- package/package.json +4 -1
- package/src/errors/errors.ts +12 -0
- package/src/function/function-runner.ts +5 -4
- package/src/function/functions.types.ts +1 -0
- package/src/function/index.ts +10 -0
- package/src/handle-error.test.ts +2 -2
- package/src/handle-error.ts +8 -8
- package/src/index.ts +1 -2
- package/src/middleware/index.ts +2 -0
- package/src/middleware/remote-auth.test.ts +4 -4
- package/src/middleware/remote-auth.ts +7 -2
- package/src/permissions.ts +70 -0
- package/src/pikku-state.test.ts +0 -26
- package/src/pikku-state.ts +1 -5
- package/src/remote.ts +46 -0
- package/src/schema.ts +1 -0
- package/src/services/deployment-service.ts +17 -1
- package/src/services/in-memory-queue-service.ts +46 -0
- package/src/services/index.ts +21 -1
- package/src/services/logger-console.ts +127 -47
- package/src/services/logger.ts +6 -0
- package/src/services/meta-service.ts +523 -0
- package/src/services/workflow-service.ts +8 -0
- package/src/testing/service-tests.ts +0 -10
- package/src/types/core.types.ts +8 -0
- package/src/types/state.types.ts +2 -2
- package/src/wirings/ai-agent/ai-agent-prepare.ts +51 -40
- package/src/wirings/ai-agent/ai-agent-registry.ts +3 -3
- package/src/wirings/ai-agent/ai-agent-runner.ts +16 -1
- package/src/wirings/ai-agent/ai-agent-stream.ts +8 -0
- package/src/wirings/ai-agent/ai-agent.types.ts +5 -3
- package/src/wirings/channel/channel-runner.ts +4 -5
- package/src/wirings/cli/cli-runner.test.ts +8 -7
- package/src/wirings/cli/cli-runner.ts +4 -3
- package/src/wirings/cli/command-parser.ts +8 -3
- package/src/wirings/http/http-runner.ts +27 -11
- package/src/wirings/http/http.types.ts +2 -0
- package/src/wirings/mcp/mcp-runner.ts +7 -9
- package/src/wirings/queue/queue-runner.test.ts +5 -11
- package/src/wirings/queue/queue-runner.ts +11 -3
- package/src/wirings/rpc/rpc-runner.ts +82 -115
- package/src/wirings/scheduler/scheduler-runner.test.ts +5 -11
- package/src/wirings/scheduler/scheduler-runner.ts +13 -5
- package/src/wirings/trigger/trigger-runner.test.ts +10 -11
- package/src/wirings/trigger/trigger-runner.ts +6 -4
- package/src/wirings/workflow/dsl/workflow-runner.ts +11 -10
- package/src/wirings/workflow/graph/graph-runner.ts +19 -4
- package/src/wirings/workflow/index.ts +17 -6
- package/src/wirings/workflow/pikku-workflow-service.ts +284 -24
- package/src/wirings/workflow/workflow-queue-workers.ts +85 -0
- package/src/wirings/workflow/workflow.types.ts +16 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/wirings/ai-agent/agent-dynamic-workflow.d.ts +0 -6
- package/dist/wirings/ai-agent/agent-dynamic-workflow.js +0 -468
- package/dist/wirings/workflow/workflow-helpers.d.ts +0 -36
- package/dist/wirings/workflow/workflow-helpers.js +0 -38
- package/src/wirings/ai-agent/agent-dynamic-workflow.ts +0 -610
- package/src/wirings/workflow/workflow-helpers.test.ts +0 -129
- package/src/wirings/workflow/workflow-helpers.ts +0 -79
|
@@ -252,7 +252,7 @@ describe('pikkuRemoteAuthMiddleware', () => {
|
|
|
252
252
|
http: {
|
|
253
253
|
request: createMockRequest(
|
|
254
254
|
{ authorization: 'Bearer valid-token' },
|
|
255
|
-
'/rpc/otherFunc'
|
|
255
|
+
'/remote/rpc/otherFunc'
|
|
256
256
|
),
|
|
257
257
|
},
|
|
258
258
|
} as any,
|
|
@@ -273,7 +273,7 @@ describe('pikkuRemoteAuthMiddleware', () => {
|
|
|
273
273
|
http: {
|
|
274
274
|
request: createMockRequest(
|
|
275
275
|
{ authorization: 'Bearer valid-token' },
|
|
276
|
-
'/rpc/myFunc'
|
|
276
|
+
'/remote/rpc/myFunc'
|
|
277
277
|
),
|
|
278
278
|
},
|
|
279
279
|
} as any,
|
|
@@ -295,7 +295,7 @@ describe('pikkuRemoteAuthMiddleware', () => {
|
|
|
295
295
|
http: {
|
|
296
296
|
request: createMockRequest(
|
|
297
297
|
{ authorization: 'Bearer valid-token' },
|
|
298
|
-
'/rpc/anyFunc'
|
|
298
|
+
'/remote/rpc/anyFunc'
|
|
299
299
|
),
|
|
300
300
|
},
|
|
301
301
|
} as any,
|
|
@@ -339,7 +339,7 @@ describe('pikkuRemoteAuthMiddleware', () => {
|
|
|
339
339
|
http: {
|
|
340
340
|
request: createMockRequest(
|
|
341
341
|
{ authorization: 'Bearer valid-token' },
|
|
342
|
-
'/rpc/my%20func'
|
|
342
|
+
'/remote/rpc/my%20func'
|
|
343
343
|
),
|
|
344
344
|
},
|
|
345
345
|
} as any,
|
|
@@ -12,6 +12,9 @@ export const pikkuRemoteAuthMiddleware = pikkuMiddleware(
|
|
|
12
12
|
try {
|
|
13
13
|
secret = await secrets.getSecret('PIKKU_REMOTE_SECRET')
|
|
14
14
|
} catch {
|
|
15
|
+
if (http.request.path().startsWith('/remote/rpc/')) {
|
|
16
|
+
throw new UnauthorizedError()
|
|
17
|
+
}
|
|
15
18
|
return next()
|
|
16
19
|
}
|
|
17
20
|
if (!jwt) {
|
|
@@ -42,8 +45,10 @@ export const pikkuRemoteAuthMiddleware = pikkuMiddleware(
|
|
|
42
45
|
throw new UnauthorizedError()
|
|
43
46
|
}
|
|
44
47
|
|
|
45
|
-
if (payload?.fn && http.request.path().startsWith('/rpc/')) {
|
|
46
|
-
const fn = decodeURIComponent(
|
|
48
|
+
if (payload?.fn && http.request.path().startsWith('/remote/rpc/')) {
|
|
49
|
+
const fn = decodeURIComponent(
|
|
50
|
+
http.request.path().slice('/remote/rpc/'.length)
|
|
51
|
+
)
|
|
47
52
|
if (fn && payload.fn !== fn) {
|
|
48
53
|
throw new UnauthorizedError()
|
|
49
54
|
}
|
package/src/permissions.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
CoreServices,
|
|
3
|
+
CoreUserSession,
|
|
3
4
|
PikkuWiringTypes,
|
|
4
5
|
PermissionMetadata,
|
|
5
6
|
PikkuWire,
|
|
@@ -325,3 +326,72 @@ export const runPermissions = async (
|
|
|
325
326
|
throw new ForbiddenError('Permission denied')
|
|
326
327
|
}
|
|
327
328
|
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Checks whether a session passes the auth checks (pikkuAuth only) for a
|
|
332
|
+
* given function/agent. Skips pikkuPermission checks since those require
|
|
333
|
+
* request data which isn't available at filter time.
|
|
334
|
+
*
|
|
335
|
+
* @param funcPermissions - The PermissionMetadata[] from function or agent metadata
|
|
336
|
+
* @param session - The user's session
|
|
337
|
+
* @param services - Singleton services
|
|
338
|
+
* @param packageName - Optional package namespace
|
|
339
|
+
* @returns true if the session passes all auth checks (or no auth checks exist)
|
|
340
|
+
*/
|
|
341
|
+
export const checkAuthPermissions = async (
|
|
342
|
+
funcPermissions: PermissionMetadata[] | undefined,
|
|
343
|
+
session: CoreUserSession,
|
|
344
|
+
services: CoreServices,
|
|
345
|
+
packageName: string | null = null
|
|
346
|
+
): Promise<boolean> => {
|
|
347
|
+
if (!funcPermissions?.length) return true
|
|
348
|
+
|
|
349
|
+
const allPermissions = combinePermissions(
|
|
350
|
+
'agent',
|
|
351
|
+
`authcheck:${Math.random()}`,
|
|
352
|
+
{
|
|
353
|
+
funcInheritedPermissions: funcPermissions,
|
|
354
|
+
packageName,
|
|
355
|
+
}
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
if (allPermissions.length === 0) return true
|
|
359
|
+
|
|
360
|
+
const wire = { session } as unknown as PikkuWire<
|
|
361
|
+
any,
|
|
362
|
+
never,
|
|
363
|
+
any,
|
|
364
|
+
never,
|
|
365
|
+
never,
|
|
366
|
+
never
|
|
367
|
+
>
|
|
368
|
+
|
|
369
|
+
// Extract only pikkuAuth permissions (marked with __pikkuAuth)
|
|
370
|
+
const authPerms: CorePikkuPermission[] = []
|
|
371
|
+
for (const permission of allPermissions) {
|
|
372
|
+
if (typeof permission === 'function') {
|
|
373
|
+
if ((permission as any).__pikkuAuth) {
|
|
374
|
+
authPerms.push(permission)
|
|
375
|
+
}
|
|
376
|
+
} else if (permission && typeof permission === 'object') {
|
|
377
|
+
for (const funcs of Object.values(permission)) {
|
|
378
|
+
const arr = Array.isArray(funcs) ? funcs : [funcs]
|
|
379
|
+
for (const fn of arr) {
|
|
380
|
+
if (typeof fn === 'function' && (fn as any).__pikkuAuth) {
|
|
381
|
+
authPerms.push(fn)
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// No auth permissions = allowed (only data-dependent permissions exist)
|
|
389
|
+
if (authPerms.length === 0) return true
|
|
390
|
+
|
|
391
|
+
// All auth permissions must pass
|
|
392
|
+
for (const perm of authPerms) {
|
|
393
|
+
const result = await perm(services, null, wire)
|
|
394
|
+
if (result) return true
|
|
395
|
+
}
|
|
396
|
+
return false
|
|
397
|
+
}
|
package/src/pikku-state.test.ts
CHANGED
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
getAllPackageStates,
|
|
8
8
|
getSingletonServices,
|
|
9
9
|
getCreateWireServices,
|
|
10
|
-
getPikkuMetaDir,
|
|
11
10
|
addPackageServiceFactories,
|
|
12
11
|
} from './pikku-state.js'
|
|
13
12
|
|
|
@@ -176,31 +175,6 @@ describe('getCreateWireServices', () => {
|
|
|
176
175
|
})
|
|
177
176
|
})
|
|
178
177
|
|
|
179
|
-
describe('getPikkuMetaDir', () => {
|
|
180
|
-
test('should return null by default', () => {
|
|
181
|
-
const result = getPikkuMetaDir()
|
|
182
|
-
assert.strictEqual(result, null)
|
|
183
|
-
})
|
|
184
|
-
|
|
185
|
-
test('should return metaDir when set', () => {
|
|
186
|
-
pikkuState(null, 'package', 'metaDir', '/some/path' as any)
|
|
187
|
-
const result = getPikkuMetaDir()
|
|
188
|
-
assert.strictEqual(result, '/some/path')
|
|
189
|
-
})
|
|
190
|
-
|
|
191
|
-
test('should return metaDir for specific package', () => {
|
|
192
|
-
pikkuState('@test/pkg', 'package', 'metaDir', '/addon/path' as any)
|
|
193
|
-
const result = getPikkuMetaDir('@test/pkg')
|
|
194
|
-
assert.strictEqual(result, '/addon/path')
|
|
195
|
-
})
|
|
196
|
-
|
|
197
|
-
test('should treat null packageName as main', () => {
|
|
198
|
-
pikkuState(null, 'package', 'metaDir', '/main/path' as any)
|
|
199
|
-
const result = getPikkuMetaDir(null)
|
|
200
|
-
assert.strictEqual(result, '/main/path')
|
|
201
|
-
})
|
|
202
|
-
})
|
|
203
|
-
|
|
204
178
|
describe('addPackageServiceFactories', () => {
|
|
205
179
|
test('should register factories for addon package', () => {
|
|
206
180
|
const mockFactories = {
|
package/src/pikku-state.ts
CHANGED
|
@@ -156,8 +156,8 @@ const createEmptyPackageState = (): PikkuPackageState => ({
|
|
|
156
156
|
package: {
|
|
157
157
|
factories: null,
|
|
158
158
|
singletonServices: null,
|
|
159
|
-
metaDir: null,
|
|
160
159
|
credentialsMeta: null,
|
|
160
|
+
requiredParentServices: null,
|
|
161
161
|
},
|
|
162
162
|
})
|
|
163
163
|
|
|
@@ -188,10 +188,6 @@ if (!getAllPackageStates().has('__main__')) {
|
|
|
188
188
|
resetPikkuState()
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
-
export const getPikkuMetaDir = (packageName?: string | null): string | null => {
|
|
192
|
-
return pikkuState(packageName ?? null, 'package', 'metaDir')
|
|
193
|
-
}
|
|
194
|
-
|
|
195
191
|
export const getSingletonServices = (): CoreSingletonServices => {
|
|
196
192
|
const services = pikkuState(null, 'package', 'singletonServices')
|
|
197
193
|
if (!services) throw new Error('Singleton services not initialized')
|
package/src/remote.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { JWTService } from './services/jwt-service.js'
|
|
2
|
+
import type { SecretService } from './services/secret-service.js'
|
|
3
|
+
import { encryptJSON } from './crypto-utils.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Build Authorization headers with JWT-signed session and traceId for
|
|
7
|
+
* pikkuRemoteAuthMiddleware on the receiving end.
|
|
8
|
+
*
|
|
9
|
+
* Used by all deployment services (Kysely, Redis, MongoDB, Lambda, CF, Azure)
|
|
10
|
+
* regardless of transport (HTTP, Lambda Invoke, service bindings).
|
|
11
|
+
*/
|
|
12
|
+
export async function buildRemoteHeaders(
|
|
13
|
+
jwt: JWTService | undefined,
|
|
14
|
+
secrets: SecretService | undefined,
|
|
15
|
+
funcName: string,
|
|
16
|
+
session?: unknown,
|
|
17
|
+
traceId?: string
|
|
18
|
+
): Promise<Record<string, string>> {
|
|
19
|
+
const headers: Record<string, string> = {
|
|
20
|
+
'content-type': 'application/json',
|
|
21
|
+
...(traceId && { 'x-request-id': traceId }),
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let secret: string | undefined
|
|
25
|
+
try {
|
|
26
|
+
secret = await secrets?.getSecret('PIKKU_REMOTE_SECRET')
|
|
27
|
+
} catch {}
|
|
28
|
+
|
|
29
|
+
if (secret && jwt) {
|
|
30
|
+
const sessionEnc = session
|
|
31
|
+
? await encryptJSON(secret, { session })
|
|
32
|
+
: undefined
|
|
33
|
+
const token = await jwt.encode(
|
|
34
|
+
{ value: 5, unit: 'minute' },
|
|
35
|
+
{
|
|
36
|
+
aud: 'pikku-remote',
|
|
37
|
+
fn: funcName,
|
|
38
|
+
iat: Math.floor(Date.now() / 1000),
|
|
39
|
+
session: sessionEnc,
|
|
40
|
+
}
|
|
41
|
+
)
|
|
42
|
+
headers.authorization = `Bearer ${token}`
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return headers
|
|
46
|
+
}
|
package/src/schema.ts
CHANGED
|
@@ -100,6 +100,7 @@ export const coerceTopLevelDataFromSchema = (
|
|
|
100
100
|
packageName: string | null = null
|
|
101
101
|
) => {
|
|
102
102
|
const schema = pikkuState(packageName, 'misc', 'schemas').get(schemaName)
|
|
103
|
+
if (!schema?.properties) return
|
|
103
104
|
for (const key in schema.properties) {
|
|
104
105
|
const property = schema.properties[key]
|
|
105
106
|
if (typeof property === 'boolean') {
|
|
@@ -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
|
-
|
|
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
|
+
}
|
package/src/services/index.ts
CHANGED
|
@@ -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'
|
|
@@ -2,97 +2,177 @@ import type { Logger } from './logger.js'
|
|
|
2
2
|
import { LogLevel } from './logger.js'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
}
|
package/src/services/logger.ts
CHANGED
|
@@ -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
|
}
|