nuxt-openapi-hyperfetch 0.3.6-beta → 0.3.8-beta

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.
@@ -38,6 +38,11 @@ function buildImports(resource, composablesRelDir, sdkRelDir, runtimeRelDir) {
38
38
  // zod
39
39
  lines.push(`import { z } from 'zod';`);
40
40
  lines.push('');
41
+ // Vue — computed needed for the detail connector wrapper
42
+ if (resource.detailEndpoint) {
43
+ lines.push(`import { computed } from 'vue';`);
44
+ lines.push('');
45
+ }
41
46
  // connector-types — structural interfaces for return types
42
47
  const connectorTypeImports = ['ListConnectorReturn'];
43
48
  if (resource.detailEndpoint) {
@@ -238,7 +243,10 @@ function buildFunctionBody(resource) {
238
243
  }
239
244
  if (resource.detailEndpoint) {
240
245
  const fn = toAsyncDataName(resource.detailEndpoint.operationId);
241
- subConnectors.push(` const detail = useDetailConnector(${fn}) as unknown as DetailConnectorReturn<${pascal}>;`);
246
+ // Wrap the composable to map the generic idRef to the actual path param name.
247
+ // useDetailConnector passes a ref<id> and calls refresh() after updating it.
248
+ const pathParam = resource.detailEndpoint.pathParams[0] ?? 'id';
249
+ subConnectors.push(` const detail = useDetailConnector(`, ` (idRef, opts) => ${fn}(computed(() => ({ ${pathParam}: idRef.value })) as any, opts),`, ` ) as unknown as DetailConnectorReturn<${pascal}>;`);
242
250
  }
243
251
  if (resource.createEndpoint) {
244
252
  const fn = toAsyncDataName(resource.createEndpoint.operationId);
@@ -10,5 +10,5 @@ export declare function useDetailConnector(composableFn: any, options?: {}): {
10
10
  load: (id: any) => Promise<void>;
11
11
  clear: () => void;
12
12
  _composable: any;
13
- _currentId: any;
13
+ _idRef: any;
14
14
  };
@@ -16,23 +16,32 @@ import { ref, computed } from 'vue';
16
16
  */
17
17
  export function useDetailConnector(composableFn, options = {}) {
18
18
  const { fields = [] } = options;
19
- // The item ID to load reactive. null = not loaded yet.
20
- const currentId = ref(null);
21
- // ── Execute the underlying composable lazily (only when currentId changes)
22
- // We call the composable with lazy: true so it doesn't auto-fetch on mount.
23
- // load(id) sets currentId which triggers the watch inside the composable.
24
- const composable = composableFn(computed(() => (currentId.value !== null ? { id: currentId.value } : null)), { lazy: true, immediate: false });
19
+ // ── Reactive ID ref passed to the composable wrapper ──────────────────────
20
+ // The generated connector wraps the composable like:
21
+ // (idRef, opts) => useAsyncDataGetPetById(computed(() => ({ petId: idRef.value })), opts)
22
+ // This lets us update idRef.value in load(id) so refresh() picks up the new value.
23
+ const idRef = ref(null);
24
+ // ── Execute the underlying composable ──────────────────────────────────────
25
+ // watch: false + immediate: false + lazy: true prevent any fetch until
26
+ // load(id) is called explicitly. The URL is only evaluated on refresh().
27
+ const composable = composableFn(idRef, {
28
+ watch: false,
29
+ immediate: false,
30
+ lazy: true,
31
+ });
25
32
  // ── Derived state ──────────────────────────────────────────────────────────
26
33
  const item = computed(() => composable.data?.value ?? null);
27
34
  const loading = computed(() => composable.pending?.value ?? false);
28
35
  const error = computed(() => composable.error?.value ?? null);
29
36
  // ── Actions ────────────────────────────────────────────────────────────────
30
37
  async function load(id) {
31
- currentId.value = id;
38
+ idRef.value = id;
32
39
  await composable.refresh?.();
33
40
  }
34
41
  function clear() {
35
- currentId.value = null;
42
+ idRef.value = null;
43
+ if (composable.data)
44
+ composable.data.value = null;
36
45
  }
37
46
  return {
38
47
  // State
@@ -43,8 +52,8 @@ export function useDetailConnector(composableFn, options = {}) {
43
52
  // Actions
44
53
  load,
45
54
  clear,
46
- // Expose composable for advanced use (e.g. useFormConnector loadWith)
55
+ // Expose composable for advanced use
47
56
  _composable: composable,
48
- _currentId: currentId,
57
+ _idRef: idRef,
49
58
  };
50
59
  }
package/dist/index.js CHANGED
@@ -216,7 +216,7 @@ program
216
216
  await generateConnectors({
217
217
  inputSpec: inputPath,
218
218
  outputDir: `${composablesOutputDir}/connectors`,
219
- composablesRelDir: '../use-async-data',
219
+ composablesRelDir: '../use-async-data/composables',
220
220
  runtimeRelDir: '../../runtime',
221
221
  });
222
222
  spinner.stop('✓ Generated headless UI connectors');
@@ -73,7 +73,7 @@ export default defineNuxtModule({
73
73
  await generateConnectors({
74
74
  inputSpec: resolvedInput,
75
75
  outputDir: connectorsOutputDir,
76
- composablesRelDir: '../use-async-data',
76
+ composablesRelDir: '../use-async-data/composables',
77
77
  runtimeRelDir: '../../runtime',
78
78
  }, logger);
79
79
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-openapi-hyperfetch",
3
- "version": "0.3.6-beta",
3
+ "version": "0.3.8-beta",
4
4
  "description": "Nuxt useFetch, useAsyncData and Nuxt server OpenAPI generator",
5
5
  "type": "module",
6
6
  "author": "",
@@ -48,6 +48,12 @@ function buildImports(resource: ResourceInfo, composablesRelDir: string, sdkRelD
48
48
  lines.push(`import { z } from 'zod';`);
49
49
  lines.push('');
50
50
 
51
+ // Vue — computed needed for the detail connector wrapper
52
+ if (resource.detailEndpoint) {
53
+ lines.push(`import { computed } from 'vue';`);
54
+ lines.push('');
55
+ }
56
+
51
57
  // connector-types — structural interfaces for return types
52
58
  const connectorTypeImports: string[] = ['ListConnectorReturn'];
53
59
  if (resource.detailEndpoint) {
@@ -283,7 +289,14 @@ function buildFunctionBody(resource: ResourceInfo): string {
283
289
 
284
290
  if (resource.detailEndpoint) {
285
291
  const fn = toAsyncDataName(resource.detailEndpoint.operationId);
286
- subConnectors.push(` const detail = useDetailConnector(${fn}) as unknown as DetailConnectorReturn<${pascal}>;`);
292
+ // Wrap the composable to map the generic idRef to the actual path param name.
293
+ // useDetailConnector passes a ref<id> and calls refresh() after updating it.
294
+ const pathParam = resource.detailEndpoint.pathParams[0] ?? 'id';
295
+ subConnectors.push(
296
+ ` const detail = useDetailConnector(`,
297
+ ` (idRef, opts) => ${fn}(computed(() => ({ ${pathParam}: idRef.value })) as any, opts),`,
298
+ ` ) as unknown as DetailConnectorReturn<${pascal}>;`
299
+ );
287
300
  }
288
301
 
289
302
  if (resource.createEndpoint) {
@@ -18,16 +18,20 @@ import { ref, computed } from 'vue';
18
18
  export function useDetailConnector(composableFn, options = {}) {
19
19
  const { fields = [] } = options;
20
20
 
21
- // The item ID to load reactive. null = not loaded yet.
22
- const currentId = ref(null);
21
+ // ── Reactive ID ref passed to the composable wrapper ──────────────────────
22
+ // The generated connector wraps the composable like:
23
+ // (idRef, opts) => useAsyncDataGetPetById(computed(() => ({ petId: idRef.value })), opts)
24
+ // This lets us update idRef.value in load(id) so refresh() picks up the new value.
25
+ const idRef = ref(null);
23
26
 
24
- // ── Execute the underlying composable lazily (only when currentId changes) ─
25
- // We call the composable with lazy: true so it doesn't auto-fetch on mount.
26
- // load(id) sets currentId which triggers the watch inside the composable.
27
- const composable = composableFn(
28
- computed(() => (currentId.value !== null ? { id: currentId.value } : null)),
29
- { lazy: true, immediate: false }
30
- );
27
+ // ── Execute the underlying composable ──────────────────────────────────────
28
+ // watch: false + immediate: false + lazy: true prevent any fetch until
29
+ // load(id) is called explicitly. The URL is only evaluated on refresh().
30
+ const composable = composableFn(idRef, {
31
+ watch: false,
32
+ immediate: false,
33
+ lazy: true,
34
+ });
31
35
 
32
36
  // ── Derived state ──────────────────────────────────────────────────────────
33
37
 
@@ -38,12 +42,13 @@ export function useDetailConnector(composableFn, options = {}) {
38
42
  // ── Actions ────────────────────────────────────────────────────────────────
39
43
 
40
44
  async function load(id) {
41
- currentId.value = id;
45
+ idRef.value = id;
42
46
  await composable.refresh?.();
43
47
  }
44
48
 
45
49
  function clear() {
46
- currentId.value = null;
50
+ idRef.value = null;
51
+ if (composable.data) composable.data.value = null;
47
52
  }
48
53
 
49
54
  return {
@@ -57,8 +62,8 @@ export function useDetailConnector(composableFn, options = {}) {
57
62
  load,
58
63
  clear,
59
64
 
60
- // Expose composable for advanced use (e.g. useFormConnector loadWith)
65
+ // Expose composable for advanced use
61
66
  _composable: composable,
62
- _currentId: currentId,
67
+ _idRef: idRef,
63
68
  };
64
69
  }
package/src/index.ts CHANGED
@@ -276,7 +276,7 @@ program
276
276
  await generateConnectors({
277
277
  inputSpec: inputPath,
278
278
  outputDir: `${composablesOutputDir}/connectors`,
279
- composablesRelDir: '../use-async-data',
279
+ composablesRelDir: '../use-async-data/composables',
280
280
  runtimeRelDir: '../../runtime',
281
281
  });
282
282
  spinner.stop('✓ Generated headless UI connectors');
@@ -112,7 +112,7 @@ export default defineNuxtModule<ModuleOptions>({
112
112
  {
113
113
  inputSpec: resolvedInput,
114
114
  outputDir: connectorsOutputDir,
115
- composablesRelDir: '../use-async-data',
115
+ composablesRelDir: '../use-async-data/composables',
116
116
  runtimeRelDir: '../../runtime',
117
117
  },
118
118
  logger