@forgebook/nuxt 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +121 -2
- package/dist/src/app/components.d.ts +119 -0
- package/dist/src/app/components.js +196 -0
- package/dist/src/app/data.d.ts +109 -0
- package/dist/src/app/data.js +155 -0
- package/dist/src/app/define.d.ts +30 -0
- package/dist/src/app/define.js +30 -0
- package/dist/src/app/errors.d.ts +43 -0
- package/dist/src/app/errors.js +41 -0
- package/dist/src/app/fetch.d.ts +63 -0
- package/dist/src/app/fetch.js +73 -0
- package/dist/src/app/head.d.ts +28 -0
- package/dist/src/app/head.js +23 -0
- package/dist/src/app/router.d.ts +69 -0
- package/dist/src/app/router.js +93 -0
- package/dist/src/app/state.d.ts +107 -0
- package/dist/src/app/state.js +137 -0
- package/dist/src/asyncDataRun.d.ts +39 -0
- package/dist/src/asyncDataRun.js +128 -0
- package/dist/src/nuxtError.d.ts +50 -0
- package/dist/src/nuxtError.js +65 -0
- package/dist/src/nuxtRenderer.d.ts +14 -0
- package/dist/src/nuxtRenderer.js +67 -0
- package/dist/src/nuxtStore.d.ts +144 -0
- package/dist/src/nuxtStore.js +196 -0
- package/dist/src/pageProject.d.ts +11 -0
- package/dist/src/pageProject.js +11 -0
- package/dist/src/parameters.d.ts +67 -0
- package/dist/src/parameters.js +89 -0
- package/dist/src/project.d.ts +49 -0
- package/dist/src/project.js +7 -0
- package/dist/src/renderer.d.ts +9 -0
- package/dist/src/renderer.js +10 -0
- package/dist/src/stories.d.ts +54 -0
- package/dist/src/stories.js +11 -0
- package/dist/src/storyCode.d.ts +3 -0
- package/dist/src/storyCode.js +9 -0
- package/dist/src/storyFetch.d.ts +74 -0
- package/dist/src/storyFetch.js +146 -0
- package/dist/src/storyNuxt.d.ts +48 -0
- package/dist/src/storyNuxt.js +26 -0
- package/dist/src/vite/componentNames.d.ts +36 -0
- package/dist/src/vite/componentNames.js +72 -0
- package/dist/src/vite/extractDocs.d.ts +16 -0
- package/dist/src/vite/extractDocs.js +22 -0
- package/dist/src/vite/nuxt.d.ts +13 -0
- package/dist/src/vite/nuxt.js +36 -0
- package/dist/src/vite/nuxtConfig.d.ts +85 -0
- package/dist/src/vite/nuxtConfig.js +261 -0
- package/dist/src/vite/nuxtPlugin.d.ts +51 -0
- package/dist/src/vite/nuxtPlugin.js +466 -0
- package/dist/src/vite/pageRoutes.d.ts +23 -0
- package/dist/src/vite/pageRoutes.js +88 -0
- package/dist/src/vite/placeKeys.d.ts +10 -0
- package/dist/src/vite/placeKeys.js +117 -0
- package/dist/src/vite/standIns.d.ts +26 -0
- package/dist/src/vite/standIns.js +96 -0
- package/package.json +118 -3
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nuxt's data fetching in a catalogue: `useAsyncData`, its lazy form, `refreshNuxtData`, `clearNuxtData` and
|
|
3
|
+
* `useNuxtData`. `useFetch` is written on it (`fetch.ts`).
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* A story gives the data of a key (`parameters.nuxt.data`) and the composable returns it without calling its handler,
|
|
7
|
+
* as Nuxt returns the payload the server sent. Without it the handler runs. The calls of one key share their data, as
|
|
8
|
+
* Nuxt's do; a key that is a ref follows it, each value with its own data. A call without a key gets the one the plugin
|
|
9
|
+
* writes for its place in the code, as Nuxt's compiler does.
|
|
10
|
+
*
|
|
11
|
+
* On the server (a generated server test) no handler runs, since no server is there to answer: the story's data is
|
|
12
|
+
* drawn, or nothing.
|
|
13
|
+
*
|
|
14
|
+
* What is returned is Nuxt 4's: `data` and `error` are `undefined` until there is one, and the result can be awaited,
|
|
15
|
+
* at once for a lazy call. `server`, `dedupe` and `deep` change nothing in the page, where everything runs.
|
|
16
|
+
*
|
|
17
|
+
* Internal: the code the plugin writes imports it (`#imports`, `#app`, `#components`); a story or a component imports
|
|
18
|
+
* Nuxt's names as in the app, never this module, whose exports may change in any release.
|
|
19
|
+
*
|
|
20
|
+
* @module
|
|
21
|
+
*/
|
|
22
|
+
import { computed, getCurrentScope, isRef, onScopeDispose, watch } from "vue";
|
|
23
|
+
import { entryOf, startRun, waitedRun } from "../asyncDataRun.js";
|
|
24
|
+
import { useNuxtStore } from "../nuxtStore.js";
|
|
25
|
+
/**
|
|
26
|
+
* A call read as Nuxt reads it: `(key, handler, options)`, or `(handler, options)` under the key the plugin wrote last
|
|
27
|
+
* for its place in the code, or a key of its own.
|
|
28
|
+
*
|
|
29
|
+
* @param store - the story's store, for a key of its own.
|
|
30
|
+
* @param first - the key, or the handler.
|
|
31
|
+
* @param second - the handler, the options, or the plugin's key.
|
|
32
|
+
* @param third - the options, or the plugin's key.
|
|
33
|
+
*/
|
|
34
|
+
const readCall = (store, first, second, third) => {
|
|
35
|
+
if (typeof first !== "function")
|
|
36
|
+
return {
|
|
37
|
+
key: first,
|
|
38
|
+
handler: typeof second === "function" ? second : undefined,
|
|
39
|
+
options: typeof third === "object" ? third : {}
|
|
40
|
+
};
|
|
41
|
+
const placeKey = typeof second === "string" ? second : third;
|
|
42
|
+
return {
|
|
43
|
+
key: typeof placeKey === "string" ? placeKey : store.nextKey("data"),
|
|
44
|
+
handler: first,
|
|
45
|
+
options: typeof second === "object" ? second : {}
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
export function useAsyncData(first, second, third) {
|
|
49
|
+
const store = useNuxtStore();
|
|
50
|
+
const { key, handler, options } = readCall(store, first, second, third);
|
|
51
|
+
const keyNow = () => (isRef(key) ? key.value : key);
|
|
52
|
+
const entryNow = () => entryOf(store, keyNow(), () => options.default?.());
|
|
53
|
+
const start = () => startRun(store, entryNow(), keyNow(), handler, options);
|
|
54
|
+
const firstEntry = entryNow();
|
|
55
|
+
firstEntry.refresh ??= start;
|
|
56
|
+
const started = options.immediate === false ? Promise.resolve() : waitedRun(firstEntry, start);
|
|
57
|
+
const sources = options.watch === false ? [] : [...(options.watch ?? []), ...(isRef(key) ? [key] : [])];
|
|
58
|
+
if (sources.length > 0) {
|
|
59
|
+
const stop = watch(sources, () => {
|
|
60
|
+
void start();
|
|
61
|
+
});
|
|
62
|
+
if (getCurrentScope() !== undefined)
|
|
63
|
+
onScopeDispose(stop);
|
|
64
|
+
}
|
|
65
|
+
const asyncData = {
|
|
66
|
+
data: computed({
|
|
67
|
+
get: () => entryNow().data.value,
|
|
68
|
+
set: (value) => {
|
|
69
|
+
entryNow().data.value = value;
|
|
70
|
+
}
|
|
71
|
+
}),
|
|
72
|
+
pending: computed(() => entryNow().status.value === "pending"),
|
|
73
|
+
status: computed({
|
|
74
|
+
get: () => entryNow().status.value,
|
|
75
|
+
set: (value) => {
|
|
76
|
+
entryNow().status.value = value;
|
|
77
|
+
}
|
|
78
|
+
}),
|
|
79
|
+
error: computed({
|
|
80
|
+
get: () => entryNow().error.value,
|
|
81
|
+
set: (value) => {
|
|
82
|
+
entryNow().error.value = value;
|
|
83
|
+
}
|
|
84
|
+
}),
|
|
85
|
+
refresh: start,
|
|
86
|
+
execute: start,
|
|
87
|
+
clear: () => clearEntry(entryNow())
|
|
88
|
+
};
|
|
89
|
+
// a lazy call does not hold what awaits it, as Nuxt's lazy fetch does not hold navigation
|
|
90
|
+
const awaited = options.lazy === true ? Promise.resolve() : started;
|
|
91
|
+
return Object.assign(awaited.then(() => asyncData), asyncData);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* `useAsyncData` that does not hold what awaits it.
|
|
95
|
+
*
|
|
96
|
+
* @param key - the key.
|
|
97
|
+
* @param handler - what fetches the data.
|
|
98
|
+
* @param options - its options.
|
|
99
|
+
*/
|
|
100
|
+
export const useLazyAsyncData = (key, handler, options = {}) => useAsyncData(key, handler, { ...options, lazy: true });
|
|
101
|
+
/**
|
|
102
|
+
* Empties an entry, as before its first run: its data back to its default.
|
|
103
|
+
*
|
|
104
|
+
* @param entry - the entry.
|
|
105
|
+
*/
|
|
106
|
+
const clearEntry = (entry) => {
|
|
107
|
+
entry.runId += 1;
|
|
108
|
+
entry.controller?.abort();
|
|
109
|
+
entry.data.value = entry.defaultData();
|
|
110
|
+
entry.error.value = undefined;
|
|
111
|
+
entry.status.value = "idle";
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* The keys a function for every key takes: the ones given, or all.
|
|
115
|
+
*
|
|
116
|
+
* @param store - the story's store.
|
|
117
|
+
* @param keys - a key, keys, or none.
|
|
118
|
+
*/
|
|
119
|
+
const keysOf = (store, keys) => {
|
|
120
|
+
if (keys === undefined)
|
|
121
|
+
return [...store.asyncData.keys()];
|
|
122
|
+
return typeof keys === "string" ? [keys] : keys;
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* Runs the handlers of keys again.
|
|
126
|
+
*
|
|
127
|
+
* @param keys - a key, keys, or none for all.
|
|
128
|
+
*/
|
|
129
|
+
export const refreshNuxtData = async (keys) => {
|
|
130
|
+
const store = useNuxtStore();
|
|
131
|
+
await Promise.all(keysOf(store, keys).map((key) => store.asyncData.get(key)?.refresh?.()));
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* Empties the data of keys, back to each one's default.
|
|
135
|
+
*
|
|
136
|
+
* @param keys - a key, keys, or none for all.
|
|
137
|
+
*/
|
|
138
|
+
export const clearNuxtData = (keys) => {
|
|
139
|
+
const store = useNuxtStore();
|
|
140
|
+
for (const key of keysOf(store, keys)) {
|
|
141
|
+
const entry = store.asyncData.get(key);
|
|
142
|
+
if (entry !== undefined)
|
|
143
|
+
clearEntry(entry);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* The data of a key another call fetched.
|
|
148
|
+
*
|
|
149
|
+
* @param key - the key.
|
|
150
|
+
*/
|
|
151
|
+
export const useNuxtData = (key) => {
|
|
152
|
+
const store = useNuxtStore();
|
|
153
|
+
const given = Object.hasOwn(store.storyData, key) ? store.storyData[key] : undefined;
|
|
154
|
+
return { data: entryOf(store, key, () => given).data };
|
|
155
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nuxt's `define…` helpers in a catalogue: each returns what it is given, as Nuxt's do once its compiler has read them,
|
|
3
|
+
* so a component, a plugin or the app config written with one loads as it is.
|
|
4
|
+
*
|
|
5
|
+
* Internal: the code the plugin writes imports it (`#imports`, `#app`, `#components`); a story or a component imports
|
|
6
|
+
* Nuxt's names as in the app, never this module, whose exports may change in any release.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
import { defineComponent } from "vue";
|
|
11
|
+
/** A component written with Nuxt's helper: Vue's `defineComponent`, since its `asyncData` option is Nuxt 2's. */
|
|
12
|
+
export declare const defineNuxtComponent: typeof defineComponent;
|
|
13
|
+
/**
|
|
14
|
+
* A plugin: the plugin itself, since a story runs none.
|
|
15
|
+
*
|
|
16
|
+
* @param plugin - the plugin.
|
|
17
|
+
*/
|
|
18
|
+
export declare const defineNuxtPlugin: <TPlugin>(plugin: TPlugin) => TPlugin;
|
|
19
|
+
/**
|
|
20
|
+
* A payload plugin: the plugin itself, since a story runs none.
|
|
21
|
+
*
|
|
22
|
+
* @param plugin - the plugin.
|
|
23
|
+
*/
|
|
24
|
+
export declare const definePayloadPlugin: <TPlugin>(plugin: TPlugin) => TPlugin;
|
|
25
|
+
/**
|
|
26
|
+
* The app config, as `app.config.ts` writes it: the config itself.
|
|
27
|
+
*
|
|
28
|
+
* @param config - the config.
|
|
29
|
+
*/
|
|
30
|
+
export declare const defineAppConfig: <TConfig>(config: TConfig) => TConfig;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nuxt's `define…` helpers in a catalogue: each returns what it is given, as Nuxt's do once its compiler has read them,
|
|
3
|
+
* so a component, a plugin or the app config written with one loads as it is.
|
|
4
|
+
*
|
|
5
|
+
* Internal: the code the plugin writes imports it (`#imports`, `#app`, `#components`); a story or a component imports
|
|
6
|
+
* Nuxt's names as in the app, never this module, whose exports may change in any release.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
import { defineComponent } from "vue";
|
|
11
|
+
/** A component written with Nuxt's helper: Vue's `defineComponent`, since its `asyncData` option is Nuxt 2's. */
|
|
12
|
+
export const defineNuxtComponent = defineComponent;
|
|
13
|
+
/**
|
|
14
|
+
* A plugin: the plugin itself, since a story runs none.
|
|
15
|
+
*
|
|
16
|
+
* @param plugin - the plugin.
|
|
17
|
+
*/
|
|
18
|
+
export const defineNuxtPlugin = (plugin) => plugin;
|
|
19
|
+
/**
|
|
20
|
+
* A payload plugin: the plugin itself, since a story runs none.
|
|
21
|
+
*
|
|
22
|
+
* @param plugin - the plugin.
|
|
23
|
+
*/
|
|
24
|
+
export const definePayloadPlugin = (plugin) => plugin;
|
|
25
|
+
/**
|
|
26
|
+
* The app config, as `app.config.ts` writes it: the config itself.
|
|
27
|
+
*
|
|
28
|
+
* @param config - the config.
|
|
29
|
+
*/
|
|
30
|
+
export const defineAppConfig = (config) => config;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nuxt's error composables in a catalogue: `createError` and `isNuxtError` as Nuxt's, and the error `showError` sets and
|
|
3
|
+
* `useError` returns, kept in the story's store instead of replacing a page with Nuxt's error page.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* `showError` is recorded among the story's events, so a story shows what its component would have shown the user.
|
|
7
|
+
*
|
|
8
|
+
* Internal: the code the plugin writes imports it (`#imports`, `#app`, `#components`); a story or a component imports
|
|
9
|
+
* Nuxt's names as in the app, never this module, whose exports may change in any release.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
import type { Ref } from "vue";
|
|
14
|
+
import { type NuxtError, type NuxtErrorInput } from "../nuxtError.ts";
|
|
15
|
+
/**
|
|
16
|
+
* An error as Nuxt makes it: from a message, Nuxt's fields, or another error.
|
|
17
|
+
*
|
|
18
|
+
* @param input - the message, the fields or the error.
|
|
19
|
+
*/
|
|
20
|
+
export declare const createError: (input: string | NuxtErrorInput | Error) => NuxtError;
|
|
21
|
+
/**
|
|
22
|
+
* Whether a value is an error Nuxt made.
|
|
23
|
+
*
|
|
24
|
+
* @param value - the value.
|
|
25
|
+
*/
|
|
26
|
+
export declare const isNuxtError: (value: unknown) => value is NuxtError;
|
|
27
|
+
/** The error `showError` set, if any. */
|
|
28
|
+
export declare const useError: () => Ref<NuxtError | undefined>;
|
|
29
|
+
/**
|
|
30
|
+
* Shows an error, as Nuxt's error page would: the story's `useError` returns it, and the call is recorded.
|
|
31
|
+
*
|
|
32
|
+
* @param input - the message, the fields or the error.
|
|
33
|
+
* @returns the error.
|
|
34
|
+
*/
|
|
35
|
+
export declare const showError: (input: string | NuxtErrorInput | Error) => NuxtError;
|
|
36
|
+
/**
|
|
37
|
+
* Clears the error, and goes where `redirect` says.
|
|
38
|
+
*
|
|
39
|
+
* @param options - where to go after.
|
|
40
|
+
*/
|
|
41
|
+
export declare const clearError: (options?: {
|
|
42
|
+
readonly redirect?: string;
|
|
43
|
+
}) => Promise<void>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { createError as createNuxtError, isNuxtError as isError } from "../nuxtError.js";
|
|
2
|
+
import { useNuxtStore } from "../nuxtStore.js";
|
|
3
|
+
/**
|
|
4
|
+
* An error as Nuxt makes it: from a message, Nuxt's fields, or another error.
|
|
5
|
+
*
|
|
6
|
+
* @param input - the message, the fields or the error.
|
|
7
|
+
*/
|
|
8
|
+
export const createError = (input) => createNuxtError(input);
|
|
9
|
+
/**
|
|
10
|
+
* Whether a value is an error Nuxt made.
|
|
11
|
+
*
|
|
12
|
+
* @param value - the value.
|
|
13
|
+
*/
|
|
14
|
+
export const isNuxtError = (value) => isError(value);
|
|
15
|
+
/** The error `showError` set, if any. */
|
|
16
|
+
export const useError = () => useNuxtStore().error;
|
|
17
|
+
/**
|
|
18
|
+
* Shows an error, as Nuxt's error page would: the story's `useError` returns it, and the call is recorded.
|
|
19
|
+
*
|
|
20
|
+
* @param input - the message, the fields or the error.
|
|
21
|
+
* @returns the error.
|
|
22
|
+
*/
|
|
23
|
+
export const showError = (input) => {
|
|
24
|
+
const store = useNuxtStore();
|
|
25
|
+
const error = createNuxtError(input);
|
|
26
|
+
store.error.value = error;
|
|
27
|
+
store.record("showError", [error.statusCode, error.message]);
|
|
28
|
+
return error;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Clears the error, and goes where `redirect` says.
|
|
32
|
+
*
|
|
33
|
+
* @param options - where to go after.
|
|
34
|
+
*/
|
|
35
|
+
export const clearError = async (options = {}) => {
|
|
36
|
+
const store = useNuxtStore();
|
|
37
|
+
store.error.value = undefined;
|
|
38
|
+
store.record("clearError", options.redirect === undefined ? [] : [options.redirect]);
|
|
39
|
+
if (options.redirect !== undefined)
|
|
40
|
+
await store.move(options.redirect, true);
|
|
41
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nuxt's `useFetch`, its lazy form and `$fetch` in a catalogue: `useAsyncData` with the story's `$fetch`.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* Its key is the request as it is made, so a story can write it: the URL with its query, the method before it when not
|
|
6
|
+
* GET, the body after it when there is one (`/api/products?page=2`, `POST /api/cart {"id":1}`). Nuxt's own key is a
|
|
7
|
+
* hash of the same, which a story could not write. Its URL, query, body and method may be refs or getters: a change
|
|
8
|
+
* makes another key, and another request, as in Nuxt, unless `watch: false`. Without the story's data for the key, the
|
|
9
|
+
* request goes out, and the catalogue's MSW handlers answer it.
|
|
10
|
+
*
|
|
11
|
+
* Internal: the code the plugin writes imports it (`#imports`, `#app`, `#components`); a story or a component imports
|
|
12
|
+
* Nuxt's names as in the app, never this module, whose exports may change in any release.
|
|
13
|
+
*
|
|
14
|
+
* @module
|
|
15
|
+
*/
|
|
16
|
+
import { type MaybeRefOrGetter } from "vue";
|
|
17
|
+
import { type FetchQuery, type StoryFetchOptions } from "../storyFetch.ts";
|
|
18
|
+
import { type AsyncData, type AsyncDataOptions } from "./data.ts";
|
|
19
|
+
/** What `useFetch` takes: the request's options, each of which may follow a ref, and `useAsyncData`'s. */
|
|
20
|
+
export type UseFetchOptions<TResult> = AsyncDataOptions<TResult> & Pick<StoryFetchOptions, "baseURL" | "responseType"> & {
|
|
21
|
+
/** The key the data is shared and given under; the request as it is made by default. */
|
|
22
|
+
readonly key?: string;
|
|
23
|
+
/** The request's method; GET by default. */
|
|
24
|
+
readonly method?: MaybeRefOrGetter<string>;
|
|
25
|
+
/** The search params, by name; each value may be a ref too. */
|
|
26
|
+
readonly query?: MaybeRefOrGetter<FetchQuery>;
|
|
27
|
+
/** `query`'s other name. */
|
|
28
|
+
readonly params?: MaybeRefOrGetter<FetchQuery>;
|
|
29
|
+
/** The body: an object or an array is sent as JSON. */
|
|
30
|
+
readonly body?: MaybeRefOrGetter<unknown>;
|
|
31
|
+
/** The headers. */
|
|
32
|
+
readonly headers?: MaybeRefOrGetter<HeadersInit>;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* The key of a request: the URL with its query, the method before it when not GET, the body after it.
|
|
36
|
+
*
|
|
37
|
+
* @param method - the method, in capitals.
|
|
38
|
+
* @param url - the URL.
|
|
39
|
+
* @param query - the search params.
|
|
40
|
+
* @param body - the body, if any.
|
|
41
|
+
*/
|
|
42
|
+
export declare const fetchKey: (method: string, url: string, query: FetchQuery, body: unknown) => string;
|
|
43
|
+
/**
|
|
44
|
+
* Fetches a URL, as `useAsyncData` with `$fetch`: the story's data for its key when it gives some, else the request.
|
|
45
|
+
*
|
|
46
|
+
* @param url - the URL, or a ref or getter that gives it.
|
|
47
|
+
* @param options - the request's options and `useAsyncData`'s.
|
|
48
|
+
*/
|
|
49
|
+
export declare const useFetch: <TResult = unknown>(url: MaybeRefOrGetter<string>, options?: UseFetchOptions<TResult>) => AsyncData<TResult> & Promise<AsyncData<TResult>>;
|
|
50
|
+
/**
|
|
51
|
+
* `useFetch` that does not hold what awaits it.
|
|
52
|
+
*
|
|
53
|
+
* @param url - the URL.
|
|
54
|
+
* @param options - its options.
|
|
55
|
+
*/
|
|
56
|
+
export declare const useLazyFetch: <TResult = unknown>(url: MaybeRefOrGetter<string>, options?: UseFetchOptions<TResult>) => AsyncData<TResult> & Promise<AsyncData<TResult>>;
|
|
57
|
+
/**
|
|
58
|
+
* Fetches a URL, as Nuxt's `$fetch` (ofetch), with the app's base path.
|
|
59
|
+
*
|
|
60
|
+
* @param request - the URL.
|
|
61
|
+
* @param options - the request's options.
|
|
62
|
+
*/
|
|
63
|
+
export declare const $fetch: <TResult = unknown>(request: string, options?: StoryFetchOptions) => Promise<TResult>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nuxt's `useFetch`, its lazy form and `$fetch` in a catalogue: `useAsyncData` with the story's `$fetch`.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* Its key is the request as it is made, so a story can write it: the URL with its query, the method before it when not
|
|
6
|
+
* GET, the body after it when there is one (`/api/products?page=2`, `POST /api/cart {"id":1}`). Nuxt's own key is a
|
|
7
|
+
* hash of the same, which a story could not write. Its URL, query, body and method may be refs or getters: a change
|
|
8
|
+
* makes another key, and another request, as in Nuxt, unless `watch: false`. Without the story's data for the key, the
|
|
9
|
+
* request goes out, and the catalogue's MSW handlers answer it.
|
|
10
|
+
*
|
|
11
|
+
* Internal: the code the plugin writes imports it (`#imports`, `#app`, `#components`); a story or a component imports
|
|
12
|
+
* Nuxt's names as in the app, never this module, whose exports may change in any release.
|
|
13
|
+
*
|
|
14
|
+
* @module
|
|
15
|
+
*/
|
|
16
|
+
import { computed, toValue } from "vue";
|
|
17
|
+
import { useNuxtStore } from "../nuxtStore.js";
|
|
18
|
+
import { withSearch } from "../storyFetch.js";
|
|
19
|
+
import { useAsyncData } from "./data.js";
|
|
20
|
+
/**
|
|
21
|
+
* A query whose values may be refs, read now.
|
|
22
|
+
*
|
|
23
|
+
* @param query - the query, or what gives it.
|
|
24
|
+
*/
|
|
25
|
+
const queryNow = (query) => Object.fromEntries(Object.entries(toValue(query) ?? {}).map(([name, value]) => [name, toValue(value)]));
|
|
26
|
+
/**
|
|
27
|
+
* The key of a request: the URL with its query, the method before it when not GET, the body after it.
|
|
28
|
+
*
|
|
29
|
+
* @param method - the method, in capitals.
|
|
30
|
+
* @param url - the URL.
|
|
31
|
+
* @param query - the search params.
|
|
32
|
+
* @param body - the body, if any.
|
|
33
|
+
*/
|
|
34
|
+
export const fetchKey = (method, url, query, body) => `${method === "GET" ? "" : `${method} `}${withSearch(url, query)}${body === undefined ? "" : ` ${JSON.stringify(body)}`}`;
|
|
35
|
+
/**
|
|
36
|
+
* Fetches a URL, as `useAsyncData` with `$fetch`: the story's data for its key when it gives some, else the request.
|
|
37
|
+
*
|
|
38
|
+
* @param url - the URL, or a ref or getter that gives it.
|
|
39
|
+
* @param options - the request's options and `useAsyncData`'s.
|
|
40
|
+
*/
|
|
41
|
+
export const useFetch = (url, options = {}) => {
|
|
42
|
+
const store = useNuxtStore();
|
|
43
|
+
const method = () => (toValue(options.method) ?? "GET").toUpperCase();
|
|
44
|
+
const query = () => queryNow(options.query ?? options.params);
|
|
45
|
+
const key = computed(() => options.key ?? fetchKey(method(), toValue(url), query(), toValue(options.body)));
|
|
46
|
+
const headers = toValue(options.headers);
|
|
47
|
+
return useAsyncData(key, (_app, { signal }) => {
|
|
48
|
+
const body = toValue(options.body);
|
|
49
|
+
return store.fetch(toValue(url), {
|
|
50
|
+
method: method(),
|
|
51
|
+
query: query(),
|
|
52
|
+
signal,
|
|
53
|
+
...(body === undefined ? {} : { body }),
|
|
54
|
+
...(headers === undefined ? {} : { headers }),
|
|
55
|
+
...(options.baseURL === undefined ? {} : { baseURL: options.baseURL }),
|
|
56
|
+
...(options.responseType === undefined ? {} : { responseType: options.responseType })
|
|
57
|
+
});
|
|
58
|
+
}, options);
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* `useFetch` that does not hold what awaits it.
|
|
62
|
+
*
|
|
63
|
+
* @param url - the URL.
|
|
64
|
+
* @param options - its options.
|
|
65
|
+
*/
|
|
66
|
+
export const useLazyFetch = (url, options = {}) => useFetch(url, { ...options, lazy: true });
|
|
67
|
+
/**
|
|
68
|
+
* Fetches a URL, as Nuxt's `$fetch` (ofetch), with the app's base path.
|
|
69
|
+
*
|
|
70
|
+
* @param request - the URL.
|
|
71
|
+
* @param options - the request's options.
|
|
72
|
+
*/
|
|
73
|
+
export const $fetch = (request, options) => useNuxtStore().fetch(request, options);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nuxt's head composables in a catalogue: `useHead`, `useSeoMeta` and their server and safe forms take what a
|
|
3
|
+
* component sets and leave the frame's document alone, since the frame's head is the catalogue's.
|
|
4
|
+
*
|
|
5
|
+
* Internal: the code the plugin writes imports it (`#imports`, `#app`, `#components`); a story or a component imports
|
|
6
|
+
* Nuxt's names as in the app, never this module, whose exports may change in any release.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
/** What a head composable returns: what changes the entry, and what removes it; neither has anything to do. */
|
|
11
|
+
export type HeadEntry = {
|
|
12
|
+
/** Changes what the entry set. */
|
|
13
|
+
readonly patch: (input: unknown) => void;
|
|
14
|
+
/** Removes the entry. */
|
|
15
|
+
readonly dispose: () => void;
|
|
16
|
+
};
|
|
17
|
+
/** Sets the page's head: the frame's head is the catalogue's, so nothing changes. */
|
|
18
|
+
export declare const useHead: () => HeadEntry;
|
|
19
|
+
/** Sets the page's head from values it escapes: nothing changes in a story. */
|
|
20
|
+
export declare const useHeadSafe: () => HeadEntry;
|
|
21
|
+
/** Sets the page's meta tags: nothing changes in a story. */
|
|
22
|
+
export declare const useSeoMeta: () => HeadEntry;
|
|
23
|
+
/** Sets the head on the server only: nothing, in the page. */
|
|
24
|
+
export declare const useServerHead: () => HeadEntry;
|
|
25
|
+
/** Sets the head on the server only, from values it escapes: nothing, in the page. */
|
|
26
|
+
export declare const useServerHeadSafe: () => HeadEntry;
|
|
27
|
+
/** Sets the meta tags on the server only: nothing, in the page. */
|
|
28
|
+
export declare const useServerSeoMeta: () => HeadEntry;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nuxt's head composables in a catalogue: `useHead`, `useSeoMeta` and their server and safe forms take what a
|
|
3
|
+
* component sets and leave the frame's document alone, since the frame's head is the catalogue's.
|
|
4
|
+
*
|
|
5
|
+
* Internal: the code the plugin writes imports it (`#imports`, `#app`, `#components`); a story or a component imports
|
|
6
|
+
* Nuxt's names as in the app, never this module, whose exports may change in any release.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
/** An entry with nothing to change or remove. */
|
|
11
|
+
const ENTRY = { patch: () => undefined, dispose: () => undefined };
|
|
12
|
+
/** Sets the page's head: the frame's head is the catalogue's, so nothing changes. */
|
|
13
|
+
export const useHead = () => ENTRY;
|
|
14
|
+
/** Sets the page's head from values it escapes: nothing changes in a story. */
|
|
15
|
+
export const useHeadSafe = () => ENTRY;
|
|
16
|
+
/** Sets the page's meta tags: nothing changes in a story. */
|
|
17
|
+
export const useSeoMeta = () => ENTRY;
|
|
18
|
+
/** Sets the head on the server only: nothing, in the page. */
|
|
19
|
+
export const useServerHead = () => ENTRY;
|
|
20
|
+
/** Sets the head on the server only, from values it escapes: nothing, in the page. */
|
|
21
|
+
export const useServerHeadSafe = () => ENTRY;
|
|
22
|
+
/** Sets the meta tags on the server only: nothing, in the page. */
|
|
23
|
+
export const useServerSeoMeta = () => ENTRY;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { RouteLocationNormalizedLoaded, RouteLocationRaw, Router } from "vue-router";
|
|
2
|
+
/** What `navigateTo` takes besides where to go. */
|
|
3
|
+
export type NavigateToOptions = {
|
|
4
|
+
/** Whether it replaces the history's entry instead of adding one. */
|
|
5
|
+
readonly replace?: boolean;
|
|
6
|
+
/** The HTTP status of a redirect on the server: no effect in a story. */
|
|
7
|
+
readonly redirectCode?: number;
|
|
8
|
+
/** Whether the location is outside the app, which Nuxt requires for another origin. */
|
|
9
|
+
readonly external?: boolean;
|
|
10
|
+
/** Opens the location in a new window, as `window.open` would, with its target and features. */
|
|
11
|
+
readonly open?: {
|
|
12
|
+
readonly target?: string;
|
|
13
|
+
readonly windowFeatures?: Readonly<Record<string, unknown>>;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* The story's route, which follows its router: vue-router's `useRoute` in a component's setup, the router's current
|
|
18
|
+
* route elsewhere, as Nuxt's falls back to its app's.
|
|
19
|
+
*/
|
|
20
|
+
export declare const useRoute: () => RouteLocationNormalizedLoaded;
|
|
21
|
+
/** The story's router: vue-router's own, its moves recorded. */
|
|
22
|
+
export declare const useRouter: () => Router;
|
|
23
|
+
/**
|
|
24
|
+
* Goes somewhere, as Nuxt's `navigateTo`: inside the app the story's router moves; another origin, or a new window, is
|
|
25
|
+
* recorded and left alone, so the story's frame stays where it is.
|
|
26
|
+
*
|
|
27
|
+
* @param to - where to go: a path, or a location.
|
|
28
|
+
* @param options - whether it replaces, whether it is external, whether it opens a window.
|
|
29
|
+
* @returns what the router's move returns; nothing for a navigation the story does not make.
|
|
30
|
+
* @throws a navigation to another origin without `external: true`, as Nuxt throws it.
|
|
31
|
+
*/
|
|
32
|
+
export declare const navigateTo: (to: RouteLocationRaw | undefined | null, options?: NavigateToOptions) => Promise<unknown>;
|
|
33
|
+
/**
|
|
34
|
+
* Stops a navigation from a route middleware: there is none in a story, so it returns `false`, as a middleware's
|
|
35
|
+
* `return false` does.
|
|
36
|
+
*/
|
|
37
|
+
export declare const abortNavigation: () => false;
|
|
38
|
+
/**
|
|
39
|
+
* A route middleware, as Nuxt defines one: the function itself, since a story runs no middleware.
|
|
40
|
+
*
|
|
41
|
+
* @param middleware - the middleware.
|
|
42
|
+
*/
|
|
43
|
+
export declare const defineNuxtRouteMiddleware: <TMiddleware>(middleware: TMiddleware) => TMiddleware;
|
|
44
|
+
/** Adds a route middleware: none runs in a story, so it does nothing. */
|
|
45
|
+
export declare const addRouteMiddleware: () => void;
|
|
46
|
+
/** A page's meta: read by Nuxt when it builds its routes, never at run time, so it does nothing in a story. */
|
|
47
|
+
export declare const definePageMeta: () => void;
|
|
48
|
+
/**
|
|
49
|
+
* A route's rules, as Nuxt 4 reads them at build time: nothing at run time.
|
|
50
|
+
*/
|
|
51
|
+
export declare const defineRouteRules: () => void;
|
|
52
|
+
/**
|
|
53
|
+
* Sets the page's layout: a story has no layout, so the call is recorded.
|
|
54
|
+
*
|
|
55
|
+
* @param layout - the layout's name.
|
|
56
|
+
*/
|
|
57
|
+
export declare const setPageLayout: (layout: string) => void;
|
|
58
|
+
/** Preloads a route's components: there is nothing to load in a story. */
|
|
59
|
+
export declare const preloadRouteComponents: () => Promise<void>;
|
|
60
|
+
/** Preloads components by name: they load when a story draws them. */
|
|
61
|
+
export declare const preloadComponents: () => Promise<void>;
|
|
62
|
+
/** Prefetches components by name: they load when a story draws them. */
|
|
63
|
+
export declare const prefetchComponents: () => Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* Reloads the app: recorded, since reloading the frame would start the story over.
|
|
66
|
+
*
|
|
67
|
+
* @param options - Nuxt's options (`path`, `force`, `persistState`).
|
|
68
|
+
*/
|
|
69
|
+
export declare const reloadNuxtApp: (options?: Readonly<Record<string, unknown>>) => void;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nuxt's router composables in a catalogue: `useRoute` and `useRouter` are vue-router's own, on the story's router;
|
|
3
|
+
* `navigateTo` moves it, and records where an external or new-window navigation would have gone instead of leaving the
|
|
4
|
+
* story's frame.
|
|
5
|
+
*
|
|
6
|
+
* @remarks
|
|
7
|
+
* What Nuxt does with a page (its meta, its layout, its middleware, preloading its code) has no page to act on in a
|
|
8
|
+
* story, so those functions take their arguments and do nothing, and a story's component is drawn as it is.
|
|
9
|
+
*
|
|
10
|
+
* Internal: the code the plugin writes imports it (`#imports`, `#app`, `#components`); a story or a component imports
|
|
11
|
+
* Nuxt's names as in the app, never this module, whose exports may change in any release.
|
|
12
|
+
*
|
|
13
|
+
* @module
|
|
14
|
+
*/
|
|
15
|
+
import { hasInjectionContext } from "vue";
|
|
16
|
+
import { useRoute as useVueRoute } from "vue-router";
|
|
17
|
+
import { useNuxtStore } from "../nuxtStore.js";
|
|
18
|
+
/** Whether an address names another origin, or a protocol other than the web's. */
|
|
19
|
+
const isExternal = (to) => typeof to === "string" && (/^[a-z][a-z\d+.-]*:/i.test(to) || to.startsWith("//"));
|
|
20
|
+
/**
|
|
21
|
+
* The story's route, which follows its router: vue-router's `useRoute` in a component's setup, the router's current
|
|
22
|
+
* route elsewhere, as Nuxt's falls back to its app's.
|
|
23
|
+
*/
|
|
24
|
+
export const useRoute = () => hasInjectionContext() ? useVueRoute() : useNuxtStore().router.currentRoute.value;
|
|
25
|
+
/** The story's router: vue-router's own, its moves recorded. */
|
|
26
|
+
export const useRouter = () => useNuxtStore().router;
|
|
27
|
+
/**
|
|
28
|
+
* Goes somewhere, as Nuxt's `navigateTo`: inside the app the story's router moves; another origin, or a new window, is
|
|
29
|
+
* recorded and left alone, so the story's frame stays where it is.
|
|
30
|
+
*
|
|
31
|
+
* @param to - where to go: a path, or a location.
|
|
32
|
+
* @param options - whether it replaces, whether it is external, whether it opens a window.
|
|
33
|
+
* @returns what the router's move returns; nothing for a navigation the story does not make.
|
|
34
|
+
* @throws a navigation to another origin without `external: true`, as Nuxt throws it.
|
|
35
|
+
*/
|
|
36
|
+
export const navigateTo = async (to, options = {}) => {
|
|
37
|
+
const store = useNuxtStore();
|
|
38
|
+
const target = to ?? "/";
|
|
39
|
+
const path = typeof target === "string" ? target : store.router.resolve(target).fullPath;
|
|
40
|
+
const flags = {
|
|
41
|
+
...(options.replace === true ? { replace: true } : {}),
|
|
42
|
+
...(options.external === true ? { external: true } : {}),
|
|
43
|
+
...(options.open === undefined ? {} : { open: true })
|
|
44
|
+
};
|
|
45
|
+
store.record("navigateTo", Object.keys(flags).length === 0 ? [path] : [path, flags]);
|
|
46
|
+
// a new window, or a navigation that leaves the app (a full page load), would leave the story's frame
|
|
47
|
+
if (options.open !== undefined || options.external === true)
|
|
48
|
+
return undefined;
|
|
49
|
+
if (isExternal(target))
|
|
50
|
+
throw new Error("Navigating to an external URL is not allowed by default. Use `navigateTo(url, { external: true })`.");
|
|
51
|
+
return store.move(target, options.replace === true);
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Stops a navigation from a route middleware: there is none in a story, so it returns `false`, as a middleware's
|
|
55
|
+
* `return false` does.
|
|
56
|
+
*/
|
|
57
|
+
export const abortNavigation = () => false;
|
|
58
|
+
/**
|
|
59
|
+
* A route middleware, as Nuxt defines one: the function itself, since a story runs no middleware.
|
|
60
|
+
*
|
|
61
|
+
* @param middleware - the middleware.
|
|
62
|
+
*/
|
|
63
|
+
export const defineNuxtRouteMiddleware = (middleware) => middleware;
|
|
64
|
+
/** Adds a route middleware: none runs in a story, so it does nothing. */
|
|
65
|
+
export const addRouteMiddleware = () => undefined;
|
|
66
|
+
/** A page's meta: read by Nuxt when it builds its routes, never at run time, so it does nothing in a story. */
|
|
67
|
+
export const definePageMeta = () => undefined;
|
|
68
|
+
/**
|
|
69
|
+
* A route's rules, as Nuxt 4 reads them at build time: nothing at run time.
|
|
70
|
+
*/
|
|
71
|
+
export const defineRouteRules = () => undefined;
|
|
72
|
+
/**
|
|
73
|
+
* Sets the page's layout: a story has no layout, so the call is recorded.
|
|
74
|
+
*
|
|
75
|
+
* @param layout - the layout's name.
|
|
76
|
+
*/
|
|
77
|
+
export const setPageLayout = (layout) => {
|
|
78
|
+
useNuxtStore().record("setPageLayout", [layout]);
|
|
79
|
+
};
|
|
80
|
+
/** Preloads a route's components: there is nothing to load in a story. */
|
|
81
|
+
export const preloadRouteComponents = async () => undefined;
|
|
82
|
+
/** Preloads components by name: they load when a story draws them. */
|
|
83
|
+
export const preloadComponents = async () => undefined;
|
|
84
|
+
/** Prefetches components by name: they load when a story draws them. */
|
|
85
|
+
export const prefetchComponents = async () => undefined;
|
|
86
|
+
/**
|
|
87
|
+
* Reloads the app: recorded, since reloading the frame would start the story over.
|
|
88
|
+
*
|
|
89
|
+
* @param options - Nuxt's options (`path`, `force`, `persistState`).
|
|
90
|
+
*/
|
|
91
|
+
export const reloadNuxtApp = (options = {}) => {
|
|
92
|
+
useNuxtStore().record("reloadNuxtApp", [options]);
|
|
93
|
+
};
|