@pikku/core 0.12.19 → 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 +77 -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/function-runner.js +53 -3
- package/dist/function/functions.types.d.ts +3 -2
- package/dist/index.d.ts +3 -3
- 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/content-service.d.ts +66 -37
- 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/index.d.ts +1 -1
- package/dist/services/local-content.d.ts +10 -12
- package/dist/services/local-content.js +54 -38
- 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.d.ts +3 -2
- package/dist/wirings/rpc/rpc-runner.js +45 -11
- 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/function-runner.ts +68 -3
- package/src/function/functions.types.ts +3 -2
- package/src/index.ts +22 -3
- 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/content-service.ts +79 -51
- 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/index.ts +10 -1
- package/src/services/local-content.test.ts +54 -0
- package/src/services/local-content.ts +80 -53
- 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 +60 -21
- 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,81 +1,109 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Arguments for signing a content key into a time-limited URL.
|
|
3
|
+
*/
|
|
4
|
+
export interface SignContentKeyArgs<TBucket extends string = string> {
|
|
5
|
+
bucket: TBucket
|
|
6
|
+
contentKey: string
|
|
7
|
+
dateLessThan: Date
|
|
8
|
+
dateGreaterThan?: Date
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Arguments for signing an arbitrary URL.
|
|
13
|
+
*/
|
|
14
|
+
export interface SignURLArgs {
|
|
15
|
+
url: string
|
|
16
|
+
dateLessThan: Date
|
|
17
|
+
dateGreaterThan?: Date
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Arguments for minting a presigned upload URL.
|
|
22
|
+
*/
|
|
23
|
+
export interface GetUploadURLArgs<TBucket extends string = string> {
|
|
24
|
+
bucket: TBucket
|
|
25
|
+
fileKey: string
|
|
26
|
+
contentType: string
|
|
27
|
+
size?: number
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Result of minting a presigned upload URL.
|
|
32
|
+
*/
|
|
33
|
+
export interface UploadURLResult {
|
|
34
|
+
uploadUrl: string
|
|
35
|
+
assetKey: string
|
|
36
|
+
uploadHeaders?: Record<string, string>
|
|
37
|
+
uploadMethod?: 'PUT' | 'POST'
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Arguments for an operation that targets a single object by key.
|
|
42
|
+
*/
|
|
43
|
+
export interface BucketKeyArgs<TBucket extends string = string> {
|
|
44
|
+
bucket: TBucket
|
|
45
|
+
key: string
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Arguments for writing a stream to storage.
|
|
50
|
+
*/
|
|
51
|
+
export interface WriteFileArgs<
|
|
52
|
+
TBucket extends string = string,
|
|
53
|
+
> extends BucketKeyArgs<TBucket> {
|
|
54
|
+
stream: ReadableStream | NodeJS.ReadableStream
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Arguments for copying a local file into storage.
|
|
59
|
+
*/
|
|
60
|
+
export interface CopyFileArgs<
|
|
61
|
+
TBucket extends string = string,
|
|
62
|
+
> extends BucketKeyArgs<TBucket> {
|
|
63
|
+
fromAbsolutePath: string
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface ContentService<TBucket extends string = string> {
|
|
2
67
|
/**
|
|
3
68
|
* Signs a content key to generate a secure, time-limited access URL.
|
|
4
|
-
* @param contentKey - The key representing the content object.
|
|
5
|
-
* @param dateLessThan - The expiration time for the signed URL.
|
|
6
|
-
* @param dateGreaterThan - (Optional) Start time before which access is denied.
|
|
7
69
|
*/
|
|
8
|
-
signContentKey(
|
|
9
|
-
contentKey: string,
|
|
10
|
-
dateLessThan: Date,
|
|
11
|
-
dateGreaterThan?: Date
|
|
12
|
-
): Promise<string>
|
|
70
|
+
signContentKey(args: SignContentKeyArgs<TBucket>): Promise<string>
|
|
13
71
|
|
|
14
72
|
/**
|
|
15
73
|
* Signs an arbitrary URL to generate a secure, time-limited access URL.
|
|
16
|
-
* @param url - The full URL that needs signing.
|
|
17
|
-
* @param dateLessThan - The expiration time for the signed URL.
|
|
18
|
-
* @param dateGreaterThan - (Optional) Start time before which access is denied.
|
|
19
74
|
*/
|
|
20
|
-
signURL(
|
|
21
|
-
url: string,
|
|
22
|
-
dateLessThan: Date,
|
|
23
|
-
dateGreaterThan?: Date
|
|
24
|
-
): Promise<string>
|
|
75
|
+
signURL(args: SignURLArgs): Promise<string>
|
|
25
76
|
|
|
26
77
|
/**
|
|
27
78
|
* Generates a signed URL for uploading a file directly to storage.
|
|
28
|
-
*
|
|
29
|
-
* @param contentType - The MIME type of the file.
|
|
30
|
-
* @returns A signed upload URL and the finalized asset key.
|
|
79
|
+
* Bucket policy (size limits, MIME allowlist) is enforced by the implementation.
|
|
31
80
|
*/
|
|
32
|
-
getUploadURL(
|
|
33
|
-
fileKey: string,
|
|
34
|
-
contentType: string
|
|
35
|
-
): Promise<{
|
|
36
|
-
uploadUrl: string
|
|
37
|
-
assetKey: string
|
|
38
|
-
uploadHeaders?: Record<string, string>
|
|
39
|
-
uploadMethod?: 'PUT' | 'POST'
|
|
40
|
-
}>
|
|
81
|
+
getUploadURL(args: GetUploadURLArgs<TBucket>): Promise<UploadURLResult>
|
|
41
82
|
|
|
42
83
|
/**
|
|
43
84
|
* Deletes a file from the storage backend.
|
|
44
|
-
* @param fileName - The name or key of the file to delete.
|
|
45
|
-
* @returns A boolean indicating success.
|
|
46
85
|
*/
|
|
47
|
-
deleteFile(
|
|
86
|
+
deleteFile(args: BucketKeyArgs<TBucket>): Promise<boolean>
|
|
48
87
|
|
|
49
88
|
/**
|
|
50
|
-
* Uploads a file stream to storage under
|
|
51
|
-
* @param assetKey - The key where the file will be saved.
|
|
52
|
-
* @param stream - A readable stream of the file contents.
|
|
53
|
-
* @returns A boolean indicating success.
|
|
89
|
+
* Uploads a file stream to storage under the specified bucket + key.
|
|
54
90
|
*/
|
|
55
|
-
writeFile(
|
|
56
|
-
assetKey: string,
|
|
57
|
-
stream: ReadableStream | NodeJS.ReadableStream
|
|
58
|
-
): Promise<boolean>
|
|
91
|
+
writeFile(args: WriteFileArgs<TBucket>): Promise<boolean>
|
|
59
92
|
|
|
60
93
|
/**
|
|
61
|
-
* Copies a file from a local absolute path into storage
|
|
62
|
-
* @param assetKey - The destination key.
|
|
63
|
-
* @param fromAbsolutePath - The local absolute file path.
|
|
64
|
-
* @returns A boolean indicating success.
|
|
94
|
+
* Copies a file from a local absolute path into storage.
|
|
65
95
|
*/
|
|
66
|
-
copyFile(
|
|
96
|
+
copyFile(args: CopyFileArgs<TBucket>): Promise<boolean>
|
|
67
97
|
|
|
68
98
|
/**
|
|
69
99
|
* Reads a file from storage as a readable stream.
|
|
70
|
-
* @param assetKey - The key of the file to read.
|
|
71
|
-
* @returns A readable file stream.
|
|
72
100
|
*/
|
|
73
|
-
readFile(
|
|
101
|
+
readFile(
|
|
102
|
+
args: BucketKeyArgs<TBucket>
|
|
103
|
+
): Promise<ReadableStream | NodeJS.ReadableStream>
|
|
74
104
|
|
|
75
105
|
/**
|
|
76
106
|
* Reads an entire file from storage into a Buffer.
|
|
77
|
-
* @param assetKey - The key of the file to read.
|
|
78
|
-
* @returns The file contents as a Buffer.
|
|
79
107
|
*/
|
|
80
|
-
readFileAsBuffer(
|
|
108
|
+
readFileAsBuffer(args: BucketKeyArgs<TBucket>): Promise<Buffer>
|
|
81
109
|
}
|
|
@@ -3,8 +3,7 @@ import type { SessionStore } from './session-store.js'
|
|
|
3
3
|
|
|
4
4
|
export class InMemorySessionStore<
|
|
5
5
|
UserSession extends CoreUserSession = CoreUserSession,
|
|
6
|
-
> implements SessionStore<UserSession>
|
|
7
|
-
{
|
|
6
|
+
> implements SessionStore<UserSession> {
|
|
8
7
|
private sessions = new Map<string, UserSession>()
|
|
9
8
|
|
|
10
9
|
async get(pikkuUserId: string): Promise<UserSession | undefined> {
|
|
@@ -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
|
package/src/services/index.ts
CHANGED
|
@@ -25,7 +25,16 @@ export { InMemoryQueueService } from './in-memory-queue-service.js'
|
|
|
25
25
|
export { InMemoryTriggerService } from './in-memory-trigger-service.js'
|
|
26
26
|
export { InMemoryAIRunStateService } from './in-memory-ai-run-state-service.js'
|
|
27
27
|
export { LocalGatewayService } from './local-gateway-service.js'
|
|
28
|
-
export type {
|
|
28
|
+
export type {
|
|
29
|
+
ContentService,
|
|
30
|
+
SignContentKeyArgs,
|
|
31
|
+
SignURLArgs,
|
|
32
|
+
GetUploadURLArgs,
|
|
33
|
+
UploadURLResult,
|
|
34
|
+
BucketKeyArgs,
|
|
35
|
+
WriteFileArgs,
|
|
36
|
+
CopyFileArgs,
|
|
37
|
+
} from './content-service.js'
|
|
29
38
|
export type { JWTService } from './jwt-service.js'
|
|
30
39
|
export type { Logger } from './logger.js'
|
|
31
40
|
export type { SecretService } from './secret-service.js'
|
|
@@ -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
|
+
})
|