@fluojs/cli 1.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/LICENSE +21 -0
  2. package/README.ko.md +155 -0
  3. package/README.md +155 -0
  4. package/bin/fluo.mjs +5 -0
  5. package/dist/cli.d.ts +37 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +292 -0
  8. package/dist/commands/generate.d.ts +40 -0
  9. package/dist/commands/generate.d.ts.map +1 -0
  10. package/dist/commands/generate.js +134 -0
  11. package/dist/commands/inspect.d.ts +30 -0
  12. package/dist/commands/inspect.d.ts.map +1 -0
  13. package/dist/commands/inspect.js +221 -0
  14. package/dist/commands/migrate.d.ts +30 -0
  15. package/dist/commands/migrate.d.ts.map +1 -0
  16. package/dist/commands/migrate.js +173 -0
  17. package/dist/commands/new.d.ts +45 -0
  18. package/dist/commands/new.d.ts.map +1 -0
  19. package/dist/commands/new.js +353 -0
  20. package/dist/generator-types.d.ts +21 -0
  21. package/dist/generator-types.d.ts.map +1 -0
  22. package/dist/generator-types.js +1 -0
  23. package/dist/generators/controller.d.ts +3 -0
  24. package/dist/generators/controller.d.ts.map +1 -0
  25. package/dist/generators/controller.js +22 -0
  26. package/dist/generators/guard.d.ts +3 -0
  27. package/dist/generators/guard.d.ts.map +1 -0
  28. package/dist/generators/guard.js +15 -0
  29. package/dist/generators/interceptor.d.ts +3 -0
  30. package/dist/generators/interceptor.d.ts.map +1 -0
  31. package/dist/generators/interceptor.js +15 -0
  32. package/dist/generators/manifest.d.ts +121 -0
  33. package/dist/generators/manifest.d.ts.map +1 -0
  34. package/dist/generators/manifest.js +130 -0
  35. package/dist/generators/middleware.d.ts +3 -0
  36. package/dist/generators/middleware.d.ts.map +1 -0
  37. package/dist/generators/middleware.js +15 -0
  38. package/dist/generators/module.d.ts +6 -0
  39. package/dist/generators/module.d.ts.map +1 -0
  40. package/dist/generators/module.js +143 -0
  41. package/dist/generators/render.d.ts +2 -0
  42. package/dist/generators/render.d.ts.map +1 -0
  43. package/dist/generators/render.js +17 -0
  44. package/dist/generators/repository.d.ts +3 -0
  45. package/dist/generators/repository.d.ts.map +1 -0
  46. package/dist/generators/repository.js +29 -0
  47. package/dist/generators/request-dto.d.ts +3 -0
  48. package/dist/generators/request-dto.d.ts.map +1 -0
  49. package/dist/generators/request-dto.js +17 -0
  50. package/dist/generators/response-dto.d.ts +3 -0
  51. package/dist/generators/response-dto.d.ts.map +1 -0
  52. package/dist/generators/response-dto.js +17 -0
  53. package/dist/generators/service.d.ts +3 -0
  54. package/dist/generators/service.d.ts.map +1 -0
  55. package/dist/generators/service.js +22 -0
  56. package/dist/generators/templates/controller.test.ts.ejs +21 -0
  57. package/dist/generators/templates/controller.ts.ejs +29 -0
  58. package/dist/generators/templates/guard.ts.ejs +7 -0
  59. package/dist/generators/templates/interceptor.ts.ejs +7 -0
  60. package/dist/generators/templates/middleware.ts.ejs +11 -0
  61. package/dist/generators/templates/module.ts.ejs +9 -0
  62. package/dist/generators/templates/repository.slice.test.ts.ejs +15 -0
  63. package/dist/generators/templates/repository.test.ts.ejs +9 -0
  64. package/dist/generators/templates/repository.ts.ejs +10 -0
  65. package/dist/generators/templates/request-dto.ts.ejs +9 -0
  66. package/dist/generators/templates/response-dto.ts.ejs +3 -0
  67. package/dist/generators/templates/service.test.ts.ejs +21 -0
  68. package/dist/generators/templates/service.ts.ejs +24 -0
  69. package/dist/generators/utils.d.ts +4 -0
  70. package/dist/generators/utils.d.ts.map +1 -0
  71. package/dist/generators/utils.js +18 -0
  72. package/dist/help.d.ts +8 -0
  73. package/dist/help.d.ts.map +1 -0
  74. package/dist/help.js +16 -0
  75. package/dist/index.d.ts +4 -0
  76. package/dist/index.d.ts.map +1 -0
  77. package/dist/index.js +2 -0
  78. package/dist/new/install.d.ts +51 -0
  79. package/dist/new/install.d.ts.map +1 -0
  80. package/dist/new/install.js +140 -0
  81. package/dist/new/package-spec-resolver.d.ts +4 -0
  82. package/dist/new/package-spec-resolver.d.ts.map +1 -0
  83. package/dist/new/package-spec-resolver.js +397 -0
  84. package/dist/new/prompt.d.ts +56 -0
  85. package/dist/new/prompt.d.ts.map +1 -0
  86. package/dist/new/prompt.js +278 -0
  87. package/dist/new/resolver.d.ts +32 -0
  88. package/dist/new/resolver.d.ts.map +1 -0
  89. package/dist/new/resolver.js +93 -0
  90. package/dist/new/scaffold.d.ts +14 -0
  91. package/dist/new/scaffold.d.ts.map +1 -0
  92. package/dist/new/scaffold.js +2010 -0
  93. package/dist/new/starter-profiles.d.ts +91 -0
  94. package/dist/new/starter-profiles.d.ts.map +1 -0
  95. package/dist/new/starter-profiles.js +347 -0
  96. package/dist/new/types.d.ts +63 -0
  97. package/dist/new/types.d.ts.map +1 -0
  98. package/dist/new/types.js +1 -0
  99. package/dist/registry.d.ts +10 -0
  100. package/dist/registry.d.ts.map +1 -0
  101. package/dist/registry.js +30 -0
  102. package/dist/transforms/nestjs-migrate.d.ts +33 -0
  103. package/dist/transforms/nestjs-migrate.d.ts.map +1 -0
  104. package/dist/transforms/nestjs-migrate.js +891 -0
  105. package/dist/types.d.ts +12 -0
  106. package/dist/types.d.ts.map +1 -0
  107. package/dist/types.js +1 -0
  108. package/package.json +65 -0
