nuxt-openapi-hyperfetch 0.3.81-beta → 1.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/README.md +218 -212
- package/dist/generators/components/connector-generator/templates.js +67 -17
- package/dist/generators/components/schema-analyzer/intent-detector.js +1 -12
- package/dist/generators/components/schema-analyzer/openapi-reader.js +10 -1
- package/dist/generators/components/schema-analyzer/resource-grouper.js +7 -0
- package/dist/generators/components/schema-analyzer/schema-field-mapper.js +1 -22
- package/dist/generators/components/schema-analyzer/types.d.ts +10 -0
- package/dist/generators/connectors/generator.d.ts +12 -0
- package/dist/generators/connectors/generator.js +115 -0
- package/dist/generators/connectors/runtime/connector-types.d.ts +147 -0
- package/dist/generators/connectors/runtime/connector-types.js +10 -0
- package/dist/generators/connectors/runtime/useCreateConnector.d.ts +26 -0
- package/dist/generators/connectors/runtime/useCreateConnector.js +156 -0
- package/dist/generators/connectors/runtime/useDeleteConnector.d.ts +30 -0
- package/dist/generators/connectors/runtime/useDeleteConnector.js +143 -0
- package/dist/generators/connectors/runtime/useGetAllConnector.d.ts +25 -0
- package/dist/generators/connectors/runtime/useGetAllConnector.js +127 -0
- package/dist/generators/connectors/runtime/useGetConnector.d.ts +15 -0
- package/dist/generators/connectors/runtime/useGetConnector.js +99 -0
- package/dist/generators/connectors/runtime/useUpdateConnector.d.ts +34 -0
- package/dist/generators/connectors/runtime/useUpdateConnector.js +211 -0
- package/dist/generators/connectors/runtime/zod-error-merger.d.ts +23 -0
- package/dist/generators/connectors/runtime/zod-error-merger.js +106 -0
- package/dist/generators/connectors/templates.d.ts +4 -0
- package/dist/generators/connectors/templates.js +376 -0
- package/dist/generators/connectors/types.d.ts +37 -0
- package/dist/generators/connectors/types.js +7 -0
- package/dist/generators/shared/runtime/useDeleteConnector.js +4 -2
- package/dist/generators/shared/runtime/useDetailConnector.d.ts +0 -1
- package/dist/generators/shared/runtime/useDetailConnector.js +9 -20
- package/dist/generators/shared/runtime/useFormConnector.js +4 -3
- package/dist/generators/use-async-data/runtime/useApiAsyncData.js +14 -5
- package/dist/generators/use-async-data/templates.js +20 -16
- package/dist/generators/use-fetch/templates.js +1 -1
- package/dist/index.js +1 -16
- package/dist/module/index.js +2 -3
- package/package.json +4 -3
- package/src/cli/prompts.ts +1 -7
- package/src/generators/components/connector-generator/templates.ts +97 -22
- package/src/generators/components/schema-analyzer/intent-detector.ts +1 -16
- package/src/generators/components/schema-analyzer/openapi-reader.ts +14 -1
- package/src/generators/components/schema-analyzer/resource-grouper.ts +9 -0
- package/src/generators/components/schema-analyzer/schema-field-mapper.ts +1 -26
- package/src/generators/components/schema-analyzer/types.ts +11 -0
- package/src/generators/connectors/generator.ts +137 -0
- package/src/generators/connectors/runtime/connector-types.ts +207 -0
- package/src/generators/connectors/runtime/useCreateConnector.ts +199 -0
- package/src/generators/connectors/runtime/useDeleteConnector.ts +179 -0
- package/src/generators/connectors/runtime/useGetAllConnector.ts +151 -0
- package/src/generators/connectors/runtime/useGetConnector.ts +120 -0
- package/src/generators/connectors/runtime/useUpdateConnector.ts +257 -0
- package/src/generators/connectors/runtime/zod-error-merger.ts +119 -0
- package/src/generators/connectors/templates.ts +481 -0
- package/src/generators/connectors/types.ts +39 -0
- package/src/generators/shared/runtime/useDeleteConnector.ts +4 -2
- package/src/generators/shared/runtime/useDetailConnector.ts +8 -19
- package/src/generators/shared/runtime/useFormConnector.ts +4 -3
- package/src/generators/use-async-data/runtime/useApiAsyncData.ts +16 -5
- package/src/generators/use-async-data/templates.ts +24 -16
- package/src/generators/use-fetch/templates.ts +1 -1
- package/src/index.ts +2 -19
- package/src/module/index.ts +2 -5
- package/docs/generated-components.md +0 -615
- package/docs/headless-composables-ui.md +0 -569
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// @ts-nocheck - This file runs in user's Nuxt project with different TypeScript config
|
|
2
|
+
/**
|
|
3
|
+
* useCreateConnector — Runtime connector for POST endpoints.
|
|
4
|
+
*
|
|
5
|
+
* Uses $fetch directly (no useAsyncData) so:
|
|
6
|
+
* - execute() always fires a real network request, no SSR cache interference
|
|
7
|
+
* - Can be called multiple times (create multiple items)
|
|
8
|
+
* - Validates with Zod before sending
|
|
9
|
+
*
|
|
10
|
+
* Copied to the user's project alongside the generated connectors.
|
|
11
|
+
*/
|
|
12
|
+
import { ref, computed } from 'vue';
|
|
13
|
+
import { mergeZodErrors } from './zod-error-merger.js';
|
|
14
|
+
import { getGlobalBaseUrl, mergeCallbacks } from '../composables/shared/runtime/apiHelpers.js';
|
|
15
|
+
/**
|
|
16
|
+
* @param url The endpoint URL string. e.g. '/pet'
|
|
17
|
+
* @param options Configuration: schema, fields, method, baseURL, callbacks, etc.
|
|
18
|
+
*/
|
|
19
|
+
export function useCreateConnector(url, options = {}) {
|
|
20
|
+
const { schema: baseSchema, schemaOverride, fields = [], method = 'POST', baseURL: baseURLOpt, errorConfig = {}, onRequest: onRequestOpt, onSuccess: onSuccessOpt, onError: onErrorOpt, onFinish: onFinishOpt, autoClose = true, autoReset = false, skipGlobalCallbacks, } = options;
|
|
21
|
+
const baseURL = baseURLOpt || getGlobalBaseUrl();
|
|
22
|
+
if (!baseURL) {
|
|
23
|
+
console.warn('[useCreateConnector] No baseURL configured. Set runtimeConfig.public.apiBaseUrl in nuxt.config.ts or pass baseURL in options.');
|
|
24
|
+
}
|
|
25
|
+
// Resolve active schema: schemaOverride(base) / schemaOverride / base / none
|
|
26
|
+
const schema = schemaOverride
|
|
27
|
+
? typeof schemaOverride === 'function'
|
|
28
|
+
? schemaOverride(baseSchema)
|
|
29
|
+
: schemaOverride
|
|
30
|
+
: baseSchema;
|
|
31
|
+
if (schemaOverride && !schema) {
|
|
32
|
+
console.warn('[useCreateConnector] schemaOverride resolved to undefined — validation will be skipped. Check your schemaOverride function returns a valid Zod schema.');
|
|
33
|
+
}
|
|
34
|
+
// ── Form state ─────────────────────────────────────────────────────────────
|
|
35
|
+
const model = ref({});
|
|
36
|
+
const errors = ref({});
|
|
37
|
+
const loading = ref(false);
|
|
38
|
+
const error = ref(null);
|
|
39
|
+
const submitted = ref(false);
|
|
40
|
+
// Callbacks — developer-assignable (can also be passed as options)
|
|
41
|
+
// Both the connector-level option and the per-operation registration are called.
|
|
42
|
+
let _localOnSuccess = null;
|
|
43
|
+
let _localOnError = null;
|
|
44
|
+
// ── UI state ───────────────────────────────────────────────────────────────
|
|
45
|
+
const isOpen = ref(false);
|
|
46
|
+
const ui = {
|
|
47
|
+
isOpen,
|
|
48
|
+
open() {
|
|
49
|
+
isOpen.value = true;
|
|
50
|
+
},
|
|
51
|
+
close() {
|
|
52
|
+
isOpen.value = false;
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
// ── Derived ────────────────────────────────────────────────────────────────
|
|
56
|
+
const isValid = computed(() => {
|
|
57
|
+
if (!schema)
|
|
58
|
+
return true;
|
|
59
|
+
return schema.safeParse(model.value).success;
|
|
60
|
+
});
|
|
61
|
+
const hasErrors = computed(() => Object.keys(errors.value).length > 0);
|
|
62
|
+
// ── Actions ────────────────────────────────────────────────────────────────
|
|
63
|
+
function setValues(data) {
|
|
64
|
+
model.value = { ...model.value, ...data };
|
|
65
|
+
}
|
|
66
|
+
function setField(key, value) {
|
|
67
|
+
model.value = { ...model.value, [key]: value };
|
|
68
|
+
}
|
|
69
|
+
function reset() {
|
|
70
|
+
model.value = {};
|
|
71
|
+
errors.value = {};
|
|
72
|
+
error.value = null;
|
|
73
|
+
submitted.value = false;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Validate with Zod (if schema provided) then POST via $fetch.
|
|
77
|
+
* @param data Optional payload override. Falls back to model.value.
|
|
78
|
+
* @returns The response data, or undefined if validation failed.
|
|
79
|
+
*/
|
|
80
|
+
async function execute(data) {
|
|
81
|
+
submitted.value = true;
|
|
82
|
+
const payload = data ?? model.value;
|
|
83
|
+
// 1. Zod validation
|
|
84
|
+
if (schema) {
|
|
85
|
+
const result = schema.safeParse(payload);
|
|
86
|
+
if (!result.success) {
|
|
87
|
+
errors.value = mergeZodErrors(result.error.flatten().fieldErrors, errorConfig);
|
|
88
|
+
console.error('[useCreateConnector] Validation failed — request was not sent.', errors.value);
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
errors.value = {};
|
|
92
|
+
}
|
|
93
|
+
// 2. $fetch POST
|
|
94
|
+
loading.value = true;
|
|
95
|
+
error.value = null;
|
|
96
|
+
// Merge global + local callbacks (onRequest modifications, rule-based suppression)
|
|
97
|
+
const merged = mergeCallbacks(url, method, {
|
|
98
|
+
onRequest: onRequestOpt,
|
|
99
|
+
onSuccess: onSuccessOpt,
|
|
100
|
+
onError: onErrorOpt,
|
|
101
|
+
onFinish: onFinishOpt,
|
|
102
|
+
}, skipGlobalCallbacks);
|
|
103
|
+
// onRequest hook — collects header/body/query modifications from global rules and local option
|
|
104
|
+
const requestMods = await merged.onRequest({ url, method, body: payload });
|
|
105
|
+
try {
|
|
106
|
+
const result = await $fetch(url, {
|
|
107
|
+
method,
|
|
108
|
+
body: requestMods?.body ?? payload,
|
|
109
|
+
...(requestMods?.headers ? { headers: requestMods.headers } : {}),
|
|
110
|
+
...(requestMods?.query ? { query: requestMods.query } : {}),
|
|
111
|
+
...(baseURL ? { baseURL } : {}),
|
|
112
|
+
});
|
|
113
|
+
await merged.onSuccess(result, { operation: 'create' });
|
|
114
|
+
_localOnSuccess?.(result);
|
|
115
|
+
if (autoClose)
|
|
116
|
+
ui.close();
|
|
117
|
+
if (autoReset)
|
|
118
|
+
reset();
|
|
119
|
+
await merged.onFinish({ url, method, data: result, success: true });
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
error.value = err;
|
|
124
|
+
await merged.onError(err, { operation: 'create' });
|
|
125
|
+
_localOnError?.(err);
|
|
126
|
+
await merged.onFinish({ url, method, error: err, success: false });
|
|
127
|
+
throw err;
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
loading.value = false;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// ── Return ─────────────────────────────────────────────────────────────────
|
|
134
|
+
return {
|
|
135
|
+
// Form state
|
|
136
|
+
model,
|
|
137
|
+
errors,
|
|
138
|
+
loading,
|
|
139
|
+
error,
|
|
140
|
+
submitted,
|
|
141
|
+
isValid,
|
|
142
|
+
hasErrors,
|
|
143
|
+
fields: computed(() => fields),
|
|
144
|
+
// Actions
|
|
145
|
+
execute,
|
|
146
|
+
refresh: execute,
|
|
147
|
+
reset,
|
|
148
|
+
setValues,
|
|
149
|
+
setField,
|
|
150
|
+
// Callbacks
|
|
151
|
+
onSuccess: (fn) => { _localOnSuccess = fn; },
|
|
152
|
+
onError: (fn) => { _localOnError = fn; },
|
|
153
|
+
// UI
|
|
154
|
+
ui,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param idFn Function that extracts the resource ID from a staged item.
|
|
3
|
+
* e.g. (item) => item.petId ?? item.id
|
|
4
|
+
* @param urlFn URL string or function that receives an id and returns the URL string.
|
|
5
|
+
* e.g. '/pet' (when ID is sent via body) or (id) => `/pet/${id}`
|
|
6
|
+
* @param options Optional configuration
|
|
7
|
+
*/
|
|
8
|
+
export declare function useDeleteConnector(idFn: any, urlFn: any, options?: {}): {
|
|
9
|
+
staged: any;
|
|
10
|
+
hasStaged: any;
|
|
11
|
+
loading: any;
|
|
12
|
+
error: any;
|
|
13
|
+
stage: (item: any) => void;
|
|
14
|
+
cancel: () => void;
|
|
15
|
+
execute: (item: any) => Promise<void>;
|
|
16
|
+
refresh: (item: any) => Promise<void>;
|
|
17
|
+
onSuccess: (fn: any) => void;
|
|
18
|
+
onError: (fn: any) => void;
|
|
19
|
+
ui: {
|
|
20
|
+
isOpen: any;
|
|
21
|
+
/**
|
|
22
|
+
* Stage the item and open the confirmation UI (modal/drawer/etc).
|
|
23
|
+
*/
|
|
24
|
+
open(item: any): void;
|
|
25
|
+
/**
|
|
26
|
+
* Cancel and close the confirmation UI.
|
|
27
|
+
*/
|
|
28
|
+
close(): void;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
@@ -0,0 +1,143 @@
|
|
|
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
|
+
* Uses $fetch directly (no useAsyncData) so:
|
|
6
|
+
* - execute() always fires a real network request, no SSR cache interference
|
|
7
|
+
* - Supports staging pattern (stage → confirm via ui) or direct execution
|
|
8
|
+
*
|
|
9
|
+
* Copied to the user's project alongside the generated connectors.
|
|
10
|
+
*/
|
|
11
|
+
import { ref, computed } from 'vue';
|
|
12
|
+
import { getGlobalBaseUrl, mergeCallbacks } from '../composables/shared/runtime/apiHelpers.js';
|
|
13
|
+
/**
|
|
14
|
+
* @param idFn Function that extracts the resource ID from a staged item.
|
|
15
|
+
* e.g. (item) => item.petId ?? item.id
|
|
16
|
+
* @param urlFn URL string or function that receives an id and returns the URL string.
|
|
17
|
+
* e.g. '/pet' (when ID is sent via body) or (id) => `/pet/${id}`
|
|
18
|
+
* @param options Optional configuration
|
|
19
|
+
*/
|
|
20
|
+
export function useDeleteConnector(idFn, urlFn, options = {}) {
|
|
21
|
+
const resolveUrl = (id) => (typeof urlFn === 'function' ? urlFn(id) : urlFn);
|
|
22
|
+
const { baseURL: baseURLOpt, onRequest: onRequestOpt, onSuccess: onSuccessOpt, onError: onErrorOpt, onFinish: onFinishOpt, autoClose = true, skipGlobalCallbacks, } = options;
|
|
23
|
+
const baseURL = baseURLOpt || getGlobalBaseUrl();
|
|
24
|
+
if (!baseURL) {
|
|
25
|
+
console.warn('[useDeleteConnector] No baseURL configured. Set runtimeConfig.public.apiBaseUrl in nuxt.config.ts or pass baseURL in options.');
|
|
26
|
+
}
|
|
27
|
+
// ── State ──────────────────────────────────────────────────────────────────
|
|
28
|
+
const staged = ref(null);
|
|
29
|
+
const loading = ref(false);
|
|
30
|
+
const error = ref(null);
|
|
31
|
+
// Callbacks — developer-assignable (can also be passed as options)
|
|
32
|
+
// Both the connector-level option and the per-operation registration are called.
|
|
33
|
+
let _localOnSuccess = null;
|
|
34
|
+
let _localOnError = null;
|
|
35
|
+
// ── UI state ───────────────────────────────────────────────────────────────
|
|
36
|
+
const isOpen = ref(false);
|
|
37
|
+
const ui = {
|
|
38
|
+
isOpen,
|
|
39
|
+
/**
|
|
40
|
+
* Stage the item and open the confirmation UI (modal/drawer/etc).
|
|
41
|
+
*/
|
|
42
|
+
open(item) {
|
|
43
|
+
stage(item);
|
|
44
|
+
isOpen.value = true;
|
|
45
|
+
},
|
|
46
|
+
/**
|
|
47
|
+
* Cancel and close the confirmation UI.
|
|
48
|
+
*/
|
|
49
|
+
close() {
|
|
50
|
+
cancel();
|
|
51
|
+
isOpen.value = false;
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
// ── Derived ────────────────────────────────────────────────────────────────
|
|
55
|
+
const hasStaged = computed(() => staged.value !== null);
|
|
56
|
+
// ── Actions ────────────────────────────────────────────────────────────────
|
|
57
|
+
/**
|
|
58
|
+
* Stage an item for deletion without opening any UI.
|
|
59
|
+
* Useful when you want to control the UI yourself.
|
|
60
|
+
*/
|
|
61
|
+
function stage(item) {
|
|
62
|
+
staged.value = item;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Clear the staged item and reset error state.
|
|
66
|
+
*/
|
|
67
|
+
function cancel() {
|
|
68
|
+
staged.value = null;
|
|
69
|
+
error.value = null;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Execute the DELETE request.
|
|
73
|
+
* @param item Optional — if provided, uses this item instead of staged.
|
|
74
|
+
* Allows direct deletion without staging: await del.execute(row)
|
|
75
|
+
*/
|
|
76
|
+
async function execute(item) {
|
|
77
|
+
const target = item ?? staged.value;
|
|
78
|
+
if (!target) {
|
|
79
|
+
console.warn('[useDeleteConnector] execute() called with no item and nothing staged — request was not sent. Call stage(item) or pass the item directly to execute(item).');
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const id = idFn(target);
|
|
83
|
+
if (id === undefined || id === null) {
|
|
84
|
+
console.warn('[useDeleteConnector] idFn returned undefined/null — could not resolve resource ID. Request was not sent.', { target });
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const url = resolveUrl(id);
|
|
88
|
+
loading.value = true;
|
|
89
|
+
error.value = null;
|
|
90
|
+
// Merge global + local callbacks (onRequest modifications, rule-based suppression)
|
|
91
|
+
const merged = mergeCallbacks(url, 'DELETE', {
|
|
92
|
+
onRequest: onRequestOpt,
|
|
93
|
+
onSuccess: onSuccessOpt,
|
|
94
|
+
onError: onErrorOpt,
|
|
95
|
+
onFinish: onFinishOpt,
|
|
96
|
+
}, skipGlobalCallbacks);
|
|
97
|
+
// onRequest hook — collects header/body/query modifications
|
|
98
|
+
const requestMods = await merged.onRequest({ url, method: 'DELETE' });
|
|
99
|
+
try {
|
|
100
|
+
await $fetch(url, {
|
|
101
|
+
method: 'DELETE',
|
|
102
|
+
...(requestMods?.headers ? { headers: requestMods.headers } : {}),
|
|
103
|
+
...(requestMods?.query ? { query: requestMods.query } : {}),
|
|
104
|
+
...(baseURL ? { baseURL } : {}),
|
|
105
|
+
});
|
|
106
|
+
const deletedItem = target;
|
|
107
|
+
await merged.onSuccess(deletedItem, { operation: 'delete' });
|
|
108
|
+
_localOnSuccess?.(deletedItem);
|
|
109
|
+
cancel();
|
|
110
|
+
if (autoClose)
|
|
111
|
+
ui.close();
|
|
112
|
+
await merged.onFinish({ url, method: 'DELETE', success: true });
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
error.value = err;
|
|
116
|
+
await merged.onError(err, { operation: 'delete' });
|
|
117
|
+
_localOnError?.(err);
|
|
118
|
+
await merged.onFinish({ url, method: 'DELETE', error: err, success: false });
|
|
119
|
+
throw err;
|
|
120
|
+
}
|
|
121
|
+
finally {
|
|
122
|
+
loading.value = false;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// ── Return ─────────────────────────────────────────────────────────────────
|
|
126
|
+
return {
|
|
127
|
+
// State
|
|
128
|
+
staged,
|
|
129
|
+
hasStaged,
|
|
130
|
+
loading,
|
|
131
|
+
error,
|
|
132
|
+
// Actions
|
|
133
|
+
stage,
|
|
134
|
+
cancel,
|
|
135
|
+
execute,
|
|
136
|
+
refresh: execute,
|
|
137
|
+
// Callbacks
|
|
138
|
+
onSuccess: (fn) => { _localOnSuccess = fn; },
|
|
139
|
+
onError: (fn) => { _localOnError = fn; },
|
|
140
|
+
// UI
|
|
141
|
+
ui,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param factory A zero-argument function that calls and returns the underlying
|
|
3
|
+
* useAsyncData composable, e.g. () => useAsyncDataGetPets(params)
|
|
4
|
+
* Called once during connector setup (inside setup()).
|
|
5
|
+
* @param options Configuration for the connector
|
|
6
|
+
*/
|
|
7
|
+
export declare function useGetAllConnector(factory: any, options?: {}): {
|
|
8
|
+
items: any;
|
|
9
|
+
columns: any;
|
|
10
|
+
loading: any;
|
|
11
|
+
error: any;
|
|
12
|
+
pagination: any;
|
|
13
|
+
goToPage: (page: any) => void;
|
|
14
|
+
nextPage: () => void;
|
|
15
|
+
prevPage: () => void;
|
|
16
|
+
setPerPage: (n: any) => void;
|
|
17
|
+
selected: any;
|
|
18
|
+
select: (item: any) => void;
|
|
19
|
+
deselect: (item: any) => void;
|
|
20
|
+
toggleSelect: (item: any) => void;
|
|
21
|
+
clearSelection: () => void;
|
|
22
|
+
load: (_params: any) => Promise<void>;
|
|
23
|
+
onSuccess: any;
|
|
24
|
+
onError: any;
|
|
25
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// @ts-nocheck - This file runs in user's Nuxt project with different TypeScript config
|
|
2
|
+
/**
|
|
3
|
+
* useGetAllConnector — Runtime connector for list/collection GET endpoints.
|
|
4
|
+
*
|
|
5
|
+
* Wraps a useAsyncData composable (reactive, SSR-compatible, supports pagination).
|
|
6
|
+
* The factory pattern means the composable is initialized in setup() context.
|
|
7
|
+
*
|
|
8
|
+
* Key differences from the old useListConnector:
|
|
9
|
+
* - items instead of rows
|
|
10
|
+
* - select/deselect/toggleSelect instead of onRowSelect
|
|
11
|
+
* - load(params?) instead of refresh()
|
|
12
|
+
* - No CRUD coordination methods (create/update/remove/_createTrigger etc.)
|
|
13
|
+
* — coordination is the component's responsibility via callbacks
|
|
14
|
+
*
|
|
15
|
+
* Copied to the user's project alongside the generated connectors.
|
|
16
|
+
*/
|
|
17
|
+
import { ref, computed } from 'vue';
|
|
18
|
+
/**
|
|
19
|
+
* @param factory A zero-argument function that calls and returns the underlying
|
|
20
|
+
* useAsyncData composable, e.g. () => useAsyncDataGetPets(params)
|
|
21
|
+
* Called once during connector setup (inside setup()).
|
|
22
|
+
* @param options Configuration for the connector
|
|
23
|
+
*/
|
|
24
|
+
export function useGetAllConnector(factory, options = {}) {
|
|
25
|
+
const { columns = [], columnLabels = {}, columnLabel = null } = options;
|
|
26
|
+
// ── Execute the underlying composable once (in setup context) ─────────────
|
|
27
|
+
const composable = factory();
|
|
28
|
+
// ── Derived state ──────────────────────────────────────────────────────────
|
|
29
|
+
const items = computed(() => {
|
|
30
|
+
const data = composable.data?.value;
|
|
31
|
+
if (!data)
|
|
32
|
+
return [];
|
|
33
|
+
// Support both direct arrays and { data: [...] } shapes (paginated APIs)
|
|
34
|
+
if (Array.isArray(data))
|
|
35
|
+
return data;
|
|
36
|
+
if (Array.isArray(data.data))
|
|
37
|
+
return data.data;
|
|
38
|
+
return [];
|
|
39
|
+
});
|
|
40
|
+
const loading = computed(() => composable.pending?.value ?? false);
|
|
41
|
+
const error = computed(() => composable.error?.value ?? null);
|
|
42
|
+
// Pagination — passthrough from the underlying composable when paginated: true
|
|
43
|
+
const pagination = computed(() => composable.pagination?.value ?? null);
|
|
44
|
+
function goToPage(page) {
|
|
45
|
+
composable.pagination?.value?.goToPage?.(page);
|
|
46
|
+
}
|
|
47
|
+
function nextPage() {
|
|
48
|
+
composable.pagination?.value?.nextPage?.();
|
|
49
|
+
}
|
|
50
|
+
function prevPage() {
|
|
51
|
+
composable.pagination?.value?.prevPage?.();
|
|
52
|
+
}
|
|
53
|
+
function setPerPage(n) {
|
|
54
|
+
composable.pagination?.value?.setPerPage?.(n);
|
|
55
|
+
}
|
|
56
|
+
// ── Selection ──────────────────────────────────────────────────────────────
|
|
57
|
+
const selected = ref([]);
|
|
58
|
+
function select(item) {
|
|
59
|
+
if (!selected.value.includes(item)) {
|
|
60
|
+
selected.value = [...selected.value, item];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function deselect(item) {
|
|
64
|
+
selected.value = selected.value.filter((r) => r !== item);
|
|
65
|
+
}
|
|
66
|
+
function toggleSelect(item) {
|
|
67
|
+
if (selected.value.includes(item)) {
|
|
68
|
+
deselect(item);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
select(item);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function clearSelection() {
|
|
75
|
+
selected.value = [];
|
|
76
|
+
}
|
|
77
|
+
// ── Callbacks — developer-assignable ──────────────────────────────────────
|
|
78
|
+
const onSuccess = ref(null);
|
|
79
|
+
const onError = ref(null);
|
|
80
|
+
// ── Load / refresh ─────────────────────────────────────────────────────────
|
|
81
|
+
/**
|
|
82
|
+
* Reload the list. Equivalent to refresh() on the underlying composable.
|
|
83
|
+
* @param _params Reserved for future use (reactive params are handled by
|
|
84
|
+
* the underlying useAsyncData watch sources).
|
|
85
|
+
*/
|
|
86
|
+
async function load(_params) {
|
|
87
|
+
await composable.refresh?.();
|
|
88
|
+
if (!composable.error?.value) {
|
|
89
|
+
onSuccess.value?.(items.value);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
onError.value?.(composable.error.value);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// ── Column label resolution ────────────────────────────────────────────────
|
|
96
|
+
const resolvedColumns = computed(() => columns.map((col) => ({
|
|
97
|
+
...col,
|
|
98
|
+
label: columnLabel
|
|
99
|
+
? columnLabel(col.key)
|
|
100
|
+
: (columnLabels[col.key] ?? col.label),
|
|
101
|
+
})));
|
|
102
|
+
// ── Return ─────────────────────────────────────────────────────────────────
|
|
103
|
+
return {
|
|
104
|
+
// State
|
|
105
|
+
items,
|
|
106
|
+
columns: resolvedColumns,
|
|
107
|
+
loading,
|
|
108
|
+
error,
|
|
109
|
+
// Pagination
|
|
110
|
+
pagination,
|
|
111
|
+
goToPage,
|
|
112
|
+
nextPage,
|
|
113
|
+
prevPage,
|
|
114
|
+
setPerPage,
|
|
115
|
+
// Selection
|
|
116
|
+
selected,
|
|
117
|
+
select,
|
|
118
|
+
deselect,
|
|
119
|
+
toggleSelect,
|
|
120
|
+
clearSelection,
|
|
121
|
+
// Actions
|
|
122
|
+
load,
|
|
123
|
+
// Callbacks
|
|
124
|
+
onSuccess,
|
|
125
|
+
onError,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param urlFn URL string or function that receives an id and returns the URL string.
|
|
3
|
+
* e.g. '/pet/me' or (id) => `/pet/${id}`
|
|
4
|
+
* @param options Optional configuration
|
|
5
|
+
*/
|
|
6
|
+
export declare function useGetConnector(urlFn: any, options?: {}): {
|
|
7
|
+
data: any;
|
|
8
|
+
loading: any;
|
|
9
|
+
error: any;
|
|
10
|
+
fields: any;
|
|
11
|
+
load: (id: any) => Promise<any>;
|
|
12
|
+
clear: () => void;
|
|
13
|
+
onSuccess: (fn: any) => void;
|
|
14
|
+
onError: (fn: any) => void;
|
|
15
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// @ts-nocheck - This file runs in user's Nuxt project with different TypeScript config
|
|
2
|
+
/**
|
|
3
|
+
* useGetConnector — Runtime connector for single-item GET endpoints.
|
|
4
|
+
*
|
|
5
|
+
* Uses $fetch directly (no useAsyncData) so:
|
|
6
|
+
* - load(id) is truly imperative and awaitable
|
|
7
|
+
* - Returns the fetched item from load()
|
|
8
|
+
* - No SSR key registration, no cache interference
|
|
9
|
+
*
|
|
10
|
+
* Copied to the user's project alongside the generated connectors.
|
|
11
|
+
*/
|
|
12
|
+
import { ref, computed } from 'vue';
|
|
13
|
+
import { getGlobalBaseUrl, mergeCallbacks } from '../composables/shared/runtime/apiHelpers.js';
|
|
14
|
+
/**
|
|
15
|
+
* @param urlFn URL string or function that receives an id and returns the URL string.
|
|
16
|
+
* e.g. '/pet/me' or (id) => `/pet/${id}`
|
|
17
|
+
* @param options Optional configuration
|
|
18
|
+
*/
|
|
19
|
+
export function useGetConnector(urlFn, options = {}) {
|
|
20
|
+
const resolveUrl = (id) => (typeof urlFn === 'function' ? urlFn(id) : urlFn);
|
|
21
|
+
const { fields = [], baseURL: baseURLOpt, onRequest: onRequestOpt, onSuccess: onSuccessOpt, onError: onErrorOpt, skipGlobalCallbacks, } = options;
|
|
22
|
+
const baseURL = baseURLOpt || getGlobalBaseUrl();
|
|
23
|
+
if (!baseURL) {
|
|
24
|
+
console.warn('[useGetConnector] No baseURL configured. Set runtimeConfig.public.apiBaseUrl in nuxt.config.ts or pass baseURL in options.');
|
|
25
|
+
}
|
|
26
|
+
// Callbacks — developer-assignable (can also be passed as options)
|
|
27
|
+
// Both the connector-level option and the per-operation registration are called.
|
|
28
|
+
let _localOnSuccess = null;
|
|
29
|
+
let _localOnError = null;
|
|
30
|
+
// ── State ──────────────────────────────────────────────────────────────────
|
|
31
|
+
const data = ref(null);
|
|
32
|
+
const loading = ref(false);
|
|
33
|
+
const error = ref(null);
|
|
34
|
+
// ── Actions ────────────────────────────────────────────────────────────────
|
|
35
|
+
/**
|
|
36
|
+
* Fetch a single item by ID.
|
|
37
|
+
* Returns the fetched item so it can be awaited imperatively:
|
|
38
|
+
* const pet = await get.load(5)
|
|
39
|
+
*/
|
|
40
|
+
async function load(id) {
|
|
41
|
+
if (id === undefined || id === null) {
|
|
42
|
+
console.warn('[useGetConnector] load() called with undefined/null id — request was not sent.');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
loading.value = true;
|
|
46
|
+
error.value = null;
|
|
47
|
+
// Merge global + local callbacks (onRequest modifications, rule-based suppression)
|
|
48
|
+
const url = resolveUrl(id);
|
|
49
|
+
const merged = mergeCallbacks(url, 'GET', {
|
|
50
|
+
onRequest: onRequestOpt,
|
|
51
|
+
onSuccess: onSuccessOpt,
|
|
52
|
+
onError: onErrorOpt,
|
|
53
|
+
}, skipGlobalCallbacks);
|
|
54
|
+
// onRequest hook — collects header/query modifications
|
|
55
|
+
const requestMods = await merged.onRequest({ url, method: 'GET' });
|
|
56
|
+
try {
|
|
57
|
+
const result = await $fetch(url, {
|
|
58
|
+
method: 'GET',
|
|
59
|
+
...(requestMods?.headers ? { headers: requestMods.headers } : {}),
|
|
60
|
+
...(requestMods?.query ? { query: requestMods.query } : {}),
|
|
61
|
+
...(baseURL ? { baseURL } : {}),
|
|
62
|
+
});
|
|
63
|
+
data.value = result;
|
|
64
|
+
await merged.onSuccess(result, { operation: 'get' });
|
|
65
|
+
_localOnSuccess?.(result);
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
error.value = err;
|
|
70
|
+
await merged.onError(err, { operation: 'get' });
|
|
71
|
+
_localOnError?.(err);
|
|
72
|
+
throw err;
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
loading.value = false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Clear the current item from state.
|
|
80
|
+
*/
|
|
81
|
+
function clear() {
|
|
82
|
+
data.value = null;
|
|
83
|
+
error.value = null;
|
|
84
|
+
}
|
|
85
|
+
// ── Return ─────────────────────────────────────────────────────────────────
|
|
86
|
+
return {
|
|
87
|
+
// State
|
|
88
|
+
data,
|
|
89
|
+
loading,
|
|
90
|
+
error,
|
|
91
|
+
fields: computed(() => fields),
|
|
92
|
+
// Actions
|
|
93
|
+
load,
|
|
94
|
+
clear,
|
|
95
|
+
// Callbacks
|
|
96
|
+
onSuccess: (fn) => { _localOnSuccess = fn; },
|
|
97
|
+
onError: (fn) => { _localOnError = fn; },
|
|
98
|
+
};
|
|
99
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param urlFn URL string or function that receives an id and returns the URL string.
|
|
3
|
+
* e.g. '/pet' (when ID is sent via body) or (id) => `/pet/${id}`
|
|
4
|
+
* @param options Configuration: schema, fields, method, baseURL, callbacks, etc.
|
|
5
|
+
*/
|
|
6
|
+
export declare function useUpdateConnector(urlFn: any, options?: {}): {
|
|
7
|
+
model: any;
|
|
8
|
+
errors: any;
|
|
9
|
+
loading: any;
|
|
10
|
+
error: any;
|
|
11
|
+
submitted: any;
|
|
12
|
+
isValid: any;
|
|
13
|
+
hasErrors: any;
|
|
14
|
+
fields: any;
|
|
15
|
+
targetId: any;
|
|
16
|
+
load: (id: any) => Promise<void>;
|
|
17
|
+
execute: (id: any, data: any) => Promise<any>;
|
|
18
|
+
refresh: (id: any, data: any) => Promise<any>;
|
|
19
|
+
reset: () => void;
|
|
20
|
+
setValues: (data: any) => void;
|
|
21
|
+
setField: (key: any, value: any) => void;
|
|
22
|
+
onSuccess: (fn: any) => void;
|
|
23
|
+
onError: (fn: any) => void;
|
|
24
|
+
ui: {
|
|
25
|
+
isOpen: any;
|
|
26
|
+
/**
|
|
27
|
+
* Open the update form.
|
|
28
|
+
* @param item If provided, pre-fills the model immediately (no extra fetch needed).
|
|
29
|
+
* Typically pass the row object from the table.
|
|
30
|
+
*/
|
|
31
|
+
open(item: any): void;
|
|
32
|
+
close(): void;
|
|
33
|
+
};
|
|
34
|
+
};
|