@pikku/core 0.12.0 → 0.12.1
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 +24 -0
- package/dist/errors/errors.d.ts +6 -0
- package/dist/errors/errors.js +10 -0
- package/dist/errors/index.d.ts +1 -0
- package/dist/errors/index.js +1 -0
- package/dist/function/function-runner.d.ts +3 -3
- package/dist/function/function-runner.js +66 -44
- package/dist/function/functions.types.d.ts +1 -0
- package/dist/handle-error.d.ts +2 -2
- package/dist/handle-error.js +2 -2
- package/dist/index.d.ts +5 -3
- package/dist/index.js +2 -1
- package/dist/internal.d.ts +3 -0
- package/dist/internal.js +2 -0
- package/dist/middleware/auth-bearer.d.ts +1 -1
- package/dist/middleware/auth-bearer.js +1 -1
- package/dist/middleware/auth-cookie.d.ts +2 -2
- package/dist/middleware/auth-cookie.js +1 -1
- package/dist/middleware/cors.d.ts +2 -2
- package/dist/middleware/cors.js +45 -37
- package/dist/middleware-runner.d.ts +1 -1
- package/dist/permissions.d.ts +2 -2
- package/dist/pikku-state.d.ts +9 -8
- package/dist/pikku-state.js +30 -17
- package/dist/schema.d.ts +4 -4
- package/dist/schema.js +9 -5
- package/dist/services/ai-agent-runner-service.d.ts +22 -3
- package/dist/services/ai-run-state-service.d.ts +1 -1
- package/dist/services/ai-storage-service.d.ts +1 -1
- package/dist/services/content-service.d.ts +6 -0
- package/dist/services/gopass-secrets.d.ts +1 -1
- package/dist/services/gopass-secrets.js +3 -0
- package/dist/services/in-memory-ai-run-state-service.d.ts +15 -0
- package/dist/services/in-memory-ai-run-state-service.js +44 -0
- package/dist/services/in-memory-trigger-service.d.ts +0 -1
- package/dist/services/in-memory-trigger-service.js +6 -8
- package/dist/services/index.d.ts +3 -2
- package/dist/services/index.js +1 -0
- package/dist/services/local-content.d.ts +2 -1
- package/dist/services/local-content.js +6 -1
- package/dist/services/local-secrets.d.ts +2 -2
- package/dist/services/local-variables.d.ts +1 -1
- package/dist/services/logger-console.d.ts +2 -1
- package/dist/services/scheduler-service.d.ts +0 -12
- package/dist/services/scheduler-service.js +0 -6
- package/dist/services/scoped-secret-service.d.ts +1 -1
- package/dist/services/trigger-service.d.ts +0 -7
- package/dist/services/user-session-service.d.ts +3 -3
- package/dist/services/workflow-service.d.ts +2 -3
- package/dist/types/core.types.d.ts +24 -18
- package/dist/types/state.types.d.ts +17 -15
- package/dist/utils.d.ts +5 -5
- package/dist/utils.js +12 -9
- package/dist/wirings/ai-agent/ai-agent-assistant-ui.d.ts +5 -0
- package/dist/wirings/ai-agent/ai-agent-assistant-ui.js +146 -0
- package/dist/wirings/ai-agent/ai-agent-helpers.d.ts +28 -0
- package/dist/wirings/ai-agent/ai-agent-helpers.js +40 -0
- package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +4 -5
- package/dist/wirings/ai-agent/ai-agent-prepare.js +66 -30
- package/dist/wirings/ai-agent/ai-agent-registry.d.ts +1 -1
- package/dist/wirings/ai-agent/ai-agent-runner.js +107 -8
- package/dist/wirings/ai-agent/ai-agent-stream.d.ts +2 -1
- package/dist/wirings/ai-agent/ai-agent-stream.js +246 -87
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +61 -2
- package/dist/wirings/ai-agent/index.d.ts +3 -1
- package/dist/wirings/ai-agent/index.js +2 -0
- package/dist/wirings/channel/channel-common.d.ts +2 -2
- package/dist/wirings/channel/channel-handler.d.ts +3 -3
- package/dist/wirings/channel/channel-handler.js +4 -4
- package/dist/wirings/channel/channel-runner.d.ts +5 -5
- package/dist/wirings/channel/channel-runner.js +3 -2
- package/dist/wirings/channel/channel-store.d.ts +1 -1
- package/dist/wirings/channel/channel.types.d.ts +4 -6
- package/dist/wirings/channel/local/local-channel-runner.d.ts +7 -2
- package/dist/wirings/channel/local/local-channel-runner.js +4 -3
- package/dist/wirings/channel/local/local-eventhub-service.d.ts +2 -2
- package/dist/wirings/channel/log-channels.d.ts +1 -1
- package/dist/wirings/channel/pikku-abstract-channel-handler.d.ts +1 -1
- package/dist/wirings/channel/serverless/serverless-channel-runner.d.ts +4 -4
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +25 -19
- package/dist/wirings/cli/channel/cli-channel-runner.d.ts +1 -1
- package/dist/wirings/cli/cli-runner.d.ts +2 -2
- package/dist/wirings/cli/cli.types.d.ts +3 -3
- package/dist/wirings/cli/command-parser.d.ts +1 -1
- package/dist/wirings/http/http-runner.d.ts +9 -9
- package/dist/wirings/http/http-runner.js +33 -14
- package/dist/wirings/http/http.types.d.ts +2 -6
- package/dist/wirings/http/log-http-routes.d.ts +1 -1
- package/dist/wirings/http/pikku-fetch-http-request.d.ts +1 -1
- package/dist/wirings/http/pikku-fetch-http-response.d.ts +2 -2
- package/dist/wirings/http/pikku-fetch-http-response.js +6 -1
- package/dist/wirings/http/routers/http-router.d.ts +1 -1
- package/dist/wirings/http/routers/path-to-regex.d.ts +2 -2
- package/dist/wirings/mcp/mcp-endpoint-registry.d.ts +1 -1
- package/dist/wirings/mcp/mcp-runner.d.ts +0 -3
- package/dist/wirings/mcp/mcp-runner.js +4 -2
- package/dist/wirings/mcp/mcp.types.d.ts +2 -2
- package/dist/wirings/oauth2/oauth2-client.d.ts +3 -3
- package/dist/wirings/oauth2/wire-oauth2-credential.d.ts +1 -1
- package/dist/wirings/queue/index.d.ts +1 -1
- package/dist/wirings/queue/index.js +1 -1
- package/dist/wirings/queue/queue-runner.d.ts +1 -12
- package/dist/wirings/queue/queue-runner.js +4 -12
- package/dist/wirings/queue/queue.types.d.ts +3 -9
- package/dist/wirings/queue/register-queue-helper.d.ts +2 -2
- package/dist/wirings/queue/register-queue-helper.js +1 -1
- package/dist/wirings/queue/validate-worker-config.d.ts +1 -1
- package/dist/wirings/rpc/index.d.ts +2 -0
- package/dist/wirings/rpc/index.js +1 -0
- package/dist/wirings/rpc/rpc-runner.d.ts +36 -14
- package/dist/wirings/rpc/rpc-runner.js +56 -28
- package/dist/wirings/rpc/rpc-types.d.ts +14 -2
- package/dist/wirings/rpc/wire-addon.d.ts +10 -0
- package/dist/wirings/rpc/wire-addon.js +9 -0
- package/dist/wirings/scheduler/index.d.ts +1 -1
- package/dist/wirings/scheduler/index.js +1 -1
- package/dist/wirings/scheduler/log-schedulers.d.ts +1 -1
- package/dist/wirings/scheduler/scheduler-runner.d.ts +3 -10
- package/dist/wirings/scheduler/scheduler-runner.js +4 -25
- package/dist/wirings/scheduler/scheduler.types.d.ts +2 -2
- package/dist/wirings/trigger/pikku-trigger-service.d.ts +2 -6
- package/dist/wirings/trigger/pikku-trigger-service.js +11 -16
- package/dist/wirings/trigger/trigger-runner.d.ts +1 -5
- package/dist/wirings/trigger/trigger-runner.js +4 -3
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +2 -6
- package/dist/wirings/workflow/pikku-workflow-service.js +20 -29
- package/dist/wirings/workflow/workflow.types.d.ts +2 -2
- package/package.json +2 -1
- package/src/crypto-utils.test.ts +116 -0
- package/src/errors/error.test.ts +143 -2
- package/src/errors/errors.ts +10 -0
- package/src/errors/index.ts +1 -0
- package/src/function/function-runner.test.ts +2 -2
- package/src/function/function-runner.ts +72 -49
- package/src/function/functions.types.ts +1 -0
- package/src/handle-error.test.ts +361 -0
- package/src/handle-error.ts +4 -4
- package/src/index.ts +3 -10
- package/src/internal.ts +6 -0
- package/src/middleware/auth-apikey.test.ts +1 -1
- package/src/middleware/auth-bearer.test.ts +1 -1
- package/src/middleware/auth-bearer.ts +2 -5
- package/src/middleware/auth-cookie.test.ts +1 -1
- package/src/middleware/auth-cookie.ts +3 -5
- package/src/middleware/cors.test.ts +424 -0
- package/src/middleware/cors.ts +14 -6
- package/src/middleware/remote-auth.test.ts +488 -0
- package/src/middleware-runner.test.ts +1 -1
- package/src/middleware-runner.ts +1 -1
- package/src/permissions.test.ts +2 -2
- package/src/permissions.ts +2 -2
- package/src/pikku-state.test.ts +224 -0
- package/src/pikku-state.ts +40 -28
- package/src/schema.test.ts +198 -6
- package/src/schema.ts +11 -7
- package/src/services/ai-agent-runner-service.ts +15 -3
- package/src/services/ai-run-state-service.ts +1 -1
- package/src/services/ai-storage-service.ts +1 -1
- package/src/services/content-service.ts +7 -0
- package/src/services/gopass-secrets.ts +4 -1
- package/src/services/in-memory-ai-run-state-service.ts +73 -0
- package/src/services/in-memory-trigger-service.ts +6 -10
- package/src/services/in-memory-workflow-service.test.ts +351 -0
- package/src/services/index.ts +2 -1
- package/src/services/local-content.ts +9 -3
- package/src/services/local-secrets.test.ts +80 -0
- package/src/services/local-secrets.ts +2 -2
- package/src/services/local-variables.test.ts +61 -0
- package/src/services/local-variables.ts +1 -1
- package/src/services/logger-console.test.ts +118 -0
- package/src/services/logger-console.ts +2 -1
- package/src/services/scheduler-service.ts +0 -18
- package/src/services/scoped-secret-service.test.ts +74 -0
- package/src/services/scoped-secret-service.ts +1 -1
- package/src/services/trigger-service.ts +0 -21
- package/src/services/typed-secret-service.test.ts +93 -0
- package/src/services/typed-variables-service.test.ts +73 -0
- package/src/services/user-session-service.test.ts +113 -0
- package/src/services/user-session-service.ts +3 -3
- package/src/services/workflow-service.ts +2 -12
- package/src/time-utils.test.ts +1 -1
- package/src/types/core.types.ts +25 -19
- package/src/types/state.types.ts +24 -15
- package/src/utils.test.ts +350 -0
- package/src/utils.ts +14 -13
- package/src/wirings/ai-agent/ai-agent-assistant-ui.test.ts +363 -0
- package/src/wirings/ai-agent/ai-agent-assistant-ui.ts +214 -0
- package/src/wirings/ai-agent/ai-agent-helpers.test.ts +152 -0
- package/src/wirings/ai-agent/ai-agent-helpers.ts +76 -0
- package/src/wirings/ai-agent/ai-agent-model-config.test.ts +115 -0
- package/src/wirings/ai-agent/ai-agent-prepare.ts +79 -45
- package/src/wirings/ai-agent/ai-agent-registry.ts +1 -1
- package/src/wirings/ai-agent/ai-agent-runner.test.ts +245 -3
- package/src/wirings/ai-agent/ai-agent-runner.ts +121 -7
- package/src/wirings/ai-agent/ai-agent-stream.test.ts +430 -24
- package/src/wirings/ai-agent/ai-agent-stream.ts +377 -102
- package/src/wirings/ai-agent/ai-agent.types.ts +57 -2
- package/src/wirings/ai-agent/index.ts +11 -0
- package/src/wirings/channel/channel-common.ts +2 -2
- package/src/wirings/channel/channel-handler.ts +13 -9
- package/src/wirings/channel/channel-runner.ts +6 -6
- package/src/wirings/channel/channel-store.ts +1 -1
- package/src/wirings/channel/channel.types.ts +4 -8
- package/src/wirings/channel/local/local-channel-runner.test.ts +19 -12
- package/src/wirings/channel/local/local-channel-runner.ts +18 -13
- package/src/wirings/channel/local/local-eventhub-service.test.ts +2 -2
- package/src/wirings/channel/local/local-eventhub-service.ts +2 -2
- package/src/wirings/channel/log-channels.ts +1 -1
- package/src/wirings/channel/pikku-abstract-channel-handler.ts +1 -1
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +37 -32
- package/src/wirings/cli/channel/cli-channel-runner.ts +1 -1
- package/src/wirings/cli/cli-runner.test.ts +1 -1
- package/src/wirings/cli/cli-runner.ts +11 -4
- package/src/wirings/cli/cli.types.ts +3 -3
- package/src/wirings/cli/command-parser.test.ts +1 -1
- package/src/wirings/cli/command-parser.ts +1 -1
- package/src/wirings/http/http-routes.test.ts +1 -1
- package/src/wirings/http/http-runner.test.ts +9 -17
- package/src/wirings/http/http-runner.ts +43 -27
- package/src/wirings/http/http.types.ts +1 -14
- package/src/wirings/http/log-http-routes.ts +1 -1
- package/src/wirings/http/pikku-fetch-http-request.ts +1 -1
- package/src/wirings/http/pikku-fetch-http-response.ts +12 -5
- package/src/wirings/http/routers/http-router.ts +1 -1
- package/src/wirings/http/routers/path-to-regex.test.ts +1 -1
- package/src/wirings/http/routers/path-to-regex.ts +4 -3
- package/src/wirings/mcp/mcp-endpoint-registry.ts +5 -1
- package/src/wirings/mcp/mcp-runner.ts +9 -15
- package/src/wirings/mcp/mcp.types.ts +2 -2
- package/src/wirings/oauth2/oauth2-client.ts +3 -3
- package/src/wirings/oauth2/wire-oauth2-credential.ts +1 -1
- package/src/wirings/queue/index.ts +0 -1
- package/src/wirings/queue/queue-runner.test.ts +52 -25
- package/src/wirings/queue/queue-runner.ts +8 -30
- package/src/wirings/queue/queue.types.ts +3 -13
- package/src/wirings/queue/register-queue-helper.ts +3 -5
- package/src/wirings/queue/validate-worker-config.test.ts +108 -0
- package/src/wirings/queue/validate-worker-config.ts +4 -1
- package/src/wirings/rpc/index.ts +2 -0
- package/src/wirings/rpc/rpc-runner.ts +92 -49
- package/src/wirings/rpc/rpc-types.ts +17 -2
- package/src/wirings/rpc/wire-addon.ts +20 -0
- package/src/wirings/scheduler/index.ts +0 -1
- package/src/wirings/scheduler/log-schedulers.ts +1 -1
- package/src/wirings/scheduler/scheduler-runner.test.ts +49 -60
- package/src/wirings/scheduler/scheduler-runner.ts +9 -56
- package/src/wirings/scheduler/scheduler.types.ts +2 -2
- package/src/wirings/secret/validate-secret-definitions.test.ts +140 -0
- package/src/wirings/trigger/pikku-trigger-service.ts +17 -39
- package/src/wirings/trigger/trigger-runner.test.ts +79 -0
- package/src/wirings/trigger/trigger-runner.ts +8 -11
- package/src/wirings/variable/validate-variable-definitions.test.ts +91 -0
- package/src/wirings/workflow/graph/graph-runner.test.ts +14 -22
- package/src/wirings/workflow/graph/template.test.ts +49 -0
- package/src/wirings/workflow/pikku-workflow-service.test.ts +15 -27
- package/src/wirings/workflow/pikku-workflow-service.ts +29 -45
- package/src/wirings/workflow/workflow-helpers.test.ts +129 -0
- package/src/wirings/workflow/workflow.types.ts +2 -2
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/wirings/workflow/workflow-utils.d.ts +0 -1
- package/dist/wirings/workflow/workflow-utils.js +0 -1
- package/src/wirings/workflow/workflow-utils.ts +0 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { describe, test } from 'node:test'
|
|
2
|
+
import assert from 'node:assert'
|
|
3
|
+
import { LocalVariablesService } from './local-variables.js'
|
|
4
|
+
|
|
5
|
+
describe('LocalVariablesService', () => {
|
|
6
|
+
test('should get a variable', () => {
|
|
7
|
+
const service = new LocalVariablesService({ MY_VAR: 'hello' })
|
|
8
|
+
assert.strictEqual(service.get('MY_VAR'), 'hello')
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
test('should return undefined for missing variable', () => {
|
|
12
|
+
const service = new LocalVariablesService({})
|
|
13
|
+
assert.strictEqual(service.get('MISSING'), undefined)
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
test('should set a variable', () => {
|
|
17
|
+
const service = new LocalVariablesService({})
|
|
18
|
+
service.set('KEY', 'value')
|
|
19
|
+
assert.strictEqual(service.get('KEY'), 'value')
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
test('should delete a variable', () => {
|
|
23
|
+
const service = new LocalVariablesService({ KEY: 'val' })
|
|
24
|
+
service.delete('KEY')
|
|
25
|
+
assert.strictEqual(service.get('KEY'), undefined)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
test('should check if variable exists', () => {
|
|
29
|
+
const service = new LocalVariablesService({ KEY: 'val' })
|
|
30
|
+
assert.strictEqual(service.has('KEY'), true)
|
|
31
|
+
assert.strictEqual(service.has('MISSING'), false)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
test('should get all variables', () => {
|
|
35
|
+
const vars = { A: '1', B: '2' }
|
|
36
|
+
const service = new LocalVariablesService(vars)
|
|
37
|
+
assert.deepStrictEqual(service.getAll(), vars)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
test('should get JSON variable', () => {
|
|
41
|
+
const service = new LocalVariablesService({ DATA: '{"key":"val"}' })
|
|
42
|
+
const result = service.getJSON('DATA')
|
|
43
|
+
assert.deepStrictEqual(result, { key: 'val' })
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
test('should return undefined for missing JSON variable', () => {
|
|
47
|
+
const service = new LocalVariablesService({})
|
|
48
|
+
assert.strictEqual(service.getJSON('MISSING'), undefined)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
test('should set JSON variable', () => {
|
|
52
|
+
const service = new LocalVariablesService({})
|
|
53
|
+
service.setJSON('DATA', { key: 'val' })
|
|
54
|
+
assert.strictEqual(service.get('DATA'), '{"key":"val"}')
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
test('should handle has with undefined value', () => {
|
|
58
|
+
const service = new LocalVariablesService({ KEY: undefined })
|
|
59
|
+
assert.strictEqual(service.has('KEY'), false)
|
|
60
|
+
})
|
|
61
|
+
})
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { describe, test, beforeEach } from 'node:test'
|
|
2
|
+
import assert from 'node:assert'
|
|
3
|
+
import { ConsoleLogger } from './logger-console.js'
|
|
4
|
+
import { LogLevel } from './logger.js'
|
|
5
|
+
|
|
6
|
+
describe('ConsoleLogger', () => {
|
|
7
|
+
let logger: ConsoleLogger
|
|
8
|
+
let captured: { method: string; args: any[] }[]
|
|
9
|
+
let origConsole: Record<string, any>
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
logger = new ConsoleLogger()
|
|
13
|
+
captured = []
|
|
14
|
+
origConsole = {
|
|
15
|
+
trace: console.trace,
|
|
16
|
+
debug: console.debug,
|
|
17
|
+
info: console.info,
|
|
18
|
+
warn: console.warn,
|
|
19
|
+
error: console.error,
|
|
20
|
+
log: console.log,
|
|
21
|
+
}
|
|
22
|
+
console.trace = (...args: any[]) => captured.push({ method: 'trace', args })
|
|
23
|
+
console.debug = (...args: any[]) => captured.push({ method: 'debug', args })
|
|
24
|
+
console.info = (...args: any[]) => captured.push({ method: 'info', args })
|
|
25
|
+
console.warn = (...args: any[]) => captured.push({ method: 'warn', args })
|
|
26
|
+
console.error = (...args: any[]) => captured.push({ method: 'error', args })
|
|
27
|
+
console.log = (...args: any[]) => captured.push({ method: 'log', args })
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
// Restore console after each test
|
|
31
|
+
test('should log info at default level', () => {
|
|
32
|
+
logger.info('test message')
|
|
33
|
+
assert.strictEqual(captured.length, 1)
|
|
34
|
+
assert.strictEqual(captured[0].method, 'info')
|
|
35
|
+
assert.ok(captured[0].args.includes('test message'))
|
|
36
|
+
Object.assign(console, origConsole)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
test('should not log debug at default info level', () => {
|
|
40
|
+
logger.debug('debug message')
|
|
41
|
+
assert.strictEqual(captured.length, 0)
|
|
42
|
+
Object.assign(console, origConsole)
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
test('should log debug when level is set to debug', () => {
|
|
46
|
+
logger.setLevel(LogLevel.debug)
|
|
47
|
+
logger.debug('debug message')
|
|
48
|
+
assert.strictEqual(captured.length, 1)
|
|
49
|
+
assert.strictEqual(captured[0].method, 'debug')
|
|
50
|
+
Object.assign(console, origConsole)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
test('should log warn at info level', () => {
|
|
54
|
+
logger.warn('warning')
|
|
55
|
+
assert.strictEqual(captured.length, 1)
|
|
56
|
+
assert.strictEqual(captured[0].method, 'warn')
|
|
57
|
+
Object.assign(console, origConsole)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
test('should log error at info level', () => {
|
|
61
|
+
logger.error('error message')
|
|
62
|
+
assert.strictEqual(captured.length, 1)
|
|
63
|
+
assert.strictEqual(captured[0].method, 'error')
|
|
64
|
+
Object.assign(console, origConsole)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
test('should log Error instance with stack trace', () => {
|
|
68
|
+
const err = new Error('test error')
|
|
69
|
+
logger.error(err)
|
|
70
|
+
assert.strictEqual(captured.length, 2) // error message + stack
|
|
71
|
+
assert.ok(captured[0].args.includes('test error'))
|
|
72
|
+
assert.strictEqual(captured[1].args[0], 'STACK:')
|
|
73
|
+
Object.assign(console, origConsole)
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
test('should not log info when level is error', () => {
|
|
77
|
+
logger.setLevel(LogLevel.error)
|
|
78
|
+
logger.info('info')
|
|
79
|
+
logger.warn('warn')
|
|
80
|
+
logger.debug('debug')
|
|
81
|
+
assert.strictEqual(captured.length, 0)
|
|
82
|
+
Object.assign(console, origConsole)
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
test('should log error when level is error', () => {
|
|
86
|
+
logger.setLevel(LogLevel.error)
|
|
87
|
+
logger.error('critical')
|
|
88
|
+
assert.strictEqual(captured.length, 1)
|
|
89
|
+
Object.assign(console, origConsole)
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
test('should support trace level when enabled', () => {
|
|
93
|
+
logger.setLevel(LogLevel.trace)
|
|
94
|
+
logger.trace!('trace message')
|
|
95
|
+
assert.strictEqual(captured.length, 1)
|
|
96
|
+
assert.strictEqual(captured[0].method, 'trace')
|
|
97
|
+
Object.assign(console, origConsole)
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
test('should log with additional metadata', () => {
|
|
101
|
+
logger.info('message', { extra: 'data' })
|
|
102
|
+
assert.ok(captured[0].args.includes('message'))
|
|
103
|
+
Object.assign(console, origConsole)
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
test('should handle object messages in info', () => {
|
|
107
|
+
logger.info({ key: 'value' })
|
|
108
|
+
assert.strictEqual(captured.length, 1)
|
|
109
|
+
Object.assign(console, origConsole)
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
test('log method should respect level', () => {
|
|
113
|
+
logger.setLevel(LogLevel.error)
|
|
114
|
+
logger.log('info', 'should not show')
|
|
115
|
+
assert.strictEqual(captured.length, 0)
|
|
116
|
+
Object.assign(console, origConsole)
|
|
117
|
+
})
|
|
118
|
+
})
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { CoreUserSession } from '../types/core.types.js'
|
|
2
|
-
import type { Logger } from './logger.js'
|
|
3
2
|
|
|
4
3
|
/**
|
|
5
4
|
* Minimal metadata for listing scheduled tasks
|
|
@@ -25,16 +24,6 @@ export interface ScheduledTaskInfo extends ScheduledTaskSummary {
|
|
|
25
24
|
status?: 'scheduled' | 'active' | 'completed' | 'failed'
|
|
26
25
|
}
|
|
27
26
|
|
|
28
|
-
export interface SchedulerRuntimeHandlers {
|
|
29
|
-
logger: Logger
|
|
30
|
-
invokeRPC: (
|
|
31
|
-
rpcName: string,
|
|
32
|
-
data?: any,
|
|
33
|
-
session?: CoreUserSession
|
|
34
|
-
) => Promise<void>
|
|
35
|
-
runScheduledTask: (name: string) => Promise<void>
|
|
36
|
-
}
|
|
37
|
-
|
|
38
27
|
/**
|
|
39
28
|
* Abstract scheduler service for persistent scheduled task management
|
|
40
29
|
* Implementations use queue backends (pg-boss, BullMQ) for distributed scheduling
|
|
@@ -85,13 +74,6 @@ export abstract class SchedulerService {
|
|
|
85
74
|
*/
|
|
86
75
|
abstract close(): Promise<void>
|
|
87
76
|
|
|
88
|
-
/**
|
|
89
|
-
* Set services needed for processing recurring tasks.
|
|
90
|
-
* Called after construction since the scheduler is created before
|
|
91
|
-
* singletonServices are fully assembled.
|
|
92
|
-
*/
|
|
93
|
-
setServices(_handlers: SchedulerRuntimeHandlers): void {}
|
|
94
|
-
|
|
95
77
|
/**
|
|
96
78
|
* Start recurring scheduled tasks
|
|
97
79
|
*/
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { describe, test } from 'node:test'
|
|
2
|
+
import assert from 'node:assert'
|
|
3
|
+
import { ScopedSecretService } from './scoped-secret-service.js'
|
|
4
|
+
|
|
5
|
+
const createMockSecrets = () => ({
|
|
6
|
+
getSecret: async (key: string) => `value-of-${key}`,
|
|
7
|
+
getSecretJSON: async (key: string) => ({ key }),
|
|
8
|
+
hasSecret: async () => true,
|
|
9
|
+
setSecretJSON: async () => {},
|
|
10
|
+
deleteSecret: async () => {},
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
describe('ScopedSecretService', () => {
|
|
14
|
+
test('should allow access to allowed keys', async () => {
|
|
15
|
+
const mock = createMockSecrets()
|
|
16
|
+
const scoped = new ScopedSecretService(mock, new Set(['KEY1', 'KEY2']))
|
|
17
|
+
const result = await scoped.getSecret('KEY1')
|
|
18
|
+
assert.strictEqual(result, 'value-of-KEY1')
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
test('should deny access to non-allowed keys', async () => {
|
|
22
|
+
const mock = createMockSecrets()
|
|
23
|
+
const scoped = new ScopedSecretService(mock, new Set(['KEY1']))
|
|
24
|
+
await assert.rejects(() => scoped.getSecret('KEY2'), {
|
|
25
|
+
message: 'Access denied to secret key: KEY2',
|
|
26
|
+
})
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
test('should allow getSecretJSON for allowed keys', async () => {
|
|
30
|
+
const mock = createMockSecrets()
|
|
31
|
+
const scoped = new ScopedSecretService(mock, new Set(['KEY1']))
|
|
32
|
+
const result = await scoped.getSecretJSON('KEY1')
|
|
33
|
+
assert.deepStrictEqual(result, { key: 'KEY1' })
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test('should deny getSecretJSON for non-allowed keys', async () => {
|
|
37
|
+
const mock = createMockSecrets()
|
|
38
|
+
const scoped = new ScopedSecretService(mock, new Set(['KEY1']))
|
|
39
|
+
await assert.rejects(() => scoped.getSecretJSON('FORBIDDEN'), {
|
|
40
|
+
message: 'Access denied to secret key: FORBIDDEN',
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test('should allow hasSecret for allowed keys', async () => {
|
|
45
|
+
const mock = createMockSecrets()
|
|
46
|
+
const scoped = new ScopedSecretService(mock, new Set(['KEY1']))
|
|
47
|
+
const result = await scoped.hasSecret('KEY1')
|
|
48
|
+
assert.strictEqual(result, true)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
test('should deny hasSecret for non-allowed keys', async () => {
|
|
52
|
+
const mock = createMockSecrets()
|
|
53
|
+
const scoped = new ScopedSecretService(mock, new Set(['KEY1']))
|
|
54
|
+
await assert.rejects(() => scoped.hasSecret('KEY2'), {
|
|
55
|
+
message: 'Access denied to secret key: KEY2',
|
|
56
|
+
})
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
test('should always throw on setSecretJSON', async () => {
|
|
60
|
+
const mock = createMockSecrets()
|
|
61
|
+
const scoped = new ScopedSecretService(mock, new Set(['KEY1']))
|
|
62
|
+
await assert.rejects(() => scoped.setSecretJSON('KEY1', 'val'), {
|
|
63
|
+
message: 'setSecretJSON is not allowed in scoped secret service',
|
|
64
|
+
})
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
test('should always throw on deleteSecret', async () => {
|
|
68
|
+
const mock = createMockSecrets()
|
|
69
|
+
const scoped = new ScopedSecretService(mock, new Set(['KEY1']))
|
|
70
|
+
await assert.rejects(() => scoped.deleteSecret('KEY1'), {
|
|
71
|
+
message: 'deleteSecret is not allowed in scoped secret service',
|
|
72
|
+
})
|
|
73
|
+
})
|
|
74
|
+
})
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
CoreSingletonServices,
|
|
3
|
-
CreateWireServices,
|
|
4
|
-
CoreServices,
|
|
5
|
-
CoreUserSession,
|
|
6
|
-
} from '../types/core.types.js'
|
|
7
|
-
|
|
8
1
|
/**
|
|
9
2
|
* Abstract TriggerService interface.
|
|
10
3
|
*
|
|
@@ -12,20 +5,6 @@ import {
|
|
|
12
5
|
* and dispatching to RPC targets or workflow starts.
|
|
13
6
|
*/
|
|
14
7
|
export interface TriggerService {
|
|
15
|
-
/**
|
|
16
|
-
* Set services needed for processing triggers.
|
|
17
|
-
* Called after construction since the trigger service is created before
|
|
18
|
-
* singletonServices are fully assembled.
|
|
19
|
-
*/
|
|
20
|
-
setServices(
|
|
21
|
-
_singletonServices: CoreSingletonServices,
|
|
22
|
-
_createWireServices?: CreateWireServices<
|
|
23
|
-
CoreSingletonServices,
|
|
24
|
-
CoreServices,
|
|
25
|
-
CoreUserSession
|
|
26
|
-
>
|
|
27
|
-
): void
|
|
28
|
-
|
|
29
8
|
/**
|
|
30
9
|
* Start all triggers
|
|
31
10
|
*/
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { describe, test } from 'node:test'
|
|
2
|
+
import assert from 'node:assert'
|
|
3
|
+
import { TypedSecretService } from './typed-secret-service.js'
|
|
4
|
+
|
|
5
|
+
const createMockSecrets = (store: Map<string, string> = new Map()) => ({
|
|
6
|
+
getSecret: async (key: string) => {
|
|
7
|
+
const val = store.get(key)
|
|
8
|
+
if (!val) throw new Error(`Not found: ${key}`)
|
|
9
|
+
return val
|
|
10
|
+
},
|
|
11
|
+
getSecretJSON: async (key: string) => {
|
|
12
|
+
const val = store.get(key)
|
|
13
|
+
if (!val) throw new Error(`Not found: ${key}`)
|
|
14
|
+
return JSON.parse(val)
|
|
15
|
+
},
|
|
16
|
+
hasSecret: async (key: string) => store.has(key),
|
|
17
|
+
setSecretJSON: async (key: string, value: unknown) => {
|
|
18
|
+
store.set(key, JSON.stringify(value))
|
|
19
|
+
},
|
|
20
|
+
deleteSecret: async (key: string) => {
|
|
21
|
+
store.delete(key)
|
|
22
|
+
},
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
describe('TypedSecretService', () => {
|
|
26
|
+
test('should delegate getSecret to underlying service', async () => {
|
|
27
|
+
const store = new Map([['API_KEY', 'sk-123']])
|
|
28
|
+
const service = new TypedSecretService(createMockSecrets(store), {})
|
|
29
|
+
const result = await service.getSecret('API_KEY')
|
|
30
|
+
assert.strictEqual(result, 'sk-123')
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test('should delegate getSecretJSON to underlying service', async () => {
|
|
34
|
+
const store = new Map([['CONFIG', '{"port":3000}']])
|
|
35
|
+
const service = new TypedSecretService(createMockSecrets(store), {})
|
|
36
|
+
const result = await service.getSecretJSON('CONFIG')
|
|
37
|
+
assert.deepStrictEqual(result, { port: 3000 })
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
test('should delegate hasSecret to underlying service', async () => {
|
|
41
|
+
const store = new Map([['EXISTS', 'val']])
|
|
42
|
+
const service = new TypedSecretService(createMockSecrets(store), {})
|
|
43
|
+
assert.strictEqual(await service.hasSecret('EXISTS'), true)
|
|
44
|
+
assert.strictEqual(await service.hasSecret('MISSING'), false)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
test('should delegate setSecretJSON to underlying service', async () => {
|
|
48
|
+
const store = new Map<string, string>()
|
|
49
|
+
const service = new TypedSecretService(createMockSecrets(store), {})
|
|
50
|
+
await service.setSecretJSON('NEW_KEY', { data: 'val' })
|
|
51
|
+
assert.strictEqual(store.get('NEW_KEY'), '{"data":"val"}')
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
test('should delegate deleteSecret to underlying service', async () => {
|
|
55
|
+
const store = new Map([['KEY', 'val']])
|
|
56
|
+
const service = new TypedSecretService(createMockSecrets(store), {})
|
|
57
|
+
await service.deleteSecret('KEY')
|
|
58
|
+
assert.strictEqual(store.has('KEY'), false)
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
test('should get all status for credentials', async () => {
|
|
62
|
+
const store = new Map([['STRIPE_KEY', 'sk-123']])
|
|
63
|
+
const meta = {
|
|
64
|
+
STRIPE_KEY: { name: 'stripe', displayName: 'Stripe' },
|
|
65
|
+
GITHUB_TOKEN: {
|
|
66
|
+
name: 'github',
|
|
67
|
+
displayName: 'GitHub',
|
|
68
|
+
oauth2: { tokenSecretId: 'GH_TOKEN' },
|
|
69
|
+
},
|
|
70
|
+
}
|
|
71
|
+
const service = new TypedSecretService(createMockSecrets(store), meta)
|
|
72
|
+
const status = await service.getAllStatus()
|
|
73
|
+
assert.strictEqual(status.length, 2)
|
|
74
|
+
const stripeStatus = status.find((s) => s.secretId === 'STRIPE_KEY')!
|
|
75
|
+
assert.strictEqual(stripeStatus.isConfigured, true)
|
|
76
|
+
assert.strictEqual(stripeStatus.displayName, 'Stripe')
|
|
77
|
+
const ghStatus = status.find((s) => s.secretId === 'GITHUB_TOKEN')!
|
|
78
|
+
assert.strictEqual(ghStatus.isConfigured, false)
|
|
79
|
+
assert.deepStrictEqual(ghStatus.oauth2, { tokenSecretId: 'GH_TOKEN' })
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
test('should get missing credentials', async () => {
|
|
83
|
+
const store = new Map([['STRIPE_KEY', 'sk-123']])
|
|
84
|
+
const meta = {
|
|
85
|
+
STRIPE_KEY: { name: 'stripe', displayName: 'Stripe' },
|
|
86
|
+
GITHUB_TOKEN: { name: 'github', displayName: 'GitHub' },
|
|
87
|
+
}
|
|
88
|
+
const service = new TypedSecretService(createMockSecrets(store), meta)
|
|
89
|
+
const missing = await service.getMissing()
|
|
90
|
+
assert.strictEqual(missing.length, 1)
|
|
91
|
+
assert.strictEqual(missing[0].secretId, 'GITHUB_TOKEN')
|
|
92
|
+
})
|
|
93
|
+
})
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { describe, test } from 'node:test'
|
|
2
|
+
import assert from 'node:assert'
|
|
3
|
+
import { TypedVariablesService } from './typed-variables-service.js'
|
|
4
|
+
import { LocalVariablesService } from './local-variables.js'
|
|
5
|
+
|
|
6
|
+
describe('TypedVariablesService', () => {
|
|
7
|
+
const createService = (vars: Record<string, string | undefined> = {}) => {
|
|
8
|
+
const underlying = new LocalVariablesService(vars)
|
|
9
|
+
const meta = {
|
|
10
|
+
DB_URL: { name: 'DB_URL', displayName: 'Database URL' },
|
|
11
|
+
API_KEY: { name: 'API_KEY', displayName: 'API Key' },
|
|
12
|
+
}
|
|
13
|
+
return new TypedVariablesService(underlying, meta)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
test('should delegate get to underlying service', () => {
|
|
17
|
+
const service = createService({ DB_URL: 'postgres://...' })
|
|
18
|
+
assert.strictEqual(service.get('DB_URL'), 'postgres://...')
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
test('should delegate set to underlying service', () => {
|
|
22
|
+
const service = createService()
|
|
23
|
+
service.set('DB_URL', 'new-value')
|
|
24
|
+
assert.strictEqual(service.get('DB_URL'), 'new-value')
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
test('should delegate has to underlying service', () => {
|
|
28
|
+
const service = createService({ DB_URL: 'val' })
|
|
29
|
+
assert.strictEqual(service.has('DB_URL'), true)
|
|
30
|
+
assert.strictEqual(service.has('MISSING'), false)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test('should delegate delete to underlying service', () => {
|
|
34
|
+
const service = createService({ DB_URL: 'val' })
|
|
35
|
+
service.delete('DB_URL')
|
|
36
|
+
assert.strictEqual(service.has('DB_URL'), false)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
test('should delegate getJSON to underlying service', () => {
|
|
40
|
+
const service = createService({ DATA: '{"key":"val"}' })
|
|
41
|
+
assert.deepStrictEqual(service.getJSON('DATA'), { key: 'val' })
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test('should delegate setJSON to underlying service', () => {
|
|
45
|
+
const service = createService()
|
|
46
|
+
service.setJSON('DATA', { key: 'val' })
|
|
47
|
+
assert.strictEqual(service.get('DATA'), '{"key":"val"}')
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
test('should get all status for configured variables', async () => {
|
|
51
|
+
const service = createService({ DB_URL: 'postgres://...' })
|
|
52
|
+
const status = await service.getAllStatus()
|
|
53
|
+
assert.strictEqual(status.length, 2)
|
|
54
|
+
const dbStatus = status.find((s) => s.variableId === 'DB_URL')!
|
|
55
|
+
assert.strictEqual(dbStatus.isConfigured, true)
|
|
56
|
+
assert.strictEqual(dbStatus.displayName, 'Database URL')
|
|
57
|
+
const apiStatus = status.find((s) => s.variableId === 'API_KEY')!
|
|
58
|
+
assert.strictEqual(apiStatus.isConfigured, false)
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
test('should get missing variables', async () => {
|
|
62
|
+
const service = createService({ DB_URL: 'val' })
|
|
63
|
+
const missing = await service.getMissing()
|
|
64
|
+
assert.strictEqual(missing.length, 1)
|
|
65
|
+
assert.strictEqual(missing[0].variableId, 'API_KEY')
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
test('should return empty missing when all configured', async () => {
|
|
69
|
+
const service = createService({ DB_URL: 'val', API_KEY: 'key' })
|
|
70
|
+
const missing = await service.getMissing()
|
|
71
|
+
assert.strictEqual(missing.length, 0)
|
|
72
|
+
})
|
|
73
|
+
})
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { describe, test } from 'node:test'
|
|
2
|
+
import assert from 'node:assert'
|
|
3
|
+
import {
|
|
4
|
+
PikkuSessionService,
|
|
5
|
+
createMiddlewareSessionWireProps,
|
|
6
|
+
createFunctionSessionWireProps,
|
|
7
|
+
} from './user-session-service.js'
|
|
8
|
+
|
|
9
|
+
describe('PikkuSessionService', () => {
|
|
10
|
+
test('should set and get session', () => {
|
|
11
|
+
const service = new PikkuSessionService()
|
|
12
|
+
service.setInitial({ userId: 'user-1' })
|
|
13
|
+
const session = service.get()
|
|
14
|
+
assert.deepStrictEqual(session, { userId: 'user-1' })
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
test('should return undefined when no session set', () => {
|
|
18
|
+
const service = new PikkuSessionService()
|
|
19
|
+
assert.strictEqual(service.get(), undefined)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
test('should mark sessionChanged when set is called', () => {
|
|
23
|
+
const service = new PikkuSessionService()
|
|
24
|
+
assert.strictEqual(service.sessionChanged, false)
|
|
25
|
+
service.set({ userId: 'user-1' })
|
|
26
|
+
assert.strictEqual(service.sessionChanged, true)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
test('should clear session', () => {
|
|
30
|
+
const service = new PikkuSessionService()
|
|
31
|
+
service.setInitial({ userId: 'user-1' })
|
|
32
|
+
service.clear()
|
|
33
|
+
assert.strictEqual(service.get(), undefined)
|
|
34
|
+
assert.strictEqual(service.sessionChanged, true)
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
test('should freeze initial session', () => {
|
|
38
|
+
const service = new PikkuSessionService()
|
|
39
|
+
service.setInitial({ userId: 'user-1' })
|
|
40
|
+
const frozen = service.freezeInitial()
|
|
41
|
+
assert.deepStrictEqual(frozen, { userId: 'user-1' })
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test('should only freeze initial once', () => {
|
|
45
|
+
const service = new PikkuSessionService()
|
|
46
|
+
service.setInitial({ userId: 'user-1' })
|
|
47
|
+
service.freezeInitial()
|
|
48
|
+
service.set({ userId: 'user-2' })
|
|
49
|
+
const frozen2 = service.freezeInitial()
|
|
50
|
+
assert.deepStrictEqual(frozen2, { userId: 'user-1' })
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
test('should throw when channelStore provided without channelId', () => {
|
|
54
|
+
assert.throws(() => new PikkuSessionService({} as any), {
|
|
55
|
+
message: 'Channel ID is required when using channel store',
|
|
56
|
+
})
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
test('should use channelStore when provided', async () => {
|
|
60
|
+
let storedSession: any
|
|
61
|
+
const store = {
|
|
62
|
+
setUserSession: (id: string, session: any) => {
|
|
63
|
+
storedSession = session
|
|
64
|
+
},
|
|
65
|
+
getChannelAndSession: (id: string) => ({ session: { userId: 'stored' } }),
|
|
66
|
+
}
|
|
67
|
+
const service = new PikkuSessionService(store as any, 'ch-1')
|
|
68
|
+
service.set({ userId: 'new' })
|
|
69
|
+
assert.deepStrictEqual(storedSession, { userId: 'new' })
|
|
70
|
+
|
|
71
|
+
const session = service.get()
|
|
72
|
+
assert.deepStrictEqual(session, { userId: 'stored' })
|
|
73
|
+
})
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
describe('createMiddlewareSessionWireProps', () => {
|
|
77
|
+
test('should return session wire props', () => {
|
|
78
|
+
const service = new PikkuSessionService()
|
|
79
|
+
service.setInitial({ userId: 'user-1' })
|
|
80
|
+
const props = createMiddlewareSessionWireProps(service)
|
|
81
|
+
assert.ok('session' in props)
|
|
82
|
+
assert.ok('setSession' in props)
|
|
83
|
+
assert.ok('getSession' in props)
|
|
84
|
+
assert.ok('hasSessionChanged' in props)
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
test('setSession should call setInitial', () => {
|
|
88
|
+
const service = new PikkuSessionService()
|
|
89
|
+
const props = createMiddlewareSessionWireProps(service)
|
|
90
|
+
props.setSession({ userId: 'user-2' })
|
|
91
|
+
assert.deepStrictEqual(service.get(), { userId: 'user-2' })
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
describe('createFunctionSessionWireProps', () => {
|
|
96
|
+
test('should return function session wire props', () => {
|
|
97
|
+
const service = new PikkuSessionService()
|
|
98
|
+
service.setInitial({ userId: 'user-1' })
|
|
99
|
+
const props = createFunctionSessionWireProps(service)
|
|
100
|
+
assert.ok('session' in props)
|
|
101
|
+
assert.ok('setSession' in props)
|
|
102
|
+
assert.ok('clearSession' in props)
|
|
103
|
+
assert.ok('getSession' in props)
|
|
104
|
+
assert.ok('hasSessionChanged' in props)
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
test('session should be frozen initial', () => {
|
|
108
|
+
const service = new PikkuSessionService()
|
|
109
|
+
service.setInitial({ userId: 'user-1' })
|
|
110
|
+
const props = createFunctionSessionWireProps(service)
|
|
111
|
+
assert.deepStrictEqual(props.session, { userId: 'user-1' })
|
|
112
|
+
})
|
|
113
|
+
})
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ChannelStore } from '../wirings/channel/channel-store.js'
|
|
2
|
-
import { CoreUserSession } from '../types/core.types.js'
|
|
1
|
+
import type { ChannelStore } from '../wirings/channel/channel-store.js'
|
|
2
|
+
import type { CoreUserSession } from '../types/core.types.js'
|
|
3
3
|
|
|
4
4
|
export interface SessionService<UserSession extends CoreUserSession> {
|
|
5
5
|
sessionChanged: boolean
|
|
@@ -66,7 +66,7 @@ export function createMiddlewareSessionWireProps<
|
|
|
66
66
|
UserSession extends CoreUserSession,
|
|
67
67
|
>(session: SessionService<UserSession>) {
|
|
68
68
|
return {
|
|
69
|
-
session: session.get(),
|
|
69
|
+
session: session.get() as UserSession | undefined,
|
|
70
70
|
setSession: (s: UserSession) => session.setInitial(s),
|
|
71
71
|
getSession: () => session.get(),
|
|
72
72
|
hasSessionChanged: () => session.sessionChanged,
|
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
CoreSingletonServices,
|
|
4
|
-
CreateWireServices,
|
|
5
|
-
CoreConfig,
|
|
6
|
-
} from '../types/core.types.js'
|
|
7
|
-
import {
|
|
1
|
+
import type { SerializedError } from '../types/core.types.js'
|
|
2
|
+
import type {
|
|
8
3
|
WorkflowRun,
|
|
9
4
|
WorkflowRunWire,
|
|
10
5
|
StepState,
|
|
@@ -37,11 +32,6 @@ export interface WorkflowService {
|
|
|
37
32
|
|
|
38
33
|
// Orchestration operations
|
|
39
34
|
resumeWorkflow(runId: string): Promise<void>
|
|
40
|
-
setServices(
|
|
41
|
-
singletonServices: CoreSingletonServices,
|
|
42
|
-
createWireServices: CreateWireServices | undefined,
|
|
43
|
-
config: CoreConfig
|
|
44
|
-
): void
|
|
45
35
|
startWorkflow<I>(
|
|
46
36
|
name: string,
|
|
47
37
|
input: I,
|
package/src/time-utils.test.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { describe, test } from 'node:test'
|
|
2
2
|
import assert from 'node:assert/strict'
|
|
3
3
|
|
|
4
|
+
import type { RelativeTimeInput } from './time-utils'
|
|
4
5
|
import {
|
|
5
6
|
getRelativeTimeOffset,
|
|
6
7
|
getRelativeTimeOffsetFromNow,
|
|
7
|
-
RelativeTimeInput,
|
|
8
8
|
} from './time-utils'
|
|
9
9
|
|
|
10
10
|
const approxEqual = (a: number, b: number, delta: number = 10): boolean =>
|