@pikku/cli 0.7.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/bin/pikku-all.ts +203 -0
  3. package/bin/pikku-channels-map.ts +55 -0
  4. package/bin/pikku-channels.ts +63 -0
  5. package/bin/pikku-fetch.ts +55 -0
  6. package/bin/pikku-function-types.ts +84 -0
  7. package/bin/pikku-functions.ts +35 -0
  8. package/bin/pikku-http-map.ts +55 -0
  9. package/bin/pikku-http-routes.ts +63 -0
  10. package/bin/pikku-nextjs.test.ts +279 -0
  11. package/bin/pikku-nextjs.ts +152 -0
  12. package/bin/pikku-openapi.ts +74 -0
  13. package/bin/pikku-rpc.ts +22 -0
  14. package/bin/pikku-scheduler.ts +64 -0
  15. package/bin/pikku-schemas.ts +56 -0
  16. package/bin/pikku-websocket.ts +58 -0
  17. package/bin/pikku.ts +26 -0
  18. package/dist/bin/pikku-all.js +3 -0
  19. package/dist/bin/pikku-functions.d.ts +0 -2
  20. package/dist/bin/pikku-functions.js +2 -17
  21. package/dist/bin/pikku-rpc.d.ts +3 -0
  22. package/dist/bin/pikku-rpc.js +8 -0
  23. package/dist/bin/pikku.js +0 -0
  24. package/dist/src/pikku-cli-config.d.ts +1 -0
  25. package/dist/src/pikku-cli-config.js +3 -0
  26. package/dist/src/schema-generator.js +1 -2
  27. package/dist/tsconfig.tsbuildinfo +1 -0
  28. package/package.json +3 -3
  29. package/src/inspector-glob.ts +28 -0
  30. package/src/openapi-spec-generator.ts +227 -0
  31. package/src/pikku-cli-config.ts +240 -0
  32. package/src/schema-generator.ts +136 -0
  33. package/{dist/src/events/http/serialize-fetch-wrapper.js → src/serialize-fetch-wrapper.ts} +4 -4
  34. package/src/serialize-import-map.ts +34 -0
  35. package/{dist/src/nextjs/serialize-nextjs-backend-wrapper.js → src/serialize-nextjs-backend-wrapper.ts} +11 -4
  36. package/{dist/src/nextjs/serialize-nextjs-http-wrapper.js → src/serialize-nextjs-http-wrapper.ts} +7 -4
  37. package/{dist/src/core/serialize-pikku-types.js → src/serialize-pikku-types.ts} +46 -35
  38. package/src/serialize-scheduler-meta.ts +18 -0
  39. package/src/serialize-typed-channel-map.ts +138 -0
  40. package/src/serialize-typed-function-map.ts +151 -0
  41. package/src/serialize-typed-http-map.ts +151 -0
  42. package/{dist/src/channels/serialize-websocket-wrapper.js → src/serialize-websocket-wrapper.ts} +4 -4
  43. package/src/utils.ts +284 -0
  44. package/tsconfig.json +21 -0
  45. package/dist/bin/pikku-http.d.ts +0 -5
  46. package/dist/bin/pikku-http.js +0 -27
  47. package/dist/bin/pikku-routes-map.d.ts +0 -5
  48. package/dist/bin/pikku-routes-map.js +0 -23
  49. package/dist/src/channels/serialize-channels.d.ts +0 -3
  50. package/dist/src/channels/serialize-channels.js +0 -19
  51. package/dist/src/channels/serialize-typed-channel-map.d.ts +0 -3
  52. package/dist/src/channels/serialize-typed-channel-map.js +0 -93
  53. package/dist/src/channels/serialize-websocket-wrapper.d.ts +0 -1
  54. package/dist/src/core/serialize-import-map.d.ts +0 -2
  55. package/dist/src/core/serialize-import-map.js +0 -24
  56. package/dist/src/core/serialize-pikku-types.d.ts +0 -4
  57. package/dist/src/events/channels/serialize-channels.d.ts +0 -3
  58. package/dist/src/events/channels/serialize-channels.js +0 -19
  59. package/dist/src/events/channels/serialize-typed-channel-map.d.ts +0 -3
  60. package/dist/src/events/channels/serialize-typed-channel-map.js +0 -90
  61. package/dist/src/events/channels/serialize-websocket-wrapper.d.ts +0 -1
  62. package/dist/src/events/channels/serialize-websocket-wrapper.js +0 -61
  63. package/dist/src/events/http/serialize-fetch-wrapper.d.ts +0 -1
  64. package/dist/src/events/http/serialize-route-imports.d.ts +0 -1
  65. package/dist/src/events/http/serialize-route-imports.js +0 -13
  66. package/dist/src/events/http/serialize-route-meta.d.ts +0 -2
  67. package/dist/src/events/http/serialize-route-meta.js +0 -6
  68. package/dist/src/events/http/serialize-typed-route-map.d.ts +0 -4
  69. package/dist/src/events/http/serialize-typed-route-map.js +0 -107
  70. package/dist/src/events/scheduler/serialize-schedulers.d.ts +0 -3
  71. package/dist/src/events/scheduler/serialize-schedulers.js +0 -23
  72. package/dist/src/http/serialize-fetch-wrapper.d.ts +0 -1
  73. package/dist/src/http/serialize-fetch-wrapper.js +0 -67
  74. package/dist/src/http/serialize-route-imports.d.ts +0 -1
  75. package/dist/src/http/serialize-route-imports.js +0 -13
  76. package/dist/src/http/serialize-route-meta.d.ts +0 -2
  77. package/dist/src/http/serialize-route-meta.js +0 -6
  78. package/dist/src/http/serialize-typed-route-map.d.ts +0 -4
  79. package/dist/src/http/serialize-typed-route-map.js +0 -107
  80. package/dist/src/nextjs/serialize-nextjs-backend-wrapper.d.ts +0 -1
  81. package/dist/src/nextjs/serialize-nextjs-http-wrapper.d.ts +0 -1
  82. package/dist/src/openapi/openapi-spec-generator.d.ts +0 -79
  83. package/dist/src/openapi/openapi-spec-generator.js +0 -136
  84. package/dist/src/scheduler/serialize-schedulers.d.ts +0 -3
  85. package/dist/src/scheduler/serialize-schedulers.js +0 -23
  86. package/dist/src/schema/schema-generator.d.ts +0 -5
  87. package/dist/src/schema/schema-generator.js +0 -89
  88. package/dist/src/serialize-typed-route-map.d.ts +0 -4
  89. package/dist/src/serialize-typed-route-map.js +0 -107
