vovk-cli 0.0.1-beta.0

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 (82) hide show
  1. package/.eslintrc.js +20 -0
  2. package/README.md +1 -0
  3. package/dist/getProjectInfo/directoryExists.d.ts +1 -0
  4. package/dist/getProjectInfo/directoryExists.js +16 -0
  5. package/dist/getProjectInfo/getConfig.d.ts +7 -0
  6. package/dist/getProjectInfo/getConfig.js +29 -0
  7. package/dist/getProjectInfo/getCwdPath.d.ts +1 -0
  8. package/dist/getProjectInfo/getCwdPath.js +19 -0
  9. package/dist/getProjectInfo/getSrcRoot.d.ts +1 -0
  10. package/dist/getProjectInfo/getSrcRoot.js +19 -0
  11. package/dist/getProjectInfo/index.d.ts +48 -0
  12. package/dist/getProjectInfo/index.js +78 -0
  13. package/dist/getProjectInfo/readConfig.d.ts +3 -0
  14. package/dist/getProjectInfo/readConfig.js +73 -0
  15. package/dist/index.d.ts +3 -0
  16. package/dist/index.js +104 -0
  17. package/dist/init.d.ts +2 -0
  18. package/dist/init.js +173 -0
  19. package/dist/locateSegments.d.ts +5 -0
  20. package/dist/locateSegments.js +58 -0
  21. package/dist/postinstall.d.ts +1 -0
  22. package/dist/postinstall.js +27 -0
  23. package/dist/server/createMetadataServer.d.ts +5 -0
  24. package/dist/server/createMetadataServer.js +31 -0
  25. package/dist/server/diffMetadata.d.ts +43 -0
  26. package/dist/server/diffMetadata.js +77 -0
  27. package/dist/server/ensureMetadataFiles.d.ts +3 -0
  28. package/dist/server/ensureMetadataFiles.js +100 -0
  29. package/dist/server/generateClient.d.ts +7 -0
  30. package/dist/server/generateClient.js +98 -0
  31. package/dist/server/index.d.ts +6 -0
  32. package/dist/server/index.js +285 -0
  33. package/dist/server/isMetadataEmpty.d.ts +2 -0
  34. package/dist/server/isMetadataEmpty.js +7 -0
  35. package/dist/server/logDiffResult.d.ts +3 -0
  36. package/dist/server/logDiffResult.js +84 -0
  37. package/dist/server/writeOneMetadataFile.d.ts +11 -0
  38. package/dist/server/writeOneMetadataFile.js +34 -0
  39. package/dist/types.d.ts +30 -0
  40. package/dist/types.js +2 -0
  41. package/dist/utils/debounceWithArgs.d.ts +2 -0
  42. package/dist/utils/debounceWithArgs.js +20 -0
  43. package/dist/utils/fileExists.d.ts +1 -0
  44. package/dist/utils/fileExists.js +16 -0
  45. package/dist/utils/getAvailablePort.d.ts +10 -0
  46. package/dist/utils/getAvailablePort.js +47 -0
  47. package/package.json +43 -0
  48. package/src/getProjectInfo/directoryExists.ts +10 -0
  49. package/src/getProjectInfo/getConfig.ts +29 -0
  50. package/src/getProjectInfo/getCwdPath.ts +15 -0
  51. package/src/getProjectInfo/getSrcRoot.ts +14 -0
  52. package/src/getProjectInfo/index.ts +63 -0
  53. package/src/getProjectInfo/readConfig.ts +50 -0
  54. package/src/index.ts +112 -0
  55. package/src/init.ts +174 -0
  56. package/src/locateSegments.ts +40 -0
  57. package/src/postinstall.ts +27 -0
  58. package/src/server/createMetadataServer.ts +30 -0
  59. package/src/server/diffMetadata.ts +110 -0
  60. package/src/server/ensureMetadataFiles.ts +92 -0
  61. package/src/server/generateClient.ts +108 -0
  62. package/src/server/index.ts +306 -0
  63. package/src/server/isMetadataEmpty.ts +6 -0
  64. package/src/server/logDiffResult.ts +114 -0
  65. package/src/server/writeOneMetadataFile.ts +44 -0
  66. package/src/types.ts +58 -0
  67. package/src/utils/debounceWithArgs.ts +22 -0
  68. package/src/utils/fileExists.ts +10 -0
  69. package/src/utils/getAvailablePort.ts +50 -0
  70. package/test/data/segments/[[...vovk]]/route.ts +0 -0
  71. package/test/data/segments/bar/[[...custom]]/route.ts +0 -0
  72. package/test/data/segments/baz/[[...vovk]]/noroute.ts +0 -0
  73. package/test/data/segments/foo/[[...vovk]]/route.ts +0 -0
  74. package/test/data/segments/garply/waldo/route.ts +0 -0
  75. package/test/data/segments/grault/xxxx/[[...vovk]]/noroute.ts +0 -0
  76. package/test/data/segments/quux/corge/[[...vovk]]/route.ts +0 -0
  77. package/test/index.ts +3 -0
  78. package/test/metadata-diff.test.ts +300 -0
  79. package/test/metadata-write.test.ts +82 -0
  80. package/test/utils.test.ts +49 -0
  81. package/tsconfig.json +11 -0
  82. package/tsconfig.test.json +4 -0
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.default = locateSegments;
30
+ const fs_1 = require("fs");
31
+ const path = __importStar(require("path"));
32
+ const fileExists_1 = __importDefault(require("./utils/fileExists"));
33
+ async function locateSegments(dir, rootDir = dir) {
34
+ let results = [];
35
+ // Read the contents of the directory
36
+ const list = await fs_1.promises.readdir(dir);
37
+ // Iterate through each item in the directory
38
+ for (const file of list) {
39
+ const filePath = path.join(dir, file);
40
+ const stat = await fs_1.promises.stat(filePath);
41
+ if (stat.isDirectory()) {
42
+ // Check if the directory name matches the pattern [[...something]]
43
+ if (file.startsWith('[[...') && file.endsWith(']]')) {
44
+ // Check if there's a route.ts file inside this directory
45
+ const routeFilePath = path.join(filePath, 'route.ts');
46
+ if (await (0, fileExists_1.default)(routeFilePath)) {
47
+ // Calculate the basePath relative to the root directory
48
+ const segmentName = path.relative(rootDir, dir);
49
+ results.push({ routeFilePath, segmentName });
50
+ }
51
+ }
52
+ // Recursively search inside subdirectories
53
+ const subDirResults = await locateSegments(filePath, rootDir);
54
+ results = results.concat(subDirResults);
55
+ }
56
+ }
57
+ return results;
58
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const fs_1 = require("fs");
7
+ const path_1 = __importDefault(require("path"));
8
+ /**
9
+ * Checks if a file exists at the given path.
10
+ * @param {string} filePath - The path to the file.
11
+ * @returns {Promise<boolean>} - A promise that resolves to true if the file exists, false otherwise.
12
+ */
13
+ const fileExists = async (filePath) => !!(await fs_1.promises.stat(filePath).catch(() => false));
14
+ async function postinstall() {
15
+ const vovk = path_1.default.join(__dirname, '../../.vovk');
16
+ const js = path_1.default.join(vovk, 'client.js');
17
+ const ts = path_1.default.join(vovk, 'client.d.ts');
18
+ const index = path_1.default.join(vovk, 'index.ts');
19
+ if ((await fileExists(js)) || (await fileExists(ts)) || (await fileExists(index))) {
20
+ return;
21
+ }
22
+ await fs_1.promises.mkdir(vovk, { recursive: true });
23
+ await fs_1.promises.writeFile(js, '/* postinstall */');
24
+ await fs_1.promises.writeFile(ts, '/* postinstall */');
25
+ await fs_1.promises.writeFile(index, '/* postinstall */');
26
+ }
27
+ void postinstall();
@@ -0,0 +1,5 @@
1
+ import http from 'http';
2
+ import { VovkMetadata } from 'vovk';
3
+ export default function createMetadataServer(then: (metadata: {
4
+ metadata: VovkMetadata;
5
+ }) => void | Promise<void>, catchFn: (err: Error) => void | Promise<void>): http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.default = createMetadataServer;
7
+ const http_1 = __importDefault(require("http"));
8
+ function createMetadataServer(then, catchFn) {
9
+ return http_1.default.createServer((req, res) => {
10
+ if (req.method === 'POST' && req.url === '/__metadata') {
11
+ let body = '';
12
+ req.on('data', (chunk) => {
13
+ body += chunk.toString();
14
+ });
15
+ req.on('end', () => {
16
+ try {
17
+ const result = JSON.parse(body);
18
+ void then(result);
19
+ }
20
+ catch (e) {
21
+ void catchFn(e);
22
+ }
23
+ });
24
+ }
25
+ else {
26
+ res.writeHead(404, { 'Content-Type': 'text/plain' });
27
+ res.end('Not Found');
28
+ void catchFn(new Error('Not Found'));
29
+ }
30
+ });
31
+ }
@@ -0,0 +1,43 @@
1
+ import { VovkMetadata } from 'vovk';
2
+ import { _VovkControllerMetadata, _VovkWorkerMetadata } from 'vovk/types';
3
+ interface HandlersDiff {
4
+ nameOfClass: string;
5
+ added: string[];
6
+ removed: string[];
7
+ changed: string[];
8
+ }
9
+ interface WorkersOrControllersDiff {
10
+ added: string[];
11
+ removed: string[];
12
+ handlers: HandlersDiff[];
13
+ }
14
+ export interface DiffResult {
15
+ workers: WorkersOrControllersDiff;
16
+ controllers: WorkersOrControllersDiff;
17
+ }
18
+ export declare function diffHandlers<T extends _VovkWorkerMetadata['_handlers'] | _VovkControllerMetadata['_handlers']>(oldHandlers: T, newHandlers: T, nameOfClass: string): HandlersDiff;
19
+ export declare function diffWorkersOrControllers<T extends VovkMetadata['controllers'] | VovkMetadata['workers']>(oldItems: T, newItems: T): WorkersOrControllersDiff;
20
+ /**
21
+ example output:
22
+ {
23
+ workers: {
24
+ added: ["WorkerC"],
25
+ removed: ["WorkerA"],
26
+ handlers: []
27
+ },
28
+ controllers: {
29
+ added: ["ControllerC"],
30
+ removed: ["ControllerB"],
31
+ handlers: [
32
+ {
33
+ nameOfClass: "ControllerA",
34
+ added: ["handlerF"],
35
+ removed: [],
36
+ changed: ["handlerD"]
37
+ }
38
+ ]
39
+ }
40
+ }
41
+ */
42
+ export default function diffMetadata(oldJson: VovkMetadata, newJson: VovkMetadata): DiffResult;
43
+ export {};
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.diffHandlers = diffHandlers;
4
+ exports.diffWorkersOrControllers = diffWorkersOrControllers;
5
+ exports.default = diffMetadata;
6
+ const lodash_1 = require("lodash");
7
+ function diffHandlers(oldHandlers, newHandlers, nameOfClass) {
8
+ const added = [];
9
+ const removed = [];
10
+ const changed = []; // Array to store changed handlers
11
+ for (const [handler, newHandler] of Object.entries(newHandlers)) {
12
+ if (!(handler in oldHandlers)) {
13
+ added.push(handler);
14
+ }
15
+ else if (!(0, lodash_1.isEqual)(newHandler, oldHandlers[handler])) {
16
+ changed.push(handler); // Add to changed if handlers are not shallow equal
17
+ }
18
+ }
19
+ for (const [handler] of Object.entries(oldHandlers)) {
20
+ if (!(handler in newHandlers)) {
21
+ removed.push(handler);
22
+ }
23
+ }
24
+ return { nameOfClass, added, removed, changed };
25
+ }
26
+ function diffWorkersOrControllers(oldItems, newItems) {
27
+ const added = [];
28
+ const removed = [];
29
+ const handlersDiff = [];
30
+ for (const [item, newItem] of Object.entries(newItems)) {
31
+ if (!(item in oldItems)) {
32
+ added.push(item);
33
+ }
34
+ else {
35
+ const handlers = diffHandlers(oldItems[item]._handlers, newItem._handlers, item);
36
+ if (handlers.added.length || handlers.removed.length || handlers.changed.length) {
37
+ handlersDiff.push(handlers);
38
+ }
39
+ }
40
+ }
41
+ for (const [item] of Object.entries(oldItems)) {
42
+ if (!(item in newItems)) {
43
+ removed.push(item);
44
+ }
45
+ }
46
+ return { added, removed, handlers: handlersDiff };
47
+ }
48
+ /**
49
+ example output:
50
+ {
51
+ workers: {
52
+ added: ["WorkerC"],
53
+ removed: ["WorkerA"],
54
+ handlers: []
55
+ },
56
+ controllers: {
57
+ added: ["ControllerC"],
58
+ removed: ["ControllerB"],
59
+ handlers: [
60
+ {
61
+ nameOfClass: "ControllerA",
62
+ added: ["handlerF"],
63
+ removed: [],
64
+ changed: ["handlerD"]
65
+ }
66
+ ]
67
+ }
68
+ }
69
+ */
70
+ function diffMetadata(oldJson, newJson) {
71
+ const workersDiff = diffWorkersOrControllers(oldJson.workers ?? {}, newJson.workers ?? {});
72
+ const controllersDiff = diffWorkersOrControllers(oldJson.controllers ?? {}, newJson.controllers ?? {});
73
+ return {
74
+ workers: workersDiff,
75
+ controllers: controllersDiff,
76
+ };
77
+ }
@@ -0,0 +1,3 @@
1
+ import { ProjectInfo } from '../getProjectInfo';
2
+ export default function ensureMetadataFiles(metadataOutFullPath: string, segmentNames: string[], projectInfo: ProjectInfo | null): Promise<void>;
3
+ export declare const debouncedEnsureMetadataFiles: import("lodash").DebouncedFunc<typeof ensureMetadataFiles>;
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.debouncedEnsureMetadataFiles = void 0;
30
+ exports.default = ensureMetadataFiles;
31
+ const promises_1 = __importDefault(require("fs/promises"));
32
+ const path_1 = __importDefault(require("path"));
33
+ const debounce_1 = __importDefault(require("lodash/debounce"));
34
+ const writeOneMetadataFile_1 = __importStar(require("./writeOneMetadataFile"));
35
+ async function ensureMetadataFiles(metadataOutFullPath, segmentNames, projectInfo) {
36
+ const now = Date.now();
37
+ let hasChanged = false;
38
+ // Create index.js file
39
+ const indexContent = segmentNames
40
+ .map((segmentName) => {
41
+ return `module.exports['${segmentName}'] = require('./${segmentName || writeOneMetadataFile_1.ROOT_SEGMENT_SCHEMA_NAME}.json');`;
42
+ })
43
+ .join('\n');
44
+ const dTsContent = `import type { VovkMetadata } from 'vovk';
45
+ declare const segmentMetadata: Record<string, VovkMetadata>;
46
+ export default segmentMetadata;`;
47
+ await promises_1.default.mkdir(metadataOutFullPath, { recursive: true });
48
+ await promises_1.default.writeFile(path_1.default.join(metadataOutFullPath, 'index.js'), indexContent);
49
+ await promises_1.default.writeFile(path_1.default.join(metadataOutFullPath, 'index.d.ts'), dTsContent);
50
+ // Create JSON files (if not exist) with name [segmentName].json (where segmentName can include /, which means the folder structure can be nested) : {} (empty object)
51
+ await Promise.all(segmentNames.map(async (segmentName) => {
52
+ const { isCreated } = await (0, writeOneMetadataFile_1.default)({
53
+ metadataOutFullPath,
54
+ metadata: {
55
+ emitMetadata: false,
56
+ segmentName,
57
+ controllers: {},
58
+ workers: {},
59
+ },
60
+ skipIfExists: true,
61
+ });
62
+ if (isCreated) {
63
+ projectInfo?.log.debug(`Created empty metadata file for segment "${segmentName}"`);
64
+ hasChanged = true;
65
+ }
66
+ }));
67
+ // Recursive function to delete unnecessary JSON files and folders
68
+ async function deleteUnnecessaryJsonFiles(dirPath) {
69
+ const entries = await promises_1.default.readdir(dirPath, { withFileTypes: true });
70
+ await Promise.all(entries.map(async (entry) => {
71
+ const fullPath = path_1.default.join(dirPath, entry.name);
72
+ if (entry.isDirectory()) {
73
+ // Recursively delete unnecessary files and folders within nested directories
74
+ await deleteUnnecessaryJsonFiles(fullPath);
75
+ // Check if the directory is empty after deletion and remove it if so
76
+ const remainingEntries = await promises_1.default.readdir(fullPath);
77
+ if (remainingEntries.length === 0) {
78
+ await promises_1.default.rmdir(fullPath);
79
+ projectInfo?.log.debug(`Deleted unnecessary metadata directory "${fullPath}"`);
80
+ hasChanged = true;
81
+ }
82
+ }
83
+ else if (entry.isFile() && entry.name.endsWith('.json')) {
84
+ const relativePath = path_1.default.relative(metadataOutFullPath, fullPath);
85
+ const segmentName = relativePath.replace(/\\/g, '/').slice(0, -5); // Remove '.json' extension
86
+ if (!segmentNames.includes(segmentName) &&
87
+ !segmentNames.includes(segmentName.replace(writeOneMetadataFile_1.ROOT_SEGMENT_SCHEMA_NAME, ''))) {
88
+ await promises_1.default.unlink(fullPath);
89
+ projectInfo?.log.debug(`Deleted unnecessary metadata file for segment "${segmentName}"`);
90
+ hasChanged = true;
91
+ }
92
+ }
93
+ }));
94
+ }
95
+ // Start the recursive deletion from the root directory
96
+ await deleteUnnecessaryJsonFiles(metadataOutFullPath);
97
+ if (hasChanged)
98
+ projectInfo?.log.info(`Metadata files updated in ${Date.now() - now}ms`);
99
+ }
100
+ exports.debouncedEnsureMetadataFiles = (0, debounce_1.default)(ensureMetadataFiles, 1000);
@@ -0,0 +1,7 @@
1
+ import type { ProjectInfo } from '../getProjectInfo';
2
+ import type { Segment } from '../locateSegments';
3
+ import { VovkMetadata } from 'vovk';
4
+ export default function generateClient(projectInfo: ProjectInfo, segments: Segment[], segmentsMetadata: Record<string, VovkMetadata>): Promise<{
5
+ written: boolean;
6
+ path: string;
7
+ }>;
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.default = generateClient;
7
+ const path_1 = __importDefault(require("path"));
8
+ const promises_1 = __importDefault(require("fs/promises"));
9
+ async function generateClient(projectInfo, segments, segmentsMetadata) {
10
+ const now = Date.now();
11
+ const outDir = projectInfo.clientOutFullPath;
12
+ const validatePath = projectInfo.config.validateOnClient?.startsWith('.')
13
+ ? path_1.default.join(projectInfo.cwd, projectInfo.config.validateOnClient)
14
+ : projectInfo.config.validateOnClient;
15
+ let dts = `// auto-generated
16
+ /* eslint-disable */
17
+ import type { clientizeController } from 'vovk/client';
18
+ import type { promisifyWorker } from 'vovk/worker';
19
+ import type { VovkClientFetcher } from 'vovk/client';
20
+ import type fetcher from '${projectInfo.fetcherClientImportPath}';
21
+
22
+ `;
23
+ let js = `// auto-generated
24
+ /* eslint-disable */
25
+ const { clientizeController } = require('vovk/client');
26
+ const { promisifyWorker } = require('vovk/worker');
27
+ const { default: fetcher } = require('${projectInfo.fetcherClientImportPath}');
28
+ const metadata = require('${projectInfo.metadataOutImportPath}');
29
+ `;
30
+ let ts = `// auto-generated
31
+ /* eslint-disable */
32
+ import { clientizeController } from 'vovk/client';
33
+ import { promisifyWorker } from 'vovk/worker';
34
+ import type { VovkClientFetcher } from 'vovk/client';
35
+ import fetcher from '${projectInfo.fetcherClientImportPath}';
36
+ import metadata from '${projectInfo.metadataOutImportPath}';
37
+
38
+ `;
39
+ for (let i = 0; i < segments.length; i++) {
40
+ const { routeFilePath, segmentName } = segments[i];
41
+ const metadata = segmentsMetadata[segmentName];
42
+ if (!metadata) {
43
+ throw new Error(`Unable to generate client. No metadata found for segment ${segmentName}`);
44
+ }
45
+ if (!metadata.emitMetadata)
46
+ continue;
47
+ const importRouteFilePath = path_1.default.relative(projectInfo.config.clientOutDir, routeFilePath);
48
+ dts += `import type { Controllers as Controllers${i}, Workers as Workers${i} } from "${importRouteFilePath}";\n`;
49
+ ts += `import type { Controllers as Controllers${i}, Workers as Workers${i} } from "${importRouteFilePath}";\n`;
50
+ }
51
+ dts += `
52
+ type Options = typeof fetcher extends VovkClientFetcher<infer U> ? U : never;
53
+ `;
54
+ ts += `
55
+ ${validatePath ? `import validateOnClient from '${validatePath}';\n` : '\nconst validateOnClient = undefined;'}
56
+ type Options = typeof fetcher extends VovkClientFetcher<infer U> ? U : never;
57
+ const prefix = '${projectInfo.apiPrefix}';
58
+ `;
59
+ js += `
60
+ const { default: validateOnClient = null } = ${validatePath ? `require('${validatePath}')` : '{}'};
61
+ const prefix = '${projectInfo.apiPrefix}';
62
+ `;
63
+ for (let i = 0; i < segments.length; i++) {
64
+ const { segmentName } = segments[i];
65
+ const metadata = segmentsMetadata[segmentName];
66
+ if (!metadata) {
67
+ throw new Error(`Unable to generate client. No metadata found for segment ${segmentName}`);
68
+ }
69
+ if (!metadata.emitMetadata)
70
+ continue;
71
+ for (const key of Object.keys(metadata.controllers)) {
72
+ dts += `export const ${key}: ReturnType<typeof clientizeController<Controllers${i}["${key}"], Options>>;\n`;
73
+ js += `exports.${key} = clientizeController(metadata['${segmentName}'].controllers.${key}, '${segmentName}', { fetcher, validateOnClient, defaultOptions: { prefix } });\n`;
74
+ ts += `export const ${key} = clientizeController<Controllers${i}["${key}"], Options>(metadata['${segmentName}'].controllers.${key}, '${segmentName}', { fetcher, validateOnClient, defaultOptions: { prefix } });\n`;
75
+ }
76
+ for (const key of Object.keys(metadata.workers)) {
77
+ dts += `export const ${key}: ReturnType<typeof promisifyWorker<Workers${i}["${key}"]>>;\n`;
78
+ js += `exports.${key} = promisifyWorker(null, metadata['${segmentName}'].workers.${key});\n`;
79
+ ts += `export const ${key} = promisifyWorker<Workers${i}["${key}"]>(null, metadata['${segmentName}'].workers.${key});\n`;
80
+ }
81
+ }
82
+ const localJsPath = path_1.default.join(outDir, 'client.js');
83
+ const localDtsPath = path_1.default.join(outDir, 'client.d.ts');
84
+ const localTsPath = path_1.default.join(outDir, 'index.ts');
85
+ const existingJs = await promises_1.default.readFile(localJsPath, 'utf-8').catch(() => '');
86
+ const existingDts = await promises_1.default.readFile(localDtsPath, 'utf-8').catch(() => '');
87
+ const existingTs = await promises_1.default.readFile(localTsPath, 'utf-8').catch(() => '');
88
+ if (existingJs === js && existingDts === dts && existingTs === ts) {
89
+ projectInfo.log.info(`Client is up to date and doesn't need to be regenerated (${Date.now() - now}ms).`);
90
+ return { written: false, path: outDir };
91
+ }
92
+ await promises_1.default.mkdir(outDir, { recursive: true });
93
+ await promises_1.default.writeFile(localJsPath, js);
94
+ await promises_1.default.writeFile(localDtsPath, dts);
95
+ await promises_1.default.writeFile(localTsPath, ts);
96
+ projectInfo.log.info(`Client generated in ${Date.now() - now}ms`);
97
+ return { written: true, path: outDir };
98
+ }
@@ -0,0 +1,6 @@
1
+ export declare class VovkCLIServer {
2
+ #private;
3
+ startServer({ clientOutDir }?: {
4
+ clientOutDir?: string;
5
+ }): Promise<void>;
6
+ }