@pikku/cli 0.8.0 → 0.8.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 +37 -0
- package/bin/pikku-all.ts +122 -64
- package/bin/pikku-fetch.ts +5 -1
- package/bin/pikku-nextjs.ts +6 -2
- package/bin/pikku-openapi.ts +3 -1
- package/bin/pikku-queue-service.ts +5 -1
- package/bin/pikku-websocket.ts +5 -1
- package/cli.schema.json +131 -10
- package/dist/bin/pikku-all.js +51 -50
- package/dist/bin/pikku-fetch.js +5 -1
- package/dist/bin/pikku-nextjs.js +6 -2
- package/dist/bin/pikku-openapi.js +3 -1
- package/dist/bin/pikku-queue-service.js +5 -1
- package/dist/bin/pikku-websocket.js +5 -1
- package/dist/src/events/functions/pikku-command-services.d.ts +3 -0
- package/dist/src/events/functions/pikku-command-services.js +73 -0
- package/dist/src/events/http/serialize-typed-http-map.d.ts +0 -1
- package/dist/src/events/http/serialize-typed-http-map.js +1 -14
- package/dist/src/events/rpc/pikku-command-rpc-client.d.ts +2 -0
- package/dist/src/events/rpc/pikku-command-rpc-client.js +12 -0
- package/dist/src/events/rpc/serialize-rpc-wrapper.d.ts +1 -0
- package/dist/src/events/rpc/serialize-rpc-wrapper.js +29 -0
- package/dist/src/events/rpc/serialize-typed-rpc-map.js +1 -1
- package/dist/src/inspector-glob.js +1 -1
- package/dist/src/pikku-cli-config.d.ts +4 -1
- package/dist/src/pikku-cli-config.js +26 -14
- package/dist/src/schema-generator.js +2 -2
- package/dist/src/utils.d.ts +3 -0
- package/dist/src/utils.js +25 -6
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/events/functions/pikku-command-services.ts +125 -0
- package/src/events/http/serialize-typed-http-map.ts +1 -18
- package/src/events/rpc/pikku-command-rpc-client.ts +33 -0
- package/src/events/rpc/serialize-rpc-wrapper.ts +29 -0
- package/src/events/rpc/serialize-typed-rpc-map.ts +1 -1
- package/src/inspector-glob.ts +1 -1
- package/src/pikku-cli-config.ts +33 -17
- package/src/schema-generator.ts +2 -2
- package/src/utils.test.ts +137 -0
- package/src/utils.ts +31 -6
- package/dist/src/events/http/pikku-command-nextjs.d.ts +0 -2
- package/dist/src/events/http/pikku-command-nextjs.js +0 -36
- package/src/events/http/pikku-command-nextjs.ts +0 -111
package/dist/bin/pikku-all.js
CHANGED
|
@@ -9,46 +9,37 @@ import { pikkuChannels } from '../src/events/channels/pikku-command-channels.js'
|
|
|
9
9
|
import { inspectorGlob } from '../src/inspector-glob.js';
|
|
10
10
|
import chokidar from 'chokidar';
|
|
11
11
|
import { pikkuFunctions } from '../src/events/functions/pikku-command-functions.js';
|
|
12
|
+
import { pikkuServices } from '../src/events/functions/pikku-command-services.js';
|
|
12
13
|
import { pikkuRPC } from '../src/events/rpc/pikku-command-rpc.js';
|
|
13
14
|
import { pikkuRPCMap } from '../src/events/rpc/pikku-command-rpc-map.js';
|
|
14
|
-
import { PikkuEventTypes } from '@pikku/core';
|
|
15
15
|
import { pikkuQueue } from '../src/events/queue/pikku-command-queue.js';
|
|
16
16
|
import { pikkuQueueMap } from '../src/events/queue/pikku-command-queue-map.js';
|
|
17
17
|
import { pikkuFetch } from '../src/events/fetch/index.js';
|
|
18
|
+
import { pikkuRPCClient } from '../src/events/rpc/pikku-command-rpc-client.js';
|
|
18
19
|
import { pikkuWebSocketTyped } from '../src/events/channels/pikku-command-websocket-typed.js';
|
|
19
|
-
import { pikkuNext } from '../src/events/http/pikku-command-nextjs.js';
|
|
20
20
|
import { pikkuOpenAPI } from '../src/events/http/pikku-command-openapi.js';
|
|
21
21
|
import { pikkuMCP } from '../src/events/mcp/pikku-command-mcp.js';
|
|
22
22
|
import { pikkuQueueService } from '../src/events/queue/pikku-command-queue-service.js';
|
|
23
23
|
import { pikkuScheduler } from '../src/events/scheduler/pikku-command-scheduler.js';
|
|
24
24
|
import { pikkuSchemas } from '../src/schemas.js';
|
|
25
25
|
import { pikkuMCPJSON } from '../src/events/mcp/pikku-command-mcp-json.js';
|
|
26
|
+
import { pikkuNext } from '../src/runtimes/nextjs/pikku-command-nextjs.js';
|
|
27
|
+
const generateBootstrapFile = async (logger, cliConfig, bootstrapFile, specificImports, schemas) => {
|
|
28
|
+
// Common imports that every bootstrap file needs
|
|
29
|
+
const commonImports = [cliConfig.functionsMetaFile, cliConfig.functionsFile];
|
|
30
|
+
// Add schema if it exists
|
|
31
|
+
if (schemas) {
|
|
32
|
+
commonImports.push(`${cliConfig.schemaDirectory}/register.gen.ts`);
|
|
33
|
+
}
|
|
34
|
+
// Combine common imports with specific imports
|
|
35
|
+
const allImports = [...commonImports, ...specificImports];
|
|
36
|
+
await writeFileInDir(logger, bootstrapFile, allImports
|
|
37
|
+
.map((to) => `import '${getFileImportRelativePath(bootstrapFile, to, cliConfig.packageMappings)}'`)
|
|
38
|
+
.sort((to) => (to.includes('meta') ? -1 : 1)) // Ensure meta files are at the top
|
|
39
|
+
.join('\n'));
|
|
40
|
+
};
|
|
26
41
|
const runAll = async (logger, cliConfig, options) => {
|
|
27
|
-
const
|
|
28
|
-
all: { meta: [], events: [] },
|
|
29
|
-
};
|
|
30
|
-
const addImport = (from, type, addTo) => {
|
|
31
|
-
if (type === 'meta') {
|
|
32
|
-
boostrapImports.all.meta.push(from);
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
boostrapImports.all.events.push(from);
|
|
36
|
-
}
|
|
37
|
-
for (const transport of Object.keys(PikkuEventTypes)) {
|
|
38
|
-
if (!addTo || addTo?.includes(transport)) {
|
|
39
|
-
boostrapImports[transport] = boostrapImports[transport] || {
|
|
40
|
-
meta: [],
|
|
41
|
-
events: [],
|
|
42
|
-
};
|
|
43
|
-
if (type === 'meta') {
|
|
44
|
-
boostrapImports[transport].meta.push(from);
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
boostrapImports[transport].events.push(from);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
};
|
|
42
|
+
const allImports = [];
|
|
52
43
|
let typesDeclarationFileExists = true;
|
|
53
44
|
let visitState = await inspectorGlob(logger, cliConfig.rootDir, cliConfig.srcDirectories, cliConfig.filters);
|
|
54
45
|
if (!existsSync(cliConfig.typesDeclarationFile)) {
|
|
@@ -65,46 +56,51 @@ const runAll = async (logger, cliConfig, options) => {
|
|
|
65
56
|
logger.info(`• No functions found, skipping remaining steps...\x1b[0m`);
|
|
66
57
|
process.exit(1);
|
|
67
58
|
}
|
|
68
|
-
|
|
69
|
-
|
|
59
|
+
// Base imports for all bootstrap files
|
|
60
|
+
allImports.push(cliConfig.functionsMetaFile, cliConfig.functionsFile);
|
|
61
|
+
// Generate services map
|
|
62
|
+
await pikkuServices(logger, cliConfig, visitState);
|
|
70
63
|
await pikkuRPC(logger, cliConfig, visitState);
|
|
71
64
|
await pikkuRPCMap(logger, cliConfig, visitState);
|
|
72
|
-
|
|
65
|
+
await pikkuRPCClient(logger, cliConfig);
|
|
66
|
+
allImports.push(cliConfig.rpcMetaFile);
|
|
73
67
|
const schemas = await pikkuSchemas(logger, cliConfig, visitState);
|
|
74
68
|
if (schemas) {
|
|
75
|
-
|
|
69
|
+
allImports.push(`${cliConfig.schemaDirectory}/register.gen.ts`);
|
|
76
70
|
}
|
|
71
|
+
// RPC bootstrap is always generated since RPC is always present
|
|
72
|
+
await generateBootstrapFile(logger, cliConfig, cliConfig.bootstrapFiles.rpc, [cliConfig.rpcMetaFile], schemas);
|
|
77
73
|
const http = await pikkuHTTP(logger, cliConfig, visitState);
|
|
78
74
|
if (http) {
|
|
79
75
|
await pikkuHTTPMap(logger, cliConfig, visitState);
|
|
80
76
|
await pikkuFetch(logger, cliConfig);
|
|
81
|
-
|
|
82
|
-
|
|
77
|
+
allImports.push(cliConfig.httpRoutesMetaFile, cliConfig.httpRoutesFile);
|
|
78
|
+
await generateBootstrapFile(logger, cliConfig, cliConfig.bootstrapFiles.http, [cliConfig.httpRoutesMetaFile, cliConfig.httpRoutesFile], schemas);
|
|
83
79
|
}
|
|
84
|
-
const
|
|
85
|
-
if (
|
|
86
|
-
|
|
87
|
-
|
|
80
|
+
const scheduler = await pikkuScheduler(logger, cliConfig, visitState);
|
|
81
|
+
if (scheduler) {
|
|
82
|
+
allImports.push(cliConfig.schedulersMetaFile, cliConfig.schedulersFile);
|
|
83
|
+
await generateBootstrapFile(logger, cliConfig, cliConfig.bootstrapFiles.scheduler, [cliConfig.schedulersMetaFile, cliConfig.schedulersFile], schemas);
|
|
88
84
|
}
|
|
89
85
|
const queues = await pikkuQueue(logger, cliConfig, visitState);
|
|
90
86
|
if (queues) {
|
|
91
87
|
await pikkuQueueMap(logger, cliConfig, visitState);
|
|
92
88
|
await pikkuQueueService(logger, cliConfig);
|
|
93
|
-
|
|
94
|
-
|
|
89
|
+
allImports.push(cliConfig.queueWorkersMetaFile, cliConfig.queueWorkersFile);
|
|
90
|
+
await generateBootstrapFile(logger, cliConfig, cliConfig.bootstrapFiles.queue, [cliConfig.queueWorkersMetaFile, cliConfig.queueWorkersFile], schemas);
|
|
95
91
|
}
|
|
96
92
|
const channels = await pikkuChannels(logger, cliConfig, visitState);
|
|
97
93
|
if (channels) {
|
|
98
94
|
await pikkuChannelsMap(logger, cliConfig, visitState);
|
|
99
95
|
await pikkuWebSocketTyped(logger, cliConfig);
|
|
100
|
-
|
|
101
|
-
|
|
96
|
+
allImports.push(cliConfig.channelsMetaFile, cliConfig.channelsFile);
|
|
97
|
+
await generateBootstrapFile(logger, cliConfig, cliConfig.bootstrapFiles.channel, [cliConfig.channelsMetaFile, cliConfig.channelsFile], schemas);
|
|
102
98
|
}
|
|
103
99
|
const mcp = await pikkuMCP(logger, cliConfig, visitState);
|
|
104
100
|
if (mcp) {
|
|
105
101
|
await pikkuMCPJSON(logger, cliConfig, visitState);
|
|
106
|
-
|
|
107
|
-
|
|
102
|
+
allImports.push(cliConfig.mcpEndpointsMetaFile, cliConfig.mcpEndpointsFile);
|
|
103
|
+
await generateBootstrapFile(logger, cliConfig, cliConfig.bootstrapFiles.mcp, [cliConfig.mcpEndpointsMetaFile, cliConfig.mcpEndpointsFile], schemas);
|
|
108
104
|
}
|
|
109
105
|
if (cliConfig.nextBackendFile || cliConfig.nextHTTPFile) {
|
|
110
106
|
await pikkuNext(logger, cliConfig, visitState, options);
|
|
@@ -114,12 +110,11 @@ const runAll = async (logger, cliConfig, options) => {
|
|
|
114
110
|
visitState = await inspectorGlob(logger, cliConfig.rootDir, cliConfig.srcDirectories, cliConfig.filters);
|
|
115
111
|
await pikkuOpenAPI(logger, cliConfig, visitState);
|
|
116
112
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
113
|
+
// Generate main bootstrap file (pass all imports directly since this is the main file)
|
|
114
|
+
await writeFileInDir(logger, cliConfig.bootstrapFile, allImports
|
|
115
|
+
.map((to) => `import '${getFileImportRelativePath(cliConfig.bootstrapFile, to, cliConfig.packageMappings)}'`)
|
|
116
|
+
.sort((to) => (to.includes('meta') ? -1 : 1)) // Ensure meta files are at the top
|
|
117
|
+
.join('\n'));
|
|
123
118
|
};
|
|
124
119
|
const watch = (logger, cliConfig, options) => {
|
|
125
120
|
const configWatcher = chokidar.watch(cliConfig.srcDirectories, {
|
|
@@ -162,7 +157,11 @@ const watch = (logger, cliConfig, options) => {
|
|
|
162
157
|
};
|
|
163
158
|
export const action = async (options) => {
|
|
164
159
|
const logger = new CLILogger({ logLogo: true });
|
|
165
|
-
const cliConfig = await getPikkuCLIConfig(options.config, [],
|
|
160
|
+
const cliConfig = await getPikkuCLIConfig(options.config, [], {
|
|
161
|
+
tags: options.tags,
|
|
162
|
+
types: options.types,
|
|
163
|
+
directories: options.directories,
|
|
164
|
+
}, true);
|
|
166
165
|
if (options.watch) {
|
|
167
166
|
watch(logger, cliConfig, options);
|
|
168
167
|
}
|
|
@@ -179,6 +178,8 @@ export const all = (program) => {
|
|
|
179
178
|
.option('-se | --session-services-factory-type', 'The type of your session services factory')
|
|
180
179
|
.option('-c | --config <string>', 'The path to pikku cli config file')
|
|
181
180
|
.option('-t | --tags <tags...>', 'Which tags to filter by')
|
|
181
|
+
.option('--types <types...>', 'Which types to filter by (http, channel, queue, scheduler, rpc, mcp)')
|
|
182
|
+
.option('--directories <directories...>', 'Which directories to filter by')
|
|
182
183
|
.option('-w | --watch', 'Whether to watch file changes')
|
|
183
184
|
.action(action);
|
|
184
185
|
};
|
package/dist/bin/pikku-fetch.js
CHANGED
|
@@ -3,7 +3,11 @@ import { pikkuFetch } from '../src/events/fetch/index.js';
|
|
|
3
3
|
import { CLILogger } from '../src/utils.js';
|
|
4
4
|
export const action = async (options) => {
|
|
5
5
|
const logger = new CLILogger({ logLogo: true });
|
|
6
|
-
const cliConfig = await getPikkuCLIConfig(options.config, ['rootDir', 'schemaDirectory', 'configDir', 'fetchFile'],
|
|
6
|
+
const cliConfig = await getPikkuCLIConfig(options.config, ['rootDir', 'schemaDirectory', 'configDir', 'fetchFile'], {
|
|
7
|
+
tags: options.tags,
|
|
8
|
+
types: options.types,
|
|
9
|
+
directories: options.directories,
|
|
10
|
+
}, true);
|
|
7
11
|
await pikkuFetch(logger, cliConfig);
|
|
8
12
|
};
|
|
9
13
|
export const fetch = (program) => {
|
package/dist/bin/pikku-nextjs.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { CLILogger } from '../src/utils.js';
|
|
2
2
|
import { getPikkuCLIConfig } from '../src/pikku-cli-config.js';
|
|
3
3
|
import { inspectorGlob } from '../src/inspector-glob.js';
|
|
4
|
-
import { pikkuNext } from '../src/
|
|
4
|
+
import { pikkuNext } from '../src/runtimes/nextjs/pikku-command-nextjs.js';
|
|
5
5
|
export const action = async (options) => {
|
|
6
6
|
const logger = new CLILogger({ logLogo: true });
|
|
7
|
-
const cliConfig = await getPikkuCLIConfig(options.config, ['rootDir', 'schemaDirectory', 'configDir'],
|
|
7
|
+
const cliConfig = await getPikkuCLIConfig(options.config, ['rootDir', 'schemaDirectory', 'configDir'], {
|
|
8
|
+
tags: options.tags,
|
|
9
|
+
types: options.types,
|
|
10
|
+
directories: options.directories,
|
|
11
|
+
}, true);
|
|
8
12
|
const visitState = await inspectorGlob(logger, cliConfig.rootDir, cliConfig.srcDirectories, cliConfig.filters);
|
|
9
13
|
await pikkuNext(logger, cliConfig, visitState, options);
|
|
10
14
|
};
|
|
@@ -4,7 +4,9 @@ import { inspectorGlob } from '../src/inspector-glob.js';
|
|
|
4
4
|
import { pikkuOpenAPI } from '../src/events/http/pikku-command-openapi.js';
|
|
5
5
|
async function action({ config, tags }) {
|
|
6
6
|
const logger = new CLILogger({ logLogo: true });
|
|
7
|
-
const cliConfig = await getPikkuCLIConfig(config, ['rootDir', 'httpRoutesFile', 'openAPI', 'schemaDirectory', 'tsconfig'],
|
|
7
|
+
const cliConfig = await getPikkuCLIConfig(config, ['rootDir', 'httpRoutesFile', 'openAPI', 'schemaDirectory', 'tsconfig'], {
|
|
8
|
+
tags: tags || [],
|
|
9
|
+
});
|
|
8
10
|
const visitState = await inspectorGlob(logger, cliConfig.rootDir, cliConfig.srcDirectories, cliConfig.filters);
|
|
9
11
|
await pikkuOpenAPI(logger, cliConfig, visitState);
|
|
10
12
|
}
|
|
@@ -3,7 +3,11 @@ import { CLILogger } from '../src/utils.js';
|
|
|
3
3
|
import { pikkuQueueService } from '../src/events/queue/pikku-command-queue-service.js';
|
|
4
4
|
export const action = async (options) => {
|
|
5
5
|
const logger = new CLILogger({ logLogo: true });
|
|
6
|
-
const cliConfig = await getPikkuCLIConfig(options.config, ['rootDir', 'schemaDirectory', 'configDir', 'queueFile'],
|
|
6
|
+
const cliConfig = await getPikkuCLIConfig(options.config, ['rootDir', 'schemaDirectory', 'configDir', 'queueFile'], {
|
|
7
|
+
tags: options.tags,
|
|
8
|
+
types: options.types,
|
|
9
|
+
directories: options.directories,
|
|
10
|
+
}, true);
|
|
7
11
|
await pikkuQueueService(logger, cliConfig);
|
|
8
12
|
};
|
|
9
13
|
export const queue = (program) => {
|
|
@@ -3,7 +3,11 @@ import { getPikkuCLIConfig } from '../src/pikku-cli-config.js';
|
|
|
3
3
|
import { pikkuWebSocketTyped } from '../src/events/channels/pikku-command-websocket-typed.js';
|
|
4
4
|
export const action = async (options) => {
|
|
5
5
|
const logger = new CLILogger({ logLogo: true });
|
|
6
|
-
const cliConfig = await getPikkuCLIConfig(options.config, ['rootDir', 'schemaDirectory', 'configDir', 'fetchFile'],
|
|
6
|
+
const cliConfig = await getPikkuCLIConfig(options.config, ['rootDir', 'schemaDirectory', 'configDir', 'fetchFile'], {
|
|
7
|
+
tags: options.tags,
|
|
8
|
+
types: options.types,
|
|
9
|
+
directories: options.directories,
|
|
10
|
+
}, true);
|
|
7
11
|
await pikkuWebSocketTyped(logger, cliConfig);
|
|
8
12
|
};
|
|
9
13
|
export const websocket = (program) => {
|
|
@@ -0,0 +1,3 @@
|
|
|
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;
|
|
@@ -0,0 +1,73 @@
|
|
|
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
|
+
};
|
|
@@ -2,4 +2,3 @@ import { HTTPRoutesMeta } from '@pikku/core/http';
|
|
|
2
2
|
import { MetaInputTypes, TypesMap } from '@pikku/inspector';
|
|
3
3
|
import { FunctionsMeta } from '@pikku/core';
|
|
4
4
|
export declare const serializeTypedRoutesMap: (relativeToPath: string, packageMappings: Record<string, string>, typesMap: TypesMap, functionsMeta: FunctionsMeta, routesMeta: HTTPRoutesMeta, metaTypes: MetaInputTypes) => string;
|
|
5
|
-
export declare function generateCustomTypes(typesMap: TypesMap, requiredTypes: Set<string>): string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { serializeImportMap } from '../../serialize-import-map.js';
|
|
2
|
+
import { generateCustomTypes } from '../../utils.js';
|
|
2
3
|
export const serializeTypedRoutesMap = (relativeToPath, packageMappings, typesMap, functionsMeta, routesMeta, metaTypes) => {
|
|
3
4
|
const requiredTypes = new Set();
|
|
4
5
|
const serializedCustomTypes = generateCustomTypes(typesMap, requiredTypes);
|
|
@@ -30,20 +31,6 @@ export type RoutesWithMethod<Method extends string> = {
|
|
|
30
31
|
}[keyof RoutesMap];
|
|
31
32
|
`;
|
|
32
33
|
};
|
|
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
34
|
function generateRoutes(routesMeta, functionsMeta, typesMap, requiredTypes) {
|
|
48
35
|
// Initialize an object to collect routes
|
|
49
36
|
const routesObj = {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { serializeRPCWrapper } from './serialize-rpc-wrapper.js';
|
|
2
|
+
import { getFileImportRelativePath, logCommandInfoAndTime, writeFileInDir, } from '../../utils.js';
|
|
3
|
+
export const pikkuRPCClient = async (logger, { rpcFile, rpcMapDeclarationFile, packageMappings }) => {
|
|
4
|
+
return await logCommandInfoAndTime(logger, 'Generating RPC wrapper', 'Generated RPC wrapper', [rpcFile === undefined, "rpcFile isn't set in the pikku config"], async () => {
|
|
5
|
+
if (!rpcFile) {
|
|
6
|
+
throw new Error("rpcFile isn't set in the pikku config");
|
|
7
|
+
}
|
|
8
|
+
const rpcMapDeclarationPath = getFileImportRelativePath(rpcFile, rpcMapDeclarationFile, packageMappings);
|
|
9
|
+
const content = [serializeRPCWrapper(rpcMapDeclarationPath)];
|
|
10
|
+
await writeFileInDir(logger, rpcFile, content.join('\n'));
|
|
11
|
+
});
|
|
12
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const serializeRPCWrapper: (rpcMapPath: string) => string;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export const serializeRPCWrapper = (rpcMapPath) => {
|
|
2
|
+
return `
|
|
3
|
+
import { PikkuFetch } from "./pikku-fetch.gen.js"
|
|
4
|
+
import type { RPCInvoke } from '${rpcMapPath}'
|
|
5
|
+
|
|
6
|
+
export class PikkuRPC {
|
|
7
|
+
pikkuFetch = new PikkuFetch()
|
|
8
|
+
|
|
9
|
+
setPikkuFetch(pikkuFetch: PikkuFetch): void {
|
|
10
|
+
this.pikkuFetch = pikkuFetch
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
setServerUrl(serverUrl: string): void {
|
|
14
|
+
this.pikkuFetch.setServerUrl(serverUrl)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
setAuthorizationJWT(jwt: string | null): void {
|
|
18
|
+
this.pikkuFetch.setAuthorizationJWT(jwt)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Generic RPC invoke method
|
|
22
|
+
invoke: RPCInvoke = async (name, data) => {
|
|
23
|
+
return await this.pikkuFetch.post('/rpc', { name, data })
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const pikkuRPC = new PikkuRPC();
|
|
28
|
+
`;
|
|
29
|
+
};
|
|
@@ -6,7 +6,7 @@ export const inspectorGlob = async (logger, rootDir, srcDirectories, filters) =>
|
|
|
6
6
|
let result;
|
|
7
7
|
await logCommandInfoAndTime(logger, 'Inspecting codebase', 'Inspected codebase', [false], async () => {
|
|
8
8
|
const routeFiles = (await Promise.all(srcDirectories.map((dir) => glob(`${path.join(rootDir, dir)}/**/*.ts`)))).flat();
|
|
9
|
-
result = await inspect(routeFiles, filters);
|
|
9
|
+
result = await inspect(logger, routeFiles, filters);
|
|
10
10
|
});
|
|
11
11
|
return result;
|
|
12
12
|
};
|
|
@@ -22,6 +22,7 @@ export interface PikkuCLICoreOutputFiles {
|
|
|
22
22
|
queueMapDeclarationFile: string;
|
|
23
23
|
mcpEndpointsFile: string;
|
|
24
24
|
mcpEndpointsMetaFile: string;
|
|
25
|
+
servicesFile: string;
|
|
25
26
|
bootstrapFile: string;
|
|
26
27
|
bootstrapFiles: Record<PikkuEventTypes, string>;
|
|
27
28
|
}
|
|
@@ -38,13 +39,15 @@ export type PikkuCLIConfig = {
|
|
|
38
39
|
nextHTTPFile?: string;
|
|
39
40
|
fetchFile?: string;
|
|
40
41
|
websocketFile?: string;
|
|
42
|
+
rpcFile?: string;
|
|
41
43
|
queueFile?: string;
|
|
42
44
|
mcpJsonFile?: string;
|
|
43
45
|
openAPI?: {
|
|
44
46
|
outputFile: string;
|
|
45
47
|
additionalInfo: OpenAPISpecInfo;
|
|
46
48
|
};
|
|
49
|
+
middlewareServices?: string[];
|
|
47
50
|
filters: InspectorFilters;
|
|
48
51
|
} & PikkuCLICoreOutputFiles;
|
|
49
|
-
export declare const getPikkuCLIConfig: (configFile: string | undefined, requiredFields: Array<keyof PikkuCLIConfig>,
|
|
52
|
+
export declare const getPikkuCLIConfig: (configFile: string | undefined, requiredFields: Array<keyof PikkuCLIConfig>, filters?: InspectorFilters, exitProcess?: boolean) => Promise<PikkuCLIConfig>;
|
|
50
53
|
export declare const validateCLIConfig: (cliConfig: PikkuCLIConfig, required: Array<keyof PikkuCLIConfig>) => void;
|
|
@@ -6,14 +6,15 @@ const CONFIG_DIR_FILES = [
|
|
|
6
6
|
'nextHTTPFile',
|
|
7
7
|
'fetchFile',
|
|
8
8
|
'websocketFile',
|
|
9
|
+
'rpcFile',
|
|
9
10
|
'queueFile',
|
|
10
11
|
'mcpJsonFile',
|
|
11
12
|
];
|
|
12
|
-
export const getPikkuCLIConfig = async (configFile = undefined, requiredFields,
|
|
13
|
-
const config = await _getPikkuCLIConfig(configFile, requiredFields,
|
|
13
|
+
export const getPikkuCLIConfig = async (configFile = undefined, requiredFields, filters = {}, exitProcess = false) => {
|
|
14
|
+
const config = await _getPikkuCLIConfig(configFile, requiredFields, filters, exitProcess);
|
|
14
15
|
return config;
|
|
15
16
|
};
|
|
16
|
-
const _getPikkuCLIConfig = async (configFile = undefined, requiredFields,
|
|
17
|
+
const _getPikkuCLIConfig = async (configFile = undefined, requiredFields, filters = {}, exitProcess = false) => {
|
|
17
18
|
if (!configFile) {
|
|
18
19
|
let execDirectory = process.cwd();
|
|
19
20
|
const files = await readdir(execDirectory);
|
|
@@ -34,7 +35,7 @@ const _getPikkuCLIConfig = async (configFile = undefined, requiredFields, tags =
|
|
|
34
35
|
const configDir = dirname(configFile);
|
|
35
36
|
const config = JSON.parse(file);
|
|
36
37
|
if (config.extends) {
|
|
37
|
-
const extendedConfig = await getPikkuCLIConfig(resolve(configDir, config.extends), [],
|
|
38
|
+
const extendedConfig = await getPikkuCLIConfig(resolve(configDir, config.extends), [], filters, exitProcess);
|
|
38
39
|
result = {
|
|
39
40
|
...extendedConfig,
|
|
40
41
|
...config,
|
|
@@ -57,8 +58,9 @@ const _getPikkuCLIConfig = async (configFile = undefined, requiredFields, tags =
|
|
|
57
58
|
}
|
|
58
59
|
if (result.outDir) {
|
|
59
60
|
// Create transport/event directories
|
|
61
|
+
const functionDir = join(result.outDir, 'function');
|
|
60
62
|
const httpDir = join(result.outDir, 'http');
|
|
61
|
-
const
|
|
63
|
+
const channelDir = join(result.outDir, 'channel');
|
|
62
64
|
const rpcDir = join(result.outDir, 'rpc');
|
|
63
65
|
const schedulerDir = join(result.outDir, 'scheduler');
|
|
64
66
|
const queueDir = join(result.outDir, 'queue');
|
|
@@ -69,10 +71,10 @@ const _getPikkuCLIConfig = async (configFile = undefined, requiredFields, tags =
|
|
|
69
71
|
}
|
|
70
72
|
// Functions
|
|
71
73
|
if (!result.functionsFile) {
|
|
72
|
-
result.functionsFile = join(
|
|
74
|
+
result.functionsFile = join(functionDir, 'pikku-functions.gen.ts');
|
|
73
75
|
}
|
|
74
76
|
if (!result.functionsMetaFile) {
|
|
75
|
-
result.functionsMetaFile = join(
|
|
77
|
+
result.functionsMetaFile = join(functionDir, 'pikku-functions-meta.gen.ts');
|
|
76
78
|
}
|
|
77
79
|
if (!result.typesDeclarationFile) {
|
|
78
80
|
result.typesDeclarationFile = join(result.outDir, 'pikku-types.gen.ts');
|
|
@@ -89,13 +91,13 @@ const _getPikkuCLIConfig = async (configFile = undefined, requiredFields, tags =
|
|
|
89
91
|
}
|
|
90
92
|
// Channels/WebSocket
|
|
91
93
|
if (!result.channelsFile) {
|
|
92
|
-
result.channelsFile = join(
|
|
94
|
+
result.channelsFile = join(channelDir, 'pikku-channels.gen.ts');
|
|
93
95
|
}
|
|
94
96
|
if (!result.channelsMetaFile) {
|
|
95
|
-
result.channelsMetaFile = join(
|
|
97
|
+
result.channelsMetaFile = join(channelDir, 'pikku-channels-meta.gen.ts');
|
|
96
98
|
}
|
|
97
99
|
if (!result.channelsMapDeclarationFile) {
|
|
98
|
-
result.channelsMapDeclarationFile = join(
|
|
100
|
+
result.channelsMapDeclarationFile = join(channelDir, 'pikku-channels-map.gen.d.ts');
|
|
99
101
|
}
|
|
100
102
|
// RPC
|
|
101
103
|
if (!result.rpcMetaFile) {
|
|
@@ -106,10 +108,10 @@ const _getPikkuCLIConfig = async (configFile = undefined, requiredFields, tags =
|
|
|
106
108
|
}
|
|
107
109
|
// Scheduler
|
|
108
110
|
if (!result.schedulersFile) {
|
|
109
|
-
result.schedulersFile = join(schedulerDir, 'pikku-
|
|
111
|
+
result.schedulersFile = join(schedulerDir, 'pikku-scheduler.gen.ts');
|
|
110
112
|
}
|
|
111
113
|
if (!result.schedulersMetaFile) {
|
|
112
|
-
result.schedulersMetaFile = join(schedulerDir, 'pikku-
|
|
114
|
+
result.schedulersMetaFile = join(schedulerDir, 'pikku-scheduler-meta.gen.ts');
|
|
113
115
|
}
|
|
114
116
|
// Queue
|
|
115
117
|
if (!result.queueWorkersFile) {
|
|
@@ -121,6 +123,10 @@ const _getPikkuCLIConfig = async (configFile = undefined, requiredFields, tags =
|
|
|
121
123
|
if (!result.queueMapDeclarationFile) {
|
|
122
124
|
result.queueMapDeclarationFile = join(queueDir, 'pikku-queue-map.gen.ts');
|
|
123
125
|
}
|
|
126
|
+
// Services
|
|
127
|
+
if (!result.servicesFile) {
|
|
128
|
+
result.servicesFile = join(result.outDir, 'pikku-services.gen.ts');
|
|
129
|
+
}
|
|
124
130
|
// Bootstrap files
|
|
125
131
|
if (!result.bootstrapFile) {
|
|
126
132
|
result.bootstrapFile = join(result.outDir, 'pikku-bootstrap.gen.ts');
|
|
@@ -157,8 +163,14 @@ const _getPikkuCLIConfig = async (configFile = undefined, requiredFields, tags =
|
|
|
157
163
|
}
|
|
158
164
|
}
|
|
159
165
|
result.filters = result.filters || {};
|
|
160
|
-
if (tags.length > 0) {
|
|
161
|
-
result.filters.tags = tags;
|
|
166
|
+
if (filters.tags && filters.tags.length > 0) {
|
|
167
|
+
result.filters.tags = filters.tags;
|
|
168
|
+
}
|
|
169
|
+
if (filters.types && filters.types.length > 0) {
|
|
170
|
+
result.filters.types = filters.types;
|
|
171
|
+
}
|
|
172
|
+
if (filters.directories && filters.directories.length > 0) {
|
|
173
|
+
result.filters.directories = filters.directories;
|
|
162
174
|
}
|
|
163
175
|
if (!isAbsolute(result.tsconfig)) {
|
|
164
176
|
result.tsconfig = join(result.rootDir, result.tsconfig);
|
|
@@ -43,10 +43,10 @@ export async function generateSchemas(logger, tsconfig, typesMap, functionMeta,
|
|
|
43
43
|
catch (e) {
|
|
44
44
|
// Ignore rootless errors
|
|
45
45
|
if (e instanceof RootlessError) {
|
|
46
|
-
|
|
46
|
+
logger.error(`Error generating schema since it has no root: ${schema}`);
|
|
47
47
|
return;
|
|
48
48
|
}
|
|
49
|
-
|
|
49
|
+
logger.error(`Error generating schema: ${schema}`);
|
|
50
50
|
}
|
|
51
51
|
});
|
|
52
52
|
return schemas;
|
package/dist/src/utils.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export declare class CLILogger {
|
|
|
8
8
|
info(message: string): void;
|
|
9
9
|
error(message: string): void;
|
|
10
10
|
warn(message: string): void;
|
|
11
|
+
debug(message: string): void;
|
|
11
12
|
private logPikkuLogo;
|
|
12
13
|
}
|
|
13
14
|
export declare const getFileImportRelativePath: (from: string, to: string, packageMappings: Record<string, string>) => string;
|
|
@@ -33,6 +34,8 @@ export interface PikkuCLIOptions {
|
|
|
33
34
|
singletonServicesFactoryType?: string;
|
|
34
35
|
sessionServicesFactoryType?: string;
|
|
35
36
|
tags?: string[];
|
|
37
|
+
types?: string[];
|
|
38
|
+
directories?: string[];
|
|
36
39
|
}
|
|
37
40
|
export declare const getPikkuFilesAndMethods: (logger: CLILogger, { singletonServicesTypeImportMap, sessionServicesTypeImportMap, userSessionTypeImportMap, sessionServicesFactories, singletonServicesFactories, configFactories, }: InspectorState, packageMappings: Record<string, string>, outputFile: string, { configFileType, singletonServicesFactoryType, sessionServicesFactoryType, }: PikkuCLIOptions, requires?: Partial<{
|
|
38
41
|
config: boolean;
|