create-houdini 2.0.0-next.8 → 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,6 +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 each package to its actual published version
20
+ // independently — packages can be at different versions across a release cycle
21
+ const distTag = version.includes('-') ? version.split('-')[1].split('.')[0] : 'latest'
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
+ }
31
+ }
32
+
33
+ const houdiniVersion = resolveVersion('houdini')
34
+ const houdiniReactVersion = resolveVersion('houdini-react')
35
+ const houdiniAdapterVersion = resolveVersion('houdini-adapter-auto')
36
+
19
37
  // prepare options
20
38
  const templatesDir = sourcePath(`./templates`)
21
39
  const options = fs.readdirSync(templatesDir).map((templateDir) => {
@@ -51,12 +69,11 @@ p.intro('🎩 Welcome to Houdini!')
51
69
 
52
70
  // if we weren't given a directory, then we should ask
53
71
  if (!projectDir) {
54
- const dir = await p.text({
72
+ const dir = await pathInput({
55
73
  message: `Where should we create your project?`,
56
- placeholder: ' (press Enter to use the current directory)',
57
74
  })
58
75
 
59
- if (p.isCancel(dir)) {
76
+ if (dir === null) {
60
77
  process.exit(1)
61
78
  }
62
79
 
@@ -130,13 +147,46 @@ let apiUrl = options_cli.schema?.startsWith('http') ? options_cli.schema : templ
130
147
  if (!localSchema) {
131
148
  let pullSchema_content = ''
132
149
  if (apiUrl === '') {
133
- const { apiUrl: apiUrlCli, pullSchema_content: pullSchema_content_cli } =
134
- await pullSchemaCli()
135
- apiUrl = apiUrlCli
136
- if (pullSchema_content_cli === null) {
137
- 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
+ }
138
165
  } else {
139
- 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'
140
190
  }
141
191
  } else {
142
192
  const pullSchema_content_local = await pullSchema(apiUrl, {})
@@ -147,22 +197,20 @@ if (!localSchema) {
147
197
  }
148
198
  }
149
199
 
150
- writeFileSync(path.join(projectDir, 'schema.graphql'), pullSchema_content)
200
+ if (pullSchema_content) {
201
+ writeFileSync(path.join(projectDir, 'schema.graphql'), pullSchema_content)
202
+ }
151
203
  }
152
204
 
153
- // the final client config depends on whether we have a local schema or not
154
- const clientConfig = localSchema
155
- ? ``
156
- : `{
157
- url: '${apiUrl}',
158
- }`
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 = ``
159
208
 
209
+ // a remote api sets the top-level `url` (watchSchema defaults to it), env-switched per build.
160
210
  const configFile = localSchema
161
211
  ? ''
162
212
  : `
163
- watchSchema: {
164
- url: '${apiUrl}',
165
- },
213
+ url: import.meta.env.VITE_API_URL ?? '${apiUrl}',
166
214
  `
167
215
 
168
216
  copy(
@@ -171,7 +219,9 @@ copy(
171
219
  {
172
220
  API_URL: apiUrl,
173
221
  PROJECT_NAME: projectName,
174
- HOUDINI_VERSION: version,
222
+ HOUDINI_VERSION: houdiniVersion,
223
+ HOUDINI_REACT_VERSION: houdiniReactVersion,
224
+ HOUDINI_ADAPTER_VERSION: houdiniAdapterVersion,
175
225
  ["'CLIENT_CONFIG'"]: clientConfig,
176
226
  ["'CONFIG_FILE'"]: configFile,
177
227
  },
@@ -369,6 +419,59 @@ function extractHeadersStr(/** @type {string} */ str) {
369
419
  return obj
370
420
  }
371
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
+
372
475
  function pCancel(cancelText = 'Operation cancelled.') {
373
476
  p.cancel(cancelText)
374
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.8",
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
  }