nuxt-openapi-hyperfetch 0.1.6-alpha.1 → 0.2.7-alpha.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 (97) hide show
  1. package/CONTRIBUTING.md +291 -292
  2. package/INSTRUCTIONS.md +327 -327
  3. package/LICENSE +202 -202
  4. package/README.md +231 -227
  5. package/dist/cli/logger.d.ts +26 -0
  6. package/dist/cli/logger.js +36 -0
  7. package/dist/cli/logo.js +6 -6
  8. package/dist/generators/components/connector-generator/generator.d.ts +12 -0
  9. package/dist/generators/components/connector-generator/generator.js +116 -0
  10. package/dist/generators/components/connector-generator/templates.d.ts +18 -0
  11. package/dist/generators/components/connector-generator/templates.js +222 -0
  12. package/dist/generators/components/connector-generator/types.d.ts +32 -0
  13. package/dist/generators/components/connector-generator/types.js +7 -0
  14. package/dist/generators/components/schema-analyzer/index.d.ts +17 -0
  15. package/dist/generators/components/schema-analyzer/index.js +20 -0
  16. package/dist/generators/components/schema-analyzer/intent-detector.d.ts +17 -0
  17. package/dist/generators/components/schema-analyzer/intent-detector.js +143 -0
  18. package/dist/generators/components/schema-analyzer/openapi-reader.d.ts +11 -0
  19. package/dist/generators/components/schema-analyzer/openapi-reader.js +76 -0
  20. package/dist/generators/components/schema-analyzer/resource-grouper.d.ts +6 -0
  21. package/dist/generators/components/schema-analyzer/resource-grouper.js +132 -0
  22. package/dist/generators/components/schema-analyzer/schema-field-mapper.d.ts +35 -0
  23. package/dist/generators/components/schema-analyzer/schema-field-mapper.js +220 -0
  24. package/dist/generators/components/schema-analyzer/types.d.ts +156 -0
  25. package/dist/generators/components/schema-analyzer/types.js +7 -0
  26. package/dist/generators/nuxt-server/generator.d.ts +2 -1
  27. package/dist/generators/nuxt-server/generator.js +21 -21
  28. package/dist/generators/shared/runtime/apiHelpers.d.ts +98 -41
  29. package/dist/generators/shared/runtime/apiHelpers.js +97 -104
  30. package/dist/generators/shared/runtime/pagination.d.ts +168 -0
  31. package/dist/generators/shared/runtime/pagination.js +179 -0
  32. package/dist/generators/shared/runtime/useDeleteConnector.d.ts +16 -0
  33. package/dist/generators/shared/runtime/useDeleteConnector.js +93 -0
  34. package/dist/generators/shared/runtime/useDetailConnector.d.ts +14 -0
  35. package/dist/generators/shared/runtime/useDetailConnector.js +50 -0
  36. package/dist/generators/shared/runtime/useFormConnector.d.ts +19 -0
  37. package/dist/generators/shared/runtime/useFormConnector.js +113 -0
  38. package/dist/generators/shared/runtime/useListConnector.d.ts +25 -0
  39. package/dist/generators/shared/runtime/useListConnector.js +125 -0
  40. package/dist/generators/shared/runtime/zod-error-merger.d.ts +23 -0
  41. package/dist/generators/shared/runtime/zod-error-merger.js +106 -0
  42. package/dist/generators/shared/templates/api-callbacks-plugin.js +54 -11
  43. package/dist/generators/shared/templates/api-pagination-plugin.d.ts +51 -0
  44. package/dist/generators/shared/templates/api-pagination-plugin.js +152 -0
  45. package/dist/generators/use-async-data/generator.d.ts +2 -1
  46. package/dist/generators/use-async-data/generator.js +14 -14
  47. package/dist/generators/use-async-data/runtime/useApiAsyncData.js +130 -17
  48. package/dist/generators/use-async-data/runtime/useApiAsyncDataRaw.js +103 -13
  49. package/dist/generators/use-async-data/templates.js +20 -14
  50. package/dist/generators/use-fetch/generator.d.ts +2 -1
  51. package/dist/generators/use-fetch/generator.js +12 -12
  52. package/dist/generators/use-fetch/runtime/useApiRequest.js +149 -40
  53. package/dist/generators/use-fetch/templates.js +14 -14
  54. package/dist/index.js +25 -0
  55. package/dist/module/index.d.ts +4 -0
  56. package/dist/module/index.js +93 -0
  57. package/dist/module/types.d.ts +27 -0
  58. package/dist/module/types.js +1 -0
  59. package/docs/API-REFERENCE.md +886 -887
  60. package/docs/generated-components.md +615 -0
  61. package/docs/headless-composables-ui.md +569 -0
  62. package/eslint.config.js +13 -0
  63. package/package.json +29 -2
  64. package/src/cli/config.ts +140 -140
  65. package/src/cli/logger.ts +124 -66
  66. package/src/cli/logo.ts +25 -25
  67. package/src/cli/types.ts +50 -50
  68. package/src/generators/components/connector-generator/generator.ts +138 -0
  69. package/src/generators/components/connector-generator/templates.ts +254 -0
  70. package/src/generators/components/connector-generator/types.ts +34 -0
  71. package/src/generators/components/schema-analyzer/index.ts +44 -0
  72. package/src/generators/components/schema-analyzer/intent-detector.ts +187 -0
  73. package/src/generators/components/schema-analyzer/openapi-reader.ts +96 -0
  74. package/src/generators/components/schema-analyzer/resource-grouper.ts +166 -0
  75. package/src/generators/components/schema-analyzer/schema-field-mapper.ts +268 -0
  76. package/src/generators/components/schema-analyzer/types.ts +177 -0
  77. package/src/generators/nuxt-server/generator.ts +272 -270
  78. package/src/generators/shared/runtime/apiHelpers.ts +535 -481
  79. package/src/generators/shared/runtime/pagination.ts +323 -0
  80. package/src/generators/shared/runtime/useDeleteConnector.ts +109 -0
  81. package/src/generators/shared/runtime/useDetailConnector.ts +64 -0
  82. package/src/generators/shared/runtime/useFormConnector.ts +139 -0
  83. package/src/generators/shared/runtime/useListConnector.ts +148 -0
  84. package/src/generators/shared/runtime/zod-error-merger.ts +119 -0
  85. package/src/generators/shared/templates/api-callbacks-plugin.ts +399 -352
  86. package/src/generators/shared/templates/api-pagination-plugin.ts +158 -0
  87. package/src/generators/use-async-data/generator.ts +205 -204
  88. package/src/generators/use-async-data/runtime/useApiAsyncData.ts +329 -214
  89. package/src/generators/use-async-data/runtime/useApiAsyncDataRaw.ts +324 -230
  90. package/src/generators/use-async-data/templates.ts +257 -250
  91. package/src/generators/use-fetch/generator.ts +170 -169
  92. package/src/generators/use-fetch/runtime/useApiRequest.ts +354 -234
  93. package/src/generators/use-fetch/templates.ts +214 -214
  94. package/src/index.ts +303 -265
  95. package/src/module/index.ts +133 -0
  96. package/src/module/types.ts +31 -0
  97. package/src/generators/tanstack-query/generator.ts +0 -11
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Pagination Helpers - Used by both useFetch and useAsyncData wrappers
3
+ * Handles global pagination config, request param injection, and response meta extraction.
4
+ */
5
+ /**
6
+ * Describes how to read pagination metadata from the backend response.
7
+ *
8
+ * - `metaSource: 'headers'` — metadata comes from HTTP response headers
9
+ * - `metaSource: 'body'` — metadata is nested inside the response JSON
10
+ */
11
+ export interface PaginationMetaConfig {
12
+ /**
13
+ * Where to read pagination metadata from.
14
+ * - 'headers': from HTTP response headers (requires raw fetch)
15
+ * - 'body': from the response JSON body (default)
16
+ */
17
+ metaSource: 'headers' | 'body';
18
+ /**
19
+ * Field names (header names or dot-notation body paths) for each pagination value.
20
+ *
21
+ * Examples for headers: 'X-Total-Count', 'X-Total-Pages', 'X-Page', 'X-Per-Page'
22
+ * Examples for body: 'meta.total', 'pagination.totalPages', 'page', 'perPage'
23
+ */
24
+ fields: {
25
+ /** Total number of items across all pages */
26
+ total: string;
27
+ /** Total number of pages */
28
+ totalPages: string;
29
+ /** Current page number */
30
+ currentPage: string;
31
+ /** Number of items per page */
32
+ perPage: string;
33
+ /**
34
+ * If the actual data array lives inside a nested key (e.g. response.data),
35
+ * set this to that key name so the composable unwraps it automatically.
36
+ * Leave undefined if the response root IS the array.
37
+ */
38
+ dataKey?: string;
39
+ };
40
+ }
41
+ /**
42
+ * Describes how to send pagination parameters to the backend.
43
+ */
44
+ export interface PaginationRequestConfig {
45
+ /**
46
+ * Where to attach the pagination parameters.
47
+ * - 'query': as URL query string params (GET default, recommended)
48
+ * - 'body': merged into request body JSON (for POST-as-search APIs)
49
+ * - 'headers': as request headers
50
+ */
51
+ sendAs: 'query' | 'body' | 'headers';
52
+ /**
53
+ * Mapping from our internal names to your backend's parameter names.
54
+ * @example { page: 'page', perPage: 'limit' } // ?page=1&limit=20
55
+ * @example { page: 'p', perPage: 'per_page' } // ?p=1&per_page=20
56
+ * @example { page: 'offset', perPage: 'count' } // ?offset=1&count=20
57
+ */
58
+ params: {
59
+ page: string;
60
+ perPage: string;
61
+ };
62
+ /** Default values applied when none are passed by the composable caller */
63
+ defaults: {
64
+ page: number;
65
+ perPage: number;
66
+ };
67
+ }
68
+ /**
69
+ * Full pagination configuration object.
70
+ * Combine `meta` (how to read the response) and `request` (how to send params).
71
+ *
72
+ * @example
73
+ * // Headers-based API (e.g. many REST frameworks)
74
+ * {
75
+ * meta: {
76
+ * metaSource: 'headers',
77
+ * fields: { total: 'X-Total-Count', totalPages: 'X-Total-Pages', currentPage: 'X-Page', perPage: 'X-Per-Page' }
78
+ * },
79
+ * request: {
80
+ * sendAs: 'query',
81
+ * params: { page: 'page', perPage: 'limit' },
82
+ * defaults: { page: 1, perPage: 20 }
83
+ * }
84
+ * }
85
+ *
86
+ * @example
87
+ * // Body-based API (e.g. Laravel paginate())
88
+ * {
89
+ * meta: {
90
+ * metaSource: 'body',
91
+ * fields: { total: 'meta.total', totalPages: 'meta.last_page', currentPage: 'meta.current_page', perPage: 'meta.per_page', dataKey: 'data' }
92
+ * },
93
+ * request: {
94
+ * sendAs: 'query',
95
+ * params: { page: 'page', perPage: 'per_page' },
96
+ * defaults: { page: 1, perPage: 15 }
97
+ * }
98
+ * }
99
+ */
100
+ export interface PaginationConfig {
101
+ meta: PaginationMetaConfig;
102
+ request: PaginationRequestConfig;
103
+ }
104
+ /**
105
+ * Reactive pagination state exposed to the composable caller.
106
+ */
107
+ export interface PaginationState {
108
+ /** Current page number (reactive) */
109
+ currentPage: number;
110
+ /** Total pages as reported by the backend (reactive) */
111
+ totalPages: number;
112
+ /** Total item count as reported by the backend (reactive) */
113
+ total: number;
114
+ /** Current page size (reactive) */
115
+ perPage: number;
116
+ }
117
+ /**
118
+ * Register the global pagination configuration.
119
+ * Call this from your Nuxt plugin (plugins/api-pagination.ts).
120
+ *
121
+ * @example
122
+ * export default defineNuxtPlugin(() => {
123
+ * provide('setGlobalApiPagination', setGlobalApiPagination);
124
+ * setGlobalApiPagination({ meta: { ... }, request: { ... } });
125
+ * })
126
+ */
127
+ export declare function setGlobalApiPagination(config: PaginationConfig): void;
128
+ /**
129
+ * Retrieve the global pagination configuration, falling back to built-in defaults.
130
+ * Called internally by the runtime wrappers.
131
+ */
132
+ export declare function getGlobalApiPagination(): PaginationConfig;
133
+ /**
134
+ * Build the pagination parameters to inject into the outgoing request.
135
+ *
136
+ * Returns an object with at most one of: `query`, `body`, or `headers` populated,
137
+ * depending on `config.request.sendAs`.
138
+ */
139
+ export declare function buildPaginationRequest(page: number, perPage: number, config: PaginationConfig): {
140
+ query?: Record<string, any>;
141
+ body?: Record<string, any>;
142
+ headers?: Record<string, string>;
143
+ };
144
+ /**
145
+ * Extract pagination metadata from a **body** response.
146
+ *
147
+ * @param responseData - The raw JSON returned by the backend
148
+ * @param config - Active pagination config
149
+ * @returns Partial pagination state (only fields that were found)
150
+ */
151
+ export declare function extractPaginationMetaFromBody(responseData: any, config: PaginationConfig): Partial<PaginationState>;
152
+ /**
153
+ * Extract pagination metadata from HTTP **response headers**.
154
+ *
155
+ * @param headers - The `Headers` object from the fetch response
156
+ * @param config - Active pagination config
157
+ * @returns Partial pagination state (only fields that were found)
158
+ */
159
+ export declare function extractPaginationMetaFromHeaders(headers: Headers, config: PaginationConfig): Partial<PaginationState>;
160
+ /**
161
+ * If `config.meta.fields.dataKey` is set, unwrap the actual data array from the body.
162
+ * Otherwise return the body as-is.
163
+ *
164
+ * @example
165
+ * // Laravel paginate() response: { data: [...], meta: { total: 100, ... } }
166
+ * unwrapDataKey(response, config) // → response.data
167
+ */
168
+ export declare function unwrapDataKey<T>(responseData: any, config: PaginationConfig): T;
@@ -0,0 +1,179 @@
1
+ // @ts-nocheck - This file runs in user's Nuxt project with different TypeScript config
2
+ /**
3
+ * Pagination Helpers - Used by both useFetch and useAsyncData wrappers
4
+ * Handles global pagination config, request param injection, and response meta extraction.
5
+ */
6
+ // ---------------------------------------------------------------------------
7
+ // Internal defaults
8
+ // ---------------------------------------------------------------------------
9
+ const DEFAULT_PAGINATION_CONFIG = {
10
+ meta: {
11
+ metaSource: 'body',
12
+ fields: {
13
+ total: 'total',
14
+ totalPages: 'totalPages',
15
+ currentPage: 'currentPage',
16
+ perPage: 'perPage',
17
+ },
18
+ },
19
+ request: {
20
+ sendAs: 'query',
21
+ params: { page: 'page', perPage: 'perPage' },
22
+ defaults: { page: 1, perPage: 20 },
23
+ },
24
+ };
25
+ // ---------------------------------------------------------------------------
26
+ // Global config store
27
+ // ---------------------------------------------------------------------------
28
+ let _globalPaginationConfig = null;
29
+ /**
30
+ * Register the global pagination configuration.
31
+ * Call this from your Nuxt plugin (plugins/api-pagination.ts).
32
+ *
33
+ * @example
34
+ * export default defineNuxtPlugin(() => {
35
+ * provide('setGlobalApiPagination', setGlobalApiPagination);
36
+ * setGlobalApiPagination({ meta: { ... }, request: { ... } });
37
+ * })
38
+ */
39
+ export function setGlobalApiPagination(config) {
40
+ _globalPaginationConfig = config;
41
+ }
42
+ /**
43
+ * Retrieve the global pagination configuration, falling back to built-in defaults.
44
+ * Called internally by the runtime wrappers.
45
+ */
46
+ export function getGlobalApiPagination() {
47
+ // Try Nuxt plugin provide first (runtime usage inside components)
48
+ try {
49
+ const nuxtApp = useNuxtApp();
50
+ // @ts-ignore
51
+ if (nuxtApp.$getGlobalApiPagination) {
52
+ // @ts-ignore
53
+ const config = nuxtApp.$getGlobalApiPagination();
54
+ if (config && typeof config === 'object')
55
+ return config;
56
+ }
57
+ }
58
+ catch {
59
+ // outside Nuxt context — fall through
60
+ }
61
+ // Then the module-level variable (set via setGlobalApiPagination)
62
+ if (_globalPaginationConfig)
63
+ return _globalPaginationConfig;
64
+ return DEFAULT_PAGINATION_CONFIG;
65
+ }
66
+ // ---------------------------------------------------------------------------
67
+ // Request helpers
68
+ // ---------------------------------------------------------------------------
69
+ /**
70
+ * Build the pagination parameters to inject into the outgoing request.
71
+ *
72
+ * Returns an object with at most one of: `query`, `body`, or `headers` populated,
73
+ * depending on `config.request.sendAs`.
74
+ */
75
+ export function buildPaginationRequest(page, perPage, config) {
76
+ const { sendAs, params } = config.request;
77
+ const payload = {
78
+ [params.page]: page,
79
+ [params.perPage]: perPage,
80
+ };
81
+ if (sendAs === 'query')
82
+ return { query: payload };
83
+ if (sendAs === 'body')
84
+ return { body: payload };
85
+ if (sendAs === 'headers') {
86
+ // Header values must be strings
87
+ return {
88
+ headers: {
89
+ [params.page]: String(page),
90
+ [params.perPage]: String(perPage),
91
+ },
92
+ };
93
+ }
94
+ return { query: payload };
95
+ }
96
+ // ---------------------------------------------------------------------------
97
+ // Response meta extraction helpers
98
+ // ---------------------------------------------------------------------------
99
+ /**
100
+ * Navigate a dot-notation path on a plain object.
101
+ * Returns `undefined` if any intermediate key is missing.
102
+ *
103
+ * @example resolveDotPath({ meta: { total: 42 } }, 'meta.total') // → 42
104
+ */
105
+ function resolveDotPath(obj, path) {
106
+ if (!obj || typeof obj !== 'object')
107
+ return undefined;
108
+ const keys = path.split('.');
109
+ let current = obj;
110
+ for (const key of keys) {
111
+ if (current == null || typeof current !== 'object')
112
+ return undefined;
113
+ current = current[key];
114
+ }
115
+ return current;
116
+ }
117
+ /**
118
+ * Extract pagination metadata from a **body** response.
119
+ *
120
+ * @param responseData - The raw JSON returned by the backend
121
+ * @param config - Active pagination config
122
+ * @returns Partial pagination state (only fields that were found)
123
+ */
124
+ export function extractPaginationMetaFromBody(responseData, config) {
125
+ const { fields } = config.meta;
126
+ const result = {};
127
+ const rawTotal = resolveDotPath(responseData, fields.total);
128
+ if (rawTotal !== undefined)
129
+ result.total = Number(rawTotal);
130
+ const rawTotalPages = resolveDotPath(responseData, fields.totalPages);
131
+ if (rawTotalPages !== undefined)
132
+ result.totalPages = Number(rawTotalPages);
133
+ const rawCurrentPage = resolveDotPath(responseData, fields.currentPage);
134
+ if (rawCurrentPage !== undefined)
135
+ result.currentPage = Number(rawCurrentPage);
136
+ const rawPerPage = resolveDotPath(responseData, fields.perPage);
137
+ if (rawPerPage !== undefined)
138
+ result.perPage = Number(rawPerPage);
139
+ return result;
140
+ }
141
+ /**
142
+ * Extract pagination metadata from HTTP **response headers**.
143
+ *
144
+ * @param headers - The `Headers` object from the fetch response
145
+ * @param config - Active pagination config
146
+ * @returns Partial pagination state (only fields that were found)
147
+ */
148
+ export function extractPaginationMetaFromHeaders(headers, config) {
149
+ const { fields } = config.meta;
150
+ const result = {};
151
+ const rawTotal = headers.get(fields.total);
152
+ if (rawTotal !== null)
153
+ result.total = Number(rawTotal);
154
+ const rawTotalPages = headers.get(fields.totalPages);
155
+ if (rawTotalPages !== null)
156
+ result.totalPages = Number(rawTotalPages);
157
+ const rawCurrentPage = headers.get(fields.currentPage);
158
+ if (rawCurrentPage !== null)
159
+ result.currentPage = Number(rawCurrentPage);
160
+ const rawPerPage = headers.get(fields.perPage);
161
+ if (rawPerPage !== null)
162
+ result.perPage = Number(rawPerPage);
163
+ return result;
164
+ }
165
+ /**
166
+ * If `config.meta.fields.dataKey` is set, unwrap the actual data array from the body.
167
+ * Otherwise return the body as-is.
168
+ *
169
+ * @example
170
+ * // Laravel paginate() response: { data: [...], meta: { total: 100, ... } }
171
+ * unwrapDataKey(response, config) // → response.data
172
+ */
173
+ export function unwrapDataKey(responseData, config) {
174
+ const key = config.meta.fields.dataKey;
175
+ if (key && responseData && typeof responseData === 'object' && key in responseData) {
176
+ return responseData[key];
177
+ }
178
+ return responseData;
179
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @param composableFn The generated delete composable, e.g. useAsyncDataDeletePet
3
+ * @param options Optional configuration
4
+ */
5
+ export declare function useDeleteConnector(composableFn: any, options?: {}): {
6
+ target: any;
7
+ isOpen: any;
8
+ loading: any;
9
+ error: any;
10
+ hasTarget: any;
11
+ onSuccess: any;
12
+ onError: any;
13
+ setTarget: (item: any) => void;
14
+ cancel: () => void;
15
+ confirm: () => Promise<void>;
16
+ };
@@ -0,0 +1,93 @@
1
+ // @ts-nocheck - This file runs in user's Nuxt project with different TypeScript config
2
+ /**
3
+ * useDeleteConnector — Runtime connector for DELETE endpoints.
4
+ *
5
+ * Manages:
6
+ * - The target item to delete (set from the table via openDelete)
7
+ * - Modal open/close state
8
+ * - Confirmation logic
9
+ * - Callbacks onSuccess / onError
10
+ *
11
+ * Copied to the user's project alongside the generated connectors.
12
+ */
13
+ import { ref, computed } from 'vue';
14
+ /**
15
+ * @param composableFn The generated delete composable, e.g. useAsyncDataDeletePet
16
+ * @param options Optional configuration
17
+ */
18
+ export function useDeleteConnector(composableFn, options = {}) {
19
+ // ── State ──────────────────────────────────────────────────────────────────
20
+ const target = ref(null);
21
+ const isOpen = ref(false);
22
+ const loading = ref(false);
23
+ const error = ref(null);
24
+ // Callbacks — set by the developer or the generated component
25
+ const onSuccess = ref(null);
26
+ const onError = ref(null);
27
+ // ── Actions ────────────────────────────────────────────────────────────────
28
+ /**
29
+ * Set the item to delete and open the confirmation modal.
30
+ * Called by useListConnector.openDelete(row).
31
+ */
32
+ function setTarget(item) {
33
+ target.value = item;
34
+ isOpen.value = true;
35
+ }
36
+ /**
37
+ * Cancel the delete operation — close modal and clear target.
38
+ */
39
+ function cancel() {
40
+ isOpen.value = false;
41
+ target.value = null;
42
+ error.value = null;
43
+ }
44
+ /**
45
+ * Confirm the delete — call the underlying composable with the target item.
46
+ */
47
+ async function confirm() {
48
+ if (!target.value) {
49
+ return;
50
+ }
51
+ loading.value = true;
52
+ error.value = null;
53
+ try {
54
+ // Pass the full target item; the generated composable extracts the id it needs
55
+ const composable = composableFn(target.value);
56
+ if (composable.execute) {
57
+ await composable.execute();
58
+ }
59
+ const err = composable.error?.value;
60
+ if (err) {
61
+ throw err;
62
+ }
63
+ const deletedItem = target.value;
64
+ isOpen.value = false;
65
+ target.value = null;
66
+ onSuccess.value?.(deletedItem);
67
+ }
68
+ catch (err) {
69
+ error.value = err;
70
+ onError.value?.(err);
71
+ }
72
+ finally {
73
+ loading.value = false;
74
+ }
75
+ }
76
+ // ── Derived ────────────────────────────────────────────────────────────────
77
+ const hasTarget = computed(() => target.value !== null);
78
+ return {
79
+ // State
80
+ target,
81
+ isOpen,
82
+ loading,
83
+ error,
84
+ hasTarget,
85
+ // Callbacks (developer-assignable)
86
+ onSuccess,
87
+ onError,
88
+ // Actions
89
+ setTarget,
90
+ cancel,
91
+ confirm,
92
+ };
93
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @param composableFn The generated useAsyncData composable, e.g. useAsyncDataGetPetById
3
+ * @param options Optional configuration
4
+ */
5
+ export declare function useDetailConnector(composableFn: any, options?: {}): {
6
+ item: any;
7
+ loading: any;
8
+ error: any;
9
+ fields: any;
10
+ load: (id: any) => Promise<void>;
11
+ clear: () => void;
12
+ _composable: any;
13
+ _currentId: any;
14
+ };
@@ -0,0 +1,50 @@
1
+ // @ts-nocheck - This file runs in user's Nuxt project with different TypeScript config
2
+ /**
3
+ * useDetailConnector — Runtime connector for single-item GET endpoints.
4
+ *
5
+ * Wraps a useAsyncData composable that returns a single object and exposes:
6
+ * - item, loading, error state
7
+ * - load(id) to fetch a specific item on demand
8
+ * - fields derived from the response (used by detail view components)
9
+ *
10
+ * Copied to the user's project alongside the generated connectors.
11
+ */
12
+ import { ref, computed } from 'vue';
13
+ /**
14
+ * @param composableFn The generated useAsyncData composable, e.g. useAsyncDataGetPetById
15
+ * @param options Optional configuration
16
+ */
17
+ export function useDetailConnector(composableFn, options = {}) {
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 });
25
+ // ── Derived state ──────────────────────────────────────────────────────────
26
+ const item = computed(() => composable.data?.value ?? null);
27
+ const loading = computed(() => composable.pending?.value ?? false);
28
+ const error = computed(() => composable.error?.value ?? null);
29
+ // ── Actions ────────────────────────────────────────────────────────────────
30
+ async function load(id) {
31
+ currentId.value = id;
32
+ await composable.refresh?.();
33
+ }
34
+ function clear() {
35
+ currentId.value = null;
36
+ }
37
+ return {
38
+ // State
39
+ item,
40
+ loading,
41
+ error,
42
+ fields: computed(() => fields),
43
+ // Actions
44
+ load,
45
+ clear,
46
+ // Expose composable for advanced use (e.g. useFormConnector loadWith)
47
+ _composable: composable,
48
+ _currentId: currentId,
49
+ };
50
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @param composableFn The generated mutation composable, e.g. useAsyncDataCreatePet
3
+ * @param options { schema, fields, loadWith?, errorConfig? }
4
+ */
5
+ export declare function useFormConnector(composableFn: any, options?: {}): {
6
+ model: any;
7
+ errors: any;
8
+ loading: any;
9
+ submitError: any;
10
+ submitted: any;
11
+ isValid: any;
12
+ hasErrors: any;
13
+ fields: any;
14
+ onSuccess: any;
15
+ onError: any;
16
+ submit: () => Promise<void>;
17
+ reset: () => void;
18
+ setValues: (data: any) => void;
19
+ };
@@ -0,0 +1,113 @@
1
+ // @ts-nocheck - This file runs in user's Nuxt project with different TypeScript config
2
+ /**
3
+ * useFormConnector — Runtime connector for create/update form endpoints.
4
+ *
5
+ * Responsibilities:
6
+ * - Hold the reactive form model
7
+ * - Validate with a Zod schema (generated at code-gen time) on submit
8
+ * - Merge Zod error messages with per-field overrides from config
9
+ * - Submit the validated data via the provided useAsyncData composable
10
+ * - Optionally pre-fill from a useDetailConnector (loadWith option)
11
+ *
12
+ * Copied to the user's project alongside the generated connectors.
13
+ */
14
+ import { ref, computed, watch } from 'vue';
15
+ import { mergeZodErrors } from './zod-error-merger.js';
16
+ /**
17
+ * @param composableFn The generated mutation composable, e.g. useAsyncDataCreatePet
18
+ * @param options { schema, fields, loadWith?, errorConfig? }
19
+ */
20
+ export function useFormConnector(composableFn, options = {}) {
21
+ const { schema, fields = [], loadWith = null, errorConfig = {} } = options;
22
+ // ── Form state ─────────────────────────────────────────────────────────────
23
+ const model = ref({});
24
+ const errors = ref({});
25
+ const loading = ref(false);
26
+ const submitError = ref(null);
27
+ const submitted = ref(false);
28
+ // Callbacks — set by the developer or the generated component
29
+ const onSuccess = ref(null);
30
+ const onError = ref(null);
31
+ // ── Pre-fill from detail connector ────────────────────────────────────────
32
+ if (loadWith) {
33
+ // When the detail item changes (e.g. user clicks "Edit"), pre-fill the model
34
+ watch(() => loadWith.item?.value, (newItem) => {
35
+ if (newItem) {
36
+ setValues(newItem);
37
+ }
38
+ }, { immediate: true });
39
+ }
40
+ // ── Actions ────────────────────────────────────────────────────────────────
41
+ function setValues(data) {
42
+ model.value = { ...model.value, ...data };
43
+ }
44
+ function reset() {
45
+ model.value = {};
46
+ errors.value = {};
47
+ submitError.value = null;
48
+ submitted.value = false;
49
+ }
50
+ async function submit() {
51
+ submitted.value = true;
52
+ // 1. Zod validation (if schema provided)
53
+ if (schema) {
54
+ const result = schema.safeParse(model.value);
55
+ if (!result.success) {
56
+ const fieldErrors = result.error.flatten().fieldErrors;
57
+ errors.value = mergeZodErrors(fieldErrors, errorConfig);
58
+ return;
59
+ }
60
+ // Clear previous errors on successful validation
61
+ errors.value = {};
62
+ }
63
+ // 2. Call the underlying composable
64
+ loading.value = true;
65
+ submitError.value = null;
66
+ try {
67
+ // The mutation composable accepts the model as its payload
68
+ const composable = composableFn(model.value);
69
+ // Wait for the async data to resolve
70
+ if (composable.execute) {
71
+ await composable.execute();
72
+ }
73
+ const data = composable.data?.value;
74
+ const err = composable.error?.value;
75
+ if (err) {
76
+ throw err;
77
+ }
78
+ onSuccess.value?.(data);
79
+ }
80
+ catch (err) {
81
+ submitError.value = err;
82
+ onError.value?.(err);
83
+ }
84
+ finally {
85
+ loading.value = false;
86
+ }
87
+ }
88
+ // ── Derived ────────────────────────────────────────────────────────────────
89
+ const isValid = computed(() => {
90
+ if (!schema)
91
+ return true;
92
+ return schema.safeParse(model.value).success;
93
+ });
94
+ const hasErrors = computed(() => Object.keys(errors.value).length > 0);
95
+ return {
96
+ // State
97
+ model,
98
+ errors,
99
+ loading,
100
+ submitError,
101
+ submitted,
102
+ isValid,
103
+ hasErrors,
104
+ fields: computed(() => fields),
105
+ // Callbacks (developer-assignable)
106
+ onSuccess,
107
+ onError,
108
+ // Actions
109
+ submit,
110
+ reset,
111
+ setValues,
112
+ };
113
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @param composableFn The generated useAsyncData composable, e.g. useAsyncDataGetPets
3
+ * @param options Configuration for the list connector
4
+ */
5
+ export declare function useListConnector(composableFn: any, options?: {}): {
6
+ rows: any;
7
+ columns: any;
8
+ loading: any;
9
+ error: any;
10
+ pagination: any;
11
+ goToPage: (page: any) => void;
12
+ nextPage: () => void;
13
+ prevPage: () => void;
14
+ setPerPage: (n: any) => void;
15
+ selected: any;
16
+ onRowSelect: (row: any) => void;
17
+ clearSelection: () => void;
18
+ refresh: () => void;
19
+ create: () => void;
20
+ update: (row: any) => void;
21
+ remove: (row: any) => void;
22
+ _createTrigger: any;
23
+ _updateTarget: any;
24
+ _deleteTarget: any;
25
+ };