@pikku/cli 0.10.1 → 0.10.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.
Files changed (150) hide show
  1. package/.pikku/channel/pikku-channel-types.gen.ts +4 -3
  2. package/.pikku/channel/pikku-channels-map.gen.d.ts +2 -2
  3. package/.pikku/channel/pikku-channels-meta.gen.ts +1 -1
  4. package/.pikku/channel/pikku-channels.gen.ts +1 -1
  5. package/.pikku/cli/pikku-cli-types.gen.ts +23 -1
  6. package/.pikku/cli/pikku-cli-wirings-meta.gen.ts +4 -115
  7. package/.pikku/cli/pikku-cli-wirings.gen.ts +2 -3
  8. package/.pikku/function/pikku-function-types.gen.ts +1 -1
  9. package/.pikku/function/pikku-functions-meta.gen.ts +156 -138
  10. package/.pikku/function/pikku-functions-meta.min.gen.ts +37 -32
  11. package/.pikku/function/pikku-functions.gen.ts +1 -1
  12. package/.pikku/http/pikku-http-types.gen.ts +1 -1
  13. package/.pikku/http/pikku-http-wirings-map.gen.d.ts +2 -2
  14. package/.pikku/http/pikku-http-wirings-meta.gen.ts +1 -1
  15. package/.pikku/http/pikku-http-wirings.gen.ts +1 -1
  16. package/.pikku/mcp/pikku-mcp-types.gen.ts +1 -1
  17. package/.pikku/mcp/pikku-mcp-wirings-meta.gen.ts +1 -1
  18. package/.pikku/mcp/pikku-mcp-wirings.gen.ts +1 -1
  19. package/.pikku/pikku-bootstrap.gen.ts +1 -1
  20. package/.pikku/pikku-services.gen.ts +16 -12
  21. package/.pikku/pikku-types.gen.ts +1 -1
  22. package/.pikku/pikku-websocket.gen.ts +15 -1
  23. package/.pikku/queue/pikku-queue-types.gen.ts +1 -1
  24. package/.pikku/queue/pikku-queue-workers-wirings-map.gen.d.ts +2 -2
  25. package/.pikku/queue/pikku-queue-workers-wirings-meta.gen.ts +1 -1
  26. package/.pikku/queue/pikku-queue-workers-wirings.gen.ts +1 -1
  27. package/.pikku/rpc/pikku-rpc-wirings-map.gen.d.ts +2 -2
  28. package/.pikku/rpc/pikku-rpc-wirings-map.internal.gen.d.ts +10 -9
  29. package/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.ts +9 -8
  30. package/.pikku/scheduler/pikku-scheduler-types.gen.ts +1 -1
  31. package/.pikku/scheduler/pikku-schedulers-wirings-meta.gen.ts +1 -1
  32. package/.pikku/scheduler/pikku-schedulers-wirings.gen.ts +1 -1
  33. package/.pikku/schemas/register.gen.ts +5 -5
  34. package/.pikku/schemas/schemas/PikkuCLIConfig.schema.json +1 -1
  35. package/.pikku/schemas/schemas/PikkuChannelsOutput.schema.json +1 -1
  36. package/.pikku/schemas/schemas/PikkuSchemasOutput.schema.json +1 -1
  37. package/CHANGELOG.md +49 -0
  38. package/bin/pikku.ts +30 -21
  39. package/cli.schema.json +1 -1
  40. package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +4 -3
  41. package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
  42. package/dist/.pikku/channel/pikku-channels-meta.gen.js +1 -1
  43. package/dist/.pikku/channel/pikku-channels.gen.d.ts +1 -1
  44. package/dist/.pikku/channel/pikku-channels.gen.js +1 -1
  45. package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +18 -1
  46. package/dist/.pikku/cli/pikku-cli-types.gen.js +20 -1
  47. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +4 -115
  48. package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -2
  49. package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -2
  50. package/dist/.pikku/function/pikku-function-types.gen.d.ts +1 -1
  51. package/dist/.pikku/function/pikku-function-types.gen.js +1 -1
  52. package/dist/.pikku/function/pikku-functions-meta.gen.js +156 -138
  53. package/dist/.pikku/function/pikku-functions-meta.min.gen.js +37 -32
  54. package/dist/.pikku/function/pikku-functions.gen.js +1 -1
  55. package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
  56. package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
  57. package/dist/.pikku/http/pikku-http-wirings-meta.gen.js +1 -1
  58. package/dist/.pikku/http/pikku-http-wirings.gen.d.ts +1 -1
  59. package/dist/.pikku/http/pikku-http-wirings.gen.js +1 -1
  60. package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
  61. package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
  62. package/dist/.pikku/mcp/pikku-mcp-wirings-meta.gen.js +1 -1
  63. package/dist/.pikku/mcp/pikku-mcp-wirings.gen.d.ts +1 -1
  64. package/dist/.pikku/mcp/pikku-mcp-wirings.gen.js +1 -1
  65. package/dist/.pikku/pikku-bootstrap.gen.d.ts +1 -1
  66. package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
  67. package/dist/.pikku/pikku-services.gen.d.ts +9 -6
  68. package/dist/.pikku/pikku-services.gen.js +8 -2
  69. package/dist/.pikku/pikku-types.gen.d.ts +1 -1
  70. package/dist/.pikku/pikku-types.gen.js +1 -1
  71. package/dist/.pikku/pikku-websocket.gen.d.ts +15 -1
  72. package/dist/.pikku/pikku-websocket.gen.js +15 -1
  73. package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
  74. package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
  75. package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
  76. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
  77. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.js +1 -1
  78. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +9 -8
  79. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
  80. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
  81. package/dist/.pikku/scheduler/pikku-schedulers-wirings-meta.gen.js +1 -1
  82. package/dist/.pikku/scheduler/pikku-schedulers-wirings.gen.d.ts +1 -1
  83. package/dist/.pikku/scheduler/pikku-schedulers-wirings.gen.js +1 -1
  84. package/dist/.pikku/schemas/register.gen.js +3 -3
  85. package/dist/.pikku/schemas/schemas/PikkuCLIConfig.schema.json +1 -1
  86. package/dist/.pikku/schemas/schemas/PikkuChannelsOutput.schema.json +1 -1
  87. package/dist/.pikku/schemas/schemas/PikkuSchemasOutput.schema.json +1 -1
  88. package/dist/bin/pikku.js +24 -19
  89. package/dist/src/cli.wiring.js +107 -99
  90. package/dist/src/functions/commands/all.js +31 -2
  91. package/dist/src/functions/commands/bootstrap.d.ts +1 -0
  92. package/dist/src/functions/commands/bootstrap.js +23 -0
  93. package/dist/src/functions/runtimes/nextjs/serialize-nextjs-backend-wrapper.js +46 -2
  94. package/dist/src/functions/wirings/channels/serialize-channel-types.js +3 -2
  95. package/dist/src/functions/wirings/channels/serialize-websocket-wrapper.js +14 -0
  96. package/dist/src/functions/wirings/cli/pikku-command-cli-entry.js +4 -4
  97. package/dist/src/functions/wirings/cli/serialize-channel-cli-client.js +24 -4
  98. package/dist/src/functions/wirings/cli/serialize-channel-cli.js +32 -7
  99. package/dist/src/functions/wirings/cli/serialize-cli-types.js +22 -0
  100. package/dist/src/functions/wirings/functions/pikku-command-services.d.ts +1 -1
  101. package/dist/src/functions/wirings/functions/pikku-command-services.js +54 -26
  102. package/dist/src/functions/wirings/functions/schemas.js +2 -2
  103. package/dist/src/functions/wirings/http/pikku-command-openapi.js +1 -1
  104. package/dist/src/functions/wirings/middleware/pikku-command-middleware.js +3 -10
  105. package/dist/src/middleware/log-command-info-and-time.d.ts +1 -1
  106. package/dist/src/middleware/log-command-info-and-time.js +8 -5
  107. package/dist/src/services/cli-logger.service.d.ts +7 -2
  108. package/dist/src/services/cli-logger.service.js +16 -4
  109. package/dist/src/services.js +77 -12
  110. package/dist/src/utils/command-summary.d.ts +43 -0
  111. package/dist/src/utils/command-summary.js +73 -0
  112. package/dist/src/utils/file-writer.js +2 -2
  113. package/dist/src/utils/pikku-cli-config.js +28 -0
  114. package/dist/src/utils/schema-generator.d.ts +2 -2
  115. package/dist/src/utils/schema-generator.js +3 -3
  116. package/dist/tsconfig.tsbuildinfo +1 -1
  117. package/package.json +3 -4
  118. package/pikku.config.json +5 -2
  119. package/src/cli.wiring.ts +106 -101
  120. package/src/functions/commands/all.ts +38 -2
  121. package/src/functions/commands/bootstrap.ts +27 -0
  122. package/src/functions/runtimes/nextjs/serialize-nextjs-backend-wrapper.ts +46 -2
  123. package/src/functions/wirings/channels/serialize-channel-types.ts +3 -2
  124. package/src/functions/wirings/channels/serialize-websocket-wrapper.ts +14 -0
  125. package/src/functions/wirings/cli/pikku-command-cli-entry.ts +4 -4
  126. package/src/functions/wirings/cli/serialize-channel-cli-client.ts +24 -4
  127. package/src/functions/wirings/cli/serialize-channel-cli.ts +40 -8
  128. package/src/functions/wirings/cli/serialize-cli-types.ts +22 -0
  129. package/src/functions/wirings/functions/pikku-command-services.ts +57 -28
  130. package/src/functions/wirings/functions/schemas.ts +4 -3
  131. package/src/functions/wirings/http/pikku-command-openapi.ts +2 -1
  132. package/src/functions/wirings/middleware/pikku-command-middleware.ts +11 -22
  133. package/src/middleware/log-command-info-and-time.ts +8 -5
  134. package/src/services/cli-logger.service.ts +20 -5
  135. package/src/services.ts +86 -11
  136. package/src/utils/command-summary.ts +101 -0
  137. package/src/utils/file-writer.ts +2 -2
  138. package/src/utils/pikku-cli-config.ts +28 -0
  139. package/src/utils/schema-generator.ts +5 -4
  140. package/types/application-types.d.ts +5 -1
  141. package/types/config.d.ts +16 -6
  142. package/.pikku/cli/pikku-cli-channel.gen.ts +0 -34
  143. package/.pikku/cli/pikku-cli-client.gen.ts +0 -43
  144. package/.pikku/cli/pikku-cli.gen.ts +0 -41
  145. package/dist/.pikku/cli/pikku-cli-channel.gen.d.ts +0 -1
  146. package/dist/.pikku/cli/pikku-cli-channel.gen.js +0 -33
  147. package/dist/.pikku/cli/pikku-cli-client.gen.d.ts +0 -10
  148. package/dist/.pikku/cli/pikku-cli-client.gen.js +0 -34
  149. package/dist/.pikku/cli/pikku-cli.gen.d.ts +0 -10
  150. package/dist/.pikku/cli/pikku-cli.gen.js +0 -38
