@pikku/core 0.12.20 → 0.12.21
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 +11 -0
- package/dist/dev/hot-reload.js +20 -6
- package/dist/errors/error-handler.d.ts +1 -1
- package/dist/errors/error-handler.js +2 -2
- package/dist/function/functions.types.d.ts +3 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/middleware/index.d.ts +2 -2
- package/dist/middleware/index.js +2 -2
- package/dist/middleware/telemetry.d.ts +2 -2
- package/dist/middleware/telemetry.js +2 -2
- package/dist/middleware-runner.d.ts +15 -27
- package/dist/middleware-runner.js +25 -30
- package/dist/permissions.d.ts +15 -22
- package/dist/permissions.js +30 -25
- package/dist/pikku-request.js +1 -1
- package/dist/pikku-state.js +2 -3
- package/dist/services/ai-agent-runner-service.d.ts +1 -0
- package/dist/services/in-memory-queue-service.js +1 -1
- package/dist/services/in-memory-workflow-service.d.ts +15 -13
- package/dist/services/in-memory-workflow-service.js +31 -13
- package/dist/services/local-content.js +8 -1
- package/dist/services/user-session-service.d.ts +1 -1
- package/dist/testing/service-tests.js +24 -0
- package/dist/types/core.types.d.ts +4 -0
- package/dist/types/state.types.d.ts +2 -18
- package/dist/wirings/ai-agent/ai-agent-memory.d.ts +24 -5
- package/dist/wirings/ai-agent/ai-agent-memory.js +128 -23
- package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +10 -1
- package/dist/wirings/ai-agent/ai-agent-model-config.js +15 -35
- package/dist/wirings/ai-agent/ai-agent-prepare.js +4 -1
- package/dist/wirings/ai-agent/ai-agent-runner.js +45 -31
- package/dist/wirings/ai-agent/ai-agent-stream.js +63 -34
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +20 -0
- package/dist/wirings/channel/channel-handler.js +1 -1
- package/dist/wirings/channel/channel-store.d.ts +13 -0
- package/dist/wirings/channel/channel.types.d.ts +3 -0
- package/dist/wirings/channel/local/local-channel-runner.js +23 -5
- package/dist/wirings/channel/pikku-abstract-channel-handler.js +8 -0
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +9 -0
- package/dist/wirings/cli/cli-runner.js +24 -5
- package/dist/wirings/cli/command-parser.js +19 -4
- package/dist/wirings/http/http-runner.js +72 -36
- package/dist/wirings/http/http.types.d.ts +1 -0
- package/dist/wirings/http/pikku-fetch-http-request.js +3 -1
- package/dist/wirings/http/web-request.js +32 -0
- package/dist/wirings/rpc/rpc-runner.js +13 -3
- package/dist/wirings/workflow/graph/graph-node.d.ts +8 -0
- package/dist/wirings/workflow/graph/graph-node.js +4 -0
- package/dist/wirings/workflow/graph/graph-runner.js +12 -10
- package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +4 -0
- package/dist/wirings/workflow/index.d.ts +1 -1
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +81 -16
- package/dist/wirings/workflow/pikku-workflow-service.js +266 -45
- package/dist/wirings/workflow/workflow.types.d.ts +34 -0
- package/package.json +1 -1
- package/run-tests.sh +4 -1
- package/src/dev/hot-reload.test.ts +62 -11
- package/src/dev/hot-reload.ts +28 -7
- package/src/errors/error-handler.ts +8 -2
- package/src/errors/error.test.ts +2 -0
- package/src/function/function-runner.test.ts +500 -10
- package/src/function/functions.types.ts +3 -2
- package/src/index.ts +12 -2
- package/src/middleware/index.ts +11 -2
- package/src/middleware/telemetry.ts +2 -2
- package/src/middleware-runner.test.ts +16 -16
- package/src/middleware-runner.ts +42 -30
- package/src/permissions.test.ts +27 -24
- package/src/permissions.ts +41 -25
- package/src/pikku-request.test.ts +35 -0
- package/src/pikku-request.ts +1 -1
- package/src/pikku-state.ts +2 -3
- package/src/run-tests-script.test.ts +18 -0
- package/src/services/ai-agent-runner-service.ts +1 -0
- package/src/services/in-memory-queue-service.ts +1 -1
- package/src/services/in-memory-session-store.ts +1 -2
- package/src/services/in-memory-workflow-service.test.ts +33 -11
- package/src/services/in-memory-workflow-service.ts +49 -13
- package/src/services/local-content.test.ts +54 -0
- package/src/services/local-content.ts +12 -1
- package/src/services/typed-credential-service.ts +3 -3
- package/src/services/typed-secret-service.ts +3 -3
- package/src/services/typed-variables-service.ts +3 -3
- package/src/services/user-session-service.ts +4 -4
- package/src/testing/service-tests.ts +30 -0
- package/src/types/core.types.ts +6 -2
- package/src/types/state.types.ts +2 -13
- package/src/wirings/ai-agent/ai-agent-memory.test.ts +324 -0
- package/src/wirings/ai-agent/ai-agent-memory.ts +187 -36
- package/src/wirings/ai-agent/ai-agent-model-config.test.ts +12 -90
- package/src/wirings/ai-agent/ai-agent-model-config.ts +14 -38
- package/src/wirings/ai-agent/ai-agent-prepare.test.ts +292 -0
- package/src/wirings/ai-agent/ai-agent-prepare.ts +4 -1
- package/src/wirings/ai-agent/ai-agent-registry.test.ts +230 -3
- package/src/wirings/ai-agent/ai-agent-runner.test.ts +625 -6
- package/src/wirings/ai-agent/ai-agent-runner.ts +65 -50
- package/src/wirings/ai-agent/ai-agent-stream.test.ts +544 -5
- package/src/wirings/ai-agent/ai-agent-stream.ts +71 -69
- package/src/wirings/ai-agent/ai-agent.types.ts +24 -0
- package/src/wirings/channel/channel-handler.test.ts +272 -0
- package/src/wirings/channel/channel-handler.ts +1 -1
- package/src/wirings/channel/channel-middleware-runner.test.ts +163 -0
- package/src/wirings/channel/channel-store.ts +19 -0
- package/src/wirings/channel/channel.types.ts +4 -0
- package/src/wirings/channel/local/local-channel-runner.test.ts +63 -0
- package/src/wirings/channel/local/local-channel-runner.ts +41 -5
- package/src/wirings/channel/local/local-eventhub-service.ts +3 -3
- package/src/wirings/channel/pikku-abstract-channel-handler.ts +9 -2
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +23 -5
- package/src/wirings/cli/channel/cli-raw-channel-runner.ts +7 -2
- package/src/wirings/cli/cli-runner.test.ts +255 -2
- package/src/wirings/cli/cli-runner.ts +31 -10
- package/src/wirings/cli/cli.types.ts +4 -8
- package/src/wirings/cli/command-parser.test.ts +83 -0
- package/src/wirings/cli/command-parser.ts +23 -4
- package/src/wirings/http/http-runner.test.ts +296 -1
- package/src/wirings/http/http-runner.ts +87 -57
- package/src/wirings/http/http.types.ts +11 -26
- package/src/wirings/http/pikku-fetch-http-request.ts +8 -4
- package/src/wirings/http/pikku-fetch-http-response.test.ts +41 -0
- package/src/wirings/http/web-request.test.ts +115 -0
- package/src/wirings/http/web-request.ts +43 -5
- package/src/wirings/mcp/mcp-runner.test.ts +367 -0
- package/src/wirings/queue/queue.types.ts +2 -5
- package/src/wirings/rpc/rpc-runner.test.ts +511 -0
- package/src/wirings/rpc/rpc-runner.ts +15 -3
- package/src/wirings/rpc/wire-addon.test.ts +57 -0
- package/src/wirings/workflow/graph/graph-node.ts +12 -0
- package/src/wirings/workflow/graph/graph-runner.test.ts +98 -0
- package/src/wirings/workflow/graph/graph-runner.ts +28 -10
- package/src/wirings/workflow/graph/workflow-graph.types.ts +4 -0
- package/src/wirings/workflow/index.ts +1 -0
- package/src/wirings/workflow/pikku-workflow-service.test.ts +19 -2
- package/src/wirings/workflow/pikku-workflow-service.ts +370 -71
- package/src/wirings/workflow/workflow-queue-workers.test.ts +131 -0
- package/src/wirings/workflow/workflow.types.ts +68 -5
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { describe, test, beforeEach } from 'node:test'
|
|
2
2
|
import assert from 'node:assert'
|
|
3
3
|
import { InMemoryWorkflowService } from './in-memory-workflow-service.js'
|
|
4
|
+
import { getQueueWorkers } from '../wirings/queue/queue-runner.js'
|
|
5
|
+
import { pikkuState } from '../pikku-state.js'
|
|
4
6
|
|
|
5
7
|
let service: InMemoryWorkflowService
|
|
6
8
|
|
|
@@ -48,17 +50,10 @@ describe('InMemoryWorkflowService', () => {
|
|
|
48
50
|
})
|
|
49
51
|
|
|
50
52
|
test('should persist deterministic planned steps metadata', async () => {
|
|
51
|
-
const runId = await service.createRun(
|
|
52
|
-
|
|
53
|
-
{},
|
|
54
|
-
|
|
55
|
-
'h',
|
|
56
|
-
{} as any,
|
|
57
|
-
{
|
|
58
|
-
deterministic: true,
|
|
59
|
-
plannedSteps: [{ stepName: 'Step 1' }, { stepName: 'Step 2' }],
|
|
60
|
-
}
|
|
61
|
-
)
|
|
53
|
+
const runId = await service.createRun('wf', {}, true, 'h', {} as any, {
|
|
54
|
+
deterministic: true,
|
|
55
|
+
plannedSteps: [{ stepName: 'Step 1' }, { stepName: 'Step 2' }],
|
|
56
|
+
})
|
|
62
57
|
|
|
63
58
|
const run = await service.getRun(runId)
|
|
64
59
|
assert.strictEqual(run?.deterministic, true)
|
|
@@ -369,4 +364,31 @@ describe('InMemoryWorkflowService', () => {
|
|
|
369
364
|
assert.deepStrictEqual(history, [])
|
|
370
365
|
})
|
|
371
366
|
})
|
|
367
|
+
|
|
368
|
+
describe('queue worker registration', () => {
|
|
369
|
+
test('rewireQueueWorkers registers workflow queues added after construction', () => {
|
|
370
|
+
const stepQueue = 'wf-step-regression-enrich'
|
|
371
|
+
const orchQueue = 'wf-orchestrator-regression-onboarding'
|
|
372
|
+
|
|
373
|
+
const ws = new InMemoryWorkflowService()
|
|
374
|
+
|
|
375
|
+
const queueMeta = pikkuState(null, 'queue', 'meta')
|
|
376
|
+
queueMeta[stepQueue] = {
|
|
377
|
+
name: stepQueue,
|
|
378
|
+
pikkuFuncId: 'pikkuWorkflowWorker:regressionEnrich',
|
|
379
|
+
}
|
|
380
|
+
queueMeta[orchQueue] = {
|
|
381
|
+
name: orchQueue,
|
|
382
|
+
pikkuFuncId: 'pikkuWorkflowOrchestrator:regressionOnboarding',
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
assert.strictEqual(getQueueWorkers().has(stepQueue), false)
|
|
386
|
+
assert.strictEqual(getQueueWorkers().has(orchQueue), false)
|
|
387
|
+
|
|
388
|
+
ws.rewireQueueWorkers()
|
|
389
|
+
|
|
390
|
+
assert.strictEqual(getQueueWorkers().has(stepQueue), true)
|
|
391
|
+
assert.strictEqual(getQueueWorkers().has(orchQueue), true)
|
|
392
|
+
})
|
|
393
|
+
})
|
|
372
394
|
})
|
|
@@ -37,6 +37,7 @@ export class InMemoryWorkflowService
|
|
|
37
37
|
extends PikkuWorkflowService
|
|
38
38
|
implements WorkflowRunService
|
|
39
39
|
{
|
|
40
|
+
private sleepTimers = new Set<ReturnType<typeof setTimeout>>()
|
|
40
41
|
private runs = new Map<string, WorkflowRun>()
|
|
41
42
|
private steps = new Map<string, StepState>() // keyed by `${runId}:${stepName}`
|
|
42
43
|
private stepData = new Map<string, InternalStepData>() // keyed by stepId
|
|
@@ -51,7 +52,7 @@ export class InMemoryWorkflowService
|
|
|
51
52
|
{ graph: any; source: string; status: WorkflowVersionStatus }
|
|
52
53
|
>() // keyed by `${name}:${graphHash}`
|
|
53
54
|
|
|
54
|
-
async
|
|
55
|
+
protected async createRunImpl(
|
|
55
56
|
workflowName: string,
|
|
56
57
|
input: any,
|
|
57
58
|
inline: boolean,
|
|
@@ -90,6 +91,25 @@ export class InMemoryWorkflowService
|
|
|
90
91
|
return runId
|
|
91
92
|
}
|
|
92
93
|
|
|
94
|
+
protected override async scheduleSleep(
|
|
95
|
+
runId: string,
|
|
96
|
+
stepId: string,
|
|
97
|
+
duration: number
|
|
98
|
+
): Promise<boolean> {
|
|
99
|
+
const timer = setTimeout(async () => {
|
|
100
|
+
this.sleepTimers.delete(timer)
|
|
101
|
+
try {
|
|
102
|
+
await this.executeWorkflowSleepCompleted(runId, stepId)
|
|
103
|
+
} catch (error: any) {
|
|
104
|
+
this.logger?.error(
|
|
105
|
+
`Failed to resume workflow sleep for runId ${runId}: ${error?.message ?? error}`
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
}, duration)
|
|
109
|
+
this.sleepTimers.add(timer)
|
|
110
|
+
return true
|
|
111
|
+
}
|
|
112
|
+
|
|
93
113
|
async getRun(id: string): Promise<WorkflowRun | null> {
|
|
94
114
|
return this.runs.get(id) || null
|
|
95
115
|
}
|
|
@@ -100,7 +120,7 @@ export class InMemoryWorkflowService
|
|
|
100
120
|
return this.stepHistory.get(runId) || []
|
|
101
121
|
}
|
|
102
122
|
|
|
103
|
-
async
|
|
123
|
+
protected async updateRunStatusImpl(
|
|
104
124
|
id: string,
|
|
105
125
|
status: WorkflowStatus,
|
|
106
126
|
output?: any,
|
|
@@ -115,7 +135,7 @@ export class InMemoryWorkflowService
|
|
|
115
135
|
}
|
|
116
136
|
}
|
|
117
137
|
|
|
118
|
-
async
|
|
138
|
+
protected async insertStepStateImpl(
|
|
119
139
|
runId: string,
|
|
120
140
|
stepName: string,
|
|
121
141
|
rpcName: string | null,
|
|
@@ -159,7 +179,7 @@ export class InMemoryWorkflowService
|
|
|
159
179
|
return step
|
|
160
180
|
}
|
|
161
181
|
|
|
162
|
-
async
|
|
182
|
+
protected async setStepRunningImpl(stepId: string): Promise<void> {
|
|
163
183
|
for (const step of this.steps.values()) {
|
|
164
184
|
if (step.stepId === stepId) {
|
|
165
185
|
step.status = 'running'
|
|
@@ -170,7 +190,7 @@ export class InMemoryWorkflowService
|
|
|
170
190
|
}
|
|
171
191
|
}
|
|
172
192
|
|
|
173
|
-
async
|
|
193
|
+
protected async setStepScheduledImpl(stepId: string): Promise<void> {
|
|
174
194
|
for (const step of this.steps.values()) {
|
|
175
195
|
if (step.stepId === stepId) {
|
|
176
196
|
step.status = 'scheduled'
|
|
@@ -181,7 +201,10 @@ export class InMemoryWorkflowService
|
|
|
181
201
|
}
|
|
182
202
|
}
|
|
183
203
|
|
|
184
|
-
async
|
|
204
|
+
protected async setStepResultImpl(
|
|
205
|
+
stepId: string,
|
|
206
|
+
result: any
|
|
207
|
+
): Promise<void> {
|
|
185
208
|
for (const step of this.steps.values()) {
|
|
186
209
|
if (step.stepId === stepId) {
|
|
187
210
|
step.status = 'succeeded'
|
|
@@ -193,7 +216,10 @@ export class InMemoryWorkflowService
|
|
|
193
216
|
}
|
|
194
217
|
}
|
|
195
218
|
|
|
196
|
-
async
|
|
219
|
+
protected async setStepErrorImpl(
|
|
220
|
+
stepId: string,
|
|
221
|
+
error: Error
|
|
222
|
+
): Promise<void> {
|
|
197
223
|
for (const step of this.steps.values()) {
|
|
198
224
|
if (step.stepId === stepId) {
|
|
199
225
|
step.status = 'failed'
|
|
@@ -209,7 +235,10 @@ export class InMemoryWorkflowService
|
|
|
209
235
|
}
|
|
210
236
|
}
|
|
211
237
|
|
|
212
|
-
async
|
|
238
|
+
protected async setStepChildRunIdImpl(
|
|
239
|
+
stepId: string,
|
|
240
|
+
childRunId: string
|
|
241
|
+
): Promise<void> {
|
|
213
242
|
for (const step of this.steps.values()) {
|
|
214
243
|
if (step.stepId === stepId) {
|
|
215
244
|
step.childRunId = childRunId
|
|
@@ -219,7 +248,7 @@ export class InMemoryWorkflowService
|
|
|
219
248
|
}
|
|
220
249
|
}
|
|
221
250
|
|
|
222
|
-
async
|
|
251
|
+
protected async createRetryAttemptImpl(
|
|
223
252
|
failedStepId: string,
|
|
224
253
|
status: 'pending' | 'running'
|
|
225
254
|
): Promise<StepState> {
|
|
@@ -354,6 +383,10 @@ export class InMemoryWorkflowService
|
|
|
354
383
|
}
|
|
355
384
|
|
|
356
385
|
async close(): Promise<void> {
|
|
386
|
+
for (const timer of this.sleepTimers) {
|
|
387
|
+
clearTimeout(timer)
|
|
388
|
+
}
|
|
389
|
+
this.sleepTimers.clear()
|
|
357
390
|
// Clear all in-memory state
|
|
358
391
|
this.runs.clear()
|
|
359
392
|
this.steps.clear()
|
|
@@ -439,11 +472,14 @@ export class InMemoryWorkflowService
|
|
|
439
472
|
}
|
|
440
473
|
}
|
|
441
474
|
|
|
442
|
-
async
|
|
475
|
+
protected async setBranchTakenImpl(
|
|
476
|
+
stepId: string,
|
|
477
|
+
branchKey: string
|
|
478
|
+
): Promise<void> {
|
|
443
479
|
this.branchKeys.set(stepId, branchKey)
|
|
444
480
|
}
|
|
445
481
|
|
|
446
|
-
async
|
|
482
|
+
protected async updateRunStateImpl(
|
|
447
483
|
runId: string,
|
|
448
484
|
name: string,
|
|
449
485
|
value: unknown
|
|
@@ -457,7 +493,7 @@ export class InMemoryWorkflowService
|
|
|
457
493
|
return this.runState.get(runId) || {}
|
|
458
494
|
}
|
|
459
495
|
|
|
460
|
-
async
|
|
496
|
+
protected async upsertWorkflowVersionImpl(
|
|
461
497
|
name: string,
|
|
462
498
|
graphHash: string,
|
|
463
499
|
graph: any,
|
|
@@ -471,7 +507,7 @@ export class InMemoryWorkflowService
|
|
|
471
507
|
})
|
|
472
508
|
}
|
|
473
509
|
|
|
474
|
-
async
|
|
510
|
+
protected async updateWorkflowVersionStatusImpl(
|
|
475
511
|
name: string,
|
|
476
512
|
graphHash: string,
|
|
477
513
|
status: WorkflowVersionStatus
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import assert from 'node:assert/strict'
|
|
2
|
+
import { describe, test } from 'node:test'
|
|
3
|
+
|
|
4
|
+
import { LocalContent } from './local-content.js'
|
|
5
|
+
|
|
6
|
+
describe('LocalContent signing', () => {
|
|
7
|
+
test('binds notBefore into the signature payload', async () => {
|
|
8
|
+
let capturedPayload:
|
|
9
|
+
| { signedAt: number; expiresAt: number; notBefore?: number }
|
|
10
|
+
| undefined
|
|
11
|
+
|
|
12
|
+
const content = new LocalContent(
|
|
13
|
+
{
|
|
14
|
+
localFileUploadPath: '/tmp/uploads',
|
|
15
|
+
uploadUrlPrefix: '/reaper',
|
|
16
|
+
assetUrlPrefix: '/assets',
|
|
17
|
+
server: 'http://localhost:3000',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
info: () => {},
|
|
21
|
+
warn: () => {},
|
|
22
|
+
error: () => {},
|
|
23
|
+
debug: () => {},
|
|
24
|
+
setLevel: () => {},
|
|
25
|
+
} as any,
|
|
26
|
+
{
|
|
27
|
+
encode: async (_expiresIn: any, payload: any) => {
|
|
28
|
+
capturedPayload = payload
|
|
29
|
+
return 'signed-token'
|
|
30
|
+
},
|
|
31
|
+
decode: async () => ({}),
|
|
32
|
+
}
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
const dateGreaterThan = new Date(Date.now() + 60_000)
|
|
36
|
+
const dateLessThan = new Date(Date.now() + 120_000)
|
|
37
|
+
const signedUrl = await content.signContentKey({
|
|
38
|
+
bucket: 'avatars',
|
|
39
|
+
contentKey: 'user-1.png',
|
|
40
|
+
dateLessThan,
|
|
41
|
+
dateGreaterThan,
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
const url = new URL(signedUrl)
|
|
45
|
+
assert.equal(url.searchParams.get('signature'), 'signed-token')
|
|
46
|
+
assert.ok(capturedPayload)
|
|
47
|
+
assert.equal(capturedPayload?.expiresAt, dateLessThan.getTime())
|
|
48
|
+
assert.equal(capturedPayload?.notBefore, dateGreaterThan.getTime())
|
|
49
|
+
assert.equal(
|
|
50
|
+
url.searchParams.get('notBefore'),
|
|
51
|
+
String(dateGreaterThan.getTime())
|
|
52
|
+
)
|
|
53
|
+
})
|
|
54
|
+
})
|
|
@@ -65,9 +65,20 @@ export class LocalContent implements ContentService {
|
|
|
65
65
|
1,
|
|
66
66
|
Math.floor((expiresAt - signedAt) / 1000)
|
|
67
67
|
)
|
|
68
|
+
const payload: {
|
|
69
|
+
signedAt: number
|
|
70
|
+
expiresAt: number
|
|
71
|
+
notBefore?: number
|
|
72
|
+
} = {
|
|
73
|
+
signedAt,
|
|
74
|
+
expiresAt,
|
|
75
|
+
}
|
|
76
|
+
if (dateGreaterThan) {
|
|
77
|
+
payload.notBefore = dateGreaterThan.getTime()
|
|
78
|
+
}
|
|
68
79
|
const signature = await this.jwt.encode(
|
|
69
80
|
{ value: expiresInSeconds, unit: 'second' },
|
|
70
|
-
|
|
81
|
+
payload
|
|
71
82
|
)
|
|
72
83
|
params.set('signature', signature)
|
|
73
84
|
}
|
|
@@ -15,9 +15,9 @@ export type CredentialMetaInfo = {
|
|
|
15
15
|
oauth2?: boolean
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export class TypedCredentialService<
|
|
19
|
-
|
|
20
|
-
{
|
|
18
|
+
export class TypedCredentialService<
|
|
19
|
+
TMap = Record<string, unknown>,
|
|
20
|
+
> implements CredentialService {
|
|
21
21
|
constructor(
|
|
22
22
|
private credentials: CredentialService,
|
|
23
23
|
private credentialsMeta: Record<string, CredentialMetaInfo>
|
|
@@ -14,9 +14,9 @@ export type CredentialMeta = {
|
|
|
14
14
|
oauth2?: { tokenSecretId: string }
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
export class TypedSecretService<
|
|
18
|
-
|
|
19
|
-
{
|
|
17
|
+
export class TypedSecretService<
|
|
18
|
+
TMap = Record<string, unknown>,
|
|
19
|
+
> implements SecretService {
|
|
20
20
|
constructor(
|
|
21
21
|
private secrets: SecretService,
|
|
22
22
|
private credentialsMeta: Record<string, CredentialMeta>
|
|
@@ -12,9 +12,9 @@ export type VariableMeta = {
|
|
|
12
12
|
displayName: string
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
export class TypedVariablesService<
|
|
16
|
-
|
|
17
|
-
{
|
|
15
|
+
export class TypedVariablesService<
|
|
16
|
+
TMap = Record<string, unknown>,
|
|
17
|
+
> implements VariablesService {
|
|
18
18
|
constructor(
|
|
19
19
|
private variables: VariablesService,
|
|
20
20
|
private variablesMeta: Record<string, VariableMeta>
|
|
@@ -11,12 +11,12 @@ export interface SessionService<UserSession extends CoreUserSession> {
|
|
|
11
11
|
get(): UserSession | undefined
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
export class PikkuSessionService<
|
|
15
|
-
|
|
16
|
-
{
|
|
14
|
+
export class PikkuSessionService<
|
|
15
|
+
UserSession extends CoreUserSession,
|
|
16
|
+
> implements SessionService<UserSession> {
|
|
17
17
|
public sessionChanged = false
|
|
18
18
|
public initial: UserSession | undefined
|
|
19
|
-
|
|
19
|
+
protected session: UserSession | undefined
|
|
20
20
|
private pikkuUserId?: string
|
|
21
21
|
|
|
22
22
|
constructor(private sessionStore?: SessionStore<UserSession>) {}
|
|
@@ -102,6 +102,36 @@ export function defineServiceTests(config: ServiceTestConfig): void {
|
|
|
102
102
|
test('removeChannels with empty array is no-op', async () => {
|
|
103
103
|
await store.removeChannels([])
|
|
104
104
|
})
|
|
105
|
+
|
|
106
|
+
test('session round-trip — set / get / clear', async () => {
|
|
107
|
+
await store.addChannel({
|
|
108
|
+
channelId: 'ch-state',
|
|
109
|
+
channelName: 'test-channel',
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
// initially undefined
|
|
113
|
+
const empty = await store.getState('ch-state')
|
|
114
|
+
assert.equal(empty, undefined)
|
|
115
|
+
|
|
116
|
+
// set + get
|
|
117
|
+
const payload = { userId: 'u-7', meta: { foo: 1 } }
|
|
118
|
+
await store.setState('ch-state', payload)
|
|
119
|
+
const got = await store.getState('ch-state')
|
|
120
|
+
assert.deepEqual(got, payload)
|
|
121
|
+
|
|
122
|
+
// overwrite
|
|
123
|
+
const next = { userId: 'u-8' }
|
|
124
|
+
await store.setState('ch-state', next)
|
|
125
|
+
const got2 = await store.getState('ch-state')
|
|
126
|
+
assert.deepEqual(got2, next)
|
|
127
|
+
|
|
128
|
+
// clear
|
|
129
|
+
await store.clearState('ch-state')
|
|
130
|
+
const after = await store.getState('ch-state')
|
|
131
|
+
assert.equal(after, undefined)
|
|
132
|
+
|
|
133
|
+
await store.removeChannels(['ch-state'])
|
|
134
|
+
})
|
|
105
135
|
})
|
|
106
136
|
}
|
|
107
137
|
|
package/src/types/core.types.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
CorePikkuChannelMiddleware,
|
|
10
10
|
CorePikkuChannelMiddlewareFactory,
|
|
11
11
|
} from '../wirings/channel/channel.types.js'
|
|
12
|
+
import type { EventHubService } from '../wirings/channel/eventhub-service.js'
|
|
12
13
|
import type { PikkuRPC } from '../wirings/rpc/rpc-types.js'
|
|
13
14
|
import type { PikkuMCP } from '../wirings/mcp/mcp.types.js'
|
|
14
15
|
import type { PikkuScheduledTask } from '../wirings/scheduler/scheduler.types.js'
|
|
@@ -115,6 +116,7 @@ export type FunctionRuntimeMeta = {
|
|
|
115
116
|
version?: number
|
|
116
117
|
approvalRequired?: boolean
|
|
117
118
|
approvalDescription?: string
|
|
119
|
+
implementationHash?: string
|
|
118
120
|
contractHash?: string
|
|
119
121
|
inputHash?: string
|
|
120
122
|
outputHash?: string
|
|
@@ -216,6 +218,8 @@ export interface CoreSingletonServices<Config extends CoreConfig = CoreConfig> {
|
|
|
216
218
|
workflowService?: WorkflowService
|
|
217
219
|
/** The queue service */
|
|
218
220
|
queueService?: QueueService
|
|
221
|
+
/** Event hub for realtime pub/sub across channels */
|
|
222
|
+
eventHub?: EventHubService<Record<string, any>>
|
|
219
223
|
/** The scheduler service */
|
|
220
224
|
schedulerService?: SchedulerService
|
|
221
225
|
/** The deployment service for service discovery */
|
|
@@ -485,8 +489,8 @@ export type CreateSingletonServices<
|
|
|
485
489
|
*/
|
|
486
490
|
export type CreateWireServices<
|
|
487
491
|
SingletonServices extends CoreSingletonServices = CoreSingletonServices,
|
|
488
|
-
Services extends
|
|
489
|
-
CoreServices<SingletonServices
|
|
492
|
+
Services extends CoreServices<SingletonServices> =
|
|
493
|
+
CoreServices<SingletonServices>,
|
|
490
494
|
UserSession extends CoreUserSession = CoreUserSession,
|
|
491
495
|
> = (
|
|
492
496
|
services: SingletonServices,
|
package/src/types/state.types.ts
CHANGED
|
@@ -138,6 +138,7 @@ export interface PikkuPackageState {
|
|
|
138
138
|
middleware: {
|
|
139
139
|
tagGroup: Record<string, CorePikkuMiddlewareGroup>
|
|
140
140
|
httpGroup: Record<string, CorePikkuMiddlewareGroup>
|
|
141
|
+
global: CorePikkuMiddlewareGroup
|
|
141
142
|
}
|
|
142
143
|
channelMiddleware: {
|
|
143
144
|
tagGroup: Record<string, CorePikkuChannelMiddleware[]>
|
|
@@ -145,6 +146,7 @@ export interface PikkuPackageState {
|
|
|
145
146
|
permissions: {
|
|
146
147
|
tagGroup: Record<string, CorePermissionGroup | CorePikkuPermission[]>
|
|
147
148
|
httpGroup: Record<string, CorePermissionGroup | CorePikkuPermission[]>
|
|
149
|
+
global: (CorePermissionGroup | CorePikkuPermission)[]
|
|
148
150
|
}
|
|
149
151
|
misc: {
|
|
150
152
|
errors: Map<PikkuError, ErrorDetails>
|
|
@@ -153,19 +155,6 @@ export interface PikkuPackageState {
|
|
|
153
155
|
channelMiddleware: Record<string, CorePikkuChannelMiddleware[]>
|
|
154
156
|
permissions: Record<string, CorePermissionGroup | CorePikkuPermission[]>
|
|
155
157
|
}
|
|
156
|
-
models: {
|
|
157
|
-
config: {
|
|
158
|
-
models?: Record<
|
|
159
|
-
string,
|
|
160
|
-
string | { model: string; temperature?: number; maxSteps?: number }
|
|
161
|
-
>
|
|
162
|
-
agentDefaults?: { temperature?: number; maxSteps?: number }
|
|
163
|
-
agentOverrides?: Record<
|
|
164
|
-
string,
|
|
165
|
-
{ model?: string; temperature?: number; maxSteps?: number }
|
|
166
|
-
>
|
|
167
|
-
} | null
|
|
168
|
-
}
|
|
169
158
|
package: {
|
|
170
159
|
/** Service factory functions for addon packages */
|
|
171
160
|
factories: {
|