@pikku/core 0.12.2 → 0.12.3

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.
Files changed (131) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/crypto-utils.d.ts +10 -0
  3. package/dist/crypto-utils.js +62 -0
  4. package/dist/function/function-runner.js +4 -4
  5. package/dist/function/functions.types.d.ts +26 -1
  6. package/dist/function/functions.types.js +16 -0
  7. package/dist/handle-error.d.ts +1 -1
  8. package/dist/handle-error.js +7 -3
  9. package/dist/index.d.ts +14 -2
  10. package/dist/index.js +1 -1
  11. package/dist/pikku-state.js +3 -1
  12. package/dist/schema.js +1 -1
  13. package/dist/services/in-memory-workflow-service.d.ts +8 -2
  14. package/dist/services/in-memory-workflow-service.js +28 -1
  15. package/dist/services/workflow-service.d.ts +8 -2
  16. package/dist/testing/index.d.ts +2 -0
  17. package/dist/testing/index.js +1 -0
  18. package/dist/testing/service-tests.d.ts +31 -0
  19. package/dist/testing/service-tests.js +598 -0
  20. package/dist/types/core.types.d.ts +9 -1
  21. package/dist/types/state.types.d.ts +4 -2
  22. package/dist/utils/hash.d.ts +2 -0
  23. package/dist/utils/hash.js +23 -0
  24. package/dist/wirings/ai-agent/agent-dynamic-workflow.d.ts +6 -0
  25. package/dist/wirings/ai-agent/agent-dynamic-workflow.js +348 -0
  26. package/dist/wirings/ai-agent/ai-agent-memory.d.ts +1 -1
  27. package/dist/wirings/ai-agent/ai-agent-memory.js +6 -5
  28. package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +10 -7
  29. package/dist/wirings/ai-agent/ai-agent-prepare.js +127 -47
  30. package/dist/wirings/ai-agent/ai-agent-runner.d.ts +4 -0
  31. package/dist/wirings/ai-agent/ai-agent-runner.js +381 -27
  32. package/dist/wirings/ai-agent/ai-agent-stream.d.ts +7 -2
  33. package/dist/wirings/ai-agent/ai-agent-stream.js +109 -46
  34. package/dist/wirings/ai-agent/ai-agent.types.d.ts +22 -1
  35. package/dist/wirings/ai-agent/index.d.ts +1 -2
  36. package/dist/wirings/ai-agent/index.js +1 -2
  37. package/dist/wirings/channel/channel-handler.js +5 -1
  38. package/dist/wirings/channel/channel.types.d.ts +1 -7
  39. package/dist/wirings/channel/local/local-channel-handler.d.ts +1 -1
  40. package/dist/wirings/channel/local/local-channel-handler.js +5 -3
  41. package/dist/wirings/channel/local/local-channel-runner.js +14 -4
  42. package/dist/wirings/channel/serverless/serverless-channel-runner.js +4 -1
  43. package/dist/wirings/cli/cli-runner.js +10 -2
  44. package/dist/wirings/cli/cli.types.d.ts +1 -0
  45. package/dist/wirings/http/http-routes.js +0 -1
  46. package/dist/wirings/http/http-runner.d.ts +1 -1
  47. package/dist/wirings/http/http-runner.js +25 -3
  48. package/dist/wirings/http/http.types.d.ts +3 -11
  49. package/dist/wirings/http/index.d.ts +2 -1
  50. package/dist/wirings/http/index.js +1 -0
  51. package/dist/wirings/http/pikku-fetch-http-request.d.ts +1 -0
  52. package/dist/wirings/http/pikku-fetch-http-request.js +3 -0
  53. package/dist/wirings/http/pikku-fetch-http-response.d.ts +1 -0
  54. package/dist/wirings/http/pikku-fetch-http-response.js +4 -4
  55. package/dist/wirings/http/web-request.d.ts +12 -0
  56. package/dist/wirings/http/web-request.js +85 -0
  57. package/dist/wirings/mcp/mcp-endpoint-registry.js +1 -1
  58. package/dist/wirings/mcp/mcp-runner.js +13 -1
  59. package/dist/wirings/rpc/rpc-runner.d.ts +30 -6
  60. package/dist/wirings/rpc/rpc-runner.js +36 -14
  61. package/dist/wirings/rpc/rpc-types.d.ts +6 -1
  62. package/dist/wirings/rpc/wire-addon.d.ts +1 -0
  63. package/dist/wirings/rpc/wire-addon.js +1 -1
  64. package/dist/wirings/scheduler/scheduler-runner.js +1 -0
  65. package/dist/wirings/workflow/graph/graph-validation.d.ts +3 -0
  66. package/dist/wirings/workflow/graph/graph-validation.js +175 -0
  67. package/dist/wirings/workflow/graph/index.d.ts +1 -0
  68. package/dist/wirings/workflow/graph/index.js +1 -0
  69. package/dist/wirings/workflow/index.d.ts +1 -1
  70. package/dist/wirings/workflow/pikku-workflow-service.d.ts +8 -2
  71. package/dist/wirings/workflow/pikku-workflow-service.js +1 -2
  72. package/dist/wirings/workflow/workflow.types.d.ts +10 -1
  73. package/package.json +4 -2
  74. package/src/crypto-utils.test.ts +99 -1
  75. package/src/crypto-utils.ts +114 -0
  76. package/src/function/function-runner.ts +5 -5
  77. package/src/function/functions.types.ts +38 -1
  78. package/src/handle-error.test.ts +65 -2
  79. package/src/handle-error.ts +8 -4
  80. package/src/index.ts +14 -0
  81. package/src/pikku-state.ts +3 -1
  82. package/src/schema.ts +1 -1
  83. package/src/services/in-memory-workflow-service.ts +45 -2
  84. package/src/services/workflow-service.ts +12 -1
  85. package/src/testing/index.ts +2 -0
  86. package/src/testing/service-tests.ts +873 -0
  87. package/src/types/core.types.ts +9 -1
  88. package/src/types/state.types.ts +4 -2
  89. package/src/utils/hash.test.ts +68 -0
  90. package/src/utils/hash.ts +26 -0
  91. package/src/wirings/ai-agent/agent-dynamic-workflow.ts +469 -0
  92. package/src/wirings/ai-agent/ai-agent-memory.ts +7 -6
  93. package/src/wirings/ai-agent/ai-agent-prepare.ts +175 -61
  94. package/src/wirings/ai-agent/ai-agent-runner.test.ts +3 -1
  95. package/src/wirings/ai-agent/ai-agent-runner.ts +553 -31
  96. package/src/wirings/ai-agent/ai-agent-stream.test.ts +209 -2
  97. package/src/wirings/ai-agent/ai-agent-stream.ts +182 -89
  98. package/src/wirings/ai-agent/ai-agent.types.ts +23 -1
  99. package/src/wirings/ai-agent/index.ts +1 -5
  100. package/src/wirings/channel/channel-handler.ts +11 -2
  101. package/src/wirings/channel/channel.types.ts +1 -7
  102. package/src/wirings/channel/local/local-channel-handler.ts +5 -3
  103. package/src/wirings/channel/local/local-channel-runner.ts +17 -7
  104. package/src/wirings/channel/serverless/serverless-channel-runner.ts +4 -1
  105. package/src/wirings/cli/cli-runner.ts +12 -2
  106. package/src/wirings/cli/cli.types.ts +1 -0
  107. package/src/wirings/http/http-routes.ts +0 -1
  108. package/src/wirings/http/http-runner.ts +35 -10
  109. package/src/wirings/http/http.types.ts +3 -12
  110. package/src/wirings/http/index.ts +3 -0
  111. package/src/wirings/http/pikku-fetch-http-request.ts +4 -0
  112. package/src/wirings/http/pikku-fetch-http-response.ts +4 -4
  113. package/src/wirings/http/web-request.test.ts +236 -0
  114. package/src/wirings/http/web-request.ts +104 -0
  115. package/src/wirings/mcp/mcp-endpoint-registry.ts +1 -1
  116. package/src/wirings/mcp/mcp-runner.ts +30 -12
  117. package/src/wirings/rpc/rpc-runner.ts +45 -24
  118. package/src/wirings/rpc/rpc-types.ts +6 -1
  119. package/src/wirings/rpc/wire-addon.ts +2 -1
  120. package/src/wirings/scheduler/scheduler-runner.ts +1 -0
  121. package/src/wirings/workflow/graph/graph-validation.test.ts +170 -0
  122. package/src/wirings/workflow/graph/graph-validation.ts +237 -0
  123. package/src/wirings/workflow/graph/index.ts +5 -0
  124. package/src/wirings/workflow/index.ts +1 -0
  125. package/src/wirings/workflow/pikku-workflow-service.ts +14 -3
  126. package/src/wirings/workflow/workflow.types.ts +9 -1
  127. package/tsconfig.tsbuildinfo +1 -1
  128. package/dist/wirings/ai-agent/ai-agent-assistant-ui.d.ts +0 -5
  129. package/dist/wirings/ai-agent/ai-agent-assistant-ui.js +0 -168
  130. package/src/wirings/ai-agent/ai-agent-assistant-ui.test.ts +0 -363
  131. package/src/wirings/ai-agent/ai-agent-assistant-ui.ts +0 -238