package/src/cli.wiring.ts CHANGED
@@ -1,102 +1,107 @@
1
- import { pikkuSchemas } from './functions/wirings/functions/schemas.js'
2
- import { pikkuFetch } from './functions/wirings/fetch/index.js'
3
- import { pikkuWebSocketTyped } from './functions/wirings/channels/pikku-command-websocket-typed.js'
4
- import { pikkuRPCClient } from './functions/wirings/rpc/pikku-command-rpc-client.js'
5
- import { pikkuQueueService } from './functions/wirings/queue/pikku-command-queue-service.js'
6
- import { pikkuOpenAPI } from './functions/wirings/http/pikku-command-openapi.js'
7
- import { pikkuNext } from './functions/runtimes/nextjs/pikku-command-nextjs.js'
8
- import { pikkuCLICommand, wireCLI } from '../.pikku/cli/pikku-cli-types.gen.js'
9
- import { all } from './functions/commands/all.js'
10
- import { clientCLIRenderer } from './services.js'
1
+ // import { pikkuSchemas } from './functions/wirings/functions/schemas.js'
2
+ // import { pikkuFetch } from './functions/wirings/fetch/index.js'
3
+ // import { pikkuWebSocketTyped } from './functions/wirings/channels/pikku-command-websocket-typed.js'
4
+ // import { pikkuRPCClient } from './functions/wirings/rpc/pikku-command-rpc-client.js'
5
+ // import { pikkuQueueService } from './functions/wirings/queue/pikku-command-queue-service.js'
6
+ // import { pikkuOpenAPI } from './functions/wirings/http/pikku-command-openapi.js'
7
+ // import { pikkuNext } from './functions/runtimes/nextjs/pikku-command-nextjs.js'
8
+ // import { pikkuCLICommand, wireCLI } from '../.pikku/cli/pikku-cli-types.gen.js'
9
+ // import { all } from './functions/commands/all.js'
10
+ // import { bootstrap } from './functions/commands/bootstrap.js'
11
+ // import { clientCLIRenderer } from './services.js'
11
12
 
