@pikku/core 0.11.1 → 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 +24 -0
- package/dist/errors/error-handler.js +3 -3
- package/dist/function/function-runner.d.ts +4 -3
- package/dist/function/function-runner.js +60 -14
- package/dist/function/functions.types.d.ts +84 -5
- package/dist/function/functions.types.js +41 -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-bearer.d.ts +1 -1
- package/dist/middleware/auth-cookie.d.ts +1 -1
- package/dist/middleware/timeout.d.ts +1 -1
- package/dist/middleware-runner.d.ts +3 -14
- package/dist/middleware-runner.js +8 -8
- package/dist/permissions.d.ts +3 -86
- package/dist/permissions.js +11 -67
- 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/workflow-service.d.ts +38 -0
- package/dist/services/workflow-service.js +1 -0
- package/dist/types/core.types.d.ts +12 -4
- package/dist/types/core.types.js +1 -1
- package/dist/types/state.types.d.ts +135 -0
- package/dist/types/state.types.js +1 -0
- package/dist/utils.d.ts +8 -0
- package/dist/utils.js +45 -0
- package/dist/wirings/channel/channel-handler.js +1 -1
- package/dist/wirings/channel/channel-runner.js +5 -5
- package/dist/wirings/channel/log-channels.js +1 -1
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +2 -2
- package/dist/wirings/cli/channel/cli-channel-runner.js +3 -2
- package/dist/wirings/cli/cli-runner.js +10 -10
- package/dist/wirings/cli/cli.types.d.ts +1 -0
- 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 +2 -2
- package/dist/wirings/http/http-runner.js +21 -12
- package/dist/wirings/http/http.types.d.ts +14 -1
- 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.js +21 -21
- package/dist/wirings/queue/queue-runner.js +6 -6
- 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 +7 -8
- package/dist/wirings/rpc/rpc-runner.js +62 -14
- 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.js +5 -5
- 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 -12
- package/dist/wirings/workflow/index.js +6 -11
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +96 -6
- package/dist/wirings/workflow/pikku-workflow-service.js +230 -103
- 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 +133 -211
- package/package.json +10 -1
- package/src/errors/error-handler.ts +3 -3
- package/src/function/function-runner.test.ts +1 -1
- package/src/function/function-runner.ts +86 -16
- package/src/function/functions.types.ts +126 -4
- package/src/index.ts +10 -5
- package/src/middleware-runner.ts +16 -9
- package/src/permissions.test.ts +28 -86
- package/src/permissions.ts +21 -80
- package/src/pikku-state.ts +156 -201
- package/src/schema.ts +42 -13
- package/src/services/workflow-service.ts +74 -0
- package/src/types/core.types.ts +12 -3
- package/src/types/state.types.ts +195 -0
- package/src/utils.ts +55 -0
- package/src/wirings/channel/channel-handler.ts +1 -1
- package/src/wirings/channel/channel-runner.ts +5 -5
- package/src/wirings/channel/local/local-channel-runner.test.ts +3 -1
- package/src/wirings/channel/log-channels.ts +1 -1
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +2 -2
- package/src/wirings/cli/channel/cli-channel-runner.ts +4 -3
- package/src/wirings/cli/cli-runner.test.ts +19 -19
- package/src/wirings/cli/cli-runner.ts +10 -9
- package/src/wirings/cli/cli.types.ts +1 -0
- 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 +2 -2
- package/src/wirings/http/http-runner.ts +30 -13
- package/src/wirings/http/http.types.ts +14 -0
- 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 +21 -21
- package/src/wirings/queue/queue-runner.test.ts +19 -19
- package/src/wirings/queue/queue-runner.ts +6 -6
- package/src/wirings/rpc/index.ts +1 -1
- package/src/wirings/rpc/rpc-runner.ts +88 -22
- 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 +27 -27
- package/src/wirings/scheduler/scheduler-runner.ts +5 -5
- 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 +53 -26
- package/src/wirings/workflow/pikku-workflow-service.ts +333 -117
- 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 +166 -277
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/wirings/workflow/workflow-runner.d.ts +0 -34
- package/dist/wirings/workflow/workflow-runner.js +0 -65
- package/src/function/function-runner.ts.bak +0 -188
- package/src/wirings/workflow/workflow-runner.ts +0 -72
|
@@ -57,7 +57,7 @@ export const wireCLI = <
|
|
|
57
57
|
cli: CoreCLI<Commands, GlobalOptions, PikkuMiddleware, GlobalOutput>
|
|
58
58
|
) => {
|
|
59
59
|
// Get the existing metadata that was generated during inspection
|
|
60
|
-
const cliMeta = pikkuState('cli', 'meta') || {}
|
|
60
|
+
const cliMeta = pikkuState(null, 'cli', 'meta') || {}
|
|
61
61
|
|
|
62
62
|
if (!cliMeta.programs?.[cli.program]) {
|
|
63
63
|
throw new Error(
|
|
@@ -67,7 +67,7 @@ export const wireCLI = <
|
|
|
67
67
|
|
|
68
68
|
// Get existing programs state and add this program
|
|
69
69
|
const programs: Record<string, CLIProgramState> =
|
|
70
|
-
pikkuState('cli', 'programs') || {}
|
|
70
|
+
pikkuState(null, 'cli', 'programs') || {}
|
|
71
71
|
programs[cli.program] = {
|
|
72
72
|
defaultRenderer: (cli.render ||
|
|
73
73
|
defaultJSONRenderer) as CorePikkuCLIRender<any>,
|
|
@@ -75,7 +75,7 @@ export const wireCLI = <
|
|
|
75
75
|
renderers: {},
|
|
76
76
|
tags: cli.tags,
|
|
77
77
|
}
|
|
78
|
-
pikkuState('cli', 'programs', programs)
|
|
78
|
+
pikkuState(null, 'cli', 'programs', programs)
|
|
79
79
|
|
|
80
80
|
// Register all command functions recursively
|
|
81
81
|
registerCLICommands(
|
|
@@ -130,7 +130,7 @@ function registerCLICommands(
|
|
|
130
130
|
program: string
|
|
131
131
|
) {
|
|
132
132
|
// Get the CLI metadata to find actual function names
|
|
133
|
-
const cliMeta = pikkuState('cli', 'meta').programs[program]
|
|
133
|
+
const cliMeta = pikkuState(null, 'cli', 'meta').programs[program]
|
|
134
134
|
|
|
135
135
|
for (const [name, command] of Object.entries(commands)) {
|
|
136
136
|
const fullPath = [...path, name]
|
|
@@ -166,6 +166,7 @@ function registerCLICommands(
|
|
|
166
166
|
|
|
167
167
|
// Store the options and middleware in program state for use during execution
|
|
168
168
|
const programs: Record<string, CLIProgramState> = pikkuState(
|
|
169
|
+
null,
|
|
169
170
|
'cli',
|
|
170
171
|
'programs'
|
|
171
172
|
)
|
|
@@ -208,10 +209,10 @@ function pluckCLIData(
|
|
|
208
209
|
funcName: string,
|
|
209
210
|
availableOptions: Record<string, CLIOption>
|
|
210
211
|
): Record<string, any> {
|
|
211
|
-
const funcMeta = pikkuState('function', 'meta')[funcName]
|
|
212
|
+
const funcMeta = pikkuState(null, 'function', 'meta')[funcName]
|
|
212
213
|
const schemaName = funcMeta?.inputSchemaName
|
|
213
214
|
const schema = schemaName
|
|
214
|
-
? pikkuState('misc', 'schemas').get(schemaName)
|
|
215
|
+
? pikkuState(null, 'misc', 'schemas').get(schemaName)
|
|
215
216
|
: null
|
|
216
217
|
|
|
217
218
|
if (schema && schema.properties) {
|
|
@@ -249,7 +250,7 @@ export async function runCLICommand({
|
|
|
249
250
|
createWireServices?: CreateWireServices
|
|
250
251
|
}): Promise<any> {
|
|
251
252
|
// Get the command metadata to find the function name
|
|
252
|
-
const cliMeta = pikkuState('cli', 'meta')
|
|
253
|
+
const cliMeta = pikkuState(null, 'cli', 'meta')
|
|
253
254
|
const programMeta = cliMeta.programs?.[program]
|
|
254
255
|
if (!programMeta) {
|
|
255
256
|
throw new NotFoundError(`Program not found: ${program}`)
|
|
@@ -275,7 +276,7 @@ export async function runCLICommand({
|
|
|
275
276
|
|
|
276
277
|
// Get program-specific data
|
|
277
278
|
const programs: Record<string, CLIProgramState> =
|
|
278
|
-
pikkuState('cli', 'programs') || {}
|
|
279
|
+
pikkuState(null, 'cli', 'programs') || {}
|
|
279
280
|
const programData = programs[program]
|
|
280
281
|
|
|
281
282
|
// Combine program middleware + command middleware from the hierarchy
|
|
@@ -406,7 +407,7 @@ export async function executeCLI({
|
|
|
406
407
|
|
|
407
408
|
try {
|
|
408
409
|
// Get CLI metadata from state
|
|
409
|
-
const allCLIMeta = pikkuState('cli', 'meta') as unknown as
|
|
410
|
+
const allCLIMeta = pikkuState(null, 'cli', 'meta') as unknown as
|
|
410
411
|
| CLIMeta
|
|
411
412
|
| undefined
|
|
412
413
|
if (!allCLIMeta) {
|
|
@@ -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'
|
|
@@ -17,13 +17,13 @@ const sessionMiddleware: CorePikkuMiddleware = async (services, wire, 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',
|
|
@@ -36,6 +36,7 @@ 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
38
|
import { httpRouter } from './routers/http-router.js'
|
|
39
|
+
import { startWorkflowByHttpWire } from '../workflow/workflow-utils.js'
|
|
39
40
|
|
|
40
41
|
/**
|
|
41
42
|
* Registers HTTP middleware for a specific route pattern.
|
|
@@ -68,9 +69,10 @@ import { httpRouter } from './routers/http-router.js'
|
|
|
68
69
|
*/
|
|
69
70
|
export const addHTTPMiddleware = <PikkuMiddleware extends CorePikkuMiddleware>(
|
|
70
71
|
pattern: string,
|
|
71
|
-
middleware: CorePikkuMiddlewareGroup
|
|
72
|
+
middleware: CorePikkuMiddlewareGroup,
|
|
73
|
+
packageName: string | null = null
|
|
72
74
|
): CorePikkuMiddlewareGroup => {
|
|
73
|
-
const httpGroups = pikkuState('middleware', 'httpGroup')
|
|
75
|
+
const httpGroups = pikkuState(packageName, 'middleware', 'httpGroup')
|
|
74
76
|
httpGroups[pattern] = middleware
|
|
75
77
|
return middleware
|
|
76
78
|
}
|
|
@@ -106,9 +108,10 @@ export const addHTTPMiddleware = <PikkuMiddleware extends CorePikkuMiddleware>(
|
|
|
106
108
|
*/
|
|
107
109
|
export const addHTTPPermission = <PikkuPermission extends CorePikkuPermission>(
|
|
108
110
|
pattern: string,
|
|
109
|
-
permissions: CorePermissionGroup | CorePikkuPermission[]
|
|
111
|
+
permissions: CorePermissionGroup | CorePikkuPermission[],
|
|
112
|
+
packageName: string | null = null
|
|
110
113
|
): CorePermissionGroup | CorePikkuPermission[] => {
|
|
111
|
-
const httpGroups = pikkuState('permissions', 'httpGroup')
|
|
114
|
+
const httpGroups = pikkuState(packageName, 'permissions', 'httpGroup')
|
|
112
115
|
httpGroups[pattern] = permissions
|
|
113
116
|
return permissions
|
|
114
117
|
}
|
|
@@ -151,17 +154,19 @@ export const wireHTTP = <
|
|
|
151
154
|
PikkuMiddleware
|
|
152
155
|
>
|
|
153
156
|
) => {
|
|
154
|
-
const httpMeta = pikkuState('http', 'meta')
|
|
157
|
+
const httpMeta = pikkuState(null, 'http', 'meta')
|
|
155
158
|
const routeMeta = httpMeta[httpWiring.method][httpWiring.route]
|
|
156
159
|
if (!routeMeta) {
|
|
157
160
|
throw new Error('Route metadata not found')
|
|
158
161
|
}
|
|
159
|
-
|
|
160
|
-
|
|
162
|
+
if (httpWiring.func) {
|
|
163
|
+
addFunction(routeMeta.pikkuFuncName, httpWiring.func)
|
|
164
|
+
}
|
|
165
|
+
const routes = pikkuState(null, 'http', 'routes')
|
|
161
166
|
if (!routes.has(httpWiring.method)) {
|
|
162
167
|
routes.set(httpWiring.method, new Map())
|
|
163
168
|
}
|
|
164
|
-
pikkuState('http', 'routes')
|
|
169
|
+
pikkuState(null, 'http', 'routes')
|
|
165
170
|
.get(httpWiring.method)
|
|
166
171
|
?.set(httpWiring.route, httpWiring as any)
|
|
167
172
|
}
|
|
@@ -184,10 +189,10 @@ const getMatchingRoute = (requestType: string, requestPath: string) => {
|
|
|
184
189
|
)
|
|
185
190
|
|
|
186
191
|
if (matchedPath) {
|
|
187
|
-
const route = pikkuState('http', 'routes')
|
|
192
|
+
const route = pikkuState(null, 'http', 'routes')
|
|
188
193
|
.get(requestType.toLowerCase() as HTTPMethod)!
|
|
189
194
|
.get(matchedPath.route)!
|
|
190
|
-
const meta = pikkuState('http', 'meta')[
|
|
195
|
+
const meta = pikkuState(null, 'http', 'meta')[
|
|
191
196
|
requestType.toLowerCase() as PikkuWiringTypes
|
|
192
197
|
][route.route]
|
|
193
198
|
|
|
@@ -273,13 +278,13 @@ const executeRoute = async (
|
|
|
273
278
|
const { singletonServices, createWireServices, skipUserSession, requestId } =
|
|
274
279
|
services
|
|
275
280
|
|
|
281
|
+
// Attach URL parameters to the request object
|
|
282
|
+
http?.request?.setParams(params)
|
|
283
|
+
|
|
276
284
|
const requiresSession = route.auth !== false
|
|
277
285
|
let wireServices: any
|
|
278
286
|
let result: any
|
|
279
287
|
|
|
280
|
-
// Attach URL parameters to the request object
|
|
281
|
-
http?.request?.setParams(params)
|
|
282
|
-
|
|
283
288
|
singletonServices.logger.info(
|
|
284
289
|
`Matched route: ${route.route} | method: ${route.method.toUpperCase()} | auth: ${requiresSession.toString()}`
|
|
285
290
|
)
|
|
@@ -321,6 +326,18 @@ const executeRoute = async (
|
|
|
321
326
|
|
|
322
327
|
const wire: PikkuWire = { http, channel, session: userSession }
|
|
323
328
|
|
|
329
|
+
if (matchedRoute.meta.workflow === true) {
|
|
330
|
+
await startWorkflowByHttpWire(
|
|
331
|
+
singletonServices,
|
|
332
|
+
createWireServices,
|
|
333
|
+
matchedRoute,
|
|
334
|
+
wire
|
|
335
|
+
)
|
|
336
|
+
return wireServices
|
|
337
|
+
? { wireServices, result: http.response }
|
|
338
|
+
: { result: http.response }
|
|
339
|
+
}
|
|
340
|
+
|
|
324
341
|
result = await runPikkuFunc(
|
|
325
342
|
'http',
|
|
326
343
|
`${meta.method}:${meta.route}`,
|
|
@@ -225,6 +225,19 @@ export type CoreHTTPFunctionWiring<
|
|
|
225
225
|
middleware?: PikkuMiddleware[]
|
|
226
226
|
sse?: undefined
|
|
227
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
|
+
}
|
|
228
241
|
|
|
229
242
|
/**
|
|
230
243
|
* Represents the input types for HTTP wiring metadata, including parameters, query, and body types.
|
|
@@ -245,6 +258,7 @@ export type HTTPWiringMeta = CommonWireMeta & {
|
|
|
245
258
|
query?: string[]
|
|
246
259
|
inputTypes?: HTTPFunctionMetaInputTypes
|
|
247
260
|
sse?: true
|
|
261
|
+
workflow?: true
|
|
248
262
|
}
|
|
249
263
|
export type HTTPWiringsMeta = Record<HTTPMethod, Record<string, HTTPWiringMeta>>
|
|
250
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
|
|
@@ -23,6 +23,7 @@ describe('PathToRegexRouter', () => {
|
|
|
23
23
|
test('should correctly identify static routes', () => {
|
|
24
24
|
// Setup test routes
|
|
25
25
|
pikkuState(
|
|
26
|
+
null,
|
|
26
27
|
'http',
|
|
27
28
|
'routes',
|
|
28
29
|
new Map([
|
|
@@ -36,8 +37,8 @@ describe('PathToRegexRouter', () => {
|
|
|
36
37
|
],
|
|
37
38
|
])
|
|
38
39
|
)
|
|
39
|
-
pikkuState('http', 'middleware', new Map())
|
|
40
|
-
pikkuState('channel', 'channels', new Map())
|
|
40
|
+
pikkuState(null, 'http', 'middleware', new Map())
|
|
41
|
+
pikkuState(null, 'channel', 'channels', new Map())
|
|
41
42
|
|
|
42
43
|
router.initialize()
|
|
43
44
|
|
|
@@ -56,6 +57,7 @@ describe('PathToRegexRouter', () => {
|
|
|
56
57
|
test('should handle dynamic routes with parameters', () => {
|
|
57
58
|
// Setup test routes with parameters
|
|
58
59
|
pikkuState(
|
|
60
|
+
null,
|
|
59
61
|
'http',
|
|
60
62
|
'routes',
|
|
61
63
|
new Map([
|
|
@@ -71,8 +73,8 @@ describe('PathToRegexRouter', () => {
|
|
|
71
73
|
],
|
|
72
74
|
])
|
|
73
75
|
)
|
|
74
|
-
pikkuState('http', 'middleware', new Map())
|
|
75
|
-
pikkuState('channel', 'channels', new Map())
|
|
76
|
+
pikkuState(null, 'http', 'middleware', new Map())
|
|
77
|
+
pikkuState(null, 'channel', 'channels', new Map())
|
|
76
78
|
|
|
77
79
|
router.initialize()
|
|
78
80
|
|
|
@@ -98,6 +100,7 @@ describe('PathToRegexRouter', () => {
|
|
|
98
100
|
test('should handle multi-parameter routes', () => {
|
|
99
101
|
// Setup routes with multiple parameters
|
|
100
102
|
pikkuState(
|
|
103
|
+
null,
|
|
101
104
|
'http',
|
|
102
105
|
'routes',
|
|
103
106
|
new Map([
|
|
@@ -116,8 +119,8 @@ describe('PathToRegexRouter', () => {
|
|
|
116
119
|
],
|
|
117
120
|
])
|
|
118
121
|
)
|
|
119
|
-
pikkuState('http', 'middleware', new Map())
|
|
120
|
-
pikkuState('channel', 'channels', new Map())
|
|
122
|
+
pikkuState(null, 'http', 'middleware', new Map())
|
|
123
|
+
pikkuState(null, 'channel', 'channels', new Map())
|
|
121
124
|
|
|
122
125
|
router.initialize()
|
|
123
126
|
|
|
@@ -139,6 +142,7 @@ describe('PathToRegexRouter', () => {
|
|
|
139
142
|
test('should prioritize static routes over dynamic routes for performance', () => {
|
|
140
143
|
// Setup mixed routes where static could conflict with dynamic
|
|
141
144
|
pikkuState(
|
|
145
|
+
null,
|
|
142
146
|
'http',
|
|
143
147
|
'routes',
|
|
144
148
|
new Map([
|
|
@@ -151,8 +155,8 @@ describe('PathToRegexRouter', () => {
|
|
|
151
155
|
],
|
|
152
156
|
])
|
|
153
157
|
)
|
|
154
|
-
pikkuState('http', 'middleware', new Map())
|
|
155
|
-
pikkuState('channel', 'channels', new Map())
|
|
158
|
+
pikkuState(null, 'http', 'middleware', new Map())
|
|
159
|
+
pikkuState(null, 'channel', 'channels', new Map())
|
|
156
160
|
|
|
157
161
|
router.initialize()
|
|
158
162
|
|
|
@@ -167,6 +171,7 @@ describe('PathToRegexRouter', () => {
|
|
|
167
171
|
describe('Path Normalization', () => {
|
|
168
172
|
test('should normalize paths without leading slash', () => {
|
|
169
173
|
pikkuState(
|
|
174
|
+
null,
|
|
170
175
|
'http',
|
|
171
176
|
'routes',
|
|
172
177
|
new Map([
|
|
@@ -179,8 +184,8 @@ describe('PathToRegexRouter', () => {
|
|
|
179
184
|
],
|
|
180
185
|
])
|
|
181
186
|
)
|
|
182
|
-
pikkuState('http', 'middleware', new Map())
|
|
183
|
-
pikkuState('channel', 'channels', new Map())
|
|
187
|
+
pikkuState(null, 'http', 'middleware', new Map())
|
|
188
|
+
pikkuState(null, 'channel', 'channels', new Map())
|
|
184
189
|
|
|
185
190
|
router.initialize()
|
|
186
191
|
|
|
@@ -201,9 +206,10 @@ describe('PathToRegexRouter', () => {
|
|
|
201
206
|
|
|
202
207
|
describe('Channel Routes Integration', () => {
|
|
203
208
|
test('should handle channel routes as GET routes', () => {
|
|
204
|
-
pikkuState('http', 'routes', new Map())
|
|
205
|
-
pikkuState('http', 'middleware', new Map())
|
|
209
|
+
pikkuState(null, 'http', 'routes', new Map())
|
|
210
|
+
pikkuState(null, 'http', 'middleware', new Map())
|
|
206
211
|
pikkuState(
|
|
212
|
+
null,
|
|
207
213
|
'channel',
|
|
208
214
|
'channels',
|
|
209
215
|
new Map([
|
|
@@ -233,11 +239,13 @@ describe('PathToRegexRouter', () => {
|
|
|
233
239
|
const routeMiddleware = [async () => {}]
|
|
234
240
|
|
|
235
241
|
pikkuState(
|
|
242
|
+
null,
|
|
236
243
|
'http',
|
|
237
244
|
'routes',
|
|
238
245
|
new Map([['get', new Map([['/api/test', mockRoute('/api/test')]])]])
|
|
239
246
|
)
|
|
240
247
|
pikkuState(
|
|
248
|
+
null,
|
|
241
249
|
'http',
|
|
242
250
|
'middleware',
|
|
243
251
|
new Map([
|
|
@@ -245,7 +253,7 @@ describe('PathToRegexRouter', () => {
|
|
|
245
253
|
['/api/test', routeMiddleware],
|
|
246
254
|
])
|
|
247
255
|
)
|
|
248
|
-
pikkuState('channel', 'channels', new Map())
|
|
256
|
+
pikkuState(null, 'channel', 'channels', new Map())
|
|
249
257
|
|
|
250
258
|
router.initialize()
|
|
251
259
|
|
|
@@ -260,12 +268,13 @@ describe('PathToRegexRouter', () => {
|
|
|
260
268
|
describe('No Match Scenarios', () => {
|
|
261
269
|
test('should return null for non-existent routes', () => {
|
|
262
270
|
pikkuState(
|
|
271
|
+
null,
|
|
263
272
|
'http',
|
|
264
273
|
'routes',
|
|
265
274
|
new Map([['get', new Map([['/existing', mockRoute('/existing')]])]])
|
|
266
275
|
)
|
|
267
|
-
pikkuState('http', 'middleware', new Map())
|
|
268
|
-
pikkuState('channel', 'channels', new Map())
|
|
276
|
+
pikkuState(null, 'http', 'middleware', new Map())
|
|
277
|
+
pikkuState(null, 'channel', 'channels', new Map())
|
|
269
278
|
|
|
270
279
|
router.initialize()
|
|
271
280
|
|
|
@@ -275,12 +284,13 @@ describe('PathToRegexRouter', () => {
|
|
|
275
284
|
|
|
276
285
|
test('should return null for unsupported HTTP methods', () => {
|
|
277
286
|
pikkuState(
|
|
287
|
+
null,
|
|
278
288
|
'http',
|
|
279
289
|
'routes',
|
|
280
290
|
new Map([['get', new Map([['/test', mockRoute('/test')]])]])
|
|
281
291
|
)
|
|
282
|
-
pikkuState('http', 'middleware', new Map())
|
|
283
|
-
pikkuState('channel', 'channels', new Map())
|
|
292
|
+
pikkuState(null, 'http', 'middleware', new Map())
|
|
293
|
+
pikkuState(null, 'channel', 'channels', new Map())
|
|
284
294
|
|
|
285
295
|
router.initialize()
|
|
286
296
|
|
|
@@ -292,12 +302,13 @@ describe('PathToRegexRouter', () => {
|
|
|
292
302
|
describe('Lazy Initialization', () => {
|
|
293
303
|
test('should initialize automatically on first match call', () => {
|
|
294
304
|
pikkuState(
|
|
305
|
+
null,
|
|
295
306
|
'http',
|
|
296
307
|
'routes',
|
|
297
308
|
new Map([['get', new Map([['/test', mockRoute('/test')]])]])
|
|
298
309
|
)
|
|
299
|
-
pikkuState('http', 'middleware', new Map())
|
|
300
|
-
pikkuState('channel', 'channels', new Map())
|
|
310
|
+
pikkuState(null, 'http', 'middleware', new Map())
|
|
311
|
+
pikkuState(null, 'channel', 'channels', new Map())
|
|
301
312
|
|
|
302
313
|
// Don't call initialize manually
|
|
303
314
|
const result = router.match('get', '/test')
|
|
@@ -25,8 +25,8 @@ export class PathToRegexRouter implements Router {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
public initialize() {
|
|
28
|
-
const routes = pikkuState('http', 'routes')
|
|
29
|
-
const channelRoutes = pikkuState('channel', 'channels')
|
|
28
|
+
const routes = pikkuState(null, 'http', 'routes')
|
|
29
|
+
const channelRoutes = pikkuState(null, 'channel', 'channels')
|
|
30
30
|
|
|
31
31
|
// Helper function to compile routes for a given method
|
|
32
32
|
const compileRoutesForMethod = (
|