@fluojs/cli 2.0.1 → 3.0.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 (118) hide show
  1. package/README.ko.md +169 -21
  2. package/README.md +172 -21
  3. package/dist/cli.d.ts +5 -4
  4. package/dist/cli.d.ts.map +1 -1
  5. package/dist/cli.js +127 -35
  6. package/dist/commands/diagnostics.d.ts +35 -0
  7. package/dist/commands/diagnostics.d.ts.map +1 -1
  8. package/dist/commands/diagnostics.js +60 -0
  9. package/dist/commands/inspect.d.ts +5 -1
  10. package/dist/commands/inspect.d.ts.map +1 -1
  11. package/dist/commands/inspect.js +84 -17
  12. package/dist/commands/migrate.d.ts.map +1 -1
  13. package/dist/commands/migrate.js +27 -15
  14. package/dist/commands/migration-transform-tokens.d.ts +15 -0
  15. package/dist/commands/migration-transform-tokens.d.ts.map +1 -0
  16. package/dist/commands/migration-transform-tokens.js +41 -0
  17. package/dist/commands/new.d.ts.map +1 -1
  18. package/dist/commands/new.js +29 -9
  19. package/dist/commands/output-path-safety.d.ts +14 -0
  20. package/dist/commands/output-path-safety.d.ts.map +1 -0
  21. package/dist/commands/output-path-safety.js +34 -0
  22. package/dist/commands/scripts.js +2 -2
  23. package/dist/commands/typegen-artifact.d.ts +54 -0
  24. package/dist/commands/typegen-artifact.d.ts.map +1 -0
  25. package/dist/commands/typegen-artifact.js +117 -0
  26. package/dist/commands/typegen-generation-child.d.ts +2 -0
  27. package/dist/commands/typegen-generation-child.d.ts.map +1 -0
  28. package/dist/commands/typegen-generation-child.js +59 -0
  29. package/dist/commands/typegen-generation-process.d.ts +46 -0
  30. package/dist/commands/typegen-generation-process.d.ts.map +1 -0
  31. package/dist/commands/typegen-generation-process.js +131 -0
  32. package/dist/commands/typegen-generation-protocol.d.ts +16 -0
  33. package/dist/commands/typegen-generation-protocol.d.ts.map +1 -0
  34. package/dist/commands/typegen-generation-protocol.js +35 -0
  35. package/dist/commands/typegen-isolated-source.d.ts +10 -0
  36. package/dist/commands/typegen-isolated-source.d.ts.map +1 -0
  37. package/dist/commands/typegen-isolated-source.js +75 -0
  38. package/dist/commands/typegen-options.d.ts +20 -0
  39. package/dist/commands/typegen-options.d.ts.map +1 -0
  40. package/dist/commands/typegen-options.js +71 -0
  41. package/dist/commands/typegen-source.d.ts +59 -0
  42. package/dist/commands/typegen-source.d.ts.map +1 -0
  43. package/dist/commands/typegen-source.js +183 -0
  44. package/dist/commands/typegen-watch.d.ts +46 -0
  45. package/dist/commands/typegen-watch.d.ts.map +1 -0
  46. package/dist/commands/typegen-watch.js +212 -0
  47. package/dist/commands/typegen.d.ts +29 -0
  48. package/dist/commands/typegen.d.ts.map +1 -0
  49. package/dist/commands/typegen.js +119 -0
  50. package/dist/dev-runner/node-restart-runner.d.ts.map +1 -1
  51. package/dist/dev-runner/node-restart-runner.js +54 -7
  52. package/dist/fixtures/inspect-react-app.module.d.ts +4 -0
  53. package/dist/fixtures/inspect-react-app.module.d.ts.map +1 -0
  54. package/dist/fixtures/inspect-react-app.module.js +32 -0
  55. package/dist/fixtures/typegen-react-app.module.d.ts +4 -0
  56. package/dist/fixtures/typegen-react-app.module.d.ts.map +1 -0
  57. package/dist/fixtures/typegen-react-app.module.js +33 -0
  58. package/dist/index.d.ts +6 -5
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +3 -2
  61. package/dist/new/install.js +1 -1
  62. package/dist/new/package-spec-resolver.d.ts.map +1 -1
  63. package/dist/new/package-spec-resolver.js +50 -59
  64. package/dist/new/prompt.d.ts +1 -0
  65. package/dist/new/prompt.d.ts.map +1 -1
  66. package/dist/new/prompt.js +40 -12
  67. package/dist/new/published-internal-dependencies.d.ts +20 -0
  68. package/dist/new/published-internal-dependencies.d.ts.map +1 -0
  69. package/dist/new/published-internal-dependencies.js +20 -0
  70. package/dist/new/react-vite-ssr-scaffold.d.ts +19 -0
  71. package/dist/new/react-vite-ssr-scaffold.d.ts.map +1 -0
  72. package/dist/new/react-vite-ssr-scaffold.js +108 -0
  73. package/dist/new/resolver.d.ts +2 -2
  74. package/dist/new/resolver.d.ts.map +1 -1
  75. package/dist/new/resolver.js +5 -1
  76. package/dist/new/scaffold.d.ts.map +1 -1
  77. package/dist/new/scaffold.js +62 -31
  78. package/dist/new/starter-profiles.d.ts +8 -4
  79. package/dist/new/starter-profiles.d.ts.map +1 -1
  80. package/dist/new/starter-profiles.js +52 -18
  81. package/dist/new/templates/react-vite-ssr/README.md.ejs +74 -0
  82. package/dist/new/templates/react-vite-ssr/playwright.config.ts.ejs +26 -0
  83. package/dist/new/templates/react-vite-ssr/src/app.test.ts.ejs +82 -0
  84. package/dist/new/templates/react-vite-ssr/src/app.ts.ejs +91 -0
  85. package/dist/new/templates/react-vite-ssr/src/entry-client.tsx.ejs +29 -0
  86. package/dist/new/templates/react-vite-ssr/src/entry-server.tsx.ejs +52 -0
  87. package/dist/new/templates/react-vite-ssr/src/load-manifest.test.ts.ejs +55 -0
  88. package/dist/new/templates/react-vite-ssr/src/load-manifest.ts.ejs +53 -0
  89. package/dist/new/templates/react-vite-ssr/src/main.ts.ejs +18 -0
  90. package/dist/new/templates/react-vite-ssr/src/page.tsx.ejs +43 -0
  91. package/dist/new/templates/react-vite-ssr/src/react-app.test.tsx.ejs +67 -0
  92. package/dist/new/templates/react-vite-ssr/src/react-app.tsx.ejs +46 -0
  93. package/dist/new/templates/react-vite-ssr/src/styles.css.ejs +25 -0
  94. package/dist/new/templates/react-vite-ssr/src/styles.d.ts.ejs +1 -0
  95. package/dist/new/templates/react-vite-ssr/tests/production-hydration.spec.ts.ejs +54 -0
  96. package/dist/new/templates/react-vite-ssr/tsconfig.json.ejs +16 -0
  97. package/dist/new/templates/react-vite-ssr/vite.client.config.ts.ejs +24 -0
  98. package/dist/new/templates/react-vite-ssr/vite.server.config.ts.ejs +17 -0
  99. package/dist/new/templates/react-vite-ssr/vitest.config.ts.ejs +10 -0
  100. package/dist/new/types.d.ts +4 -0
  101. package/dist/new/types.d.ts.map +1 -1
  102. package/dist/public-typegen.d.ts +14 -0
  103. package/dist/public-typegen.d.ts.map +1 -0
  104. package/dist/public-typegen.js +17 -0
  105. package/dist/run-cli.d.ts +2 -1
  106. package/dist/run-cli.d.ts.map +1 -1
  107. package/dist/studio/sidecar.d.ts.map +1 -1
  108. package/dist/studio/sidecar.js +35 -9
  109. package/dist/transforms/nestjs-migrate.d.ts +4 -1
  110. package/dist/transforms/nestjs-migrate.d.ts.map +1 -1
  111. package/dist/transforms/nestjs-migrate.js +625 -65
  112. package/dist/typegen-contract.d.ts +10 -0
  113. package/dist/typegen-contract.d.ts.map +1 -0
  114. package/dist/typegen-contract.js +9 -0
  115. package/dist/usage.d.ts +6 -0
  116. package/dist/usage.d.ts.map +1 -1
  117. package/dist/usage.js +47 -0
  118. package/package.json +19 -10
