Skip to content

Commit 2e9b699

Browse files
Fix(app) init scaffolding (#14)
* fix(webdocs): use 302 redirect for /install route * fix(app): fix scaffolded project to work out of the box - Replace auth/login.http (non-existent endpoint) with posts/create.http - Add missing userId variable to treq.jsonc config - Simplify generated run.ts (remove flag parsing, warnings boilerplate) - Use @t-req/core "latest" instead of "^0.1.0" - Scaffold tsconfig.json and type devDependencies per runtime * chore: add changeset
1 parent 25eed69 commit 2e9b699

File tree

4 files changed

+107
-51
lines changed

4 files changed

+107
-51
lines changed

.changeset/deep-paws-dig.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@t-req/app": minor
3+
---
4+
5+
Fix treq init to scaffold projects that work immediately — replace broken auth/login

packages/app/src/cmd/init.ts

Lines changed: 49 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -199,17 +199,21 @@ async function createProjectStructure(projectPath: string, config: ProjectConfig
199199
// Create directories using Bun shell
200200
await $`mkdir -p ${projectPath}`.quiet();
201201
await $`mkdir -p ${join(projectPath, '.treq')}`.quiet();
202-
await $`mkdir -p ${join(projectPath, 'collection', 'auth')}`.quiet();
202+
await $`mkdir -p ${join(projectPath, 'collection', 'posts')}`.quiet();
203203
await $`mkdir -p ${join(projectPath, 'collection', 'users')}`.quiet();
204204

205205
// Write root files
206206
await Bun.write(join(projectPath, 'treq.jsonc'), generateConfig());
207207
await Bun.write(join(projectPath, 'run.ts'), generateRunScript(config.runtime));
208208
await Bun.write(join(projectPath, 'package.json'), generatePackageJson(projectName, config));
209+
await Bun.write(join(projectPath, 'tsconfig.json'), generateTsconfig(config.runtime));
209210
await Bun.write(join(projectPath, '.gitignore'), generateGitignore());
210211

211212
// Write collection
212-
await Bun.write(join(projectPath, 'collection', 'auth', 'login.http'), generateLoginRequest());
213+
await Bun.write(
214+
join(projectPath, 'collection', 'posts', 'create.http'),
215+
generateCreatePostRequest()
216+
);
213217
await Bun.write(
214218
join(projectPath, 'collection', 'users', 'list.http'),
215219
generateListUsersRequest()
@@ -222,7 +226,8 @@ export function generateConfig(): string {
222226
"variables": {
223227
// Default base URL for the included sample requests.
224228
// Switch profiles with: treq run ... --profile dev
225-
"baseUrl": "https://jsonplaceholder.typicode.com"
229+
"baseUrl": "https://jsonplaceholder.typicode.com",
230+
"userId": 1
226231
// Example substitutions:
227232
// "apiKey": "{env:API_KEY}",
228233
// "authToken": "{file:./secrets/token.txt}"
@@ -251,48 +256,23 @@ export function generateConfig(): string {
251256
export function generateRunScript(runtime: Runtime): string {
252257
const shebang = runtime === 'bun' ? '#!/usr/bin/env bun' : '#!/usr/bin/env npx tsx';
253258

259+
const nodeImport =
260+
runtime === 'node' ? "\nimport { createNodeIO } from '@t-req/core/runtime';" : '';
261+
const ioOption = runtime === 'node' ? '\n io: createNodeIO(),' : '';
262+
254263
return `${shebang}
255264
import { createClient } from '@t-req/core';
256-
import { resolveProjectConfig } from '@t-req/core/config';
257-
${runtime === 'node' ? "import { createNodeIO } from '@t-req/core/runtime';" : ''}
258-
259-
function getFlagValue(name: string): string | undefined {
260-
const idx = process.argv.indexOf(name);
261-
if (idx === -1) return undefined;
262-
const value = process.argv[idx + 1];
263-
return value && !value.startsWith('-') ? value : undefined;
264-
}
265+
import { resolveProjectConfig } from '@t-req/core/config';${nodeImport}
265266
266-
const profile = getFlagValue('--profile') ?? process.env.TREQ_PROFILE;
267-
const { config, meta } = await resolveProjectConfig({
268-
startDir: process.cwd(),
269-
profile: profile || undefined,
270-
});
271-
272-
for (const warning of meta.warnings) {
273-
console.warn(\`Warning: \${warning}\`);
274-
}
267+
const { config } = await resolveProjectConfig({ startDir: process.cwd() });
275268
276-
const client = createClient({
277-
${runtime === 'node' ? 'io: createNodeIO(),' : ''}
269+
const client = createClient({${ioOption}
278270
variables: config.variables,
279-
// Map config defaults into the client (timeout + headers/redirects/ssl/proxy).
280-
timeout: config.defaults.timeoutMs,
281271
defaults: config.defaults,
282272
});
283273
284-
// Example: Get a user
285-
console.log('Fetching user...');
286-
const response = await client.run('./collection/users/get.http', {
287-
variables: { userId: 1 },
288-
});
289-
290-
if (response.ok) {
291-
const user = await response.json();
292-
console.log('User:', user);
293-
} else {
294-
console.error('Failed to fetch user:', response.status, response.statusText);
295-
}
274+
const response = await client.run('./collection/users/get.http');
275+
console.log(response.status, await response.json());
296276
`;
297277
}
298278

@@ -308,12 +288,17 @@ export function generatePackageJson(projectName: string, config: ProjectConfig):
308288
start: runCommand
309289
},
310290
dependencies: {
311-
'@t-req/core': '^0.1.0'
291+
'@t-req/core': 'latest'
312292
}
313293
};
314294

315-
if (config.runtime === 'node') {
295+
if (config.runtime === 'bun') {
296+
pkg['devDependencies'] = {
297+
'@types/bun': 'latest'
298+
};
299+
} else {
316300
pkg['devDependencies'] = {
301+
'@types/node': '^22.0.0',
317302
tsx: '^4.0.0'
318303
};
319304
}
@@ -333,11 +318,33 @@ dist/
333318
`;
334319
}
335320

336-
export function generateLoginRequest(): string {
337-
return `POST {{baseUrl}}/auth/login
321+
export function generateTsconfig(runtime: Runtime): string {
322+
const types = runtime === 'bun' ? 'bun-types' : 'node';
323+
return `${JSON.stringify(
324+
{
325+
compilerOptions: {
326+
target: 'ESNext',
327+
module: 'ESNext',
328+
moduleResolution: 'bundler',
329+
types: [types],
330+
strict: true,
331+
noEmit: true
332+
}
333+
},
334+
null,
335+
2
336+
)}\n`;
337+
}
338+
339+
export function generateCreatePostRequest(): string {
340+
return `POST {{baseUrl}}/posts
338341
Content-Type: application/json
339342
340-
{"email": "{{email}}", "password": "{{password}}"}
343+
{
344+
"title": "Hello from t-req",
345+
"body": "This is a sample post.",
346+
"userId": 1
347+
}
341348
`;
342349
}
343350

packages/app/test/cmd/init.test.ts

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import { describe, expect, test } from 'bun:test';
22
import {
33
generateConfig,
4+
generateCreatePostRequest,
5+
generateGetUserRequest,
46
generateGitignore,
5-
generateLoginRequest,
7+
generateListUsersRequest,
68
generatePackageJson,
79
generateRunScript,
10+
generateTsconfig,
811
getInstallCommand,
912
getNextSteps,
1013
validateProjectName
@@ -102,16 +105,24 @@ describe('generated file contents', () => {
102105
expect(pkg.private).toBe(true);
103106
});
104107

105-
test('should add tsx devDependency for node runtime', () => {
108+
test('should add type devDependencies per runtime', () => {
106109
const bunPkg = JSON.parse(
107110
generatePackageJson('test', { name: 'test', runtime: 'bun', packageManager: 'bun' })
108111
) as { devDependencies?: Record<string, string> };
109-
expect(bunPkg.devDependencies).toBeUndefined();
112+
expect(bunPkg.devDependencies?.['@types/bun']).toBe('latest');
110113

111114
const nodePkg = JSON.parse(
112115
generatePackageJson('test', { name: 'test', runtime: 'node', packageManager: 'npm' })
113116
) as { devDependencies?: Record<string, string> };
114117
expect(nodePkg.devDependencies?.tsx).toBe('^4.0.0');
118+
expect(nodePkg.devDependencies?.['@types/node']).toBe('^22.0.0');
119+
});
120+
121+
test('should use latest for @t-req/core dependency', () => {
122+
const pkg = JSON.parse(
123+
generatePackageJson('test', { name: 'test', runtime: 'bun', packageManager: 'bun' })
124+
) as { dependencies: Record<string, string> };
125+
expect(pkg.dependencies['@t-req/core']).toBe('latest');
115126
});
116127

117128
test('should generate .gitignore with common patterns', () => {
@@ -132,11 +143,44 @@ describe('generated file contents', () => {
132143
});
133144

134145
test('should generate sample HTTP request files', () => {
135-
const loginRequest = generateLoginRequest();
136-
expect(loginRequest).toContain('POST');
137-
expect(loginRequest).toContain('{{baseUrl}}');
138-
expect(loginRequest).toContain('{{email}}');
139-
expect(loginRequest).toContain('{{password}}');
146+
const createPost = generateCreatePostRequest();
147+
expect(createPost).toContain('POST');
148+
expect(createPost).toContain('{{baseUrl}}/posts');
149+
expect(createPost).toContain('"title"');
150+
expect(createPost).not.toContain('{{email}}');
151+
expect(createPost).not.toContain('{{password}}');
152+
});
153+
154+
test('should generate run script with resolveProjectConfig and without getFlagValue', () => {
155+
const script = generateRunScript('bun');
156+
expect(script).toContain('resolveProjectConfig');
157+
expect(script).not.toContain('getFlagValue');
158+
expect(script).not.toContain('meta.warnings');
159+
});
160+
161+
test('should generate tsconfig with bun-types for bun runtime', () => {
162+
const tsconfig = JSON.parse(generateTsconfig('bun'));
163+
expect(tsconfig.compilerOptions.types).toEqual(['bun-types']);
164+
});
165+
166+
test('should generate tsconfig with node types for node runtime', () => {
167+
const tsconfig = JSON.parse(generateTsconfig('node'));
168+
expect(tsconfig.compilerOptions.types).toEqual(['node']);
169+
});
170+
171+
test('all template variables should be defined in config', () => {
172+
const config = generateConfig();
173+
const templates = [
174+
generateCreatePostRequest(),
175+
generateListUsersRequest(),
176+
generateGetUserRequest()
177+
];
178+
for (const tpl of templates) {
179+
const vars = [...tpl.matchAll(/\{\{(\w+)\}\}/g)].map((m) => m[1]);
180+
for (const v of vars) {
181+
expect(config).toContain(`"${v}"`);
182+
}
183+
}
140184
});
141185
});
142186

packages/webdocs/public/_redirects

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
/install https://raw.githubusercontent.com/tensorix-labs/t-req/main/install 200
1+
/install https://raw.githubusercontent.com/tensorix-labs/t-req/main/install 302

0 commit comments

Comments
 (0)