@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
@@ -1,136 +0,0 @@
1
- import { pikkuState } from '@pikku/core';
2
- import _convertSchema from '@openapi-contrib/json-schema-to-openapi-schema';
3
- const convertSchema = 'default' in _convertSchema ? _convertSchema.default : _convertSchema;
4
- const getErrorResponseForConstructorName = (constructorName) => {
5
- const errors = Array.from(pikkuState('misc', 'errors').entries());
6
- const foundError = errors.find(([e]) => e.name === constructorName);
7
- if (foundError) {
8
- return foundError[1];
9
- }
10
- return undefined;
11
- };
12
- const convertSchemasToBodyPayloads = async (routesMeta, schemas) => {
13
- const requiredSchemas = new Set(routesMeta
14
- .map(({ inputTypes, output }) => [inputTypes?.body, output])
15
- .flat()
16
- .filter((schema) => !!schema));
17
- const convertedEntries = await Promise.all(Object.entries(schemas).map(async ([key, schema]) => {
18
- if (requiredSchemas.has(key)) {
19
- const convertedSchema = await convertSchema(schema, {
20
- convertUnreferencedDefinitions: false,
21
- dereference: { circular: 'ignore' },
22
- });
23
- return [key, convertedSchema];
24
- }
25
- return;
26
- }));
27
- return Object.fromEntries(convertedEntries.filter((s) => !!s));
28
- };
29
- export async function generateOpenAPISpec(routeMeta, schemas, additionalInfo) {
30
- const paths = {};
31
- routeMeta.forEach((meta) => {
32
- const { route, method, inputTypes, output, params, query, docs } = meta;
33
- const path = route.replace(/:(\w+)/g, '{$1}'); // Convert ":param" to "{param}"
34
- if (!paths[path]) {
35
- paths[path] = {};
36
- }
37
- const responses = {};
38
- docs?.errors?.forEach((error) => {
39
- const errorResponse = getErrorResponseForConstructorName(error);
40
- if (errorResponse) {
41
- responses[errorResponse.status] = {
42
- description: errorResponse.message,
43
- };
44
- }
45
- });
46
- const operation = {
47
- description: docs?.description ||
48
- `This endpoint handles the ${method.toUpperCase()} request for the route ${route}.`,
49
- tags: docs?.tags || [route.split('/')[1] || 'default'],
50
- parameters: [],
51
- responses: {
52
- ...responses,
53
- '200': {
54
- description: 'Successful response',
55
- content: output
56
- ? {
57
- 'application/json': {
58
- schema: typeof output === 'string' &&
59
- ['boolean', 'string', 'number'].includes(output)
60
- ? { type: output }
61
- : { $ref: `#/components/schemas/${output}` },
62
- },
63
- }
64
- : undefined,
65
- },
66
- },
67
- };
68
- const bodyType = inputTypes?.body;
69
- if (bodyType) {
70
- operation.requestBody = {
71
- required: true,
72
- content: {
73
- 'application/json': {
74
- schema: typeof bodyType === 'string' &&
75
- ['boolean', 'string', 'number'].includes(bodyType)
76
- ? { type: bodyType }
77
- : { $ref: `#/components/schemas/${bodyType}` },
78
- },
79
- },
80
- };
81
- }
82
- if (params) {
83
- operation.parameters = params.map((param) => ({
84
- name: param,
85
- in: 'path',
86
- required: true,
87
- schema: { type: 'string' },
88
- }));
89
- }
90
- if (query) {
91
- operation.parameters.push(...query.map((query) => ({
92
- name: query,
93
- in: 'query',
94
- required: false,
95
- schema: { type: 'string' },
96
- })));
97
- }
98
- paths[path][method] = operation;
99
- });
100
- return {
101
- openapi: '3.1.0',
102
- info: additionalInfo.info,
103
- servers: additionalInfo.servers,
104
- paths,
105
- components: {
106
- schemas: await convertSchemasToBodyPayloads(routeMeta, schemas),
107
- responses: {},
108
- parameters: {},
109
- examples: {},
110
- requestBodies: {},
111
- headers: {},
112
- securitySchemes: additionalInfo.securitySchemes || {
113
- ApiKeyAuth: {
114
- type: 'apiKey',
115
- in: 'header',
116
- name: 'x-api-key',
117
- },
118
- BearerAuth: {
119
- type: 'http',
120
- scheme: 'bearer',
121
- },
122
- },
123
- },
124
- security: additionalInfo.security || [
125
- {
126
- ApiKeyAuth: [],
127
- },
128
- {
129
- BearerAuth: [],
130
- },
131
- ],
132
- tags: additionalInfo.tags,
133
- externalDocs: additionalInfo.externalDocs,
134
- // definitions
135
- };
136
- }
@@ -1,3 +0,0 @@
1
- import { ScheduledTasksMeta } from '@pikku/core/scheduler';
2
- export declare const serializeSchedulers: (outputPath: string, filesWithScheduledTasks: Set<string>, packageMappings?: Record<string, string>) => string;
3
- export declare const serializeSchedulerMeta: (scheduledTasksMeta: ScheduledTasksMeta) => string;
@@ -1,23 +0,0 @@
1
- import { getFileImportRelativePath } from '../utils.js';
2
- export const serializeSchedulers = (outputPath, filesWithScheduledTasks, packageMappings = {}) => {
3
- const serializedOutput = [
4
- '/* The files with an addSerializedTasks function call */',
5
- ];
6
- Array.from(filesWithScheduledTasks)
7
- .sort()
8
- .forEach((path) => {
9
- const filePath = getFileImportRelativePath(outputPath, path, packageMappings);
10
- serializedOutput.push(`import '${filePath}'`);
11
- });
12
- return serializedOutput.join('\n');
13
- };
14
- export const serializeSchedulerMeta = (scheduledTasksMeta) => {
15
- const serializedOutput = [];
16
- serializedOutput.push("import { pikkuState } from '@pikku/core'");
17
- serializedOutput.push(`pikkuState('scheduler', 'meta', ${JSON.stringify(scheduledTasksMeta, null, 2)})`);
18
- const scheduledTasksMetaValues = Object.values(scheduledTasksMeta);
19
- if (scheduledTasksMetaValues.length > 0) {
20
- serializedOutput.push(`export type ScheduledTaskNames = '${scheduledTasksMetaValues.map((s) => s.name).join("' | '")}'`);
21
- }
22
- return serializedOutput.join('\n');
23
- };
@@ -1,5 +0,0 @@
1
- import { JSONValue } from '@pikku/core';
2
- import { HTTPRoutesMeta } from '@pikku/core/http';
3
- import { TypesMap } from '@pikku/inspector';
4
- export declare function generateSchemas(tsconfig: string, typesMaps: TypesMap[], httpRoutesMeta: HTTPRoutesMeta): Promise<Record<string, JSONValue>>;
5
- export declare function saveSchemas(schemaParentDir: string, schemas: Record<string, JSONValue>, typesMap: TypesMap, routesMeta: HTTPRoutesMeta, supportsImportAttributes: boolean): Promise<void>;
@@ -1,89 +0,0 @@
1
- import { createGenerator, RootlessError } from 'ts-json-schema-generator';
2
- import { logInfo, writeFileInDir } from '../utils.js';
3
- import { mkdir, writeFile } from 'fs/promises';
4
- export async function generateSchemas(tsconfig, typesMaps, httpRoutesMeta) {
5
- const schemasSet = new Set(typesMaps.flatMap((tm) => [...tm.customTypes.keys()]));
6
- for (const { input, inputTypes } of httpRoutesMeta) {
7
- if (input) {
8
- for (const typesMap of typesMaps) {
9
- const uniqueName = typesMap.getUniqueName(input);
10
- if (uniqueName) {
11
- schemasSet.add(uniqueName);
12
- break;
13
- }
14
- }
15
- }
16
- // if (output) {
17
- // for (const typesMap of typesMaps) {
18
- // const uniqueName = typesMap.getUniqueName(output)
19
- // if (uniqueName) {
20
- // console.log('Adding output schema:', uniqueName)
21
- // schemasSet.add(uniqueName)
22
- // break
23
- // }
24
- // }
25
- // }
26
- if (inputTypes?.body) {
27
- schemasSet.add(inputTypes.body);
28
- }
29
- if (inputTypes?.query) {
30
- schemasSet.add(inputTypes.query);
31
- }
32
- if (inputTypes?.params) {
33
- schemasSet.add(inputTypes.params);
34
- }
35
- }
36
- const generator = createGenerator({
37
- tsconfig,
38
- skipTypeCheck: true,
39
- topRef: false,
40
- discriminatorType: 'open-api',
41
- });
42
- const schemas = {};
43
- schemasSet.forEach((schema) => {
44
- try {
45
- schemas[schema] = generator.createSchema(schema);
46
- }
47
- catch (e) {
48
- // Ignore rootless errors
49
- if (e instanceof RootlessError) {
50
- console.error('Error generating schema since it has no root:', schema);
51
- return;
52
- }
53
- throw e;
54
- }
55
- });
56
- return schemas;
57
- }
58
- export async function saveSchemas(schemaParentDir, schemas, typesMap, routesMeta, supportsImportAttributes) {
59
- await writeFileInDir(`${schemaParentDir}/register.gen.ts`, 'export const empty = null;');
60
- const desiredSchemas = new Set([
61
- ...routesMeta
62
- .map(({ input, output }) => [
63
- input ? typesMap.getUniqueName(input) : undefined,
64
- output ? typesMap.getUniqueName(output) : undefined,
65
- ])
66
- .flat()
67
- .filter((s) => !!s &&
68
- !['boolean', 'string', 'number', 'null', 'undefined'].includes(s)),
69
- ...typesMap.customTypes.keys(),
70
- ]);
71
- if (desiredSchemas.size === 0) {
72
- logInfo(`• Skipping schemas since none found.\x1b[0m`);
73
- return;
74
- }
75
- await mkdir(`${schemaParentDir}/schemas`, { recursive: true });
76
- await Promise.all(Object.entries(schemas).map(async ([schemaName, schema]) => {
77
- if (desiredSchemas.has(schemaName)) {
78
- await writeFile(`${schemaParentDir}/schemas/${schemaName}.schema.json`, JSON.stringify(schema), 'utf-8');
79
- }
80
- }));
81
- const schemaImports = Array.from(desiredSchemas)
82
- .map((schema) => `
83
- import * as ${schema} from './schemas/${schema}.schema.json' ${supportsImportAttributes ? `with { type: 'json' }` : ''}
84
- addSchema('${schema}', ${schema})
85
- `)
86
- .join('\n');
87
- await writeFileInDir(`${schemaParentDir}/register.gen.ts`, `import { addSchema } from '@pikku/core/schema'
88
- ${schemaImports}`);
89
- }
@@ -1,4 +0,0 @@
1
- import { HTTPRoutesMeta } from '@pikku/core/http';
2
- import { MetaInputTypes, TypesMap } from '@pikku/inspector';
3
- export declare const serializeTypedRoutesMap: (relativeToPath: string, packageMappings: Record<string, string>, typesMap: TypesMap, routesMeta: HTTPRoutesMeta, metaTypes: MetaInputTypes) => string;
4
- export declare function generateCustomTypes(typesMap: TypesMap, requiredTypes: Set<string>): string;
@@ -1,107 +0,0 @@
1
- import { serializeImportMap } from './serialize-import-map.js';
2
- export const serializeTypedRoutesMap = (relativeToPath, packageMappings, typesMap, routesMeta, metaTypes) => {
3
- const requiredTypes = new Set();
4
- const serializedCustomTypes = generateCustomTypes(typesMap, requiredTypes);
5
- const serializedMetaTypes = generateMetaTypes(metaTypes, typesMap);
6
- const serializedRoutes = generateRoutes(routesMeta, typesMap, requiredTypes);
7
- const serializedImportMap = serializeImportMap(relativeToPath, packageMappings, typesMap, requiredTypes);
8
- return `/**
9
- * This provides the structure needed for typescript to be aware of routes and their return types
10
- */
11
-
12
- ${serializedImportMap}
13
- ${serializedCustomTypes}
14
- ${serializedMetaTypes}
15
-
16
- interface RouteHandler<I, O> {
17
- input: I;
18
- output: O;
19
- }
20
-
21
- ${serializedRoutes}
22
-
23
- export type RouteHandlerOf<Route extends keyof RoutesMap, Method extends keyof RoutesMap[Route]> =
24
- RoutesMap[Route][Method] extends { input: infer I; output: infer O }
25
- ? RouteHandler<I, O>
26
- : never;
27
-
28
- export type RoutesWithMethod<Method extends string> = {
29
- [Route in keyof RoutesMap]: Method extends keyof RoutesMap[Route] ? Route : never;
30
- }[keyof RoutesMap];
31
- `;
32
- };
33
- export function generateCustomTypes(typesMap, requiredTypes) {
34
- return `
35
- // Custom types are those that are defined directly within generics
36
- // or are broken into simpler types
37
- ${Array.from(typesMap.customTypes.entries())
38
- .map(([name, { type, references }]) => {
39
- references.forEach((name) => {
40
- const originalName = typesMap.getTypeMeta(name).originalName;
41
- requiredTypes.add(originalName);
42
- });
43
- return `export type ${name} = ${type}`;
44
- })
45
- .join('\n')}`;
46
- }
47
- function generateRoutes(routesMeta, typesMap, requiredTypes) {
48
- // Initialize an object to collect routes
49
- const routesObj = {};
50
- for (const meta of routesMeta) {
51
- const { route, method, input, output } = meta;
52
- // Initialize the route entry if it doesn't exist
53
- if (!routesObj[route]) {
54
- routesObj[route] = {};
55
- }
56
- // Store the input and output types separately for RouteHandler
57
- const inputType = input ? typesMap.getTypeMeta(input).uniqueName : 'null';
58
- const outputType = output ? typesMap.getTypeMeta(output).uniqueName : 'null';
59
- requiredTypes.add(inputType);
60
- requiredTypes.add(outputType);
61
- // Add method entry
62
- routesObj[route][method] = {
63
- inputType,
64
- outputType,
65
- };
66
- }
67
- // Build the routes object as a string
68
- let routesStr = 'export type RoutesMap = {\n';
69
- for (const [routePath, methods] of Object.entries(routesObj)) {
70
- routesStr += ` readonly '${routePath}': {\n`;
71
- for (const [method, handler] of Object.entries(methods)) {
72
- routesStr += ` readonly ${method.toUpperCase()}: RouteHandler<${handler.inputType}, ${handler.outputType}>,\n`;
73
- }
74
- routesStr += ' },\n';
75
- }
76
- routesStr += '};';
77
- return routesStr;
78
- }
79
- const generateMetaTypes = (metaTypes, typesMap) => {
80
- const nameToTypeMap = Array.from(metaTypes.entries()).reduce((result, [_name, { query, body, params }]) => {
81
- const { uniqueName } = typesMap.getTypeMeta(_name);
82
- const queryType = query && query.length > 0
83
- ? `Pick<${uniqueName}, '${query?.join("' | '")}'>`
84
- : undefined;
85
- if (queryType) {
86
- result.set(`${uniqueName}Query`, queryType);
87
- }
88
- const paramsType = params && params.length > 0
89
- ? `Pick<${uniqueName}, '${params.join("' | '")}'>`
90
- : undefined;
91
- if (paramsType) {
92
- result.set(`${uniqueName}Params`, paramsType);
93
- }
94
- const bodyType = (body && body.length > 0) || (params && params.length > 0)
95
- ? `Omit<${uniqueName}, '${[...new Set([...(query || []), ...(params || [])])].join("' | '")}'>`
96
- : uniqueName;
97
- if (bodyType) {
98
- result.set(`${uniqueName}Body`, bodyType);
99
- }
100
- return result;
101
- }, new Map());
102
- return `
103
- // The '& {}' is a workaround for not directly refering to a type since it confuses typescript
104
- ${Array.from(nameToTypeMap.entries())
105
- .map(([name, type]) => `export type ${name} = ${type} & {}`)
106
- .join('\n')}`;
107
- };