@pikku/core 0.11.0 → 0.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -1
- package/dist/errors/error-handler.js +3 -3
- package/dist/errors/errors.d.ts +1 -1
- package/dist/errors/errors.js +3 -3
- package/dist/function/function-runner.d.ts +8 -8
- package/dist/function/function-runner.js +88 -23
- package/dist/function/functions.types.d.ts +104 -33
- package/dist/function/functions.types.js +50 -7
- package/dist/handle-error.d.ts +1 -1
- package/dist/handle-error.js +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.js +5 -2
- package/dist/middleware/auth-apikey.d.ts +1 -1
- package/dist/middleware/auth-apikey.js +3 -3
- package/dist/middleware/auth-bearer.d.ts +1 -1
- package/dist/middleware/auth-bearer.js +3 -3
- package/dist/middleware/auth-cookie.d.ts +1 -1
- package/dist/middleware/auth-cookie.js +5 -5
- package/dist/middleware/timeout.d.ts +1 -1
- package/dist/middleware/timeout.js +3 -2
- package/dist/middleware-runner.d.ts +6 -20
- package/dist/middleware-runner.js +19 -20
- package/dist/permissions.d.ts +6 -89
- package/dist/permissions.js +24 -81
- package/dist/pikku-state.d.ts +32 -104
- package/dist/pikku-state.js +140 -66
- package/dist/schema.d.ts +8 -6
- package/dist/schema.js +25 -13
- package/dist/services/user-session-service.d.ts +7 -3
- package/dist/services/user-session-service.js +8 -1
- package/dist/services/workflow-service.d.ts +38 -0
- package/dist/services/workflow-service.js +1 -0
- package/dist/types/core.types.d.ts +40 -41
- package/dist/types/core.types.js +4 -15
- package/dist/types/state.types.d.ts +135 -0
- package/dist/types/state.types.js +1 -0
- package/dist/utils.d.ts +9 -1
- package/dist/utils.js +48 -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 +7 -10
- package/dist/wirings/channel/channel-runner.d.ts +2 -2
- package/dist/wirings/channel/channel-runner.js +5 -5
- 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/log-channels.js +1 -1
- package/dist/wirings/channel/serverless/serverless-channel-runner.d.ts +1 -1
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +43 -48
- package/dist/wirings/cli/channel/cli-channel-runner.js +3 -2
- package/dist/wirings/cli/cli-runner.d.ts +5 -5
- package/dist/wirings/cli/cli-runner.js +20 -38
- package/dist/wirings/cli/cli.types.d.ts +16 -11
- package/dist/wirings/forge-node/forge-node.types.d.ts +120 -0
- package/dist/wirings/forge-node/forge-node.types.js +38 -0
- package/dist/wirings/forge-node/index.d.ts +1 -0
- package/dist/wirings/forge-node/index.js +1 -0
- package/dist/wirings/http/http-runner.d.ts +8 -8
- package/dist/wirings/http/http-runner.js +46 -51
- package/dist/wirings/http/http.types.d.ts +19 -11
- package/dist/wirings/http/log-http-routes.js +1 -1
- package/dist/wirings/http/routers/path-to-regex.js +2 -2
- package/dist/wirings/mcp/mcp-runner.d.ts +2 -2
- package/dist/wirings/mcp/mcp-runner.js +33 -40
- 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 +13 -23
- package/dist/wirings/queue/queue.types.d.ts +4 -11
- 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 +17 -16
- package/dist/wirings/rpc/rpc-runner.js +98 -61
- package/dist/wirings/rpc/rpc-types.d.ts +7 -0
- package/dist/wirings/scheduler/log-schedulers.js +1 -1
- package/dist/wirings/scheduler/scheduler-runner.d.ts +3 -3
- package/dist/wirings/scheduler/scheduler-runner.js +18 -29
- package/dist/wirings/scheduler/scheduler.types.d.ts +3 -8
- package/dist/wirings/trigger/index.d.ts +2 -0
- package/dist/wirings/trigger/index.js +2 -0
- package/dist/wirings/trigger/trigger-runner.d.ts +29 -0
- package/dist/wirings/trigger/trigger-runner.js +57 -0
- package/dist/wirings/trigger/trigger.types.d.ts +42 -0
- package/dist/wirings/trigger/trigger.types.js +1 -0
- package/dist/wirings/workflow/dsl/index.d.ts +5 -0
- package/dist/wirings/workflow/dsl/index.js +4 -0
- package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +286 -0
- package/dist/wirings/workflow/dsl/workflow-dsl.types.js +5 -0
- package/dist/wirings/workflow/dsl/workflow-runner.d.ts +5 -0
- package/dist/wirings/workflow/dsl/workflow-runner.js +22 -0
- package/dist/wirings/workflow/graph/graph-node.d.ts +122 -0
- package/dist/wirings/workflow/graph/graph-node.js +58 -0
- package/dist/wirings/workflow/graph/graph-runner.d.ts +35 -0
- package/dist/wirings/workflow/graph/graph-runner.js +452 -0
- package/dist/wirings/workflow/graph/index.d.ts +3 -0
- package/dist/wirings/workflow/graph/index.js +3 -0
- package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +95 -0
- package/dist/wirings/workflow/graph/workflow-graph.types.js +15 -0
- package/dist/wirings/workflow/index.d.ts +7 -3
- package/dist/wirings/workflow/index.js +6 -3
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +108 -10
- package/dist/wirings/workflow/pikku-workflow-service.js +274 -165
- package/dist/wirings/workflow/wire-workflow.d.ts +42 -0
- package/dist/wirings/workflow/wire-workflow.js +53 -0
- package/dist/wirings/workflow/workflow-utils.d.ts +23 -0
- package/dist/wirings/workflow/workflow-utils.js +66 -0
- package/dist/wirings/workflow/workflow.types.d.ts +135 -128
- package/package.json +11 -2
- package/src/errors/error-handler.ts +3 -3
- package/src/errors/errors.ts +3 -3
- package/src/factory-functions.test.ts +9 -36
- package/src/function/function-runner.test.ts +58 -69
- package/src/function/function-runner.ts +130 -37
- package/src/function/functions.types.ts +193 -54
- package/src/handle-error.ts +1 -1
- package/src/index.ts +10 -5
- 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 +29 -25
- package/src/permissions.test.ts +68 -130
- package/src/permissions.ts +41 -100
- package/src/pikku-state.ts +156 -201
- package/src/schema.ts +42 -13
- package/src/services/user-session-service.ts +14 -4
- package/src/services/workflow-service.ts +74 -0
- package/src/types/core.types.ts +79 -58
- package/src/types/state.types.ts +195 -0
- package/src/utils.ts +59 -4
- package/src/wirings/channel/channel-common.ts +4 -7
- package/src/wirings/channel/channel-handler.ts +17 -23
- package/src/wirings/channel/channel-runner.ts +7 -7
- package/src/wirings/channel/channel.types.ts +14 -11
- package/src/wirings/channel/local/local-channel-runner.test.ts +8 -4
- package/src/wirings/channel/local/local-channel-runner.ts +23 -38
- package/src/wirings/channel/log-channels.ts +1 -1
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +53 -79
- package/src/wirings/cli/channel/cli-channel-runner.ts +4 -3
- package/src/wirings/cli/cli-runner.test.ts +26 -26
- package/src/wirings/cli/cli-runner.ts +34 -71
- package/src/wirings/cli/cli.types.ts +23 -16
- package/src/wirings/forge-node/forge-node.types.ts +135 -0
- package/src/wirings/forge-node/index.ts +1 -0
- package/src/wirings/http/http-runner.test.ts +10 -10
- package/src/wirings/http/http-runner.ts +56 -66
- package/src/wirings/http/http.types.ts +19 -14
- package/src/wirings/http/log-http-routes.ts +1 -1
- package/src/wirings/http/routers/path-to-regex.test.ts +30 -19
- package/src/wirings/http/routers/path-to-regex.ts +2 -2
- package/src/wirings/mcp/mcp-runner.ts +44 -69
- 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 +16 -38
- package/src/wirings/queue/queue.types.ts +4 -11
- package/src/wirings/rpc/index.ts +1 -1
- package/src/wirings/rpc/rpc-runner.ts +129 -77
- package/src/wirings/rpc/rpc-types.ts +8 -0
- package/src/wirings/scheduler/log-schedulers.ts +1 -1
- package/src/wirings/scheduler/scheduler-runner.test.ts +627 -0
- package/src/wirings/scheduler/scheduler-runner.ts +29 -55
- package/src/wirings/scheduler/scheduler.types.ts +3 -9
- package/src/wirings/trigger/index.ts +2 -0
- package/src/wirings/trigger/trigger-runner.ts +96 -0
- package/src/wirings/trigger/trigger.types.ts +56 -0
- package/src/wirings/workflow/dsl/index.ts +30 -0
- package/src/wirings/workflow/dsl/workflow-dsl.types.ts +312 -0
- package/src/wirings/workflow/dsl/workflow-runner.ts +27 -0
- package/src/wirings/workflow/graph/graph-node.ts +227 -0
- package/src/wirings/workflow/graph/graph-runner.ts +694 -0
- package/src/wirings/workflow/graph/index.ts +3 -0
- package/src/wirings/workflow/graph/workflow-graph.types.ts +126 -0
- package/src/wirings/workflow/index.ts +60 -12
- package/src/wirings/workflow/pikku-workflow-service.ts +401 -195
- package/src/wirings/workflow/wire-workflow.ts +94 -0
- package/src/wirings/workflow/workflow-utils.ts +120 -0
- package/src/wirings/workflow/workflow.types.ts +167 -188
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/wirings/workflow/workflow-runner.d.ts +0 -35
- package/dist/wirings/workflow/workflow-runner.js +0 -68
- package/src/wirings/workflow/workflow-runner.ts +0 -85
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Forge node types for workflow builder visualization.
|
|
3
|
+
* wireForgeNode is metadata-only - no runtime behavior.
|
|
4
|
+
* The CLI extracts this via AST and generates JSON metadata.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The type of forge node.
|
|
9
|
+
* - trigger: Starts workflows (webhooks, schedules, events)
|
|
10
|
+
* - action: Operations that do something (API calls, send email, database ops)
|
|
11
|
+
* - end: Terminal nodes with no outputs (logging, notifications)
|
|
12
|
+
*/
|
|
13
|
+
export type ForgeNodeType = 'trigger' | 'action' | 'end'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Configuration for wireForgeNode.
|
|
17
|
+
* This is the input type that developers use when defining nodes.
|
|
18
|
+
*/
|
|
19
|
+
export type CoreForgeNode = {
|
|
20
|
+
/** Unique identifier for this node */
|
|
21
|
+
name: string
|
|
22
|
+
/** Human-readable name for UI display */
|
|
23
|
+
displayName: string
|
|
24
|
+
/** Grouping category (validated against forge.node.categories in config) */
|
|
25
|
+
category: string
|
|
26
|
+
/** Node type determining behavior and outputs */
|
|
27
|
+
type: ForgeNodeType
|
|
28
|
+
/** RPC name to call when node executes (local name, Forge handles package aliasing) */
|
|
29
|
+
rpc: string
|
|
30
|
+
/** Optional description for UI */
|
|
31
|
+
description?: string
|
|
32
|
+
/** Whether to add an error output port alongside the default output */
|
|
33
|
+
errorOutput?: boolean
|
|
34
|
+
/** Optional tags for filtering/categorization */
|
|
35
|
+
tags?: string[]
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Metadata generated for each forge node.
|
|
40
|
+
* This is the output type that the CLI generates.
|
|
41
|
+
*/
|
|
42
|
+
export type ForgeNodeMeta = {
|
|
43
|
+
name: string
|
|
44
|
+
displayName: string
|
|
45
|
+
category: string
|
|
46
|
+
type: ForgeNodeType
|
|
47
|
+
/** RPC name (local, remapped by Forge for external packages) */
|
|
48
|
+
rpc: string
|
|
49
|
+
description?: string
|
|
50
|
+
/** Whether node has error output port */
|
|
51
|
+
errorOutput: boolean
|
|
52
|
+
/** Input schema name extracted from RPC */
|
|
53
|
+
inputSchemaName: string | null
|
|
54
|
+
/** Output schema name extracted from RPC */
|
|
55
|
+
outputSchemaName: string | null
|
|
56
|
+
tags?: string[]
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Record of all forge node metadata, keyed by node name.
|
|
61
|
+
*/
|
|
62
|
+
export type ForgeNodesMeta = Record<string, ForgeNodeMeta>
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* No-op function for wireForgeNode.
|
|
66
|
+
* This exists purely for TypeScript type checking and will be tree-shaken.
|
|
67
|
+
* The CLI extracts metadata via AST parsing.
|
|
68
|
+
*/
|
|
69
|
+
export const wireForgeNode = (_config: CoreForgeNode): void => {
|
|
70
|
+
// No-op - metadata only, extracted by CLI via AST
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Configuration for wireForgeCredential.
|
|
75
|
+
* Declares credentials/secrets required by a Forge package.
|
|
76
|
+
* Uses Zod for schema definition - converted to JSON Schema at build time.
|
|
77
|
+
*/
|
|
78
|
+
export type CoreForgeCredential<T = unknown> = {
|
|
79
|
+
/** Unique identifier for this credential */
|
|
80
|
+
name: string
|
|
81
|
+
/** Human-readable name for UI display */
|
|
82
|
+
displayName: string
|
|
83
|
+
/** Optional description for UI */
|
|
84
|
+
description?: string
|
|
85
|
+
/** Key used with SecretService.getSecret() to retrieve the credential */
|
|
86
|
+
secretId: string
|
|
87
|
+
/** Zod schema defining the structure of the credential */
|
|
88
|
+
schema: T
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Metadata generated for each forge credential.
|
|
93
|
+
* Schema is converted from Zod to JSON Schema at build time.
|
|
94
|
+
*/
|
|
95
|
+
export type ForgeCredentialMeta = {
|
|
96
|
+
name: string
|
|
97
|
+
displayName: string
|
|
98
|
+
description?: string
|
|
99
|
+
secretId: string
|
|
100
|
+
/** JSON Schema (converted from Zod at build time) or zodLookup reference name */
|
|
101
|
+
schema: Record<string, unknown> | string
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Record of all forge credential metadata, keyed by credential name.
|
|
106
|
+
*/
|
|
107
|
+
export type ForgeCredentialsMeta = Record<string, ForgeCredentialMeta>
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* No-op function for wireForgeCredential.
|
|
111
|
+
* This exists purely for TypeScript type checking and will be tree-shaken.
|
|
112
|
+
* The CLI extracts metadata via AST parsing.
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```typescript
|
|
116
|
+
* import { z } from 'zod'
|
|
117
|
+
*
|
|
118
|
+
* const slackCredentials = z.object({
|
|
119
|
+
* botToken: z.string().describe('Bot OAuth token'),
|
|
120
|
+
* signingSecret: z.string().describe('Request signing secret')
|
|
121
|
+
* })
|
|
122
|
+
*
|
|
123
|
+
* wireForgeCredential({
|
|
124
|
+
* name: 'slack',
|
|
125
|
+
* displayName: 'Slack Credentials',
|
|
126
|
+
* secretId: 'SLACK_CREDENTIALS',
|
|
127
|
+
* schema: slackCredentials
|
|
128
|
+
* })
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
export const wireForgeCredential = <T>(
|
|
132
|
+
_config: CoreForgeCredential<T>
|
|
133
|
+
): void => {
|
|
134
|
+
// No-op - metadata only, extracted by CLI via AST
|
|
135
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './forge-node.types.js'
|
|
@@ -11,19 +11,19 @@ import {
|
|
|
11
11
|
import { addFunction } from '../../function/function-runner.js'
|
|
12
12
|
import { httpRouter } from './routers/http-router.js'
|
|
13
13
|
|
|
14
|
-
const sessionMiddleware: CorePikkuMiddleware = async (services,
|
|
15
|
-
|
|
14
|
+
const sessionMiddleware: CorePikkuMiddleware = async (services, wire, next) => {
|
|
15
|
+
wire.session?.set({ userId: 'test' } as any)
|
|
16
16
|
await next()
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
const setHTTPFunctionMap = (func: any) => {
|
|
20
|
-
pikkuState('function', 'meta', {
|
|
20
|
+
pikkuState(null, 'function', 'meta', {
|
|
21
21
|
pikku_func_name: {
|
|
22
22
|
pikkuFuncName: 'pikku_func_name',
|
|
23
23
|
services: ['userSession'],
|
|
24
24
|
},
|
|
25
25
|
} as any)
|
|
26
|
-
pikkuState('http', 'meta', {
|
|
26
|
+
pikkuState(null, 'http', 'meta', {
|
|
27
27
|
get: {
|
|
28
28
|
test: {
|
|
29
29
|
pikkuFuncName: 'pikku_func_name',
|
|
@@ -43,7 +43,7 @@ const setHTTPFunctionMap = (func: any) => {
|
|
|
43
43
|
|
|
44
44
|
describe('fetch', () => {
|
|
45
45
|
let singletonServices: any
|
|
46
|
-
let
|
|
46
|
+
let createWireServices: any
|
|
47
47
|
let request: any
|
|
48
48
|
let response: any
|
|
49
49
|
|
|
@@ -59,7 +59,7 @@ describe('fetch', () => {
|
|
|
59
59
|
},
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
createWireServices = async () => ({})
|
|
63
63
|
request = new PikkuMockRequest('/test', 'get')
|
|
64
64
|
response = new PikkuMockResponse()
|
|
65
65
|
|
|
@@ -77,7 +77,7 @@ describe('fetch', () => {
|
|
|
77
77
|
async () =>
|
|
78
78
|
fetch(request, {
|
|
79
79
|
singletonServices,
|
|
80
|
-
|
|
80
|
+
createWireServices,
|
|
81
81
|
bubbleErrors: true,
|
|
82
82
|
}),
|
|
83
83
|
NotFoundError
|
|
@@ -99,7 +99,7 @@ describe('fetch', () => {
|
|
|
99
99
|
|
|
100
100
|
const result = await fetch(request, {
|
|
101
101
|
singletonServices,
|
|
102
|
-
|
|
102
|
+
createWireServices,
|
|
103
103
|
})
|
|
104
104
|
|
|
105
105
|
assert.deepStrictEqual(await result.json(), { success: true })
|
|
@@ -122,7 +122,7 @@ describe('fetch', () => {
|
|
|
122
122
|
|
|
123
123
|
await fetch(request, {
|
|
124
124
|
singletonServices,
|
|
125
|
-
|
|
125
|
+
createWireServices,
|
|
126
126
|
})
|
|
127
127
|
|
|
128
128
|
assert.strictEqual(await permissions.test(), true)
|
|
@@ -143,7 +143,7 @@ describe('fetch', () => {
|
|
|
143
143
|
async () =>
|
|
144
144
|
fetch(request, {
|
|
145
145
|
singletonServices,
|
|
146
|
-
|
|
146
|
+
createWireServices,
|
|
147
147
|
bubbleErrors: true,
|
|
148
148
|
}),
|
|
149
149
|
error
|
|
@@ -18,25 +18,25 @@ import {
|
|
|
18
18
|
CoreUserSession,
|
|
19
19
|
CorePikkuMiddleware,
|
|
20
20
|
CorePikkuMiddlewareGroup,
|
|
21
|
-
|
|
21
|
+
WireServices,
|
|
22
|
+
PikkuWire,
|
|
22
23
|
PikkuWiringTypes,
|
|
23
|
-
PikkuInteraction,
|
|
24
24
|
} from '../../types/core.types.js'
|
|
25
25
|
import { NotFoundError } from '../../errors/errors.js'
|
|
26
26
|
import {
|
|
27
|
-
|
|
27
|
+
closeWireServices,
|
|
28
28
|
createWeakUID,
|
|
29
29
|
isSerializable,
|
|
30
30
|
} from '../../utils.js'
|
|
31
|
-
import {
|
|
31
|
+
import { PikkuSessionService } from '../../services/user-session-service.js'
|
|
32
32
|
import { handleHTTPError } from '../../handle-error.js'
|
|
33
33
|
import { pikkuState } from '../../pikku-state.js'
|
|
34
34
|
import { PikkuFetchHTTPResponse } from './pikku-fetch-http-response.js'
|
|
35
35
|
import { PikkuFetchHTTPRequest } from './pikku-fetch-http-request.js'
|
|
36
36
|
import { PikkuChannel } from '../channel/channel.types.js'
|
|
37
37
|
import { addFunction, runPikkuFunc } from '../../function/function-runner.js'
|
|
38
|
-
import { rpcService } from '../rpc/rpc-runner.js'
|
|
39
38
|
import { httpRouter } from './routers/http-router.js'
|
|
39
|
+
import { startWorkflowByHttpWire } from '../workflow/workflow-utils.js'
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
42
|
* Registers HTTP middleware for a specific route pattern.
|
|
@@ -69,9 +69,10 @@ import { httpRouter } from './routers/http-router.js'
|
|
|
69
69
|
*/
|
|
70
70
|
export const addHTTPMiddleware = <PikkuMiddleware extends CorePikkuMiddleware>(
|
|
71
71
|
pattern: string,
|
|
72
|
-
middleware: CorePikkuMiddlewareGroup
|
|
72
|
+
middleware: CorePikkuMiddlewareGroup,
|
|
73
|
+
packageName: string | null = null
|
|
73
74
|
): CorePikkuMiddlewareGroup => {
|
|
74
|
-
const httpGroups = pikkuState('middleware', 'httpGroup')
|
|
75
|
+
const httpGroups = pikkuState(packageName, 'middleware', 'httpGroup')
|
|
75
76
|
httpGroups[pattern] = middleware
|
|
76
77
|
return middleware
|
|
77
78
|
}
|
|
@@ -107,9 +108,10 @@ export const addHTTPMiddleware = <PikkuMiddleware extends CorePikkuMiddleware>(
|
|
|
107
108
|
*/
|
|
108
109
|
export const addHTTPPermission = <PikkuPermission extends CorePikkuPermission>(
|
|
109
110
|
pattern: string,
|
|
110
|
-
permissions: CorePermissionGroup | CorePikkuPermission[]
|
|
111
|
+
permissions: CorePermissionGroup | CorePikkuPermission[],
|
|
112
|
+
packageName: string | null = null
|
|
111
113
|
): CorePermissionGroup | CorePikkuPermission[] => {
|
|
112
|
-
const httpGroups = pikkuState('permissions', 'httpGroup')
|
|
114
|
+
const httpGroups = pikkuState(packageName, 'permissions', 'httpGroup')
|
|
113
115
|
httpGroups[pattern] = permissions
|
|
114
116
|
return permissions
|
|
115
117
|
}
|
|
@@ -152,17 +154,19 @@ export const wireHTTP = <
|
|
|
152
154
|
PikkuMiddleware
|
|
153
155
|
>
|
|
154
156
|
) => {
|
|
155
|
-
const httpMeta = pikkuState('http', 'meta')
|
|
157
|
+
const httpMeta = pikkuState(null, 'http', 'meta')
|
|
156
158
|
const routeMeta = httpMeta[httpWiring.method][httpWiring.route]
|
|
157
159
|
if (!routeMeta) {
|
|
158
160
|
throw new Error('Route metadata not found')
|
|
159
161
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
+
if (httpWiring.func) {
|
|
163
|
+
addFunction(routeMeta.pikkuFuncName, httpWiring.func)
|
|
164
|
+
}
|
|
165
|
+
const routes = pikkuState(null, 'http', 'routes')
|
|
162
166
|
if (!routes.has(httpWiring.method)) {
|
|
163
167
|
routes.set(httpWiring.method, new Map())
|
|
164
168
|
}
|
|
165
|
-
pikkuState('http', 'routes')
|
|
169
|
+
pikkuState(null, 'http', 'routes')
|
|
166
170
|
.get(httpWiring.method)
|
|
167
171
|
?.set(httpWiring.route, httpWiring as any)
|
|
168
172
|
}
|
|
@@ -185,10 +189,10 @@ const getMatchingRoute = (requestType: string, requestPath: string) => {
|
|
|
185
189
|
)
|
|
186
190
|
|
|
187
191
|
if (matchedPath) {
|
|
188
|
-
const route = pikkuState('http', 'routes')
|
|
192
|
+
const route = pikkuState(null, 'http', 'routes')
|
|
189
193
|
.get(requestType.toLowerCase() as HTTPMethod)!
|
|
190
194
|
.get(matchedPath.route)!
|
|
191
|
-
const meta = pikkuState('http', 'meta')[
|
|
195
|
+
const meta = pikkuState(null, 'http', 'meta')[
|
|
192
196
|
requestType.toLowerCase() as PikkuWiringTypes
|
|
193
197
|
][route.route]
|
|
194
198
|
|
|
@@ -203,16 +207,16 @@ const getMatchingRoute = (requestType: string, requestPath: string) => {
|
|
|
203
207
|
}
|
|
204
208
|
|
|
205
209
|
/**
|
|
206
|
-
* Combines the request and response objects into a single HTTP
|
|
210
|
+
* Combines the request and response objects into a single HTTP wire object.
|
|
207
211
|
*
|
|
208
212
|
* This utility function creates an object that holds both the HTTP request and response,
|
|
209
213
|
* which simplifies passing these around through middleware and route execution.
|
|
210
214
|
*
|
|
211
215
|
* @param {PikkuHTTPRequest | undefined} request - The HTTP request object.
|
|
212
216
|
* @param {PikkuHTTPResponse | undefined} response - The HTTP response object.
|
|
213
|
-
* @returns {PikkuHTTP | undefined} The combined HTTP
|
|
217
|
+
* @returns {PikkuHTTP | undefined} The combined HTTP wire object or undefined if none provided.
|
|
214
218
|
*/
|
|
215
|
-
export const
|
|
219
|
+
export const createHTTPWire = (
|
|
216
220
|
request: PikkuHTTPRequest | undefined,
|
|
217
221
|
response: PikkuHTTPResponse | undefined
|
|
218
222
|
): PikkuHTTP | undefined => {
|
|
@@ -246,15 +250,15 @@ export const createHTTPInteraction = (
|
|
|
246
250
|
*
|
|
247
251
|
* @param {Object} services - A collection of shared services and utilities.
|
|
248
252
|
* @param {Object} matchedRoute - Contains route details, URL parameters, and optional schema.
|
|
249
|
-
* @param {PikkuHTTP | undefined} http - The HTTP
|
|
253
|
+
* @param {PikkuHTTP | undefined} http - The HTTP wire object.
|
|
250
254
|
* @param {Object} options - Options for route execution (e.g., whether to coerce query strings to arrays).
|
|
251
|
-
* @returns {Promise<any>} An object containing the route handler result and
|
|
255
|
+
* @returns {Promise<any>} An object containing the route handler result and wire services (if any).
|
|
252
256
|
* @throws Throws errors like MissingSessionError or ForbiddenError on validation failures.
|
|
253
257
|
*/
|
|
254
258
|
const executeRoute = async (
|
|
255
259
|
services: {
|
|
256
260
|
singletonServices: any
|
|
257
|
-
|
|
261
|
+
createWireServices?: any
|
|
258
262
|
skipUserSession: boolean
|
|
259
263
|
requestId: string
|
|
260
264
|
},
|
|
@@ -269,22 +273,18 @@ const executeRoute = async (
|
|
|
269
273
|
coerceDataFromSchema: boolean
|
|
270
274
|
}
|
|
271
275
|
) => {
|
|
272
|
-
const userSession = new
|
|
276
|
+
const userSession = new PikkuSessionService<CoreUserSession>()
|
|
273
277
|
const { params, route, meta } = matchedRoute
|
|
274
|
-
const {
|
|
275
|
-
|
|
276
|
-
createSessionServices,
|
|
277
|
-
skipUserSession,
|
|
278
|
-
requestId,
|
|
279
|
-
} = services
|
|
280
|
-
|
|
281
|
-
const requiresSession = route.auth !== false
|
|
282
|
-
let sessionServices: any
|
|
283
|
-
let result: any
|
|
278
|
+
const { singletonServices, createWireServices, skipUserSession, requestId } =
|
|
279
|
+
services
|
|
284
280
|
|
|
285
281
|
// Attach URL parameters to the request object
|
|
286
282
|
http?.request?.setParams(params)
|
|
287
283
|
|
|
284
|
+
const requiresSession = route.auth !== false
|
|
285
|
+
let wireServices: any
|
|
286
|
+
let result: any
|
|
287
|
+
|
|
288
288
|
singletonServices.logger.info(
|
|
289
289
|
`Matched route: ${route.route} | method: ${route.method.toUpperCase()} | auth: ${requiresSession.toString()}`
|
|
290
290
|
)
|
|
@@ -324,38 +324,28 @@ const executeRoute = async (
|
|
|
324
324
|
}
|
|
325
325
|
}
|
|
326
326
|
|
|
327
|
-
const
|
|
328
|
-
|
|
329
|
-
const getAllServices = async (session?: CoreUserSession) => {
|
|
330
|
-
// Create session-specific services for handling the request
|
|
331
|
-
sessionServices = await createSessionServices(
|
|
332
|
-
{ ...singletonServices, userSession, channel },
|
|
333
|
-
{ http },
|
|
334
|
-
session
|
|
335
|
-
)
|
|
327
|
+
const wire: PikkuWire = { http, channel, session: userSession }
|
|
336
328
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
channel,
|
|
344
|
-
},
|
|
345
|
-
interaction,
|
|
346
|
-
route.auth
|
|
329
|
+
if (matchedRoute.meta.workflow === true) {
|
|
330
|
+
await startWorkflowByHttpWire(
|
|
331
|
+
singletonServices,
|
|
332
|
+
createWireServices,
|
|
333
|
+
matchedRoute,
|
|
334
|
+
wire
|
|
347
335
|
)
|
|
336
|
+
return wireServices
|
|
337
|
+
? { wireServices, result: http.response }
|
|
338
|
+
: { result: http.response }
|
|
348
339
|
}
|
|
349
340
|
|
|
350
341
|
result = await runPikkuFunc(
|
|
351
|
-
|
|
342
|
+
'http',
|
|
352
343
|
`${meta.method}:${meta.route}`,
|
|
353
344
|
meta.pikkuFuncName,
|
|
354
345
|
{
|
|
355
346
|
singletonServices,
|
|
356
|
-
|
|
347
|
+
createWireServices,
|
|
357
348
|
auth: route.auth !== false,
|
|
358
|
-
userSession,
|
|
359
349
|
data,
|
|
360
350
|
inheritedMiddleware: meta.middleware,
|
|
361
351
|
wireMiddleware: route.middleware,
|
|
@@ -363,7 +353,7 @@ const executeRoute = async (
|
|
|
363
353
|
wirePermissions: route.permissions,
|
|
364
354
|
coerceDataFromSchema: options.coerceDataFromSchema,
|
|
365
355
|
tags: route.tags,
|
|
366
|
-
|
|
356
|
+
wire,
|
|
367
357
|
}
|
|
368
358
|
)
|
|
369
359
|
|
|
@@ -378,7 +368,7 @@ const executeRoute = async (
|
|
|
378
368
|
// TODO: Evaluate if the response stream should be explicitly ended.
|
|
379
369
|
// http?.response?.end()
|
|
380
370
|
|
|
381
|
-
return
|
|
371
|
+
return wireServices ? { result, wireServices } : { result }
|
|
382
372
|
}
|
|
383
373
|
|
|
384
374
|
/**
|
|
@@ -431,11 +421,11 @@ export const pikkuFetch = async <In, Out>(
|
|
|
431
421
|
* middleware execution, error handling, and session service cleanup.
|
|
432
422
|
*
|
|
433
423
|
* This function does the following:
|
|
434
|
-
* - Wraps the incoming request and response into an HTTP
|
|
424
|
+
* - Wraps the incoming request and response into an HTTP wire object.
|
|
435
425
|
* - Determines the correct route based on HTTP method and path.
|
|
436
426
|
* - Executes middleware and the route handler.
|
|
437
427
|
* - Catches and handles errors, optionally bubbling them if configured.
|
|
438
|
-
* - Cleans up any
|
|
428
|
+
* - Cleans up any wire services created during processing.
|
|
439
429
|
*
|
|
440
430
|
* @template In Expected input data type.
|
|
441
431
|
* @template Out Expected output data type.
|
|
@@ -449,7 +439,7 @@ export const fetchData = async <In, Out>(
|
|
|
449
439
|
response: PikkuHTTPResponse,
|
|
450
440
|
{
|
|
451
441
|
singletonServices,
|
|
452
|
-
|
|
442
|
+
createWireServices,
|
|
453
443
|
skipUserSession = false,
|
|
454
444
|
respondWith404 = true,
|
|
455
445
|
logWarningsForStatusCodes = [],
|
|
@@ -462,11 +452,11 @@ export const fetchData = async <In, Out>(
|
|
|
462
452
|
(request as any).getHeader?.('x-request-id') ||
|
|
463
453
|
generateRequestId?.() ||
|
|
464
454
|
createWeakUID()
|
|
465
|
-
let
|
|
455
|
+
let wireServices: WireServices<typeof singletonServices> | undefined
|
|
466
456
|
let result: Out
|
|
467
457
|
|
|
468
|
-
// Combine the request and response into one
|
|
469
|
-
const http =
|
|
458
|
+
// Combine the request and response into one wire object
|
|
459
|
+
const http = createHTTPWire(
|
|
470
460
|
request instanceof Request ? new PikkuFetchHTTPRequest(request) : request,
|
|
471
461
|
response
|
|
472
462
|
)
|
|
@@ -487,10 +477,10 @@ export const fetchData = async <In, Out>(
|
|
|
487
477
|
}
|
|
488
478
|
|
|
489
479
|
// Execute the matched route along with its middleware and session management
|
|
490
|
-
;({ result,
|
|
480
|
+
;({ result, wireServices } = await executeRoute(
|
|
491
481
|
{
|
|
492
482
|
singletonServices,
|
|
493
|
-
|
|
483
|
+
createWireServices,
|
|
494
484
|
skipUserSession,
|
|
495
485
|
requestId,
|
|
496
486
|
},
|
|
@@ -513,8 +503,8 @@ export const fetchData = async <In, Out>(
|
|
|
513
503
|
)
|
|
514
504
|
} finally {
|
|
515
505
|
// Clean up any session-specific services created during processing
|
|
516
|
-
if (
|
|
517
|
-
await
|
|
506
|
+
if (wireServices) {
|
|
507
|
+
await closeWireServices(singletonServices.logger, wireServices)
|
|
518
508
|
}
|
|
519
509
|
}
|
|
520
510
|
}
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import type { SerializeOptions } from 'cookie'
|
|
2
2
|
import type { PikkuError } from '../../errors/error-handler.js'
|
|
3
3
|
import type {
|
|
4
|
-
PikkuDocs,
|
|
5
4
|
CoreServices,
|
|
6
5
|
CoreSingletonServices,
|
|
7
6
|
CoreUserSession,
|
|
8
|
-
|
|
7
|
+
CreateWireServices,
|
|
9
8
|
CorePikkuMiddleware,
|
|
10
|
-
|
|
11
|
-
PermissionMetadata,
|
|
9
|
+
CommonWireMeta,
|
|
12
10
|
} from '../../types/core.types.js'
|
|
13
11
|
import type {
|
|
14
12
|
CorePikkuFunction,
|
|
@@ -46,7 +44,7 @@ export type RunHTTPWiringOptions = Partial<{
|
|
|
46
44
|
|
|
47
45
|
export type RunHTTPWiringParams = {
|
|
48
46
|
singletonServices: CoreSingletonServices
|
|
49
|
-
|
|
47
|
+
createWireServices: CreateWireServices<
|
|
50
48
|
CoreSingletonServices,
|
|
51
49
|
CoreServices<CoreSingletonServices>,
|
|
52
50
|
CoreUserSession
|
|
@@ -83,7 +81,7 @@ export type CoreHTTPFunction = {
|
|
|
83
81
|
}>
|
|
84
82
|
}
|
|
85
83
|
/**
|
|
86
|
-
* Represents a http
|
|
84
|
+
* Represents a http wire within Pikku, including a request and response.
|
|
87
85
|
*/
|
|
88
86
|
export interface PikkuHTTP<In = unknown> {
|
|
89
87
|
request?: PikkuHTTPRequest<In>
|
|
@@ -123,14 +121,12 @@ export type CoreHTTPFunctionWiring<
|
|
|
123
121
|
In,
|
|
124
122
|
Out,
|
|
125
123
|
any,
|
|
126
|
-
any,
|
|
127
124
|
any
|
|
128
125
|
> = CorePikkuFunction<In, Out>,
|
|
129
126
|
PikkuFunctionSessionless extends CorePikkuFunctionSessionless<
|
|
130
127
|
In,
|
|
131
128
|
Out,
|
|
132
129
|
any,
|
|
133
|
-
any,
|
|
134
130
|
any
|
|
135
131
|
> = CorePikkuFunctionSessionless<In, Out>,
|
|
136
132
|
PikkuPermission extends CorePikkuPermission<
|
|
@@ -229,6 +225,19 @@ export type CoreHTTPFunctionWiring<
|
|
|
229
225
|
middleware?: PikkuMiddleware[]
|
|
230
226
|
sse?: undefined
|
|
231
227
|
})
|
|
228
|
+
| {
|
|
229
|
+
/** Route triggers a workflow matched by route/method from workflow wires.http */
|
|
230
|
+
route: R
|
|
231
|
+
method: HTTPMethod
|
|
232
|
+
workflow: true
|
|
233
|
+
func?: undefined
|
|
234
|
+
permissions?: undefined
|
|
235
|
+
auth?: undefined
|
|
236
|
+
tags?: undefined
|
|
237
|
+
middleware?: undefined
|
|
238
|
+
returnsJSON?: undefined
|
|
239
|
+
sse?: boolean
|
|
240
|
+
}
|
|
232
241
|
|
|
233
242
|
/**
|
|
234
243
|
* Represents the input types for HTTP wiring metadata, including parameters, query, and body types.
|
|
@@ -242,18 +251,14 @@ export type HTTPFunctionMetaInputTypes = {
|
|
|
242
251
|
/**
|
|
243
252
|
* Represents metadata for a set of HTTP wirings, including HTTP wiring details, methods, input/output types, and documentation.
|
|
244
253
|
*/
|
|
245
|
-
export type HTTPWiringMeta = {
|
|
246
|
-
pikkuFuncName: string
|
|
254
|
+
export type HTTPWiringMeta = CommonWireMeta & {
|
|
247
255
|
route: string
|
|
248
256
|
method: HTTPMethod
|
|
249
257
|
params?: string[]
|
|
250
258
|
query?: string[]
|
|
251
259
|
inputTypes?: HTTPFunctionMetaInputTypes
|
|
252
|
-
docs?: PikkuDocs
|
|
253
|
-
tags?: string[]
|
|
254
260
|
sse?: true
|
|
255
|
-
|
|
256
|
-
permissions?: PermissionMetadata[] // Pre-resolved permission chain (global + route + tag + explicit)
|
|
261
|
+
workflow?: true
|
|
257
262
|
}
|
|
258
263
|
export type HTTPWiringsMeta = Record<HTTPMethod, Record<string, HTTPWiringMeta>>
|
|
259
264
|
|
|
@@ -6,7 +6,7 @@ import { Logger } from '../../services/index.js'
|
|
|
6
6
|
* @param logger - A logger for logging information.
|
|
7
7
|
*/
|
|
8
8
|
export const logRoutes = (logger: Logger) => {
|
|
9
|
-
const routesByType = pikkuState('http', 'routes')
|
|
9
|
+
const routesByType = pikkuState(null, 'http', 'routes')
|
|
10
10
|
if (routesByType.size === 0) {
|
|
11
11
|
logger.info('No routes added')
|
|
12
12
|
return
|