@pikku/cli 0.6.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/CHANGELOG.md +445 -0
  2. package/README.md +3 -0
  3. package/bin/pikku-all.ts +110 -0
  4. package/bin/pikku-channels-map.ts +53 -0
  5. package/bin/pikku-channels.ts +57 -0
  6. package/bin/pikku-fetch.ts +54 -0
  7. package/bin/pikku-function-types.ts +76 -0
  8. package/bin/pikku-nextjs.test.ts +279 -0
  9. package/bin/pikku-nextjs.ts +113 -0
  10. package/bin/pikku-openapi.ts +71 -0
  11. package/bin/pikku-routes-map.ts +54 -0
  12. package/bin/pikku-routes.ts +55 -0
  13. package/bin/pikku-scheduler.ts +61 -0
  14. package/bin/pikku-schemas.ts +51 -0
  15. package/bin/pikku-websocket.ts +54 -0
  16. package/bin/pikku.ts +26 -0
  17. package/cli.schema.json +212 -0
  18. package/dist/bin/pikku-all.d.ts +4 -0
  19. package/dist/bin/pikku-all.js +71 -0
  20. package/dist/bin/pikku-channels-map.d.ts +5 -0
  21. package/dist/bin/pikku-channels-map.js +27 -0
  22. package/dist/bin/pikku-channels.d.ts +5 -0
  23. package/dist/bin/pikku-channels.js +32 -0
  24. package/dist/bin/pikku-fetch.d.ts +6 -0
  25. package/dist/bin/pikku-fetch.js +25 -0
  26. package/dist/bin/pikku-function-types.d.ts +6 -0
  27. package/dist/bin/pikku-function-types.js +32 -0
  28. package/dist/bin/pikku-nextjs.d.ts +7 -0
  29. package/dist/bin/pikku-nextjs.js +40 -0
  30. package/dist/bin/pikku-openapi.d.ts +5 -0
  31. package/dist/bin/pikku-openapi.js +41 -0
  32. package/dist/bin/pikku-routes-map.d.ts +5 -0
  33. package/dist/bin/pikku-routes-map.js +27 -0
  34. package/dist/bin/pikku-routes.d.ts +5 -0
  35. package/dist/bin/pikku-routes.js +33 -0
  36. package/dist/bin/pikku-scheduler.d.ts +5 -0
  37. package/dist/bin/pikku-scheduler.js +32 -0
  38. package/dist/bin/pikku-schemas.d.ts +5 -0
  39. package/dist/bin/pikku-schemas.js +27 -0
  40. package/dist/bin/pikku-websocket.d.ts +6 -0
  41. package/dist/bin/pikku-websocket.js +25 -0
  42. package/dist/bin/pikku.d.ts +2 -0
  43. package/dist/bin/pikku.js +23 -0
  44. package/dist/src/channels/serialize-channels.d.ts +3 -0
  45. package/dist/src/channels/serialize-channels.js +19 -0
  46. package/dist/src/channels/serialize-typed-channel-map.d.ts +3 -0
  47. package/dist/src/channels/serialize-typed-channel-map.js +87 -0
  48. package/dist/src/channels/serialize-websocket-wrapper.d.ts +1 -0
  49. package/dist/src/channels/serialize-websocket-wrapper.js +61 -0
  50. package/dist/src/core/serialize-import-map.d.ts +2 -0
  51. package/dist/src/core/serialize-import-map.js +23 -0
  52. package/dist/src/core/serialize-pikku-types.d.ts +4 -0
  53. package/dist/src/core/serialize-pikku-types.js +48 -0
  54. package/dist/src/http/serialize-fetch-wrapper.d.ts +1 -0
  55. package/dist/src/http/serialize-fetch-wrapper.js +57 -0
  56. package/dist/src/http/serialize-route-imports.d.ts +1 -0
  57. package/dist/src/http/serialize-route-imports.js +13 -0
  58. package/dist/src/http/serialize-route-meta.d.ts +2 -0
  59. package/dist/src/http/serialize-route-meta.js +6 -0
  60. package/dist/src/http/serialize-typed-route-map.d.ts +3 -0
  61. package/dist/src/http/serialize-typed-route-map.js +107 -0
  62. package/dist/src/inspector-glob.d.ts +2 -0
  63. package/dist/src/inspector-glob.js +12 -0
  64. package/dist/src/nextjs/serialize-nextjs-wrapper.d.ts +1 -0
  65. package/dist/src/nextjs/serialize-nextjs-wrapper.js +149 -0
  66. package/dist/src/openapi/openapi-spec-generator.d.ts +79 -0
  67. package/dist/src/openapi/openapi-spec-generator.js +135 -0
  68. package/dist/src/pikku-cli-config.d.ts +31 -0
  69. package/dist/src/pikku-cli-config.js +113 -0
  70. package/dist/src/scheduler/serialize-schedulers.d.ts +3 -0
  71. package/dist/src/scheduler/serialize-schedulers.js +22 -0
  72. package/dist/src/schema/schema-generator.d.ts +5 -0
  73. package/dist/src/schema/schema-generator.js +79 -0
  74. package/dist/src/utils.d.ts +34 -0
  75. package/dist/src/utils.js +109 -0
  76. package/dist/tsconfig.tsbuildinfo +1 -0
  77. package/package.json +42 -0
  78. package/run-tests.sh +53 -0
  79. package/src/channels/serialize-channels.ts +34 -0
  80. package/src/channels/serialize-typed-channel-map.ts +133 -0
  81. package/src/channels/serialize-websocket-wrapper.ts +61 -0
  82. package/src/core/serialize-import-map.ts +33 -0
  83. package/src/core/serialize-pikku-types.ts +53 -0
  84. package/src/http/serialize-fetch-wrapper.ts +57 -0
  85. package/src/http/serialize-route-imports.ts +24 -0
  86. package/src/http/serialize-route-meta.ts +10 -0
  87. package/src/http/serialize-typed-route-map.ts +147 -0
  88. package/src/inspector-glob.ts +27 -0
  89. package/src/nextjs/serialize-nextjs-wrapper.ts +156 -0
  90. package/src/openapi/openapi-spec-generator.ts +229 -0
  91. package/src/pikku-cli-config.ts +189 -0
  92. package/src/scheduler/serialize-schedulers.ts +43 -0
  93. package/src/schema/schema-generator.ts +117 -0
  94. package/src/utils.ts +219 -0
  95. package/tsconfig.json +21 -0
