@vesperjs/vue 0.1.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/dist/index.mjs ADDED
@@ -0,0 +1,282 @@
1
+ import { computed, ref } from "@vue/reactivity";
2
+ import { persistentAtom } from "@nanostores/persistent";
3
+ import { ofetch } from "ofetch";
4
+ import { createI18n } from "vue-i18n";
5
+ //#region src/stores/nano/base-url.ts
6
+ const $baseUrl = persistentAtom("baseURL", "");
7
+ persistentAtom("timeZone", "");
8
+ //#endregion
9
+ //#region src/stores/use-base-url-store.ts
10
+ function useBaseUrlStore() {
11
+ return { baseURL: computed({
12
+ get() {
13
+ return $baseUrl.get();
14
+ },
15
+ set(value) {
16
+ $baseUrl.set(value);
17
+ }
18
+ }) };
19
+ }
20
+ //#endregion
21
+ //#region src/composables/backend/api/use-api-constants.ts
22
+ function useApiConstants() {
23
+ const { baseURL } = useBaseUrlStore();
24
+ return { baseURL };
25
+ }
26
+ //#endregion
27
+ //#region src/composables/backend/api/use-ofetch.ts
28
+ const useOFetch = async (url, options) => {
29
+ const pending = ref(true);
30
+ const data = ref();
31
+ const error = ref();
32
+ try {
33
+ data.value = await ofetch(url, options);
34
+ } catch (err) {
35
+ error.value = err;
36
+ }
37
+ pending.value = false;
38
+ return {
39
+ data: data.value,
40
+ error: error.value,
41
+ pending: pending.value
42
+ };
43
+ };
44
+ //#endregion
45
+ //#region src/i18n/i18n.ts
46
+ const i18n = createI18n({
47
+ legacy: false,
48
+ locale: "en",
49
+ fallbackLocale: "en",
50
+ messages: {
51
+ en: { backend: { error: {
52
+ api: "An error has occurred.({message})",
53
+ login: "Please log in.",
54
+ not_found: "This {source} has been deleted."
55
+ } } },
56
+ ja: { backend: { error: {
57
+ api: "不具合が発生しました。({message})",
58
+ login: "ログインしなおしてください。",
59
+ not_found: "この{source}は削除されています。"
60
+ } } }
61
+ }
62
+ });
63
+ //#endregion
64
+ //#region src/composables/use-locale.ts
65
+ const useLocale = () => {
66
+ const { locale, availableLocales, fallbackLocale } = i18n.global;
67
+ const autoDetect = () => {
68
+ const viewLocale = globalThis.navigator.languages[0];
69
+ locale.value = availableLocales.includes(viewLocale) ? viewLocale : fallbackLocale.value;
70
+ };
71
+ return {
72
+ locale,
73
+ autoDetect
74
+ };
75
+ };
76
+ //#endregion
77
+ //#region src/composables/backend/api/use-http-headers.ts
78
+ const useHttpHeaders = () => {
79
+ const { locale } = useLocale();
80
+ return { commonHeaders: computed(() => ({
81
+ "X-Requested-With": "XMLHttpRequest",
82
+ Accept: "application/json",
83
+ "Accept-Language": locale.value
84
+ })) };
85
+ };
86
+ //#endregion
87
+ //#region src/composables/backend/api/use-query-api.ts
88
+ const useQueryApi = async (url, options) => {
89
+ const { commonHeaders } = useHttpHeaders();
90
+ const { baseURL } = useApiConstants();
91
+ const tokenRef = ref();
92
+ const headers = commonHeaders.value;
93
+ if (options?.token) {
94
+ headers.Authorization = `Bearer ${options.token}`;
95
+ tokenRef.value = options.token;
96
+ }
97
+ const getOptions = {
98
+ baseURL: baseURL.value,
99
+ method: "get",
100
+ query: options?.query ?? {},
101
+ headers,
102
+ onResponse({ response }) {
103
+ if (!tokenRef.value) tokenRef.value = response.headers.get("Authorization")?.split(" ")[1];
104
+ }
105
+ };
106
+ if (options?.signal) getOptions.signal = options.signal;
107
+ if (options?.onRequestError) getOptions.onRequestError = options.onRequestError;
108
+ if (options?.onResponseError) getOptions.onResponseError = options.onResponseError;
109
+ const { data, error, pending } = await useOFetch(url, getOptions);
110
+ return {
111
+ token: tokenRef.value,
112
+ data,
113
+ error,
114
+ pending
115
+ };
116
+ };
117
+ //#endregion
118
+ //#region src/composables/backend/api/use-mutation-api.ts
119
+ const useMutationApi = async (url, { method, body = {}, token = null, onRequestError, onResponseError }) => {
120
+ const { commonHeaders } = useHttpHeaders();
121
+ const { baseURL } = useApiConstants();
122
+ const headers = commonHeaders.value;
123
+ const tokenRef = ref();
124
+ if (token) {
125
+ headers.Authorization = `Bearer ${token}`;
126
+ tokenRef.value = token;
127
+ }
128
+ const options = {
129
+ baseURL: baseURL.value,
130
+ headers,
131
+ method
132
+ };
133
+ if (onRequestError) options.onRequestError = onRequestError;
134
+ if (onResponseError) options.onResponseError = onResponseError;
135
+ if (method == "post" || method == "put") {
136
+ options.body = body;
137
+ options.onResponse = ({ response }) => {
138
+ if (method == "post" && !tokenRef.value || method == "put") tokenRef.value = response.headers.get("Authorization")?.split(" ")[1];
139
+ };
140
+ }
141
+ const { data, error, pending } = await useOFetch(url, options);
142
+ return {
143
+ token: tokenRef.value,
144
+ data,
145
+ error,
146
+ pending
147
+ };
148
+ };
149
+ //#endregion
150
+ //#region src/composables/backend/error/use-external-errors.ts
151
+ function useExternalErrors({ flash }) {
152
+ const errors = ref({});
153
+ const externalErrors = computed({
154
+ get() {
155
+ return errors.value;
156
+ },
157
+ set(value) {
158
+ if (errors.value) for (const key in value) errors.value[key] = value[key] ?? [];
159
+ }
160
+ });
161
+ const clearExternalErrors = () => {
162
+ externalErrors.value = {};
163
+ };
164
+ const isSuccess = () => {
165
+ let result = true;
166
+ for (const key in errors.value) if (errors.value[key].length > 0) result = false;
167
+ if (flash.value.alert) result = false;
168
+ return result;
169
+ };
170
+ return {
171
+ externalErrors,
172
+ clearExternalErrors,
173
+ isSuccess
174
+ };
175
+ }
176
+ //#endregion
177
+ //#region src/composables/backend/error/use-backend-error-info.ts
178
+ function useBackendErrorInfo() {
179
+ const info = ref({});
180
+ const backendErrorInfo = computed(() => {
181
+ return info.value;
182
+ });
183
+ const clearBackendErrorInfo = () => {
184
+ info.value = {};
185
+ };
186
+ return {
187
+ backendErrorInfo,
188
+ clearBackendErrorInfo
189
+ };
190
+ }
191
+ //#endregion
192
+ //#region src/composables/backend/use-alert.ts
193
+ function useAlert({ flash, caller }) {
194
+ const { backendErrorInfo, clearBackendErrorInfo } = useBackendErrorInfo();
195
+ const setError = function(error, options) {
196
+ const off = options?.off ?? false;
197
+ clearBackendErrorInfo();
198
+ backendErrorInfo.value.status = error.status;
199
+ if (off) switch (error.status) {
200
+ case 401:
201
+ if (caller && "clearAccount" in caller && caller.clearAccount) caller.clearAccount();
202
+ break;
203
+ }
204
+ else switch (error.status) {
205
+ case 401:
206
+ flash.value.alert = i18n.global.t("backend.error.login");
207
+ if (caller && "clearAccount" in caller && caller.clearAccount) caller.clearAccount();
208
+ break;
209
+ case 404:
210
+ {
211
+ const backendError = error.data;
212
+ backendErrorInfo.value.error = backendError;
213
+ }
214
+ break;
215
+ case 422:
216
+ if (caller && "externalErrors" in caller && caller.externalErrors && error.data) {
217
+ const { errors } = error.data;
218
+ caller.externalErrors.value = errors;
219
+ }
220
+ break;
221
+ default: flash.value.alert = i18n.global.t("backend.error.api", { message: error.message });
222
+ }
223
+ };
224
+ const reload = () => {
225
+ if (backendErrorInfo.value.status == 404) globalThis.setTimeout(() => {
226
+ globalThis.location.reload();
227
+ }, 1e3);
228
+ };
229
+ return {
230
+ backendErrorInfo,
231
+ setError,
232
+ reload
233
+ };
234
+ }
235
+ //#endregion
236
+ //#region src/composables/util/use-date.ts
237
+ function useDate() {
238
+ const isValidDate = (str) => {
239
+ return !!str && !!str.match(/\d{4}\/\d{2}\/\d{2}/) && !isNaN(Date.parse(str));
240
+ };
241
+ return { isValidDate };
242
+ }
243
+ //#endregion
244
+ //#region src/composables/use-entity.ts
245
+ function useEntity() {
246
+ const create = ({ from }) => {
247
+ const model = {};
248
+ Object.assign(model, from);
249
+ return model;
250
+ };
251
+ const copy = ({ from, to }) => {
252
+ Object.assign(to, from);
253
+ };
254
+ return {
255
+ create,
256
+ copy
257
+ };
258
+ }
259
+ //#endregion
260
+ //#region src/composables/use-flash.ts
261
+ function useFlash() {
262
+ const flash = ref({});
263
+ const clearFlash = () => {
264
+ flash.value = {};
265
+ };
266
+ return {
267
+ flash,
268
+ clearFlash
269
+ };
270
+ }
271
+ //#endregion
272
+ //#region src/composables/use-nano-route.ts
273
+ function useNanoRoute(router) {
274
+ const page = router.get();
275
+ return {
276
+ params: page?.params,
277
+ query: page?.search,
278
+ path: page?.path
279
+ };
280
+ }
281
+ //#endregion
282
+ export { i18n, useAlert, useApiConstants, useDate, useEntity, useExternalErrors, useFlash, useLocale, useMutationApi, useNanoRoute, useOFetch, useQueryApi };
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@vesperjs/vue",
3
+ "version": "0.1.0",
4
+ "keywords": [
5
+ "vue.js"
6
+ ],
7
+ "license": "MIT",
8
+ "author": "Yasumada Ashida",
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "type": "module",
13
+ "exports": {
14
+ ".": "./dist/index.mjs",
15
+ "./package.json": "./package.json"
16
+ },
17
+ "dependencies": {
18
+ "@formkit/tempo": "^1.0.0",
19
+ "@nanostores/persistent": "^1.3.3",
20
+ "@nanostores/router": "^1.0.0",
21
+ "@vue/reactivity": "^3.6.0-beta.8",
22
+ "nanostores": "^1.2.0",
23
+ "ofetch": "1.5.1",
24
+ "undici": "7.24.4",
25
+ "vue-i18n": "11.3.0"
26
+ },
27
+ "devDependencies": {
28
+ "@typescript-eslint/eslint-plugin": "^8.57.0",
29
+ "@typescript-eslint/parser": "^8.57.0",
30
+ "@vue/eslint-config-typescript": "^14.7.0",
31
+ "eslint": "^9.39.4",
32
+ "eslint-plugin-vue": "^10.8.0",
33
+ "oxfmt": "^0.41.0",
34
+ "tsdown": "^0.21.4",
35
+ "typescript": "5.9.3"
36
+ },
37
+ "scripts": {
38
+ "build": "tsdown --dts",
39
+ "build:check": "tsc--noEmit",
40
+ "lint": "eslint --fix './src/**/*.{js,ts}'",
41
+ "fmt": "oxfmt",
42
+ "fmt:check": "oxfmt --check"
43
+ }
44
+ }