@@ -0,0 +1,56 @@
1
+ import type { BootstrapAnswers, PackageManager } from './types.js';
2
+ /** Default package manager used when detection has no signal. */
3
+ export declare const DEFAULT_PACKAGE_MANAGER: PackageManager;
4
+ type WritableStream = {
5
+ write(message: string): unknown;
6
+ };
7
+ type ReadableStream = {
8
+ isTTY?: boolean;
9
+ };
10
+ type PromptChoice<T extends string> = {
11
+ label: string;
12
+ value: T;
13
+ };
14
+ /** Prompt contract used by the interactive `fluo new` wizard. */
15
+ export interface BootstrapPrompter {
16
+ close?(): void;
17
+ confirm(message: string, defaultValue: boolean): Promise<boolean>;
18
+ select<T extends string>(message: string, choices: readonly PromptChoice<T>[], defaultValue?: T): Promise<T>;
19
+ text(message: string): Promise<string>;
20
+ }
21
+ /** Runtime overrides for resolving bootstrap answers in tests and editors. */
22
+ export interface ResolveBootstrapAnswersOptions {
23
+ interactive?: boolean;
24
+ prompt?: BootstrapPrompter;
25
+ stdin?: ReadableStream;
26
+ stdout?: WritableStream;
27
+ }
28
+ /**
29
+ * Detects the package manager that should back the generated starter.
30
+ *
31
+ * @param startDirectory Directory used for lockfile and manifest discovery.
32
+ * @param userAgent Optional package-manager user agent from the caller.
33
+ * @returns The detected package manager, or the repo default when no signal exists.
34
+ */
35
+ export declare function detectPackageManager(startDirectory: string, userAgent?: string): PackageManager;
36
+ /**
37
+ * Resolves partial bootstrap selections onto the shared answer model.
38
+ *
39
+ * @param partial Partial bootstrap selections collected from flags or runtime callers.
40
+ * @param cwd Working directory used for package-manager detection.
41
+ * @param userAgent Optional package-manager user agent from the caller.
42
+ * @returns Fully resolved bootstrap answers with defaults applied.
43
+ */
44
+ export declare function resolveBootstrapAnswers(partial: Partial<BootstrapAnswers>, cwd: string, userAgent?: string): BootstrapAnswers;
45
+ /**
46
+ * Collects bootstrap answers through the interactive wizard when needed.
47
+ *
48
+ * @param partial Partial bootstrap selections collected from flags or runtime callers.
49
+ * @param cwd Working directory used for package-manager detection.
50
+ * @param userAgent Optional package-manager user agent from the caller.
51
+ * @param options Runtime overrides for interactive prompting.
52
+ * @returns Fully resolved bootstrap answers for scaffolding.
53
+ */
54
+ export declare function collectBootstrapAnswers(partial: Partial<BootstrapAnswers>, cwd: string, userAgent?: string, options?: ResolveBootstrapAnswersOptions): Promise<BootstrapAnswers>;
55
+ export {};
56
+ //# sourceMappingURL=prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/new/prompt.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEnE,iEAAiE;AACjE,eAAO,MAAM,uBAAuB,EAAE,cAAuB,CAAC;AAI9D,KAAK,cAAc,GAAG;IACpB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,KAAK,YAAY,CAAC,CAAC,SAAS,MAAM,IAAI;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,CAAC,CAAC;CACV,CAAC;AAQF,iEAAiE;AACjE,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,IAAI,IAAI,CAAC;IACf,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClE,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,YAAY,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC7G,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACxC;AAED,8EAA8E;AAC9E,MAAM,WAAW,8BAA8B;IAC7C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,MAAM,CAAC,EAAE,cAAc,CAAC;CACzB;AA6OD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,cAAc,EAAE,MAAM,EACtB,SAAS,CAAC,EAAE,MAAM,GACjB,cAAc,CAIhB;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,OAAO,CAAC,gBAAgB,CAAC,EAClC,GAAG,EAAE,MAAM,EACX,SAAS,CAAC,EAAE,MAAM,GACjB,gBAAgB,CAgBlB;AAED;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,OAAO,CAAC,gBAAgB,CAAC,EAClC,GAAG,EAAE,MAAM,EACX,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,GAAE,8BAAmC,GAC3C,OAAO,CAAC,gBAAgB,CAAC,CA0B3B"}
@@ -0,0 +1,278 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { dirname, join, resolve } from 'node:path';
3
+ import * as clack from '@clack/prompts';
4
+ import { resolveBootstrapSchema } from './resolver.js';
5
+ import { DOCUMENTED_MICROSERVICE_TRANSPORTS, getApplicationStarterProfiles } from './starter-profiles.js';
6
+ /** Default package manager used when detection has no signal. */
7
+ export const DEFAULT_PACKAGE_MANAGER = 'pnpm';
8
+ const DEFAULT_INSTALL_DEPENDENCIES = true;
9
+ const DEFAULT_INITIALIZE_GIT = false;
10
+ const STARTER_SHAPE_CHOICES = [{
11
+ label: 'Application',
12
+ value: 'application'
13
+ }, {
14
+ label: 'Microservice',
15
+ value: 'microservice'
16
+ }, {
17
+ label: 'Mixed',
18
+ value: 'mixed'
19
+ }];
20
+
21
+ /** Prompt contract used by the interactive `fluo new` wizard. */
22
+
23
+ /** Runtime overrides for resolving bootstrap answers in tests and editors. */
24
+
25
+ function hasOwnValue(partial, key) {
26
+ return partial[key] !== undefined;
27
+ }
28
+ function createBootstrapPrompter() {
29
+ return {
30
+ async confirm(message, defaultValue) {
31
+ const result = await clack.confirm({
32
+ message,
33
+ initialValue: defaultValue
34
+ });
35
+ if (clack.isCancel(result)) {
36
+ clack.cancel('Operation cancelled.');
37
+ process.exit(0);
38
+ }
39
+ return result;
40
+ },
41
+ async select(message, choices, defaultValue) {
42
+ const result = await clack.select({
43
+ message,
44
+ options: choices.map(choice => ({
45
+ label: choice.label,
46
+ value: choice.value
47
+ })),
48
+ initialValue: defaultValue
49
+ });
50
+ if (clack.isCancel(result)) {
51
+ clack.cancel('Operation cancelled.');
52
+ process.exit(0);
53
+ }
54
+ return result;
55
+ },
56
+ async text(message) {
57
+ const result = await clack.text({
58
+ message,
59
+ validate(value) {
60
+ if (!value || value.trim().length === 0) {
61
+ return 'Value is required.';
62
+ }
63
+ }
64
+ });
65
+ if (clack.isCancel(result)) {
66
+ clack.cancel('Operation cancelled.');
67
+ process.exit(0);
68
+ }
69
+ return result;
70
+ }
71
+ };
72
+ }
73
+ function shouldPromptForAnswers(partial, interactive) {
74
+ const selectedRuntime = partial.runtime;
75
+ return interactive && (!hasOwnValue(partial, 'projectName') || !hasOwnValue(partial, 'shape') || !hasOwnValue(partial, 'tooling') || !hasOwnValue(partial, 'packageManager') || !hasOwnValue(partial, 'installDependencies') || !hasOwnValue(partial, 'initializeGit') || partial.shape === 'application' && !hasOwnValue(partial, 'runtime') || partial.shape === 'application' && selectedRuntime === 'node' && !hasOwnValue(partial, 'platform') || partial.shape === 'microservice' && !hasOwnValue(partial, 'transport'));
76
+ }
77
+ async function resolveInteractiveBootstrapAnswers(partial, cwd, userAgent, prompt) {
78
+ const answers = {
79
+ ...partial
80
+ };
81
+ const detectedPackageManager = detectPackageManager(cwd, userAgent);
82
+ if (!answers.projectName) {
83
+ answers.projectName = assertValidProjectName(await prompt.text('Project name'));
84
+ }
85
+ if (!answers.shape) {
86
+ answers.shape = await prompt.select('Starter shape', STARTER_SHAPE_CHOICES, 'application');
87
+ }
88
+ if (answers.shape === 'application' && !answers.runtime) {
89
+ answers.runtime = await prompt.select('Runtime', [{
90
+ label: 'Bun',
91
+ value: 'bun'
92
+ }, {
93
+ label: 'Cloudflare Workers',
94
+ value: 'cloudflare-workers'
95
+ }, {
96
+ label: 'Deno',
97
+ value: 'deno'
98
+ }, {
99
+ label: 'Node.js',
100
+ value: 'node'
101
+ }], 'node');
102
+ }
103
+ if (answers.shape === 'application' && !answers.platform) {
104
+ if (answers.runtime === 'node') {
105
+ const applicationProfiles = getApplicationStarterProfiles('node');
106
+ answers.platform = await prompt.select('HTTP platform', applicationProfiles.map(profile => ({
107
+ label: profile.platformPromptLabel ?? profile.schema.platform,
108
+ value: profile.schema.platform
109
+ })), 'fastify');
110
+ } else if (answers.runtime === 'bun' || answers.runtime === 'deno' || answers.runtime === 'cloudflare-workers') {
111
+ answers.platform = answers.runtime;
112
+ }
113
+ }
114
+ if (answers.shape === 'microservice' && !answers.transport) {
115
+ answers.transport = await prompt.select('Microservice transport', DOCUMENTED_MICROSERVICE_TRANSPORTS.map(transport => ({
116
+ label: transport,
117
+ value: transport
118
+ })), 'tcp');
119
+ }
120
+ if (!answers.tooling) {
121
+ answers.tooling = await prompt.select('Tooling preset', [{
122
+ label: 'standard',
123
+ value: 'standard'
124
+ }], 'standard');
125
+ }
126
+ if (!answers.packageManager) {
127
+ answers.packageManager = await prompt.select('Package manager', [{
128
+ label: 'pnpm',
129
+ value: 'pnpm'
130
+ }, {
131
+ label: 'npm',
132
+ value: 'npm'
133
+ }, {
134
+ label: 'yarn',
135
+ value: 'yarn'
136
+ }, {
137
+ label: 'bun',
138
+ value: 'bun'
139
+ }], detectedPackageManager);
140
+ }
141
+ if (!hasOwnValue(answers, 'installDependencies')) {
142
+ answers.installDependencies = await prompt.confirm('Install dependencies now', DEFAULT_INSTALL_DEPENDENCIES);
143
+ }
144
+ if (!hasOwnValue(answers, 'initializeGit')) {
145
+ answers.initializeGit = await prompt.confirm('Initialize a git repository', DEFAULT_INITIALIZE_GIT);
146
+ }
147
+ return resolveBootstrapAnswers(answers, cwd, userAgent);
148
+ }
149
+ function assertValidProjectName(projectName) {
150
+ const trimmed = projectName.trim();
151
+ if (trimmed.length === 0) {
152
+ throw new Error('Project name is required.');
153
+ }
154
+ if (trimmed.includes('/') || trimmed.includes('\\') || trimmed.includes('..')) {
155
+ throw new Error(`Invalid project name "${projectName}": must not contain path separators or traversal sequences.`);
156
+ }
157
+ return trimmed;
158
+ }
159
+ function parsePackageManager(value) {
160
+ if (!value) {
161
+ return undefined;
162
+ }
163
+ if (value.startsWith('bun')) {
164
+ return 'bun';
165
+ }
166
+ if (value.startsWith('pnpm')) {
167
+ return 'pnpm';
168
+ }
169
+ if (value.startsWith('yarn')) {
170
+ return 'yarn';
171
+ }
172
+ if (value.startsWith('npm')) {
173
+ return 'npm';
174
+ }
175
+ return undefined;
176
+ }
177
+ function detectFromUserAgent(userAgent) {
178
+ if (!userAgent) {
179
+ return undefined;
180
+ }
181
+ const candidate = userAgent.split(' ')[0];
182
+ return parsePackageManager(candidate);
183
+ }
184
+ function detectFromDirectory(startDirectory) {
185
+ let currentDirectory = resolve(startDirectory);
186
+ while (true) {
187
+ const packageJsonPath = join(currentDirectory, 'package.json');
188
+ if (existsSync(packageJsonPath)) {
189
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
190
+ const fromPackageManagerField = parsePackageManager(packageJson.packageManager);
191
+ if (fromPackageManagerField) {
192
+ return fromPackageManagerField;
193
+ }
194
+ }
195
+ if (existsSync(join(currentDirectory, 'bun.lock')) || existsSync(join(currentDirectory, 'bun.lockb'))) {
196
+ return 'bun';
197
+ }
198
+ if (existsSync(join(currentDirectory, 'pnpm-lock.yaml'))) {
199
+ return 'pnpm';
200
+ }
201
+ if (existsSync(join(currentDirectory, 'yarn.lock'))) {
202
+ return 'yarn';
203
+ }
204
+ if (existsSync(join(currentDirectory, 'package-lock.json'))) {
205
+ return 'npm';
206
+ }
207
+ const parentDirectory = dirname(currentDirectory);
208
+ if (parentDirectory === currentDirectory) {
209
+ return undefined;
210
+ }
211
+ currentDirectory = parentDirectory;
212
+ }
213
+ }
214
+
215
+ /**
216
+ * Detects the package manager that should back the generated starter.
217
+ *
218
+ * @param startDirectory Directory used for lockfile and manifest discovery.
219
+ * @param userAgent Optional package-manager user agent from the caller.
220
+ * @returns The detected package manager, or the repo default when no signal exists.
221
+ */
222
+ export function detectPackageManager(startDirectory, userAgent) {
223
+ return detectFromUserAgent(userAgent) ?? detectFromDirectory(startDirectory) ?? DEFAULT_PACKAGE_MANAGER;
224
+ }
225
+
226
+ /**
227
+ * Resolves partial bootstrap selections onto the shared answer model.
228
+ *
229
+ * @param partial Partial bootstrap selections collected from flags or runtime callers.
230
+ * @param cwd Working directory used for package-manager detection.
231
+ * @param userAgent Optional package-manager user agent from the caller.
232
+ * @returns Fully resolved bootstrap answers with defaults applied.
233
+ */
234
+ export function resolveBootstrapAnswers(partial, cwd, userAgent) {
235
+ if (!partial.projectName) {
236
+ throw new Error('Project name is required.');
237
+ }
238
+ const projectName = assertValidProjectName(partial.projectName);
239
+ const schema = resolveBootstrapSchema(partial);
240
+ return {
241
+ initializeGit: partial.initializeGit ?? DEFAULT_INITIALIZE_GIT,
242
+ installDependencies: partial.installDependencies ?? DEFAULT_INSTALL_DEPENDENCIES,
243
+ packageManager: partial.packageManager ?? detectPackageManager(cwd, userAgent),
244
+ ...schema,
245
+ projectName,
246
+ targetDirectory: partial.targetDirectory ?? `./${projectName}`
247
+ };
248
+ }
249
+
250
+ /**
251
+ * Collects bootstrap answers through the interactive wizard when needed.
252
+ *
253
+ * @param partial Partial bootstrap selections collected from flags or runtime callers.
254
+ * @param cwd Working directory used for package-manager detection.
255
+ * @param userAgent Optional package-manager user agent from the caller.
256
+ * @param options Runtime overrides for interactive prompting.
257
+ * @returns Fully resolved bootstrap answers for scaffolding.
258
+ */
259
+ export async function collectBootstrapAnswers(partial, cwd, userAgent, options = {}) {
260
+ const interactive = options.interactive ?? (options.prompt !== undefined || Boolean(options.stdin?.isTTY ?? process.stdin.isTTY));
261
+ if (!shouldPromptForAnswers(partial, interactive)) {
262
+ return resolveBootstrapAnswers(partial, cwd, userAgent);
263
+ }
264
+ const prompt = options.prompt ?? createBootstrapPrompter();
265
+ const isInteractiveShell = options.prompt === undefined;
266
+ try {
267
+ if (isInteractiveShell) {
268
+ clack.intro('fluo new');
269
+ }
270
+ const answers = await resolveInteractiveBootstrapAnswers(partial, cwd, userAgent, prompt);
271
+ if (isInteractiveShell) {
272
+ clack.outro(`Project created! Run: cd ${answers.targetDirectory}`);
273
+ }
274
+ return answers;
275
+ } finally {
276
+ prompt.close?.();
277
+ }
278
+ }
@@ -0,0 +1,32 @@
1
+ import type { BootstrapOptions, BootstrapSchema } from './types.js';
2
+ import { type StarterProfile } from './starter-profiles.js';
3
+ type BootstrapResolutionInput = Partial<BootstrapSchema> & Pick<Partial<BootstrapOptions>, 'packageManager'>;
4
+ /**
5
+ * Shape-first compatibility baseline for `fluo new` until additional starter variants ship.
6
+ */
7
+ export declare const DEFAULT_BOOTSTRAP_SCHEMA: BootstrapSchema;
8
+ /**
9
+ * Dependency set required by the currently supported `fluo new` starter baseline.
10
+ */
11
+ export interface ResolvedBootstrapPlan {
12
+ dependencies: StarterProfile['dependencies'];
13
+ emitter: StarterProfile['emitter'];
14
+ profile: StarterProfile;
15
+ schema: BootstrapSchema;
16
+ }
17
+ /**
18
+ * Resolves a partial starter schema onto the currently supported v2 compatibility baseline.
19
+ *
20
+ * @param partial Partial CLI/runtime schema selections.
21
+ * @returns A normalized bootstrap schema with defaults applied.
22
+ */
23
+ export declare function resolveBootstrapSchema(partial?: Partial<BootstrapSchema>): BootstrapSchema;
24
+ /**
25
+ * Resolves the dependency and emitter plan for the requested starter schema.
26
+ *
27
+ * @param options Partial or full bootstrap options collected from the CLI/runtime surface.
28
+ * @returns The normalized schema plus the emitter boundary that should render scaffold files.
29
+ */
30
+ export declare function resolveBootstrapPlan(options: BootstrapResolutionInput | BootstrapOptions): ResolvedBootstrapPlan;
31
+ export {};
32
+ //# sourceMappingURL=resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../src/new/resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EAGhB,MAAM,YAAY,CAAC;AACpB,OAAO,EAYL,KAAK,cAAc,EACpB,MAAM,uBAAuB,CAAC;AAE/B,KAAK,wBAAwB,GAAG,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC,CAAC;AAE7G;;GAEG;AACH,eAAO,MAAM,wBAAwB,EAAE,eAA6C,CAAC;AAErF;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,YAAY,EAAE,cAAc,CAAC,cAAc,CAAC,CAAC;IAC7C,OAAO,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC;IACnC,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,eAAe,CAAC;CACzB;AAyBD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,OAAO,CAAC,eAAe,CAAM,GAAG,eAAe,CAe9F;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,wBAAwB,GAAG,gBAAgB,GAAG,qBAAqB,CAkFhH"}
@@ -0,0 +1,93 @@
1
+ import { getDefaultBootstrapSchema, getDefaultBootstrapSchemaForShape, getStarterProfileForShape, getStarterProfileFromSchema, isSupportedMicroserviceStarterTransport, SUPPORTED_BOOTSTRAP_PLATFORMS, SUPPORTED_BOOTSTRAP_RUNTIMES, SUPPORTED_BOOTSTRAP_SHAPES, SUPPORTED_BOOTSTRAP_TOOLING_PRESETS, SUPPORTED_BOOTSTRAP_TOPOLOGY_MODES, SUPPORTED_BOOTSTRAP_TRANSPORTS } from './starter-profiles.js';
2
+ /**
3
+ * Shape-first compatibility baseline for `fluo new` until additional starter variants ship.
4
+ */
5
+ export const DEFAULT_BOOTSTRAP_SCHEMA = getDefaultBootstrapSchema();
6
+
7
+ /**
8
+ * Dependency set required by the currently supported `fluo new` starter baseline.
9
+ */
10
+
11
+ function defaultSchemaForShape(shape, runtime) {
12
+ return getDefaultBootstrapSchemaForShape(shape, runtime);
13
+ }
14
+ function assertOneOf(label, value, supported) {
15
+ if (!supported.includes(value)) {
16
+ throw new Error(`Unsupported ${label} "${value}". Supported values: ${supported.join(', ')}.`);
17
+ }
18
+ return value;
19
+ }
20
+ function normalizeTopology(topology) {
21
+ return {
22
+ deferred: topology?.deferred ?? true,
23
+ mode: assertOneOf('topology mode', topology?.mode ?? DEFAULT_BOOTSTRAP_SCHEMA.topology.mode, SUPPORTED_BOOTSTRAP_TOPOLOGY_MODES)
24
+ };
25
+ }
26
+
27
+ /**
28
+ * Resolves a partial starter schema onto the currently supported v2 compatibility baseline.
29
+ *
30
+ * @param partial Partial CLI/runtime schema selections.
31
+ * @returns A normalized bootstrap schema with defaults applied.
32
+ */
33
+ export function resolveBootstrapSchema(partial = {}) {
34
+ const shape = assertOneOf('shape', partial.shape ?? DEFAULT_BOOTSTRAP_SCHEMA.shape, SUPPORTED_BOOTSTRAP_SHAPES);
35
+ const runtime = partial.runtime ? assertOneOf('runtime', partial.runtime, SUPPORTED_BOOTSTRAP_RUNTIMES) : undefined;
36
+ const defaults = defaultSchemaForShape(shape, runtime);
37
+ return {
38
+ platform: assertOneOf('platform', partial.platform ?? defaults.platform, SUPPORTED_BOOTSTRAP_PLATFORMS),
39
+ runtime: assertOneOf('runtime', partial.runtime ?? defaults.runtime, SUPPORTED_BOOTSTRAP_RUNTIMES),
40
+ shape,
41
+ tooling: assertOneOf('tooling', partial.tooling ?? defaults.tooling, SUPPORTED_BOOTSTRAP_TOOLING_PRESETS),
42
+ topology: normalizeTopology(partial.topology),
43
+ transport: assertOneOf('transport', partial.transport ?? defaults.transport, SUPPORTED_BOOTSTRAP_TRANSPORTS)
44
+ };
45
+ }
46
+
47
+ /**
48
+ * Resolves the dependency and emitter plan for the requested starter schema.
49
+ *
50
+ * @param options Partial or full bootstrap options collected from the CLI/runtime surface.
51
+ * @returns The normalized schema plus the emitter boundary that should render scaffold files.
52
+ */
53
+ export function resolveBootstrapPlan(options) {
54
+ const schema = resolveBootstrapSchema(options);
55
+ const starterProfile = getStarterProfileFromSchema(schema);
56
+ if (starterProfile) {
57
+ return {
58
+ dependencies: starterProfile.dependencies,
59
+ emitter: starterProfile.emitter,
60
+ profile: starterProfile,
61
+ schema
62
+ };
63
+ }
64
+ const defaultProfile = getStarterProfileForShape(schema.shape);
65
+ if (schema.shape === 'microservice' && schema.transport === 'http') {
66
+ throw new Error('Unsupported bootstrap schema "microservice/node/http/' + schema.platform + '/standard/single-package". ' + 'Microservice starters require a transport-aware microservice transport such as tcp, redis-streams, mqtt, grpc, nats, kafka, or rabbitmq.');
67
+ }
68
+ if (schema.shape === 'application' && isSupportedMicroserviceStarterTransport(schema.transport)) {
69
+ throw new Error('Unsupported bootstrap schema "application/node/' + schema.transport + '/' + schema.platform + '/standard/single-package". ' + 'Application starters currently require the HTTP transport across the Fastify, Express, raw Node.js, Bun, Deno, and Cloudflare Workers starter profiles.');
70
+ }
71
+ if (schema.shape === 'mixed' && schema.transport === 'http') {
72
+ throw new Error('Unsupported bootstrap schema "mixed/node/http/' + schema.platform + '/standard/' + schema.topology.mode + '". ' + 'The first mixed starter uses the HTTP API plus an attached TCP microservice; use tcp for the supported mixed contract.');
73
+ }
74
+ if (schema.shape === 'microservice' && isSupportedMicroserviceStarterTransport(schema.transport) && schema.transport !== defaultProfile.schema.transport) {
75
+ throw new Error('Unsupported bootstrap schema "microservice/node/' + schema.transport + '/' + schema.platform + '/standard/single-package". ' + 'The first-class microservice starters currently scaffold tcp, redis-streams, nats, kafka, rabbitmq, mqtt, and grpc.');
76
+ }
77
+ if (schema.shape === 'mixed' && isSupportedMicroserviceStarterTransport(schema.transport) && schema.transport !== defaultProfile.schema.transport) {
78
+ throw new Error('Unsupported bootstrap schema "mixed/node/' + schema.transport + '/' + schema.platform + '/standard/' + schema.topology.mode + '". ' + 'The first mixed starter currently supports only the attached TCP microservice contract.');
79
+ }
80
+ if (schema.shape === 'application' && schema.topology.mode !== 'single-package') {
81
+ throw new Error('Unsupported bootstrap schema "application/node/' + schema.transport + '/' + schema.platform + '/standard/' + schema.topology.mode + '". ' + 'Application starters currently support only the single-package HTTP topology; use --shape mixed for the API + microservice starter.');
82
+ }
83
+ if (schema.shape === 'microservice' && schema.topology.mode !== 'single-package') {
84
+ throw new Error('Unsupported bootstrap schema "microservice/node/' + schema.transport + '/' + schema.platform + '/standard/' + schema.topology.mode + '". ' + 'Microservice starters currently support only the single-package microservice topology.');
85
+ }
86
+ if (schema.shape === 'mixed' && schema.topology.mode !== 'single-package') {
87
+ throw new Error('Unsupported bootstrap schema "mixed/node/' + schema.transport + '/' + schema.platform + '/standard/' + schema.topology.mode + '". ' + 'Mixed starters currently support only the single-package contract: one Fastify HTTP application with an attached TCP microservice.');
88
+ }
89
+ if (schema.tooling !== 'standard' || schema.topology.deferred !== true) {
90
+ throw new Error(`Unsupported bootstrap schema "${schema.shape}/${schema.runtime}/${schema.transport}/${schema.platform}/${schema.tooling}/${schema.topology.mode}". ` + 'The current compatibility baseline supports the standard single-package Node + Fastify/Express/raw Node.js HTTP starters, Bun/Deno/Cloudflare Workers HTTP starters, the tcp/redis-streams/nats/kafka/rabbitmq/mqtt/grpc microservice starters, and the mixed single-package starter.');
91
+ }
92
+ throw new Error(`Unsupported bootstrap schema "${schema.shape}/${schema.runtime}/${schema.transport}/${schema.platform}/${schema.tooling}/${schema.topology.mode}". ` + 'The current compatibility baseline supports the standard single-package Node + Fastify/Express/raw Node.js HTTP starters, Bun/Deno/Cloudflare Workers HTTP starters, the tcp/redis-streams/nats/kafka/rabbitmq/mqtt/grpc microservice starters, and the mixed single-package starter.');
93
+ }
@@ -0,0 +1,14 @@
1
+ import type { BootstrapOptions } from './types.js';
2
+ /**
3
+ * Scaffolds a new fluo application into the target directory.
4
+ *
5
+ * @param options Bootstrap configuration for the new project.
6
+ * @param importMetaUrl Optional URL of the importing module for relative path resolution.
7
+ * @returns A promise that resolves when the project has been scaffolded.
8
+ */
9
+ export declare function scaffoldBootstrapApp(options: BootstrapOptions, importMetaUrl?: string): Promise<void>;
10
+ /**
11
+ * Alias for {@link scaffoldBootstrapApp}.
12
+ */
13
+ export declare const scaffoldFluoApp: typeof scaffoldBootstrapApp;
14
+ //# sourceMappingURL=scaffold.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../src/new/scaffold.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,gBAAgB,EAAkB,MAAM,YAAY,CAAC;AAijEnE;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,gBAAgB,EACzB,aAAa,SAAkB,GAC9B,OAAO,CAAC,IAAI,CAAC,CA6Bf;AAED;;GAEG;AACH,eAAO,MAAM,eAAe,6BAAuB,CAAC"}