@pikku/cli 0.7.1 → 0.7.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.
- package/CHANGELOG.md +17 -0
- package/bin/pikku-all.ts +5 -2
- package/bin/pikku-channels-map.ts +2 -33
- package/bin/pikku-channels.ts +2 -30
- package/bin/pikku-fetch.ts +3 -3
- package/bin/pikku-function-types.ts +8 -42
- package/bin/pikku-functions.ts +3 -16
- package/bin/pikku-http-map.ts +3 -32
- package/bin/pikku-http-routes.ts +2 -30
- package/bin/pikku-nextjs.ts +1 -1
- package/bin/pikku-openapi.ts +4 -2
- package/bin/pikku-rpc-map.ts +25 -0
- package/bin/pikku-rpc.ts +62 -7
- package/bin/pikku-scheduler.ts +2 -30
- package/bin/pikku-schemas.ts +5 -4
- package/bin/pikku-websocket.ts +1 -1
- package/bin/pikku.ts +0 -10
- package/dist/bin/pikku-all.d.ts +1 -1
- package/dist/bin/pikku-all.js +5 -2
- package/dist/bin/pikku-channels-map.d.ts +0 -2
- package/dist/bin/pikku-channels-map.js +1 -16
- package/dist/bin/pikku-channels.d.ts +0 -2
- package/dist/bin/pikku-channels.js +1 -16
- package/dist/bin/pikku-fetch.d.ts +1 -1
- package/dist/bin/pikku-fetch.js +1 -1
- package/dist/bin/pikku-function-types.d.ts +2 -4
- package/dist/bin/pikku-function-types.js +3 -22
- package/dist/bin/pikku-functions.js +3 -4
- package/dist/bin/pikku-http-map.d.ts +0 -2
- package/dist/bin/pikku-http-map.js +2 -17
- package/dist/bin/pikku-http-routes.d.ts +0 -2
- package/dist/bin/pikku-http-routes.js +1 -16
- package/dist/bin/pikku-nextjs.d.ts +1 -1
- package/dist/bin/pikku-nextjs.js +1 -1
- package/dist/bin/pikku-openapi.js +3 -3
- package/dist/bin/pikku-rpc-map.d.ts +3 -0
- package/dist/bin/pikku-rpc-map.js +8 -0
- package/dist/bin/pikku-rpc.d.ts +5 -1
- package/dist/bin/pikku-rpc.js +33 -6
- package/dist/bin/pikku-scheduler.d.ts +0 -2
- package/dist/bin/pikku-scheduler.js +1 -16
- package/dist/bin/pikku-schemas.d.ts +1 -1
- package/dist/bin/pikku-schemas.js +4 -4
- package/dist/bin/pikku-websocket.d.ts +1 -1
- package/dist/bin/pikku-websocket.js +1 -1
- package/dist/bin/pikku.js +0 -10
- package/dist/src/inspector-glob.js +1 -1
- package/dist/src/openapi-spec-generator.d.ts +2 -2
- package/dist/src/openapi-spec-generator.js +14 -5
- package/dist/src/pikku-cli-config.d.ts +7 -5
- package/dist/src/pikku-cli-config.js +6 -0
- package/dist/src/schema-generator.d.ts +3 -3
- package/dist/src/schema-generator.js +16 -34
- package/dist/src/serialize-pikku-types.d.ts +1 -1
- package/dist/src/serialize-pikku-types.js +6 -3
- package/dist/src/serialize-typed-channel-map.js +2 -2
- package/dist/src/serialize-typed-http-map.d.ts +2 -1
- package/dist/src/serialize-typed-http-map.js +11 -5
- package/dist/src/serialize-typed-rpc-map.d.ts +4 -0
- package/dist/src/serialize-typed-rpc-map.js +66 -0
- package/dist/src/{utils.d.ts → utils/utils.d.ts} +2 -1
- package/dist/src/{utils.js → utils/utils.js} +15 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/inspector-glob.ts +1 -1
- package/src/openapi-spec-generator.ts +23 -4
- package/src/pikku-cli-config.ts +31 -5
- package/src/schema-generator.ts +18 -36
- package/src/serialize-pikku-types.ts +6 -3
- package/src/serialize-typed-channel-map.ts +2 -2
- package/src/serialize-typed-http-map.ts +19 -3
- package/src/serialize-typed-rpc-map.ts +105 -0
- package/src/{utils.ts → utils/utils.ts} +20 -2
- package/dist/src/serialize-typed-function-map.d.ts +0 -4
- package/dist/src/serialize-typed-function-map.js +0 -107
- package/src/serialize-typed-function-map.ts +0 -151
- /package/dist/src/{serialize-import-map.d.ts → utils/serialize-import-map.d.ts} +0 -0
- /package/dist/src/{serialize-import-map.js → utils/serialize-import-map.js} +0 -0
- /package/src/{serialize-import-map.ts → utils/serialize-import-map.ts} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
*
|
|
3
3
|
*/
|
|
4
|
-
export const serializePikkuTypes = (userSessionTypeImport, userSessionTypeName, singletonServicesTypeImport, singletonServicesTypeName, sessionServicesTypeImport,
|
|
4
|
+
export const serializePikkuTypes = (userSessionTypeImport, userSessionTypeName, singletonServicesTypeImport, singletonServicesTypeName, sessionServicesTypeImport, rpcMapTypeImport) => {
|
|
5
5
|
return `/**
|
|
6
6
|
* This is used to provide the application types in the typescript project
|
|
7
7
|
*/
|
|
@@ -15,6 +15,7 @@ import { CoreAPIChannel, PikkuChannel, addChannel as addCoreChannel } from '@pik
|
|
|
15
15
|
${userSessionTypeImport}
|
|
16
16
|
${singletonServicesTypeImport}
|
|
17
17
|
${sessionServicesTypeImport}
|
|
18
|
+
${rpcMapTypeImport}
|
|
18
19
|
|
|
19
20
|
export type APIPermission<In = unknown, RequiredServices extends ${singletonServicesTypeName} = ${singletonServicesTypeName}> = CoreAPIPermission<In, RequiredServices, ${userSessionTypeName}>
|
|
20
21
|
export type APIMiddleware<RequiredServices extends ${singletonServicesTypeName} = ${singletonServicesTypeName}> = PikkuMiddleware<RequiredServices, ${userSessionTypeName}>
|
|
@@ -23,7 +24,8 @@ type APIFunctionSessionless<
|
|
|
23
24
|
In = unknown,
|
|
24
25
|
Out = never,
|
|
25
26
|
ChannelData = null, // null means optional channel
|
|
26
|
-
RequiredServices extends Services = Services &
|
|
27
|
+
RequiredServices extends Services = Services &
|
|
28
|
+
{ rpc: TypedPikkuRPC } & (
|
|
27
29
|
[ChannelData] extends [null]
|
|
28
30
|
? { channel?: PikkuChannel<unknown, Out> } // Optional channel
|
|
29
31
|
: { channel: PikkuChannel<ChannelData, Out> } // Required channel with any data type
|
|
@@ -34,7 +36,8 @@ type APIFunction<
|
|
|
34
36
|
In = unknown,
|
|
35
37
|
Out = never,
|
|
36
38
|
ChannelData = null, // null means optional channel
|
|
37
|
-
RequiredServices extends Services = Services &
|
|
39
|
+
RequiredServices extends Services = Services &
|
|
40
|
+
{ rpc: TypedPikkuRPC } & (
|
|
38
41
|
[ChannelData] extends [null]
|
|
39
42
|
? { channel?: PikkuChannel<unknown, Out> } // Optional channel
|
|
40
43
|
: { channel: PikkuChannel<ChannelData, Out> } // Required channel with any data type
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { serializeImportMap } from './serialize-import-map.js';
|
|
2
|
-
import { generateCustomTypes } from './
|
|
1
|
+
import { serializeImportMap } from './utils/serialize-import-map.js';
|
|
2
|
+
import { generateCustomTypes } from './utils/utils.js';
|
|
3
3
|
export const serializeTypedChannelsMap = (relativeToPath, packageMappings, typesMap, channelsMeta) => {
|
|
4
4
|
const { channels, requiredTypes } = generateChannels(channelsMeta);
|
|
5
5
|
typesMap.customTypes.forEach(({ references }) => {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { HTTPRoutesMeta } from '@pikku/core/http';
|
|
2
2
|
import { MetaInputTypes, TypesMap } from '@pikku/inspector';
|
|
3
|
-
|
|
3
|
+
import { FunctionsMeta } from '@pikku/core';
|
|
4
|
+
export declare const serializeTypedRoutesMap: (relativeToPath: string, packageMappings: Record<string, string>, typesMap: TypesMap, functionsMeta: FunctionsMeta, routesMeta: HTTPRoutesMeta, metaTypes: MetaInputTypes) => string;
|
|
4
5
|
export declare function generateCustomTypes(typesMap: TypesMap, requiredTypes: Set<string>): string;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { serializeImportMap } from './serialize-import-map.js';
|
|
2
|
-
export const serializeTypedRoutesMap = (relativeToPath, packageMappings, typesMap, routesMeta, metaTypes) => {
|
|
1
|
+
import { serializeImportMap } from './utils/serialize-import-map.js';
|
|
2
|
+
export const serializeTypedRoutesMap = (relativeToPath, packageMappings, typesMap, functionsMeta, routesMeta, metaTypes) => {
|
|
3
3
|
const requiredTypes = new Set();
|
|
4
4
|
const serializedCustomTypes = generateCustomTypes(typesMap, requiredTypes);
|
|
5
5
|
const serializedMetaTypes = generateMetaTypes(metaTypes, typesMap);
|
|
6
|
-
const serializedRoutes = generateRoutes(routesMeta, typesMap, requiredTypes);
|
|
6
|
+
const serializedRoutes = generateRoutes(routesMeta, functionsMeta, typesMap, requiredTypes);
|
|
7
7
|
const serializedImportMap = serializeImportMap(relativeToPath, packageMappings, typesMap, requiredTypes);
|
|
8
8
|
return `/**
|
|
9
9
|
* This provides the structure needed for typescript to be aware of routes and their return types
|
|
@@ -44,11 +44,17 @@ ${Array.from(typesMap.customTypes.entries())
|
|
|
44
44
|
})
|
|
45
45
|
.join('\n')}`;
|
|
46
46
|
}
|
|
47
|
-
function generateRoutes(routesMeta, typesMap, requiredTypes) {
|
|
47
|
+
function generateRoutes(routesMeta, functionsMeta, typesMap, requiredTypes) {
|
|
48
48
|
// Initialize an object to collect routes
|
|
49
49
|
const routesObj = {};
|
|
50
50
|
for (const meta of routesMeta) {
|
|
51
|
-
const { route, method,
|
|
51
|
+
const { route, method, pikkuFuncName } = meta;
|
|
52
|
+
const functionMeta = functionsMeta[pikkuFuncName];
|
|
53
|
+
if (!functionMeta) {
|
|
54
|
+
throw new Error(`Function ${pikkuFuncName} not found in functionsMeta. Please check your configuration.`);
|
|
55
|
+
}
|
|
56
|
+
const input = functionMeta.inputs ? functionMeta.inputs[0] : undefined;
|
|
57
|
+
const output = functionMeta.outputs ? functionMeta.outputs[0] : undefined;
|
|
52
58
|
// Initialize the route entry if it doesn't exist
|
|
53
59
|
if (!routesObj[route]) {
|
|
54
60
|
routesObj[route] = {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { TypesMap } from '@pikku/inspector';
|
|
2
|
+
import { FunctionsMeta } from '@pikku/core';
|
|
3
|
+
import { RPCMeta } from '../../core/src/rpc/rpc-types.js';
|
|
4
|
+
export declare const serializeTypedRPCMap: (relativeToPath: string, packageMappings: Record<string, string>, typesMap: TypesMap, functionsMeta: FunctionsMeta, rpcMeta: Record<string, RPCMeta>) => string;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { serializeImportMap } from './utils/serialize-import-map.js';
|
|
2
|
+
import { generateCustomTypes } from './utils/utils.js';
|
|
3
|
+
export const serializeTypedRPCMap = (relativeToPath, packageMappings, typesMap, functionsMeta, rpcMeta) => {
|
|
4
|
+
const requiredTypes = new Set();
|
|
5
|
+
const serializedCustomTypes = generateCustomTypes(typesMap, requiredTypes);
|
|
6
|
+
const serializedRPCs = generateRPCs(rpcMeta, functionsMeta, typesMap, requiredTypes);
|
|
7
|
+
const serializedImportMap = serializeImportMap(relativeToPath, packageMappings, typesMap, requiredTypes);
|
|
8
|
+
return `/**
|
|
9
|
+
* This provides the structure needed for typescript to be aware of RPCs and their return types
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
${serializedImportMap}
|
|
13
|
+
${serializedCustomTypes}
|
|
14
|
+
|
|
15
|
+
interface RPCHandler<I, O> {
|
|
16
|
+
input: I;
|
|
17
|
+
output: O;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
${serializedRPCs}
|
|
21
|
+
|
|
22
|
+
type RPCInvoke = <Name extends keyof RPCMap>(
|
|
23
|
+
name: Name,
|
|
24
|
+
data: RPCMap[Name]['input'],
|
|
25
|
+
options?: {
|
|
26
|
+
location?: 'local' | 'remote' | 'auto'
|
|
27
|
+
}
|
|
28
|
+
) => Promise<RPCMap[Name]['output']>
|
|
29
|
+
|
|
30
|
+
export type TypedPikkuRPC = {
|
|
31
|
+
depth: number;
|
|
32
|
+
global: boolean;
|
|
33
|
+
invoke: RPCInvoke;
|
|
34
|
+
}
|
|
35
|
+
`;
|
|
36
|
+
};
|
|
37
|
+
function generateRPCs(rpcMeta, functionsMeta, typesMap, requiredTypes) {
|
|
38
|
+
// Initialize an object to collect RPCs
|
|
39
|
+
const rpcsObj = {};
|
|
40
|
+
// Iterate through RPC metadata
|
|
41
|
+
for (const [funcName, { pikkuFuncName }] of Object.entries(rpcMeta)) {
|
|
42
|
+
const functionMeta = functionsMeta[pikkuFuncName];
|
|
43
|
+
if (!functionMeta) {
|
|
44
|
+
throw new Error(`Function ${funcName} not found in functionsMeta. Please check your configuration.`);
|
|
45
|
+
}
|
|
46
|
+
const input = functionMeta.inputs ? functionMeta.inputs[0] : undefined;
|
|
47
|
+
const output = functionMeta.outputs ? functionMeta.outputs[0] : undefined;
|
|
48
|
+
// Store the input and output types for RPCHandler
|
|
49
|
+
const inputType = input ? typesMap.getTypeMeta(input).uniqueName : 'null';
|
|
50
|
+
const outputType = output ? typesMap.getTypeMeta(output).uniqueName : 'null';
|
|
51
|
+
requiredTypes.add(inputType);
|
|
52
|
+
requiredTypes.add(outputType);
|
|
53
|
+
// Add RPC entry
|
|
54
|
+
rpcsObj[funcName] = {
|
|
55
|
+
inputType,
|
|
56
|
+
outputType,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
// Build the RPCs object as a string
|
|
60
|
+
let rpcsStr = 'export type RPCMap = {\n';
|
|
61
|
+
for (const [funcName, handler] of Object.entries(rpcsObj)) {
|
|
62
|
+
rpcsStr += ` readonly '${funcName}': RPCHandler<${handler.inputType}, ${handler.outputType}>,\n`;
|
|
63
|
+
}
|
|
64
|
+
rpcsStr += '};\n';
|
|
65
|
+
return rpcsStr;
|
|
66
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { InspectorState } from '@pikku/inspector';
|
|
1
|
+
import { InspectorState, TypesMap } from '@pikku/inspector';
|
|
2
2
|
export declare const logPrimary: (message: string) => void;
|
|
3
3
|
export declare const logSuccess: (message: string) => void;
|
|
4
4
|
export declare const logInfo: (message: string) => void;
|
|
@@ -39,4 +39,5 @@ export declare const logCommandInfoAndTime: (commandStart: string, commandEnd: s
|
|
|
39
39
|
export declare const logPikkuLogo: () => void;
|
|
40
40
|
export declare const DO_NOT_MODIFY_COMMENT = "/**\n * This file was generated by the @pikku/cli\n */\n";
|
|
41
41
|
export declare const serializeFileImports: (importType: string, outputPath: string, files: Set<string>, packageMappings?: Record<string, string>) => string;
|
|
42
|
+
export declare function generateCustomTypes(typesMap: TypesMap, requiredTypes: Set<string>): string;
|
|
42
43
|
export {};
|
|
@@ -123,7 +123,7 @@ const logo = `
|
|
|
123
123
|
`;
|
|
124
124
|
export const logPikkuLogo = () => {
|
|
125
125
|
logPrimary(logo);
|
|
126
|
-
const packageJson = JSON.parse(readFileSync(`${dirname(__filename)}
|
|
126
|
+
const packageJson = JSON.parse(readFileSync(`${dirname(__filename)}/../../../package.json`, 'utf-8'));
|
|
127
127
|
logPrimary(`⚙️ Welcome to the Pikku CLI (v${packageJson.version})\n`);
|
|
128
128
|
};
|
|
129
129
|
// TODO: add version back in once the ESM dust settles
|
|
@@ -143,3 +143,17 @@ export const serializeFileImports = (importType, outputPath, files, packageMappi
|
|
|
143
143
|
});
|
|
144
144
|
return serializedOutput.join('\n');
|
|
145
145
|
};
|
|
146
|
+
export function generateCustomTypes(typesMap, requiredTypes) {
|
|
147
|
+
return `
|
|
148
|
+
// Custom types are those that are defined directly within generics
|
|
149
|
+
// or are broken into simpler types
|
|
150
|
+
${Array.from(typesMap.customTypes.entries())
|
|
151
|
+
.map(([name, { type, references }]) => {
|
|
152
|
+
references.forEach((name) => {
|
|
153
|
+
const originalName = typesMap.getTypeMeta(name).originalName;
|
|
154
|
+
requiredTypes.add(originalName);
|
|
155
|
+
});
|
|
156
|
+
return `export type ${name} = ${type}`;
|
|
157
|
+
})
|
|
158
|
+
.join('\n')}`;
|
|
159
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../bin/pikku-all.ts","../bin/pikku-channels-map.ts","../bin/pikku-channels.ts","../bin/pikku-fetch.ts","../bin/pikku-function-types.ts","../bin/pikku-functions.ts","../bin/pikku-http-map.ts","../bin/pikku-http-routes.ts","../bin/pikku-nextjs.ts","../bin/pikku-openapi.ts","../bin/pikku-rpc.ts","../bin/pikku-scheduler.ts","../bin/pikku-schemas.ts","../bin/pikku-websocket.ts","../bin/pikku.ts","../src/inspector-glob.ts","../src/openapi-spec-generator.ts","../src/pikku-cli-config.ts","../src/schema-generator.ts","../src/serialize-fetch-wrapper.ts","../src/serialize-
|
|
1
|
+
{"root":["../bin/pikku-all.ts","../bin/pikku-channels-map.ts","../bin/pikku-channels.ts","../bin/pikku-fetch.ts","../bin/pikku-function-types.ts","../bin/pikku-functions.ts","../bin/pikku-http-map.ts","../bin/pikku-http-routes.ts","../bin/pikku-nextjs.ts","../bin/pikku-openapi.ts","../bin/pikku-rpc-map.ts","../bin/pikku-rpc.ts","../bin/pikku-scheduler.ts","../bin/pikku-schemas.ts","../bin/pikku-websocket.ts","../bin/pikku.ts","../src/inspector-glob.ts","../src/openapi-spec-generator.ts","../src/pikku-cli-config.ts","../src/schema-generator.ts","../src/serialize-fetch-wrapper.ts","../src/serialize-nextjs-backend-wrapper.ts","../src/serialize-nextjs-http-wrapper.ts","../src/serialize-pikku-types.ts","../src/serialize-scheduler-meta.ts","../src/serialize-typed-channel-map.ts","../src/serialize-typed-http-map.ts","../src/serialize-typed-rpc-map.ts","../src/serialize-websocket-wrapper.ts","../src/utils/serialize-import-map.ts","../src/utils/utils.ts"],"version":"5.7.3"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/cli",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.3",
|
|
4
4
|
"author": "yasser.fadl@gmail.com",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@openapi-contrib/json-schema-to-openapi-schema": "^3.0.2",
|
|
25
|
-
"@pikku/core": "^0.7.
|
|
26
|
-
"@pikku/inspector": "^0.7.
|
|
25
|
+
"@pikku/core": "^0.7.5",
|
|
26
|
+
"@pikku/inspector": "^0.7.4",
|
|
27
27
|
"@types/cookie": "^0.6.0",
|
|
28
28
|
"@types/uuid": "^10.0.0",
|
|
29
29
|
"chalk": "^5.4.1",
|
package/src/inspector-glob.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as path from 'path'
|
|
2
2
|
import { glob } from 'tinyglobby'
|
|
3
3
|
import { InspectorFilters, InspectorState, inspect } from '@pikku/inspector'
|
|
4
|
-
import { logCommandInfoAndTime } from './utils.js'
|
|
4
|
+
import { logCommandInfoAndTime } from './utils/utils.js'
|
|
5
5
|
|
|
6
6
|
export const inspectorGlob = async (
|
|
7
7
|
rootDir: string,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HTTPRoutesMeta, pikkuState } from '@pikku/core'
|
|
1
|
+
import { FunctionsMeta, HTTPRoutesMeta, pikkuState } from '@pikku/core'
|
|
2
2
|
import _convertSchema from '@openapi-contrib/json-schema-to-openapi-schema'
|
|
3
3
|
const convertSchema =
|
|
4
4
|
'default' in _convertSchema ? (_convertSchema.default as any) : _convertSchema
|
|
@@ -75,12 +75,16 @@ const getErrorResponseForConstructorName = (constructorName: string) => {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
const convertSchemasToBodyPayloads = async (
|
|
78
|
+
functionsMeta: FunctionsMeta,
|
|
78
79
|
routesMeta: HTTPRoutesMeta,
|
|
79
80
|
schemas: Record<string, any>
|
|
80
81
|
) => {
|
|
81
82
|
const requiredSchemas = new Set(
|
|
82
83
|
routesMeta
|
|
83
|
-
.map(({ inputTypes,
|
|
84
|
+
.map(({ inputTypes, pikkuFuncName }) => {
|
|
85
|
+
const output = functionsMeta[pikkuFuncName]?.outputs?.[0]
|
|
86
|
+
return [inputTypes?.body, output]
|
|
87
|
+
})
|
|
84
88
|
.flat()
|
|
85
89
|
.filter((schema) => !!schema)
|
|
86
90
|
)
|
|
@@ -100,6 +104,7 @@ const convertSchemasToBodyPayloads = async (
|
|
|
100
104
|
}
|
|
101
105
|
|
|
102
106
|
export async function generateOpenAPISpec(
|
|
107
|
+
functionsMeta: FunctionsMeta,
|
|
103
108
|
routeMeta: HTTPRoutesMeta,
|
|
104
109
|
schemas: Record<string, any>,
|
|
105
110
|
additionalInfo: OpenAPISpecInfo
|
|
@@ -107,7 +112,17 @@ export async function generateOpenAPISpec(
|
|
|
107
112
|
const paths: Record<string, any> = {}
|
|
108
113
|
|
|
109
114
|
routeMeta.forEach((meta) => {
|
|
110
|
-
const { route, method, inputTypes,
|
|
115
|
+
const { route, method, inputTypes, pikkuFuncName, params, query, docs } =
|
|
116
|
+
meta
|
|
117
|
+
const functionMeta = functionsMeta[pikkuFuncName]
|
|
118
|
+
if (!functionMeta) {
|
|
119
|
+
console.error(
|
|
120
|
+
`• No function metadata found for '${pikkuFuncName}' in route '${route}'.`
|
|
121
|
+
)
|
|
122
|
+
return
|
|
123
|
+
}
|
|
124
|
+
const output = functionMeta.outputs ? functionMeta.outputs[0] : undefined
|
|
125
|
+
|
|
111
126
|
const path = route.replace(/:(\w+)/g, '{$1}') // Convert ":param" to "{param}"
|
|
112
127
|
|
|
113
128
|
if (!paths[path]) {
|
|
@@ -194,7 +209,11 @@ export async function generateOpenAPISpec(
|
|
|
194
209
|
servers: additionalInfo.servers,
|
|
195
210
|
paths,
|
|
196
211
|
components: {
|
|
197
|
-
schemas: await convertSchemasToBodyPayloads(
|
|
212
|
+
schemas: await convertSchemasToBodyPayloads(
|
|
213
|
+
functionsMeta,
|
|
214
|
+
routeMeta,
|
|
215
|
+
schemas
|
|
216
|
+
),
|
|
198
217
|
responses: {},
|
|
199
218
|
parameters: {},
|
|
200
219
|
examples: {},
|
package/src/pikku-cli-config.ts
CHANGED
|
@@ -4,20 +4,37 @@ import { OpenAPISpecInfo } from './openapi-spec-generator.js'
|
|
|
4
4
|
import { InspectorFilters } from '@pikku/inspector'
|
|
5
5
|
|
|
6
6
|
export interface PikkuCLICoreOutputFiles {
|
|
7
|
+
// Base directory
|
|
7
8
|
outDir?: string
|
|
9
|
+
|
|
10
|
+
// Schema and types
|
|
11
|
+
schemaDirectory: string
|
|
12
|
+
typesDeclarationFile: string
|
|
13
|
+
|
|
14
|
+
// Function definitions
|
|
8
15
|
functionsFile: string
|
|
9
16
|
functionsMetaFile: string
|
|
17
|
+
|
|
18
|
+
// HTTP routes
|
|
10
19
|
httpRoutesFile: string
|
|
11
20
|
httpRoutesMetaFile: string
|
|
21
|
+
httpRoutesMapDeclarationFile: string
|
|
22
|
+
|
|
23
|
+
// Channels
|
|
12
24
|
channelsFile: string
|
|
13
25
|
channelsMetaFile: string
|
|
26
|
+
channelsMapDeclarationFile: string
|
|
27
|
+
|
|
28
|
+
// RPC
|
|
29
|
+
rpcFile: string
|
|
30
|
+
rpcMetaFile: string
|
|
31
|
+
rpcMapDeclarationFile: string
|
|
32
|
+
|
|
33
|
+
// Schedulers
|
|
14
34
|
schedulersFile: string
|
|
15
35
|
schedulersMetaFile: string
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
typesDeclarationFile: string
|
|
19
|
-
httpRoutesMapDeclarationFile: string
|
|
20
|
-
channelsMapDeclarationFile: string
|
|
36
|
+
|
|
37
|
+
// Application bootstrap
|
|
21
38
|
bootstrapFile: string
|
|
22
39
|
}
|
|
23
40
|
|
|
@@ -139,6 +156,15 @@ const _getPikkuCLIConfig = async (
|
|
|
139
156
|
if (!result.rpcFile) {
|
|
140
157
|
result.rpcFile = join(result.outDir, 'pikku-rpc.gen.ts')
|
|
141
158
|
}
|
|
159
|
+
if (!result.rpcMetaFile) {
|
|
160
|
+
result.rpcMetaFile = join(result.outDir, 'pikku-rpc-meta.gen.ts')
|
|
161
|
+
}
|
|
162
|
+
if (!result.rpcMapDeclarationFile) {
|
|
163
|
+
result.rpcMapDeclarationFile = join(
|
|
164
|
+
result.outDir,
|
|
165
|
+
'pikku-rpc-map.gen.ts'
|
|
166
|
+
)
|
|
167
|
+
}
|
|
142
168
|
if (!result.httpRoutesFile) {
|
|
143
169
|
result.httpRoutesFile = join(result.outDir, 'pikku-http-routes.gen.ts')
|
|
144
170
|
}
|
package/src/schema-generator.ts
CHANGED
|
@@ -1,45 +1,27 @@
|
|
|
1
1
|
import { createGenerator, RootlessError } from 'ts-json-schema-generator'
|
|
2
|
-
import { logInfo, writeFileInDir } from './utils.js'
|
|
2
|
+
import { logInfo, writeFileInDir } from './utils/utils.js'
|
|
3
3
|
import { mkdir, writeFile } from 'fs/promises'
|
|
4
|
-
import { JSONValue } from '@pikku/core'
|
|
4
|
+
import { FunctionsMeta, JSONValue } from '@pikku/core'
|
|
5
5
|
import { HTTPRoutesMeta } from '@pikku/core/http'
|
|
6
6
|
import { TypesMap } from '@pikku/inspector'
|
|
7
7
|
|
|
8
8
|
export async function generateSchemas(
|
|
9
9
|
tsconfig: string,
|
|
10
|
-
|
|
10
|
+
typesMap: TypesMap,
|
|
11
|
+
functionMeta: FunctionsMeta,
|
|
11
12
|
httpRoutesMeta: HTTPRoutesMeta
|
|
12
13
|
): Promise<Record<string, JSONValue>> {
|
|
13
|
-
const schemasSet = new Set(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
try {
|
|
21
|
-
const uniqueName = typesMap.getUniqueName(input)
|
|
22
|
-
if (uniqueName) {
|
|
23
|
-
found = true
|
|
24
|
-
schemasSet.add(uniqueName)
|
|
25
|
-
break
|
|
26
|
-
}
|
|
27
|
-
} catch (e) {}
|
|
28
|
-
}
|
|
29
|
-
if (!found) {
|
|
30
|
-
console.error('Input type not found in any types map:', input)
|
|
14
|
+
const schemasSet = new Set(typesMap.customTypes.keys())
|
|
15
|
+
for (const { inputs, outputs } of Object.values(functionMeta)) {
|
|
16
|
+
const types = [...(inputs || []), ...(outputs || [])]
|
|
17
|
+
for (const type of types) {
|
|
18
|
+
const uniqueName = typesMap.getUniqueName(type)
|
|
19
|
+
if (uniqueName) {
|
|
20
|
+
schemasSet.add(uniqueName)
|
|
31
21
|
}
|
|
32
22
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
// const uniqueName = typesMap.getUniqueName(output)
|
|
36
|
-
// if (uniqueName) {
|
|
37
|
-
// console.log('Adding output schema:', uniqueName)
|
|
38
|
-
// schemasSet.add(uniqueName)
|
|
39
|
-
// break
|
|
40
|
-
// }
|
|
41
|
-
// }
|
|
42
|
-
// }
|
|
23
|
+
}
|
|
24
|
+
for (const { inputTypes } of httpRoutesMeta) {
|
|
43
25
|
if (inputTypes?.body) {
|
|
44
26
|
schemasSet.add(inputTypes.body)
|
|
45
27
|
}
|
|
@@ -78,7 +60,7 @@ export async function saveSchemas(
|
|
|
78
60
|
schemaParentDir: string,
|
|
79
61
|
schemas: Record<string, JSONValue>,
|
|
80
62
|
typesMap: TypesMap,
|
|
81
|
-
|
|
63
|
+
functionsMeta: FunctionsMeta,
|
|
82
64
|
supportsImportAttributes: boolean
|
|
83
65
|
) {
|
|
84
66
|
await writeFileInDir(
|
|
@@ -87,10 +69,10 @@ export async function saveSchemas(
|
|
|
87
69
|
)
|
|
88
70
|
|
|
89
71
|
const desiredSchemas = new Set([
|
|
90
|
-
...
|
|
91
|
-
.map(({
|
|
92
|
-
|
|
93
|
-
|
|
72
|
+
...Object.values(functionsMeta)
|
|
73
|
+
.map(({ inputs, outputs }) => [
|
|
74
|
+
inputs?.[0] ? typesMap.getUniqueName(inputs[0]) : undefined,
|
|
75
|
+
outputs?.[0] ? typesMap.getUniqueName(outputs[0]) : undefined,
|
|
94
76
|
])
|
|
95
77
|
.flat()
|
|
96
78
|
.filter(
|
|
@@ -7,7 +7,7 @@ export const serializePikkuTypes = (
|
|
|
7
7
|
singletonServicesTypeImport: string,
|
|
8
8
|
singletonServicesTypeName: string,
|
|
9
9
|
sessionServicesTypeImport: string,
|
|
10
|
-
|
|
10
|
+
rpcMapTypeImport: string
|
|
11
11
|
) => {
|
|
12
12
|
return `/**
|
|
13
13
|
* This is used to provide the application types in the typescript project
|
|
@@ -22,6 +22,7 @@ import { CoreAPIChannel, PikkuChannel, addChannel as addCoreChannel } from '@pik
|
|
|
22
22
|
${userSessionTypeImport}
|
|
23
23
|
${singletonServicesTypeImport}
|
|
24
24
|
${sessionServicesTypeImport}
|
|
25
|
+
${rpcMapTypeImport}
|
|
25
26
|
|
|
26
27
|
export type APIPermission<In = unknown, RequiredServices extends ${singletonServicesTypeName} = ${singletonServicesTypeName}> = CoreAPIPermission<In, RequiredServices, ${userSessionTypeName}>
|
|
27
28
|
export type APIMiddleware<RequiredServices extends ${singletonServicesTypeName} = ${singletonServicesTypeName}> = PikkuMiddleware<RequiredServices, ${userSessionTypeName}>
|
|
@@ -30,7 +31,8 @@ type APIFunctionSessionless<
|
|
|
30
31
|
In = unknown,
|
|
31
32
|
Out = never,
|
|
32
33
|
ChannelData = null, // null means optional channel
|
|
33
|
-
RequiredServices extends Services = Services &
|
|
34
|
+
RequiredServices extends Services = Services &
|
|
35
|
+
{ rpc: TypedPikkuRPC } & (
|
|
34
36
|
[ChannelData] extends [null]
|
|
35
37
|
? { channel?: PikkuChannel<unknown, Out> } // Optional channel
|
|
36
38
|
: { channel: PikkuChannel<ChannelData, Out> } // Required channel with any data type
|
|
@@ -41,7 +43,8 @@ type APIFunction<
|
|
|
41
43
|
In = unknown,
|
|
42
44
|
Out = never,
|
|
43
45
|
ChannelData = null, // null means optional channel
|
|
44
|
-
RequiredServices extends Services = Services &
|
|
46
|
+
RequiredServices extends Services = Services &
|
|
47
|
+
{ rpc: TypedPikkuRPC } & (
|
|
45
48
|
[ChannelData] extends [null]
|
|
46
49
|
? { channel?: PikkuChannel<unknown, Out> } // Optional channel
|
|
47
50
|
: { channel: PikkuChannel<ChannelData, Out> } // Required channel with any data type
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ChannelsMeta } from '@pikku/core/channel'
|
|
2
|
-
import { serializeImportMap } from './serialize-import-map.js'
|
|
2
|
+
import { serializeImportMap } from './utils/serialize-import-map.js'
|
|
3
3
|
import { TypesMap } from '@pikku/inspector'
|
|
4
|
-
import { generateCustomTypes } from './
|
|
4
|
+
import { generateCustomTypes } from './utils/utils.js'
|
|
5
5
|
|
|
6
6
|
export const serializeTypedChannelsMap = (
|
|
7
7
|
relativeToPath: string,
|
|
@@ -1,18 +1,25 @@
|
|
|
1
1
|
import { HTTPRoutesMeta } from '@pikku/core/http'
|
|
2
|
-
import { serializeImportMap } from './serialize-import-map.js'
|
|
2
|
+
import { serializeImportMap } from './utils/serialize-import-map.js'
|
|
3
3
|
import { MetaInputTypes, TypesMap } from '@pikku/inspector'
|
|
4
|
+
import { FunctionsMeta } from '@pikku/core'
|
|
4
5
|
|
|
5
6
|
export const serializeTypedRoutesMap = (
|
|
6
7
|
relativeToPath: string,
|
|
7
8
|
packageMappings: Record<string, string>,
|
|
8
9
|
typesMap: TypesMap,
|
|
10
|
+
functionsMeta: FunctionsMeta,
|
|
9
11
|
routesMeta: HTTPRoutesMeta,
|
|
10
12
|
metaTypes: MetaInputTypes
|
|
11
13
|
) => {
|
|
12
14
|
const requiredTypes = new Set<string>()
|
|
13
15
|
const serializedCustomTypes = generateCustomTypes(typesMap, requiredTypes)
|
|
14
16
|
const serializedMetaTypes = generateMetaTypes(metaTypes, typesMap)
|
|
15
|
-
const serializedRoutes = generateRoutes(
|
|
17
|
+
const serializedRoutes = generateRoutes(
|
|
18
|
+
routesMeta,
|
|
19
|
+
functionsMeta,
|
|
20
|
+
typesMap,
|
|
21
|
+
requiredTypes
|
|
22
|
+
)
|
|
16
23
|
|
|
17
24
|
const serializedImportMap = serializeImportMap(
|
|
18
25
|
relativeToPath,
|
|
@@ -67,6 +74,7 @@ ${Array.from(typesMap.customTypes.entries())
|
|
|
67
74
|
|
|
68
75
|
function generateRoutes(
|
|
69
76
|
routesMeta: HTTPRoutesMeta,
|
|
77
|
+
functionsMeta: FunctionsMeta,
|
|
70
78
|
typesMap: TypesMap,
|
|
71
79
|
requiredTypes: Set<string>
|
|
72
80
|
) {
|
|
@@ -77,7 +85,15 @@ function generateRoutes(
|
|
|
77
85
|
> = {}
|
|
78
86
|
|
|
79
87
|
for (const meta of routesMeta) {
|
|
80
|
-
const { route, method,
|
|
88
|
+
const { route, method, pikkuFuncName } = meta
|
|
89
|
+
const functionMeta = functionsMeta[pikkuFuncName]
|
|
90
|
+
if (!functionMeta) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
`Function ${pikkuFuncName} not found in functionsMeta. Please check your configuration.`
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
const input = functionMeta.inputs ? functionMeta.inputs[0] : undefined
|
|
96
|
+
const output = functionMeta.outputs ? functionMeta.outputs[0] : undefined
|
|
81
97
|
|
|
82
98
|
// Initialize the route entry if it doesn't exist
|
|
83
99
|
if (!routesObj[route]) {
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { serializeImportMap } from './utils/serialize-import-map.js'
|
|
2
|
+
import { TypesMap } from '@pikku/inspector'
|
|
3
|
+
import { FunctionsMeta } from '@pikku/core'
|
|
4
|
+
import { generateCustomTypes } from './utils/utils.js'
|
|
5
|
+
import { RPCMeta } from '../../core/src/rpc/rpc-types.js'
|
|
6
|
+
|
|
7
|
+
export const serializeTypedRPCMap = (
|
|
8
|
+
relativeToPath: string,
|
|
9
|
+
packageMappings: Record<string, string>,
|
|
10
|
+
typesMap: TypesMap,
|
|
11
|
+
functionsMeta: FunctionsMeta,
|
|
12
|
+
rpcMeta: Record<string, RPCMeta>
|
|
13
|
+
) => {
|
|
14
|
+
const requiredTypes = new Set<string>()
|
|
15
|
+
const serializedCustomTypes = generateCustomTypes(typesMap, requiredTypes)
|
|
16
|
+
const serializedRPCs = generateRPCs(
|
|
17
|
+
rpcMeta,
|
|
18
|
+
functionsMeta,
|
|
19
|
+
typesMap,
|
|
20
|
+
requiredTypes
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
const serializedImportMap = serializeImportMap(
|
|
24
|
+
relativeToPath,
|
|
25
|
+
packageMappings,
|
|
26
|
+
typesMap,
|
|
27
|
+
requiredTypes
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
return `/**
|
|
31
|
+
* This provides the structure needed for typescript to be aware of RPCs and their return types
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
${serializedImportMap}
|
|
35
|
+
${serializedCustomTypes}
|
|
36
|
+
|
|
37
|
+
interface RPCHandler<I, O> {
|
|
38
|
+
input: I;
|
|
39
|
+
output: O;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
${serializedRPCs}
|
|
43
|
+
|
|
44
|
+
type RPCInvoke = <Name extends keyof RPCMap>(
|
|
45
|
+
name: Name,
|
|
46
|
+
data: RPCMap[Name]['input'],
|
|
47
|
+
options?: {
|
|
48
|
+
location?: 'local' | 'remote' | 'auto'
|
|
49
|
+
}
|
|
50
|
+
) => Promise<RPCMap[Name]['output']>
|
|
51
|
+
|
|
52
|
+
export type TypedPikkuRPC = {
|
|
53
|
+
depth: number;
|
|
54
|
+
global: boolean;
|
|
55
|
+
invoke: RPCInvoke;
|
|
56
|
+
}
|
|
57
|
+
`
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function generateRPCs(
|
|
61
|
+
rpcMeta: Record<string, RPCMeta>,
|
|
62
|
+
functionsMeta: FunctionsMeta,
|
|
63
|
+
typesMap: TypesMap,
|
|
64
|
+
requiredTypes: Set<string>
|
|
65
|
+
) {
|
|
66
|
+
// Initialize an object to collect RPCs
|
|
67
|
+
const rpcsObj: Record<string, { inputType: string; outputType: string }> = {}
|
|
68
|
+
|
|
69
|
+
// Iterate through RPC metadata
|
|
70
|
+
for (const [funcName, { pikkuFuncName }] of Object.entries(rpcMeta)) {
|
|
71
|
+
const functionMeta = functionsMeta[pikkuFuncName]
|
|
72
|
+
if (!functionMeta) {
|
|
73
|
+
throw new Error(
|
|
74
|
+
`Function ${funcName} not found in functionsMeta. Please check your configuration.`
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const input = functionMeta.inputs ? functionMeta.inputs[0] : undefined
|
|
79
|
+
const output = functionMeta.outputs ? functionMeta.outputs[0] : undefined
|
|
80
|
+
|
|
81
|
+
// Store the input and output types for RPCHandler
|
|
82
|
+
const inputType = input ? typesMap.getTypeMeta(input).uniqueName : 'null'
|
|
83
|
+
const outputType = output ? typesMap.getTypeMeta(output).uniqueName : 'null'
|
|
84
|
+
|
|
85
|
+
requiredTypes.add(inputType)
|
|
86
|
+
requiredTypes.add(outputType)
|
|
87
|
+
|
|
88
|
+
// Add RPC entry
|
|
89
|
+
rpcsObj[funcName] = {
|
|
90
|
+
inputType,
|
|
91
|
+
outputType,
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Build the RPCs object as a string
|
|
96
|
+
let rpcsStr = 'export type RPCMap = {\n'
|
|
97
|
+
|
|
98
|
+
for (const [funcName, handler] of Object.entries(rpcsObj)) {
|
|
99
|
+
rpcsStr += ` readonly '${funcName}': RPCHandler<${handler.inputType}, ${handler.outputType}>,\n`
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
rpcsStr += '};\n'
|
|
103
|
+
|
|
104
|
+
return rpcsStr
|
|
105
|
+
}
|