12
- wireCLI({
13
- program: 'pikku',
14
- description:
15
- 'Pikku CLI - Code generation tool for type-safe backend development',
16
- render: clientCLIRenderer,
17
- options: {
18
- config: {
19
- description: 'Path to pikku.config.json file',
20
- short: 'c',
21
- },
22
- logLevel: {
23
- description: 'Set log level',
24
- default: 'info' as const,
25
- short: 'l',
26
- },
27
- userSessionType: {
28
- description:
29
- 'Specify which UserSession type to use (when multiple exist)',
30
- },
31
- singletonServicesFactoryType: {
32
- description: 'Specify which singleton services factory to use',
33
- },
34
- sessionServicesFactoryType: {
35
- description: 'Specify which session services factory to use',
36
- },
37
- stateOutput: {
38
- description: 'Save inspector state to JSON file for reuse',
39
- },
40
- stateInput: {
41
- description: 'Load inspector state from JSON file (skips inspection)',
42
- },
43
- },
44
- commands: {
45
- all: pikkuCLICommand({
46
- func: all,
47
- description: 'Generate all Pikku files (types, schemas, wirings, etc.)',
48
- isDefault: true,
49
- options: {
50
- tags: {
51
- description: 'Filter functions by tags (comma-separated)',
52
- short: 't',
53
- },
54
- types: {
55
- description: 'Filter functions by types (comma-separated)',
56
- },
57
- directories: {
58
- description: 'Filter functions by directories (comma-separated)',
59
- short: 'd',
60
- },
61
- httpMethods: {
62
- description: 'Filter HTTP routes by methods (comma-separated)',
63
- },
64
- httpRoutes: {
65
- description: 'Filter HTTP routes by route patterns (comma-separated)',
66
- },
67
- names: {
68
- description: 'Filter functions by name patterns (supports wildcards)',
69
- short: 'n',
70
- },
71
- },
72
- }),
73
- schemas: pikkuCLICommand({
74
- func: pikkuSchemas,
75
- description: 'Generate JSON schemas for function input/output types',
76
- }),
77
- fetch: pikkuCLICommand({
78
- func: pikkuFetch,
79
- description: 'Generate type-safe HTTP fetch client',
80
- }),
81
- websocket: pikkuCLICommand({
82
- func: pikkuWebSocketTyped,
83
- description: 'Generate type-safe WebSocket client',
84
- }),
85
- rpc: pikkuCLICommand({
86
- func: pikkuRPCClient,
87
- description: 'Generate RPC client wrappers',
88
- }),
89
- 'queue-service': pikkuCLICommand({
90
- func: pikkuQueueService,
91
- description: 'Generate queue service wrapper',
92
- }),
93
- openapi: pikkuCLICommand({
94
- func: pikkuOpenAPI,
95
- description: 'Generate OpenAPI specification from HTTP routes',
96
- }),
97
- nextjs: pikkuCLICommand({
98
- func: pikkuNext,
99
- description: 'Generate Next.js backend and HTTP wrappers',
100
- }),
101
- },
102
- })
13
+ // wireCLI({
14
+ // program: 'pikku',
15
+ // description:
16
+ // 'Pikku CLI - Code generation tool for type-safe backend development',
17
+ // render: clientCLIRenderer,
18
+ // options: {
19
+ // config: {
20
+ // description: 'Path to pikku.config.json file',
21
+ // short: 'c',
22
+ // },
23
+ // logLevel: {
24
+ // description: 'Set log level',
25
+ // default: 'info' as const,
26
+ // short: 'l',
27
+ // },
28
+ // userSessionType: {
29
+ // description:
30
+ // 'Specify which UserSession type to use (when multiple exist)',
31
+ // },
32
+ // singletonServicesFactoryType: {
33
+ // description: 'Specify which singleton services factory to use',
34
+ // },
35
+ // sessionServicesFactoryType: {
36
+ // description: 'Specify which session services factory to use',
37
+ // },
38
+ // stateOutput: {
39
+ // description: 'Save inspector state to JSON file for reuse',
40
+ // },
41
+ // stateInput: {
42
+ // description: 'Load inspector state from JSON file (skips inspection)',
43
+ // },
44
+ // },
45
+ // commands: {
46
+ // all: pikkuCLICommand({
47
+ // func: all,
48
+ // description: 'Generate all Pikku files (types, schemas, wirings, etc.)',
49
+ // isDefault: true,
50
+ // options: {
51
+ // tags: {
52
+ // description: 'Filter functions by tags (comma-separated)',
53
+ // short: 't',
54
+ // },
55
+ // types: {
56
+ // description: 'Filter functions by types (comma-separated)',
57
+ // },
58
+ // directories: {
59
+ // description: 'Filter functions by directories (comma-separated)',
60
+ // short: 'd',
61
+ // },
62
+ // httpMethods: {
63
+ // description: 'Filter HTTP routes by methods (comma-separated)',
64
+ // },
65
+ // httpRoutes: {
66
+ // description: 'Filter HTTP routes by route patterns (comma-separated)',
67
+ // },
68
+ // names: {
69
+ // description: 'Filter functions by name patterns (supports wildcards)',
70
+ // short: 'n',
71
+ // },
72
+ // },
73
+ // }),
74
+ // bootstrap: pikkuCLICommand({
75
+ // func: bootstrap,
76
+ // description: 'Generate only type files (setup phase only)',
77
+ // }),
78
+ // schemas: pikkuCLICommand({
79
+ // func: pikkuSchemas,
80
+ // description: 'Generate JSON schemas for function input/output types',
81
+ // }),
82
+ // fetch: pikkuCLICommand({
83
+ // func: pikkuFetch,
84
+ // description: 'Generate type-safe HTTP fetch client',
85
+ // }),
86
+ // websocket: pikkuCLICommand({
87
+ // func: pikkuWebSocketTyped,
88
+ // description: 'Generate type-safe WebSocket client',
89
+ // }),
90
+ // rpc: pikkuCLICommand({
91
+ // func: pikkuRPCClient,
92
+ // description: 'Generate RPC client wrappers',
93
+ // }),
94
+ // 'queue-service': pikkuCLICommand({
95
+ // func: pikkuQueueService,
96
+ // description: 'Generate queue service wrapper',
97
+ // }),
98
+ // openapi: pikkuCLICommand({
99
+ // func: pikkuOpenAPI,
100
+ // description: 'Generate OpenAPI specification from HTTP routes',
101
+ // }),
102
+ // nextjs: pikkuCLICommand({
103
+ // func: pikkuNext,
104
+ // description: 'Generate Next.js backend and HTTP wrappers',
105
+ // }),
106
+ // },
107
+ // })
@@ -2,9 +2,11 @@ import { existsSync } from 'fs'
2
2
  import { pikkuVoidFunc } from '../../../.pikku/pikku-types.gen.js'
