create-houdini 2.0.0-next.9 → 2.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.
package/bin.js CHANGED
@@ -16,17 +16,24 @@ let projectName = projectDir
16
16
  const { version } = JSON.parse(fs.readFileSync(new URL('package.json', import.meta.url), 'utf-8'))
17
17
  console.log(`${grey(`create-houdini version ${version}`)}\n`)
18
18
 
19
- // derive the dist-tag from our own version, then resolve it to a real version from the registry
19
+ // derive the dist-tag from our own version, then resolve each package to its actual published version
20
+ // independently — packages can be at different versions across a release cycle
20
21
  const distTag = version.includes('-') ? version.split('-')[1].split('.')[0] : 'latest'
21
- let houdiniVersion = version
22
- try {
23
- const { execSync } = await import('node:child_process')
24
- const resolved = execSync(`npm view houdini@${distTag} version`, { encoding: 'utf-8' }).trim()
25
- if (resolved) houdiniVersion = resolved
26
- } catch {
27
- // offline or registry unavailable — fall back to create-houdini's own version
22
+ const { execSync } = await import('node:child_process')
23
+
24
+ function resolveVersion(pkg) {
25
+ try {
26
+ const resolved = execSync(`npm view ${pkg}@${distTag} version`, { encoding: 'utf-8' }).trim()
27
+ return resolved || version
28
+ } catch {
29
+ return version
30
+ }
28
31
  }
29
32
 
33
+ const houdiniVersion = resolveVersion('houdini')
34
+ const houdiniReactVersion = resolveVersion('houdini-react')
35
+ const houdiniAdapterVersion = resolveVersion('houdini-adapter-auto')
36
+
30
37
  // prepare options
31
38
  const templatesDir = sourcePath(`./templates`)
32
39
  const options = fs.readdirSync(templatesDir).map((templateDir) => {
@@ -62,12 +69,11 @@ p.intro('🎩 Welcome to Houdini!')
62
69
 
63
70
  // if we weren't given a directory, then we should ask
64
71
  if (!projectDir) {
65
- const dir = await p.text({
72
+ const dir = await pathInput({
66
73
  message: `Where should we create your project?`,
67
- placeholder: ' (press Enter to use the current directory)',
68
74
  })
69
75
 
70
- if (p.isCancel(dir)) {
76
+ if (dir === null) {
71
77
  process.exit(1)
72
78
  }
73
79
 
@@ -141,13 +147,46 @@ let apiUrl = options_cli.schema?.startsWith('http') ? options_cli.schema : templ
141
147
  if (!localSchema) {
142
148
  let pullSchema_content = ''
143
149
  if (apiUrl === '') {
144
- const { apiUrl: apiUrlCli, pullSchema_content: pullSchema_content_cli } =
145
- await pullSchemaCli()
146
- apiUrl = apiUrlCli
147
- if (pullSchema_content_cli === null) {
148
- pCancel('There was a problem pulling your shema. Please try again.')
150
+ const apiRunning = await p.confirm({
151
+ message: 'Is your API currently running?',
152
+ initialValue: true,
153
+ })
154
+ if (p.isCancel(apiRunning)) pCancel()
155
+
156
+ if (apiRunning) {
157
+ const { apiUrl: apiUrlCli, pullSchema_content: pullSchema_content_cli } =
158
+ await pullSchemaCli()
159
+ apiUrl = apiUrlCli
160
+ if (pullSchema_content_cli === null) {
161
+ pCancel('There was a problem pulling your shema. Please try again.')
162
+ } else {
163
+ pullSchema_content = pullSchema_content_cli
164
+ }
149
165
  } else {
150
- pullSchema_content = pullSchema_content_cli
166
+ const hasSchemaFile = await p.confirm({
167
+ message: 'Do you have a schema file on disk we can use?',
168
+ initialValue: false,
169
+ })
170
+ if (p.isCancel(hasSchemaFile)) pCancel()
171
+
172
+ if (hasSchemaFile) {
173
+ const schemaFilePath = await pathInput({
174
+ message: 'Where is the schema file?',
175
+ initialValue: './schema.graphql',
176
+ validate: (value) => {
177
+ if (!value) return 'Please enter a valid path'
178
+ try {
179
+ fs.statSync(path.resolve(value))
180
+ } catch {
181
+ return 'File not found'
182
+ }
183
+ },
184
+ })
185
+ if (schemaFilePath === null) pCancel()
186
+ pullSchema_content = fs.readFileSync(path.resolve(schemaFilePath), 'utf-8')
187
+ }
188
+
189
+ apiUrl = 'API_URL'
151
190
  }
152
191
  } else {
153
192
  const pullSchema_content_local = await pullSchema(apiUrl, {})
@@ -158,22 +197,20 @@ if (!localSchema) {
158
197
  }
159
198
  }
160
199
 
161
- writeFileSync(path.join(projectDir, 'schema.graphql'), pullSchema_content)
200
+ if (pullSchema_content) {
201
+ writeFileSync(path.join(projectDir, 'schema.graphql'), pullSchema_content)
202
+ }
162
203
  }
163
204
 
164
- // the final client config depends on whether we have a local schema or not
165
- const clientConfig = localSchema
166
- ? ``
167
- : `{
168
- url: '${apiUrl}',
169
- }`
205
+ // the api url lives in houdini.config.js (`url`) now, never the client passing it to
206
+ // HoudiniClient throws. So the client takes no config here.
207
+ const clientConfig = ``
170
208
 
209
+ // a remote api sets the top-level `url` (watchSchema defaults to it), env-switched per build.
171
210
  const configFile = localSchema
172
211
  ? ''
173
212
  : `
174
- watchSchema: {
175
- url: '${apiUrl}',
176
- },
213
+ url: import.meta.env.VITE_API_URL ?? '${apiUrl}',
177
214
  `
178
215
 
179
216
  copy(
@@ -183,6 +220,8 @@ copy(
183
220
  API_URL: apiUrl,
184
221
  PROJECT_NAME: projectName,
185
222
  HOUDINI_VERSION: houdiniVersion,
223
+ HOUDINI_REACT_VERSION: houdiniReactVersion,
224
+ HOUDINI_ADAPTER_VERSION: houdiniAdapterVersion,
186
225
  ["'CLIENT_CONFIG'"]: clientConfig,
187
226
  ["'CONFIG_FILE'"]: configFile,
188
227
  },
@@ -380,6 +419,59 @@ function extractHeadersStr(/** @type {string} */ str) {
380
419
  return obj
381
420
  }
382
421
 
422
+ async function pathInput({ message, initialValue = '', validate }) {
423
+ const { createInterface } = await import('node:readline')
424
+
425
+ function completer(line) {
426
+ const isTrailingSlash = line.endsWith('/')
427
+ const dir = isTrailingSlash ? line || '.' : path.dirname(line) || '.'
428
+ const base = isTrailingSlash ? '' : path.basename(line)
429
+ let hits = []
430
+ try {
431
+ hits = fs
432
+ .readdirSync(dir)
433
+ .filter((e) => e.startsWith(base))
434
+ .map((e) => {
435
+ const full = path.join(dir, e)
436
+ try {
437
+ return fs.statSync(full).isDirectory() ? full + '/' : full
438
+ } catch {
439
+ return full
440
+ }
441
+ })
442
+ } catch {}
443
+ return [hits, line]
444
+ }
445
+
446
+ process.stdout.write(`\n${gray('◆')} ${message}\n`)
447
+
448
+ for (;;) {
449
+ const answer = await new Promise((resolve) => {
450
+ const rl = createInterface({ input: process.stdin, output: process.stdout, completer })
451
+ rl.setPrompt(`${gray('│')} `)
452
+ rl.prompt()
453
+ rl.once('line', (v) => {
454
+ rl.close()
455
+ resolve(v.trim() || initialValue)
456
+ })
457
+ rl.on('SIGINT', () => {
458
+ rl.close()
459
+ resolve(null)
460
+ })
461
+ })
462
+
463
+ if (answer === null) return null
464
+ if (validate) {
465
+ const err = validate(answer)
466
+ if (err) {
467
+ process.stdout.write(`${gray('▲')} ${err}\n`)
468
+ continue
469
+ }
470
+ }
471
+ return answer
472
+ }
473
+ }
474
+
383
475
  function pCancel(cancelText = 'Operation cancelled.') {
384
476
  p.cancel(cancelText)
385
477
  process.exit(1)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-houdini",
3
- "version": "2.0.0-next.9",
3
+ "version": "2.0.0",
4
4
  "description": "A CLI for creating new Houdini projects",
5
5
  "repository": {
6
6
  "type": "git",
@@ -8,16 +8,15 @@
8
8
  },
9
9
  "license": "MIT",
10
10
  "homepage": "https://houdinigraphql.com/",
11
- "bin": "./bin.js",
12
11
  "dependencies": {
13
- "@clack/prompts": "^0.6.3",
14
- "commander": "^9.4.0",
15
- "graphql": "16.8.0",
12
+ "@clack/prompts": "^1.5.1",
13
+ "commander": "^15.0.0",
14
+ "graphql": "16.14.1",
16
15
  "kleur": "^4.1.5"
17
16
  },
18
17
  "devDependencies": {
19
- "@types/node": "^22.13.1",
20
- "prettier": "^2.8.3"
18
+ "@types/node": "^25.9.1",
19
+ "prettier": "^3.8.3"
21
20
  },
22
21
  "files": [
23
22
  "fragments",
@@ -33,5 +32,8 @@
33
32
  "check": "tsc",
34
33
  "lint": "prettier --check . --config ../../.prettierrc --ignore-path ../../.gitignore --ignore-path .gitignore --plugin prettier-plugin-svelte --plugin-search-dir=.",
35
34
  "format": "pnpm lint --write"
35
+ },
36
+ "bin": {
37
+ "create-houdini": "./bin.js"
36
38
  }
37
39
  }
@@ -1,8 +1,8 @@
1
1
  projects:
2
2
  default:
3
3
  schema:
4
- - ./$houdini/graphql/schema.graphql
4
+ - .houdini/graphql/schema.graphql
5
5
  documents:
6
6
  - '**/*.gql'
7
7
  - '**/*.jsx'
8
- - ./$houdini/graphql/documents.gql
8
+ - .houdini/graphql/documents.gql
@@ -16,7 +16,7 @@ dist
16
16
  dist-ssr
17
17
  *.local
18
18
 
19
- ./$houdini
19
+ .houdini
20
20
  ./dist
21
21
 
22
22
  # Editor directories and files
@@ -10,20 +10,20 @@
10
10
  },
11
11
  "dependencies": {
12
12
  "houdini": "^HOUDINI_VERSION",
13
- "houdini-react": "^HOUDINI_VERSION",
14
- "houdini-adapter-auto": "^HOUDINI_VERSION",
13
+ "houdini-react": "^HOUDINI_REACT_VERSION",
14
+ "houdini-adapter-auto": "^HOUDINI_ADAPTER_VERSION",
15
15
  "react": "^19.0.0",
16
16
  "react-dom": "^19.0.0",
17
- "graphql-yoga": "4.0.4",
18
- "graphql": "15.8.0",
19
- "@whatwg-node/server": "^0.9.14"
17
+ "graphql-yoga": "^5.21.1",
18
+ "graphql": "^16.0.0",
19
+ "@whatwg-node/server": "^0.11.0"
20
20
  },
21
21
  "devDependencies": {
22
- "@vitejs/plugin-react": "^4.0.0",
23
- "vite": "^4.1.0"
22
+ "@vitejs/plugin-react": "^6.0.2",
23
+ "vite": "^8.0.0"
24
24
  },
25
25
  "resolutions": {
26
- "graphql": "15.8.0",
26
+ "graphql": "^16.0.0",
27
27
  "react": "^19.0.0",
28
28
  "react-dom": "^19.0.0"
29
29
  }
@@ -1,8 +1,8 @@
1
1
  projects:
2
2
  default:
3
3
  schema:
4
- - ./$houdini/graphql/schema.graphql
4
+ - .houdini/graphql/schema.graphql
5
5
  documents:
6
6
  - '**/*.gql'
7
7
  - '**/*.tsx'
8
- - ./$houdini/graphql/documents.gql
8
+ - .houdini/graphql/documents.gql
@@ -16,7 +16,7 @@ node_modules
16
16
  dist
17
17
  dist-ssr
18
18
  *.local
19
- $houdini
19
+ .houdini
20
20
 
21
21
  # Editor directories and files
22
22
  .vscode/*
@@ -10,23 +10,23 @@
10
10
  },
11
11
  "dependencies": {
12
12
  "houdini": "^HOUDINI_VERSION",
13
- "houdini-react": "^HOUDINI_VERSION",
14
- "houdini-adapter-auto": "^HOUDINI_VERSION",
13
+ "houdini-react": "^HOUDINI_REACT_VERSION",
14
+ "houdini-adapter-auto": "^HOUDINI_ADAPTER_VERSION",
15
15
  "react": "^19.0.0",
16
16
  "react-dom": "^19.0.0",
17
- "graphql-yoga": "4.0.4",
18
- "graphql": "15.8.0",
19
- "@whatwg-node/server": "^0.9.14"
17
+ "graphql-yoga": "^5.21.1",
18
+ "graphql": "^16.0.0",
19
+ "@whatwg-node/server": "^0.11.0"
20
20
  },
21
21
  "devDependencies": {
22
22
  "@types/react": "^19.0.7",
23
23
  "@types/react-dom": "^19.0.3",
24
- "@vitejs/plugin-react": "^4.0.0",
25
- "typescript": "^5.9.3",
26
- "vite": "^4.1.0"
24
+ "@vitejs/plugin-react": "^6.0.2",
25
+ "typescript": "^6.0.0",
26
+ "vite": "^8.0.0"
27
27
  },
28
28
  "resolutions": {
29
- "graphql": "15.8.0",
29
+ "graphql": "^16.0.0",
30
30
  "react": "^19.0.0",
31
31
  "react-dom": "^19.0.0"
32
32
  }