@@ -0,0 +1,117 @@
1
+ import { renameSync } from 'node:fs';
2
+ import { mkdir, readFile, rm, writeFile } from 'node:fs/promises';
3
+ import { basename, dirname, join } from 'node:path';
4
+
5
+ /** Filesystem boundary used by deterministic typegen artifact commits. */
6
+
7
+ /** Stable non-mutating comparison result for an existing typegen target. */
8
+
9
+ /** Stable write action reported after an atomic typegen artifact commit. */
10
+
11
+ const NODE_FILE_SYSTEM = {
12
+ async mkdir(path) {
13
+ await mkdir(path, {
14
+ recursive: true
15
+ });
16
+ },
17
+ readFile: path => readFile(path, 'utf8'),
18
+ rename(source, destination) {
19
+ renameSync(source, destination);
20
+ return undefined;
21
+ },
22
+ async rm(path) {
23
+ await rm(path, {
24
+ force: true
25
+ });
26
+ },
27
+ async writeFile(path, content) {
28
+ await writeFile(path, content, {
29
+ encoding: 'utf8',
30
+ flag: 'wx'
31
+ });
32
+ }
33
+ };
34
+ let temporaryFileSequence = 0;
35
+ function isMissingFileError(error) {
36
+ return typeof error === 'object' && error !== null && 'code' in error && error.code === 'ENOENT';
37
+ }
38
+ async function readExistingArtifact(outputPath, fileSystem) {
39
+ try {
40
+ return await fileSystem.readFile(outputPath);
41
+ } catch (error) {
42
+ if (isMissingFileError(error)) {
43
+ return undefined;
44
+ }
45
+ throw error;
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Compares an existing artifact with expected generated bytes without writing.
51
+ *
52
+ * @param outputPath Target artifact path.
53
+ * @param expectedSource Authoritative generated source.
54
+ * @param inspect Structural artifact classifier.
55
+ * @param fileSystem Filesystem boundary used to read the target.
56
+ * @returns A stable unchanged, missing, stale, malformed, or unsupported-version result.
57
+ */
58
+ export async function checkTypegenArtifact(outputPath, expectedSource, inspect, fileSystem = NODE_FILE_SYSTEM) {
59
+ const existingSource = await readExistingArtifact(outputPath, fileSystem);
60
+ if (existingSource === undefined) {
61
+ return {
62
+ status: 'MISSING'
63
+ };
64
+ }
65
+ if (existingSource === expectedSource) {
66
+ return {
67
+ status: 'UNCHANGED'
68
+ };
69
+ }
70
+ const inspection = inspect(existingSource);
71
+ if (inspection.status === 'malformed') {
72
+ return {
73
+ status: 'MALFORMED'
74
+ };
75
+ }
76
+ if (inspection.status === 'unsupported-version') {
77
+ return {
78
+ status: 'UNSUPPORTED_VERSION',
79
+ version: inspection.version
80
+ };
81
+ }
82
+ return {
83
+ status: 'STALE'
84
+ };
85
+ }
86
+
87
+ /**
88
+ * Atomically publishes generated source while skipping byte-identical rewrites.
89
+ *
90
+ * @param outputPath Target artifact path.
91
+ * @param source Complete generated source to publish.
92
+ * @param fileSystem Filesystem boundary used for the atomic replacement.
93
+ * @param signal Optional owner cancellation signal checked before publication.
94
+ * @returns The stable create, update, or unchanged action.
95
+ */
96
+ export async function writeTypegenArtifact(outputPath, source, fileSystem = NODE_FILE_SYSTEM, signal) {
97
+ signal?.throwIfAborted();
98
+ const existingSource = await readExistingArtifact(outputPath, fileSystem);
99
+ if (existingSource === source) {
100
+ return 'UNCHANGED';
101
+ }
102
+ await fileSystem.mkdir(dirname(outputPath));
103
+ temporaryFileSequence += 1;
104
+ const temporaryPath = join(dirname(outputPath), `.${basename(outputPath)}.${String(process.pid)}.${String(temporaryFileSequence)}.tmp`);
105
+ let committed = false;
106
+ try {
107
+ await fileSystem.writeFile(temporaryPath, source);
108
+ signal?.throwIfAborted();
109
+ fileSystem.rename(temporaryPath, outputPath);
110
+ committed = true;
111
+ } finally {
112
+ if (!committed) {
113
+ await fileSystem.rm(temporaryPath);
114
+ }
115
+ }
116
+ return existingSource === undefined ? 'CREATE' : 'UPDATE';
117
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=typegen-generation-child.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typegen-generation-child.d.ts","sourceRoot":"","sources":["../../src/commands/typegen-generation-child.ts"],"names":[],"mappings":""}
@@ -0,0 +1,59 @@
1
+ import { createProcessIsolatedTypegenSource } from './typegen-isolated-source.js';
2
+ import { TypegenCommandError } from './typegen-options.js';
3
+ function readGenerationArgs() {
4
+ const [cwd, modulePath, exportName] = process.argv.slice(2);
5
+ if (cwd === undefined || modulePath === undefined || exportName === undefined) {
6
+ throw new TypegenCommandError('Typegen generation process received incomplete arguments.');
7
+ }
8
+ return {
9
+ cwd,
10
+ exportName,
11
+ modulePath
12
+ };
13
+ }
14
+ function sendGenerationMessage(message) {
15
+ if (process.send === undefined) {
16
+ throw new TypegenCommandError('Typegen generation process requires an IPC channel.');
17
+ }
18
+ const send = process.send.bind(process);
19
+ return new Promise((resolve, reject) => {
20
+ send(message, error => {
21
+ if (error === null) {
22
+ resolve();
23
+ return;
24
+ }
25
+ reject(error);
26
+ });
27
+ });
28
+ }
29
+ async function runGenerationChild() {
30
+ let message;
31
+ try {
32
+ const request = readGenerationArgs();
33
+ const parsed = {
34
+ check: false,
35
+ exportName: request.exportName,
36
+ modulePath: request.modulePath,
37
+ outputPath: '',
38
+ watch: false
39
+ };
40
+ message = {
41
+ kind: 'source',
42
+ source: await createProcessIsolatedTypegenSource(parsed, request.cwd)
43
+ };
44
+ } catch (error) {
45
+ process.exitCode = 1;
46
+ message = {
47
+ kind: 'error',
48
+ message: error instanceof Error ? error.message : String(error)
49
+ };
50
+ }
51
+ try {
52
+ await sendGenerationMessage(message);
53
+ } finally {
54
+ if (process.connected) {
55
+ process.disconnect();
56
+ }
57
+ }
58
+ }
59
+ await runGenerationChild();
@@ -0,0 +1,46 @@
1
+ type TypegenGenerationRequest = {
2
+ readonly cwd: string;
3
+ readonly exportName: string;
4
+ readonly modulePath: string;
5
+ };
6
+ /** Listener boundary for one short-lived typegen generation child. */
7
+ export type TypegenGenerationChild = {
8
+ readonly kill: (signal: NodeJS.Signals) => boolean;
9
+ readonly offError: (listener: (error: Error) => void) => void;
10
+ readonly offExit: (listener: (code: number | null, signal: NodeJS.Signals | null) => void) => void;
11
+ readonly offMessage: (listener: (message: unknown) => void) => void;
12
+ readonly onError: (listener: (error: Error) => void) => void;
13
+ readonly onExit: (listener: (code: number | null, signal: NodeJS.Signals | null) => void) => void;
14
+ readonly onMessage: (listener: (message: unknown) => void) => void;
15
+ };
16
+ type TypegenGenerationSpawner = (request: TypegenGenerationRequest) => TypegenGenerationChild;
17
+ /** One short-lived typegen generation process controlled by its watch coordinator. */
18
+ export type TypegenGenerationProcess = {
19
+ cancel(): void;
20
+ readonly result: Promise<string>;
21
+ };
22
+ /**
23
+ * Waits for a generation child to return source and exit, then removes every completion listener.
24
+ *
25
+ * @param child Generation child listener boundary.
26
+ * @returns Generated source after successful process exit.
27
+ */
28
+ export declare function waitForTypegenGenerationChild(child: TypegenGenerationChild): Promise<string>;
29
+ /**
30
+ * Starts one default typegen generation child for a coordinator to complete or cancel.
31
+ *
32
+ * @param request Consumer directory, application module path, and selected export.
33
+ * @param spawnGeneration Child-process factory used by the default runtime and lifecycle tests.
34
+ * @returns A cancellable child process whose result settles only after a clean process exit.
35
+ */
36
+ export declare function startTypegenGenerationProcess(request: TypegenGenerationRequest, spawnGeneration?: TypegenGenerationSpawner): TypegenGenerationProcess;
37
+ /**
38
+ * Runs one default typegen generation in a short-lived child process.
39
+ *
40
+ * @param request Consumer directory, application module path, and selected export.
41
+ * @param spawnGeneration Child-process factory used by the default runtime and lifecycle tests.
42
+ * @returns Generated source after the child process has exited.
43
+ */
44
+ export declare function runTypegenGenerationProcess(request: TypegenGenerationRequest, spawnGeneration?: TypegenGenerationSpawner): Promise<string>;
45
+ export {};
46
+ //# sourceMappingURL=typegen-generation-process.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typegen-generation-process.d.ts","sourceRoot":"","sources":["../../src/commands/typegen-generation-process.ts"],"names":[],"mappings":"AAQA,KAAK,wBAAwB,GAAG;IAC9B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEF,sEAAsE;AACtE,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,KAAK,OAAO,CAAC;IACnD,QAAQ,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,KAAK,IAAI,CAAC;IAC9D,QAAQ,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,KAAK,IAAI,KAAK,IAAI,CAAC;IACnG,QAAQ,CAAC,UAAU,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,KAAK,IAAI,CAAC;IACpE,QAAQ,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,KAAK,IAAI,CAAC;IAC7D,QAAQ,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,KAAK,IAAI,KAAK,IAAI,CAAC;IAClG,QAAQ,CAAC,SAAS,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,KAAK,IAAI,CAAC;CACpE,CAAC;AAEF,KAAK,wBAAwB,GAAG,CAAC,OAAO,EAAE,wBAAwB,KAAK,sBAAsB,CAAC;AA2B9F,sFAAsF;AACtF,MAAM,MAAM,wBAAwB,GAAG;IACrC,MAAM,IAAI,IAAI,CAAC;IACf,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;CAClC,CAAC;AASF;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,CAsC5F;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,wBAAwB,EACjC,eAAe,GAAE,wBAAgD,GAChE,wBAAwB,CA0B1B;AAED;;;;;;GAMG;AACH,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,wBAAwB,EACjC,eAAe,GAAE,wBAAgD,GAChE,OAAO,CAAC,MAAM,CAAC,CAEjB"}
@@ -0,0 +1,131 @@
1
+ import { fork } from 'node:child_process';
2
+ import { createRequire } from 'node:module';
3
+ import { dirname, extname, join } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { parseTypegenGenerationMessage } from './typegen-generation-protocol.js';
6
+ import { TypegenCommandError } from './typegen-options.js';
7
+
8
+ /** Listener boundary for one short-lived typegen generation child. */
9
+
10
+ const CHILD_TERMINATION_GRACE_MS = 500;
11
+ function createGenerationChild(request) {
12
+ const currentPath = fileURLToPath(import.meta.url);
13
+ const extension = extname(currentPath);
14
+ const childPath = join(dirname(currentPath), `typegen-generation-child${extension}`);
15
+ const execArgv = extension === '.ts' ? ['--experimental-import-meta-resolve', '--import', createRequire(import.meta.url).resolve('tsx')] : ['--experimental-import-meta-resolve'];
16
+ const child = fork(childPath, [request.cwd, request.modulePath, request.exportName], {
17
+ cwd: request.cwd,
18
+ execArgv,
19
+ stdio: ['ignore', 'ignore', 'ignore', 'ipc']
20
+ });
21
+ return {
22
+ kill: signal => child.kill(signal),
23
+ offError: listener => child.off('error', listener),
24
+ offExit: listener => child.off('exit', listener),
25
+ offMessage: listener => child.off('message', listener),
26
+ onError: listener => child.once('error', listener),
27
+ onExit: listener => child.once('exit', listener),
28
+ onMessage: listener => child.on('message', listener)
29
+ };
30
+ }
31
+
32
+ /** One short-lived typegen generation process controlled by its watch coordinator. */
33
+
34
+ function describeExit(code, signal) {
35
+ if (signal !== null) {
36
+ return `signal ${signal}`;
37
+ }
38
+ return code === null ? 'without an exit code' : `with exit code ${String(code)}`;
39
+ }
40
+
41
+ /**
42
+ * Waits for a generation child to return source and exit, then removes every completion listener.
43
+ *
44
+ * @param child Generation child listener boundary.
45
+ * @returns Generated source after successful process exit.
46
+ */
47
+ export function waitForTypegenGenerationChild(child) {
48
+ return new Promise((resolve, reject) => {
49
+ let message;
50
+ const cleanup = () => {
51
+ child.offError(onError);
52
+ child.offExit(onExit);
53
+ child.offMessage(onMessage);
54
+ };
55
+ const onError = error => {
56
+ cleanup();
57
+ reject(error);
58
+ };
59
+ const onMessage = value => {
60
+ try {
61
+ message = parseTypegenGenerationMessage(value);
62
+ } catch (error) {
63
+ message = {
64
+ kind: 'error',
65
+ message: error instanceof Error ? error.message : String(error)
66
+ };
67
+ }
68
+ };
69
+ const onExit = (code, signal) => {
70
+ cleanup();
71
+ if (message?.kind === 'error') {
72
+ reject(new TypegenCommandError(message.message));
73
+ return;
74
+ }
75
+ if (message?.kind === 'source' && code === 0) {
76
+ resolve(message.source);
77
+ return;
78
+ }
79
+ reject(new TypegenCommandError(`Typegen generation process exited ${describeExit(code, signal)} before returning source.`));
80
+ };
81
+ child.onError(onError);
82
+ child.onExit(onExit);
83
+ child.onMessage(onMessage);
84
+ });
85
+ }
86
+
87
+ /**
88
+ * Starts one default typegen generation child for a coordinator to complete or cancel.
89
+ *
90
+ * @param request Consumer directory, application module path, and selected export.
91
+ * @param spawnGeneration Child-process factory used by the default runtime and lifecycle tests.
92
+ * @returns A cancellable child process whose result settles only after a clean process exit.
93
+ */
94
+ export function startTypegenGenerationProcess(request, spawnGeneration = createGenerationChild) {
95
+ const child = spawnGeneration(request);
96
+ let cancelled = false;
97
+ let forcedKillTimer;
98
+ const result = waitForTypegenGenerationChild(child).finally(() => {
99
+ if (forcedKillTimer !== undefined) {
100
+ clearTimeout(forcedKillTimer);
101
+ forcedKillTimer = undefined;
102
+ }
103
+ });
104
+ return {
105
+ cancel() {
106
+ if (cancelled) {
107
+ return;
108
+ }
109
+ cancelled = true;
110
+ if (!child.kill('SIGTERM')) {
111
+ return;
112
+ }
113
+ forcedKillTimer = setTimeout(() => {
114
+ forcedKillTimer = undefined;
115
+ child.kill('SIGKILL');
116
+ }, CHILD_TERMINATION_GRACE_MS);
117
+ },
118
+ result
119
+ };
120
+ }
121
+
122
+ /**
123
+ * Runs one default typegen generation in a short-lived child process.
124
+ *
125
+ * @param request Consumer directory, application module path, and selected export.
126
+ * @param spawnGeneration Child-process factory used by the default runtime and lifecycle tests.
127
+ * @returns Generated source after the child process has exited.
128
+ */
129
+ export async function runTypegenGenerationProcess(request, spawnGeneration = createGenerationChild) {
130
+ return startTypegenGenerationProcess(request, spawnGeneration).result;
131
+ }
@@ -0,0 +1,16 @@
1
+ /** IPC outcome emitted by one isolated typegen generation child. */
2
+ export type TypegenGenerationMessage = {
3
+ readonly kind: 'error';
4
+ readonly message: string;
5
+ } | {
6
+ readonly kind: 'source';
7
+ readonly source: string;
8
+ };
9
+ /**
10
+ * Parses an untrusted generation child IPC payload.
11
+ *
12
+ * @param value IPC payload received from the child process.
13
+ * @returns A validated source or error message.
14
+ */
15
+ export declare function parseTypegenGenerationMessage(value: unknown): TypegenGenerationMessage;
16
+ //# sourceMappingURL=typegen-generation-protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typegen-generation-protocol.d.ts","sourceRoot":"","sources":["../../src/commands/typegen-generation-protocol.ts"],"names":[],"mappings":"AAEA,oEAAoE;AACpE,MAAM,MAAM,wBAAwB,GAChC;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACpD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzD;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,wBAAwB,CAkBtF"}
@@ -0,0 +1,35 @@
1
+ import { TypegenCommandError } from './typegen-options.js';
2
+
3
+ /** IPC outcome emitted by one isolated typegen generation child. */
4
+
5
+ /**
6
+ * Parses an untrusted generation child IPC payload.
7
+ *
8
+ * @param value IPC payload received from the child process.
9
+ * @returns A validated source or error message.
10
+ */
11
+ export function parseTypegenGenerationMessage(value) {
12
+ if (typeof value !== 'object' || value === null) {
13
+ throw new TypegenCommandError('Typegen generation process returned an invalid IPC message.');
14
+ }
15
+ const kind = Reflect.get(value, 'kind');
16
+ if (kind === 'error') {
17
+ const message = Reflect.get(value, 'message');
18
+ if (typeof message === 'string') {
19
+ return {
20
+ kind,
21
+ message
22
+ };
23
+ }
24
+ }
25
+ if (kind === 'source') {
26
+ const source = Reflect.get(value, 'source');
27
+ if (typeof source === 'string') {
28
+ return {
29
+ kind,
30
+ source
31
+ };
32
+ }
33
+ }
34
+ throw new TypegenCommandError('Typegen generation process returned an invalid IPC message.');
35
+ }
@@ -0,0 +1,10 @@
1
+ import type { ParsedTypegenArgs } from './typegen-options.js';
2
+ /**
3
+ * Generates source inside the default short-lived process while preserving one native module graph.
4
+ *
5
+ * @param parsed Parsed typegen command options.
6
+ * @param cwd Consumer project directory.
7
+ * @returns Complete deterministic generated source.
8
+ */
9
+ export declare function createProcessIsolatedTypegenSource(parsed: ParsedTypegenArgs, cwd: string): Promise<string>;
10
+ //# sourceMappingURL=typegen-isolated-source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typegen-isolated-source.d.ts","sourceRoot":"","sources":["../../src/commands/typegen-isolated-source.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAkE9D;;;;;;GAMG;AACH,wBAAsB,kCAAkC,CACtD,MAAM,EAAE,iBAAiB,EACzB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,CAAC,CAcjB"}
@@ -0,0 +1,75 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { dirname, extname, resolve } from 'node:path';
3
+ import { pathToFileURL } from 'node:url';
4
+ import { TypegenCommandError } from './typegen-options.js';
5
+ import { createTypegenSource, generateTypegenSource, loadReactTypegenModules } from './typegen-source.js';
6
+ const TYPESCRIPT_MODULE_EXTENSIONS = new Set(['.ts', '.tsx', '.mts', '.cts']);
7
+ const TYPEGEN_MODULE_IDS = ['@fluojs/react', '@fluojs/react/typegen', '@fluojs/runtime'];
8
+ function isModuleNotFoundError(error) {
9
+ return typeof error === 'object' && error !== null && 'code' in error && (error.code === 'MODULE_NOT_FOUND' || error.code === 'ERR_MODULE_NOT_FOUND');
10
+ }
11
+ function resolveProjectModuleUrl(moduleId, cwd) {
12
+ const parentUrls = [pathToFileURL(resolve(cwd, 'package.json')).href, import.meta.url];
13
+ for (const parentUrl of parentUrls) {
14
+ try {
15
+ return import.meta.resolve(moduleId, parentUrl);
16
+ } catch (error) {
17
+ if (!isModuleNotFoundError(error)) {
18
+ throw error;
19
+ }
20
+ }
21
+ }
22
+ throw new TypegenCommandError(`Unable to resolve ${moduleId} from the inspected project.`);
23
+ }
24
+ function requireNamespace(owner, name) {
25
+ const value = Reflect.get(owner, name);
26
+ if (typeof value !== 'object' || value === null) {
27
+ throw new TypegenCommandError(`Required typegen namespace ${name} is unavailable.`);
28
+ }
29
+ return value;
30
+ }
31
+ async function importNativeTypegenGraph(modulePath, cwd) {
32
+ const imports = {
33
+ application: pathToFileURL(modulePath).href,
34
+ react: resolveProjectModuleUrl(TYPEGEN_MODULE_IDS[0], cwd),
35
+ typegen: resolveProjectModuleUrl(TYPEGEN_MODULE_IDS[1], cwd),
36
+ runtime: resolveProjectModuleUrl(TYPEGEN_MODULE_IDS[2], cwd)
37
+ };
38
+ const source = `${Object.entries(imports).map(([name, url]) => `import * as ${name} from ${JSON.stringify(url)};`).join('\n')}\nexport { application, react, runtime, typegen };\n`;
39
+ const graphUrl = `data:text/javascript;charset=utf-8,${encodeURIComponent(source)}`;
40
+ const graph = await import(graphUrl);
41
+ return {
42
+ application: requireNamespace(graph, 'application'),
43
+ modules: {
44
+ react: requireNamespace(graph, 'react'),
45
+ runtime: requireNamespace(graph, 'runtime'),
46
+ typegen: requireNamespace(graph, 'typegen')
47
+ }
48
+ };
49
+ }
50
+
51
+ /**
52
+ * Generates source inside the default short-lived process while preserving one native module graph.
53
+ *
54
+ * @param parsed Parsed typegen command options.
55
+ * @param cwd Consumer project directory.
56
+ * @returns Complete deterministic generated source.
57
+ */
58
+ export async function createProcessIsolatedTypegenSource(parsed, cwd) {
59
+ const modulePath = resolve(cwd, parsed.modulePath);
60
+ if (TYPESCRIPT_MODULE_EXTENSIONS.has(extname(modulePath))) {
61
+ const tsconfigPath = resolve(dirname(modulePath), 'tsconfig.json');
62
+ const modules = await loadReactTypegenModules(cwd, existsSync(tsconfigPath) ? tsconfigPath : false);
63
+ return createTypegenSource({
64
+ cwd,
65
+ modules,
66
+ parsed
67
+ });
68
+ }
69
+ const imported = await importNativeTypegenGraph(modulePath, cwd);
70
+ return generateTypegenSource({
71
+ application: imported.application,
72
+ modules: imported.modules,
73
+ parsed
74
+ });
75
+ }
@@ -0,0 +1,20 @@
1
+ /** Parsed lifecycle and path options for one typegen invocation. */
2
+ export type ParsedTypegenArgs = {
3
+ readonly check: boolean;
4
+ readonly exportName: string;
5
+ readonly modulePath: string;
6
+ readonly outputPath: string;
7
+ readonly watch: boolean;
8
+ };
9
+ /** Invalid typegen command arguments or unavailable runtime tooling. */
10
+ export declare class TypegenCommandError extends Error {
11
+ readonly name = "TypegenCommandError";
12
+ }
13
+ /**
14
+ * Parses command arguments after `fluo typegen`.
15
+ *
16
+ * @param argv Raw typegen command arguments.
17
+ * @returns Parsed module, output, export, and lifecycle options.
18
+ */
19
+ export declare function parseTypegenArgs(argv: readonly string[]): ParsedTypegenArgs;
20
+ //# sourceMappingURL=typegen-options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typegen-options.d.ts","sourceRoot":"","sources":["../../src/commands/typegen-options.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,wEAAwE;AACxE,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,IAAI,yBAAyB;CACvC;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,iBAAiB,CAsD3E"}
@@ -0,0 +1,71 @@
1
+ /** Parsed lifecycle and path options for one typegen invocation. */
2
+
3
+ /** Invalid typegen command arguments or unavailable runtime tooling. */
4
+ export class TypegenCommandError extends Error {
5
+ name = 'TypegenCommandError';
6
+ }
7
+
8
+ /**
9
+ * Parses command arguments after `fluo typegen`.
10
+ *
11
+ * @param argv Raw typegen command arguments.
12
+ * @returns Parsed module, output, export, and lifecycle options.
13
+ */
14
+ export function parseTypegenArgs(argv) {
15
+ let check = false;
16
+ let exportName = 'AppModule';
17
+ let modulePath;
18
+ let outputPath;
19
+ let watch = false;
20
+ for (let index = 0; index < argv.length; index += 1) {
21
+ const option = argv[index];
22
+ if (option === '--check') {
23
+ check = true;
24
+ continue;
25
+ }
26
+ if (option === '--watch') {
27
+ watch = true;
28
+ continue;
29
+ }
30
+ if (option === '--output') {
31
+ const next = argv[index + 1];
32
+ if (next === undefined || next.startsWith('-')) {
33
+ throw new TypegenCommandError('Expected --output to have a file path value.');
34
+ }
35
+ outputPath = next;
36
+ index += 1;
37
+ continue;
38
+ }
39
+ if (option === '--export') {
40
+ const next = argv[index + 1];
41
+ if (next === undefined || next.startsWith('-')) {
42
+ throw new TypegenCommandError('Expected --export to have a symbol name value.');
43
+ }
44
+ exportName = next;
45
+ index += 1;
46
+ continue;
47
+ }
48
+ if (option?.startsWith('-')) {
49
+ throw new TypegenCommandError(`Unknown option for typegen command: ${option}`);
50
+ }
51
+ if (option !== undefined) {
52
+ if (modulePath !== undefined) {
53
+ throw new TypegenCommandError(`Unexpected extra positional argument: ${option}`);
54
+ }
55
+ modulePath = option;
56
+ }
57
+ }
58
+ if (modulePath === undefined || outputPath === undefined) {
59
+ throw new TypegenCommandError('Usage: fluo typegen <module-path> --output <path> [--export <name>] [--check|--watch]');
60
+ }
61
+ if (check && watch) {
62
+ throw new TypegenCommandError('fluo typegen accepts only one of --check or --watch.');
63
+ }
64
+ return {
65
+ check,
66
+ exportName,
67
+ modulePath,
68
+ outputPath,
69
+ watch
70
+ };
71
+ }
@@ -0,0 +1,59 @@
1
+ import type { ParsedTypegenArgs } from './typegen-options.js';
2
+ /** Dynamically loaded package surfaces required by typegen. */
3
+ export type ReactTypegenModules = {
4
+ readonly react: object;
5
+ readonly runtime: object;
6
+ readonly typegen: object;
7
+ };
8
+ /** Structural artifact result returned by the React typegen package. */
9
+ export type ReactTypegenArtifactInspection = {
10
+ readonly status: 'malformed';
11
+ } | {
12
+ readonly status: 'unsupported-version';
13
+ readonly version: number;
14
+ } | {
15
+ readonly status: 'valid';
16
+ readonly version: number;
17
+ };
18
+ type CreateTypegenSourceOptions = {
19
+ readonly cwd: string;
20
+ readonly modules: ReactTypegenModules;
21
+ readonly parsed: ParsedTypegenArgs;
22
+ };
23
+ type GenerateTypegenSourceOptions = {
24
+ readonly application: object;
25
+ readonly modules: ReactTypegenModules;
26
+ readonly parsed: ParsedTypegenArgs;
27
+ };
28
+ /**
29
+ * Loads typegen package entrypoints from the consumer project or CLI installation.
30
+ *
31
+ * @param cwd Consumer project directory used for package resolution.
32
+ * @param tsconfig TypeScript configuration path, or `false` for native package resolution.
33
+ * @returns React, React typegen, and runtime module namespaces.
34
+ */
35
+ export declare function loadReactTypegenModules(cwd: string, tsconfig?: string | false): Promise<ReactTypegenModules>;
36
+ /**
37
+ * Bootstraps the selected module and generates source from authoritative route descriptors.
38
+ *
39
+ * @param options Parsed command, consumer directory, module namespaces, and native import boundary.
40
+ * @returns Complete deterministic generated source.
41
+ */
42
+ export declare function createTypegenSource(options: CreateTypegenSourceOptions): Promise<string>;
43
+ /**
44
+ * Generates source from one already-imported application and its matching tooling namespaces.
45
+ *
46
+ * @param options Application namespace, generation modules, and parsed command selection.
47
+ * @returns Complete deterministic generated source.
48
+ */
49
+ export declare function generateTypegenSource(options: GenerateTypegenSourceOptions): Promise<string>;
50
+ /**
51
+ * Inspects an existing generated source value through the loaded React typegen package.
52
+ *
53
+ * @param modules Loaded React typegen module namespace.
54
+ * @param source Existing artifact source.
55
+ * @returns Parsed current, malformed, or unsupported-version status.
56
+ */
57
+ export declare function inspectReactTypegenArtifact(modules: ReactTypegenModules, source: string): ReactTypegenArtifactInspection;
58
+ export {};
59
+ //# sourceMappingURL=typegen-source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typegen-source.d.ts","sourceRoot":"","sources":["../../src/commands/typegen-source.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAG9D,+DAA+D;AAC/D,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,wEAAwE;AACxE,MAAM,MAAM,8BAA8B,GACtC;IAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GAChC;IAAE,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACpE;IAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3D,KAAK,0BAA0B,GAAG;IAChC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;CACpC,CAAC;AAEF,KAAK,4BAA4B,GAAG;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;CACpC,CAAC;AAwEF;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAM,GAAG,KAAa,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAKzH;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,MAAM,CAAC,CAU9F;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,GAAG,OAAO,CAAC,MAAM,CAAC,CAqClG;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,mBAAmB,EAC5B,MAAM,EAAE,MAAM,GACb,8BAA8B,CAmBhC"}