@pikku/core 0.10.2 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/dist/errors/errors.d.ts +1 -1
- package/dist/errors/errors.js +3 -3
- package/dist/function/function-runner.d.ts +6 -7
- package/dist/function/function-runner.js +35 -16
- package/dist/function/functions.types.d.ts +23 -30
- package/dist/function/functions.types.js +9 -6
- package/dist/handle-error.d.ts +1 -1
- package/dist/handle-error.js +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/middleware/auth-apikey.d.ts +1 -0
- package/dist/middleware/auth-apikey.js +3 -3
- package/dist/middleware/auth-bearer.d.ts +1 -0
- package/dist/middleware/auth-bearer.js +3 -3
- package/dist/middleware/auth-cookie.d.ts +1 -0
- package/dist/middleware/auth-cookie.js +5 -5
- package/dist/middleware/timeout.d.ts +1 -0
- package/dist/middleware/timeout.js +3 -2
- package/dist/middleware-runner.d.ts +3 -6
- package/dist/middleware-runner.js +11 -11
- package/dist/permissions.d.ts +6 -6
- package/dist/permissions.js +15 -15
- package/dist/pikku-state.d.ts +7 -2
- package/dist/pikku-state.js +4 -0
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.js +1 -0
- package/dist/services/scheduler-service.d.ts +63 -0
- package/dist/services/scheduler-service.js +6 -0
- package/dist/services/user-session-service.d.ts +7 -3
- package/dist/services/user-session-service.js +8 -1
- package/dist/time-utils.d.ts +14 -0
- package/dist/time-utils.js +62 -0
- package/dist/types/core.types.d.ts +48 -35
- package/dist/types/core.types.js +3 -13
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +3 -3
- package/dist/wirings/channel/channel-common.js +2 -3
- package/dist/wirings/channel/channel-handler.d.ts +3 -2
- package/dist/wirings/channel/channel-handler.js +6 -9
- package/dist/wirings/channel/channel-runner.d.ts +2 -2
- package/dist/wirings/channel/channel.types.d.ts +10 -5
- package/dist/wirings/channel/local/local-channel-runner.d.ts +1 -1
- package/dist/wirings/channel/local/local-channel-runner.js +19 -26
- package/dist/wirings/channel/serverless/serverless-channel-runner.d.ts +1 -1
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +41 -46
- package/dist/wirings/cli/channel/cli-channel-runner.js +1 -1
- package/dist/wirings/cli/cli-runner.d.ts +5 -5
- package/dist/wirings/cli/cli-runner.js +11 -29
- package/dist/wirings/cli/cli.types.d.ts +15 -11
- package/dist/wirings/http/http-runner.d.ts +6 -6
- package/dist/wirings/http/http-runner.js +25 -39
- package/dist/wirings/http/http.types.d.ts +5 -10
- package/dist/wirings/mcp/mcp-runner.d.ts +2 -2
- package/dist/wirings/mcp/mcp-runner.js +12 -19
- package/dist/wirings/mcp/mcp.types.d.ts +6 -0
- package/dist/wirings/queue/queue-runner.d.ts +3 -3
- package/dist/wirings/queue/queue-runner.js +7 -14
- package/dist/wirings/queue/queue.types.d.ts +4 -13
- package/dist/wirings/rpc/index.d.ts +1 -1
- package/dist/wirings/rpc/index.js +1 -1
- package/dist/wirings/rpc/rpc-runner.d.ts +13 -7
- package/dist/wirings/rpc/rpc-runner.js +50 -26
- package/dist/wirings/rpc/rpc-types.d.ts +1 -0
- package/dist/wirings/scheduler/scheduler-runner.d.ts +3 -3
- package/dist/wirings/scheduler/scheduler-runner.js +13 -24
- package/dist/wirings/scheduler/scheduler.types.d.ts +3 -8
- package/dist/wirings/workflow/index.d.ts +15 -0
- package/dist/wirings/workflow/index.js +14 -0
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +160 -0
- package/dist/wirings/workflow/pikku-workflow-service.js +430 -0
- package/dist/wirings/workflow/workflow-runner.d.ts +34 -0
- package/dist/wirings/workflow/workflow-runner.js +65 -0
- package/dist/wirings/workflow/workflow.types.d.ts +332 -0
- package/dist/wirings/workflow/workflow.types.js +1 -0
- package/package.json +3 -4
- package/src/errors/errors.ts +3 -3
- package/src/factory-functions.test.ts +9 -36
- package/src/function/function-runner.test.ts +57 -68
- package/src/function/function-runner.ts +51 -28
- package/src/function/function-runner.ts.bak +188 -0
- package/src/function/functions.types.ts +69 -51
- package/src/handle-error.ts +1 -1
- package/src/index.ts +2 -0
- package/src/middleware/auth-apikey.test.ts +360 -0
- package/src/middleware/auth-apikey.ts +3 -7
- package/src/middleware/auth-bearer.test.ts +447 -0
- package/src/middleware/auth-bearer.ts +27 -33
- package/src/middleware/auth-cookie.test.ts +525 -0
- package/src/middleware/auth-cookie.ts +6 -6
- package/src/middleware/timeout.ts +4 -2
- package/src/middleware-runner.test.ts +58 -127
- package/src/middleware-runner.ts +13 -15
- package/src/permissions.test.ts +41 -45
- package/src/permissions.ts +21 -20
- package/src/pikku-state.ts +14 -2
- package/src/services/index.ts +1 -0
- package/src/services/scheduler-service.ts +76 -0
- package/src/services/user-session-service.ts +14 -4
- package/src/time-utils.ts +75 -0
- package/src/types/core.types.ts +92 -51
- package/src/utils.ts +4 -4
- package/src/wirings/channel/channel-common.ts +4 -7
- package/src/wirings/channel/channel-handler.ts +16 -22
- package/src/wirings/channel/channel-runner.ts +2 -2
- package/src/wirings/channel/channel.types.ts +14 -11
- package/src/wirings/channel/local/local-channel-runner.test.ts +5 -3
- package/src/wirings/channel/local/local-channel-runner.ts +23 -38
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +51 -77
- package/src/wirings/cli/channel/cli-channel-runner.ts +1 -1
- package/src/wirings/cli/cli-runner.test.ts +7 -7
- package/src/wirings/cli/cli-runner.ts +25 -63
- package/src/wirings/cli/cli.types.ts +22 -16
- package/src/wirings/http/http-runner.test.ts +8 -8
- package/src/wirings/http/http-runner.ts +29 -56
- package/src/wirings/http/http.types.ts +5 -14
- package/src/wirings/mcp/mcp-runner.ts +23 -48
- package/src/wirings/mcp/mcp.types.ts +6 -0
- package/src/wirings/queue/queue-runner.test.ts +641 -0
- package/src/wirings/queue/queue-runner.ts +10 -24
- package/src/wirings/queue/queue.types.ts +5 -15
- package/src/wirings/rpc/index.ts +1 -1
- package/src/wirings/rpc/rpc-runner.ts +71 -32
- package/src/wirings/rpc/rpc-types.ts +1 -0
- package/src/wirings/scheduler/scheduler-runner.test.ts +627 -0
- package/src/wirings/scheduler/scheduler-runner.ts +24 -50
- package/src/wirings/scheduler/scheduler.types.ts +3 -9
- package/src/wirings/workflow/index.ts +43 -0
- package/src/wirings/workflow/pikku-workflow-service.ts +746 -0
- package/src/wirings/workflow/workflow-runner.ts +72 -0
- package/src/wirings/workflow/workflow.types.ts +422 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/services/file-channel-store.d.ts +0 -19
- package/dist/services/file-channel-store.js +0 -69
- package/dist/services/file-eventhub-store.d.ts +0 -17
- package/dist/services/file-eventhub-store.js +0 -71
- package/src/services/file-channel-store.ts +0 -86
- package/src/services/file-eventhub-store.ts +0 -90
package/src/permissions.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CoreServices,
|
|
3
|
-
CoreUserSession,
|
|
4
3
|
PikkuWiringTypes,
|
|
5
4
|
PermissionMetadata,
|
|
5
|
+
PikkuWire,
|
|
6
6
|
} from './types/core.types.js'
|
|
7
7
|
import {
|
|
8
8
|
CorePermissionGroup,
|
|
@@ -16,14 +16,14 @@ import { freezeDedupe } from './utils.js'
|
|
|
16
16
|
* This function validates permissions by iterating over permission groups and executing the corresponding permission functions. If all functions in at least one group return true, the permission is considered valid.
|
|
17
17
|
* @param services - The core services required for permission validation.
|
|
18
18
|
* @param data - The data to be used in the permission validation functions.
|
|
19
|
-
* @param
|
|
19
|
+
* @param wire - The wire object containing request/response context and session.
|
|
20
20
|
* @returns A promise that resolves to void.
|
|
21
21
|
*/
|
|
22
|
-
export const verifyPermissions = async (
|
|
22
|
+
export const verifyPermissions = async <Out = any>(
|
|
23
23
|
permissions: CorePermissionGroup,
|
|
24
24
|
services: CoreServices,
|
|
25
25
|
data: any,
|
|
26
|
-
|
|
26
|
+
wire: PikkuWire<any, never, any, never, never, never>
|
|
27
27
|
): Promise<boolean> => {
|
|
28
28
|
if (!permissions) {
|
|
29
29
|
return true
|
|
@@ -38,13 +38,13 @@ export const verifyPermissions = async (
|
|
|
38
38
|
for (const funcs of permissionGroups) {
|
|
39
39
|
if (funcs instanceof Array) {
|
|
40
40
|
const permissioned = await Promise.all(
|
|
41
|
-
funcs.map((func) => func(services, data,
|
|
41
|
+
funcs.map((func) => func(services, data, wire))
|
|
42
42
|
)
|
|
43
43
|
if (permissioned.every((result) => result)) {
|
|
44
44
|
valid = true
|
|
45
45
|
}
|
|
46
46
|
} else {
|
|
47
|
-
valid = await funcs(services, data,
|
|
47
|
+
valid = await funcs(services, data, wire as any)
|
|
48
48
|
}
|
|
49
49
|
if (valid) {
|
|
50
50
|
return true
|
|
@@ -190,13 +190,14 @@ const combinedPermissionsCache: Record<
|
|
|
190
190
|
PikkuWiringTypes,
|
|
191
191
|
Record<string, readonly (CorePermissionGroup | CorePikkuPermission)[]>
|
|
192
192
|
> = {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
193
|
+
http: {},
|
|
194
|
+
rpc: {},
|
|
195
|
+
channel: {},
|
|
196
|
+
queue: {},
|
|
197
|
+
scheduler: {},
|
|
198
|
+
mcp: {},
|
|
199
|
+
cli: {},
|
|
200
|
+
workflow: {},
|
|
200
201
|
}
|
|
201
202
|
|
|
202
203
|
/**
|
|
@@ -334,17 +335,17 @@ export const runPermissions = async (
|
|
|
334
335
|
wirePermissions,
|
|
335
336
|
funcInheritedPermissions,
|
|
336
337
|
funcPermissions,
|
|
337
|
-
|
|
338
|
+
services,
|
|
339
|
+
wire,
|
|
338
340
|
data,
|
|
339
|
-
session,
|
|
340
341
|
}: {
|
|
341
342
|
wireInheritedPermissions?: PermissionMetadata[]
|
|
342
343
|
wirePermissions?: CorePermissionGroup | CorePikkuPermission[]
|
|
343
344
|
funcInheritedPermissions?: PermissionMetadata[]
|
|
344
345
|
funcPermissions?: CorePermissionGroup | CorePikkuPermission[]
|
|
345
|
-
|
|
346
|
+
services: CoreServices
|
|
347
|
+
wire: PikkuWire<any, never, any, never, never, never>
|
|
346
348
|
data: any
|
|
347
|
-
session?: CoreUserSession
|
|
348
349
|
}
|
|
349
350
|
) => {
|
|
350
351
|
// Combine all permissions: wireInheritedPermissions → wirePermissions → funcInheritedPermissions → funcPermissions
|
|
@@ -361,9 +362,9 @@ export const runPermissions = async (
|
|
|
361
362
|
for (const permission of allPermissions) {
|
|
362
363
|
const result = await verifyPermissions(
|
|
363
364
|
typeof permission === 'function' ? { permission } : permission,
|
|
364
|
-
|
|
365
|
+
services,
|
|
365
366
|
data,
|
|
366
|
-
|
|
367
|
+
wire
|
|
367
368
|
)
|
|
368
369
|
if (result) {
|
|
369
370
|
permissioned = true
|
|
@@ -371,7 +372,7 @@ export const runPermissions = async (
|
|
|
371
372
|
}
|
|
372
373
|
}
|
|
373
374
|
if (!permissioned) {
|
|
374
|
-
|
|
375
|
+
services.logger.debug('Permission denied - combined permissions')
|
|
375
376
|
throw new ForbiddenError('Permission denied')
|
|
376
377
|
}
|
|
377
378
|
}
|
package/src/pikku-state.ts
CHANGED
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
CorePikkuPermission,
|
|
22
22
|
} from './function/functions.types.js'
|
|
23
23
|
import {
|
|
24
|
-
|
|
24
|
+
QueueWorkersMeta,
|
|
25
25
|
CoreQueueWorker,
|
|
26
26
|
} from './wirings/queue/queue.types.js'
|
|
27
27
|
import {
|
|
@@ -33,6 +33,10 @@ import {
|
|
|
33
33
|
MCPPromptMeta,
|
|
34
34
|
} from './wirings/mcp/mcp.types.js'
|
|
35
35
|
import { CLIMeta, CLIProgramState } from './wirings/cli/cli.types.js'
|
|
36
|
+
import {
|
|
37
|
+
CoreWorkflow,
|
|
38
|
+
WorkflowsMeta,
|
|
39
|
+
} from './wirings/workflow/workflow.types.js'
|
|
36
40
|
|
|
37
41
|
interface PikkuState {
|
|
38
42
|
function: {
|
|
@@ -65,7 +69,11 @@ interface PikkuState {
|
|
|
65
69
|
}
|
|
66
70
|
queue: {
|
|
67
71
|
registrations: Map<string, CoreQueueWorker>
|
|
68
|
-
meta:
|
|
72
|
+
meta: QueueWorkersMeta
|
|
73
|
+
}
|
|
74
|
+
workflows: {
|
|
75
|
+
registrations: Map<string, CoreWorkflow>
|
|
76
|
+
meta: WorkflowsMeta
|
|
69
77
|
}
|
|
70
78
|
mcp: {
|
|
71
79
|
resources: Map<string, CoreMCPResource>
|
|
@@ -166,6 +174,10 @@ export const resetPikkuState = () => {
|
|
|
166
174
|
registrations: new Map(),
|
|
167
175
|
meta: {},
|
|
168
176
|
},
|
|
177
|
+
workflows: {
|
|
178
|
+
registrations: new Map(),
|
|
179
|
+
meta: {},
|
|
180
|
+
},
|
|
169
181
|
mcp: {
|
|
170
182
|
resources: new Map(),
|
|
171
183
|
resourcesMeta: {} as MCPResourceMeta,
|
package/src/services/index.ts
CHANGED
|
@@ -10,6 +10,7 @@ export * from './secret-service.js'
|
|
|
10
10
|
export * from './variables-service.js'
|
|
11
11
|
export * from './schema-service.js'
|
|
12
12
|
export * from './user-session-service.js'
|
|
13
|
+
export * from './scheduler-service.js'
|
|
13
14
|
|
|
14
15
|
// Local implementations
|
|
15
16
|
export * from './local-secrets.js'
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { CoreUserSession } from '../types/core.types.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Minimal metadata for listing scheduled tasks
|
|
5
|
+
*/
|
|
6
|
+
export interface ScheduledTaskSummary {
|
|
7
|
+
/** Unique task ID */
|
|
8
|
+
taskId: string
|
|
9
|
+
/** RPC function name to invoke */
|
|
10
|
+
rpcName: string
|
|
11
|
+
/** Scheduled execution time */
|
|
12
|
+
scheduledFor: Date
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Full metadata for a scheduled task retrieved from the queue
|
|
17
|
+
*/
|
|
18
|
+
export interface ScheduledTaskInfo extends ScheduledTaskSummary {
|
|
19
|
+
/** Data to pass to the RPC function */
|
|
20
|
+
data?: any
|
|
21
|
+
/** User session */
|
|
22
|
+
session?: CoreUserSession
|
|
23
|
+
/** Task status */
|
|
24
|
+
status?: 'scheduled' | 'active' | 'completed' | 'failed'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Abstract scheduler service for persistent scheduled task management
|
|
29
|
+
* Implementations use queue backends (pg-boss, BullMQ) for distributed scheduling
|
|
30
|
+
*/
|
|
31
|
+
export abstract class SchedulerService {
|
|
32
|
+
/**
|
|
33
|
+
* Initialize the scheduler service
|
|
34
|
+
*/
|
|
35
|
+
abstract init(): Promise<void>
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Schedule a one-off delayed RPC call
|
|
39
|
+
* @param delay - Delay before execution (number in milliseconds or duration string like "5h", "30m")
|
|
40
|
+
* @param rpcName - RPC function name to invoke
|
|
41
|
+
* @param data - Data to pass to the RPC function
|
|
42
|
+
* @param session - Optional user session
|
|
43
|
+
* @returns Task ID
|
|
44
|
+
*/
|
|
45
|
+
abstract scheduleRPC(
|
|
46
|
+
delay: number | string,
|
|
47
|
+
rpcName: string,
|
|
48
|
+
data?: any,
|
|
49
|
+
session?: CoreUserSession
|
|
50
|
+
): Promise<string>
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Unschedule a task by ID
|
|
54
|
+
* @param taskId - Task ID
|
|
55
|
+
* @returns Success status
|
|
56
|
+
*/
|
|
57
|
+
abstract unschedule(taskId: string): Promise<boolean>
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Get a scheduled task by ID with full details
|
|
61
|
+
* @param taskId - Task ID
|
|
62
|
+
* @returns Task info or null if not found
|
|
63
|
+
*/
|
|
64
|
+
abstract getTask(taskId: string): Promise<ScheduledTaskInfo | null>
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Get all scheduled tasks with minimal info
|
|
68
|
+
* @returns Array of task summaries with taskId, rpcName, and schedule
|
|
69
|
+
*/
|
|
70
|
+
abstract getAllTasks(): Promise<ScheduledTaskSummary[]>
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Close any open connections
|
|
74
|
+
*/
|
|
75
|
+
abstract close(): Promise<void>
|
|
76
|
+
}
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import { ChannelStore } from '../wirings/channel/channel-store.js'
|
|
2
2
|
import { CoreUserSession } from '../types/core.types.js'
|
|
3
3
|
|
|
4
|
-
export interface
|
|
4
|
+
export interface SessionService<UserSession extends CoreUserSession> {
|
|
5
5
|
sessionChanged: boolean
|
|
6
|
+
initial: UserSession | undefined
|
|
6
7
|
setInitial(session: UserSession): void
|
|
8
|
+
freezeInitial(): UserSession | undefined
|
|
7
9
|
set(session: UserSession): Promise<void> | void
|
|
8
10
|
clear(): Promise<void> | void
|
|
9
|
-
get(): Promise<UserSession
|
|
11
|
+
get(): Promise<UserSession> | UserSession | undefined
|
|
10
12
|
}
|
|
11
13
|
|
|
12
|
-
export class
|
|
13
|
-
implements
|
|
14
|
+
export class PikkuSessionService<UserSession extends CoreUserSession>
|
|
15
|
+
implements SessionService<UserSession>
|
|
14
16
|
{
|
|
15
17
|
public sessionChanged = false
|
|
18
|
+
public initial: UserSession | undefined
|
|
16
19
|
private session: UserSession | undefined
|
|
17
20
|
constructor(
|
|
18
21
|
private channelStore?: ChannelStore<unknown, unknown, UserSession>,
|
|
@@ -27,6 +30,13 @@ export class PikkuUserSessionService<UserSession extends CoreUserSession>
|
|
|
27
30
|
this.session = session
|
|
28
31
|
}
|
|
29
32
|
|
|
33
|
+
public freezeInitial() {
|
|
34
|
+
if (this.initial === undefined) {
|
|
35
|
+
this.initial = this.session
|
|
36
|
+
}
|
|
37
|
+
return this.initial
|
|
38
|
+
}
|
|
39
|
+
|
|
30
40
|
public set(session: UserSession) {
|
|
31
41
|
this.sessionChanged = true
|
|
32
42
|
this.session = session
|
package/src/time-utils.ts
CHANGED
|
@@ -30,3 +30,78 @@ export const getRelativeTimeOffsetFromNow = (
|
|
|
30
30
|
): Date => {
|
|
31
31
|
return new Date(Date.now() + getRelativeTimeOffset(relativeTime))
|
|
32
32
|
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Get duration in milliseconds from a string or number
|
|
36
|
+
* @param duration
|
|
37
|
+
* @returns
|
|
38
|
+
*/
|
|
39
|
+
export const getDurationInMilliseconds = (
|
|
40
|
+
duration: string | number
|
|
41
|
+
): number => {
|
|
42
|
+
if (typeof duration === 'number') {
|
|
43
|
+
return duration
|
|
44
|
+
}
|
|
45
|
+
return parseDurationString(duration)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Parse a duration string to milliseconds
|
|
50
|
+
* Supports formats like: '2s', '5s', '5sec', '5seconds', '5m', '5min', '5minutes', '1h', '1hour', '2d', '2day', '1w', '1week'
|
|
51
|
+
*
|
|
52
|
+
* @param duration - Duration string (e.g., '2s', '5min', '2hours', '1day')
|
|
53
|
+
* @returns Duration in milliseconds
|
|
54
|
+
*/
|
|
55
|
+
export const parseDurationString = (duration: string): number => {
|
|
56
|
+
const match = duration.match(
|
|
57
|
+
/^(\d+)(ms|milliseconds?|s|sec|seconds?|m|min|minutes?|h|hour|hours?|d|day|days?|w|week|weeks?|y|year|years?)$/
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
if (!match) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
`Invalid duration format: ${duration}. Use formats like '2s', '5s', '5min', '1hour', '2days', '1week'`
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const value = parseInt(match[1], 10)
|
|
67
|
+
const unitStr = match[2]
|
|
68
|
+
|
|
69
|
+
// Handle milliseconds specially
|
|
70
|
+
if (
|
|
71
|
+
unitStr === 'ms' ||
|
|
72
|
+
unitStr === 'millisecond' ||
|
|
73
|
+
unitStr === 'milliseconds'
|
|
74
|
+
) {
|
|
75
|
+
return value
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Map string variations to TimeUnit
|
|
79
|
+
let unit: TimeUnit
|
|
80
|
+
if (
|
|
81
|
+
unitStr === 's' ||
|
|
82
|
+
unitStr === 'sec' ||
|
|
83
|
+
unitStr === 'second' ||
|
|
84
|
+
unitStr === 'seconds'
|
|
85
|
+
) {
|
|
86
|
+
unit = 'second'
|
|
87
|
+
} else if (
|
|
88
|
+
unitStr === 'm' ||
|
|
89
|
+
unitStr === 'min' ||
|
|
90
|
+
unitStr === 'minute' ||
|
|
91
|
+
unitStr === 'minutes'
|
|
92
|
+
) {
|
|
93
|
+
unit = 'minute'
|
|
94
|
+
} else if (unitStr === 'h' || unitStr === 'hour' || unitStr === 'hours') {
|
|
95
|
+
unit = 'hour'
|
|
96
|
+
} else if (unitStr === 'd' || unitStr === 'day' || unitStr === 'days') {
|
|
97
|
+
unit = 'day'
|
|
98
|
+
} else if (unitStr === 'w' || unitStr === 'week' || unitStr === 'weeks') {
|
|
99
|
+
unit = 'week'
|
|
100
|
+
} else if (unitStr === 'y' || unitStr === 'year' || unitStr === 'years') {
|
|
101
|
+
unit = 'year'
|
|
102
|
+
} else {
|
|
103
|
+
throw new Error(`Unknown time unit: ${unitStr}`)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return getRelativeTimeOffset({ value, unit })
|
|
107
|
+
}
|
package/src/types/core.types.ts
CHANGED
|
@@ -3,23 +3,30 @@ import { VariablesService } from '../services/variables-service.js'
|
|
|
3
3
|
import { SchemaService } from '../services/schema-service.js'
|
|
4
4
|
import { JWTService } from '../services/jwt-service.js'
|
|
5
5
|
import { PikkuHTTP } from '../wirings/http/http.types.js'
|
|
6
|
-
import {
|
|
6
|
+
import { SessionService } from '../services/user-session-service.js'
|
|
7
7
|
import { PikkuChannel } from '../wirings/channel/channel.types.js'
|
|
8
8
|
import { PikkuRPC } from '../wirings/rpc/rpc-types.js'
|
|
9
9
|
import { PikkuMCP } from '../wirings/mcp/mcp.types.js'
|
|
10
10
|
import { PikkuScheduledTask } from '../wirings/scheduler/scheduler.types.js'
|
|
11
|
-
import { PikkuQueue } from '../wirings/queue/queue.types.js'
|
|
11
|
+
import { PikkuQueue, QueueService } from '../wirings/queue/queue.types.js'
|
|
12
12
|
import { PikkuCLI } from '../wirings/cli/cli.types.js'
|
|
13
|
+
import {
|
|
14
|
+
PikkuWorkflowWire,
|
|
15
|
+
WorkflowService,
|
|
16
|
+
WorkflowServiceConfig,
|
|
17
|
+
WorkflowStepWire,
|
|
18
|
+
} from '../wirings/workflow/workflow.types.js'
|
|
19
|
+
import { SchedulerService } from '../services/scheduler-service.js'
|
|
13
20
|
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
export type PikkuWiringTypes =
|
|
22
|
+
| 'http'
|
|
23
|
+
| 'scheduler'
|
|
24
|
+
| 'channel'
|
|
25
|
+
| 'rpc'
|
|
26
|
+
| 'queue'
|
|
27
|
+
| 'mcp'
|
|
28
|
+
| 'cli'
|
|
29
|
+
| 'workflow'
|
|
23
30
|
|
|
24
31
|
export interface FunctionServicesMeta {
|
|
25
32
|
optimized: boolean
|
|
@@ -73,20 +80,22 @@ export type FunctionRuntimeMeta = {
|
|
|
73
80
|
inputSchemaName: string | null
|
|
74
81
|
outputSchemaName: string | null
|
|
75
82
|
expose?: boolean
|
|
83
|
+
internal?: boolean
|
|
76
84
|
}
|
|
77
85
|
|
|
78
86
|
export type FunctionMeta = FunctionRuntimeMeta &
|
|
79
|
-
Partial<
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
Partial<
|
|
88
|
+
{
|
|
89
|
+
name: string
|
|
90
|
+
services: FunctionServicesMeta
|
|
91
|
+
usedWires: string[]
|
|
92
|
+
inputs: string[] | null
|
|
93
|
+
outputs: string[] | null
|
|
94
|
+
middleware: MiddlewareMetadata[]
|
|
95
|
+
permissions: PermissionMetadata[]
|
|
96
|
+
isDirectFunction: boolean
|
|
97
|
+
} & CommonWireMeta
|
|
98
|
+
>
|
|
90
99
|
|
|
91
100
|
export type FunctionsRuntimeMeta = Record<string, FunctionRuntimeMeta>
|
|
92
101
|
export type FunctionsMeta = Record<string, FunctionMeta>
|
|
@@ -137,6 +146,8 @@ export type CoreConfig<Config extends Record<string, unknown> = {}> = {
|
|
|
137
146
|
logLevel?: LogLevel
|
|
138
147
|
/** Secrets used by the application (optional). */
|
|
139
148
|
secrets?: {}
|
|
149
|
+
|
|
150
|
+
workflow?: WorkflowServiceConfig
|
|
140
151
|
} & Config
|
|
141
152
|
|
|
142
153
|
/**
|
|
@@ -158,32 +169,53 @@ export interface CoreSingletonServices<Config extends CoreConfig = CoreConfig> {
|
|
|
158
169
|
logger: Logger
|
|
159
170
|
/** The variable service to be used */
|
|
160
171
|
variables: VariablesService
|
|
172
|
+
/** The workflow orchestrator service */
|
|
173
|
+
workflowService?: WorkflowService
|
|
174
|
+
/** The queue service */
|
|
175
|
+
queueService?: QueueService
|
|
176
|
+
/** The scheduler service */
|
|
177
|
+
schedulerService?: SchedulerService
|
|
161
178
|
}
|
|
162
179
|
|
|
163
180
|
/**
|
|
164
|
-
* Represents different forms of
|
|
181
|
+
* Represents different forms of wire within Pikku and the outside world.
|
|
165
182
|
*/
|
|
166
|
-
export type
|
|
183
|
+
export type PikkuWire<
|
|
184
|
+
In = unknown,
|
|
185
|
+
Out = unknown,
|
|
186
|
+
HasInitialSession extends boolean = false,
|
|
187
|
+
UserSession extends CoreUserSession = CoreUserSession,
|
|
188
|
+
TypedRPC extends PikkuRPC = PikkuRPC,
|
|
189
|
+
IsChannel extends true | null = null,
|
|
190
|
+
MCPTools extends string | never = never,
|
|
191
|
+
TypedWorkflow extends PikkuWorkflowWire | never = PikkuWorkflowWire,
|
|
192
|
+
> = Partial<{
|
|
167
193
|
http: PikkuHTTP<In>
|
|
168
|
-
mcp: PikkuMCP
|
|
169
|
-
rpc:
|
|
170
|
-
channel:
|
|
194
|
+
mcp: PikkuMCP<MCPTools>
|
|
195
|
+
rpc: TypedRPC
|
|
196
|
+
channel: [IsChannel] extends [null]
|
|
197
|
+
? PikkuChannel<unknown, Out>
|
|
198
|
+
: PikkuChannel<unknown, Out> | undefined
|
|
171
199
|
scheduledTask: PikkuScheduledTask
|
|
172
200
|
queue: PikkuQueue
|
|
173
201
|
cli: PikkuCLI
|
|
202
|
+
workflow: TypedWorkflow
|
|
203
|
+
workflowStep: WorkflowStepWire
|
|
204
|
+
initialSession: HasInitialSession extends true
|
|
205
|
+
? UserSession
|
|
206
|
+
: UserSession | undefined
|
|
207
|
+
session: SessionService<UserSession>
|
|
174
208
|
}>
|
|
175
209
|
|
|
176
210
|
/**
|
|
177
|
-
* A function that can wrap an
|
|
211
|
+
* A function that can wrap an wire and be called before or after
|
|
178
212
|
*/
|
|
179
213
|
export type CorePikkuMiddleware<
|
|
180
214
|
SingletonServices extends CoreSingletonServices = CoreSingletonServices,
|
|
181
215
|
UserSession extends CoreUserSession = CoreUserSession,
|
|
182
216
|
> = (
|
|
183
|
-
services: SingletonServices
|
|
184
|
-
|
|
185
|
-
},
|
|
186
|
-
interactions: PikkuInteraction,
|
|
217
|
+
services: SingletonServices,
|
|
218
|
+
wires: PikkuWire<unknown, unknown, false, UserSession>,
|
|
187
219
|
next: () => Promise<void>
|
|
188
220
|
) => Promise<void>
|
|
189
221
|
|
|
@@ -235,7 +267,7 @@ export type CorePikkuMiddlewareGroup<
|
|
|
235
267
|
* ```typescript
|
|
236
268
|
* // Direct function syntax
|
|
237
269
|
* export const logMiddleware = pikkuMiddleware(
|
|
238
|
-
* async ({ logger },
|
|
270
|
+
* async ({ logger }, next) => {
|
|
239
271
|
* logger.info('Request started')
|
|
240
272
|
* await next()
|
|
241
273
|
* }
|
|
@@ -245,7 +277,7 @@ export type CorePikkuMiddlewareGroup<
|
|
|
245
277
|
* export const logMiddleware = pikkuMiddleware({
|
|
246
278
|
* name: 'Request Logger',
|
|
247
279
|
* description: 'Logs request information',
|
|
248
|
-
* func: async ({ logger },
|
|
280
|
+
* func: async ({ logger }, next) => {
|
|
249
281
|
* logger.info('Request started')
|
|
250
282
|
* await next()
|
|
251
283
|
* }
|
|
@@ -273,7 +305,7 @@ export const pikkuMiddleware = <
|
|
|
273
305
|
* message,
|
|
274
306
|
* level = 'info'
|
|
275
307
|
* }) => {
|
|
276
|
-
* return pikkuMiddleware(async ({ logger },
|
|
308
|
+
* return pikkuMiddleware(async ({ logger }, next) => {
|
|
277
309
|
* logger[level](message)
|
|
278
310
|
* await next()
|
|
279
311
|
* })
|
|
@@ -287,20 +319,15 @@ export const pikkuMiddlewareFactory = <In = any>(
|
|
|
287
319
|
}
|
|
288
320
|
|
|
289
321
|
/**
|
|
290
|
-
* Represents the core services used by Pikku, including singleton services
|
|
322
|
+
* Represents the core services used by Pikku, including singleton services.
|
|
291
323
|
*/
|
|
292
|
-
export type CoreServices<
|
|
293
|
-
SingletonServices
|
|
294
|
-
UserSession extends CoreUserSession = CoreUserSession,
|
|
295
|
-
> = SingletonServices &
|
|
296
|
-
PikkuInteraction & {
|
|
297
|
-
userSession?: UserSessionService<UserSession>
|
|
298
|
-
}
|
|
324
|
+
export type CoreServices<SingletonServices = CoreSingletonServices> =
|
|
325
|
+
SingletonServices
|
|
299
326
|
|
|
300
|
-
export type
|
|
327
|
+
export type WireServices<
|
|
301
328
|
SingletonServices extends CoreSingletonServices = CoreSingletonServices,
|
|
302
329
|
Services = CoreServices<SingletonServices>,
|
|
303
|
-
> = Omit<Services, keyof SingletonServices |
|
|
330
|
+
> = Omit<Services, keyof SingletonServices | 'session'>
|
|
304
331
|
|
|
305
332
|
/**
|
|
306
333
|
* Defines a function type for creating singleton services from the given configuration.
|
|
@@ -316,16 +343,15 @@ export type CreateSingletonServices<
|
|
|
316
343
|
/**
|
|
317
344
|
* Defines a function type for creating session-specific services.
|
|
318
345
|
*/
|
|
319
|
-
export type
|
|
346
|
+
export type CreateWireServices<
|
|
320
347
|
SingletonServices extends CoreSingletonServices = CoreSingletonServices,
|
|
321
348
|
Services extends
|
|
322
349
|
CoreServices<SingletonServices> = CoreServices<SingletonServices>,
|
|
323
350
|
UserSession extends CoreUserSession = CoreUserSession,
|
|
324
351
|
> = (
|
|
325
352
|
services: SingletonServices,
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
) => Promise<SessionServices<Services, SingletonServices>>
|
|
353
|
+
wire: PikkuWire<unknown, unknown, false, UserSession>
|
|
354
|
+
) => Promise<WireServices<Services, SingletonServices>>
|
|
329
355
|
|
|
330
356
|
/**
|
|
331
357
|
* Defines a function type for creating config.
|
|
@@ -338,9 +364,24 @@ export type CreateConfig<
|
|
|
338
364
|
/**
|
|
339
365
|
* Represents the documentation for a route, including summary, description, tags, and errors.
|
|
340
366
|
*/
|
|
341
|
-
export type
|
|
367
|
+
export type CommonWireMeta = {
|
|
368
|
+
pikkuFuncName: string
|
|
369
|
+
|
|
370
|
+
tags?: string[]
|
|
342
371
|
summary?: string
|
|
343
372
|
description?: string
|
|
344
|
-
tags?: string[]
|
|
345
373
|
errors?: string[]
|
|
374
|
+
|
|
375
|
+
middleware?: MiddlewareMetadata[]
|
|
376
|
+
permissions?: PermissionMetadata[]
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Serialized error for storage
|
|
381
|
+
*/
|
|
382
|
+
export interface SerializedError {
|
|
383
|
+
message: string
|
|
384
|
+
stack?: string
|
|
385
|
+
code?: string
|
|
386
|
+
[key: string]: any
|
|
346
387
|
}
|
package/src/utils.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { Logger } from './services/logger.js'
|
|
2
2
|
|
|
3
|
-
// TODO:
|
|
3
|
+
// TODO: WireServices probably needs it's own type
|
|
4
4
|
// but is an issue for the future and will be tackled
|
|
5
5
|
// with dependency injection
|
|
6
|
-
export const
|
|
6
|
+
export const closeWireServices = async (
|
|
7
7
|
logger: Logger,
|
|
8
|
-
|
|
8
|
+
wireServices: Record<string, any>
|
|
9
9
|
) => {
|
|
10
10
|
await Promise.all(
|
|
11
|
-
Object.values(
|
|
11
|
+
Object.values(wireServices).map(async (service) => {
|
|
12
12
|
if (service?.close) {
|
|
13
13
|
try {
|
|
14
14
|
await service.close()
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
CoreServices,
|
|
3
|
-
PikkuWiringTypes,
|
|
4
|
-
CorePikkuMiddleware,
|
|
5
|
-
} from '../../types/core.types.js'
|
|
1
|
+
import { CoreServices, CorePikkuMiddleware } from '../../types/core.types.js'
|
|
6
2
|
import { CoreChannel, ChannelMessageMeta } from './channel.types.js'
|
|
7
3
|
import { combineMiddleware, runMiddleware } from '../../middleware-runner.js'
|
|
8
4
|
import { runPikkuFuncDirectly } from '../../function/function-runner.js'
|
|
@@ -49,7 +45,7 @@ export const runChannelLifecycleWithMiddleware = async ({
|
|
|
49
45
|
|
|
50
46
|
// Use combineMiddleware to properly resolve metadata + inline middleware
|
|
51
47
|
const allMiddleware = combineMiddleware(
|
|
52
|
-
|
|
48
|
+
'channel',
|
|
53
49
|
`${channelConfig.name}:${lifecycleType}`,
|
|
54
50
|
{
|
|
55
51
|
wireInheritedMiddleware: meta.middleware,
|
|
@@ -61,7 +57,8 @@ export const runChannelLifecycleWithMiddleware = async ({
|
|
|
61
57
|
const runLifecycle = async () => {
|
|
62
58
|
return await runPikkuFuncDirectly(
|
|
63
59
|
meta.pikkuFuncName,
|
|
64
|
-
|
|
60
|
+
services,
|
|
61
|
+
{ channel },
|
|
65
62
|
data
|
|
66
63
|
)
|
|
67
64
|
}
|