@pikku/cli 0.9.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/bin/pikku-all.ts +6 -1
- package/dist/bin/pikku-all.js +6 -1
- package/dist/bin/pikku.js +0 -0
- package/dist/src/utils.d.ts +5 -1
- package/dist/src/utils.js +17 -6
- package/package.json +3 -3
- package/src/utils.ts +26 -6
- 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,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
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { logCommandInfoAndTime, writeFileInDir } from '../../utils.js';
|
|
2
|
-
import { serializeTypedHTTPWiringsMap } from './serialize-typed-http-map.js';
|
|
3
|
-
export const pikkuHTTPMap = async (logger, { httpMapDeclarationFile, packageMappings }, { http, functions }) => {
|
|
4
|
-
return await logCommandInfoAndTime(logger, 'Creating HTTP map', 'Created HTTP map', [http.files.size === 0], async () => {
|
|
5
|
-
const content = serializeTypedHTTPWiringsMap(httpMapDeclarationFile, packageMappings, functions.typesMap, functions.meta, http.meta, http.metaInputTypes);
|
|
6
|
-
await writeFileInDir(logger, httpMapDeclarationFile, content);
|
|
7
|
-
});
|
|
8
|
-
};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { logCommandInfoAndTime, serializeFileImports, writeFileInDir, } from '../../utils.js';
|
|
2
|
-
export const pikkuHTTP = async (logger, cliConfig, visitState) => {
|
|
3
|
-
return await logCommandInfoAndTime(logger, 'Finding HTTP routes', 'Found HTTP routes', [visitState.http.files.size === 0], async () => {
|
|
4
|
-
const { httpWiringsFile, httpWiringMetaFile, packageMappings } = cliConfig;
|
|
5
|
-
const { http } = visitState;
|
|
6
|
-
await writeFileInDir(logger, httpWiringsFile, serializeFileImports('wireHTTP', httpWiringsFile, http.files, packageMappings));
|
|
7
|
-
await writeFileInDir(logger, httpWiringMetaFile, `import { pikkuState } from '@pikku/core'\npikkuState('http', 'meta', ${JSON.stringify(http.meta, null, 2)})`);
|
|
8
|
-
});
|
|
9
|
-
};
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { serializeNextJsBackendWrapper as serializeNextBackendWrapper } from '../../runtimes/nextjs/serialize-nextjs-backend-wrapper.js';
|
|
2
|
-
import { serializeNextJsHTTPWrapper as serializeNextHTTPWrapper } from '../../runtimes/nextjs/serialize-nextjs-http-wrapper.js';
|
|
3
|
-
import { getFileImportRelativePath, getPikkuFilesAndMethods, logCommandInfoAndTime, writeFileInDir, } from '../../utils.js';
|
|
4
|
-
export const pikkuNext = async (logger, { nextBackendFile, nextHTTPFile, httpRoutesMapDeclarationFile, packageMappings, fetchFile, bootstrapFiles, }, visitState, options = {}) => {
|
|
5
|
-
return await logCommandInfoAndTime(logger, 'Generating nextjs wrapper', 'Generated nextjs wrapper', [
|
|
6
|
-
nextBackendFile === undefined && nextHTTPFile === undefined,
|
|
7
|
-
'nextjs outfile is not defined',
|
|
8
|
-
], async () => {
|
|
9
|
-
if (!nextBackendFile && !nextHTTPFile) {
|
|
10
|
-
throw new Error('nextBackendFile or nextHTTPFile is required in pikku config for nextJS');
|
|
11
|
-
}
|
|
12
|
-
if (nextHTTPFile && !fetchFile) {
|
|
13
|
-
throw new Error('fetchFile is required in pikku config in order for nextJS http wrapper to work');
|
|
14
|
-
}
|
|
15
|
-
if (nextBackendFile) {
|
|
16
|
-
const { pikkuConfigFactory, singletonServicesFactory, sessionServicesFactory, } = await getPikkuFilesAndMethods(logger, visitState, packageMappings, nextBackendFile, options, {
|
|
17
|
-
config: true,
|
|
18
|
-
singletonServicesFactory: true,
|
|
19
|
-
sessionServicesFactory: true,
|
|
20
|
-
});
|
|
21
|
-
const pikkuConfigImport = `import { ${pikkuConfigFactory.variable} as createConfig } from '${getFileImportRelativePath(nextBackendFile, pikkuConfigFactory.file, packageMappings)}'`;
|
|
22
|
-
const singletonServicesImport = `import { ${singletonServicesFactory.variable} as createSingletonServices } from '${getFileImportRelativePath(nextBackendFile, singletonServicesFactory.file, packageMappings)}'`;
|
|
23
|
-
const sessionServicesImport = `import { ${sessionServicesFactory.variable} as createSessionServices } from '${getFileImportRelativePath(nextBackendFile, sessionServicesFactory.file, packageMappings)}'`;
|
|
24
|
-
const httpBootstrapPath = getFileImportRelativePath(nextBackendFile, bootstrapFiles.http, packageMappings);
|
|
25
|
-
const routesMapDeclarationPath = getFileImportRelativePath(nextBackendFile, httpRoutesMapDeclarationFile, packageMappings);
|
|
26
|
-
const content = serializeNextBackendWrapper(httpBootstrapPath, routesMapDeclarationPath, pikkuConfigImport, singletonServicesImport, sessionServicesImport);
|
|
27
|
-
await writeFileInDir(logger, nextBackendFile, content);
|
|
28
|
-
}
|
|
29
|
-
if (nextHTTPFile && fetchFile) {
|
|
30
|
-
const routesMapDeclarationPath = getFileImportRelativePath(nextHTTPFile, httpRoutesMapDeclarationFile, packageMappings);
|
|
31
|
-
const fetchPath = getFileImportRelativePath(nextHTTPFile, fetchFile, packageMappings);
|
|
32
|
-
const content = serializeNextHTTPWrapper(routesMapDeclarationPath, fetchPath);
|
|
33
|
-
await writeFileInDir(logger, nextHTTPFile, content);
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
};
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { logCommandInfoAndTime, writeFileInDir } from '../../utils.js';
|
|
2
|
-
import { generateSchemas } from '../../schema-generator.js';
|
|
3
|
-
import { generateOpenAPISpec } from './openapi-spec-generator.js';
|
|
4
|
-
import { stringify } from 'yaml';
|
|
5
|
-
export const pikkuOpenAPI = async (logger, { tsconfig, openAPI }, { http, functions }) => {
|
|
6
|
-
return await logCommandInfoAndTime(logger, 'Creating OpenAPI spec', 'Created OpenAPI spec', [openAPI?.outputFile === undefined, 'openAPI outfile is not defined'], async () => {
|
|
7
|
-
if (!openAPI?.outputFile) {
|
|
8
|
-
throw new Error('openAPI is required');
|
|
9
|
-
}
|
|
10
|
-
const schemas = await generateSchemas(logger, tsconfig, functions.typesMap, functions.meta, http.meta);
|
|
11
|
-
const openAPISpec = await generateOpenAPISpec(functions.meta, http.meta, schemas, openAPI.additionalInfo);
|
|
12
|
-
if (openAPI.outputFile.endsWith('.json')) {
|
|
13
|
-
await writeFileInDir(logger, openAPI.outputFile, JSON.stringify(openAPISpec, null, 2), { ignoreModifyComment: true });
|
|
14
|
-
}
|
|
15
|
-
else if (openAPI.outputFile.endsWith('.yaml') ||
|
|
16
|
-
openAPI.outputFile.endsWith('.yml')) {
|
|
17
|
-
await writeFileInDir(logger, openAPI.outputFile, stringify(openAPISpec), { ignoreModifyComment: true });
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
|
-
};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { logCommandInfoAndTime, serializeFileImports, writeFileInDir, } from '../../utils.js';
|
|
2
|
-
export const pikkuHTTP = async (logger, cliConfig, visitState) => {
|
|
3
|
-
return await logCommandInfoAndTime(logger, 'Finding HTTP routes', 'Found HTTP routes', [visitState.http.files.size === 0], async () => {
|
|
4
|
-
const { httpWiringsFile, httpWiringMetaFile, packageMappings } = cliConfig;
|
|
5
|
-
const { http } = visitState;
|
|
6
|
-
await writeFileInDir(logger, httpWiringsFile, serializeFileImports('wireHTTP', httpWiringsFile, http.files, packageMappings));
|
|
7
|
-
await writeFileInDir(logger, httpWiringMetaFile, `import { pikkuState } from '@pikku/core'\npikkuState('http', 'meta', ${JSON.stringify(http.meta, null, 2)})`);
|
|
8
|
-
});
|
|
9
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const serializeFetchWrapper: (routesMapPath: string) => string;
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
export const serializeFetchWrapper = (routesMapPath) => {
|
|
2
|
-
return `
|
|
3
|
-
import { CorePikkuFetch, HTTPMethod } from '@pikku/fetch'
|
|
4
|
-
import type { RoutesMap, RouteHandlerOf, RoutesWithMethod } from '${routesMapPath}'
|
|
5
|
-
|
|
6
|
-
export class PikkuFetch extends CorePikkuFetch {
|
|
7
|
-
public async post<Route extends RoutesWithMethod<'POST'>>(
|
|
8
|
-
route: Route,
|
|
9
|
-
...args: null extends RouteHandlerOf<Route, 'POST'>['input']
|
|
10
|
-
? [data?: Exclude<RouteHandlerOf<Route, 'POST'>['input'], null>, options?: Omit<RequestInit, 'body'>]
|
|
11
|
-
: [data: RouteHandlerOf<Route, 'POST'>['input'], options?: Omit<RequestInit, 'body'>]
|
|
12
|
-
): Promise<RouteHandlerOf<Route, 'POST'>['output']> {
|
|
13
|
-
const [data, options] = args;
|
|
14
|
-
return super.api(route, 'POST', data, options);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
public async get<Route extends RoutesWithMethod<'GET'>>(
|
|
18
|
-
route: Route,
|
|
19
|
-
...args: null extends RouteHandlerOf<Route, 'GET'>['input']
|
|
20
|
-
? [data?: Exclude<RouteHandlerOf<Route, 'GET'>['input'], null>, options?: Omit<RequestInit, 'body'>]
|
|
21
|
-
: [data: RouteHandlerOf<Route, 'GET'>['input'], options?: Omit<RequestInit, 'body'>]
|
|
22
|
-
): Promise<RouteHandlerOf<Route, 'GET'>['output']> {
|
|
23
|
-
const [data, options] = args;
|
|
24
|
-
return super.api(route, 'GET', data, options);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
public async patch<Route extends RoutesWithMethod<'PATCH'>>(
|
|
28
|
-
route: Route,
|
|
29
|
-
...args: null extends RouteHandlerOf<Route, 'PATCH'>['input']
|
|
30
|
-
? [data?: Exclude<RouteHandlerOf<Route, 'PATCH'>['input'], null>, options?: Omit<RequestInit, 'body'>]
|
|
31
|
-
: [data: RouteHandlerOf<Route, 'PATCH'>['input'], options?: Omit<RequestInit, 'body'>]
|
|
32
|
-
): Promise<RouteHandlerOf<Route, 'PATCH'>['output']> {
|
|
33
|
-
const [data, options] = args;
|
|
34
|
-
return super.api(route, 'PATCH', data, options);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
public async head<Route extends RoutesWithMethod<'HEAD'>>(
|
|
38
|
-
route: Route,
|
|
39
|
-
...args: null extends RouteHandlerOf<Route, 'HEAD'>['input']
|
|
40
|
-
? [data?: Exclude<RouteHandlerOf<Route, 'HEAD'>['input'], null>, options?: Omit<RequestInit, 'body'>]
|
|
41
|
-
: [data: RouteHandlerOf<Route, 'HEAD'>['input'], options?: Omit<RequestInit, 'body'>]
|
|
42
|
-
): Promise<RouteHandlerOf<Route, 'HEAD'>['output']> {
|
|
43
|
-
const [data, options] = args;
|
|
44
|
-
return super.api(route, 'HEAD', data, options);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
public async delete<Route extends RoutesWithMethod<'DELETE'>>(
|
|
48
|
-
route: Route,
|
|
49
|
-
...args: null extends RouteHandlerOf<Route, 'DELETE'>['input']
|
|
50
|
-
? [data?: Exclude<RouteHandlerOf<Route, 'DELETE'>['input'], null>, options?: Omit<RequestInit, 'body'>]
|
|
51
|
-
: [data: RouteHandlerOf<Route, 'DELETE'>['input'], options?: Omit<RequestInit, 'body'>]
|
|
52
|
-
): Promise<RouteHandlerOf<Route, 'DELETE'>['output']> {
|
|
53
|
-
const [data, options] = args;
|
|
54
|
-
return super.api(route, 'DELETE', data, options);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
public async fetch<
|
|
58
|
-
Route extends keyof RoutesMap,
|
|
59
|
-
Method extends keyof RoutesMap[Route]
|
|
60
|
-
>(route: Route, method: Method, data: RouteHandlerOf<Route, Method>['input'], options?: Omit<RequestInit, 'body'>): Promise<Response> {
|
|
61
|
-
return await super.fetch(route, method as HTTPMethod, data, options);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export const pikkuFetch = new PikkuFetch();
|
|
66
|
-
`;
|
|
67
|
-
};
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { HTTPWiringsMeta } from '@pikku/core/http';
|
|
2
|
-
import { MetaInputTypes, TypesMap } from '@pikku/inspector';
|
|
3
|
-
import { FunctionsMeta } from '@pikku/core';
|
|
4
|
-
export declare const serializeTypedHTTPWiringsMap: (relativeToPath: string, packageMappings: Record<string, string>, typesMap: TypesMap, functionsMeta: FunctionsMeta, wiringsMeta: HTTPWiringsMeta, metaTypes: MetaInputTypes) => string;
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { serializeImportMap } from '../../serialize-import-map.js';
|
|
2
|
-
import { generateCustomTypes } from '../../utils.js';
|
|
3
|
-
export const serializeTypedHTTPWiringsMap = (relativeToPath, packageMappings, typesMap, functionsMeta, wiringsMeta, metaTypes) => {
|
|
4
|
-
const requiredTypes = new Set();
|
|
5
|
-
const serializedCustomTypes = generateCustomTypes(typesMap, requiredTypes);
|
|
6
|
-
const serializedMetaTypes = generateMetaTypes(metaTypes, typesMap);
|
|
7
|
-
const serializedHTTPWirings = generateHTTPWirings(wiringsMeta, functionsMeta, typesMap, requiredTypes);
|
|
8
|
-
const serializedImportMap = serializeImportMap(relativeToPath, packageMappings, typesMap, requiredTypes);
|
|
9
|
-
return `/**
|
|
10
|
-
* This provides the structure needed for typescript to be aware of routes and their return types
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
${serializedImportMap}
|
|
14
|
-
${serializedCustomTypes}
|
|
15
|
-
${serializedMetaTypes}
|
|
16
|
-
|
|
17
|
-
interface HTTPWiringHandler<I, O> {
|
|
18
|
-
input: I;
|
|
19
|
-
output: O;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
${serializedHTTPWirings}
|
|
23
|
-
|
|
24
|
-
export type HTTPWiringHandlerOf<HTTPWiring extends keyof HTTPWiringsMap, Method extends keyof HTTPWiringsMap[HTTPWiring]> =
|
|
25
|
-
HTTPWiringsMap[HTTPWiring][Method] extends { input: infer I; output: infer O }
|
|
26
|
-
? HTTPWiringHandler<I, O>
|
|
27
|
-
: never;
|
|
28
|
-
|
|
29
|
-
export type HTTPWiringsWithMethod<Method extends string> = {
|
|
30
|
-
[HTTPWiring in keyof HTTPWiringsMap]: Method extends keyof HTTPWiringsMap[HTTPWiring] ? HTTPWiring : never;
|
|
31
|
-
}[keyof HTTPWiringsMap];
|
|
32
|
-
`;
|
|
33
|
-
};
|
|
34
|
-
function generateHTTPWirings(routesMeta, functionsMeta, typesMap, requiredTypes) {
|
|
35
|
-
// Initialize an object to collect routes
|
|
36
|
-
const routesObj = {};
|
|
37
|
-
for (const meta of routesMeta) {
|
|
38
|
-
const { route, method, pikkuFuncName } = meta;
|
|
39
|
-
const functionMeta = functionsMeta[pikkuFuncName];
|
|
40
|
-
if (!functionMeta) {
|
|
41
|
-
throw new Error(`Function ${pikkuFuncName} not found in functionsMeta. Please check your configuration.`);
|
|
42
|
-
}
|
|
43
|
-
const input = functionMeta.inputs ? functionMeta.inputs[0] : undefined;
|
|
44
|
-
const output = functionMeta.outputs ? functionMeta.outputs[0] : undefined;
|
|
45
|
-
// Initialize the route entry if it doesn't exist
|
|
46
|
-
if (!routesObj[route]) {
|
|
47
|
-
routesObj[route] = {};
|
|
48
|
-
}
|
|
49
|
-
// Store the input and output types separately for RouteHandler
|
|
50
|
-
const inputType = input ? typesMap.getTypeMeta(input).uniqueName : 'null';
|
|
51
|
-
const outputType = output ? typesMap.getTypeMeta(output).uniqueName : 'null';
|
|
52
|
-
requiredTypes.add(inputType);
|
|
53
|
-
requiredTypes.add(outputType);
|
|
54
|
-
// Add method entry
|
|
55
|
-
routesObj[route][method] = {
|
|
56
|
-
inputType,
|
|
57
|
-
outputType,
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
// Build the routes object as a string
|
|
61
|
-
let routesStr = 'export type RoutesMap = {\n';
|
|
62
|
-
for (const [routePath, methods] of Object.entries(routesObj)) {
|
|
63
|
-
routesStr += ` readonly '${routePath}': {\n`;
|
|
64
|
-
for (const [method, handler] of Object.entries(methods)) {
|
|
65
|
-
routesStr += ` readonly ${method.toUpperCase()}: RouteHandler<${handler.inputType}, ${handler.outputType}>,\n`;
|
|
66
|
-
}
|
|
67
|
-
routesStr += ' },\n';
|
|
68
|
-
}
|
|
69
|
-
routesStr += '};';
|
|
70
|
-
return routesStr;
|
|
71
|
-
}
|
|
72
|
-
const generateMetaTypes = (metaTypes, typesMap) => {
|
|
73
|
-
const nameToTypeMap = Array.from(metaTypes.entries()).reduce((result, [_name, { query, body, params }]) => {
|
|
74
|
-
const { uniqueName } = typesMap.getTypeMeta(_name);
|
|
75
|
-
const queryType = query && query.length > 0
|
|
76
|
-
? `Pick<${uniqueName}, '${query?.join("' | '")}'>`
|
|
77
|
-
: undefined;
|
|
78
|
-
if (queryType) {
|
|
79
|
-
result.set(`${uniqueName}Query`, queryType);
|
|
80
|
-
}
|
|
81
|
-
const paramsType = params && params.length > 0
|
|
82
|
-
? `Pick<${uniqueName}, '${params.join("' | '")}'>`
|
|
83
|
-
: undefined;
|
|
84
|
-
if (paramsType) {
|
|
85
|
-
result.set(`${uniqueName}Params`, paramsType);
|
|
86
|
-
}
|
|
87
|
-
const bodyType = (body && body.length > 0) || (params && params.length > 0)
|
|
88
|
-
? `Omit<${uniqueName}, '${[...new Set([...(query || []), ...(params || [])])].join("' | '")}'>`
|
|
89
|
-
: uniqueName;
|
|
90
|
-
if (bodyType) {
|
|
91
|
-
result.set(`${uniqueName}Body`, bodyType);
|
|
92
|
-
}
|
|
93
|
-
return result;
|
|
94
|
-
}, new Map());
|
|
95
|
-
return `
|
|
96
|
-
// The '& {}' is a workaround for not directly refering to a type since it confuses typescript
|
|
97
|
-
${Array.from(nameToTypeMap.entries())
|
|
98
|
-
.map(([name, type]) => `export type ${name} = ${type} & {}`)
|
|
99
|
-
.join('\n')}`;
|
|
100
|
-
};
|