@@ -0,0 +1,40 @@
1
+ import { serializeNextJsWrapper } from '../src/nextjs/serialize-nextjs-wrapper.js';
2
+ import { getFileImportRelativePath, getPikkuFilesAndMethods, logCommandInfoAndTime, logPikkuLogo, writeFileInDir, } from '../src/utils.js';
3
+ import { getPikkuCLIConfig } from '../src/pikku-cli-config.js';
4
+ import { inspectorGlob } from '../src/inspector-glob.js';
5
+ export const pikkuNext = async ({ nextJSfile, routesFile, routesMapDeclarationFile, schemaDirectory, packageMappings, }, visitState, options) => {
6
+ return await logCommandInfoAndTime('Generating nextjs wrapper', 'Generated nextjs wrapper', [nextJSfile === undefined, 'nextjs outfile is not defined'], async () => {
7
+ if (!nextJSfile) {
8
+ throw new Error('nextJSfile is required in pikku config');
9
+ }
10
+ const { pikkuConfigFactory, singletonServicesFactory, sessionServicesFactory, } = await getPikkuFilesAndMethods(visitState, packageMappings, nextJSfile, options, {
11
+ config: true,
12
+ singletonServicesFactory: true,
13
+ sessionServicesFactory: true,
14
+ });
15
+ const pikkuConfigImport = `import { ${pikkuConfigFactory.variable} as createConfig } from '${getFileImportRelativePath(nextJSfile, pikkuConfigFactory.file, packageMappings)}'`;
16
+ const singletonServicesImport = `import { ${singletonServicesFactory.variable} as createSingletonServices } from '${getFileImportRelativePath(nextJSfile, singletonServicesFactory.file, packageMappings)}'`;
17
+ const sessionServicesImport = `import { ${sessionServicesFactory.variable} as createSessionServices } from '${getFileImportRelativePath(nextJSfile, sessionServicesFactory.file, packageMappings)}'`;
18
+ const routesPath = getFileImportRelativePath(nextJSfile, routesFile, packageMappings);
19
+ const routesMapDeclarationPath = getFileImportRelativePath(nextJSfile, routesMapDeclarationFile, packageMappings);
20
+ const schemasPath = getFileImportRelativePath(nextJSfile, `${schemaDirectory}/register.gen.ts`, packageMappings);
21
+ const content = serializeNextJsWrapper(routesPath, routesMapDeclarationPath, schemasPath, pikkuConfigImport, singletonServicesImport, sessionServicesImport);
22
+ await writeFileInDir(nextJSfile, content);
23
+ });
24
+ };
25
+ export const action = async (options) => {
26
+ logPikkuLogo();
27
+ const cliConfig = await getPikkuCLIConfig(options.config, ['rootDir', 'schemaDirectory', 'configDir', 'nextJSfile'], true);
28
+ const visitState = await inspectorGlob(cliConfig.rootDir, cliConfig.routeDirectories);
29
+ await pikkuNext(cliConfig, visitState, options);
30
+ };
31
+ export const nextjs = (program) => {
32
+ program
33
+ .command('nextjs')
34
+ .description('generate nextjs wrapper')
35
+ .option('-ct | --pikku-config-type', 'The type of your pikku config object')
36
+ .option('-ss | --singleton-services-factory-type', 'The type of your singleton services factory')
37
+ .option('-se | --session-services-factory-type', 'The type of your session services factory')
38
+ .option('-c | --config <string>', 'The path to pikku cli config file')
39
+ .action(action);
40
+ };
@@ -0,0 +1,5 @@
1
+ import { Command } from 'commander';
2
+ import { PikkuCLIConfig } from '../src/pikku-cli-config.js';
3
+ import { InspectorState } from '@pikku/inspector';
4
+ export declare const pikkuOpenAPI: ({ tsconfig, openAPI }: PikkuCLIConfig, { http }: InspectorState) => Promise<void>;
5
+ export declare const openapi: (program: Command) => void;
@@ -0,0 +1,41 @@
1
+ import { logCommandInfoAndTime, logPikkuLogo, writeFileInDir, } from '../src/utils.js';
2
+ import { generateSchemas } from '../src/schema/schema-generator.js';
3
+ import { generateOpenAPISpec } from '../src/openapi/openapi-spec-generator.js';
4
+ import { getPikkuCLIConfig } from '../src/pikku-cli-config.js';
5
+ import { stringify } from 'yaml';
6
+ import { inspectorGlob } from '../src/inspector-glob.js';
7
+ export const pikkuOpenAPI = async ({ tsconfig, openAPI }, { http }) => {
8
+ await logCommandInfoAndTime('Creating OpenAPI spec', 'Created OpenAPI spec', [openAPI?.outputFile === undefined, 'openAPI outfile is not defined'], async () => {
9
+ if (!openAPI?.outputFile) {
10
+ throw new Error('openAPI is required');
11
+ }
12
+ const schemas = await generateSchemas(tsconfig, http.typesMap, http.meta);
13
+ const openAPISpec = await generateOpenAPISpec(http.meta, schemas, openAPI.additionalInfo);
14
+ if (openAPI.outputFile.endsWith('.json')) {
15
+ await writeFileInDir(openAPI.outputFile, JSON.stringify(openAPISpec, null, 2), true);
16
+ }
17
+ else if (openAPI.outputFile.endsWith('.yaml') ||
18
+ openAPI.outputFile.endsWith('.yml')) {
19
+ await writeFileInDir(openAPI.outputFile, stringify(openAPISpec), true);
20
+ }
21
+ });
22
+ };
23
+ async function action({ config }) {
24
+ logPikkuLogo();
25
+ const cliConfig = await getPikkuCLIConfig(config, [
26
+ 'rootDir',
27
+ 'routesFile',
28
+ 'openAPI',
29
+ 'schemaDirectory',
30
+ 'tsconfig',
31
+ ]);
32
+ const visitState = await inspectorGlob(cliConfig.rootDir, cliConfig.routeDirectories);
33
+ await pikkuOpenAPI(cliConfig, visitState);
34
+ }
35
+ export const openapi = (program) => {
36
+ program
37
+ .command('openapi')
38
+ .description('Generate an openapi spec')
39
+ .option('-c | --config <string>', 'The path to pikku cli config file')
40
+ .action(action);
41
+ };
@@ -0,0 +1,5 @@
1
+ import { Command } from 'commander';
2
+ import { PikkuCLIConfig } from '../src/pikku-cli-config.js';
3
+ import { InspectorState } from '@pikku/inspector';
4
+ export declare const pikkuHTTPMap: ({ routesMapDeclarationFile, packageMappings }: PikkuCLIConfig, { http }: InspectorState) => Promise<boolean>;
5
+ export declare const routesMap: (program: Command) => void;
@@ -0,0 +1,27 @@
1
+ import { getPikkuCLIConfig } from '../src/pikku-cli-config.js';
2
+ import { logCommandInfoAndTime, logPikkuLogo, writeFileInDir, } from '../src/utils.js';
3
+ import { serializeTypedRoutesMap } from '../src/http/serialize-typed-route-map.js';
4
+ import { inspectorGlob } from '../src/inspector-glob.js';
5
+ export const pikkuHTTPMap = async ({ routesMapDeclarationFile, packageMappings }, { http }) => {
6
+ return await logCommandInfoAndTime('Creating routes map', 'Created routes map', [http.files.size === 0], async () => {
7
+ const content = serializeTypedRoutesMap(routesMapDeclarationFile, packageMappings, http.typesMap, http.meta, http.metaInputTypes);
8
+ await writeFileInDir(routesMapDeclarationFile, content);
9
+ });
10
+ };
11
+ async function action(cliOptions) {
12
+ logPikkuLogo();
13
+ const cliConfig = await getPikkuCLIConfig(cliOptions.config, [
14
+ 'rootDir',
15
+ 'routeDirectories',
16
+ 'routesFile',
17
+ ]);
18
+ const visitState = await inspectorGlob(cliConfig.rootDir, cliConfig.routeDirectories);
19
+ await pikkuHTTPMap(cliConfig, visitState);
20
+ }
21
+ export const routesMap = (program) => {
22
+ program
23
+ .command('map')
24
+ .description('Generate a map of all routes to aid in type checking')
25
+ .option('-c | --config <string>', 'The path to pikku cli config file')
26
+ .action(action);
27
+ };
@@ -0,0 +1,5 @@
1
+ import { Command } from 'commander';
2
+ import { PikkuCLIConfig } from '../src/pikku-cli-config.js';
3
+ import { InspectorState } from '@pikku/inspector';
4
+ export declare const pikkuRoutes: (cliConfig: PikkuCLIConfig, visitState: InspectorState) => Promise<boolean>;
5
+ export declare const routes: (program: Command) => void;
@@ -0,0 +1,33 @@
1
+ import { getPikkuCLIConfig } from '../src/pikku-cli-config.js';
2
+ import { serializeHTTPRoutesMeta } from '../src/http/serialize-route-meta.js';
3
+ import { logCommandInfoAndTime, logPikkuLogo, writeFileInDir, } from '../src/utils.js';
4
+ import { serializeRoutes } from '../src/http/serialize-route-imports.js';
5
+ import { inspectorGlob } from '../src/inspector-glob.js';
6
+ export const pikkuRoutes = async (cliConfig, visitState) => {
7
+ return await logCommandInfoAndTime('Finding routes', 'Found routes', [visitState.http.files.size === 0], async () => {
8
+ const { routesFile, packageMappings } = cliConfig;
9
+ const { http } = visitState;
10
+ const content = [
11
+ serializeRoutes(routesFile, http.files, packageMappings),
12
+ serializeHTTPRoutesMeta(http.meta),
13
+ ];
14
+ await writeFileInDir(routesFile, content.join('\n\n'));
15
+ });
16
+ };
17
+ async function action(cliOptions) {
18
+ logPikkuLogo();
19
+ const cliConfig = await getPikkuCLIConfig(cliOptions.config, [
20
+ 'rootDir',
21
+ 'routeDirectories',
22
+ 'routesFile',
23
+ ]);
24
+ const visitState = await inspectorGlob(cliConfig.rootDir, cliConfig.routeDirectories);
25
+ await pikkuRoutes(cliConfig, visitState);
26
+ }
27
+ export const routes = (program) => {
28
+ program
29
+ .command('routes')
30
+ .description('Find all routes to import')
31
+ .option('-c | --config <string>', 'The path to pikku cli config file')
32
+ .action(action);
33
+ };
@@ -0,0 +1,5 @@
1
+ import { Command } from 'commander';
2
+ import { PikkuCLIConfig } from '../src/pikku-cli-config.js';
3
+ import { InspectorState } from '@pikku/inspector';
4
+ export declare const pikkuScheduler: (cliConfig: PikkuCLIConfig, visitState: InspectorState) => Promise<boolean>;
5
+ export declare const schedules: (program: Command) => void;
@@ -0,0 +1,32 @@
1
+ import { getPikkuCLIConfig } from '../src/pikku-cli-config.js';
2
+ import { logCommandInfoAndTime, logPikkuLogo, writeFileInDir, } from '../src/utils.js';
3
+ import { serializeSchedulerMeta, serializeSchedulers, } from '../src/scheduler/serialize-schedulers.js';
4
+ import { inspectorGlob } from '../src/inspector-glob.js';
5
+ export const pikkuScheduler = async (cliConfig, visitState) => {
6
+ return await logCommandInfoAndTime('Finding scheduled tasks', 'Found scheduled tasks', [visitState.scheduledTasks.files.size === 0], async () => {
7
+ const { schedulersFile, packageMappings } = cliConfig;
8
+ const { scheduledTasks } = visitState;
9
+ const content = [
10
+ serializeSchedulers(schedulersFile, scheduledTasks.files, packageMappings),
11
+ serializeSchedulerMeta(scheduledTasks.meta),
12
+ ];
13
+ await writeFileInDir(schedulersFile, content.join('\n\n'));
14
+ });
15
+ };
16
+ async function action(cliOptions) {
17
+ logPikkuLogo();
18
+ const cliConfig = await getPikkuCLIConfig(cliOptions.config, [
19
+ 'rootDir',
20
+ 'routeDirectories',
21
+ 'routesFile',
22
+ ]);
23
+ const visitState = await inspectorGlob(cliConfig.rootDir, cliConfig.routeDirectories);
24
+ await pikkuScheduler(cliConfig, visitState);
25
+ }
26
+ export const schedules = (program) => {
27
+ program
28
+ .command('scheduler')
29
+ .description('Find all scheduled tasks to import')
30
+ .option('-c | --config <string>', 'The path to pikku cli config file')
31
+ .action(action);
32
+ };
@@ -0,0 +1,5 @@
1
+ import { Command } from 'commander';
2
+ import { PikkuCLIConfig } from '../src/pikku-cli-config.js';
3
+ import { InspectorState } from '@pikku/inspector';
4
+ export declare const pikkuSchemas: ({ tsconfig, schemaDirectory, supportsImportAttributes }: PikkuCLIConfig, { http }: InspectorState) => Promise<boolean>;
5
+ export declare const schemas: (program: Command) => void;
@@ -0,0 +1,27 @@
1
+ import { saveSchemas, generateSchemas } from '../src/schema/schema-generator.js';
2
+ import { getPikkuCLIConfig } from '../src/pikku-cli-config.js';
3
+ import { logCommandInfoAndTime, logPikkuLogo } from '../src/utils.js';
4
+ import { inspectorGlob } from '../src/inspector-glob.js';
5
+ export const pikkuSchemas = async ({ tsconfig, schemaDirectory, supportsImportAttributes }, { http }) => {
6
+ return await logCommandInfoAndTime('Creating schemas', 'Created schemas', [false], async () => {
7
+ const schemas = await generateSchemas(tsconfig, http.typesMap, http.meta);
8
+ await saveSchemas(schemaDirectory, schemas, http.typesMap, http.meta, supportsImportAttributes);
9
+ });
10
+ };
11
+ async function action({ config }) {
12
+ logPikkuLogo();
13
+ const cliConfig = await getPikkuCLIConfig(config, [
14
+ 'routeDirectories',
15
+ 'schemaDirectory',
16
+ 'tsconfig',
17
+ ]);
18
+ const visitState = await inspectorGlob(cliConfig.rootDir, cliConfig.routeDirectories);
19
+ await pikkuSchemas(cliConfig, visitState);
20
+ }
21
+ export const schemas = (program) => {
22
+ program
23
+ .command('schemas')
24
+ .description('Generate schemas for all the expected function input types')
25
+ .option('-c | --config <string>', 'The path to pikku cli config file')
26
+ .action(action);
27
+ };
@@ -0,0 +1,6 @@
1
+ import { Command } from 'commander';
2
+ import { PikkuCLIOptions } from '../src/utils.js';
3
+ import { PikkuCLIConfig } from '../src/pikku-cli-config.js';
4
+ export declare const pikkuWebSocket: ({ websocketFile, channelsMapDeclarationFile, packageMappings, }: PikkuCLIConfig) => Promise<void>;
5
+ export declare const action: (options: PikkuCLIOptions) => Promise<void>;
6
+ export declare const websocket: (program: Command) => void;
@@ -0,0 +1,25 @@
1
+ import { getFileImportRelativePath, logCommandInfoAndTime, logPikkuLogo, writeFileInDir, } from '../src/utils.js';
2
+ import { getPikkuCLIConfig } from '../src/pikku-cli-config.js';
3
+ import { serializeWebsocketWrapper } from '../src/channels/serialize-websocket-wrapper.js';
4
+ export const pikkuWebSocket = async ({ websocketFile, channelsMapDeclarationFile, packageMappings, }) => {
5
+ await logCommandInfoAndTime('Generating websocket wrapper', 'Generated websocket wrapper', [websocketFile === undefined, 'websocketFile is required in pikku config'], async () => {
6
+ if (!websocketFile) {
7
+ throw new Error('fetchFile is required in pikku config');
8
+ }
9
+ const channelsMapDeclarationPath = getFileImportRelativePath(websocketFile, channelsMapDeclarationFile, packageMappings);
10
+ const content = [serializeWebsocketWrapper(channelsMapDeclarationPath)];
11
+ await writeFileInDir(websocketFile, content.join('\n'));
12
+ });
13
+ };
14
+ export const action = async (options) => {
15
+ logPikkuLogo();
16
+ const cliConfig = await getPikkuCLIConfig(options.config, ['rootDir', 'schemaDirectory', 'configDir', 'fetchFile'], true);
17
+ await pikkuWebSocket(cliConfig);
18
+ };
19
+ export const websocket = (program) => {
20
+ program
21
+ .command('websocket')
22
+ .description('generate websocket wrapper')
23
+ .option('-c | --config <string>', 'The path to pikku cli config file')
24
+ .action(action);
25
+ };
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { schemas } from './pikku-schemas.js';
4
+ import { routes } from './pikku-routes.js';
5
+ import { nextjs } from './pikku-nextjs.js';
6
+ import { all } from './pikku-all.js';
7
+ import { functionTypes } from './pikku-function-types.js';
8
+ import { routesMap } from './pikku-routes-map.js';
9
+ import { fetch } from './pikku-fetch.js';
10
+ import { channels } from './pikku-channels.js';
11
+ import { schedules } from './pikku-scheduler.js';
12
+ const program = new Command('pikku');
13
+ program.usage('[command]');
14
+ all(program);
15
+ routes(program);
16
+ routesMap(program);
17
+ functionTypes(program);
18
+ schemas(program);
19
+ nextjs(program);
20
+ fetch(program);
21
+ channels(program);
22
+ schedules(program);
23
+ program.parse(process.argv);
@@ -0,0 +1,3 @@
1
+ import { ChannelsMeta } from '@pikku/core/channel';
2
+ export declare const serializeChannels: (outputPath: string, filesWithChannels: Set<string>, packageMappings?: Record<string, string>) => string;
3
+ export declare const serializeChannelMeta: (channelsMeta: ChannelsMeta) => string;
@@ -0,0 +1,19 @@
1
+ import { getFileImportRelativePath } from '../utils.js';
2
+ export const serializeChannels = (outputPath, filesWithChannels, packageMappings = {}) => {
3
+ const serializedOutput = [
4
+ '/* The files with an addChannel function call */',
5
+ ];
6
+ Array.from(filesWithChannels)
7
+ .sort()
8
+ .forEach((path) => {
9
+ const filePath = getFileImportRelativePath(outputPath, path, packageMappings);
10
+ serializedOutput.push(`import '${filePath}'`);
11
+ });
12
+ return serializedOutput.join('\n');
13
+ };
14
+ export const serializeChannelMeta = (channelsMeta) => {
15
+ const serializedOutput = [];
16
+ serializedOutput.push("import { setChannelsMeta } from '@pikku/core/channel'");
17
+ serializedOutput.push(`setChannelsMeta(${JSON.stringify(channelsMeta, null, 2)})`);
18
+ return serializedOutput.join('\n');
19
+ };
@@ -0,0 +1,3 @@
1
+ import { ChannelsMeta } from '@pikku/core/channel';
2
+ import { TypesMap } from '@pikku/inspector';
3
+ export declare const serializeTypedChannelsMap: (relativeToPath: string, packageMappings: Record<string, string>, typesMap: TypesMap, channelsMeta: ChannelsMeta) => string;
@@ -0,0 +1,87 @@
1
+ import { serializeImportMap } from '../core/serialize-import-map.js';
2
+ export const serializeTypedChannelsMap = (relativeToPath, packageMappings, typesMap, channelsMeta) => {
3
+ const { channels, requiredTypes } = generateChannels(channelsMeta);
4
+ typesMap.customTypes.forEach(({ references }) => {
5
+ for (const reference of references) {
6
+ requiredTypes.add(reference);
7
+ }
8
+ });
9
+ const imports = serializeImportMap(relativeToPath, packageMappings, typesMap, requiredTypes);
10
+ return `/**
11
+ * This provides the structure needed for TypeScript to be aware of channels
12
+ */
13
+
14
+ ${imports}
15
+
16
+ interface ChannelHandler<I, O> {
17
+ input: I;
18
+ output: O;
19
+ }
20
+
21
+ ${channels}
22
+
23
+ export type ChannelDefaultHandlerOf<Channel extends keyof ChannelsMap> =
24
+ ChannelsMap[Channel]['defaultMessage'] extends { input: infer I; output: infer O }
25
+ ? ChannelHandler<I, O>
26
+ : never;
27
+
28
+ export type ChannelRouteHandlerOf<
29
+ Channel extends keyof ChannelsMap,
30
+ Route extends keyof ChannelsMap[Channel]['routes'],
31
+ Method extends keyof ChannelsMap[Channel]['routes'][Route],
32
+ > =
33
+ ChannelsMap[Channel]['routes'][Route][Method] extends { input: infer I; output: infer O }
34
+ ? ChannelHandler<I, O>
35
+ : never;
36
+ `;
37
+ };
38
+ function generateChannels(channelsMeta) {
39
+ const requiredTypes = new Set();
40
+ const channelsObject = {};
41
+ for (const meta of channelsMeta) {
42
+ const { name, messageRoutes, message } = meta;
43
+ if (!channelsObject[name]) {
44
+ channelsObject[name] = { message, routes: {} };
45
+ }
46
+ for (const [key, route] of Object.entries(messageRoutes)) {
47
+ if (!channelsObject[name].routes[key]) {
48
+ channelsObject[name].routes[key] = {};
49
+ }
50
+ for (const [method, { inputs, outputs }] of Object.entries(route)) {
51
+ const inputTypes = inputs || null;
52
+ const outputTypes = outputs || null;
53
+ channelsObject[name].routes[key][method] = {
54
+ inputTypes,
55
+ outputTypes,
56
+ };
57
+ inputTypes?.forEach((type) => requiredTypes.add(type));
58
+ outputTypes?.forEach((type) => requiredTypes.add(type));
59
+ }
60
+ }
61
+ }
62
+ let routesStr = 'export type ChannelsMap = {\n';
63
+ for (const [channelPath, { routes, message }] of Object.entries(channelsObject)) {
64
+ routesStr += ` readonly '${channelPath}': {\n`;
65
+ // Add `routes` object
66
+ routesStr += ` readonly routes: {\n`;
67
+ for (const [key, methods] of Object.entries(routes)) {
68
+ routesStr += ` readonly ${key}: {\n`;
69
+ for (const [method, handler] of Object.entries(methods)) {
70
+ routesStr += ` readonly ${method}: ChannelHandler<${formatTypeArray(handler.inputTypes)}, ${formatTypeArray(handler.outputTypes)}>,\n`;
71
+ }
72
+ routesStr += ' },\n';
73
+ }
74
+ routesStr += ' },\n';
75
+ // Add `defaultMessage` outside `routes`
76
+ if (message) {
77
+ routesStr += ` readonly defaultMessage: ChannelHandler<${formatTypeArray(message.inputs)}, ${formatTypeArray(message.outputs)}>,\n`;
78
+ }
79
+ routesStr += ' },\n';
80
+ }
81
+ routesStr += '};';
82
+ return { channels: routesStr, requiredTypes };
83
+ }
84
+ // Utility to format type arrays
85
+ function formatTypeArray(types) {
86
+ return types ? types.join(' | ') : 'null';
87
+ }
@@ -0,0 +1 @@
1
+ export declare const serializeWebsocketWrapper: (channelsMapPath: string) => string;
@@ -0,0 +1,61 @@
1
+ export const serializeWebsocketWrapper = (channelsMapPath) => {
2
+ return `import { AbstractPikkuWebsocket, AbstractPikkuRouteHandler } 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 AbstractPikkuRouteHandler {
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> extends AbstractPikkuWebsocket {
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
+ };
@@ -0,0 +1,2 @@
1
+ import { TypesMap } from '@pikku/inspector';
2
+ export declare const serializeImportMap: (relativeToPath: string, packageMappings: Record<string, string>, typesMap: TypesMap, requiredTypes: Set<string>) => string;
@@ -0,0 +1,23 @@
1
+ import { getFileImportRelativePath } from '../utils.js';
2
+ export const serializeImportMap = (relativeToPath, packageMappings, typesMap, requiredTypes) => {
3
+ const paths = new Map();
4
+ Array.from(requiredTypes).forEach((requiredType) => {
5
+ const { originalName, uniqueName, path } = typesMap.getTypeMeta(requiredType);
6
+ if (!path) {
7
+ return;
8
+ }
9
+ const variables = paths.get(path) || [];
10
+ if (originalName === uniqueName) {
11
+ variables.push(originalName);
12
+ }
13
+ else {
14
+ variables.push(`${originalName} as ${uniqueName}`);
15
+ }
16
+ paths.set(path, variables);
17
+ });
18
+ const imports = [];
19
+ for (const [path, variables] of paths.entries()) {
20
+ imports.push(`import type { ${variables.join(', ')} } from '${getFileImportRelativePath(relativeToPath, path, packageMappings)}'`);
21
+ }
22
+ return imports.join('\n');
23
+ };
@@ -0,0 +1,4 @@
1
+ /**
2
+ *
3
+ */
4
+ export declare const serializePikkuTypes: (userSessionTypeImport: string, userSessionTypeName: string, sessionServicesTypeImport: string, servicesTypeName: string) => string;
@@ -0,0 +1,48 @@
1
+ /**
2
+ *
3
+ */
4
+ export const serializePikkuTypes = (userSessionTypeImport, userSessionTypeName, sessionServicesTypeImport, servicesTypeName) => {
5
+ return `/**
6
+ * This is used to provide the application types in the typescript project
7
+ */
8
+
9
+ import { CoreAPIFunction, CoreAPIFunctionSessionless, CoreAPIPermission, MakeRequired } from '@pikku/core'
10
+ import { CoreHTTPFunctionRoute, AssertRouteParams } from '@pikku/core/http'
11
+ import { CoreScheduledTask } from '@pikku/core/scheduler'
12
+ import { CoreAPIChannel, CoreChannelConnection, CoreChannelDisconnection, CoreChannelMessage, PikkuChannel } from '@pikku/core/channel'
13
+
14
+ ${userSessionTypeImport}
15
+ ${sessionServicesTypeImport}
16
+
17
+ export type APIPermission<In = unknown, RequiredServices = ${servicesTypeName}> = CoreAPIPermission<In, RequiredServices, ${userSessionTypeName}>
18
+
19
+ export type APIFunctionSessionless<In = unknown, Out = never, RequiredServices = ${servicesTypeName}> = CoreAPIFunctionSessionless<In, Out, RequiredServices, ${userSessionTypeName}>
20
+ export type APIFunction<In = unknown, Out = never, RequiredServices = ${servicesTypeName}> = CoreAPIFunction<In, Out, RequiredServices, ${userSessionTypeName}>
21
+ type APIRoute<In, Out, Route extends string> = CoreHTTPFunctionRoute<In, Out, Route, APIFunction<In, Out>, APIFunctionSessionless<In, Out>, APIPermission<In>>
22
+
23
+ export type ChannelConnection<Out = never, ChannelData = unknown, RequiredServices extends ${servicesTypeName} = ${servicesTypeName}> = (services: MakeRequired<Services, 'eventHub'>, channel: PikkuChannel<${userSessionTypeName}, ChannelData, Out>) => Promise<void>
24
+ export type ChannelDisconnection<ChannelData = unknown, RequiredServices extends ${servicesTypeName} = ${servicesTypeName}> = (services: MakeRequired<Services, 'eventHub'>, channel: PikkuChannel<${userSessionTypeName}, ChannelData, never>) => Promise<void>
25
+ export type ChannelMessage<In, Out = never, ChannelData = unknown, RequiredServices extends ${servicesTypeName} = ${servicesTypeName}> = (services: MakeRequired<Services, 'eventHub'>, channel: PikkuChannel<${userSessionTypeName}, ChannelData, Out>, data: In) => Promise<Out | void>
26
+ type APIChannel<ChannelData, Channel extends string, In extends unknown, Out extends unknown> = CoreAPIChannel<ChannelData, Channel, ChannelConnection, ChannelDisconnection, ChannelMessage<In, Out, ChannelData>>
27
+
28
+ type ScheduledTask = CoreScheduledTask<APIFunctionSessionless<void, void>, ${userSessionTypeName}>
29
+
30
+ declare module "@pikku/core" {
31
+ // type APIPermission<In = unknown, RequiredServices = ${servicesTypeName}> = CoreAPIPermission<In, RequiredServices, ${userSessionTypeName}>
32
+ // type APIFunction = <In = unknown, Out = never, RequiredServices = ${servicesTypeName}> = CoreAPIFunction<In, Out, RequiredServices, ${userSessionTypeName}>
33
+ // type APIFunctionSessionless = <In = unknown, Out = never, RequiredServices = ${servicesTypeName}> = CoreAPIFunctionSessionless<In, Out, RequiredServices, ${userSessionTypeName}>
34
+
35
+ function addChannel<ChannelData, Channel extends string>(
36
+ channel: APIChannel<ChannelData, Channel> & AssertRouteParams<ChannelData, Channel>
37
+ ): void;
38
+
39
+ function addRoute<In, Out, Route extends string>(
40
+ route: APIRoute<In, Out, Route> & AssertRouteParams<In, Route>
41
+ ): void;
42
+
43
+ function addScheduledTask(
44
+ task: ScheduledTask
45
+ ): void;
46
+ }
47
+ `;
48
+ };
@@ -0,0 +1 @@
1
+ export declare const serializeFetchWrapper: (routesMapPath: string) => string;
@@ -0,0 +1,57 @@
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 AbstractPikkuFetch {
7
+ public async post<Route extends RoutesWithMethod<'POST'>>(
8
+ route: Route,
9
+ data: RouteHandlerOf<Route, 'POST'>['input'] = null,
10
+ options?: Omit<RequestInit, 'body'>
11
+ ): Promise<RouteHandlerOf<Route, 'POST'>['output']> {
12
+ return super.api(route, 'POST', data, options);
13
+ }
14
+
15
+ public async get<Route extends RoutesWithMethod<'GET'>>(
16
+ route: Route,
17
+ data: RouteHandlerOf<Route, 'GET'>['input'] = null,
18
+ options?: Omit<RequestInit, 'body'>
19
+ ): Promise<RouteHandlerOf<Route, 'GET'>['output']> {
20
+ return super.api(route, 'GET', data, options);
21
+ }
22
+
23
+ public async patch<Route extends RoutesWithMethod<'PATCH'>>(
24
+ route: Route,
25
+ data: RouteHandlerOf<Route, 'PATCH'>['input'] = null,
26
+ options?: Omit<RequestInit, 'body'>
27
+ ): Promise<RouteHandlerOf<Route, 'PATCH'>['output']> {
28
+ return super.api(route, 'PATCH', data, options);
29
+ }
30
+
31
+ public async head<Route extends RoutesWithMethod<'HEAD'>>(
32
+ route: Route,
33
+ data: RouteHandlerOf<Route, 'HEAD'>['input'] = null,
34
+ options?: Omit<RequestInit, 'body'>
35
+ ): Promise<RouteHandlerOf<Route, 'HEAD'>['output']> {
36
+ return super.api(route, 'HEAD', data, options);
37
+ }
38
+
39
+ public async delete<Route extends RoutesWithMethod<'DELETE'>>(
40
+ route: Route,
41
+ data: RouteHandlerOf<Route, 'DELETE'>['input'] = null,
42
+ options?: Omit<RequestInit, 'body'>
43
+ ): Promise<RouteHandlerOf<Route, 'DELETE'>['output']> {
44
+ return super.api(route, 'DELETE', data, options);
45
+ }
46
+
47
+ public async fetch<
48
+ Route extends keyof RoutesMap,
49
+ Method extends keyof RoutesMap[Route]
50
+ >(route: Route, method: Method, data: RouteHandlerOf<Route, Method>['input'], options?: Omit<RequestInit, 'body'>): Promise<Response> {
51
+ return await super.fetch(route, method as HTTPMethod, data, options)
52
+ }
53
+ }
54
+
55
+ export const pikkuFetch = new PikkuFetch()
56
+ `;
57
+ };
@@ -0,0 +1 @@
1
+ export declare const serializeRoutes: (outputPath: string, filesWithRoutes: Set<string>, packageMappings?: Record<string, string>) => string;