@pikku/cli 0.9.0 → 0.9.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.
- package/CHANGELOG.md +30 -0
- package/bin/pikku-all.ts +9 -4
- package/bin/pikku-nextjs.ts +3 -3
- package/dist/bin/pikku-all.js +9 -4
- package/dist/bin/pikku-nextjs.js +3 -3
- package/dist/bin/pikku.js +0 -0
- package/dist/src/serialize-pikku-types.js +28 -25
- package/dist/src/utils.d.ts +5 -1
- package/dist/src/utils.js +17 -6
- package/dist/src/wirings/rpc/pikku-command-rpc-client.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +11 -11
- package/src/serialize-pikku-types.ts +28 -25
- package/src/utils.ts +26 -6
- package/src/wirings/rpc/pikku-command-rpc-client.ts +1 -1
- package/dist/src/events/channels/pikku-channels.d.ts +0 -2
- package/dist/src/events/channels/pikku-channels.js +0 -9
- package/dist/src/events/channels/pikku-command-channels-map.d.ts +0 -2
- package/dist/src/events/channels/pikku-command-channels-map.js +0 -8
- package/dist/src/events/channels/pikku-command-channels.d.ts +0 -2
- package/dist/src/events/channels/pikku-command-channels.js +0 -9
- package/dist/src/events/channels/pikku-command-websocket-typed.d.ts +0 -2
- package/dist/src/events/channels/pikku-command-websocket-typed.js +0 -15
- package/dist/src/events/channels/serialize-typed-channel-map.d.ts +0 -4
- package/dist/src/events/channels/serialize-typed-channel-map.js +0 -111
- package/dist/src/events/channels/serialize-websocket-wrapper.d.ts +0 -1
- package/dist/src/events/channels/serialize-websocket-wrapper.js +0 -75
- package/dist/src/events/fetch/index.d.ts +0 -2
- package/dist/src/events/fetch/index.js +0 -12
- package/dist/src/events/functions/pikku-command-function-types.d.ts +0 -2
- package/dist/src/events/functions/pikku-command-function-types.js +0 -13
- package/dist/src/events/functions/pikku-command-functions.d.ts +0 -6
- package/dist/src/events/functions/pikku-command-functions.js +0 -35
- package/dist/src/events/functions/pikku-command-services.d.ts +0 -3
- package/dist/src/events/functions/pikku-command-services.js +0 -73
- package/dist/src/events/functions/pikku-function-types.d.ts +0 -2
- package/dist/src/events/functions/pikku-function-types.js +0 -13
- package/dist/src/events/functions/pikku-functions.d.ts +0 -6
- package/dist/src/events/functions/pikku-functions.js +0 -35
- package/dist/src/events/http/openapi-spec-generator.d.ts +0 -79
- package/dist/src/events/http/openapi-spec-generator.js +0 -145
- package/dist/src/events/http/pikku-command-http-map.d.ts +0 -2
- package/dist/src/events/http/pikku-command-http-map.js +0 -8
- package/dist/src/events/http/pikku-command-http-routes.d.ts +0 -2
- package/dist/src/events/http/pikku-command-http-routes.js +0 -9
- package/dist/src/events/http/pikku-command-nextjs.d.ts +0 -2
- package/dist/src/events/http/pikku-command-nextjs.js +0 -36
- package/dist/src/events/http/pikku-command-openapi.d.ts +0 -2
- package/dist/src/events/http/pikku-command-openapi.js +0 -20
- package/dist/src/events/http/pikku-http-routes.d.ts +0 -2
- package/dist/src/events/http/pikku-http-routes.js +0 -9
- package/dist/src/events/http/serialize-fetch-wrapper.d.ts +0 -1
- package/dist/src/events/http/serialize-fetch-wrapper.js +0 -67
- package/dist/src/events/http/serialize-typed-http-map.d.ts +0 -4
- package/dist/src/events/http/serialize-typed-http-map.js +0 -100
- package/dist/src/events/mcp/pikku-command-mcp-json.d.ts +0 -2
- package/dist/src/events/mcp/pikku-command-mcp-json.js +0 -13
- package/dist/src/events/mcp/pikku-command-mcp.d.ts +0 -2
- package/dist/src/events/mcp/pikku-command-mcp.js +0 -54
- package/dist/src/events/mcp/serialize-mcp-json.d.ts +0 -5
- package/dist/src/events/mcp/serialize-mcp-json.js +0 -101
- package/dist/src/events/queue/pikku-command-queue-map.d.ts +0 -2
- package/dist/src/events/queue/pikku-command-queue-map.js +0 -8
- package/dist/src/events/queue/pikku-command-queue-service.d.ts +0 -2
- package/dist/src/events/queue/pikku-command-queue-service.js +0 -12
- package/dist/src/events/queue/pikku-command-queue.d.ts +0 -2
- package/dist/src/events/queue/pikku-command-queue.js +0 -10
- package/dist/src/events/queue/pikku-queue-map.d.ts +0 -2
- package/dist/src/events/queue/pikku-queue-map.js +0 -8
- package/dist/src/events/queue/pikku-queue.d.ts +0 -2
- package/dist/src/events/queue/pikku-queue.js +0 -10
- package/dist/src/events/queue/serialize-queue-map.d.ts +0 -4
- package/dist/src/events/queue/serialize-queue-map.js +0 -77
- package/dist/src/events/queue/serialize-queue-meta.d.ts +0 -2
- package/dist/src/events/queue/serialize-queue-meta.js +0 -6
- package/dist/src/events/queue/serialize-queue-wrapper.d.ts +0 -1
- package/dist/src/events/queue/serialize-queue-wrapper.js +0 -35
- package/dist/src/events/rpc/index.d.ts +0 -2
- package/dist/src/events/rpc/index.js +0 -12
- package/dist/src/events/rpc/pikku-command-rpc-client.d.ts +0 -2
- package/dist/src/events/rpc/pikku-command-rpc-client.js +0 -12
- package/dist/src/events/rpc/pikku-command-rpc-map.d.ts +0 -2
- package/dist/src/events/rpc/pikku-command-rpc-map.js +0 -8
- package/dist/src/events/rpc/pikku-command-rpc.d.ts +0 -2
- package/dist/src/events/rpc/pikku-command-rpc.js +0 -6
- package/dist/src/events/rpc/pikku-rpc.d.ts +0 -2
- package/dist/src/events/rpc/pikku-rpc.js +0 -6
- package/dist/src/events/rpc/serialize-rpc-wrapper.d.ts +0 -1
- package/dist/src/events/rpc/serialize-rpc-wrapper.js +0 -68
- package/dist/src/events/rpc/serialize-typed-rpc-map.d.ts +0 -4
- package/dist/src/events/rpc/serialize-typed-rpc-map.js +0 -66
- package/dist/src/events/scheduler/pikku-command-scheduler.d.ts +0 -2
- package/dist/src/events/scheduler/pikku-command-scheduler.js +0 -10
- package/dist/src/events/scheduler/serialize-scheduler-meta.d.ts +0 -2
- package/dist/src/events/scheduler/serialize-scheduler-meta.js +0 -10
- package/lcov.info +0 -582
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { logCommandInfoAndTime, getFileImportRelativePath, writeFileInDir, } from '../../utils.js';
|
|
2
|
-
import { serializeWebsocketWrapper } from './serialize-websocket-wrapper.js';
|
|
3
|
-
export const pikkuWebSocketTyped = async (logger, { websocketFile, channelsMapDeclarationFile, packageMappings }) => {
|
|
4
|
-
return await logCommandInfoAndTime(logger, 'Generating websocket wrapper', 'Generated websocket wrapper', [
|
|
5
|
-
websocketFile === undefined,
|
|
6
|
-
"websocketFile isn't set in the pikku config",
|
|
7
|
-
], async () => {
|
|
8
|
-
if (!websocketFile) {
|
|
9
|
-
throw new Error("fetchFile is isn't set in the pikku config");
|
|
10
|
-
}
|
|
11
|
-
const channelsMapDeclarationPath = getFileImportRelativePath(websocketFile, channelsMapDeclarationFile, packageMappings);
|
|
12
|
-
const content = [serializeWebsocketWrapper(channelsMapDeclarationPath)];
|
|
13
|
-
await writeFileInDir(logger, websocketFile, content.join('\n'));
|
|
14
|
-
});
|
|
15
|
-
};
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { ChannelsMeta } from '@pikku/core/channel';
|
|
2
|
-
import { TypesMap } from '@pikku/inspector';
|
|
3
|
-
import { FunctionsMeta } from '@pikku/core';
|
|
4
|
-
export declare const serializeTypedChannelsMap: (relativeToPath: string, packageMappings: Record<string, string>, typesMap: TypesMap, functionsMeta: FunctionsMeta, channelsMeta: ChannelsMeta) => string;
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { serializeImportMap } from '../../serialize-import-map.js';
|
|
2
|
-
import { generateCustomTypes } from '../../utils.js';
|
|
3
|
-
export const serializeTypedChannelsMap = (relativeToPath, packageMappings, typesMap, functionsMeta, channelsMeta) => {
|
|
4
|
-
const { channels, requiredTypes } = generateChannels(functionsMeta, channelsMeta);
|
|
5
|
-
typesMap.customTypes.forEach(({ references }) => {
|
|
6
|
-
for (const reference of references) {
|
|
7
|
-
requiredTypes.add(reference);
|
|
8
|
-
}
|
|
9
|
-
});
|
|
10
|
-
const imports = serializeImportMap(relativeToPath, packageMappings, typesMap, requiredTypes);
|
|
11
|
-
const serializedCustomTypes = generateCustomTypes(typesMap, requiredTypes);
|
|
12
|
-
return `/**
|
|
13
|
-
* This provides the structure needed for TypeScript to be aware of channels
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
${imports}
|
|
17
|
-
${serializedCustomTypes}
|
|
18
|
-
|
|
19
|
-
interface ChannelHandler<I, O> {
|
|
20
|
-
input: I;
|
|
21
|
-
output: O;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
${channels}
|
|
25
|
-
|
|
26
|
-
export type ChannelDefaultHandlerOf<Channel extends keyof ChannelsMap> =
|
|
27
|
-
ChannelsMap[Channel]['defaultMessage'] extends { input: infer I; output: infer O }
|
|
28
|
-
? ChannelHandler<I, O>
|
|
29
|
-
: never;
|
|
30
|
-
|
|
31
|
-
export type ChannelRouteHandlerOf<
|
|
32
|
-
Channel extends keyof ChannelsMap,
|
|
33
|
-
Route extends keyof ChannelsMap[Channel]['routes'],
|
|
34
|
-
Method extends keyof ChannelsMap[Channel]['routes'][Route],
|
|
35
|
-
> =
|
|
36
|
-
ChannelsMap[Channel]['routes'][Route][Method] extends { input: infer I; output: infer O }
|
|
37
|
-
? ChannelHandler<I, O>
|
|
38
|
-
: never;
|
|
39
|
-
`;
|
|
40
|
-
};
|
|
41
|
-
function generateChannels(functionsMeta, channelsMeta) {
|
|
42
|
-
const requiredTypes = new Set();
|
|
43
|
-
const channelsObject = {};
|
|
44
|
-
for (const meta of Object.values(channelsMeta)) {
|
|
45
|
-
const { name, messageWirings, message } = meta;
|
|
46
|
-
if (!channelsObject[name]) {
|
|
47
|
-
channelsObject[name] = { message: null, routes: {} };
|
|
48
|
-
}
|
|
49
|
-
if (message) {
|
|
50
|
-
const func = functionsMeta[message.pikkuFuncName];
|
|
51
|
-
if (!func) {
|
|
52
|
-
throw new Error(`Function ${message.pikkuFuncName} not found in functionsMeta for channel ${name}`);
|
|
53
|
-
}
|
|
54
|
-
const inputTypes = func.inputs || null;
|
|
55
|
-
const outputTypes = func.outputs || null;
|
|
56
|
-
channelsObject[name].message = {
|
|
57
|
-
inputs: inputTypes,
|
|
58
|
-
outputs: outputTypes,
|
|
59
|
-
};
|
|
60
|
-
inputTypes?.forEach((type) => requiredTypes.add(type));
|
|
61
|
-
outputTypes?.forEach((type) => requiredTypes.add(type));
|
|
62
|
-
}
|
|
63
|
-
for (const [key, route] of Object.entries(messageWirings)) {
|
|
64
|
-
if (!channelsObject[name].routes[key]) {
|
|
65
|
-
channelsObject[name].routes[key] = {};
|
|
66
|
-
}
|
|
67
|
-
for (const [method, { pikkuFuncName }] of Object.entries(route)) {
|
|
68
|
-
const func = functionsMeta[pikkuFuncName];
|
|
69
|
-
if (!func) {
|
|
70
|
-
throw new Error(`Function ${pikkuFuncName} not found in functionsMeta for channel ${name}, route ${key}, method ${method}`);
|
|
71
|
-
}
|
|
72
|
-
const inputTypes = func.inputs || null;
|
|
73
|
-
const outputTypes = func.outputs || null;
|
|
74
|
-
channelsObject[name].routes[key][method] = {
|
|
75
|
-
inputTypes,
|
|
76
|
-
outputTypes,
|
|
77
|
-
};
|
|
78
|
-
inputTypes?.forEach((type) => requiredTypes.add(type));
|
|
79
|
-
outputTypes?.forEach((type) => requiredTypes.add(type));
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
let routesStr = 'export type ChannelsMap = {\n';
|
|
84
|
-
for (const [channelPath, { routes, message }] of Object.entries(channelsObject)) {
|
|
85
|
-
routesStr += ` readonly '${channelPath}': {\n`;
|
|
86
|
-
// Add `routes` object
|
|
87
|
-
routesStr += ` readonly routes: {\n`;
|
|
88
|
-
for (const [key, methods] of Object.entries(routes)) {
|
|
89
|
-
routesStr += ` readonly ${key}: {\n`;
|
|
90
|
-
for (const [method, handler] of Object.entries(methods)) {
|
|
91
|
-
routesStr += ` readonly ${method}: ChannelHandler<${formatTypeArray(handler.inputTypes) || 'void'}, ${formatTypeArray(handler.outputTypes) || 'never'}>,\n`;
|
|
92
|
-
}
|
|
93
|
-
routesStr += ' },\n';
|
|
94
|
-
}
|
|
95
|
-
routesStr += ' },\n';
|
|
96
|
-
// Add `defaultMessage` outside `routes`
|
|
97
|
-
if (message) {
|
|
98
|
-
routesStr += ` readonly defaultMessage: ChannelHandler<${formatTypeArray(message.inputs)}, ${formatTypeArray(message.outputs)}>,\n`;
|
|
99
|
-
}
|
|
100
|
-
else {
|
|
101
|
-
routesStr += ` readonly defaultMessage: never,\n`;
|
|
102
|
-
}
|
|
103
|
-
routesStr += ' },\n';
|
|
104
|
-
}
|
|
105
|
-
routesStr += '};';
|
|
106
|
-
return { channels: routesStr, requiredTypes };
|
|
107
|
-
}
|
|
108
|
-
// Utility to format type arrays
|
|
109
|
-
function formatTypeArray(types) {
|
|
110
|
-
return types ? types.join(' | ') : 'null';
|
|
111
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const serializeWebsocketWrapper: (channelsMapPath: string) => string;
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
export const serializeWebsocketWrapper = (channelsMapPath) => {
|
|
2
|
-
return `import { CorePikkuWebsocket, CorePikkuRouteHandler } from '@pikku/websocket'
|
|
3
|
-
import { ChannelDefaultHandlerOf, ChannelRouteHandlerOf, ChannelsMap } from '${channelsMapPath}';
|
|
4
|
-
|
|
5
|
-
class PikkuWebSocketRoute<Channel extends keyof ChannelsMap, Route extends keyof ChannelsMap[Channel]['routes']> extends CorePikkuRouteHandler {
|
|
6
|
-
public subscribe<
|
|
7
|
-
Method extends keyof ChannelsMap[Channel]['routes'][Route],
|
|
8
|
-
Data extends ChannelRouteHandlerOf<Channel, Route, Method>['output']
|
|
9
|
-
>(method: Method, callback: (data: Data) => void
|
|
10
|
-
) {
|
|
11
|
-
super.subscribe(method.toString(), callback)
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
public unsubscribe<
|
|
15
|
-
Method extends keyof ChannelsMap[Channel]['routes'][Route],
|
|
16
|
-
Data extends ChannelRouteHandlerOf<Channel, Route, Method>['output']
|
|
17
|
-
>(method: Method, callback?: (data: Data) => void) {
|
|
18
|
-
super.unsubscribe(method.toString(), callback)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
public send<
|
|
22
|
-
Method extends keyof ChannelsMap[Channel]['routes'][Route],
|
|
23
|
-
Data extends ChannelRouteHandlerOf<Channel, Route, Method>['input']
|
|
24
|
-
>(method: Method, data: Data) {
|
|
25
|
-
super.send(method.toString(), data)
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export class PikkuWebSocket<Channel extends keyof ChannelsMap, Topics extends Record<string, any> = {}> extends CorePikkuWebsocket {
|
|
30
|
-
/**
|
|
31
|
-
* Send a message to a specific route and method.
|
|
32
|
-
* Validates the input data type.
|
|
33
|
-
*/
|
|
34
|
-
public getRoute<Route extends keyof ChannelsMap[Channel]['routes']>(route: Route): PikkuWebSocketRoute<Channel, Route> {
|
|
35
|
-
return super.getRoute(route)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Subscribe to a specific route and method.
|
|
40
|
-
*/
|
|
41
|
-
public subscribe<Data extends ChannelDefaultHandlerOf<Channel>['output']>(
|
|
42
|
-
callback: (data: Data) => void
|
|
43
|
-
) {
|
|
44
|
-
super.subscribe(callback)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Subscribe to a specific route and method.
|
|
49
|
-
*/
|
|
50
|
-
public unsubscribe<Data extends ChannelDefaultHandlerOf<Channel>['output']>(
|
|
51
|
-
callback?: (data: Data) => void
|
|
52
|
-
) {
|
|
53
|
-
super.unsubscribe(callback)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
public send(data: ChannelDefaultHandlerOf<Channel>['input']) {
|
|
57
|
-
super.send(data)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Subscribe to a topic from the EventHub system with strong typing.
|
|
62
|
-
*/
|
|
63
|
-
public subscribeToEventHub<Topic extends keyof EventHubTopics>(
|
|
64
|
-
topic: Topic,
|
|
65
|
-
callback: (data: EventHubTopics[Topic]) => void
|
|
66
|
-
) {
|
|
67
|
-
super.subscribe((data) => {
|
|
68
|
-
if (data.topic === topic) {
|
|
69
|
-
callback(data as EventHubTopics[Topic])
|
|
70
|
-
}
|
|
71
|
-
})
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
`;
|
|
75
|
-
};
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { serializeFetchWrapper } from '../http/serialize-fetch-wrapper.js';
|
|
2
|
-
import { getFileImportRelativePath, logCommandInfoAndTime, writeFileInDir, } from '../../utils.js';
|
|
3
|
-
export const pikkuFetch = async (logger, { fetchFile, httpMapDeclarationFile, packageMappings }) => {
|
|
4
|
-
return await logCommandInfoAndTime(logger, 'Generating fetch wrapper', 'Generated fetch wrapper', [fetchFile === undefined, "fetchFile isn't set in the pikku config"], async () => {
|
|
5
|
-
if (!fetchFile) {
|
|
6
|
-
throw new Error("fetchFile is isn't set in the pikku config");
|
|
7
|
-
}
|
|
8
|
-
const routesMapDeclarationPath = getFileImportRelativePath(fetchFile, httpMapDeclarationFile, packageMappings);
|
|
9
|
-
const content = [serializeFetchWrapper(routesMapDeclarationPath)];
|
|
10
|
-
await writeFileInDir(logger, fetchFile, content.join('\n'));
|
|
11
|
-
});
|
|
12
|
-
};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { getFileImportRelativePath, getPikkuFilesAndMethods, logCommandInfoAndTime, writeFileInDir, } from '../../utils.js';
|
|
2
|
-
import { serializePikkuTypes } from '../../serialize-pikku-types.js';
|
|
3
|
-
export const pikkuFunctionTypes = async (logger, { typesDeclarationFile: typesFile, packageMappings, rpcMapDeclarationFile }, visitState, options = {}) => {
|
|
4
|
-
return await logCommandInfoAndTime(logger, 'Creating api types', 'Created api types', [false], async () => {
|
|
5
|
-
const { userSessionType, sessionServicesType, singletonServicesType } = await getPikkuFilesAndMethods(logger, visitState, packageMappings, typesFile, options, {
|
|
6
|
-
userSessionType: true,
|
|
7
|
-
sessionServiceType: true,
|
|
8
|
-
singletonServicesType: true,
|
|
9
|
-
});
|
|
10
|
-
const content = serializePikkuTypes(`import type { ${userSessionType.type} } from '${getFileImportRelativePath(typesFile, userSessionType.typePath, packageMappings)}'`, userSessionType.type, `import type { ${singletonServicesType.type} } from '${getFileImportRelativePath(typesFile, singletonServicesType.typePath, packageMappings)}'`, singletonServicesType.type, `import type { ${sessionServicesType.type} } from '${getFileImportRelativePath(typesFile, sessionServicesType.typePath, packageMappings)}'`, `import type { TypedPikkuRPC } from '${getFileImportRelativePath(typesFile, rpcMapDeclarationFile, packageMappings)}'`);
|
|
11
|
-
await writeFileInDir(logger, typesFile, content);
|
|
12
|
-
});
|
|
13
|
-
};
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { PikkuCommand } from '../../types.js';
|
|
2
|
-
export declare const serializeFunctionImports: (outputPath: string, functionsMap: Map<string, {
|
|
3
|
-
path: string;
|
|
4
|
-
exportedName: string;
|
|
5
|
-
}>, packageMappings?: Record<string, string>) => string;
|
|
6
|
-
export declare const pikkuFunctions: PikkuCommand;
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { getFileImportRelativePath, logCommandInfoAndTime, writeFileInDir, } from '../../utils.js';
|
|
2
|
-
export const serializeFunctionImports = (outputPath, functionsMap, packageMappings = {}) => {
|
|
3
|
-
const serializedImports = [
|
|
4
|
-
`/* Import and register RPCs */`,
|
|
5
|
-
`import { addFunction } from '@pikku/core'`,
|
|
6
|
-
];
|
|
7
|
-
const serializedRegistrations = [];
|
|
8
|
-
// Sort by function name for consistent output
|
|
9
|
-
const sortedEntries = Array.from(functionsMap.entries()).sort((a, b) => a[0].localeCompare(b[0]));
|
|
10
|
-
for (const [name, { path, exportedName }] of sortedEntries) {
|
|
11
|
-
const filePath = getFileImportRelativePath(outputPath, path, packageMappings);
|
|
12
|
-
// For directly exported functions, we can just import and register them
|
|
13
|
-
if (name === exportedName) {
|
|
14
|
-
serializedImports.push(`import { ${exportedName} } from '${filePath}'`);
|
|
15
|
-
serializedRegistrations.push(`addFunction('${name}', { func: ${exportedName} })`);
|
|
16
|
-
}
|
|
17
|
-
// For renamed functions, we need to import and alias them
|
|
18
|
-
else {
|
|
19
|
-
serializedImports.push(`import { ${exportedName} as ${name} } from '${filePath}'`);
|
|
20
|
-
serializedRegistrations.push(`addFunction('${name}', ${name})`);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
// Add a blank line between imports and registrations
|
|
24
|
-
if (serializedImports.length > 0 && serializedRegistrations.length > 0) {
|
|
25
|
-
serializedImports.push('');
|
|
26
|
-
}
|
|
27
|
-
// Combine the imports and registrations
|
|
28
|
-
return [...serializedImports, ...serializedRegistrations].join('\n');
|
|
29
|
-
};
|
|
30
|
-
export const pikkuFunctions = async (logger, { functionsMetaFile, functionsFile, packageMappings }, { functions }) => {
|
|
31
|
-
return await logCommandInfoAndTime(logger, 'Serializing Pikku functions', 'Serialized Pikku functions', [false], async () => {
|
|
32
|
-
await writeFileInDir(logger, functionsFile, serializeFunctionImports(functionsFile, functions.files, packageMappings));
|
|
33
|
-
await writeFileInDir(logger, functionsMetaFile, `import { pikkuState } from '@pikku/core'\npikkuState('function', 'meta', ${JSON.stringify(functions.meta, null, 2)})`);
|
|
34
|
-
});
|
|
35
|
-
};
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import { PikkuCommand } from '../../types.js';
|
|
2
|
-
export declare const serializeServicesMap: (functionsMetaData: Record<string, any>, middlewareServices: string[] | undefined, servicesImport: string, sessionServicesImport: string) => string;
|
|
3
|
-
export declare const pikkuServices: PikkuCommand;
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { getFileImportRelativePath, getPikkuFilesAndMethods, logCommandInfoAndTime, writeFileInDir, } from '../../utils.js';
|
|
2
|
-
export const serializeServicesMap = (functionsMetaData, middlewareServices = [], servicesImport, sessionServicesImport) => {
|
|
3
|
-
// Extract all unique services from all functions
|
|
4
|
-
const usedServices = new Set();
|
|
5
|
-
// Internal services that are created internally and not via the create service script
|
|
6
|
-
const internalServices = new Set(['rpc', 'mcp', 'channel', 'userSession']);
|
|
7
|
-
for (const funcMeta of Object.values(functionsMetaData)) {
|
|
8
|
-
if (funcMeta.services && Array.isArray(funcMeta.services.services)) {
|
|
9
|
-
funcMeta.services.services.forEach((service) => {
|
|
10
|
-
// Only include services that are not internal
|
|
11
|
-
if (!internalServices.has(service)) {
|
|
12
|
-
usedServices.add(service);
|
|
13
|
-
}
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
// Add middleware services that might not be detected from function inspection
|
|
18
|
-
middlewareServices.forEach((service) => {
|
|
19
|
-
if (!internalServices.has(service)) {
|
|
20
|
-
usedServices.add(service);
|
|
21
|
-
}
|
|
22
|
-
});
|
|
23
|
-
// Create a map of services with true for all needed services
|
|
24
|
-
const servicesMap = Object.fromEntries(Array.from(usedServices)
|
|
25
|
-
.sort()
|
|
26
|
-
.map((service) => [service, true]));
|
|
27
|
-
// Generate the TypeScript code
|
|
28
|
-
const serviceKeys = Object.keys(servicesMap).sort();
|
|
29
|
-
// Services that are always required internally by the framework
|
|
30
|
-
const defaultServices = ['config', 'logger', 'variables', 'schema'];
|
|
31
|
-
// Combine default services with detected services
|
|
32
|
-
const allRequiredServices = [
|
|
33
|
-
...new Set([...defaultServices, ...serviceKeys]),
|
|
34
|
-
].sort();
|
|
35
|
-
// For RequiredSingletonServices, we need to pick from the actual SingletonServices interface
|
|
36
|
-
// This will be resolved at compile time based on what's actually in the SingletonServices interface
|
|
37
|
-
// We don't need to hardcode which services are singletons beyond the core framework ones
|
|
38
|
-
const code = [
|
|
39
|
-
'/**',
|
|
40
|
-
' * This file was generated by the @pikku/cli',
|
|
41
|
-
' */',
|
|
42
|
-
'',
|
|
43
|
-
servicesImport,
|
|
44
|
-
sessionServicesImport,
|
|
45
|
-
"import type { PikkuInteraction } from '@pikku/core'",
|
|
46
|
-
'',
|
|
47
|
-
'export const singletonServices = {',
|
|
48
|
-
...Object.keys(servicesMap).map((service) => ` '${service}': true,`),
|
|
49
|
-
'} as const',
|
|
50
|
-
'',
|
|
51
|
-
'// Singleton services (created once at startup)',
|
|
52
|
-
'// Only includes services that are both required and available in SingletonServices',
|
|
53
|
-
`export type RequiredSingletonServices = Pick<SingletonServices, Extract<keyof SingletonServices, ${allRequiredServices.map((key) => `'${key}'`).join(' | ')}>> & Partial<Omit<SingletonServices, ${allRequiredServices.map((key) => `'${key}'`).join(' | ')}>>`,
|
|
54
|
-
'',
|
|
55
|
-
'// Session services (created per request, can access singleton services)',
|
|
56
|
-
'// Omits singleton services and PikkuInteraction (mcp, rpc, http, channel)',
|
|
57
|
-
`export type RequiredSessionServices = Omit<Services, keyof SingletonServices | keyof PikkuInteraction>`,
|
|
58
|
-
'',
|
|
59
|
-
].join('\n');
|
|
60
|
-
return code;
|
|
61
|
-
};
|
|
62
|
-
export const pikkuServices = async (logger, cliConfig, visitState) => {
|
|
63
|
-
return await logCommandInfoAndTime(logger, 'Generating Pikku services map', 'Generated Pikku services map', [visitState.functions.files.size === 0], async () => {
|
|
64
|
-
const { sessionServicesType, singletonServicesType } = await getPikkuFilesAndMethods(logger, visitState, cliConfig.packageMappings, cliConfig.typesDeclarationFile, {}, {
|
|
65
|
-
sessionServiceType: true,
|
|
66
|
-
singletonServicesType: true,
|
|
67
|
-
});
|
|
68
|
-
const servicesImport = `import type { ${singletonServicesType.type} } from '${getFileImportRelativePath(cliConfig.typesDeclarationFile, singletonServicesType.typePath, cliConfig.packageMappings)}'`;
|
|
69
|
-
const sessionServicesImport = `import type { ${sessionServicesType.type} } from '${getFileImportRelativePath(cliConfig.typesDeclarationFile, sessionServicesType.typePath, cliConfig.packageMappings)}'`;
|
|
70
|
-
const servicesCode = serializeServicesMap(visitState.functions.meta, cliConfig.middlewareServices, servicesImport, sessionServicesImport);
|
|
71
|
-
await writeFileInDir(logger, cliConfig.servicesFile, servicesCode);
|
|
72
|
-
});
|
|
73
|
-
};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { getFileImportRelativePath, getPikkuFilesAndMethods, logCommandInfoAndTime, writeFileInDir, } from '../../utils.js';
|
|
2
|
-
import { serializePikkuTypes } from '../../serialize-pikku-types.js';
|
|
3
|
-
export const pikkuFunctionTypes = async (logger, { typesDeclarationFile: typesFile, packageMappings, rpcMapDeclarationFile }, visitState, options = {}) => {
|
|
4
|
-
return await logCommandInfoAndTime(logger, 'Creating api types', 'Created api types', [false], async () => {
|
|
5
|
-
const { userSessionType, sessionServicesType, singletonServicesType } = await getPikkuFilesAndMethods(logger, visitState, packageMappings, typesFile, options, {
|
|
6
|
-
userSessionType: true,
|
|
7
|
-
sessionServiceType: true,
|
|
8
|
-
singletonServicesType: true,
|
|
9
|
-
});
|
|
10
|
-
const content = serializePikkuTypes(`import type { ${userSessionType.type} } from '${getFileImportRelativePath(typesFile, userSessionType.typePath, packageMappings)}'`, userSessionType.type, `import type { ${singletonServicesType.type} } from '${getFileImportRelativePath(typesFile, singletonServicesType.typePath, packageMappings)}'`, singletonServicesType.type, `import type { ${sessionServicesType.type} } from '${getFileImportRelativePath(typesFile, sessionServicesType.typePath, packageMappings)}'`, `import type { TypedPikkuRPC } from '${getFileImportRelativePath(typesFile, rpcMapDeclarationFile, packageMappings)}'`);
|
|
11
|
-
await writeFileInDir(logger, typesFile, content);
|
|
12
|
-
});
|
|
13
|
-
};
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { PikkuCommand } from '../../types.js';
|
|
2
|
-
export declare const serializeFunctionImports: (outputPath: string, functionsMap: Map<string, {
|
|
3
|
-
path: string;
|
|
4
|
-
exportedName: string;
|
|
5
|
-
}>, packageMappings?: Record<string, string>) => string;
|
|
6
|
-
export declare const pikkuFunctions: PikkuCommand;
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { getFileImportRelativePath, logCommandInfoAndTime, writeFileInDir, } from '../../utils.js';
|
|
2
|
-
export const serializeFunctionImports = (outputPath, functionsMap, packageMappings = {}) => {
|
|
3
|
-
const serializedImports = [
|
|
4
|
-
`/* Import and register RPCs */`,
|
|
5
|
-
`import { addFunction } from '@pikku/core'`,
|
|
6
|
-
];
|
|
7
|
-
const serializedRegistrations = [];
|
|
8
|
-
// Sort by function name for consistent output
|
|
9
|
-
const sortedEntries = Array.from(functionsMap.entries()).sort((a, b) => a[0].localeCompare(b[0]));
|
|
10
|
-
for (const [name, { path, exportedName }] of sortedEntries) {
|
|
11
|
-
const filePath = getFileImportRelativePath(outputPath, path, packageMappings);
|
|
12
|
-
// For directly exported functions, we can just import and register them
|
|
13
|
-
if (name === exportedName) {
|
|
14
|
-
serializedImports.push(`import { ${exportedName} } from '${filePath}'`);
|
|
15
|
-
serializedRegistrations.push(`addFunction('${name}', { func: ${exportedName} })`);
|
|
16
|
-
}
|
|
17
|
-
// For renamed functions, we need to import and alias them
|
|
18
|
-
else {
|
|
19
|
-
serializedImports.push(`import { ${exportedName} as ${name} } from '${filePath}'`);
|
|
20
|
-
serializedRegistrations.push(`addFunction('${name}', ${name})`);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
// Add a blank line between imports and registrations
|
|
24
|
-
if (serializedImports.length > 0 && serializedRegistrations.length > 0) {
|
|
25
|
-
serializedImports.push('');
|
|
26
|
-
}
|
|
27
|
-
// Combine the imports and registrations
|
|
28
|
-
return [...serializedImports, ...serializedRegistrations].join('\n');
|
|
29
|
-
};
|
|
30
|
-
export const pikkuFunctions = async (logger, { functionsMetaFile, functionsFile, packageMappings }, { functions }) => {
|
|
31
|
-
return await logCommandInfoAndTime(logger, 'Serializing Pikku functions', 'Serialized Pikku functions', [false], async () => {
|
|
32
|
-
await writeFileInDir(logger, functionsFile, serializeFunctionImports(functionsFile, functions.files, packageMappings));
|
|
33
|
-
await writeFileInDir(logger, functionsMetaFile, `import { pikkuState } from '@pikku/core'\npikkuState('function', 'meta', ${JSON.stringify(functions.meta, null, 2)})`);
|
|
34
|
-
});
|
|
35
|
-
};
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { FunctionsMeta, HTTPWiringsMeta } from '@pikku/core';
|
|
2
|
-
interface OpenAPISpec {
|
|
3
|
-
openapi: string;
|
|
4
|
-
info: {
|
|
5
|
-
title: string;
|
|
6
|
-
version: string;
|
|
7
|
-
description?: string;
|
|
8
|
-
termsOfService?: string;
|
|
9
|
-
contact?: {
|
|
10
|
-
name?: string;
|
|
11
|
-
url?: string;
|
|
12
|
-
email?: string;
|
|
13
|
-
};
|
|
14
|
-
license?: {
|
|
15
|
-
name: string;
|
|
16
|
-
url?: string;
|
|
17
|
-
};
|
|
18
|
-
};
|
|
19
|
-
servers: {
|
|
20
|
-
url: string;
|
|
21
|
-
description?: string;
|
|
22
|
-
}[];
|
|
23
|
-
paths: Record<string, any>;
|
|
24
|
-
components: {
|
|
25
|
-
schemas: Record<string, any>;
|
|
26
|
-
responses?: Record<string, any>;
|
|
27
|
-
parameters?: Record<string, any>;
|
|
28
|
-
examples?: Record<string, any>;
|
|
29
|
-
requestBodies?: Record<string, any>;
|
|
30
|
-
headers?: Record<string, any>;
|
|
31
|
-
securitySchemes?: Record<string, any>;
|
|
32
|
-
};
|
|
33
|
-
security?: {
|
|
34
|
-
[key: string]: any[];
|
|
35
|
-
}[];
|
|
36
|
-
tags?: {
|
|
37
|
-
name: string;
|
|
38
|
-
description?: string;
|
|
39
|
-
}[];
|
|
40
|
-
externalDocs?: {
|
|
41
|
-
description?: string;
|
|
42
|
-
url: string;
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
export interface OpenAPISpecInfo {
|
|
46
|
-
info: {
|
|
47
|
-
title: string;
|
|
48
|
-
version: string;
|
|
49
|
-
description: string;
|
|
50
|
-
termsOfService?: string;
|
|
51
|
-
contact?: {
|
|
52
|
-
name?: string;
|
|
53
|
-
url?: string;
|
|
54
|
-
email?: string;
|
|
55
|
-
};
|
|
56
|
-
license?: {
|
|
57
|
-
name: string;
|
|
58
|
-
url?: string;
|
|
59
|
-
};
|
|
60
|
-
};
|
|
61
|
-
servers: {
|
|
62
|
-
url: string;
|
|
63
|
-
description?: string;
|
|
64
|
-
}[];
|
|
65
|
-
tags?: {
|
|
66
|
-
name: string;
|
|
67
|
-
description?: string;
|
|
68
|
-
}[];
|
|
69
|
-
externalDocs?: {
|
|
70
|
-
description?: string;
|
|
71
|
-
url: string;
|
|
72
|
-
};
|
|
73
|
-
securitySchemes?: Record<string, any>;
|
|
74
|
-
security?: {
|
|
75
|
-
[key: string]: any[];
|
|
76
|
-
}[];
|
|
77
|
-
}
|
|
78
|
-
export declare function generateOpenAPISpec(functionsMeta: FunctionsMeta, routeMeta: HTTPWiringsMeta, schemas: Record<string, any>, additionalInfo: OpenAPISpecInfo): Promise<OpenAPISpec>;
|
|
79
|
-
export {};
|
|
@@ -1,145 +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 (functionsMeta, routesMeta, schemas) => {
|
|
13
|
-
const requiredSchemas = new Set(routesMeta
|
|
14
|
-
.map(({ inputTypes, pikkuFuncName }) => {
|
|
15
|
-
const output = functionsMeta[pikkuFuncName]?.outputs?.[0];
|
|
16
|
-
return [inputTypes?.body, output];
|
|
17
|
-
})
|
|
18
|
-
.flat()
|
|
19
|
-
.filter((schema) => !!schema));
|
|
20
|
-
const convertedEntries = await Promise.all(Object.entries(schemas).map(async ([key, schema]) => {
|
|
21
|
-
if (requiredSchemas.has(key)) {
|
|
22
|
-
const convertedSchema = await convertSchema(schema, {
|
|
23
|
-
convertUnreferencedDefinitions: false,
|
|
24
|
-
dereference: { circular: 'ignore' },
|
|
25
|
-
});
|
|
26
|
-
return [key, convertedSchema];
|
|
27
|
-
}
|
|
28
|
-
return;
|
|
29
|
-
}));
|
|
30
|
-
return Object.fromEntries(convertedEntries.filter((s) => !!s));
|
|
31
|
-
};
|
|
32
|
-
export async function generateOpenAPISpec(functionsMeta, routeMeta, schemas, additionalInfo) {
|
|
33
|
-
const paths = {};
|
|
34
|
-
routeMeta.forEach((meta) => {
|
|
35
|
-
const { route, method, inputTypes, pikkuFuncName, params, query, docs } = meta;
|
|
36
|
-
const functionMeta = functionsMeta[pikkuFuncName];
|
|
37
|
-
if (!functionMeta) {
|
|
38
|
-
console.error(`• No function metadata found for '${pikkuFuncName}' in route '${route}'.`);
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
const output = functionMeta.outputs ? functionMeta.outputs[0] : undefined;
|
|
42
|
-
const path = route.replace(/:(\w+)/g, '{$1}'); // Convert ":param" to "{param}"
|
|
43
|
-
if (!paths[path]) {
|
|
44
|
-
paths[path] = {};
|
|
45
|
-
}
|
|
46
|
-
const responses = {};
|
|
47
|
-
docs?.errors?.forEach((error) => {
|
|
48
|
-
const errorResponse = getErrorResponseForConstructorName(error);
|
|
49
|
-
if (errorResponse) {
|
|
50
|
-
responses[errorResponse.status] = {
|
|
51
|
-
description: errorResponse.message,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
const operation = {
|
|
56
|
-
description: docs?.description ||
|
|
57
|
-
`This endpoint handles the ${method.toUpperCase()} request for the route ${route}.`,
|
|
58
|
-
tags: docs?.tags || [route.split('/')[1] || 'default'],
|
|
59
|
-
parameters: [],
|
|
60
|
-
responses: {
|
|
61
|
-
...responses,
|
|
62
|
-
'200': {
|
|
63
|
-
description: 'Successful response',
|
|
64
|
-
content: output
|
|
65
|
-
? {
|
|
66
|
-
'application/json': {
|
|
67
|
-
schema: typeof output === 'string' &&
|
|
68
|
-
['boolean', 'string', 'number'].includes(output)
|
|
69
|
-
? { type: output }
|
|
70
|
-
: { $ref: `#/components/schemas/${output}` },
|
|
71
|
-
},
|
|
72
|
-
}
|
|
73
|
-
: undefined,
|
|
74
|
-
},
|
|
75
|
-
},
|
|
76
|
-
};
|
|
77
|
-
const bodyType = inputTypes?.body;
|
|
78
|
-
if (bodyType) {
|
|
79
|
-
operation.requestBody = {
|
|
80
|
-
required: true,
|
|
81
|
-
content: {
|
|
82
|
-
'application/json': {
|
|
83
|
-
schema: typeof bodyType === 'string' &&
|
|
84
|
-
['boolean', 'string', 'number'].includes(bodyType)
|
|
85
|
-
? { type: bodyType }
|
|
86
|
-
: { $ref: `#/components/schemas/${bodyType}` },
|
|
87
|
-
},
|
|
88
|
-
},
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
if (params) {
|
|
92
|
-
operation.parameters = params.map((param) => ({
|
|
93
|
-
name: param,
|
|
94
|
-
in: 'path',
|
|
95
|
-
required: true,
|
|
96
|
-
schema: { type: 'string' },
|
|
97
|
-
}));
|
|
98
|
-
}
|
|
99
|
-
if (query) {
|
|
100
|
-
operation.parameters.push(...query.map((query) => ({
|
|
101
|
-
name: query,
|
|
102
|
-
in: 'query',
|
|
103
|
-
required: false,
|
|
104
|
-
schema: { type: 'string' },
|
|
105
|
-
})));
|
|
106
|
-
}
|
|
107
|
-
paths[path][method] = operation;
|
|
108
|
-
});
|
|
109
|
-
return {
|
|
110
|
-
openapi: '3.1.0',
|
|
111
|
-
info: additionalInfo.info,
|
|
112
|
-
servers: additionalInfo.servers,
|
|
113
|
-
paths,
|
|
114
|
-
components: {
|
|
115
|
-
schemas: await convertSchemasToBodyPayloads(functionsMeta, routeMeta, schemas),
|
|
116
|
-
responses: {},
|
|
117
|
-
parameters: {},
|
|
118
|
-
examples: {},
|
|
119
|
-
requestBodies: {},
|
|
120
|
-
headers: {},
|
|
121
|
-
securitySchemes: additionalInfo.securitySchemes || {
|
|
122
|
-
ApiKeyAuth: {
|
|
123
|
-
type: 'apiKey',
|
|
124
|
-
in: 'header',
|
|
125
|
-
name: 'x-api-key',
|
|
126
|
-
},
|
|
127
|
-
BearerAuth: {
|
|
128
|
-
type: 'http',
|
|
129
|
-
scheme: 'bearer',
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
|
-
},
|
|
133
|
-
security: additionalInfo.security || [
|
|
134
|
-
{
|
|
135
|
-
ApiKeyAuth: [],
|
|
136
|
-
},
|
|
137
|
-
{
|
|
138
|
-
BearerAuth: [],
|
|
139
|
-
},
|
|
140
|
-
],
|
|
141
|
-
tags: additionalInfo.tags,
|
|
142
|
-
externalDocs: additionalInfo.externalDocs,
|
|
143
|
-
// definitions
|
|
144
|
-
};
|
|
145
|
-
}
|