3
3
  import { getFileImportRelativePath } from '../../utils/file-import-path.js'
4
4
  import { writeFileInDir } from '../../utils/file-writer.js'
5
+ import { CommandSummary } from '../../utils/command-summary.js'
5
6
 
6
7
  export const all: any = pikkuVoidFunc({
7
8
  func: async ({ logger, config, rpc, getInspectorState }) => {
9
+ const summary = new CommandSummary('all')
8
10
  const allImports: string[] = []
9
11
  let typesDeclarationFileExists = true
10
12
 
@@ -16,7 +18,7 @@ export const all: any = pikkuVoidFunc({
16
18
 
17
19
  // This is needed since the wireHTTP function will add the routes to the visitState
18
20
  if (!typesDeclarationFileExists) {
19
- logger.info(`• Type file first created, inspecting again...\x1b[0m`)
21
+ logger.debug(`• Type file first created, inspecting again...`)
20
22
  await getInspectorState(true)
21
23
  }
22
24
 
@@ -125,7 +127,7 @@ export const all: any = pikkuVoidFunc({
125
127
  }
126
128
 
127
129
  if (config.openAPI) {
128
- logger.info(
130
+ logger.debug(
129
131
  `• OpenAPI requires a reinspection to pickup new generated types..`
130
132
  )
131
133
  await getInspectorState(true)
@@ -145,6 +147,40 @@ export const all: any = pikkuVoidFunc({
145
147
  .join('\n')
146
148
  )
147
149
 
150
+ // Get final inspector state and collect stats for summary
151
+ const state = await getInspectorState()
152
+ if (state.http?.meta)
153
+ summary.set('httpRoutes', Object.keys(state.http.meta).length)
154
+ if (state.channels?.meta)
155
+ summary.set('channels', Object.keys(state.channels.meta).length)
156
+ if (state.scheduledTasks?.meta)
157
+ summary.set(
158
+ 'scheduledTasks',
159
+ Object.keys(state.scheduledTasks.meta).length
160
+ )
161
+ if (state.queueWorkers?.meta)
162
+ summary.set('queueWorkers', Object.keys(state.queueWorkers.meta).length)
163
+ if (state.mcpEndpoints) {
164
+ const mcpTotal =
165
+ Object.keys(state.mcpEndpoints.toolsMeta || {}).length +
166
+ Object.keys(state.mcpEndpoints.resourcesMeta || {}).length +
167
+ Object.keys(state.mcpEndpoints.promptsMeta || {}).length
168
+ if (mcpTotal > 0) summary.set('mcpEndpoints', mcpTotal)
169
+ }
170
+ if (state.cli?.meta) {
171
+ // Count total CLI commands across all programs
172
+ const totalCommands = Object.values(state.cli.meta).reduce(
173
+ (sum, program) => sum + (program.commands?.length || 0),
174
+ 0
175
+ )
176
+ if (totalCommands > 0) summary.set('cliCommands', totalCommands)
177
+ }
178
+
179
+ // Display summary (unless in silent mode)
180
+ if (!logger.isSilent()) {
181
+ console.log(summary.format())
182
+ }
183
+
148
184
  // Check for critical errors and exit if any were logged
149
185
  if (logger.hasCriticalErrors()) {
150
186
  process.exit(1)
@@ -0,0 +1,27 @@
1
+ import { pikkuVoidFunc } from '../../../.pikku/pikku-types.gen.js'
2
+
3
+ export const bootstrap: any = pikkuVoidFunc({
4
+ func: async ({ logger, config, rpc, getInspectorState }) => {
5
+ // Initialize inspector state in bootstrap mode with core types only
6
+ // This allows bootstrap to run immediately without inspecting the codebase
7
+ // All subsequent RPC commands will use this cached state
8
+ await getInspectorState(false, false, true)
9
+
10
+ await rpc.invoke('pikkuFunctionTypes', null)
11
+
12
+ // Generate wiring-specific type files for tree-shaking
13
+ // These use the bootstrap mode state with core types
14
+ await rpc.invoke('pikkuFunctionTypesSplit', null)
15
+ await rpc.invoke('pikkuHTTPTypes', null)
16
+ await rpc.invoke('pikkuChannelTypes', null)
17
+ await rpc.invoke('pikkuSchedulerTypes', null)
18
+ await rpc.invoke('pikkuQueueTypes', null)
19
+ await rpc.invoke('pikkuMCPTypes', null)
20
+ await rpc.invoke('pikkuCLITypes', null)
21
+
22
+ // Check for critical errors and exit if any were logged
23
+ if (logger.hasCriticalErrors()) {
24
+ process.exit(1)
25
+ }
26
+ },
27
+ })
@@ -6,14 +6,17 @@ export const serializeNextJsBackendWrapper = (
6
6
  sessionServicesImport: string
7
7
  ) => {
8
8
  return `'server-only'
9
-
9
+
10
10
  /**
11
11
  * This file provides a wrapper around the PikkuNextJS class to allow for methods to be type checked against your routes.
12
12
  * It ensures type safety for route handling methods when integrating with the @pikku/core framework.
13
13
  */
14
14
  import { PikkuNextJS } from '@pikku/next'
15
+ import { NextRequest } from 'next/server.js'
15
16
  import type { HTTPWiringsMap, HTTPWiringHandlerOf, HTTPWiringsWithMethod } from '${routesMapPath}'
16
17
 
18
+ type RouteContext = { params: Promise<Record<string, string | string[]>> }
19
+
17
20
  ${configImport}
18
21
  ${singleServicesFactoryImport}
19
22
  ${sessionServicesImport}
@@ -21,6 +24,11 @@ ${sessionServicesImport}
21
24
  import '${bootstrapPath}'
22
25
 
23
26
  let _pikku: PikkuNextJS | undefined
27
+ let _removeAPIPrefix = true
28
+
29
+ export const removeAPIPrefix = (enable: boolean) => {
30
+ _removeAPIPrefix = enable
31
+ }
24
32
 
25
33
  /**
26
34
  * Initializes and returns an instance of PikkuNextJS with helper methods for handling route requests.
@@ -178,8 +186,44 @@ export const pikku = (_options?: any) => {
178
186
  patch: dynamicPatch,
179
187
  del: dynamicDel,
180
188
  staticGet,
181
- staticPost
189
+ staticPost,
190
+ }
191
+ }
192
+
193
+ /**
194
+ * Pre-bound API request handler for Next.js App Router route handlers.
195
+ * Use this to directly export route handlers without losing context.
196
+ *
197
+ * @param req - The Next.js request object.
198
+ * @param context - Next.js route context (unused by Pikku, but required by Next.js signature).
199
+ * @returns A promise that resolves to a Next.js Response object.
200
+ *
201
+ * @example
202
+ * export const GET = pikkuAPIRequest
203
+ * export const POST = pikkuAPIRequest
204
+ */
205
+ export const pikkuAPIRequest = (
206
+ req: NextRequest,
207
+ context: RouteContext
208
+ ): Promise<Response> => {
209
+ if (!_pikku) {
210
+ _pikku = new PikkuNextJS(
211
+ createConfig as any,
212
+ createSingletonServices as any,
213
+ createSessionServices
214
+ )
215
+ }
216
+ if (_removeAPIPrefix) {
217
+ const url = new URL(req.url)
218
+ url.pathname = url.pathname.replace(/^\\/api/, '') || '/'
219
+ req = new NextRequest(url.toString(), {
220
+ method: req.method,
221
+ headers: req.headers,
222
+ body: req.body,
223
+ duplex: 'half',
224
+ } as any)
182
225
  }
226
+ return _pikku.apiRequest(req)
183
227
  }
184
228
  `
185
229
  }
@@ -10,11 +10,12 @@ export const serializeChannelTypes = (functionTypesImportPath: string) => {
10
10
  import { CoreChannel, wireChannel as wireChannelCore } from '@pikku/core/channel'
11
11
  import { CorePikkuFunctionConfig } from '@pikku/core'
12
12
  import { AssertHTTPWiringParams } from '@pikku/core/http'
13
- import type { PikkuFunctionSessionless, PikkuPermission, PikkuMiddleware } from '${functionTypesImportPath}'
13
+ import type { PikkuFunction, PikkuFunctionSessionless, PikkuPermission, PikkuMiddleware } from '${functionTypesImportPath}'
14
14
 
15
15
  /**
16
16
  * Type definition for WebSocket channels with typed data exchange.
17
17
  * Supports connection, disconnection, and message handling.
18
+ * Accepts both session-based (PikkuFunction) and sessionless (PikkuFunctionSessionless) functions.
18
19
  *
19
20
  * @template ChannelData - Type of data exchanged through the channel
20
21
  * @template Channel - String literal type for the channel name
@@ -24,7 +25,7 @@ type ChannelWiring<ChannelData, Channel extends string> = CoreChannel<
24
25
  Channel,
25
26
  CorePikkuFunctionConfig<PikkuFunctionSessionless<void, any, ChannelData>, PikkuPermission<void>, PikkuMiddleware>,
26
27
  CorePikkuFunctionConfig<PikkuFunctionSessionless<void, void, ChannelData>, PikkuPermission<void>, PikkuMiddleware>,
27
- CorePikkuFunctionConfig<PikkuFunctionSessionless<any, any, ChannelData>, PikkuPermission<any>, PikkuMiddleware>,
28
+ CorePikkuFunctionConfig<PikkuFunctionSessionless<any, any, ChannelData> | PikkuFunction<any, any, ChannelData>, PikkuPermission<any>, PikkuMiddleware>,
28
29
  PikkuPermission,
29
30
  PikkuMiddleware
30
31
  >
@@ -26,6 +26,20 @@ class PikkuWebSocketRoute<Channel extends keyof ChannelsMap, Route extends keyof
26
26
  }
27
27
  }
28
28
 
29
+ /**
30
+ * Type-safe WebSocket wrapper for Pikku channels.
31
+ *
32
+ * @example
33
+ * // Browser usage
34
+ * const ws = new WebSocket('ws://localhost:3000')
35
+ * const pikkuWS = new PikkuWebSocket<'events'>(ws)
36
+ *
37
+ * @example
38
+ * // Node.js usage
39
+ * import WebSocket from 'ws'
40
+ * const ws = new WebSocket('ws://localhost:3000')
41
+ * const pikkuWS = new PikkuWebSocket<'events'>(ws)
42
+ */
29
43
  export class PikkuWebSocket<Channel extends keyof ChannelsMap, EventHubTopics extends Record<string, any> = {}> extends CorePikkuWebsocket {
30
44
  /**
31
45
  * Send a message to a specific route and method.
@@ -52,8 +52,8 @@ export const pikkuCLIEntry: any = pikkuSessionlessFunc<void, void>({
52
52
  // Normalize entrypoint config to get type
53
53
  const entrypointType =
54
54
  typeof entrypointConfig === 'string'
55
- ? 'cli'
56
- : entrypointConfig.type || 'cli'
55
+ ? 'local'
56
+ : entrypointConfig.type || 'local'
57
57
 
58
58
  // Handle channel type entrypoint
59
59
  if (entrypointType === 'channel') {
@@ -152,11 +152,11 @@ export const pikkuCLIEntry: any = pikkuSessionlessFunc<void, void>({
152
152
  continue
153
153
  }
154
154
 
155
- // Handle CLI type entrypoint (default)
155
+ // Handle local CLI type entrypoint (default)
156
156
  const entrypointPath =
157
157
  typeof entrypointConfig === 'string'
158
158
  ? entrypointConfig
159
- : entrypointConfig.type === 'cli'
159
+ : entrypointConfig.type === 'local'
160
160
  ? entrypointConfig.path
161
161
  : undefined
162
162
 
@@ -142,8 +142,27 @@ export async function ${capitalizedName}CLIClient(
142
142
  url: string,
143
143
  args?: string[]
144
144
  ): Promise<void> {
145
+ // Get WebSocket implementation (browser or Node.js)
146
+ let WebSocketImpl: any
147
+ if (typeof WebSocket !== 'undefined') {
148
+ WebSocketImpl = WebSocket
149
+ } else {
150
+ // Node.js environment - dynamically import 'ws'
151
+ try {
152
+ const wsModule = await import('ws')
153
+ WebSocketImpl = wsModule.default
154
+ } catch (e) {
155
+ throw new Error(
156
+ 'No WebSocket implementation found. In Node.js environments, you need to:\\n' +
157
+ '1. Install the "ws" package: npm install ws\\n' +
158
+ 'Learn more: https://www.npmjs.com/package/ws'
159
+ )
160
+ }
161
+ }
162
+
145
163
  // Create WebSocket connection
146
- const pikkuWS = new CorePikkuWebsocket(url)
164
+ const ws = new WebSocketImpl(url) as WebSocket
165
+ const pikkuWS = new CorePikkuWebsocket(ws)
147
166
 
148
167
  // Register renderers for CLI commands
149
168
  const renderers = ${renderersMap}
@@ -161,10 +180,11 @@ export default ${capitalizedName}CLIClient
161
180
 
162
181
  // For direct execution (if this file is run directly)
163
182
  if (import.meta.url === \`file://\${process.argv[1]}\`) {
164
- const url = process.env.PIKKU_WS_URL || 'ws://localhost:3000${finalChannelRoute}'
183
+ const url = process.env.PIKKU_WS_URL || 'ws://localhost:4002${finalChannelRoute}'
165
184
  ${capitalizedName}CLIClient(url, process.argv.slice(2)).catch(error => {
166
- console.error('Fatal error:', error.message)
167
- process.exit(1)
185
+ console.error('Fatal channel CLI error:', error)
186
+ // TODO: We get an error code even when it exists cleanly, investigate
187
+ // process.exit(1)
168
188
  })
169
189
  }
170
190
  `
@@ -47,13 +47,6 @@ export function serializeChannelCLI(
47
47
 
48
48
  collectCommands(programMeta.commands)
49
49
 
50
- // Generate the wireChannel call
51
- const commandEntries = Object.entries(commandMap)
52
- .map(([commandKey, { pikkuFuncName }]) => {
53
- return ` '${commandKey}': ${pikkuFuncName}`
54
- })
55
- .join(',\n')
56
-
57
50
  // Generate imports from function file locations
58
51
  const funcNames = [
59
52
  ...new Set(Object.values(commandMap).map((v) => v.pikkuFuncName)),
@@ -81,19 +74,58 @@ export function serializeChannelCLI(
81
74
  packageMappings
82
75
  )
83
76
 
77
+ // Get relative path to function types file
78
+ const functionTypesPath = getFileImportRelativePath(
79
+ channelFile,
80
+ functionTypesFile,
81
+ packageMappings
82
+ )
83
+
84
84
  return `/**
85
85
  * WebSocket channel backend for '${programName}' CLI commands
86
86
  */
87
87
  import { wireChannel } from '${channelTypesPath}'
88
+ import { pikkuMiddleware } from '${functionTypesPath}'
88
89
  ${imports}
89
90
 
91
+ // Middleware to close the channel after CLI command completes
92
+ const cliCloseOnComplete = pikkuMiddleware(async (services, { channel }, next) => {
93
+ const closeChannel = () => {
94
+ setTimeout(async () => {
95
+ try {
96
+ // This gives time for the response to be sent before closing
97
+ await channel?.close()
98
+ } catch (err) {
99
+ // Ignore errors on close
100
+ }
101
+ }, 200)
102
+ }
103
+
104
+ try {
105
+ const result = await next()
106
+ closeChannel()
107
+ return result
108
+ } catch (error) {
109
+ closeChannel()
110
+ throw error
111
+ }
112
+ })
113
+
90
114
  wireChannel({
91
115
  name: '${finalChannelName}',
92
116
  route: '${finalChannelRoute}',
93
117
  auth: false,
94
118
  onMessageWiring: {
95
119
  command: {
96
- ${commandEntries}
120
+ ${Object.entries(commandMap)
121
+ .map(
122
+ ([commandKey, { pikkuFuncName }]) =>
123
+ ` '${commandKey}': {
124
+ func: ${pikkuFuncName},
125
+ middleware: [cliCloseOnComplete],
126
+ }`
127
+ )
128
+ .join(',\n')}
97
129
  }
98
130
  },
99
131
  tags: ['cli', '${programName}']
@@ -30,6 +30,28 @@ ${userSessionTypeName !== 'Session' ? `type Session = ${userSessionTypeName}` :
30
30
  */
31
31
  type PikkuCLIRender<Data, RequiredServices extends SingletonServices = SingletonServices> = CorePikkuCLIRender<Data, RequiredServices, Session>
32
32
 
33
+ /**
34
+ * Creates a type-safe CLI renderer with access to your application's singleton services.
35
+ * The renderer receives the full singleton services and output data to format and display results.
36
+ *
37
+ * @template Data - The output data type from the CLI command
38
+ * @template RequiredServices - The minimum services required for type checking (defaults to SingletonServices)
39
+ * @param render - Function that receives singleton services and data to render output
40
+ * @returns A CLI renderer configuration
41
+ *
42
+ * @example
43
+ * \`\`\`typescript
44
+ * const myRenderer = pikkuCLIRender<MyData>(({ logger }, data) => {
45
+ * logger.info(data.message)
46
+ * })
47
+ * \`\`\`
48
+ */
49
+ export const pikkuCLIRender = <Data, RequiredServices extends SingletonServices = SingletonServices>(
50
+ render: (services: SingletonServices, data: Data) => void | Promise<void>
51
+ ): PikkuCLIRender<Data, RequiredServices> => {
52
+ return render as any
53
+ }
54
+
33
55
  /**
34
56
  * CLI command configuration with project-specific types.
35
57
  * Uses CoreCLICommandConfig from @pikku/core with local middleware and render types.