@pikku/core 0.12.0 → 0.12.2
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 +40 -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/middleware-runner.js +1 -0
- package/dist/permissions.d.ts +2 -2
- package/dist/permissions.js +1 -0
- package/dist/pikku-state.d.ts +9 -8
- package/dist/pikku-state.js +34 -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/gateway-service.d.ts +19 -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 +5 -2
- package/dist/services/index.js +2 -0
- package/dist/services/local-content.d.ts +2 -1
- package/dist/services/local-content.js +6 -1
- package/dist/services/local-gateway-service.d.ts +22 -0
- package/dist/services/local-gateway-service.js +51 -0
- 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 +27 -19
- package/dist/types/state.types.d.ts +22 -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 +168 -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-memory.js +13 -2
- package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +4 -5
- package/dist/wirings/ai-agent/ai-agent-prepare.js +80 -31
- 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 +263 -89
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +96 -4
- 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 +7 -4
- package/dist/wirings/channel/channel-handler.js +15 -5
- package/dist/wirings/channel/channel-middleware-runner.js +1 -0
- 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 +10 -6
- package/dist/wirings/channel/index.d.ts +1 -1
- package/dist/wirings/channel/local/local-channel-handler.d.ts +7 -0
- package/dist/wirings/channel/local/local-channel-handler.js +17 -0
- package/dist/wirings/channel/local/local-channel-runner.d.ts +7 -2
- package/dist/wirings/channel/local/local-channel-runner.js +18 -4
- 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 +2 -1
- package/dist/wirings/channel/pikku-abstract-channel-handler.js +1 -0
- package/dist/wirings/channel/serverless/serverless-channel-runner.d.ts +4 -4
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +26 -20
- 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-runner.js +3 -0
- package/dist/wirings/cli/cli.types.d.ts +3 -3
- package/dist/wirings/cli/command-parser.d.ts +1 -1
- package/dist/wirings/gateway/gateway-runner.d.ts +24 -0
- package/dist/wirings/gateway/gateway-runner.js +325 -0
- package/dist/wirings/gateway/gateway.types.d.ts +127 -0
- package/dist/wirings/gateway/index.d.ts +2 -0
- package/dist/wirings/gateway/index.js +1 -0
- package/dist/wirings/http/http-runner.d.ts +9 -9
- package/dist/wirings/http/http-runner.js +36 -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 +4 -2
- 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 +2 -1
- package/src/permissions.test.ts +2 -2
- package/src/permissions.ts +3 -2
- package/src/pikku-state.test.ts +224 -0
- package/src/pikku-state.ts +45 -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/gateway-service.ts +20 -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 +4 -1
- package/src/services/local-content.ts +9 -3
- package/src/services/local-gateway-service.ts +62 -0
- 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 +28 -19
- package/src/types/state.types.ts +32 -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 +238 -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-memory.ts +10 -1
- package/src/wirings/ai-agent/ai-agent-model-config.test.ts +115 -0
- package/src/wirings/ai-agent/ai-agent-prepare.ts +98 -46
- 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 +390 -104
- package/src/wirings/ai-agent/ai-agent.types.ts +91 -4
- package/src/wirings/ai-agent/index.ts +13 -0
- package/src/wirings/channel/channel-common.ts +2 -2
- package/src/wirings/channel/channel-handler.ts +43 -11
- package/src/wirings/channel/channel-middleware-runner.ts +1 -0
- 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 +15 -8
- package/src/wirings/channel/index.ts +1 -0
- package/src/wirings/channel/local/local-channel-handler.ts +26 -0
- package/src/wirings/channel/local/local-channel-runner.test.ts +19 -12
- package/src/wirings/channel/local/local-channel-runner.ts +33 -14
- 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.test.ts +2 -0
- package/src/wirings/channel/pikku-abstract-channel-handler.ts +8 -1
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +38 -33
- 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 +14 -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/gateway/gateway-runner.test.ts +474 -0
- package/src/wirings/gateway/gateway-runner.ts +411 -0
- package/src/wirings/gateway/gateway.types.ts +149 -0
- package/src/wirings/gateway/index.ts +13 -0
- 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 +46 -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/src/wirings/workflow/workflow-utils.ts +0 -0
- /package/dist/{wirings/workflow/workflow-utils.d.ts → services/gateway-service.js} +0 -0
- /package/dist/wirings/{workflow/workflow-utils.js → gateway/gateway.types.js} +0 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { describe, test } from 'node:test'
|
|
2
|
+
import assert from 'node:assert'
|
|
3
|
+
import { LocalSecretService } from './local-secrets.js'
|
|
4
|
+
import { LocalVariablesService } from './local-variables.js'
|
|
5
|
+
|
|
6
|
+
describe('LocalSecretService', () => {
|
|
7
|
+
test('should get secret from local storage', async () => {
|
|
8
|
+
const service = new LocalSecretService()
|
|
9
|
+
await service.setSecretJSON('MY_KEY', { token: 'abc' })
|
|
10
|
+
const result = await service.getSecret('MY_KEY')
|
|
11
|
+
assert.strictEqual(result, '{"token":"abc"}')
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
test('should get secret from environment variables', async () => {
|
|
15
|
+
const vars = new LocalVariablesService({ MY_SECRET: 'secret-value' })
|
|
16
|
+
const service = new LocalSecretService(vars)
|
|
17
|
+
const result = await service.getSecret('MY_SECRET')
|
|
18
|
+
assert.strictEqual(result, 'secret-value')
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
test('should throw when secret not found', async () => {
|
|
22
|
+
const vars = new LocalVariablesService({})
|
|
23
|
+
const service = new LocalSecretService(vars)
|
|
24
|
+
await assert.rejects(() => service.getSecret('MISSING'), {
|
|
25
|
+
message: 'Secret Not Found: MISSING',
|
|
26
|
+
})
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
test('should get JSON secret from local storage', async () => {
|
|
30
|
+
const service = new LocalSecretService()
|
|
31
|
+
await service.setSecretJSON('JSON_KEY', { data: 42 })
|
|
32
|
+
const result = await service.getSecretJSON('JSON_KEY')
|
|
33
|
+
assert.deepStrictEqual(result, { data: 42 })
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test('should get JSON secret from environment variables', async () => {
|
|
37
|
+
const vars = new LocalVariablesService({ CONFIG: '{"port":3000}' })
|
|
38
|
+
const service = new LocalSecretService(vars)
|
|
39
|
+
const result = await service.getSecretJSON('CONFIG')
|
|
40
|
+
assert.deepStrictEqual(result, { port: 3000 })
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
test('should throw when JSON secret not found', async () => {
|
|
44
|
+
const vars = new LocalVariablesService({})
|
|
45
|
+
const service = new LocalSecretService(vars)
|
|
46
|
+
await assert.rejects(() => service.getSecretJSON('MISSING'), {
|
|
47
|
+
message: 'Secret Not Found: MISSING',
|
|
48
|
+
})
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
test('should prefer local storage over env variables', async () => {
|
|
52
|
+
const vars = new LocalVariablesService({ KEY: 'env-value' })
|
|
53
|
+
const service = new LocalSecretService(vars)
|
|
54
|
+
await service.setSecretJSON('KEY', 'local-value')
|
|
55
|
+
const result = await service.getSecret('KEY')
|
|
56
|
+
assert.strictEqual(result, '"local-value"')
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
test('should check hasSecret in local storage', async () => {
|
|
60
|
+
const vars = new LocalVariablesService({})
|
|
61
|
+
const service = new LocalSecretService(vars)
|
|
62
|
+
await service.setSecretJSON('EXISTS', 'yes')
|
|
63
|
+
assert.strictEqual(await service.hasSecret('EXISTS'), true)
|
|
64
|
+
assert.strictEqual(await service.hasSecret('NOPE'), false)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
test('should check hasSecret in environment', async () => {
|
|
68
|
+
const vars = new LocalVariablesService({ ENV_KEY: 'val' })
|
|
69
|
+
const service = new LocalSecretService(vars)
|
|
70
|
+
assert.strictEqual(await service.hasSecret('ENV_KEY'), true)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
test('should delete secret from local storage', async () => {
|
|
74
|
+
const service = new LocalSecretService()
|
|
75
|
+
await service.setSecretJSON('DEL_KEY', 'value')
|
|
76
|
+
assert.strictEqual(await service.hasSecret('DEL_KEY'), true)
|
|
77
|
+
await service.deleteSecret('DEL_KEY')
|
|
78
|
+
assert.strictEqual(await service.hasSecret('DEL_KEY'), false)
|
|
79
|
+
})
|
|
80
|
+
})
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LocalVariablesService } from './local-variables.js'
|
|
2
|
-
import { SecretService } from './secret-service.js'
|
|
3
|
-
import { VariablesService } from './variables-service.js'
|
|
2
|
+
import type { SecretService } from './secret-service.js'
|
|
3
|
+
import type { VariablesService } from './variables-service.js'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Service for retrieving secrets from environment variables.
|
|
@@ -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
|
+
})
|