@@ -69,6 +69,8 @@ export interface AIAgentInput {
69
69
  threadId: string
70
70
  resourceId: string
71
71
  attachments?: AIAgentInputAttachment[]
72
+ model?: string
73
+ temperature?: number
72
74
  }
73
75
 
74
76
  export interface AIAgentOutput {
@@ -78,6 +80,14 @@ export interface AIAgentOutput {
78
80
  threadId: string
79
81
  steps: AIAgentStep[]
80
82
  usage: { inputTokens: number; outputTokens: number }
83
+ status?: 'completed' | 'suspended'
84
+ pendingApprovals?: Array<{
85
+ toolCallId: string
86
+ toolName: string
87
+ args: unknown
88
+ reason?: string
89
+ runId: string
90
+ }>
81
91
  }
82
92
 
83
93
  export interface AIAgentToolDef {
@@ -86,6 +96,7 @@ export interface AIAgentToolDef {
86
96
  inputSchema: Record<string, unknown>
87
97
  execute: (input: unknown) => Promise<unknown>
88
98
  needsApproval?: boolean
99
+ approvalDescriptionFn?: (input: unknown) => Promise<string>
89
100
  }
90
101
 
91
102
  export interface PikkuAIMiddlewareHooks<
@@ -189,13 +200,14 @@ export type CoreAIAgent<
189
200
  temperature?: number
190
201
  tools?: unknown[]
191
202
  agents?: unknown[]
203
+ agentMode?: 'delegate' | 'supervise'
192
204
  memory?: AIAgentMemoryConfig
193
205
  maxSteps?: number
194
206
  toolChoice?: 'auto' | 'required' | 'none'
207
+ dynamicWorkflows?: 'read' | 'always' | 'ask'
195
208
  input?: unknown
196
209
  output?: unknown
197
210
  tags?: string[]
198
- protocol?: 'ui-message-stream'
199
211
  prepareStep?: (ctx: {
200
212
  stepNumber: number
201
213
  messages: AIMessage[]
@@ -267,6 +279,13 @@ export type AIStreamEvent =
267
279
  session?: string
268
280
  }
269
281
  | { type: 'audio-done'; agent?: string; session?: string }
282
+ | {
283
+ type: 'workflow-created'
284
+ workflowName: string
285
+ graph: any
286
+ agent?: string
287
+ session?: string
288
+ }
270
289
  | {
271
290
  type: 'suspended'
272
291
  reason: 'rpc-missing'
@@ -298,6 +317,7 @@ export interface AgentRunState {
298
317
  threadId: string
299
318
  resourceId: string
300
319
  status: 'running' | 'suspended' | 'completed' | 'failed'
320
+ errorMessage?: string
301
321
  suspendReason?: 'approval' | 'rpc-missing'
302
322
  missingRpcs?: string[]
303
323
  pendingApprovals?: PendingApproval[]
@@ -312,6 +332,7 @@ export interface AgentRunRow {
312
332
  threadId: string
313
333
  resourceId: string
314
334
  status: string
335
+ errorMessage?: string
315
336
  suspendReason?: string
316
337
  missingRpcs?: string[]
317
338
  usageInputTokens: number
@@ -356,5 +377,6 @@ export type AIAgentMeta = Record<
356
377
  channelMiddleware?: MiddlewareMetadata[]
357
378
  aiMiddleware?: MiddlewareMetadata[]
358
379
  permissions?: PermissionMetadata[]
380
+ dynamicWorkflows?: 'read' | 'always' | 'ask'
359
381
  }
360
382
  >
@@ -4,12 +4,8 @@ export {
4
4
  agentResume,
5
5
  agentApprove,
6
6
  } from './ai-agent-helpers.js'
7
- export { runAIAgent } from './ai-agent-runner.js'
7
+ export { runAIAgent, resumeAIAgentSync } from './ai-agent-runner.js'
8
8
  export { streamAIAgent, resumeAIAgent } from './ai-agent-stream.js'
9
- export {
10
- createAssistantUIChannel,
11
- parseAssistantUIInput,
12
- } from './ai-agent-assistant-ui.js'
13
9
  export {
14
10
  type RunAIAgentParams,
15
11
  type StreamAIAgentOptions,
@@ -98,11 +98,18 @@ export const processMessageHandlers = (
98
98
  return
99
99
  }
100
100
 
101
+ const routeMeta = getRouteMeta(
102
+ channelConfig.name,
103
+ routingProperty,
104
+ routerValue
105
+ )
101
106
  const {
102
- pikkuFuncId,
107
+ packageName,
103
108
  middleware: routeInheritedMiddleware,
104
109
  permissions: inheritedPermissions,
105
- } = getRouteMeta(channelConfig.name, routingProperty, routerValue)
110
+ } = routeMeta
111
+
112
+ const pikkuFuncId = routeMeta.pikkuFuncId
106
113
 
107
114
  // Get wire middleware: channel-level middleware + message-specific middleware
108
115
  const channelWireMiddleware = channelConfig.middleware || []
@@ -146,12 +153,14 @@ export const processMessageHandlers = (
146
153
  wireChannelMiddleware: wireChannelMiddleware as any,
147
154
  inheritedPermissions,
148
155
  wirePermissions,
156
+ coerceDataFromSchema: true,
149
157
  tags: channelConfig.tags,
150
158
  sessionService: userSession,
151
159
  wire: {
152
160
  channel: channelHandler.getChannel(),
153
161
  ...(userSession && createMiddlewareSessionWireProps(userSession)),
154
162
  },
163
+ packageName,
155
164
  })
156
165
  }
157
166
 
@@ -1,4 +1,3 @@
1
- import type { PikkuError } from '../../errors/error-handler.js'
2
1
  import type {
3
2
  HTTPFunctionMetaInputTypes,
4
3
  PikkuHTTPRequest,
@@ -47,6 +46,7 @@ export type RunChannelParams<ChannelData> = {
47
46
 
48
47
  export interface ChannelMessageMeta {
49
48
  pikkuFuncId: string
49
+ packageName?: string
50
50
  summary?: string
51
51
  description?: string
52
52
  errors?: string[]
@@ -141,12 +141,6 @@ export type CoreChannel<
141
141
  data: BinaryData,
142
142
  channel: PikkuChannel<ChannelData, any>
143
143
  ) => Promise<BinaryData | void> | BinaryData | void
144
- docs?: Partial<{
145
- description: string
146
- response: string
147
- errors: Array<typeof PikkuError>
148
- tags: string[]
149
- }>
150
144
  tags?: string[]
151
145
  }
152
146
 
@@ -8,7 +8,7 @@ export class PikkuLocalChannelHandler<
8
8
  private onMessageCallback?: (message: unknown) => void
9
9
  private onBinaryMessageCallback?: (data: BinaryData) => void
10
10
  private openCallBack?: () => void
11
- private closeCallback?: () => void
11
+ private closeCallbacks: (() => void)[] = []
12
12
  private sendCallback?: (message: Out, isBinary?: boolean) => void
13
13
  private sendBinaryCallback?: (data: BinaryData) => void
14
14
 
@@ -44,7 +44,7 @@ export class PikkuLocalChannelHandler<
44
44
  }
45
45
 
46
46
  public registerOnClose(callback: () => void): void {
47
- this.closeCallback = callback
47
+ this.closeCallbacks.push(callback)
48
48
  }
49
49
 
50
50
  public close() {
@@ -52,7 +52,9 @@ export class PikkuLocalChannelHandler<
52
52
  return
53
53
  }
54
54
  super.close()
55
- this.closeCallback?.()
55
+ for (const cb of this.closeCallbacks) {
56
+ cb()
57
+ }
56
58
  }
57
59
 
58
60
  public registerOnSend(send: (message: Out) => void) {
@@ -119,9 +119,12 @@ export const runLocalChannel = async ({
119
119
  if (result !== undefined) {
120
120
  await channel.send(result)
121
121
  }
122
- } catch (e) {
122
+ } catch (e: any) {
123
123
  singletonServices.logger.error(`Error handling onConnect: ${e}`)
124
- channel.send({ error: e.message || 'Unknown error' })
124
+ channel.send({
125
+ error: e.message || 'Unknown error',
126
+ errorName: e.constructor?.name,
127
+ })
125
128
  }
126
129
  }
127
130
  })
@@ -138,9 +141,12 @@ export const runLocalChannel = async ({
138
141
  channel,
139
142
  channelMiddlewareMeta: meta.channelMiddleware,
140
143
  })
141
- } catch (e) {
144
+ } catch (e: any) {
142
145
  singletonServices.logger.error(`Error handling onDisconnect: ${e}`)
143
- channel.send({ error: e.message || 'Unknown error' })
146
+ channel.send({
147
+ error: e.message || 'Unknown error',
148
+ errorName: e.constructor?.name,
149
+ })
144
150
  }
