@brickflow/http 0.0.13 → 0.0.14
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 +406 -0
- package/dist/module.d.mts +73 -0
- package/dist/module.json +12 -0
- package/dist/module.mjs +59 -0
- package/dist/runtime/composables/useHttp.d.ts +27 -0
- package/dist/runtime/composables/useHttp.js +197 -0
- package/dist/runtime/http/client.d.ts +3 -0
- package/dist/runtime/http/client.js +217 -0
- package/dist/runtime/plugin.d.ts +7 -0
- package/dist/runtime/plugin.js +56 -0
- package/dist/runtime/types.d.ts +21 -0
- package/dist/runtime/utils/helpers.d.ts +5 -0
- package/dist/runtime/utils/helpers.js +14 -0
- package/dist/runtime/utils/index.d.ts +6 -0
- package/dist/runtime/utils/index.js +5 -0
- package/dist/runtime/utils/indexeddb.d.ts +14 -0
- package/dist/runtime/utils/indexeddb.js +222 -0
- package/dist/runtime/utils/middleware.d.ts +8 -0
- package/dist/runtime/utils/middleware.js +20 -0
- package/dist/runtime/utils/shared.d.ts +83 -0
- package/dist/runtime/utils/shared.js +50 -0
- package/dist/runtime/utils/typed.d.ts +46 -0
- package/dist/runtime/utils/typed.js +9 -0
- package/dist/types.d.mts +11 -0
- package/package.json +22 -4
- package/CHANGELOG.md +0 -79
- package/eslint.config.mjs +0 -1
- package/prettier.config.mjs +0 -1
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { useLazyAsyncData, useNuxtApp, useRuntimeConfig, useState } from "nuxt/app";
|
|
2
|
+
import { onScopeDispose, shallowReactive, shallowRef } from "vue";
|
|
3
|
+
import { dbDeleteKeysWithPart, dbGet, dbSafeSet, getRandom, hashData } from "../utils/index.js";
|
|
4
|
+
import {
|
|
5
|
+
createHttpUrl,
|
|
6
|
+
createNetworkError,
|
|
7
|
+
isHttpErrorPayload
|
|
8
|
+
} from "../utils/shared.js";
|
|
9
|
+
const CHANNEL_NAME = "brickflow-http-tab-sync";
|
|
10
|
+
let channel;
|
|
11
|
+
export async function useHttp(options) {
|
|
12
|
+
const app = useNuxtApp();
|
|
13
|
+
const runtimeConfig = useRuntimeConfig();
|
|
14
|
+
const httpConfig = runtimeConfig.public.brickflowHttp;
|
|
15
|
+
const mapParams = (params) => {
|
|
16
|
+
if (options.mapParams) {
|
|
17
|
+
return options.mapParams(params ?? {});
|
|
18
|
+
}
|
|
19
|
+
return params ?? {};
|
|
20
|
+
};
|
|
21
|
+
const cacheEnabled = httpConfig.cache && !(httpConfig.disableCacheInDev && import.meta.dev);
|
|
22
|
+
const initFullUrl = createHttpUrl(options.url, mapParams(options.initParams));
|
|
23
|
+
let hasDataFromServer = false;
|
|
24
|
+
const result = shallowReactive({
|
|
25
|
+
data: null,
|
|
26
|
+
error: null,
|
|
27
|
+
fetch: async () => await void 0,
|
|
28
|
+
hasFirstData: false,
|
|
29
|
+
hasFreshData: false,
|
|
30
|
+
pending: true,
|
|
31
|
+
pendingCache: true
|
|
32
|
+
});
|
|
33
|
+
const controller = new AbortController();
|
|
34
|
+
const serverData = useState(`http:${initFullUrl}`, () => null);
|
|
35
|
+
if (options.server && import.meta.server) {
|
|
36
|
+
const paramsReactive = shallowRef(mapParams(options.initParams));
|
|
37
|
+
const ssr = await useLazyAsyncData(initFullUrl, async () => {
|
|
38
|
+
return await app.$http.get(options.url, {
|
|
39
|
+
params: paramsReactive.value
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
result.fetch = async (params) => {
|
|
43
|
+
paramsReactive.value = mapParams(params);
|
|
44
|
+
await ssr.refresh();
|
|
45
|
+
};
|
|
46
|
+
const payload = ssr.data.value?.data ?? null;
|
|
47
|
+
serverData.value = payload;
|
|
48
|
+
if (payload === null) {
|
|
49
|
+
result.pending = false;
|
|
50
|
+
result.pendingCache = false;
|
|
51
|
+
} else {
|
|
52
|
+
applyPayload(payload, result);
|
|
53
|
+
result.hasFirstData = true;
|
|
54
|
+
result.hasFreshData = true;
|
|
55
|
+
result.pending = false;
|
|
56
|
+
result.pendingCache = false;
|
|
57
|
+
options.effect?.(payload, {
|
|
58
|
+
cached: false,
|
|
59
|
+
params: mapParams(options.initParams)
|
|
60
|
+
});
|
|
61
|
+
if (!isHttpErrorPayload(payload)) {
|
|
62
|
+
hasDataFromServer = true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (import.meta.client) {
|
|
67
|
+
let onMessage = function(event) {
|
|
68
|
+
if (!event.data.fullUrl || !fullUrlHistory[event.data.fullUrl] || event.data.data === void 0) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const payload = event.data.data;
|
|
72
|
+
applyPayload(payload, result);
|
|
73
|
+
result.hasFirstData = true;
|
|
74
|
+
result.hasFreshData = true;
|
|
75
|
+
options.effect?.(payload, {
|
|
76
|
+
cached: false,
|
|
77
|
+
params: event.data.params ?? mapParams()
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
const fullUrlHistory = {};
|
|
81
|
+
const clientChannel = getChannel();
|
|
82
|
+
clientChannel?.addEventListener("message", onMessage);
|
|
83
|
+
if (serverData.value !== null) {
|
|
84
|
+
applyPayload(serverData.value, result);
|
|
85
|
+
result.pending = false;
|
|
86
|
+
result.pendingCache = false;
|
|
87
|
+
result.hasFirstData = true;
|
|
88
|
+
result.hasFreshData = true;
|
|
89
|
+
}
|
|
90
|
+
const raceCondition = {};
|
|
91
|
+
const runFetch = async (params, fetchOpt) => {
|
|
92
|
+
const mappedParams = mapParams(params);
|
|
93
|
+
const fullUrl = createHttpUrl(options.url, mappedParams);
|
|
94
|
+
const fetchId = Date.now() + getRandom(0, 300);
|
|
95
|
+
if (raceCondition[fullUrl]) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
raceCondition[fullUrl] = fetchId;
|
|
99
|
+
try {
|
|
100
|
+
result.pending = true;
|
|
101
|
+
result.pendingCache = true;
|
|
102
|
+
const cachedFetch = cacheEnabled && httpConfig.cacheDbName && httpConfig.cacheStoreName ? await dbGet(fullUrl, "smart-cache-v2", httpConfig.cacheStoreName) : null;
|
|
103
|
+
if (cachedFetch) {
|
|
104
|
+
applyPayload(cachedFetch.value, result);
|
|
105
|
+
result.hasFirstData = true;
|
|
106
|
+
result.pendingCache = false;
|
|
107
|
+
options.effect?.(cachedFetch.value, {
|
|
108
|
+
cached: true,
|
|
109
|
+
params: mappedParams
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (controller.signal.aborted || fetchOpt?.signal?.aborted) {
|
|
113
|
+
throw new DOMException("Aborted", "AbortError");
|
|
114
|
+
}
|
|
115
|
+
const signal = fetchOpt?.signal ? [controller.signal, fetchOpt.signal] : controller.signal;
|
|
116
|
+
const response = await app.$http.get(options.url, {
|
|
117
|
+
params: mappedParams,
|
|
118
|
+
signal
|
|
119
|
+
});
|
|
120
|
+
applyPayload(response.data, result);
|
|
121
|
+
result.hasFirstData = true;
|
|
122
|
+
result.hasFreshData = true;
|
|
123
|
+
fullUrlHistory[fullUrl] = true;
|
|
124
|
+
clientChannel?.postMessage({
|
|
125
|
+
data: normalizeBroadcastValue(response.data),
|
|
126
|
+
fullUrl,
|
|
127
|
+
params: normalizeBroadcastValue(mappedParams),
|
|
128
|
+
type: "STATE_UPDATE"
|
|
129
|
+
});
|
|
130
|
+
options.effect?.(response.data, {
|
|
131
|
+
cached: false,
|
|
132
|
+
params: mappedParams
|
|
133
|
+
});
|
|
134
|
+
if (cacheEnabled && response.status === 200) {
|
|
135
|
+
if (cachedFetch !== null) {
|
|
136
|
+
const currentHash = await hashData(response.data);
|
|
137
|
+
if (currentHash !== cachedFetch.hash) {
|
|
138
|
+
await dbDeleteKeysWithPart(options.url, "smart-cache-v2", httpConfig.cacheStoreName);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
await dbSafeSet(
|
|
142
|
+
fullUrl,
|
|
143
|
+
response.data,
|
|
144
|
+
"smart-cache-v2",
|
|
145
|
+
httpConfig.cacheStoreName,
|
|
146
|
+
httpConfig.cacheTtlMs
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
} catch (error) {
|
|
150
|
+
if (!isHttpErrorPayload(result.error)) {
|
|
151
|
+
result.error = createNetworkError(error);
|
|
152
|
+
}
|
|
153
|
+
} finally {
|
|
154
|
+
if (raceCondition[fullUrl] === fetchId) {
|
|
155
|
+
delete raceCondition[fullUrl];
|
|
156
|
+
}
|
|
157
|
+
result.pending = false;
|
|
158
|
+
result.pendingCache = false;
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
result.fetch = runFetch;
|
|
162
|
+
if (!hasDataFromServer && options.lazy !== true) {
|
|
163
|
+
await runFetch(options.initParams);
|
|
164
|
+
}
|
|
165
|
+
onScopeDispose(() => {
|
|
166
|
+
clientChannel?.removeEventListener("message", onMessage);
|
|
167
|
+
controller.abort(`Http Abort -> onScopeDispose ${options.url}`);
|
|
168
|
+
if (serverData.value !== null) {
|
|
169
|
+
serverData.value = null;
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
return result;
|
|
174
|
+
}
|
|
175
|
+
function applyPayload(payload, result) {
|
|
176
|
+
if (isHttpErrorPayload(payload)) {
|
|
177
|
+
result.data = null;
|
|
178
|
+
result.error = payload;
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
result.data = payload;
|
|
182
|
+
result.error = null;
|
|
183
|
+
}
|
|
184
|
+
function getChannel() {
|
|
185
|
+
if (!import.meta.client) {
|
|
186
|
+
return void 0;
|
|
187
|
+
}
|
|
188
|
+
channel ??= new BroadcastChannel(CHANNEL_NAME);
|
|
189
|
+
return channel;
|
|
190
|
+
}
|
|
191
|
+
function normalizeBroadcastValue(payload) {
|
|
192
|
+
try {
|
|
193
|
+
return structuredClone(payload);
|
|
194
|
+
} catch {
|
|
195
|
+
return JSON.parse(JSON.stringify(payload));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { getRetryDelay, isFormData, sleep } from "../utils/helpers.js";
|
|
2
|
+
import { getHttpRequestMiddlewares, getHttpResponseMiddlewares } from "../utils/middleware.js";
|
|
3
|
+
import {
|
|
4
|
+
joinUrl
|
|
5
|
+
} from "../utils/shared.js";
|
|
6
|
+
export function createHttpClient(options = {}) {
|
|
7
|
+
const requestTimeoutMs = options.requestTimeoutMs ?? 8e4;
|
|
8
|
+
const defaultRetry = {
|
|
9
|
+
delay: options.retry?.delay ?? 300,
|
|
10
|
+
retries: options.retry?.retries ?? 3
|
|
11
|
+
};
|
|
12
|
+
return {
|
|
13
|
+
async get(url, config = {}) {
|
|
14
|
+
const retry = {
|
|
15
|
+
delay: config.retry?.delay ?? defaultRetry.delay,
|
|
16
|
+
retries: config.retry?.retries ?? defaultRetry.retries
|
|
17
|
+
};
|
|
18
|
+
const attemptRequest = async (attempt) => {
|
|
19
|
+
const request = await createRequestContext({
|
|
20
|
+
method: "GET",
|
|
21
|
+
options,
|
|
22
|
+
params: config.params,
|
|
23
|
+
requestTimeoutMs,
|
|
24
|
+
signal: config.signal,
|
|
25
|
+
url
|
|
26
|
+
});
|
|
27
|
+
try {
|
|
28
|
+
const result = await fetch(request.url, {
|
|
29
|
+
credentials: request.credentials,
|
|
30
|
+
headers: request.headers,
|
|
31
|
+
method: request.method,
|
|
32
|
+
signal: request.signal
|
|
33
|
+
});
|
|
34
|
+
const response = buildResponse(
|
|
35
|
+
request.url,
|
|
36
|
+
await readResponseBody(result),
|
|
37
|
+
result.status
|
|
38
|
+
);
|
|
39
|
+
if (!result.ok && isRetryableStatus(result.status) && attempt < retry.retries) {
|
|
40
|
+
await sleep(getRetryDelay(attempt, retry.delay));
|
|
41
|
+
return await attemptRequest(attempt + 1);
|
|
42
|
+
}
|
|
43
|
+
await runResponseMiddlewares(response, request, options.responseMiddleware);
|
|
44
|
+
return response;
|
|
45
|
+
} catch (error) {
|
|
46
|
+
if (isAbortError(error) || attempt >= retry.retries) {
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
await sleep(getRetryDelay(attempt, retry.delay));
|
|
50
|
+
return await attemptRequest(attempt + 1);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
return await attemptRequest(0);
|
|
54
|
+
},
|
|
55
|
+
async post(url, data, config = {}) {
|
|
56
|
+
const request = await createRequestContext({
|
|
57
|
+
body: data,
|
|
58
|
+
method: "POST",
|
|
59
|
+
options,
|
|
60
|
+
params: config.params,
|
|
61
|
+
requestTimeoutMs,
|
|
62
|
+
signal: config.signal,
|
|
63
|
+
url
|
|
64
|
+
});
|
|
65
|
+
let requestBody;
|
|
66
|
+
if (request.body !== void 0) {
|
|
67
|
+
requestBody = isFormData(request.body) ? request.body : JSON.stringify(request.body);
|
|
68
|
+
}
|
|
69
|
+
const result = await fetch(request.url, {
|
|
70
|
+
body: requestBody,
|
|
71
|
+
credentials: request.credentials,
|
|
72
|
+
headers: request.headers,
|
|
73
|
+
method: request.method,
|
|
74
|
+
signal: request.signal
|
|
75
|
+
});
|
|
76
|
+
const response = buildResponse(
|
|
77
|
+
request.url,
|
|
78
|
+
await readResponseBody(result),
|
|
79
|
+
result.status
|
|
80
|
+
);
|
|
81
|
+
await runResponseMiddlewares(response, request, options.responseMiddleware);
|
|
82
|
+
return response;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function buildRequestUrl(url, params, method) {
|
|
87
|
+
if (!params || Object.keys(params).length === 0) {
|
|
88
|
+
return url;
|
|
89
|
+
}
|
|
90
|
+
const searchParams = new URLSearchParams();
|
|
91
|
+
Object.entries(params ?? {}).forEach(([key, value]) => {
|
|
92
|
+
if (value === void 0 || value === null) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (Array.isArray(value)) {
|
|
96
|
+
if (method === "POST") {
|
|
97
|
+
value.forEach((item) => {
|
|
98
|
+
searchParams.append(`${key}[]`, String(item));
|
|
99
|
+
});
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
searchParams.append(key, JSON.stringify(value));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
searchParams.append(key, String(value));
|
|
106
|
+
});
|
|
107
|
+
const query = searchParams.toString();
|
|
108
|
+
if (!query) {
|
|
109
|
+
return url;
|
|
110
|
+
}
|
|
111
|
+
const separator = url.includes("?") ? "&" : "?";
|
|
112
|
+
return `${url}${separator}${query}`;
|
|
113
|
+
}
|
|
114
|
+
function buildResponse(url, data, status) {
|
|
115
|
+
return {
|
|
116
|
+
config: {
|
|
117
|
+
url
|
|
118
|
+
},
|
|
119
|
+
data,
|
|
120
|
+
status
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function createAnySignal(signals) {
|
|
124
|
+
if (typeof AbortSignal.any === "function") {
|
|
125
|
+
return AbortSignal.any(signals);
|
|
126
|
+
}
|
|
127
|
+
const controller = new AbortController();
|
|
128
|
+
signals.filter(Boolean).forEach((signal) => {
|
|
129
|
+
signal.addEventListener("abort", () => controller.abort(signal.reason), { once: true });
|
|
130
|
+
});
|
|
131
|
+
return controller.signal;
|
|
132
|
+
}
|
|
133
|
+
async function createRequestContext(input) {
|
|
134
|
+
const signal = resolveSignal(input.signal, input.requestTimeoutMs);
|
|
135
|
+
const headers = await createRequestHeaders(
|
|
136
|
+
input.options.createHeaders,
|
|
137
|
+
input.method === "POST" && input.body !== void 0 && !isFormData(input.body) ? {
|
|
138
|
+
"Content-Type": "application/json"
|
|
139
|
+
} : void 0
|
|
140
|
+
);
|
|
141
|
+
const request = {
|
|
142
|
+
baseURL: await resolveBaseURL(input.options.baseURL),
|
|
143
|
+
body: input.body,
|
|
144
|
+
credentials: "include",
|
|
145
|
+
headers,
|
|
146
|
+
method: input.method,
|
|
147
|
+
params: input.params,
|
|
148
|
+
signal,
|
|
149
|
+
url: input.url
|
|
150
|
+
};
|
|
151
|
+
await runRequestMiddlewares(request, input.options.requestMiddleware);
|
|
152
|
+
request.url = buildRequestUrl(joinUrl(request.baseURL, request.url), request.params, request.method);
|
|
153
|
+
return request;
|
|
154
|
+
}
|
|
155
|
+
async function createRequestHeaders(createHeaders, extraHeaders) {
|
|
156
|
+
const headers = new Headers(createHeaders ? await createHeaders() : void 0);
|
|
157
|
+
const extra = new Headers(extraHeaders);
|
|
158
|
+
extra.forEach((value, key) => {
|
|
159
|
+
headers.set(key, value);
|
|
160
|
+
});
|
|
161
|
+
return headers;
|
|
162
|
+
}
|
|
163
|
+
function createTimeoutSignal(ms) {
|
|
164
|
+
if (typeof AbortSignal.timeout === "function") {
|
|
165
|
+
return AbortSignal.timeout(ms);
|
|
166
|
+
}
|
|
167
|
+
const controller = new AbortController();
|
|
168
|
+
const timeoutId = setTimeout(() => controller.abort(new DOMException("Timed out", "AbortError")), ms);
|
|
169
|
+
controller.signal.addEventListener("abort", () => clearTimeout(timeoutId), { once: true });
|
|
170
|
+
return controller.signal;
|
|
171
|
+
}
|
|
172
|
+
function isAbortError(error) {
|
|
173
|
+
return error instanceof DOMException && error.name === "AbortError";
|
|
174
|
+
}
|
|
175
|
+
function isRetryableStatus(status) {
|
|
176
|
+
return status >= 500 || status === 429;
|
|
177
|
+
}
|
|
178
|
+
async function readResponseBody(response) {
|
|
179
|
+
const raw = await response.text();
|
|
180
|
+
if (!raw) {
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
try {
|
|
184
|
+
return JSON.parse(raw);
|
|
185
|
+
} catch {
|
|
186
|
+
return raw;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
async function resolveBaseURL(baseURL) {
|
|
190
|
+
if (!baseURL) {
|
|
191
|
+
return "";
|
|
192
|
+
}
|
|
193
|
+
if (typeof baseURL === "function") {
|
|
194
|
+
return await baseURL() || "";
|
|
195
|
+
}
|
|
196
|
+
return baseURL;
|
|
197
|
+
}
|
|
198
|
+
function resolveSignal(signal, requestTimeoutMs) {
|
|
199
|
+
const timeoutSignal = createTimeoutSignal(requestTimeoutMs);
|
|
200
|
+
if (Array.isArray(signal)) {
|
|
201
|
+
return createAnySignal([...signal, timeoutSignal]);
|
|
202
|
+
}
|
|
203
|
+
if (signal) {
|
|
204
|
+
return createAnySignal([signal, timeoutSignal]);
|
|
205
|
+
}
|
|
206
|
+
return timeoutSignal;
|
|
207
|
+
}
|
|
208
|
+
async function runRequestMiddlewares(request, middlewares) {
|
|
209
|
+
for (const middleware of [...getHttpRequestMiddlewares(), ...middlewares ?? []]) {
|
|
210
|
+
await middleware(request);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
async function runResponseMiddlewares(response, request, middlewares) {
|
|
214
|
+
for (const middleware of [...getHttpResponseMiddlewares(), ...middlewares ?? []]) {
|
|
215
|
+
await middleware(response, request);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { defineNuxtPlugin, useRuntimeConfig } from "nuxt/app";
|
|
2
|
+
import { createHttpClient } from "./http/client.js";
|
|
3
|
+
import { isHttpErrorPayload } from "./utils/shared.js";
|
|
4
|
+
export default defineNuxtPlugin(() => {
|
|
5
|
+
const runtimeConfig = useRuntimeConfig();
|
|
6
|
+
const httpConfig = runtimeConfig.public.brickflowHttp;
|
|
7
|
+
const http = createHttpClient({
|
|
8
|
+
baseURL: () => httpConfig.baseURL,
|
|
9
|
+
createHeaders: () => {
|
|
10
|
+
const headers = new Headers(httpConfig.defaultHeaders);
|
|
11
|
+
headers.set("X-Requested-With", "XMLHttpRequest");
|
|
12
|
+
if (httpConfig.clientEnvHeader && import.meta.dev) {
|
|
13
|
+
headers.set("Client-Env", "development");
|
|
14
|
+
}
|
|
15
|
+
return headers;
|
|
16
|
+
},
|
|
17
|
+
requestTimeoutMs: httpConfig.requestTimeoutMs,
|
|
18
|
+
responseMiddleware: [createRuntimeHttpErrorMiddleware()],
|
|
19
|
+
retry: httpConfig.retry
|
|
20
|
+
});
|
|
21
|
+
return {
|
|
22
|
+
provide: {
|
|
23
|
+
http
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
function createRuntimeHttpErrorMiddleware() {
|
|
28
|
+
return (response) => {
|
|
29
|
+
const { data, status } = response;
|
|
30
|
+
if (status !== 451 && status < 500 || !isHttpErrorPayload(data)) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const raise = async () => {
|
|
34
|
+
const { showError } = await import("nuxt/app");
|
|
35
|
+
showError({
|
|
36
|
+
data,
|
|
37
|
+
statusCode: status
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
const raiseSafely = () => {
|
|
41
|
+
;
|
|
42
|
+
(async () => {
|
|
43
|
+
try {
|
|
44
|
+
await raise();
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.error(error);
|
|
47
|
+
}
|
|
48
|
+
})();
|
|
49
|
+
};
|
|
50
|
+
if (import.meta.server) {
|
|
51
|
+
raiseSafely();
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
setTimeout(raiseSafely, 0);
|
|
55
|
+
};
|
|
56
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { HttpRouteMap, TypedHttpClient } from './utils/typed'
|
|
2
|
+
|
|
3
|
+
declare module '#app' {
|
|
4
|
+
interface NuxtApp {
|
|
5
|
+
$http: TypedHttpClient<HttpRouteMap>
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
declare module 'nuxt/app' {
|
|
10
|
+
interface NuxtApp {
|
|
11
|
+
$http: TypedHttpClient<HttpRouteMap>
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
declare module 'vue' {
|
|
16
|
+
interface ComponentCustomProperties {
|
|
17
|
+
$http: TypedHttpClient<HttpRouteMap>
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export {}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function getRandom(min: number, max: number): number;
|
|
2
|
+
export declare function getRetryDelay(attempt: number, baseDelay: number): number;
|
|
3
|
+
export declare function isFormData(value?: FormData | Record<string, unknown> | unknown): value is FormData;
|
|
4
|
+
export declare const sleep: (ms: number) => Promise<void>;
|
|
5
|
+
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function getRandom(min, max) {
|
|
2
|
+
const hasFloat = !Number.isInteger(min) || !Number.isInteger(max);
|
|
3
|
+
return hasFloat ? Math.random() * (max - min) + min : Math.floor(Math.random() * (max - min + 1)) + min;
|
|
4
|
+
}
|
|
5
|
+
export function getRetryDelay(attempt, baseDelay) {
|
|
6
|
+
return Math.random() * baseDelay * 2 ** attempt;
|
|
7
|
+
}
|
|
8
|
+
export function isFormData(value) {
|
|
9
|
+
if (!value) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
return typeof value === "object" && typeof value.append === "function" && typeof value.has === "function";
|
|
13
|
+
}
|
|
14
|
+
export const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface DbEntry<T> {
|
|
2
|
+
expiresAt: number;
|
|
3
|
+
hash: string;
|
|
4
|
+
key: string;
|
|
5
|
+
value: T;
|
|
6
|
+
}
|
|
7
|
+
declare const allowDb: readonly ["smart-cache-v2"];
|
|
8
|
+
type AllowDB = (typeof allowDb)[number];
|
|
9
|
+
export declare function dbDeleteKeysWithPart(part: string, dbName: AllowDB, storeName: string): Promise<void>;
|
|
10
|
+
export declare function dbGet<T>(key: string, dbName: AllowDB, storeName: string): Promise<DbEntry<T> | null>;
|
|
11
|
+
export declare function dbSafeSet<T>(key: string, value: T, dbName: AllowDB, storeName: string, ttl: number, retries?: number): Promise<void>;
|
|
12
|
+
export declare function hashData(data: unknown): Promise<string>;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=indexeddb.d.ts.map
|