@brickflow/http 0.0.13 → 0.0.15
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 +425 -0
- package/dist/http.d.ts +61 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +144 -0
- package/dist/index.mjs.map +1 -0
- package/dist/nuxt.d.ts +72 -0
- package/dist/nuxt.d.ts.map +1 -0
- package/dist/nuxt.mjs +222 -0
- package/dist/nuxt.mjs.map +1 -0
- package/dist/utils-DMSINHi5.js +39 -0
- package/dist/utils-DMSINHi5.js.map +1 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.d.ts.map +1 -0
- package/package.json +36 -7
- package/CHANGELOG.md +0 -79
- package/eslint.config.mjs +0 -1
- package/prettier.config.mjs +0 -1
package/README.md
ADDED
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
# @brickflow/http
|
|
2
|
+
|
|
3
|
+
Minimal HTTP package used in this repo for:
|
|
4
|
+
|
|
5
|
+
- low-level HTTP transport via `createHttp`
|
|
6
|
+
- Nuxt async state wrapper via `createUseHttp`
|
|
7
|
+
- reusable endpoint factory via `createGet`
|
|
8
|
+
- project-level typing through `declare module '@brickflow/http'`
|
|
9
|
+
|
|
10
|
+
This package does not know your API schema by default. The schema and error type are configured in the consumer project through `type.d.ts`.
|
|
11
|
+
|
|
12
|
+
## Exports
|
|
13
|
+
|
|
14
|
+
From `@brickflow/http`:
|
|
15
|
+
|
|
16
|
+
- `createHttp`
|
|
17
|
+
- `createURL`
|
|
18
|
+
- `hashData`
|
|
19
|
+
- HTTP types: `HttpClient`, `HttpError`, `HttpKey`, `HttpParam`, `HttpResponse`, `HttpResponseData`, `HttpSuccessData`
|
|
20
|
+
|
|
21
|
+
From `@brickflow/http/nuxt`:
|
|
22
|
+
|
|
23
|
+
- `createUseHttp`
|
|
24
|
+
- `createGet`
|
|
25
|
+
- Nuxt types: `UseHttpOptions`, `UseHttpResult`, `UseHttpFn`
|
|
26
|
+
|
|
27
|
+
## 1. Configure API types in `type.d.ts`
|
|
28
|
+
|
|
29
|
+
In this repo the typing is configured in `types/http.d.ts`.
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import type { Convention, ConventionKeys } from 'convention'
|
|
33
|
+
|
|
34
|
+
type BrickHttpError = Exclude<Convention<ConventionKeys>, { status: 'success' }>
|
|
35
|
+
type BrickHttpSchema = {
|
|
36
|
+
[TKey in ConventionKeys]: Convention<TKey>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
declare module '@brickflow/http' {
|
|
40
|
+
interface HttpTypeConfig {
|
|
41
|
+
endpoints: BrickHttpSchema
|
|
42
|
+
error: BrickHttpError
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
What this gives:
|
|
48
|
+
|
|
49
|
+
- `HttpKey` becomes your endpoint union
|
|
50
|
+
- `HttpResponseData<'some/endpoint'>` becomes the response type for that endpoint
|
|
51
|
+
- `HttpSuccessData<'some/endpoint'>` becomes response without the configured error branch
|
|
52
|
+
- `UseHttpResult<T, P>['error']` is inferred from `HttpTypeConfig['error']`
|
|
53
|
+
|
|
54
|
+
This is the main place where project typing should live.
|
|
55
|
+
|
|
56
|
+
## 2. Create low-level HTTP client
|
|
57
|
+
|
|
58
|
+
Real usage from `plugins/01.di.ts`:
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import { createHttp } from '@brickflow/http'
|
|
62
|
+
|
|
63
|
+
const httpClient = createHttp({
|
|
64
|
+
baseURL: apiUrl,
|
|
65
|
+
headers: () => ({
|
|
66
|
+
'Client-Env': config.public.isDev ? 'development' : undefined,
|
|
67
|
+
'Client-Lang': String(locale.value ?? 'en'),
|
|
68
|
+
'Client-Socket-Id': socketClient?.io.id || '',
|
|
69
|
+
'X-Requested-With': 'XMLHttpRequest',
|
|
70
|
+
}),
|
|
71
|
+
onResponseError: responseInterceptor,
|
|
72
|
+
})
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Available options:
|
|
76
|
+
|
|
77
|
+
- `baseURL`
|
|
78
|
+
- `fetch`
|
|
79
|
+
- `headers`
|
|
80
|
+
- `onResponseError`
|
|
81
|
+
- `requestInit`
|
|
82
|
+
- `timeout`
|
|
83
|
+
|
|
84
|
+
`createHttp` returns:
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
interface HttpClient {
|
|
88
|
+
get(url, config?)
|
|
89
|
+
post(url, data?, config?)
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## 3. Use `HttpClient` directly
|
|
94
|
+
|
|
95
|
+
Used in domain methods that do not need cached async state.
|
|
96
|
+
|
|
97
|
+
Example from `domains/content/use-case.ts`:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
async create(title: string, type: string, description?: string) {
|
|
101
|
+
const { data } = await httpClient.post('content/create', {
|
|
102
|
+
description,
|
|
103
|
+
title,
|
|
104
|
+
type,
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
return data
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Another example:
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
async updateType(itemId: string, type: string) {
|
|
115
|
+
const { data } = await httpClient.post('content/update-type', {
|
|
116
|
+
itemId,
|
|
117
|
+
type,
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
return data
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Use this style when:
|
|
125
|
+
|
|
126
|
+
- request is one-shot
|
|
127
|
+
- you do not need `pending`, `hasFirstData`, cache, SSR sync, or `fetch()`
|
|
128
|
+
|
|
129
|
+
## 4. Create Nuxt `useHttp`
|
|
130
|
+
|
|
131
|
+
In this repo the app-level `useHttp` is created once in `core/util.ts`:
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
import { createUseHttp } from '@brickflow/http/nuxt'
|
|
135
|
+
|
|
136
|
+
const useHttp = createUseHttp({
|
|
137
|
+
getCache: () => ({
|
|
138
|
+
deleteKeysWithPart: async (part) => await dbDeleteKeysWithPart(part, 'smart-cache-v2', STORE_NAME),
|
|
139
|
+
get: async (key) => await dbGet(key, 'smart-cache-v2', STORE_NAME),
|
|
140
|
+
set: async (key, value, ttl) => await dbSafeSet(key, value, 'smart-cache-v2', STORE_NAME, ttl),
|
|
141
|
+
}),
|
|
142
|
+
getHttpClient: () => useNuxtApp().$http,
|
|
143
|
+
isDev: () => useRuntimeConfig().public.isDev,
|
|
144
|
+
})
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Dependencies:
|
|
148
|
+
|
|
149
|
+
- `getHttpClient`
|
|
150
|
+
- `getCache`
|
|
151
|
+
- `isError`
|
|
152
|
+
- `isDev`
|
|
153
|
+
- `ttl`
|
|
154
|
+
- `channelName`
|
|
155
|
+
|
|
156
|
+
`isError` can be set globally here if your project needs a custom runtime error predicate.
|
|
157
|
+
|
|
158
|
+
## 5. Bind `createGet` once
|
|
159
|
+
|
|
160
|
+
The package exports `createGet(useHttp)`, which builds typed endpoint helpers on top of your local `useHttp`.
|
|
161
|
+
|
|
162
|
+
Real usage from `core/util.ts`:
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
import { createGet as createHttpGet, createUseHttp } from '@brickflow/http/nuxt'
|
|
166
|
+
|
|
167
|
+
const useHttp = createUseHttp({ ... })
|
|
168
|
+
|
|
169
|
+
export const createGet = createHttpGet(useHttp)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
After that you can reuse `createGet` in domain files.
|
|
173
|
+
|
|
174
|
+
## 6. Create typed GET endpoints
|
|
175
|
+
|
|
176
|
+
### Without params
|
|
177
|
+
|
|
178
|
+
Example from `domains/storage/use-case.ts`:
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
plans: createGet()('storage/plans')
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### With params
|
|
185
|
+
|
|
186
|
+
Example from `domains/feed/use-case.ts`:
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
home: createGet<{
|
|
190
|
+
category?: 'fresh' | 'popular' | 'recommended' | 'updated'
|
|
191
|
+
limit: number
|
|
192
|
+
offset: number
|
|
193
|
+
}>()('feed/home')
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### With `ignore`
|
|
197
|
+
|
|
198
|
+
Example from `domains/content/use-case.ts`:
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
analytics: createGet<{
|
|
202
|
+
itemId: string
|
|
203
|
+
period: '7d' | '28d' | '90d'
|
|
204
|
+
}>()('content/analytics', {
|
|
205
|
+
ignore(res) {
|
|
206
|
+
if (res.data.kind === 'no_auth') {
|
|
207
|
+
return true
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return false
|
|
211
|
+
},
|
|
212
|
+
})
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### With `effect`
|
|
216
|
+
|
|
217
|
+
Example from `domains/root/use-case.ts`:
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
main: createGet()('root/main', {
|
|
221
|
+
effect(data, config) {
|
|
222
|
+
if (data.status === 'error') {
|
|
223
|
+
return
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (!config.cached) {
|
|
227
|
+
userStore.setUser(data.user)
|
|
228
|
+
userStore.setRegion(data.region)
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
})
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### With `effect` and success handling
|
|
235
|
+
|
|
236
|
+
Example from `domains/storage/use-case.ts`:
|
|
237
|
+
|
|
238
|
+
```ts
|
|
239
|
+
current: createGet()('storage/current', {
|
|
240
|
+
effect(data) {
|
|
241
|
+
if (data.status === 'success') {
|
|
242
|
+
storageStore.setCurrentPlan(data.plan)
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
})
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## 7. Consume endpoint state in components
|
|
249
|
+
|
|
250
|
+
### Create request object
|
|
251
|
+
|
|
252
|
+
Example from `components/Search/index.vue`:
|
|
253
|
+
|
|
254
|
+
```ts
|
|
255
|
+
const searchFastHttp = await app.$di.search.fast({
|
|
256
|
+
lazy: true,
|
|
257
|
+
server: false,
|
|
258
|
+
})
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Trigger fetch manually
|
|
262
|
+
|
|
263
|
+
```ts
|
|
264
|
+
await searchFastHttp.fetch({
|
|
265
|
+
text: searchQuery.value,
|
|
266
|
+
})
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Read `data`
|
|
270
|
+
|
|
271
|
+
```ts
|
|
272
|
+
const data = searchFastHttp.data
|
|
273
|
+
|
|
274
|
+
if (data?.status === 'success') {
|
|
275
|
+
items.value = data.items
|
|
276
|
+
users.value = data.users
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Read loading flags
|
|
281
|
+
|
|
282
|
+
Example from `components/ProfileMyGrid/index.vue`:
|
|
283
|
+
|
|
284
|
+
```vue
|
|
285
|
+
:loading="myContentHttp.pending || myContentHttp.pendingCache"
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Use `hasFirstData`
|
|
289
|
+
|
|
290
|
+
```vue
|
|
291
|
+
v-if="!myContentHttp.pending && myContentHttp.hasFirstData && items.length === 0"
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## 8. `effect` semantics
|
|
295
|
+
|
|
296
|
+
`effect` receives the full response payload.
|
|
297
|
+
|
|
298
|
+
That means:
|
|
299
|
+
|
|
300
|
+
- it is called for success
|
|
301
|
+
- it is called for error
|
|
302
|
+
- you can branch on `data.status`
|
|
303
|
+
- `config.cached` tells whether the payload came from cache
|
|
304
|
+
- `config.params` contains mapped params used for the request
|
|
305
|
+
|
|
306
|
+
Example from `pages/profile/[username].vue`:
|
|
307
|
+
|
|
308
|
+
```ts
|
|
309
|
+
const profileHttp = await app.$di.profile.info({
|
|
310
|
+
effect(data) {
|
|
311
|
+
if (data.status === 'error' && data.kind === 'not_found') {
|
|
312
|
+
showError(createError({
|
|
313
|
+
fatal: true,
|
|
314
|
+
statusCode: 404,
|
|
315
|
+
statusMessage: 'Page Not Found',
|
|
316
|
+
}))
|
|
317
|
+
}
|
|
318
|
+
},
|
|
319
|
+
initParams: {
|
|
320
|
+
username: String(profileParam.value),
|
|
321
|
+
},
|
|
322
|
+
server: true,
|
|
323
|
+
})
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
## 9. `data` and `error`
|
|
327
|
+
|
|
328
|
+
`UseHttpResult<T, P>` is split like this:
|
|
329
|
+
|
|
330
|
+
- `data`: success payload only
|
|
331
|
+
- `error`: configured project error payload only
|
|
332
|
+
|
|
333
|
+
Internally the split is done by runtime error predicate:
|
|
334
|
+
|
|
335
|
+
- global `isError` from `createUseHttp(...)`
|
|
336
|
+
- or per-request `isError`
|
|
337
|
+
- fallback: `payload.status === 'error'`
|
|
338
|
+
|
|
339
|
+
Important:
|
|
340
|
+
|
|
341
|
+
- runtime error predicate does not reconfigure TypeScript types
|
|
342
|
+
- TypeScript error type comes from `declare module '@brickflow/http'`
|
|
343
|
+
|
|
344
|
+
## 10. Supported request options
|
|
345
|
+
|
|
346
|
+
For `useHttp` / `createGet`:
|
|
347
|
+
|
|
348
|
+
- `url`
|
|
349
|
+
- `initParams`
|
|
350
|
+
- `mapParams`
|
|
351
|
+
- `effect`
|
|
352
|
+
- `ignore`
|
|
353
|
+
- `isError`
|
|
354
|
+
- `lazy`
|
|
355
|
+
- `server`
|
|
356
|
+
|
|
357
|
+
Example with `initParams`:
|
|
358
|
+
|
|
359
|
+
```ts
|
|
360
|
+
const myContentHttp = await app.$di.content.my({
|
|
361
|
+
initParams: {
|
|
362
|
+
limit: props.limit,
|
|
363
|
+
offset: 0,
|
|
364
|
+
order: selectedOrder.value,
|
|
365
|
+
orderColumn: 'date',
|
|
366
|
+
type: selectedType.value,
|
|
367
|
+
},
|
|
368
|
+
})
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
Example with `fetch(...)` overriding params:
|
|
372
|
+
|
|
373
|
+
```ts
|
|
374
|
+
await myContentHttp.fetch({
|
|
375
|
+
limit: props.limit,
|
|
376
|
+
offset,
|
|
377
|
+
order: selectedOrder.value,
|
|
378
|
+
orderColumn: 'date',
|
|
379
|
+
type: selectedType.value,
|
|
380
|
+
})
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
## 11. Cache behavior
|
|
384
|
+
|
|
385
|
+
When `getCache` is provided, `createUseHttp`:
|
|
386
|
+
|
|
387
|
+
- tries cached value first
|
|
388
|
+
- calls `effect(..., { cached: true })` for cached payload
|
|
389
|
+
- then performs fresh request
|
|
390
|
+
- stores success response in cache
|
|
391
|
+
- invalidates related keys when response hash changes
|
|
392
|
+
|
|
393
|
+
In this repo the cache is backed by IndexedDB in `core/util.ts`.
|
|
394
|
+
|
|
395
|
+
## 12. URL and hash helpers
|
|
396
|
+
|
|
397
|
+
The package also exports helpers used by the current implementation:
|
|
398
|
+
|
|
399
|
+
```ts
|
|
400
|
+
import { createURL, hashData } from '@brickflow/http'
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
`createURL(url, params)` builds query strings.
|
|
404
|
+
|
|
405
|
+
`hashData(data)` computes response hash for cache invalidation.
|
|
406
|
+
|
|
407
|
+
## 13. Recommended usage in this repo
|
|
408
|
+
|
|
409
|
+
Use `createHttp` when:
|
|
410
|
+
|
|
411
|
+
- you need direct `get/post`
|
|
412
|
+
- you are writing mutations or one-shot calls
|
|
413
|
+
|
|
414
|
+
Use `createUseHttp` + `createGet` when:
|
|
415
|
+
|
|
416
|
+
- you need SSR-aware async state
|
|
417
|
+
- you need `pending`, `pendingCache`, `hasFirstData`, `hasFreshData`
|
|
418
|
+
- you need cache integration
|
|
419
|
+
- you want reusable typed endpoint factories in domain modules
|
|
420
|
+
|
|
421
|
+
Use `type.d.ts` when:
|
|
422
|
+
|
|
423
|
+
- you want to define endpoint keys
|
|
424
|
+
- you want to define the project-wide error type
|
|
425
|
+
- you want all consumers to infer the same API schema
|
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export type ConventionError = HttpError;
|
|
2
|
+
export interface CreateHttpOptions {
|
|
3
|
+
baseURL: string;
|
|
4
|
+
fetch?: typeof fetch;
|
|
5
|
+
headers?: (() => Record<string, string | undefined>) | Record<string, string | undefined>;
|
|
6
|
+
onResponseError?: (response: HttpResponse<HttpError>) => Promise<void> | void;
|
|
7
|
+
requestInit?: Omit<RequestInit, 'body' | 'headers' | 'method' | 'signal'>;
|
|
8
|
+
timeout?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface GetConfig extends HttpConfig {
|
|
11
|
+
retry?: {
|
|
12
|
+
delay?: number;
|
|
13
|
+
retries?: number;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export interface HttpClient {
|
|
17
|
+
get: <T extends HttpKey>(url: T, config?: GetConfig) => Promise<HttpResponse<HttpResponseData<T>>>;
|
|
18
|
+
post: <T extends HttpKey>(url: T, data?: FormData | Record<string, unknown>, config?: PostConfig) => Promise<HttpResponse<HttpResponseData<T>>>;
|
|
19
|
+
}
|
|
20
|
+
export interface HttpDefaultError {
|
|
21
|
+
[key: string]: unknown;
|
|
22
|
+
kind?: string;
|
|
23
|
+
message?: string;
|
|
24
|
+
status: 'error';
|
|
25
|
+
}
|
|
26
|
+
export interface HttpDefaultSuccess {
|
|
27
|
+
[key: string]: unknown;
|
|
28
|
+
status?: 'success';
|
|
29
|
+
}
|
|
30
|
+
export type HttpError = HttpConfigValue<'error', HttpDefaultError>;
|
|
31
|
+
export type HttpKey = Extract<keyof HttpSchema, string>;
|
|
32
|
+
export type HttpParam = Record<string, boolean | number | string | string[] | undefined>;
|
|
33
|
+
export type HttpMatchedError<TData = unknown, TError = HttpError> = Extract<TData, TError>;
|
|
34
|
+
export type HttpMatchedSuccess<TData = unknown, TError = HttpError> = Exclude<TData, HttpMatchedError<TData, TError>>;
|
|
35
|
+
export type HttpErrorData<TData = unknown> = HttpMatchedError<TData>;
|
|
36
|
+
export type HttpSuccessResult<TData = unknown, TError = HttpErrorData<TData>> = HttpMatchedSuccess<TData, TError>;
|
|
37
|
+
export type HttpErrorGuard<TData = unknown, TError extends TData = HttpMatchedError<TData>> = (payload: TData) => payload is TError;
|
|
38
|
+
export interface HttpResponse<T = HttpResponseData> {
|
|
39
|
+
config: {
|
|
40
|
+
ignore?: ((response: HttpResponse<HttpError>) => boolean) | undefined;
|
|
41
|
+
url: string;
|
|
42
|
+
};
|
|
43
|
+
data: T;
|
|
44
|
+
status: number;
|
|
45
|
+
}
|
|
46
|
+
export type HttpResponseData<TKey extends HttpKey = HttpKey> = HttpSchema[TKey];
|
|
47
|
+
export type HttpSchema = HttpConfigValue<'endpoints', Record<string, HttpDefaultError | HttpDefaultSuccess>>;
|
|
48
|
+
export type HttpSuccessData<TKey extends HttpKey = HttpKey> = Exclude<HttpResponseData<TKey>, HttpError>;
|
|
49
|
+
export interface HttpTypeConfig {
|
|
50
|
+
}
|
|
51
|
+
export interface PostConfig extends HttpConfig {
|
|
52
|
+
}
|
|
53
|
+
interface HttpConfig {
|
|
54
|
+
ignore?: (response: HttpResponse<HttpError>) => boolean;
|
|
55
|
+
params?: HttpParam;
|
|
56
|
+
signal?: AbortSignal | AbortSignal[];
|
|
57
|
+
}
|
|
58
|
+
type HttpConfigValue<TKey extends string, TFallback> = TKey extends keyof HttpTypeConfig ? HttpTypeConfig[TKey] : TFallback;
|
|
59
|
+
export declare function createHttp(options: CreateHttpOptions): HttpClient;
|
|
60
|
+
export {};
|
|
61
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAA;AACtB,cAAc,SAAS,CAAA"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { n as fastDevHash, r as hashData, t as createURL } from "./utils-DMSINHi5.js";
|
|
2
|
+
//#region src/http.ts
|
|
3
|
+
function createHttp(options) {
|
|
4
|
+
const clientFetch = options.fetch ?? fetch;
|
|
5
|
+
const timeout = options.timeout ?? 8e4;
|
|
6
|
+
return {
|
|
7
|
+
get(url, config = {}) {
|
|
8
|
+
const requestUrl = `${joinUrl(options.baseURL, url)}${toQueryString(config.params, "json")}`;
|
|
9
|
+
const { delay = 300, retries = 3 } = config.retry ?? {};
|
|
10
|
+
const attemptRequest = async (attempt) => {
|
|
11
|
+
try {
|
|
12
|
+
const result = await clientFetch(requestUrl, {
|
|
13
|
+
...options.requestInit,
|
|
14
|
+
credentials: "include",
|
|
15
|
+
headers: resolveHeaders(options.headers),
|
|
16
|
+
method: "GET",
|
|
17
|
+
signal: createSignal(config.signal, timeout)
|
|
18
|
+
});
|
|
19
|
+
const parsedResult = await result.json();
|
|
20
|
+
const response = {
|
|
21
|
+
config: {
|
|
22
|
+
ignore: config.ignore,
|
|
23
|
+
url: joinUrl(options.baseURL, url)
|
|
24
|
+
},
|
|
25
|
+
data: parsedResult,
|
|
26
|
+
status: result.status
|
|
27
|
+
};
|
|
28
|
+
if (!result.ok && isRetryableStatus(result.status) && attempt < retries) {
|
|
29
|
+
await wait(getRetryDelay(attempt, delay));
|
|
30
|
+
return attemptRequest(attempt + 1);
|
|
31
|
+
}
|
|
32
|
+
await options.onResponseError?.(response);
|
|
33
|
+
return response;
|
|
34
|
+
} catch (err) {
|
|
35
|
+
if (isAbortError(err) || attempt >= retries) throw err;
|
|
36
|
+
await wait(getRetryDelay(attempt, delay));
|
|
37
|
+
return attemptRequest(attempt + 1);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
return attemptRequest(0);
|
|
41
|
+
},
|
|
42
|
+
async post(url, data, config = {}) {
|
|
43
|
+
const isForm = isFormData(data);
|
|
44
|
+
const response = await clientFetch(`${joinUrl(options.baseURL, url)}${toQueryString(config.params, "repeat")}`, {
|
|
45
|
+
...options.requestInit,
|
|
46
|
+
body: isForm || data === void 0 ? data : JSON.stringify(data),
|
|
47
|
+
credentials: "include",
|
|
48
|
+
headers: resolveHeaders(options.headers, data !== void 0 && !isForm ? { "Content-Type": "application/json" } : void 0),
|
|
49
|
+
method: "POST",
|
|
50
|
+
signal: createSignal(config.signal, timeout)
|
|
51
|
+
});
|
|
52
|
+
let parsedResult = {};
|
|
53
|
+
try {
|
|
54
|
+
parsedResult = await response.json();
|
|
55
|
+
} catch {
|
|
56
|
+
parsedResult = {};
|
|
57
|
+
}
|
|
58
|
+
const parsedResponse = {
|
|
59
|
+
config: {
|
|
60
|
+
ignore: config.ignore,
|
|
61
|
+
url: joinUrl(options.baseURL, url)
|
|
62
|
+
},
|
|
63
|
+
data: parsedResult,
|
|
64
|
+
status: response.status
|
|
65
|
+
};
|
|
66
|
+
await options.onResponseError?.(parsedResponse);
|
|
67
|
+
return parsedResponse;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function createAnySignal(signals) {
|
|
72
|
+
if (typeof AbortSignal?.any === "function") return AbortSignal.any(signals);
|
|
73
|
+
const controller = new AbortController();
|
|
74
|
+
signals.filter(Boolean).forEach((signal) => {
|
|
75
|
+
signal.addEventListener("abort", () => controller.abort(), { once: true });
|
|
76
|
+
});
|
|
77
|
+
return controller.signal;
|
|
78
|
+
}
|
|
79
|
+
function createSignal(signal, timeout) {
|
|
80
|
+
const timeoutSignal = createTimeoutSignal(timeout);
|
|
81
|
+
if (Array.isArray(signal)) return createAnySignal([...signal, timeoutSignal]);
|
|
82
|
+
if (signal) return createAnySignal([signal, timeoutSignal]);
|
|
83
|
+
return timeoutSignal;
|
|
84
|
+
}
|
|
85
|
+
function createTimeoutSignal(ms) {
|
|
86
|
+
if (typeof AbortSignal?.timeout === "function") return AbortSignal.timeout(ms);
|
|
87
|
+
const controller = new AbortController();
|
|
88
|
+
const timeoutId = setTimeout(() => controller.abort(), ms);
|
|
89
|
+
controller.signal.addEventListener("abort", () => clearTimeout(timeoutId), { once: true });
|
|
90
|
+
return controller.signal;
|
|
91
|
+
}
|
|
92
|
+
function getRetryDelay(attempt, delay) {
|
|
93
|
+
return delay * 2 ** attempt;
|
|
94
|
+
}
|
|
95
|
+
function isAbortError(err) {
|
|
96
|
+
return err instanceof DOMException && err.name === "AbortError";
|
|
97
|
+
}
|
|
98
|
+
function isFormData(value) {
|
|
99
|
+
return typeof FormData !== "undefined" && value instanceof FormData;
|
|
100
|
+
}
|
|
101
|
+
function isRetryableStatus(status) {
|
|
102
|
+
return status >= 500 || status === 429;
|
|
103
|
+
}
|
|
104
|
+
function joinUrl(baseURL, url) {
|
|
105
|
+
return `${baseURL.endsWith("/") ? baseURL.slice(0, -1) : baseURL}/${url.startsWith("/") ? url.slice(1) : url}`;
|
|
106
|
+
}
|
|
107
|
+
function resolveHeaders(value, extraHeaders) {
|
|
108
|
+
const headers = typeof value === "function" ? value() : value;
|
|
109
|
+
return Object.entries({
|
|
110
|
+
...headers,
|
|
111
|
+
...extraHeaders
|
|
112
|
+
}).reduce((acc, [key, headerValue]) => {
|
|
113
|
+
if (typeof headerValue === "string") acc[key] = headerValue;
|
|
114
|
+
return acc;
|
|
115
|
+
}, {});
|
|
116
|
+
}
|
|
117
|
+
function serializeQueryValue(urlParams, key, value, arrayMode) {
|
|
118
|
+
if (value === void 0) return;
|
|
119
|
+
if (Array.isArray(value)) {
|
|
120
|
+
if (arrayMode === "json") {
|
|
121
|
+
urlParams.append(key, JSON.stringify(value));
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
value.forEach((item) => {
|
|
125
|
+
urlParams.append(`${key}[]`, item);
|
|
126
|
+
});
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
urlParams.append(key, String(value));
|
|
130
|
+
}
|
|
131
|
+
function toQueryString(params, arrayMode = "json") {
|
|
132
|
+
const urlParams = new URLSearchParams();
|
|
133
|
+
Object.entries(params ?? {}).forEach(([key, value]) => {
|
|
134
|
+
serializeQueryValue(urlParams, key, value, arrayMode);
|
|
135
|
+
});
|
|
136
|
+
return urlParams.size > 0 ? `?${urlParams}` : "";
|
|
137
|
+
}
|
|
138
|
+
function wait(ms) {
|
|
139
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
140
|
+
}
|
|
141
|
+
//#endregion
|
|
142
|
+
export { createHttp, createURL, fastDevHash, hashData };
|
|
143
|
+
|
|
144
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/http.ts"],"sourcesContent":["export type ConventionError = HttpError\n\nexport interface CreateHttpOptions {\n baseURL: string\n fetch?: typeof fetch\n headers?: (() => Record<string, string | undefined>) | Record<string, string | undefined>\n onResponseError?: (response: HttpResponse<HttpError>) => Promise<void> | void\n requestInit?: Omit<RequestInit, 'body' | 'headers' | 'method' | 'signal'>\n timeout?: number\n}\n\nexport interface GetConfig extends HttpConfig {\n retry?: {\n delay?: number\n retries?: number\n }\n}\n\nexport interface HttpClient {\n get: <T extends HttpKey>(url: T, config?: GetConfig) => Promise<HttpResponse<HttpResponseData<T>>>\n post: <T extends HttpKey>(\n url: T,\n data?: FormData | Record<string, unknown>,\n config?: PostConfig,\n ) => Promise<HttpResponse<HttpResponseData<T>>>\n}\n\nexport interface HttpDefaultError {\n [key: string]: unknown\n kind?: string\n message?: string\n status: 'error'\n}\nexport interface HttpDefaultSuccess {\n [key: string]: unknown\n status?: 'success'\n}\nexport type HttpError = HttpConfigValue<'error', HttpDefaultError>\nexport type HttpKey = Extract<keyof HttpSchema, string>\nexport type HttpParam = Record<string, boolean | number | string | string[] | undefined>\nexport type HttpMatchedError<TData = unknown, TError = HttpError> = Extract<TData, TError>\nexport type HttpMatchedSuccess<TData = unknown, TError = HttpError> = Exclude<TData, HttpMatchedError<TData, TError>>\nexport type HttpErrorData<TData = unknown> = HttpMatchedError<TData>\nexport type HttpSuccessResult<TData = unknown, TError = HttpErrorData<TData>> = HttpMatchedSuccess<TData, TError>\nexport type HttpErrorGuard<TData = unknown, TError extends TData = HttpMatchedError<TData>> = (\n payload: TData,\n) => payload is TError\nexport interface HttpResponse<T = HttpResponseData> {\n config: {\n ignore?: ((response: HttpResponse<HttpError>) => boolean) | undefined\n url: string\n }\n data: T\n status: number\n}\n\nexport type HttpResponseData<TKey extends HttpKey = HttpKey> = HttpSchema[TKey]\n\nexport type HttpSchema = HttpConfigValue<'endpoints', Record<string, HttpDefaultError | HttpDefaultSuccess>>\n\nexport type HttpSuccessData<TKey extends HttpKey = HttpKey> = Exclude<HttpResponseData<TKey>, HttpError>\n\nexport interface HttpTypeConfig {}\n\nexport interface PostConfig extends HttpConfig {}\n\ninterface HttpConfig {\n ignore?: (response: HttpResponse<HttpError>) => boolean\n params?: HttpParam\n signal?: AbortSignal | AbortSignal[]\n}\n\ntype HttpConfigValue<TKey extends string, TFallback> = TKey extends keyof HttpTypeConfig\n ? HttpTypeConfig[TKey]\n : TFallback\n\ntype QueryArrayMode = 'json' | 'repeat'\n\nexport function createHttp(options: CreateHttpOptions): HttpClient {\n const clientFetch = options.fetch ?? fetch\n const timeout = options.timeout ?? 80000\n\n return {\n get<T extends HttpKey>(url: T, config: GetConfig = {}) {\n const requestUrl = `${joinUrl(options.baseURL, url)}${toQueryString(config.params, 'json')}`\n const { delay = 300, retries = 3 } = config.retry ?? {}\n\n const attemptRequest = async (attempt: number): Promise<HttpResponse<HttpResponseData<T>>> => {\n try {\n const result = await clientFetch(requestUrl, {\n ...options.requestInit,\n credentials: 'include',\n headers: resolveHeaders(options.headers),\n method: 'GET',\n signal: createSignal(config.signal, timeout),\n })\n\n const parsedResult = await result.json()\n const response = {\n config: {\n ignore: config.ignore,\n url: joinUrl(options.baseURL, url),\n },\n data: parsedResult,\n status: result.status,\n }\n\n if (!result.ok && isRetryableStatus(result.status) && attempt < retries) {\n await wait(getRetryDelay(attempt, delay))\n return attemptRequest(attempt + 1)\n }\n\n await options.onResponseError?.(response)\n return response\n } catch (err) {\n if (isAbortError(err) || attempt >= retries) {\n throw err\n }\n\n await wait(getRetryDelay(attempt, delay))\n return attemptRequest(attempt + 1)\n }\n }\n\n return attemptRequest(0)\n },\n async post<T extends HttpKey>(url: T, data?: FormData | Record<string, unknown>, config: PostConfig = {}) {\n const isForm = isFormData(data)\n const requestUrl = `${joinUrl(options.baseURL, url)}${toQueryString(config.params, 'repeat')}`\n const response = await clientFetch(requestUrl, {\n ...options.requestInit,\n body: isForm || data === undefined ? data : JSON.stringify(data),\n credentials: 'include',\n headers: resolveHeaders(\n options.headers,\n data !== undefined && !isForm ? { 'Content-Type': 'application/json' } : undefined,\n ),\n method: 'POST',\n signal: createSignal(config.signal, timeout),\n })\n\n let parsedResult: Awaited<ReturnType<typeof response.json>> = {}\n try {\n parsedResult = await response.json()\n } catch {\n parsedResult = {}\n }\n\n const parsedResponse = {\n config: {\n ignore: config.ignore,\n url: joinUrl(options.baseURL, url),\n },\n data: parsedResult,\n status: response.status,\n }\n\n await options.onResponseError?.(parsedResponse)\n return parsedResponse\n },\n }\n}\n\nfunction createAnySignal(signals: AbortSignal[]): AbortSignal {\n if (typeof AbortSignal?.any === 'function') {\n return AbortSignal.any(signals)\n }\n\n const controller = new AbortController()\n\n signals.filter(Boolean).forEach((signal) => {\n signal.addEventListener('abort', () => controller.abort(), { once: true })\n })\n\n return controller.signal\n}\n\nfunction createSignal(signal: AbortSignal | AbortSignal[] | undefined, timeout: number): AbortSignal {\n const timeoutSignal = createTimeoutSignal(timeout)\n\n if (Array.isArray(signal)) {\n return createAnySignal([...signal, timeoutSignal])\n }\n\n if (signal) {\n return createAnySignal([signal, timeoutSignal])\n }\n\n return timeoutSignal\n}\n\nfunction createTimeoutSignal(ms: number): AbortSignal {\n if (typeof AbortSignal?.timeout === 'function') {\n return AbortSignal.timeout(ms)\n }\n\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), ms)\n\n controller.signal.addEventListener('abort', () => clearTimeout(timeoutId), {\n once: true,\n })\n\n return controller.signal\n}\n\nfunction getRetryDelay(attempt: number, delay: number): number {\n return delay * 2 ** attempt\n}\n\nfunction isAbortError(err: unknown): boolean {\n return err instanceof DOMException && err.name === 'AbortError'\n}\n\nfunction isFormData(value: FormData | Record<string, unknown> | undefined): value is FormData {\n return typeof FormData !== 'undefined' && value instanceof FormData\n}\n\nfunction isRetryableStatus(status: number): boolean {\n return status >= 500 || status === 429\n}\n\nfunction joinUrl(baseURL: string, url: string): string {\n const normalizedBase = baseURL.endsWith('/') ? baseURL.slice(0, -1) : baseURL\n const normalizedUrl = url.startsWith('/') ? url.slice(1) : url\n\n return `${normalizedBase}/${normalizedUrl}`\n}\n\nfunction resolveHeaders(\n value: CreateHttpOptions['headers'],\n extraHeaders?: Record<string, string>,\n): Record<string, string> {\n const headers = typeof value === 'function' ? value() : value\n\n return Object.entries({\n ...headers,\n ...extraHeaders,\n }).reduce<Record<string, string>>((acc, [key, headerValue]) => {\n if (typeof headerValue === 'string') {\n acc[key] = headerValue\n }\n\n return acc\n }, {})\n}\n\nfunction serializeQueryValue(\n urlParams: URLSearchParams,\n key: string,\n value: HttpParam[string],\n arrayMode: QueryArrayMode,\n): void {\n if (value === undefined) {\n return\n }\n\n if (Array.isArray(value)) {\n if (arrayMode === 'json') {\n urlParams.append(key, JSON.stringify(value))\n return\n }\n\n value.forEach((item) => {\n urlParams.append(`${key}[]`, item)\n })\n return\n }\n\n urlParams.append(key, String(value))\n}\n\nfunction toQueryString(params?: HttpParam, arrayMode: QueryArrayMode = 'json'): string {\n const urlParams = new URLSearchParams()\n\n Object.entries(params ?? {}).forEach(([key, value]) => {\n serializeQueryValue(urlParams, key, value, arrayMode)\n })\n\n return urlParams.size > 0 ? `?${urlParams}` : ''\n}\n\nfunction wait(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n"],"mappings":"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"}
|
package/dist/nuxt.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { HttpClient, HttpError, HttpErrorGuard, HttpKey, HttpParam, HttpResponse, HttpResponseData, HttpSuccessData } from './http';
|
|
2
|
+
export interface CreateUseHttpDependencies {
|
|
3
|
+
channelName?: string;
|
|
4
|
+
getCache?: () => null | UseHttpCache;
|
|
5
|
+
getHttpClient: () => HttpClient;
|
|
6
|
+
isError?: HttpErrorGuard<unknown, HttpError>;
|
|
7
|
+
isDev?: () => boolean;
|
|
8
|
+
ttl?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface UseHttpCache {
|
|
11
|
+
deleteKeysWithPart: (part: string) => Promise<void>;
|
|
12
|
+
get: <T>(key: string) => Promise<null | UseHttpCacheEntry<T>>;
|
|
13
|
+
set: <T>(key: string, value: T, ttl: number) => Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
export interface UseHttpCacheEntry<T> {
|
|
16
|
+
hash: string;
|
|
17
|
+
value: T;
|
|
18
|
+
}
|
|
19
|
+
type UseHttpOptionsBase<T extends HttpKey, P extends HttpParam> = {
|
|
20
|
+
effect?: (data: HttpResponseData<T>, config: {
|
|
21
|
+
cached: boolean;
|
|
22
|
+
params: P;
|
|
23
|
+
}) => void;
|
|
24
|
+
ignore?: (response: HttpResponse<HttpError>) => boolean;
|
|
25
|
+
initParams?: P;
|
|
26
|
+
lazy?: true;
|
|
27
|
+
mapParams?: <R extends P>(params?: R) => R;
|
|
28
|
+
server?: boolean;
|
|
29
|
+
url: T;
|
|
30
|
+
};
|
|
31
|
+
export type UseHttpOptions<T extends HttpKey, P extends HttpParam> = UseHttpOptionsBase<T, P> & {
|
|
32
|
+
isError?: (payload: HttpResponseData<T>) => boolean;
|
|
33
|
+
};
|
|
34
|
+
export type CreateGetOptions<T extends HttpKey, P extends HttpParam> = Omit<UseHttpOptions<T, P>, 'url'>;
|
|
35
|
+
export interface CreateGetResult<T extends HttpKey, P extends HttpParam> {
|
|
36
|
+
data: HttpSuccessData<T> | null;
|
|
37
|
+
error: Extract<HttpResponseData<T>, HttpError> | null;
|
|
38
|
+
fetch: (params?: P, opt?: {
|
|
39
|
+
signal: AbortSignal;
|
|
40
|
+
}) => Promise<void>;
|
|
41
|
+
hasFirstData: boolean;
|
|
42
|
+
hasFreshData: boolean;
|
|
43
|
+
pending: boolean;
|
|
44
|
+
pendingCache: boolean;
|
|
45
|
+
}
|
|
46
|
+
export interface CreateGetPayload<T extends HttpKey, P extends HttpParam> {
|
|
47
|
+
effect?: (data: HttpResponseData<T>, config: {
|
|
48
|
+
cached: boolean;
|
|
49
|
+
params: P;
|
|
50
|
+
}) => undefined;
|
|
51
|
+
ignore?: (response: HttpResponse<HttpError>) => boolean;
|
|
52
|
+
isError?: (payload: HttpResponseData<T>) => boolean;
|
|
53
|
+
mapParams?: <R extends P>(params?: R) => R;
|
|
54
|
+
}
|
|
55
|
+
export interface UseHttpResult<T extends HttpKey, P extends HttpParam> {
|
|
56
|
+
data: HttpSuccessData<T> | null;
|
|
57
|
+
error: Extract<HttpResponseData<T>, HttpError> | null;
|
|
58
|
+
fetch: (params?: P, opt?: {
|
|
59
|
+
signal: AbortSignal;
|
|
60
|
+
}) => Promise<void>;
|
|
61
|
+
hasFirstData: boolean;
|
|
62
|
+
hasFreshData: boolean;
|
|
63
|
+
pending: boolean;
|
|
64
|
+
pendingCache: boolean;
|
|
65
|
+
}
|
|
66
|
+
export interface UseHttpFn {
|
|
67
|
+
<T extends HttpKey, P extends HttpParam>(options: UseHttpOptions<T, P>): Promise<UseHttpResult<T, P>>;
|
|
68
|
+
}
|
|
69
|
+
export declare function createGet(useHttp: UseHttpFn): <P extends HttpParam>() => <T extends HttpKey>(url: T, payload?: CreateGetPayload<T, P>) => (options?: CreateGetOptions<T, P>) => Promise<CreateGetResult<T, P>>;
|
|
70
|
+
export declare function createUseHttp(dependencies: CreateUseHttpDependencies): UseHttpFn;
|
|
71
|
+
export {};
|
|
72
|
+
//# sourceMappingURL=nuxt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nuxt.d.ts","sourceRoot":"","sources":["../src/nuxt.ts"],"names":[],"mappings":"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"}
|
package/dist/nuxt.mjs
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { r as hashData, t as createURL } from "./utils-DMSINHi5.js";
|
|
2
|
+
import { useLazyAsyncData, useState } from "#app";
|
|
3
|
+
import { onScopeDispose, shallowReactive, shallowRef } from "vue";
|
|
4
|
+
//#region src/nuxt.ts
|
|
5
|
+
const DAY = 1e3 * 60 * 60 * 24;
|
|
6
|
+
const DEFAULT_CHANNEL_NAME = "http-tab-sync";
|
|
7
|
+
const DEFAULT_TTL = DAY * 7;
|
|
8
|
+
function createGet(useHttp) {
|
|
9
|
+
return function withParams() {
|
|
10
|
+
return function withUrl(url, payload) {
|
|
11
|
+
return async function request(options = {}) {
|
|
12
|
+
return await useHttp({
|
|
13
|
+
ignore: payload?.ignore,
|
|
14
|
+
isError: options.isError ?? payload?.isError,
|
|
15
|
+
...options,
|
|
16
|
+
effect: (...args) => {
|
|
17
|
+
const [data, config] = args;
|
|
18
|
+
payload?.effect?.(data, config);
|
|
19
|
+
options?.effect?.(data, config);
|
|
20
|
+
},
|
|
21
|
+
mapParams: payload?.mapParams,
|
|
22
|
+
url
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function createUseHttp(dependencies) {
|
|
29
|
+
let channel;
|
|
30
|
+
const useHttp = async (options) => {
|
|
31
|
+
const mapParams = (params) => {
|
|
32
|
+
if (options.mapParams) return options.mapParams(params ?? {});
|
|
33
|
+
return params ?? {};
|
|
34
|
+
};
|
|
35
|
+
const effect = options.effect;
|
|
36
|
+
const isError = createIsErrorGuard(options.isError, dependencies.isError);
|
|
37
|
+
const buildUrl = createURL;
|
|
38
|
+
const initFullUrl = buildUrl(options.url, mapParams(options.initParams));
|
|
39
|
+
const httpClient = dependencies.getHttpClient();
|
|
40
|
+
const cache = import.meta.client ? dependencies.getCache?.() ?? null : null;
|
|
41
|
+
let hasDataFromServer = false;
|
|
42
|
+
const result = shallowReactive({
|
|
43
|
+
data: null,
|
|
44
|
+
error: null,
|
|
45
|
+
fetch: async (_params, _opt) => await void 0,
|
|
46
|
+
hasFirstData: false,
|
|
47
|
+
hasFreshData: false,
|
|
48
|
+
pending: true,
|
|
49
|
+
pendingCache: true
|
|
50
|
+
});
|
|
51
|
+
const setError = (value) => {
|
|
52
|
+
result.error = value;
|
|
53
|
+
};
|
|
54
|
+
const setData = (value) => {
|
|
55
|
+
result.data = value;
|
|
56
|
+
};
|
|
57
|
+
const syncResult = (payload) => {
|
|
58
|
+
if (payload == null) {
|
|
59
|
+
setData(null);
|
|
60
|
+
setError(null);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (isError(payload)) {
|
|
64
|
+
setData(null);
|
|
65
|
+
setError(payload);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
setData(payload);
|
|
69
|
+
setError(null);
|
|
70
|
+
};
|
|
71
|
+
const controller = new AbortController();
|
|
72
|
+
const serverData = useState(`http-${initFullUrl}`, () => null);
|
|
73
|
+
if (options.server && import.meta.server) {
|
|
74
|
+
const paramsReactive = shallowRef(mapParams(options.initParams));
|
|
75
|
+
const ssr = await useLazyAsyncData(initFullUrl, async () => {
|
|
76
|
+
return await httpClient.get(options.url, { params: paramsReactive.value });
|
|
77
|
+
});
|
|
78
|
+
result.fetch = async (params) => {
|
|
79
|
+
paramsReactive.value = mapParams(params);
|
|
80
|
+
await ssr.refresh();
|
|
81
|
+
};
|
|
82
|
+
serverData.value = ssr.data.value?.data ?? null;
|
|
83
|
+
const serverPayload = serverData.value;
|
|
84
|
+
syncResult(serverPayload);
|
|
85
|
+
result.pending = false;
|
|
86
|
+
result.pendingCache = false;
|
|
87
|
+
result.hasFirstData = true;
|
|
88
|
+
result.hasFreshData = true;
|
|
89
|
+
if (serverData.value) effect?.(serverData.value, {
|
|
90
|
+
cached: false,
|
|
91
|
+
params: mapParams(options.initParams)
|
|
92
|
+
});
|
|
93
|
+
if (result.data) hasDataFromServer = true;
|
|
94
|
+
}
|
|
95
|
+
if (import.meta.client) {
|
|
96
|
+
channel = getChannel(dependencies.channelName ?? DEFAULT_CHANNEL_NAME, channel);
|
|
97
|
+
const fullUrlHistory = {};
|
|
98
|
+
function onMessage(event) {
|
|
99
|
+
if (event.data.fullUrl && fullUrlHistory[event.data.fullUrl]) {
|
|
100
|
+
const eventPayload = event.data.data;
|
|
101
|
+
if (eventPayload) effect?.(eventPayload, {
|
|
102
|
+
cached: false,
|
|
103
|
+
params: event.data.params
|
|
104
|
+
});
|
|
105
|
+
syncResult(eventPayload);
|
|
106
|
+
result.hasFirstData = true;
|
|
107
|
+
result.hasFreshData = true;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
channel?.addEventListener("message", onMessage);
|
|
111
|
+
if (serverData.value) {
|
|
112
|
+
const clientServerPayload = serverData.value;
|
|
113
|
+
syncResult(clientServerPayload);
|
|
114
|
+
result.pending = false;
|
|
115
|
+
result.pendingCache = false;
|
|
116
|
+
result.hasFirstData = true;
|
|
117
|
+
result.hasFreshData = true;
|
|
118
|
+
}
|
|
119
|
+
const raceCondition = {};
|
|
120
|
+
const ttl = dependencies.ttl ?? DEFAULT_TTL;
|
|
121
|
+
const runFetch = async (params, fetchOpt) => {
|
|
122
|
+
const mappedParams = mapParams(params);
|
|
123
|
+
const fullUrl = buildUrl(options.url, mappedParams);
|
|
124
|
+
const fetchId = Date.now() + getRandom(0, 300);
|
|
125
|
+
if (raceCondition[fullUrl]) {
|
|
126
|
+
console.info("Race Condition affect", fullUrl);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
raceCondition[fullUrl] = fetchId;
|
|
130
|
+
try {
|
|
131
|
+
result.pending = true;
|
|
132
|
+
result.pendingCache = true;
|
|
133
|
+
const cachedFetch = cache && !dependencies.isDev?.() ? await cache.get(fullUrl) : null;
|
|
134
|
+
if (cachedFetch) {
|
|
135
|
+
const cachedPayload = cachedFetch.value;
|
|
136
|
+
effect?.(cachedPayload, {
|
|
137
|
+
cached: true,
|
|
138
|
+
params: mappedParams
|
|
139
|
+
});
|
|
140
|
+
syncResult(cachedPayload);
|
|
141
|
+
result.hasFirstData = true;
|
|
142
|
+
result.pendingCache = false;
|
|
143
|
+
}
|
|
144
|
+
if (controller.signal.aborted || fetchOpt?.signal?.aborted) throw new DOMException("Aborted", "AbortError");
|
|
145
|
+
const signalHttp = fetchOpt?.signal ? [controller.signal, fetchOpt.signal] : controller.signal;
|
|
146
|
+
const response = await httpClient.get(options.url, {
|
|
147
|
+
ignore: options.ignore,
|
|
148
|
+
params: mappedParams,
|
|
149
|
+
signal: signalHttp
|
|
150
|
+
});
|
|
151
|
+
const responsePayload = response.data;
|
|
152
|
+
effect?.(responsePayload, {
|
|
153
|
+
cached: false,
|
|
154
|
+
params: mappedParams
|
|
155
|
+
});
|
|
156
|
+
if (isError(responsePayload)) syncResult(responsePayload);
|
|
157
|
+
else {
|
|
158
|
+
syncResult(responsePayload);
|
|
159
|
+
const successData = responsePayload;
|
|
160
|
+
fullUrlHistory[fullUrl] = true;
|
|
161
|
+
channel?.postMessage({
|
|
162
|
+
data: normalizeBroadcastValue(successData),
|
|
163
|
+
fullUrl,
|
|
164
|
+
params: normalizeBroadcastValue(mappedParams),
|
|
165
|
+
type: "STATE_UPDATE"
|
|
166
|
+
});
|
|
167
|
+
if (cache) {
|
|
168
|
+
if (cachedFetch) {
|
|
169
|
+
if (await hashData(responsePayload) !== cachedFetch.hash) await cache.deleteKeysWithPart(options.url);
|
|
170
|
+
}
|
|
171
|
+
if (response.status === 200) await cache.set(fullUrl, successData, ttl);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
result.hasFirstData = true;
|
|
175
|
+
result.hasFreshData = true;
|
|
176
|
+
} catch (error) {
|
|
177
|
+
console.error(error);
|
|
178
|
+
} finally {
|
|
179
|
+
if (raceCondition[fullUrl] === fetchId) delete raceCondition[fullUrl];
|
|
180
|
+
result.pending = false;
|
|
181
|
+
result.pendingCache = false;
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
result.fetch = runFetch;
|
|
185
|
+
if (!hasDataFromServer && options.lazy !== true) runFetch(options.initParams);
|
|
186
|
+
onScopeDispose(() => {
|
|
187
|
+
channel?.removeEventListener("message", onMessage);
|
|
188
|
+
controller.abort(`Http Abort -> onScopeDispose ${options.url}`);
|
|
189
|
+
if (serverData.value) serverData.value = null;
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
return result;
|
|
193
|
+
};
|
|
194
|
+
return useHttp;
|
|
195
|
+
}
|
|
196
|
+
function getChannel(name, currentChannel) {
|
|
197
|
+
if (currentChannel) return currentChannel;
|
|
198
|
+
if (import.meta.server || typeof BroadcastChannel !== "function") return null;
|
|
199
|
+
return new BroadcastChannel(name);
|
|
200
|
+
}
|
|
201
|
+
function getRandom(min, max) {
|
|
202
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
203
|
+
}
|
|
204
|
+
function hasErrorStatus(payload) {
|
|
205
|
+
return Boolean(payload && typeof payload === "object" && "status" in payload && payload.status === "error");
|
|
206
|
+
}
|
|
207
|
+
function createIsErrorGuard(localGuard, globalGuard) {
|
|
208
|
+
if (localGuard) return localGuard;
|
|
209
|
+
if (globalGuard) return globalGuard;
|
|
210
|
+
return (payload) => hasErrorStatus(payload);
|
|
211
|
+
}
|
|
212
|
+
function normalizeBroadcastValue(payload) {
|
|
213
|
+
try {
|
|
214
|
+
return structuredClone(payload);
|
|
215
|
+
} catch {
|
|
216
|
+
return JSON.parse(JSON.stringify(payload));
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
//#endregion
|
|
220
|
+
export { createGet, createUseHttp };
|
|
221
|
+
|
|
222
|
+
//# sourceMappingURL=nuxt.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nuxt.mjs","names":[],"sources":["../src/nuxt.ts"],"sourcesContent":["import { useLazyAsyncData, useState } from '#app'\nimport { onScopeDispose, shallowReactive, shallowRef } from 'vue'\n\nimport type {\n HttpClient,\n HttpError,\n HttpErrorGuard,\n HttpKey,\n HttpParam,\n HttpResponse,\n HttpResponseData,\n HttpSuccessData,\n} from './http'\n\nimport { createURL, hashData } from './utils'\n\nconst DAY = 1000 * 60 * 60 * 24\nconst DEFAULT_CHANNEL_NAME = 'http-tab-sync'\nconst DEFAULT_TTL = DAY * 7\n\nexport interface CreateUseHttpDependencies {\n channelName?: string\n getCache?: () => null | UseHttpCache\n getHttpClient: () => HttpClient\n isError?: HttpErrorGuard<unknown, HttpError>\n isDev?: () => boolean\n ttl?: number\n}\n\nexport interface UseHttpCache {\n deleteKeysWithPart: (part: string) => Promise<void>\n get: <T>(key: string) => Promise<null | UseHttpCacheEntry<T>>\n set: <T>(key: string, value: T, ttl: number) => Promise<void>\n}\n\nexport interface UseHttpCacheEntry<T> {\n hash: string\n value: T\n}\n\ntype UseHttpOptionsBase<T extends HttpKey, P extends HttpParam> = {\n effect?: (\n data: HttpResponseData<T>,\n config: {\n cached: boolean\n params: P\n },\n ) => void\n ignore?: (response: HttpResponse<HttpError>) => boolean\n initParams?: P\n lazy?: true\n mapParams?: <R extends P>(params?: R) => R\n server?: boolean\n url: T\n}\n\nexport type UseHttpOptions<T extends HttpKey, P extends HttpParam> = UseHttpOptionsBase<T, P> & {\n isError?: (payload: HttpResponseData<T>) => boolean\n}\n\nexport type CreateGetOptions<T extends HttpKey, P extends HttpParam> = Omit<UseHttpOptions<T, P>, 'url'>\n\nexport interface CreateGetResult<T extends HttpKey, P extends HttpParam> {\n data: HttpSuccessData<T> | null\n error: Extract<HttpResponseData<T>, HttpError> | null\n fetch: (params?: P, opt?: { signal: AbortSignal }) => Promise<void>\n hasFirstData: boolean\n hasFreshData: boolean\n pending: boolean\n pendingCache: boolean\n}\n\nexport interface CreateGetPayload<T extends HttpKey, P extends HttpParam> {\n effect?: (\n data: HttpResponseData<T>,\n config: {\n cached: boolean\n params: P\n },\n ) => undefined\n ignore?: (response: HttpResponse<HttpError>) => boolean\n isError?: (payload: HttpResponseData<T>) => boolean\n mapParams?: <R extends P>(params?: R) => R\n}\n\nexport interface UseHttpResult<T extends HttpKey, P extends HttpParam> {\n data: HttpSuccessData<T> | null\n error: Extract<HttpResponseData<T>, HttpError> | null\n fetch: (params?: P, opt?: { signal: AbortSignal }) => Promise<void>\n hasFirstData: boolean\n hasFreshData: boolean\n pending: boolean\n pendingCache: boolean\n}\n\ntype BroadcastMessage = {\n data: unknown\n fullUrl: string\n params: HttpParam\n type: 'STATE_UPDATE'\n}\n\nexport interface UseHttpFn {\n <T extends HttpKey, P extends HttpParam>(options: UseHttpOptions<T, P>): Promise<UseHttpResult<T, P>>\n}\n\nexport function createGet(useHttp: UseHttpFn) {\n return function withParams<P extends HttpParam>() {\n return function withUrl<T extends HttpKey>(\n url: T,\n payload?: CreateGetPayload<T, P>,\n ): (options?: CreateGetOptions<T, P>) => Promise<CreateGetResult<T, P>> {\n return async function request(options: CreateGetOptions<T, P> = {}): Promise<CreateGetResult<T, P>> {\n const result = await useHttp({\n ignore: payload?.ignore,\n isError: options.isError ?? payload?.isError,\n ...options,\n effect: (...args) => {\n const [data, config] = args\n\n payload?.effect?.(data, config)\n options?.effect?.(data, config)\n },\n mapParams: payload?.mapParams,\n url,\n })\n\n return result\n }\n }\n }\n}\n\nexport function createUseHttp(dependencies: CreateUseHttpDependencies) {\n let channel: BroadcastChannel | null\n\n const useHttp: UseHttpFn = async <T extends HttpKey, P extends HttpParam>(\n options: UseHttpOptions<T, P>,\n ): Promise<UseHttpResult<T, P>> => {\n const mapParams = (params?: P): P => {\n if (options.mapParams) {\n return options.mapParams(params ?? ({} as P))\n }\n\n return params ?? ({} as P)\n }\n const effect = options.effect\n const isError = createIsErrorGuard(options.isError, dependencies.isError)\n\n const buildUrl = createURL\n const initFullUrl = buildUrl(options.url, mapParams(options.initParams))\n const httpClient = dependencies.getHttpClient()\n const cache = import.meta.client ? (dependencies.getCache?.() ?? null) : null\n let hasDataFromServer = false\n\n const result = shallowReactive({\n data: null as null | unknown,\n error: null as null | unknown,\n fetch: async (_params?: P, _opt?: { signal: AbortSignal }): Promise<void> => await undefined,\n hasFirstData: false,\n hasFreshData: false,\n pending: true,\n pendingCache: true,\n })\n const setError = (value: null | unknown): void => {\n result.error = value\n }\n const setData = (value: null | unknown): void => {\n result.data = value\n }\n const syncResult = (payload: HttpResponseData<T> | null | undefined): void => {\n if (payload == null) {\n setData(null)\n setError(null)\n return\n }\n\n if (isError(payload)) {\n setData(null)\n setError(payload)\n return\n }\n\n setData(payload)\n setError(null)\n }\n\n const controller = new AbortController()\n const serverData = useState<null | unknown>(`http-${initFullUrl}`, () => null)\n\n if (options.server && import.meta.server) {\n const paramsReactive = shallowRef(mapParams(options.initParams))\n const ssr = await useLazyAsyncData(initFullUrl, async () => {\n return await httpClient.get<T>(options.url, {\n params: paramsReactive.value,\n })\n })\n\n result.fetch = async (params?: P) => {\n paramsReactive.value = mapParams(params)\n await ssr.refresh()\n }\n\n serverData.value = ssr.data.value?.data ?? null\n const serverPayload = serverData.value as HttpResponseData<T>\n syncResult(serverPayload)\n\n result.pending = false\n result.pendingCache = false\n result.hasFirstData = true\n result.hasFreshData = true\n\n if (serverData.value) {\n effect?.(serverData.value as HttpResponseData<T>, {\n cached: false,\n params: mapParams(options.initParams),\n })\n }\n\n if (result.data) {\n hasDataFromServer = true\n }\n }\n\n if (import.meta.client) {\n channel = getChannel(dependencies.channelName ?? DEFAULT_CHANNEL_NAME, channel)\n const fullUrlHistory: Record<string, true> = {}\n\n function onMessage(event: MessageEvent<Partial<BroadcastMessage>>): void {\n if (event.data.fullUrl && fullUrlHistory[event.data.fullUrl]) {\n const eventPayload = event.data.data as HttpResponseData<T> | undefined\n\n if (eventPayload) {\n effect?.(eventPayload, {\n cached: false,\n params: event.data.params as P,\n })\n }\n\n syncResult(eventPayload)\n\n result.hasFirstData = true\n result.hasFreshData = true\n }\n }\n\n channel?.addEventListener('message', onMessage)\n\n if (serverData.value) {\n const clientServerPayload = serverData.value as HttpResponseData<T>\n syncResult(clientServerPayload)\n result.pending = false\n result.pendingCache = false\n result.hasFirstData = true\n result.hasFreshData = true\n }\n\n const raceCondition: Record<string, number> = {}\n const ttl = dependencies.ttl ?? DEFAULT_TTL\n\n const runFetch = async (params?: P, fetchOpt?: { signal?: AbortSignal }): Promise<void> => {\n const mappedParams = mapParams(params)\n const fullUrl = buildUrl(options.url, mappedParams)\n const fetchId = Date.now() + getRandom(0, 300)\n\n if (raceCondition[fullUrl]) {\n console.info('Race Condition affect', fullUrl)\n return\n }\n\n raceCondition[fullUrl] = fetchId\n\n try {\n result.pending = true\n result.pendingCache = true\n\n const cachedFetch = cache && !dependencies.isDev?.() ? await cache.get<unknown>(fullUrl) : null\n\n if (cachedFetch) {\n const cachedPayload = cachedFetch.value as HttpResponseData<T>\n\n effect?.(cachedPayload, {\n cached: true,\n params: mappedParams,\n })\n\n syncResult(cachedPayload)\n result.hasFirstData = true\n\n result.pendingCache = false\n }\n\n if (controller.signal.aborted || fetchOpt?.signal?.aborted) {\n throw new DOMException('Aborted', 'AbortError')\n }\n\n const signalHttp = fetchOpt?.signal ? [controller.signal, fetchOpt.signal] : controller.signal\n const response = await httpClient.get<T>(options.url, {\n ignore: options.ignore,\n params: mappedParams,\n signal: signalHttp,\n })\n const responsePayload = response.data as HttpResponseData<T>\n\n effect?.(responsePayload, {\n cached: false,\n params: mappedParams,\n })\n\n if (isError(responsePayload)) {\n syncResult(responsePayload)\n } else {\n syncResult(responsePayload)\n const successData = responsePayload\n\n fullUrlHistory[fullUrl] = true\n channel?.postMessage({\n data: normalizeBroadcastValue(successData),\n fullUrl,\n params: normalizeBroadcastValue(mappedParams),\n type: 'STATE_UPDATE',\n } satisfies BroadcastMessage)\n\n if (cache) {\n if (cachedFetch) {\n const newHash = await hashData(responsePayload)\n if (newHash !== cachedFetch.hash) {\n await cache.deleteKeysWithPart(options.url)\n }\n }\n\n if (response.status === 200) {\n await cache.set(fullUrl, successData, ttl)\n }\n }\n }\n\n result.hasFirstData = true\n result.hasFreshData = true\n } catch (error) {\n console.error(error)\n } finally {\n if (raceCondition[fullUrl] === fetchId) {\n delete raceCondition[fullUrl]\n }\n\n result.pending = false\n result.pendingCache = false\n }\n }\n\n result.fetch = runFetch\n\n if (!hasDataFromServer && options.lazy !== true) {\n runFetch(options.initParams)\n }\n\n onScopeDispose(() => {\n channel?.removeEventListener('message', onMessage)\n controller.abort(`Http Abort -> onScopeDispose ${options.url}`)\n\n if (serverData.value) {\n serverData.value = null\n }\n })\n }\n\n return result as UseHttpResult<T, P>\n }\n\n return useHttp\n}\n\nfunction getChannel(name: string, currentChannel?: BroadcastChannel | null): BroadcastChannel | null {\n if (currentChannel) {\n return currentChannel\n }\n\n if (import.meta.server || typeof BroadcastChannel !== 'function') {\n return null\n }\n\n return new BroadcastChannel(name)\n}\n\nfunction getRandom(min: number, max: number): number {\n return Math.floor(Math.random() * (max - min + 1)) + min\n}\n\nfunction hasErrorStatus(payload: unknown): payload is { status: 'error' } {\n return Boolean(\n payload &&\n typeof payload === 'object' &&\n 'status' in payload &&\n (payload as { status?: string }).status === 'error',\n )\n}\n\nfunction createIsErrorGuard<TData>(\n localGuard?: (payload: TData) => boolean,\n globalGuard?: HttpErrorGuard<unknown, HttpError>,\n): (payload: TData) => boolean {\n if (localGuard) {\n return localGuard\n }\n\n if (globalGuard) {\n return globalGuard as (payload: TData) => boolean\n }\n\n return (payload: TData): boolean => hasErrorStatus(payload)\n}\n\nfunction normalizeBroadcastValue<T>(payload: T): T {\n try {\n return structuredClone(payload)\n } catch {\n return JSON.parse(JSON.stringify(payload)) as T\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
//#region src/utils.ts
|
|
2
|
+
function createURL(url, params) {
|
|
3
|
+
const urlParams = new URLSearchParams();
|
|
4
|
+
Object.entries(params ?? {}).forEach(([key, value]) => {
|
|
5
|
+
if (value === void 0) return;
|
|
6
|
+
if (Array.isArray(value)) {
|
|
7
|
+
value.forEach((item) => {
|
|
8
|
+
urlParams.append(`${key}[]`, item);
|
|
9
|
+
});
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
urlParams.append(key, String(value));
|
|
13
|
+
});
|
|
14
|
+
const query = urlParams.size > 0 ? `?${urlParams}` : "";
|
|
15
|
+
return urlParams.size > 0 ? `${url}${query}` : url;
|
|
16
|
+
}
|
|
17
|
+
function fastDevHash(data) {
|
|
18
|
+
const str = JSON.stringify(data);
|
|
19
|
+
let hash = 0;
|
|
20
|
+
for (let i = 0; i < str.length; i++) {
|
|
21
|
+
const chr = str.charCodeAt(i);
|
|
22
|
+
hash = (hash << 5) - hash + chr;
|
|
23
|
+
hash |= 0;
|
|
24
|
+
}
|
|
25
|
+
return Math.abs(hash).toString(16);
|
|
26
|
+
}
|
|
27
|
+
async function hashData(data) {
|
|
28
|
+
const subtle = globalThis.crypto?.subtle;
|
|
29
|
+
if (subtle) {
|
|
30
|
+
const encoded = new TextEncoder().encode(JSON.stringify(data));
|
|
31
|
+
const buffer = await subtle.digest("SHA-1", encoded);
|
|
32
|
+
return Array.from(new Uint8Array(buffer)).map((value) => value.toString(16).padStart(2, "0")).join("");
|
|
33
|
+
}
|
|
34
|
+
return fastDevHash(data);
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
export { fastDevHash as n, hashData as r, createURL as t };
|
|
38
|
+
|
|
39
|
+
//# sourceMappingURL=utils-DMSINHi5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils-DMSINHi5.js","names":[],"sources":["../src/utils.ts"],"sourcesContent":["import type { HttpParam } from './http'\n\nexport function createURL(url: string, params?: HttpParam): string {\n const urlParams = new URLSearchParams()\n\n Object.entries(params ?? {}).forEach(([key, value]) => {\n if (value === undefined) {\n return\n }\n\n if (Array.isArray(value)) {\n value.forEach((item) => {\n urlParams.append(`${key}[]`, item)\n })\n return\n }\n\n urlParams.append(key, String(value))\n })\n\n const query = urlParams.size > 0 ? `?${urlParams}` : ''\n return urlParams.size > 0 ? `${url}${query}` : url\n}\n\nexport function fastDevHash(data: unknown): string {\n const str = JSON.stringify(data)\n let hash = 0\n\n for (let i = 0; i < str.length; i++) {\n const chr = str.charCodeAt(i)\n hash = (hash << 5) - hash + chr\n hash |= 0\n }\n\n return Math.abs(hash).toString(16)\n}\n\nexport async function hashData(data: unknown): Promise<string> {\n const subtle = globalThis.crypto?.subtle\n\n if (subtle) {\n const encoded = new TextEncoder().encode(JSON.stringify(data))\n const buffer = await subtle.digest('SHA-1', encoded)\n const array = Array.from(new Uint8Array(buffer))\n\n return array.map((value) => value.toString(16).padStart(2, '0')).join('')\n }\n\n return fastDevHash(data)\n}\n"],"mappings":";AAEA,SAAgB,UAAU,KAAa,QAA4B;CACjE,MAAM,YAAY,IAAI,gBAAgB;CAEtC,OAAO,QAAQ,UAAU,CAAC,CAAC,EAAE,SAAS,CAAC,KAAK,WAAW;EACrD,IAAI,UAAU,KAAA,GACZ;EAGF,IAAI,MAAM,QAAQ,KAAK,GAAG;GACxB,MAAM,SAAS,SAAS;IACtB,UAAU,OAAO,GAAG,IAAI,KAAK,IAAI;GACnC,CAAC;GACD;EACF;EAEA,UAAU,OAAO,KAAK,OAAO,KAAK,CAAC;CACrC,CAAC;CAED,MAAM,QAAQ,UAAU,OAAO,IAAI,IAAI,cAAc;CACrD,OAAO,UAAU,OAAO,IAAI,GAAG,MAAM,UAAU;AACjD;AAEA,SAAgB,YAAY,MAAuB;CACjD,MAAM,MAAM,KAAK,UAAU,IAAI;CAC/B,IAAI,OAAO;CAEX,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;EACnC,MAAM,MAAM,IAAI,WAAW,CAAC;EAC5B,QAAQ,QAAQ,KAAK,OAAO;EAC5B,QAAQ;CACV;CAEA,OAAO,KAAK,IAAI,IAAI,EAAE,SAAS,EAAE;AACnC;AAEA,eAAsB,SAAS,MAAgC;CAC7D,MAAM,SAAS,WAAW,QAAQ;CAElC,IAAI,QAAQ;EACV,MAAM,UAAU,IAAI,YAAY,EAAE,OAAO,KAAK,UAAU,IAAI,CAAC;EAC7D,MAAM,SAAS,MAAM,OAAO,OAAO,SAAS,OAAO;EAGnD,OAFc,MAAM,KAAK,IAAI,WAAW,MAAM,CAEnC,EAAE,KAAK,UAAU,MAAM,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE;CAC1E;CAEA,OAAO,YAAY,IAAI;AACzB"}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { HttpParam } from './http';
|
|
2
|
+
export declare function createURL(url: string, params?: HttpParam): string;
|
|
3
|
+
export declare function fastDevHash(data: unknown): string;
|
|
4
|
+
export declare function hashData(data: unknown): Promise<string>;
|
|
5
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AAEvC,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,GAAG,MAAM,CAoBjE;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAWjD;AAED,wBAAsB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAY7D"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brickflow/http",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "",
|
|
5
|
-
"
|
|
3
|
+
"version": "0.0.15",
|
|
4
|
+
"description": "Minimal HTTP transport and Nuxt state helpers for brickflow.",
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"main": "./dist/index.mjs",
|
|
10
|
+
"module": "./dist/index.mjs",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"development": "./src/index.ts",
|
|
16
|
+
"import": "./dist/index.mjs",
|
|
17
|
+
"default": "./dist/index.mjs"
|
|
18
|
+
},
|
|
19
|
+
"./nuxt": {
|
|
20
|
+
"types": "./dist/nuxt.d.ts",
|
|
21
|
+
"development": "./src/nuxt.ts",
|
|
22
|
+
"import": "./dist/nuxt.mjs",
|
|
23
|
+
"default": "./dist/nuxt.mjs"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
6
26
|
"scripts": {
|
|
7
|
-
"
|
|
27
|
+
"build": "rolldown -c build.config.ts && tsc --project tsconfig.build.json",
|
|
28
|
+
"typecheck": "NODE_OPTIONS='--conditions=development' tsc --project tsconfig.json --noEmit",
|
|
29
|
+
"lint": "pnpm run --if-present typecheck",
|
|
8
30
|
"lint:fix": "pnpm exec eslint . --fix",
|
|
9
31
|
"format": "pnpm exec prettier . --ignore-path ../../.prettierignore --write",
|
|
10
32
|
"format:check": "pnpm exec prettier . --ignore-path ../../.prettierignore --check"
|
|
@@ -12,10 +34,17 @@
|
|
|
12
34
|
"publishConfig": {
|
|
13
35
|
"access": "public"
|
|
14
36
|
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@nuxt/kit": "3.21.7"
|
|
39
|
+
},
|
|
15
40
|
"devDependencies": {
|
|
16
41
|
"@brickflow/lint": "workspace:*",
|
|
17
|
-
"@brickflow/prettier": "workspace:*"
|
|
42
|
+
"@brickflow/prettier": "workspace:*",
|
|
43
|
+
"rolldown": "1.0.3",
|
|
44
|
+
"vue-tsc": "3.3.2"
|
|
18
45
|
},
|
|
19
|
-
"
|
|
20
|
-
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"nuxt": ">=3",
|
|
48
|
+
"vue": ">=3"
|
|
49
|
+
}
|
|
21
50
|
}
|
package/CHANGELOG.md
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
# @brickflow/http
|
|
2
|
-
|
|
3
|
-
## 0.0.13
|
|
4
|
-
|
|
5
|
-
### Patch Changes
|
|
6
|
-
|
|
7
|
-
- update multiply file in types
|
|
8
|
-
|
|
9
|
-
## 0.0.12
|
|
10
|
-
|
|
11
|
-
### Patch Changes
|
|
12
|
-
|
|
13
|
-
- Fix workspace cli translate
|
|
14
|
-
|
|
15
|
-
## 0.0.11
|
|
16
|
-
|
|
17
|
-
### Patch Changes
|
|
18
|
-
|
|
19
|
-
- Ban defineSlots
|
|
20
|
-
|
|
21
|
-
## 0.0.10
|
|
22
|
-
|
|
23
|
-
### Patch Changes
|
|
24
|
-
|
|
25
|
-
- Remove cli upgrade
|
|
26
|
-
|
|
27
|
-
## 0.0.9
|
|
28
|
-
|
|
29
|
-
### Patch Changes
|
|
30
|
-
|
|
31
|
-
- fix entry cd
|
|
32
|
-
|
|
33
|
-
## 0.0.8
|
|
34
|
-
|
|
35
|
-
### Patch Changes
|
|
36
|
-
|
|
37
|
-
- Translate context
|
|
38
|
-
|
|
39
|
-
## 0.0.7
|
|
40
|
-
|
|
41
|
-
### Patch Changes
|
|
42
|
-
|
|
43
|
-
- CLI command base
|
|
44
|
-
|
|
45
|
-
## 0.0.6
|
|
46
|
-
|
|
47
|
-
### Patch Changes
|
|
48
|
-
|
|
49
|
-
- -
|
|
50
|
-
|
|
51
|
-
## 0.0.5
|
|
52
|
-
|
|
53
|
-
### Patch Changes
|
|
54
|
-
|
|
55
|
-
- Bump vesrions
|
|
56
|
-
|
|
57
|
-
## 0.0.4
|
|
58
|
-
|
|
59
|
-
### Patch Changes
|
|
60
|
-
|
|
61
|
-
- Lint support commonJS
|
|
62
|
-
|
|
63
|
-
## 0.0.3
|
|
64
|
-
|
|
65
|
-
### Patch Changes
|
|
66
|
-
|
|
67
|
-
- 75f0614: Config for all
|
|
68
|
-
|
|
69
|
-
## 0.0.2
|
|
70
|
-
|
|
71
|
-
### Patch Changes
|
|
72
|
-
|
|
73
|
-
- 1772994: Test
|
|
74
|
-
|
|
75
|
-
## 0.0.1
|
|
76
|
-
|
|
77
|
-
### Patch Changes
|
|
78
|
-
|
|
79
|
-
- First commit
|
package/eslint.config.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default } from '@brickflow/lint'
|
package/prettier.config.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default } from '@brickflow/prettier'
|