145
151
  }
146
152
 
@@ -157,9 +163,13 @@ export const runLocalChannel = async ({
157
163
  try {
158
164
  const result = await onMessage(data)
159
165
  await channel.send(result)
160
- } catch (e) {
161
- singletonServices.logger.error(`Error handling message: ${e.message}`)
162
- channel.send({ error: e.message || 'Unknown error' })
166
+ } catch (e: any) {
167
+ singletonServices.logger.error(e)
168
+ channel.send({
169
+ error: e.message || 'Unknown error',
170
+ errorName: e.constructor?.name,
171
+ })
172
+ setTimeout(() => channel.close(), 200)
163
173
  }
164
174
  })
165
175
  if (onBinaryMessage) {
@@ -276,7 +276,10 @@ export const runChannelMessage = async (
276
276
  singletonServices.logger.error(
277
277
  `Error processing message: ${e.message || e}`
278
278
  )
279
- return { error: e.message || 'Unknown error' }
279
+ return {
280
+ error: e.message || 'Unknown error',
281
+ errorName: e.constructor?.name,
282
+ }
280
283
  } finally {
281
284
  if (wireServices) {
282
285
  await closeWireServices(singletonServices.logger, wireServices)
@@ -218,7 +218,9 @@ function pluckCLIData(
218
218
  const funcMeta = pikkuState(null, 'function', 'meta')[funcName]
219
219
  const schemaName = funcMeta?.inputSchemaName
220
220
  const schema = schemaName
221
- ? pikkuState(null, 'misc', 'schemas').get(schemaName)
221
+ ? pikkuState(funcMeta?.packageName ?? null, 'misc', 'schemas').get(
222
+ schemaName
223
+ )
222
224
  : null
223
225
 
224
226
  if (schema && schema.properties) {
@@ -226,7 +228,13 @@ function pluckCLIData(
226
228
  const result: Record<string, any> = {}
227
229
  for (const key of Object.keys(schema.properties)) {
228
230
  if (key in mergedData) {
229
- result[key] = mergedData[key]
231
+ let value = mergedData[key]
232
+ // CLI passes all values as strings — coerce to array when schema expects one
233
+ const propSchema = schema.properties[key]
234
+ if (propSchema?.type === 'array' && !Array.isArray(value)) {
235
+ value = typeof value === 'string' ? value.split(',') : [value]
236
+ }
237
+ result[key] = value
230
238
  } else if (availableOptions[key]?.default !== undefined) {
231
239
  // Apply default if not provided
232
240
  result[key] = availableOptions[key].default
@@ -354,9 +362,11 @@ export async function runCLICommand({
354
362
  wireMiddleware: allWireMiddleware,
355
363
  inheritedPermissions: currentCommand.permissions,
356
364
  wirePermissions: undefined,
365
+ coerceDataFromSchema: true,
357
366
  tags: programData?.tags,
358
367
  wire,
359
368
  sessionService: userSession,
369
+ packageName: currentCommand.packageName,
360
370
  })
361
371
 
362
372
  // Apply renderer one final time with the final output (if renderer exists)
@@ -70,6 +70,7 @@ export interface CLIProgramState {
70
70
  export interface CLICommandMeta {
71
71
  parameters?: string
72
72
  pikkuFuncId: string
73
+ packageName?: string
73
74
  positionals: CLIPositional[]
74
75
  options: Record<string, CLIOption>
75
76
  renderName?: string
@@ -166,7 +166,6 @@ function registerRoute(
166
166
  contentType: route.contentType,
167
167
  timeout: route.timeout,
168
168
  headers: route.headers,
169
- docs: route.docs,
170
169
  sse: route.sse,
171
170
  } as any)
172
171
  }
@@ -38,6 +38,7 @@ import { PikkuFetchHTTPResponse } from './pikku-fetch-http-response.js'
38
38
  import { PikkuFetchHTTPRequest } from './pikku-fetch-http-request.js'
39
39
  import type { PikkuChannel } from '../channel/channel.types.js'
40
40
  import { addFunction, runPikkuFunc } from '../../function/function-runner.js'
41
+ import { applyWebResponse } from './web-request.js'
41
42
  import { httpRouter } from './routers/http-router.js'
42
43
  import { validateSchema } from '../../schema.js'
43
44
  import { runMiddleware } from '../../middleware-runner.js'
@@ -396,10 +397,13 @@ const executeRoute = async (
396
397
  tags: route.tags,
397
398
  wire,
398
399
  sessionService: userSession,
400
+ packageName: meta.packageName,
399
401
  }
400
402
  )
401
403
  if (!matchedRoute.route.sse) {
402
- if (result === undefined || result === null) {
404
+ if (result instanceof Response) {
405
+ await applyWebResponse(http!.response!, result)
406
+ } else if (result === undefined || result === null) {
403
407
  http?.response?.status(204)
404
408
  } else if (route.returnsJSON === false) {
405
409
  http?.response?.arrayBuffer(result)
@@ -484,6 +488,7 @@ export const fetchData = async <In, Out>(
484
488
  logWarningsForStatusCodes = [],
485
489
  coerceDataFromSchema = true,
486
490
  bubbleErrors = false,
491
+ exposeErrors = false,
487
492
  generateRequestId,
488
493
  }: RunHTTPWiringOptions = {}
489
494
  ): Promise<Out | void> => {
@@ -545,15 +550,35 @@ export const fetchData = async <In, Out>(
545
550
 
546
551
  return result
547
552
  } catch (e: any) {
548
- handleHTTPError(
549
- e,
550
- http,
551
- requestId,
552
- singletonServices.logger,
553
- logWarningsForStatusCodes,
554
- respondWith404,
555
- bubbleErrors
556
- )
553
+ if (matchedRoute?.route.sse) {
554
+ // For SSE routes, send error through the stream since the response is already in stream mode
555
+ singletonServices.logger.error(e instanceof Error ? e.message : e)
556
+ try {
557
+ response.arrayBuffer(
558
+ JSON.stringify({
559
+ type: 'error',
560
+ errorText: e instanceof Error ? e.message : String(e),
561
+ })
562
+ )
563
+ response.arrayBuffer('[DONE]')
564
+ } catch (streamErr: any) {
565
+ singletonServices.logger.error(
566
+ `SSE error while sending error payload: ${streamErr instanceof Error ? streamErr.message : String(streamErr)}`
567
+ )
568
+ }
569
+ response.close?.()
570
+ } else {
571
+ handleHTTPError(
572
+ e,
573
+ http,
574
+ requestId,
575
+ singletonServices.logger,
576
+ logWarningsForStatusCodes,
577
+ respondWith404,
578
+ bubbleErrors,
579
+ exposeErrors
580
+ )
581
+ }
557
582
  } finally {
558
583
  // Clean up any session-specific services created during processing
559
584
  if (wireServices) {
@@ -1,6 +1,5 @@
1
1
  import type { SerializeOptions } from 'cookie'
2
2
  import type { StandardSchemaV1 } from '@standard-schema/spec'
3
- import type { PikkuError } from '../../errors/error-handler.js'
4
3
  import type {
5
4
  CorePikkuMiddleware,
6
5
  CommonWireMeta,
@@ -36,6 +35,7 @@ export type RunHTTPWiringOptions = Partial<{
36
35
  logWarningsForStatusCodes: number[]
37
36
  coerceDataFromSchema: boolean
38
37
  bubbleErrors: boolean
38
+ exposeErrors: boolean
39
39
  generateRequestId: () => string
40
40
  }>
41
41
 
@@ -59,16 +59,6 @@ export type HTTPHeadersSchema = StandardSchemaV1<
59
59
  Record<string, string | string[] | undefined>
60
60
  >
61
61
 
62
- /**
63
- * Documentation config for OpenAPI generation
64
- */
65
- export type HTTPRouteDocsConfig = {
66
- description?: string
67
- response?: string
68
- errors?: Array<typeof PikkuError>
69
- tags?: string[]
70
- }
71
-
72
62
  /**
73
63
  * Common HTTP route configuration shared between wireHTTP and wireHTTPRoutes
74
64
  */
@@ -77,7 +67,6 @@ export type HTTPRouteBaseConfig = {
77
67
  timeout?: number
78
68
  tags?: string[]
79
69
  headers?: HTTPHeadersSchema
80
- docs?: HTTPRouteDocsConfig
81
70
  }
82
71
 
83
72
  /**
@@ -271,6 +260,7 @@ export interface PikkuHTTPRequest<In = unknown> {
271
260
  data(): Promise<In>
272
261
  json(): Promise<unknown>
273
262
  arrayBuffer(): Promise<ArrayBuffer>
263
+ headers(): Record<string, string>
274
264
  header(headerName: string): string | null
275
265
  cookie(name?: string): string | null
276
266
  params(): Partial<Record<string, string | string[]>>
@@ -293,6 +283,7 @@ export interface PikkuHTTPResponse<Out = unknown> {
293
283
  | ReadableStream
294
284
  ): this
295
285
  json(data: Out): this
286
+ send?(data: string | ArrayBuffer | Buffer): this
296
287
  redirect(location: string, status?: number): this
297
288
  close?: () => void
298
289
  setMode?: (mode: 'stream') => void
@@ -11,12 +11,15 @@ export {
11
11
  } from './http-runner.js'
12
12
 
13
13
  export { wireHTTPRoutes, defineHTTPRoutes } from './http-routes.js'
14
+ export { toWebRequest, applyWebResponse } from './web-request.js'
14
15
 
15
16
  export type {
16
17
  AssertHTTPWiringParams,
17
18
  CoreHTTPFunctionWiring,
18
19
  HTTPMethod,
19
20
  HTTPRouteBaseConfig,
21
+ HTTPRouteContract,
22
+ HTTPRouteMap,
20
23
  HTTPWiringsMeta,
21
24
  PikkuHTTPRequest,
22
25
  PikkuHTTPResponse,
@@ -43,6 +43,10 @@ export class PikkuFetchHTTPRequest<In = unknown>
43
43
  return this.request.arrayBuffer()
44
44
  }
45
45
 
46
+ public headers(): Record<string, string> {
47
+ return Object.fromEntries(this.request.headers.entries())
48
+ }
49
+
46
50
  /**
47
51
  * Retrieves the value of a specific header.
48
52
  * @param headerName - The name of the header to retrieve.
@@ -83,10 +83,10 @@ export class PikkuFetchHTTPResponse implements PikkuHTTPResponse {
83
83
  return this
84
84
  }
85
85
 
86
- // public body(body: BodyInit): this {
87
- // this.#body = body
88
- // return this
89
- // }
86
+ public send(data: any): this {
87
+ this.#body = data
88
+ return this
89
+ }
90
90
 
91
91
  public redirect(location: string, status: number = 302): this {
92
92
  if (