@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/dist/permissions.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { PikkuWiringTypes, } from './types/core.types.js';
|
|
2
1
|
import { pikkuState } from './pikku-state.js';
|
|
3
2
|
import { ForbiddenError } from './errors/errors.js';
|
|
4
3
|
import { freezeDedupe } from './utils.js';
|
|
@@ -6,10 +5,10 @@ import { freezeDedupe } from './utils.js';
|
|
|
6
5
|
* 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.
|
|
7
6
|
* @param services - The core services required for permission validation.
|
|
8
7
|
* @param data - The data to be used in the permission validation functions.
|
|
9
|
-
* @param
|
|
8
|
+
* @param wire - The wire object containing request/response context and session.
|
|
10
9
|
* @returns A promise that resolves to void.
|
|
11
10
|
*/
|
|
12
|
-
export const verifyPermissions = async (permissions, services, data,
|
|
11
|
+
export const verifyPermissions = async (permissions, services, data, wire) => {
|
|
13
12
|
if (!permissions) {
|
|
14
13
|
return true;
|
|
15
14
|
}
|
|
@@ -20,13 +19,13 @@ export const verifyPermissions = async (permissions, services, data, session) =>
|
|
|
20
19
|
}
|
|
21
20
|
for (const funcs of permissionGroups) {
|
|
22
21
|
if (funcs instanceof Array) {
|
|
23
|
-
const permissioned = await Promise.all(funcs.map((func) => func(services, data,
|
|
22
|
+
const permissioned = await Promise.all(funcs.map((func) => func(services, data, wire)));
|
|
24
23
|
if (permissioned.every((result) => result)) {
|
|
25
24
|
valid = true;
|
|
26
25
|
}
|
|
27
26
|
}
|
|
28
27
|
else {
|
|
29
|
-
valid = await funcs(services, data,
|
|
28
|
+
valid = await funcs(services, data, wire);
|
|
30
29
|
}
|
|
31
30
|
if (valid) {
|
|
32
31
|
return true;
|
|
@@ -147,13 +146,14 @@ export const getPermissionsForTags = (tags) => {
|
|
|
147
146
|
return applicablePermissions;
|
|
148
147
|
};
|
|
149
148
|
const combinedPermissionsCache = {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
149
|
+
http: {},
|
|
150
|
+
rpc: {},
|
|
151
|
+
channel: {},
|
|
152
|
+
queue: {},
|
|
153
|
+
scheduler: {},
|
|
154
|
+
mcp: {},
|
|
155
|
+
cli: {},
|
|
156
|
+
workflow: {},
|
|
157
157
|
};
|
|
158
158
|
/**
|
|
159
159
|
* Combines wiring-specific permissions with function-level permissions.
|
|
@@ -264,7 +264,7 @@ export const combinePermissions = (wireType, uid, { wireInheritedPermissions, wi
|
|
|
264
264
|
* Runs permission checks using combined permissions from all sources.
|
|
265
265
|
* Combines permissions from wire and function levels, then validates them.
|
|
266
266
|
*/
|
|
267
|
-
export const runPermissions = async (wireType, uid, { wireInheritedPermissions, wirePermissions, funcInheritedPermissions, funcPermissions,
|
|
267
|
+
export const runPermissions = async (wireType, uid, { wireInheritedPermissions, wirePermissions, funcInheritedPermissions, funcPermissions, services, wire, data, }) => {
|
|
268
268
|
// Combine all permissions: wireInheritedPermissions → wirePermissions → funcInheritedPermissions → funcPermissions
|
|
269
269
|
const allPermissions = combinePermissions(wireType, uid, {
|
|
270
270
|
wireInheritedPermissions,
|
|
@@ -276,14 +276,14 @@ export const runPermissions = async (wireType, uid, { wireInheritedPermissions,
|
|
|
276
276
|
if (allPermissions.length > 0) {
|
|
277
277
|
let permissioned = false;
|
|
278
278
|
for (const permission of allPermissions) {
|
|
279
|
-
const result = await verifyPermissions(typeof permission === 'function' ? { permission } : permission,
|
|
279
|
+
const result = await verifyPermissions(typeof permission === 'function' ? { permission } : permission, services, data, wire);
|
|
280
280
|
if (result) {
|
|
281
281
|
permissioned = true;
|
|
282
282
|
// Continue executing all permissions (don't break early)
|
|
283
283
|
}
|
|
284
284
|
}
|
|
285
285
|
if (!permissioned) {
|
|
286
|
-
|
|
286
|
+
services.logger.debug('Permission denied - combined permissions');
|
|
287
287
|
throw new ForbiddenError('Permission denied');
|
|
288
288
|
}
|
|
289
289
|
}
|
package/dist/pikku-state.d.ts
CHANGED
|
@@ -4,9 +4,10 @@ import { FunctionsMeta, CorePikkuMiddleware, CorePikkuMiddlewareGroup, FunctionS
|
|
|
4
4
|
import { CoreScheduledTask, ScheduledTasksMeta } from './wirings/scheduler/scheduler.types.js';
|
|
5
5
|
import { ErrorDetails, PikkuError } from './errors/error-handler.js';
|
|
6
6
|
import { CorePermissionGroup, CorePikkuFunctionConfig, CorePikkuPermission } from './function/functions.types.js';
|
|
7
|
-
import {
|
|
7
|
+
import { QueueWorkersMeta, CoreQueueWorker } from './wirings/queue/queue.types.js';
|
|
8
8
|
import { CoreMCPResource, CoreMCPTool, CoreMCPPrompt, MCPResourceMeta, MCPToolMeta, MCPPromptMeta } from './wirings/mcp/mcp.types.js';
|
|
9
9
|
import { CLIMeta, CLIProgramState } from './wirings/cli/cli.types.js';
|
|
10
|
+
import { CoreWorkflow, WorkflowsMeta } from './wirings/workflow/workflow.types.js';
|
|
10
11
|
interface PikkuState {
|
|
11
12
|
function: {
|
|
12
13
|
meta: FunctionsMeta;
|
|
@@ -35,7 +36,11 @@ interface PikkuState {
|
|
|
35
36
|
};
|
|
36
37
|
queue: {
|
|
37
38
|
registrations: Map<string, CoreQueueWorker>;
|
|
38
|
-
meta:
|
|
39
|
+
meta: QueueWorkersMeta;
|
|
40
|
+
};
|
|
41
|
+
workflows: {
|
|
42
|
+
registrations: Map<string, CoreWorkflow>;
|
|
43
|
+
meta: WorkflowsMeta;
|
|
39
44
|
};
|
|
40
45
|
mcp: {
|
|
41
46
|
resources: Map<string, CoreMCPResource>;
|
package/dist/pikku-state.js
CHANGED
package/dist/services/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export * from './secret-service.js';
|
|
|
8
8
|
export * from './variables-service.js';
|
|
9
9
|
export * from './schema-service.js';
|
|
10
10
|
export * from './user-session-service.js';
|
|
11
|
+
export * from './scheduler-service.js';
|
|
11
12
|
export * from './local-secrets.js';
|
|
12
13
|
export * from './local-variables.js';
|
|
13
14
|
export * from './logger-console.js';
|
package/dist/services/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export * from './secret-service.js';
|
|
|
9
9
|
export * from './variables-service.js';
|
|
10
10
|
export * from './schema-service.js';
|
|
11
11
|
export * from './user-session-service.js';
|
|
12
|
+
export * from './scheduler-service.js';
|
|
12
13
|
// Local implementations
|
|
13
14
|
export * from './local-secrets.js';
|
|
14
15
|
export * from './local-variables.js';
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { CoreUserSession } from '../types/core.types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Minimal metadata for listing scheduled tasks
|
|
4
|
+
*/
|
|
5
|
+
export interface ScheduledTaskSummary {
|
|
6
|
+
/** Unique task ID */
|
|
7
|
+
taskId: string;
|
|
8
|
+
/** RPC function name to invoke */
|
|
9
|
+
rpcName: string;
|
|
10
|
+
/** Scheduled execution time */
|
|
11
|
+
scheduledFor: Date;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Full metadata for a scheduled task retrieved from the queue
|
|
15
|
+
*/
|
|
16
|
+
export interface ScheduledTaskInfo extends ScheduledTaskSummary {
|
|
17
|
+
/** Data to pass to the RPC function */
|
|
18
|
+
data?: any;
|
|
19
|
+
/** User session */
|
|
20
|
+
session?: CoreUserSession;
|
|
21
|
+
/** Task status */
|
|
22
|
+
status?: 'scheduled' | 'active' | 'completed' | 'failed';
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Abstract scheduler service for persistent scheduled task management
|
|
26
|
+
* Implementations use queue backends (pg-boss, BullMQ) for distributed scheduling
|
|
27
|
+
*/
|
|
28
|
+
export declare abstract class SchedulerService {
|
|
29
|
+
/**
|
|
30
|
+
* Initialize the scheduler service
|
|
31
|
+
*/
|
|
32
|
+
abstract init(): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Schedule a one-off delayed RPC call
|
|
35
|
+
* @param delay - Delay before execution (number in milliseconds or duration string like "5h", "30m")
|
|
36
|
+
* @param rpcName - RPC function name to invoke
|
|
37
|
+
* @param data - Data to pass to the RPC function
|
|
38
|
+
* @param session - Optional user session
|
|
39
|
+
* @returns Task ID
|
|
40
|
+
*/
|
|
41
|
+
abstract scheduleRPC(delay: number | string, rpcName: string, data?: any, session?: CoreUserSession): Promise<string>;
|
|
42
|
+
/**
|
|
43
|
+
* Unschedule a task by ID
|
|
44
|
+
* @param taskId - Task ID
|
|
45
|
+
* @returns Success status
|
|
46
|
+
*/
|
|
47
|
+
abstract unschedule(taskId: string): Promise<boolean>;
|
|
48
|
+
/**
|
|
49
|
+
* Get a scheduled task by ID with full details
|
|
50
|
+
* @param taskId - Task ID
|
|
51
|
+
* @returns Task info or null if not found
|
|
52
|
+
*/
|
|
53
|
+
abstract getTask(taskId: string): Promise<ScheduledTaskInfo | null>;
|
|
54
|
+
/**
|
|
55
|
+
* Get all scheduled tasks with minimal info
|
|
56
|
+
* @returns Array of task summaries with taskId, rpcName, and schedule
|
|
57
|
+
*/
|
|
58
|
+
abstract getAllTasks(): Promise<ScheduledTaskSummary[]>;
|
|
59
|
+
/**
|
|
60
|
+
* Close any open connections
|
|
61
|
+
*/
|
|
62
|
+
abstract close(): Promise<void>;
|
|
63
|
+
}
|
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
import { ChannelStore } from '../wirings/channel/channel-store.js';
|
|
2
2
|
import { CoreUserSession } from '../types/core.types.js';
|
|
3
|
-
export interface
|
|
3
|
+
export interface SessionService<UserSession extends CoreUserSession> {
|
|
4
4
|
sessionChanged: boolean;
|
|
5
|
+
initial: UserSession | undefined;
|
|
5
6
|
setInitial(session: UserSession): void;
|
|
7
|
+
freezeInitial(): UserSession | undefined;
|
|
6
8
|
set(session: UserSession): Promise<void> | void;
|
|
7
9
|
clear(): Promise<void> | void;
|
|
8
|
-
get(): Promise<UserSession
|
|
10
|
+
get(): Promise<UserSession> | UserSession | undefined;
|
|
9
11
|
}
|
|
10
|
-
export declare class
|
|
12
|
+
export declare class PikkuSessionService<UserSession extends CoreUserSession> implements SessionService<UserSession> {
|
|
11
13
|
private channelStore?;
|
|
12
14
|
private channelId?;
|
|
13
15
|
sessionChanged: boolean;
|
|
16
|
+
initial: UserSession | undefined;
|
|
14
17
|
private session;
|
|
15
18
|
constructor(channelStore?: ChannelStore<unknown, unknown, UserSession> | undefined, channelId?: string | undefined);
|
|
16
19
|
setInitial(session: UserSession): void;
|
|
20
|
+
freezeInitial(): UserSession | undefined;
|
|
17
21
|
set(session: UserSession): void | Promise<void> | undefined;
|
|
18
22
|
clear(): void | Promise<void> | undefined;
|
|
19
23
|
get(): Promise<UserSession> | UserSession | undefined;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
export class
|
|
1
|
+
export class PikkuSessionService {
|
|
2
2
|
channelStore;
|
|
3
3
|
channelId;
|
|
4
4
|
sessionChanged = false;
|
|
5
|
+
initial;
|
|
5
6
|
session;
|
|
6
7
|
constructor(channelStore, channelId) {
|
|
7
8
|
this.channelStore = channelStore;
|
|
@@ -13,6 +14,12 @@ export class PikkuUserSessionService {
|
|
|
13
14
|
setInitial(session) {
|
|
14
15
|
this.session = session;
|
|
15
16
|
}
|
|
17
|
+
freezeInitial() {
|
|
18
|
+
if (this.initial === undefined) {
|
|
19
|
+
this.initial = this.session;
|
|
20
|
+
}
|
|
21
|
+
return this.initial;
|
|
22
|
+
}
|
|
16
23
|
set(session) {
|
|
17
24
|
this.sessionChanged = true;
|
|
18
25
|
this.session = session;
|
package/dist/time-utils.d.ts
CHANGED
|
@@ -9,4 +9,18 @@ export declare const getRelativeTimeOffset: ({ value, unit, }: RelativeTimeInput
|
|
|
9
9
|
* e.g. value = -1 and unit = 'day' => 1 day ago => now - 86400 seconds
|
|
10
10
|
*/
|
|
11
11
|
export declare const getRelativeTimeOffsetFromNow: (relativeTime: RelativeTimeInput) => Date;
|
|
12
|
+
/**
|
|
13
|
+
* Get duration in milliseconds from a string or number
|
|
14
|
+
* @param duration
|
|
15
|
+
* @returns
|
|
16
|
+
*/
|
|
17
|
+
export declare const getDurationInMilliseconds: (duration: string | number) => number;
|
|
18
|
+
/**
|
|
19
|
+
* Parse a duration string to milliseconds
|
|
20
|
+
* Supports formats like: '2s', '5s', '5sec', '5seconds', '5m', '5min', '5minutes', '1h', '1hour', '2d', '2day', '1w', '1week'
|
|
21
|
+
*
|
|
22
|
+
* @param duration - Duration string (e.g., '2s', '5min', '2hours', '1day')
|
|
23
|
+
* @returns Duration in milliseconds
|
|
24
|
+
*/
|
|
25
|
+
export declare const parseDurationString: (duration: string) => number;
|
|
12
26
|
export {};
|
package/dist/time-utils.js
CHANGED
|
@@ -16,3 +16,65 @@ export const getRelativeTimeOffset = ({ value, unit, }) => {
|
|
|
16
16
|
export const getRelativeTimeOffsetFromNow = (relativeTime) => {
|
|
17
17
|
return new Date(Date.now() + getRelativeTimeOffset(relativeTime));
|
|
18
18
|
};
|
|
19
|
+
/**
|
|
20
|
+
* Get duration in milliseconds from a string or number
|
|
21
|
+
* @param duration
|
|
22
|
+
* @returns
|
|
23
|
+
*/
|
|
24
|
+
export const getDurationInMilliseconds = (duration) => {
|
|
25
|
+
if (typeof duration === 'number') {
|
|
26
|
+
return duration;
|
|
27
|
+
}
|
|
28
|
+
return parseDurationString(duration);
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Parse a duration string to milliseconds
|
|
32
|
+
* Supports formats like: '2s', '5s', '5sec', '5seconds', '5m', '5min', '5minutes', '1h', '1hour', '2d', '2day', '1w', '1week'
|
|
33
|
+
*
|
|
34
|
+
* @param duration - Duration string (e.g., '2s', '5min', '2hours', '1day')
|
|
35
|
+
* @returns Duration in milliseconds
|
|
36
|
+
*/
|
|
37
|
+
export const parseDurationString = (duration) => {
|
|
38
|
+
const match = duration.match(/^(\d+)(ms|milliseconds?|s|sec|seconds?|m|min|minutes?|h|hour|hours?|d|day|days?|w|week|weeks?|y|year|years?)$/);
|
|
39
|
+
if (!match) {
|
|
40
|
+
throw new Error(`Invalid duration format: ${duration}. Use formats like '2s', '5s', '5min', '1hour', '2days', '1week'`);
|
|
41
|
+
}
|
|
42
|
+
const value = parseInt(match[1], 10);
|
|
43
|
+
const unitStr = match[2];
|
|
44
|
+
// Handle milliseconds specially
|
|
45
|
+
if (unitStr === 'ms' ||
|
|
46
|
+
unitStr === 'millisecond' ||
|
|
47
|
+
unitStr === 'milliseconds') {
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
50
|
+
// Map string variations to TimeUnit
|
|
51
|
+
let unit;
|
|
52
|
+
if (unitStr === 's' ||
|
|
53
|
+
unitStr === 'sec' ||
|
|
54
|
+
unitStr === 'second' ||
|
|
55
|
+
unitStr === 'seconds') {
|
|
56
|
+
unit = 'second';
|
|
57
|
+
}
|
|
58
|
+
else if (unitStr === 'm' ||
|
|
59
|
+
unitStr === 'min' ||
|
|
60
|
+
unitStr === 'minute' ||
|
|
61
|
+
unitStr === 'minutes') {
|
|
62
|
+
unit = 'minute';
|
|
63
|
+
}
|
|
64
|
+
else if (unitStr === 'h' || unitStr === 'hour' || unitStr === 'hours') {
|
|
65
|
+
unit = 'hour';
|
|
66
|
+
}
|
|
67
|
+
else if (unitStr === 'd' || unitStr === 'day' || unitStr === 'days') {
|
|
68
|
+
unit = 'day';
|
|
69
|
+
}
|
|
70
|
+
else if (unitStr === 'w' || unitStr === 'week' || unitStr === 'weeks') {
|
|
71
|
+
unit = 'week';
|
|
72
|
+
}
|
|
73
|
+
else if (unitStr === 'y' || unitStr === 'year' || unitStr === 'years') {
|
|
74
|
+
unit = 'year';
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
throw new Error(`Unknown time unit: ${unitStr}`);
|
|
78
|
+
}
|
|
79
|
+
return getRelativeTimeOffset({ value, unit });
|
|
80
|
+
};
|
|
@@ -3,22 +3,16 @@ 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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
channel = "channel",
|
|
17
|
-
rpc = "rpc",
|
|
18
|
-
queue = "queue",
|
|
19
|
-
mcp = "mcp",
|
|
20
|
-
cli = "cli"
|
|
21
|
-
}
|
|
13
|
+
import { PikkuWorkflowWire, WorkflowService, WorkflowServiceConfig, WorkflowStepWire } from '../wirings/workflow/workflow.types.js';
|
|
14
|
+
import { SchedulerService } from '../services/scheduler-service.js';
|
|
15
|
+
export type PikkuWiringTypes = 'http' | 'scheduler' | 'channel' | 'rpc' | 'queue' | 'mcp' | 'cli' | 'workflow';
|
|
22
16
|
export interface FunctionServicesMeta {
|
|
23
17
|
optimized: boolean;
|
|
24
18
|
services: string[];
|
|
@@ -62,18 +56,18 @@ export type FunctionRuntimeMeta = {
|
|
|
62
56
|
inputSchemaName: string | null;
|
|
63
57
|
outputSchemaName: string | null;
|
|
64
58
|
expose?: boolean;
|
|
59
|
+
internal?: boolean;
|
|
65
60
|
};
|
|
66
61
|
export type FunctionMeta = FunctionRuntimeMeta & Partial<{
|
|
67
62
|
name: string;
|
|
68
63
|
services: FunctionServicesMeta;
|
|
64
|
+
usedWires: string[];
|
|
69
65
|
inputs: string[] | null;
|
|
70
66
|
outputs: string[] | null;
|
|
71
|
-
tags: string[];
|
|
72
|
-
docs: PikkuDocs;
|
|
73
|
-
isDirectFunction: boolean;
|
|
74
67
|
middleware: MiddlewareMetadata[];
|
|
75
68
|
permissions: PermissionMetadata[];
|
|
76
|
-
|
|
69
|
+
isDirectFunction: boolean;
|
|
70
|
+
} & CommonWireMeta>;
|
|
77
71
|
export type FunctionsRuntimeMeta = Record<string, FunctionRuntimeMeta>;
|
|
78
72
|
export type FunctionsMeta = Record<string, FunctionMeta>;
|
|
79
73
|
export type MakeRequired<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
|
|
@@ -109,6 +103,7 @@ export type CoreConfig<Config extends Record<string, unknown> = {}> = {
|
|
|
109
103
|
logLevel?: LogLevel;
|
|
110
104
|
/** Secrets used by the application (optional). */
|
|
111
105
|
secrets?: {};
|
|
106
|
+
workflow?: WorkflowServiceConfig;
|
|
112
107
|
} & Config;
|
|
113
108
|
/**
|
|
114
109
|
* Represents a core user session, which can be extended for more specific session information.
|
|
@@ -129,25 +124,33 @@ export interface CoreSingletonServices<Config extends CoreConfig = CoreConfig> {
|
|
|
129
124
|
logger: Logger;
|
|
130
125
|
/** The variable service to be used */
|
|
131
126
|
variables: VariablesService;
|
|
127
|
+
/** The workflow orchestrator service */
|
|
128
|
+
workflowService?: WorkflowService;
|
|
129
|
+
/** The queue service */
|
|
130
|
+
queueService?: QueueService;
|
|
131
|
+
/** The scheduler service */
|
|
132
|
+
schedulerService?: SchedulerService;
|
|
132
133
|
}
|
|
133
134
|
/**
|
|
134
|
-
* Represents different forms of
|
|
135
|
+
* Represents different forms of wire within Pikku and the outside world.
|
|
135
136
|
*/
|
|
136
|
-
export type
|
|
137
|
+
export type PikkuWire<In = unknown, Out = unknown, HasInitialSession extends boolean = false, UserSession extends CoreUserSession = CoreUserSession, TypedRPC extends PikkuRPC = PikkuRPC, IsChannel extends true | null = null, MCPTools extends string | never = never, TypedWorkflow extends PikkuWorkflowWire | never = PikkuWorkflowWire> = Partial<{
|
|
137
138
|
http: PikkuHTTP<In>;
|
|
138
|
-
mcp: PikkuMCP
|
|
139
|
-
rpc:
|
|
140
|
-
channel: PikkuChannel<unknown, Out
|
|
139
|
+
mcp: PikkuMCP<MCPTools>;
|
|
140
|
+
rpc: TypedRPC;
|
|
141
|
+
channel: [IsChannel] extends [null] ? PikkuChannel<unknown, Out> : PikkuChannel<unknown, Out> | undefined;
|
|
141
142
|
scheduledTask: PikkuScheduledTask;
|
|
142
143
|
queue: PikkuQueue;
|
|
143
144
|
cli: PikkuCLI;
|
|
145
|
+
workflow: TypedWorkflow;
|
|
146
|
+
workflowStep: WorkflowStepWire;
|
|
147
|
+
initialSession: HasInitialSession extends true ? UserSession : UserSession | undefined;
|
|
148
|
+
session: SessionService<UserSession>;
|
|
144
149
|
}>;
|
|
145
150
|
/**
|
|
146
|
-
* A function that can wrap an
|
|
151
|
+
* A function that can wrap an wire and be called before or after
|
|
147
152
|
*/
|
|
148
|
-
export type CorePikkuMiddleware<SingletonServices extends CoreSingletonServices = CoreSingletonServices, UserSession extends CoreUserSession = CoreUserSession> = (services: SingletonServices
|
|
149
|
-
userSession: UserSessionService<UserSession>;
|
|
150
|
-
}, interactions: PikkuInteraction, next: () => Promise<void>) => Promise<void>;
|
|
153
|
+
export type CorePikkuMiddleware<SingletonServices extends CoreSingletonServices = CoreSingletonServices, UserSession extends CoreUserSession = CoreUserSession> = (services: SingletonServices, wires: PikkuWire<unknown, unknown, false, UserSession>, next: () => Promise<void>) => Promise<void>;
|
|
151
154
|
/**
|
|
152
155
|
* Configuration object for creating middleware with metadata
|
|
153
156
|
*
|
|
@@ -180,7 +183,7 @@ export type CorePikkuMiddlewareGroup<SingletonServices extends CoreSingletonServ
|
|
|
180
183
|
* ```typescript
|
|
181
184
|
* // Direct function syntax
|
|
182
185
|
* export const logMiddleware = pikkuMiddleware(
|
|
183
|
-
* async ({ logger },
|
|
186
|
+
* async ({ logger }, next) => {
|
|
184
187
|
* logger.info('Request started')
|
|
185
188
|
* await next()
|
|
186
189
|
* }
|
|
@@ -190,7 +193,7 @@ export type CorePikkuMiddlewareGroup<SingletonServices extends CoreSingletonServ
|
|
|
190
193
|
* export const logMiddleware = pikkuMiddleware({
|
|
191
194
|
* name: 'Request Logger',
|
|
192
195
|
* description: 'Logs request information',
|
|
193
|
-
* func: async ({ logger },
|
|
196
|
+
* func: async ({ logger }, next) => {
|
|
194
197
|
* logger.info('Request started')
|
|
195
198
|
* await next()
|
|
196
199
|
* }
|
|
@@ -208,7 +211,7 @@ export declare const pikkuMiddleware: <SingletonServices extends CoreSingletonSe
|
|
|
208
211
|
* message,
|
|
209
212
|
* level = 'info'
|
|
210
213
|
* }) => {
|
|
211
|
-
* return pikkuMiddleware(async ({ logger },
|
|
214
|
+
* return pikkuMiddleware(async ({ logger }, next) => {
|
|
212
215
|
* logger[level](message)
|
|
213
216
|
* await next()
|
|
214
217
|
* })
|
|
@@ -217,12 +220,10 @@ export declare const pikkuMiddleware: <SingletonServices extends CoreSingletonSe
|
|
|
217
220
|
*/
|
|
218
221
|
export declare const pikkuMiddlewareFactory: <In = any>(factory: CorePikkuMiddlewareFactory<In>) => CorePikkuMiddlewareFactory<In>;
|
|
219
222
|
/**
|
|
220
|
-
* Represents the core services used by Pikku, including singleton services
|
|
223
|
+
* Represents the core services used by Pikku, including singleton services.
|
|
221
224
|
*/
|
|
222
|
-
export type CoreServices<SingletonServices = CoreSingletonServices
|
|
223
|
-
|
|
224
|
-
};
|
|
225
|
-
export type SessionServices<SingletonServices extends CoreSingletonServices = CoreSingletonServices, Services = CoreServices<SingletonServices>> = Omit<Services, keyof SingletonServices | keyof PikkuInteraction | 'session'>;
|
|
225
|
+
export type CoreServices<SingletonServices = CoreSingletonServices> = SingletonServices;
|
|
226
|
+
export type WireServices<SingletonServices extends CoreSingletonServices = CoreSingletonServices, Services = CoreServices<SingletonServices>> = Omit<Services, keyof SingletonServices | 'session'>;
|
|
226
227
|
/**
|
|
227
228
|
* Defines a function type for creating singleton services from the given configuration.
|
|
228
229
|
*/
|
|
@@ -230,7 +231,7 @@ export type CreateSingletonServices<Config extends CoreConfig, SingletonServices
|
|
|
230
231
|
/**
|
|
231
232
|
* Defines a function type for creating session-specific services.
|
|
232
233
|
*/
|
|
233
|
-
export type
|
|
234
|
+
export type CreateWireServices<SingletonServices extends CoreSingletonServices = CoreSingletonServices, Services extends CoreServices<SingletonServices> = CoreServices<SingletonServices>, UserSession extends CoreUserSession = CoreUserSession> = (services: SingletonServices, wire: PikkuWire<unknown, unknown, false, UserSession>) => Promise<WireServices<Services, SingletonServices>>;
|
|
234
235
|
/**
|
|
235
236
|
* Defines a function type for creating config.
|
|
236
237
|
*/
|
|
@@ -238,9 +239,21 @@ export type CreateConfig<Config extends CoreConfig, RemainingArgs extends any[]
|
|
|
238
239
|
/**
|
|
239
240
|
* Represents the documentation for a route, including summary, description, tags, and errors.
|
|
240
241
|
*/
|
|
241
|
-
export type
|
|
242
|
+
export type CommonWireMeta = {
|
|
243
|
+
pikkuFuncName: string;
|
|
244
|
+
tags?: string[];
|
|
242
245
|
summary?: string;
|
|
243
246
|
description?: string;
|
|
244
|
-
tags?: string[];
|
|
245
247
|
errors?: string[];
|
|
248
|
+
middleware?: MiddlewareMetadata[];
|
|
249
|
+
permissions?: PermissionMetadata[];
|
|
246
250
|
};
|
|
251
|
+
/**
|
|
252
|
+
* Serialized error for storage
|
|
253
|
+
*/
|
|
254
|
+
export interface SerializedError {
|
|
255
|
+
message: string;
|
|
256
|
+
stack?: string;
|
|
257
|
+
code?: string;
|
|
258
|
+
[key: string]: any;
|
|
259
|
+
}
|
package/dist/types/core.types.js
CHANGED
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
export var PikkuWiringTypes;
|
|
2
|
-
(function (PikkuWiringTypes) {
|
|
3
|
-
PikkuWiringTypes["http"] = "http";
|
|
4
|
-
PikkuWiringTypes["scheduler"] = "scheduler";
|
|
5
|
-
PikkuWiringTypes["channel"] = "channel";
|
|
6
|
-
PikkuWiringTypes["rpc"] = "rpc";
|
|
7
|
-
PikkuWiringTypes["queue"] = "queue";
|
|
8
|
-
PikkuWiringTypes["mcp"] = "mcp";
|
|
9
|
-
PikkuWiringTypes["cli"] = "cli";
|
|
10
|
-
})(PikkuWiringTypes || (PikkuWiringTypes = {}));
|
|
11
1
|
/**
|
|
12
2
|
* Factory function for creating middleware with tree-shaking support
|
|
13
3
|
* Supports both direct function and configuration object syntax
|
|
@@ -16,7 +6,7 @@ export var PikkuWiringTypes;
|
|
|
16
6
|
* ```typescript
|
|
17
7
|
* // Direct function syntax
|
|
18
8
|
* export const logMiddleware = pikkuMiddleware(
|
|
19
|
-
* async ({ logger },
|
|
9
|
+
* async ({ logger }, next) => {
|
|
20
10
|
* logger.info('Request started')
|
|
21
11
|
* await next()
|
|
22
12
|
* }
|
|
@@ -26,7 +16,7 @@ export var PikkuWiringTypes;
|
|
|
26
16
|
* export const logMiddleware = pikkuMiddleware({
|
|
27
17
|
* name: 'Request Logger',
|
|
28
18
|
* description: 'Logs request information',
|
|
29
|
-
* func: async ({ logger },
|
|
19
|
+
* func: async ({ logger }, next) => {
|
|
30
20
|
* logger.info('Request started')
|
|
31
21
|
* await next()
|
|
32
22
|
* }
|
|
@@ -46,7 +36,7 @@ export const pikkuMiddleware = (middleware) => {
|
|
|
46
36
|
* message,
|
|
47
37
|
* level = 'info'
|
|
48
38
|
* }) => {
|
|
49
|
-
* return pikkuMiddleware(async ({ logger },
|
|
39
|
+
* return pikkuMiddleware(async ({ logger }, next) => {
|
|
50
40
|
* logger[level](message)
|
|
51
41
|
* await next()
|
|
52
42
|
* })
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Logger } from './services/logger.js';
|
|
2
|
-
export declare const
|
|
2
|
+
export declare const closeWireServices: (logger: Logger, wireServices: Record<string, any>) => Promise<void>;
|
|
3
3
|
export declare const createWeakUID: () => string;
|
|
4
4
|
export declare const isSerializable: (data: any) => boolean;
|
|
5
5
|
export declare const freezeDedupe: <T>(arr?: readonly T[] | T[] | undefined) => readonly T[];
|
package/dist/utils.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
// TODO:
|
|
1
|
+
// TODO: WireServices probably needs it's own type
|
|
2
2
|
// but is an issue for the future and will be tackled
|
|
3
3
|
// with dependency injection
|
|
4
|
-
export const
|
|
5
|
-
await Promise.all(Object.values(
|
|
4
|
+
export const closeWireServices = async (logger, wireServices) => {
|
|
5
|
+
await Promise.all(Object.values(wireServices).map(async (service) => {
|
|
6
6
|
if (service?.close) {
|
|
7
7
|
try {
|
|
8
8
|
await service.close();
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { PikkuWiringTypes, } from '../../types/core.types.js';
|
|
2
1
|
import { combineMiddleware, runMiddleware } from '../../middleware-runner.js';
|
|
3
2
|
import { runPikkuFuncDirectly } from '../../function/function-runner.js';
|
|
4
3
|
/**
|
|
@@ -24,13 +23,13 @@ export const runChannelLifecycleWithMiddleware = async ({ channelConfig, meta, l
|
|
|
24
23
|
? lifecycleConfig.middleware || []
|
|
25
24
|
: [];
|
|
26
25
|
// Use combineMiddleware to properly resolve metadata + inline middleware
|
|
27
|
-
const allMiddleware = combineMiddleware(
|
|
26
|
+
const allMiddleware = combineMiddleware('channel', `${channelConfig.name}:${lifecycleType}`, {
|
|
28
27
|
wireInheritedMiddleware: meta.middleware,
|
|
29
28
|
wireMiddleware: lifecycleMiddleware,
|
|
30
29
|
});
|
|
31
30
|
// Run the lifecycle function
|
|
32
31
|
const runLifecycle = async () => {
|
|
33
|
-
return await runPikkuFuncDirectly(meta.pikkuFuncName,
|
|
32
|
+
return await runPikkuFuncDirectly(meta.pikkuFuncName, services, { channel }, data);
|
|
34
33
|
};
|
|
35
34
|
// Run with middleware if any
|
|
36
35
|
if (allMiddleware.length > 0) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import { CoreServices } from '../../types/core.types.js';
|
|
1
|
+
import { CoreServices, CoreUserSession } from '../../types/core.types.js';
|
|
2
2
|
import { CoreChannel, PikkuChannelHandler } from './channel.types.js';
|
|
3
|
-
|
|
3
|
+
import { SessionService } from '../../services/user-session-service.js';
|
|
4
|
+
export declare const processMessageHandlers: (services: CoreServices, channelConfig: CoreChannel<any, any>, channelHandler: PikkuChannelHandler, userSession?: SessionService<CoreUserSession>) => (rawData: any) => Promise<unknown>;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { PikkuWiringTypes, } from '../../types/core.types.js';
|
|
2
1
|
import { pikkuState } from '../../pikku-state.js';
|
|
3
2
|
import { runPikkuFunc } from '../../function/function-runner.js';
|
|
4
3
|
const getRouteMeta = (channelName, routingProperty, routerValue) => {
|
|
@@ -32,7 +31,7 @@ const validateAuth = (requiresSession, session, onMessage) => {
|
|
|
32
31
|
}
|
|
33
32
|
return true;
|
|
34
33
|
};
|
|
35
|
-
export const processMessageHandlers = (services, channelConfig, channelHandler) => {
|
|
34
|
+
export const processMessageHandlers = (services, channelConfig, channelHandler, userSession) => {
|
|
36
35
|
const logger = services.logger;
|
|
37
36
|
const requiresSession = channelConfig.auth !== false;
|
|
38
37
|
const processMessage = async (data, onMessage, routingProperty, routerValue) => {
|
|
@@ -69,20 +68,18 @@ export const processMessageHandlers = (services, channelConfig, channelHandler)
|
|
|
69
68
|
const cacheKey = routingProperty
|
|
70
69
|
? `${channelConfig.name}:${routingProperty}:${routerValue}`
|
|
71
70
|
: `${channelConfig.name}:default`;
|
|
72
|
-
return await runPikkuFunc(
|
|
71
|
+
return await runPikkuFunc('channel', cacheKey, pikkuFuncName, {
|
|
73
72
|
singletonServices: services,
|
|
74
|
-
getAllServices: () => ({
|
|
75
|
-
...services,
|
|
76
|
-
channel: channelHandler.getChannel(),
|
|
77
|
-
}),
|
|
78
73
|
data: () => data,
|
|
79
|
-
userSession: services.userSession,
|
|
80
74
|
inheritedMiddleware,
|
|
81
75
|
wireMiddleware,
|
|
82
76
|
inheritedPermissions,
|
|
83
77
|
wirePermissions,
|
|
84
78
|
tags: channelConfig.tags,
|
|
85
|
-
|
|
79
|
+
wire: {
|
|
80
|
+
channel: channelHandler.getChannel(),
|
|
81
|
+
session: userSession,
|
|
82
|
+
},
|
|
86
83
|
});
|
|
87
84
|
};
|
|
88
85
|
return async (rawData) => {
|