@@ -0,0 +1,138 @@
1
+ import { ChannelsMeta } from '@pikku/core/channel'
2
+ import { serializeImportMap } from './serialize-import-map.js'
3
+ import { TypesMap } from '@pikku/inspector'
4
+ import { generateCustomTypes } from './serialize-typed-http-map.js'
5
+
6
+ export const serializeTypedChannelsMap = (
7
+ relativeToPath: string,
8
+ packageMappings: Record<string, string>,
9
+ typesMap: TypesMap,
10
+ channelsMeta: ChannelsMeta
11
+ ): string => {
12
+ const { channels, requiredTypes } = generateChannels(channelsMeta)
13
+ typesMap.customTypes.forEach(({ references }) => {
14
+ for (const reference of references) {
15
+ requiredTypes.add(reference)
16
+ }
17
+ })
18
+ const imports = serializeImportMap(
19
+ relativeToPath,
20
+ packageMappings,
21
+ typesMap,
22
+ requiredTypes
23
+ )
24
+ const serializedCustomTypes = generateCustomTypes(typesMap, requiredTypes)
25
+ return `/**
26
+ * This provides the structure needed for TypeScript to be aware of channels
27
+ */
28
+
29
+ ${imports}
30
+ ${serializedCustomTypes}
31
+
32
+ interface ChannelHandler<I, O> {
33
+ input: I;
34
+ output: O;
35
+ }
36
+
37
+ ${channels}
38
+
39
+ export type ChannelDefaultHandlerOf<Channel extends keyof ChannelsMap> =
40
+ ChannelsMap[Channel]['defaultMessage'] extends { input: infer I; output: infer O }
41
+ ? ChannelHandler<I, O>
42
+ : never;
43
+
44
+ export type ChannelRouteHandlerOf<
45
+ Channel extends keyof ChannelsMap,
46
+ Route extends keyof ChannelsMap[Channel]['routes'],
47
+ Method extends keyof ChannelsMap[Channel]['routes'][Route],
48
+ > =
49
+ ChannelsMap[Channel]['routes'][Route][Method] extends { input: infer I; output: infer O }
50
+ ? ChannelHandler<I, O>
51
+ : never;
52
+ `
53
+ }
54
+
55
+ function generateChannels(channelsMeta: ChannelsMeta) {
56
+ const requiredTypes = new Set<string>()
57
+ const channelsObject: Record<
58
+ string,
59
+ {
60
+ message: { inputs: string[] | null; outputs: string[] | null } | null
61
+ routes: Record<
62
+ string,
63
+ Record<
64
+ string,
65
+ {
66
+ inputTypes: string[] | null
67
+ outputTypes: string[] | null
68
+ }
69
+ >
70
+ >
71
+ }
72
+ > = {}
73
+
74
+ for (const meta of Object.values(channelsMeta)) {
75
+ const { name, messageRoutes, message } = meta
76
+
77
+ if (!channelsObject[name]) {
78
+ channelsObject[name] = { message, routes: {} }
79
+ }
80
+
81
+ for (const [key, route] of Object.entries(messageRoutes)) {
82
+ if (!channelsObject[name].routes[key]) {
83
+ channelsObject[name].routes[key] = {}
84
+ }
85
+ for (const [method, { inputs, outputs }] of Object.entries(route)) {
86
+ const inputTypes = inputs || null
87
+ const outputTypes = outputs || null
88
+ channelsObject[name].routes[key][method] = {
89
+ inputTypes,
90
+ outputTypes,
91
+ }
92
+ inputTypes?.forEach((type) => requiredTypes.add(type))
93
+ outputTypes?.forEach((type) => requiredTypes.add(type))
94
+ }
95
+ }
96
+ }
97
+
98
+ let routesStr = 'export type ChannelsMap = {\n'
99
+
100
+ for (const [channelPath, { routes, message }] of Object.entries(
101
+ channelsObject
102
+ )) {
103
+ routesStr += ` readonly '${channelPath}': {\n`
104
+
105
+ // Add `routes` object
106
+ routesStr += ` readonly routes: {\n`
107
+ for (const [key, methods] of Object.entries(routes)) {
108
+ routesStr += ` readonly ${key}: {\n`
109
+ for (const [method, handler] of Object.entries(methods)) {
110
+ routesStr += ` readonly ${method}: ChannelHandler<${
111
+ formatTypeArray(handler.inputTypes) || 'void'
112
+ }, ${formatTypeArray(handler.outputTypes) || 'never'}>,\n`
113
+ }
114
+ routesStr += ' },\n'
115
+ }
116
+ routesStr += ' },\n'
117
+
118
+ // Add `defaultMessage` outside `routes`
119
+ if (message) {
120
+ routesStr += ` readonly defaultMessage: ChannelHandler<${formatTypeArray(
121
+ message.inputs
122
+ )}, ${formatTypeArray(message.outputs)}>,\n`
123
+ } else {
124
+ routesStr += ` readonly defaultMessage: never,\n`
125
+ }
126
+
127
+ routesStr += ' },\n'
128
+ }
129
+
130
+ routesStr += '};'
131
+
132
+ return { channels: routesStr, requiredTypes }
133
+ }
134
+
135
+ // Utility to format type arrays
136
+ function formatTypeArray(types: string[] | null): string {
137
+ return types ? types.join(' | ') : 'null'
138
+ }
@@ -0,0 +1,151 @@
1
+ import { HTTPRoutesMeta } from '@pikku/core/http'
2
+ import { serializeImportMap } from './serialize-import-map.js'
3
+ import { MetaInputTypes, TypesMap } from '@pikku/inspector'
4
+
5
+ export const serializeTypedRoutesMap = (
6
+ relativeToPath: string,
7
+ packageMappings: Record<string, string>,
8
+ typesMap: TypesMap,
9
+ routesMeta: HTTPRoutesMeta,
10
+ metaTypes: MetaInputTypes
11
+ ) => {
12
+ const requiredTypes = new Set<string>()
13
+ const serializedCustomTypes = generateCustomTypes(typesMap, requiredTypes)
14
+ const serializedMetaTypes = generateMetaTypes(metaTypes, typesMap)
15
+ const serializedRoutes = generateRoutes(routesMeta, typesMap, requiredTypes)
16
+
17
+ const serializedImportMap = serializeImportMap(
18
+ relativeToPath,
19
+ packageMappings,
20
+ typesMap,
21
+ requiredTypes
22
+ )
23
+
24
+ return `/**
25
+ * This provides the structure needed for typescript to be aware of routes and their return types
26
+ */
27
+
28
+ ${serializedImportMap}
29
+ ${serializedCustomTypes}
30
+ ${serializedMetaTypes}
31
+
32
+ interface RouteHandler<I, O> {
33
+ input: I;
34
+ output: O;
35
+ }
36
+
37
+ ${serializedRoutes}
38
+
39
+ export type RouteHandlerOf<Route extends keyof RoutesMap, Method extends keyof RoutesMap[Route]> =
40
+ RoutesMap[Route][Method] extends { input: infer I; output: infer O }
41
+ ? RouteHandler<I, O>
42
+ : never;
43
+
44
+ export type RoutesWithMethod<Method extends string> = {
45
+ [Route in keyof RoutesMap]: Method extends keyof RoutesMap[Route] ? Route : never;
46
+ }[keyof RoutesMap];
47
+ `
48
+ }
49
+
50
+ export function generateCustomTypes(
51
+ typesMap: TypesMap,
52
+ requiredTypes: Set<string>
53
+ ) {
54
+ return `
55
+ // Custom types are those that are defined directly within generics
56
+ // or are broken into simpler types
57
+ ${Array.from(typesMap.customTypes.entries())
58
+ .map(([name, { type, references }]) => {
59
+ references.forEach((name) => {
60
+ const originalName = typesMap.getTypeMeta(name).originalName
61
+ requiredTypes.add(originalName)
62
+ })
63
+ return `export type ${name} = ${type}`
64
+ })
65
+ .join('\n')}`
66
+ }
67
+
68
+ function generateRoutes(
69
+ routesMeta: HTTPRoutesMeta,
70
+ typesMap: TypesMap,
71
+ requiredTypes: Set<string>
72
+ ) {
73
+ // Initialize an object to collect routes
74
+ const routesObj: Record<
75
+ string,
76
+ Record<string, { inputType: string; outputType: string }>
77
+ > = {}
78
+
79
+ for (const meta of routesMeta) {
80
+ const { route, method, input, output } = meta
81
+
82
+ // Initialize the route entry if it doesn't exist
83
+ if (!routesObj[route]) {
84
+ routesObj[route] = {}
85
+ }
86
+
87
+ // Store the input and output types separately for RouteHandler
88
+ const inputType = input ? typesMap.getTypeMeta(input).uniqueName : 'null'
89
+ const outputType = output ? typesMap.getTypeMeta(output).uniqueName : 'null'
90
+
91
+ requiredTypes.add(inputType)
92
+ requiredTypes.add(outputType)
93
+
94
+ // Add method entry
95
+ routesObj[route][method] = {
96
+ inputType,
97
+ outputType,
98
+ }
99
+ }
100
+
101
+ // Build the routes object as a string
102
+ let routesStr = 'export type RoutesMap = {\n'
103
+
104
+ for (const [routePath, methods] of Object.entries(routesObj)) {
105
+ routesStr += ` readonly '${routePath}': {\n`
106
+ for (const [method, handler] of Object.entries(methods)) {
107
+ routesStr += ` readonly ${method.toUpperCase()}: RouteHandler<${handler.inputType}, ${handler.outputType}>,\n`
108
+ }
109
+ routesStr += ' },\n'
110
+ }
111
+
112
+ routesStr += '};'
113
+
114
+ return routesStr
115
+ }
116
+
117
+ const generateMetaTypes = (metaTypes: MetaInputTypes, typesMap: TypesMap) => {
118
+ const nameToTypeMap = Array.from(metaTypes.entries()).reduce<
119
+ Map<string, string>
120
+ >((result, [_name, { query, body, params }]) => {
121
+ const { uniqueName } = typesMap.getTypeMeta(_name)
122
+ const queryType =
123
+ query && query.length > 0
124
+ ? `Pick<${uniqueName}, '${query?.join("' | '")}'>`
125
+ : undefined
126
+ if (queryType) {
127
+ result.set(`${uniqueName}Query`, queryType)
128
+ }
129
+ const paramsType =
130
+ params && params.length > 0
131
+ ? `Pick<${uniqueName}, '${params.join("' | '")}'>`
132
+ : undefined
133
+ if (paramsType) {
134
+ result.set(`${uniqueName}Params`, paramsType)
135
+ }
136
+ const bodyType =
137
+ (body && body.length > 0) || (params && params.length > 0)
138
+ ? `Omit<${uniqueName}, '${[...new Set([...(query || []), ...(params || [])])].join("' | '")}'>`
139
+ : uniqueName!
140
+ if (bodyType) {
141
+ result.set(`${uniqueName}Body`, bodyType)
142
+ }
143
+ return result
144
+ }, new Map())
145
+
146
+ return `
147
+ // The '& {}' is a workaround for not directly refering to a type since it confuses typescript
148
+ ${Array.from(nameToTypeMap.entries())
149
+ .map(([name, type]) => `export type ${name} = ${type} & {}`)
150
+ .join('\n')}`
151
+ }
@@ -0,0 +1,151 @@
1
+ import { HTTPRoutesMeta } from '@pikku/core/http'
2
+ import { serializeImportMap } from './serialize-import-map.js'
3
+ import { MetaInputTypes, TypesMap } from '@pikku/inspector'
4
+
5
+ export const serializeTypedRoutesMap = (
6
+ relativeToPath: string,
7
+ packageMappings: Record<string, string>,
8
+ typesMap: TypesMap,
9
+ routesMeta: HTTPRoutesMeta,
10
+ metaTypes: MetaInputTypes
11
+ ) => {
12
+ const requiredTypes = new Set<string>()
13
+ const serializedCustomTypes = generateCustomTypes(typesMap, requiredTypes)
14
+ const serializedMetaTypes = generateMetaTypes(metaTypes, typesMap)
15
+ const serializedRoutes = generateRoutes(routesMeta, typesMap, requiredTypes)
16
+
17
+ const serializedImportMap = serializeImportMap(
18
+ relativeToPath,
19
+ packageMappings,
20
+ typesMap,
21
+ requiredTypes
22
+ )
23
+
24
+ return `/**
25
+ * This provides the structure needed for typescript to be aware of routes and their return types
26
+ */
27
+
28
+ ${serializedImportMap}
29
+ ${serializedCustomTypes}
30
+ ${serializedMetaTypes}
31
+
32
+ interface RouteHandler<I, O> {
33
+ input: I;
34
+ output: O;
35
+ }
36
+
37
+ ${serializedRoutes}
38
+
39
+ export type RouteHandlerOf<Route extends keyof RoutesMap, Method extends keyof RoutesMap[Route]> =
40
+ RoutesMap[Route][Method] extends { input: infer I; output: infer O }
41
+ ? RouteHandler<I, O>
42
+ : never;
43
+
44
+ export type RoutesWithMethod<Method extends string> = {
45
+ [Route in keyof RoutesMap]: Method extends keyof RoutesMap[Route] ? Route : never;
46
+ }[keyof RoutesMap];
47
+ `
48
+ }
49
+
50
+ export function generateCustomTypes(
51
+ typesMap: TypesMap,
52
+ requiredTypes: Set<string>
53
+ ) {
54
+ return `
55
+ // Custom types are those that are defined directly within generics
56
+ // or are broken into simpler types
57
+ ${Array.from(typesMap.customTypes.entries())
58
+ .map(([name, { type, references }]) => {
59
+ references.forEach((name) => {
60
+ const originalName = typesMap.getTypeMeta(name).originalName
61
+ requiredTypes.add(originalName)
62
+ })
63
+ return `export type ${name} = ${type}`
64
+ })
65
+ .join('\n')}`
66
+ }
67
+
68
+ function generateRoutes(
69
+ routesMeta: HTTPRoutesMeta,
70
+ typesMap: TypesMap,
71
+ requiredTypes: Set<string>
72
+ ) {
73
+ // Initialize an object to collect routes
74
+ const routesObj: Record<
75
+ string,
76
+ Record<string, { inputType: string; outputType: string }>
77
+ > = {}
78
+
79
+ for (const meta of routesMeta) {
80
+ const { route, method, input, output } = meta
81
+
82
+ // Initialize the route entry if it doesn't exist
83
+ if (!routesObj[route]) {
84
+ routesObj[route] = {}
85
+ }
86
+
87
+ // Store the input and output types separately for RouteHandler
88
+ const inputType = input ? typesMap.getTypeMeta(input).uniqueName : 'null'
89
+ const outputType = output ? typesMap.getTypeMeta(output).uniqueName : 'null'
90
+
91
+ requiredTypes.add(inputType)
92
+ requiredTypes.add(outputType)
93
+
94
+ // Add method entry
95
+ routesObj[route][method] = {
96
+ inputType,
97
+ outputType,
98
+ }
99
+ }
100
+
101
+ // Build the routes object as a string
102
+ let routesStr = 'export type RoutesMap = {\n'
103
+
104
+ for (const [routePath, methods] of Object.entries(routesObj)) {
105
+ routesStr += ` readonly '${routePath}': {\n`
106
+ for (const [method, handler] of Object.entries(methods)) {
107
+ routesStr += ` readonly ${method.toUpperCase()}: RouteHandler<${handler.inputType}, ${handler.outputType}>,\n`
108
+ }
109
+ routesStr += ' },\n'
110
+ }
111
+
112
+ routesStr += '};'
113
+
114
+ return routesStr
115
+ }
116
+
117
+ const generateMetaTypes = (metaTypes: MetaInputTypes, typesMap: TypesMap) => {
118
+ const nameToTypeMap = Array.from(metaTypes.entries()).reduce<
119
+ Map<string, string>
120
+ >((result, [_name, { query, body, params }]) => {
121
+ const { uniqueName } = typesMap.getTypeMeta(_name)
122
+ const queryType =
123
+ query && query.length > 0
124
+ ? `Pick<${uniqueName}, '${query?.join("' | '")}'>`
125
+ : undefined
126
+ if (queryType) {
127
+ result.set(`${uniqueName}Query`, queryType)
128
+ }
129
+ const paramsType =
130
+ params && params.length > 0
131
+ ? `Pick<${uniqueName}, '${params.join("' | '")}'>`
132
+ : undefined
133
+ if (paramsType) {
134
+ result.set(`${uniqueName}Params`, paramsType)
135
+ }
136
+ const bodyType =
137
+ (body && body.length > 0) || (params && params.length > 0)
138
+ ? `Omit<${uniqueName}, '${[...new Set([...(query || []), ...(params || [])])].join("' | '")}'>`
139
+ : uniqueName!
140
+ if (bodyType) {
141
+ result.set(`${uniqueName}Body`, bodyType)
142
+ }
143
+ return result
144
+ }, new Map())
145
+
146
+ return `
147
+ // The '& {}' is a workaround for not directly refering to a type since it confuses typescript
148
+ ${Array.from(nameToTypeMap.entries())
149
+ .map(([name, type]) => `export type ${name} = ${type} & {}`)
150
+ .join('\n')}`
151
+ }
@@ -1,5 +1,5 @@
1
- export const serializeWebsocketWrapper = (channelsMapPath) => {
2
- return `import { CorePikkuWebsocket, CorePikkuRouteHandler } from '@pikku/websocket'
1
+ export const serializeWebsocketWrapper = (channelsMapPath: string) => {
2
+ return `import { CorePikkuWebsocket, CorePikkuRouteHandler } from '@pikku/websocket'
3
3
  import { ChannelDefaultHandlerOf, ChannelRouteHandlerOf, ChannelsMap } from '${channelsMapPath}';
4
4
 
5
5
  class PikkuWebSocketRoute<Channel extends keyof ChannelsMap, Route extends keyof ChannelsMap[Channel]['routes']> extends CorePikkuRouteHandler {
@@ -57,5 +57,5 @@ export class PikkuWebSocket<Channel extends keyof ChannelsMap> extends CorePikku
57
57
  super.send(data)
58
58
  }
59
59
  }
60
- `;
61
- };
60
+ `
61
+ }