@beyonk/http 12.0.0 → 12.1.1
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 +3 -5
- package/package.json +18 -12
- package/.github/workflows/publish.yml +0 -60
- package/lib/api/_just-compose.js +0 -12
- package/lib/api/index.js +0 -231
- package/lib/api/index.spec.js +0 -954
- package/lib/entrypoint.js +0 -19
- package/lib/error-handlers/access-denied.js +0 -12
- package/lib/error-handlers/bad-data.js +0 -12
- package/lib/error-handlers/conflict.js +0 -12
- package/lib/error-handlers/default.js +0 -8
- package/lib/error-handlers/expectation-failed.js +0 -12
- package/lib/error-handlers/forbidden.js +0 -12
- package/lib/error-handlers/gone.js +0 -12
- package/lib/error-handlers/handle.js +0 -25
- package/lib/error-handlers/not-acceptable.js +0 -12
- package/lib/error-handlers/not-found.js +0 -12
- package/lib/error-handlers/payment-required.js +0 -12
- package/lib/error-handlers/precondition-failed.js +0 -12
- package/lib/error-handlers/too-many-requests.js +0 -12
- package/lib/errors.js +0 -73
package/README.MD
CHANGED
|
@@ -188,9 +188,7 @@ Handlers have a signature with two items:
|
|
|
188
188
|
```js
|
|
189
189
|
.badData((e, ctx) => {
|
|
190
190
|
console.error('Bad data', e)
|
|
191
|
-
|
|
192
|
-
// or
|
|
193
|
-
ctx.error('/foo/bar')
|
|
191
|
+
throw redirect('/foo/bar')
|
|
194
192
|
})
|
|
195
193
|
```
|
|
196
194
|
|
|
@@ -201,7 +199,7 @@ However, if the `context` object you pass in has a `fetch` function, this is use
|
|
|
201
199
|
```js
|
|
202
200
|
export async function preload () {
|
|
203
201
|
await Api
|
|
204
|
-
.context(
|
|
202
|
+
.context({ fetch })
|
|
205
203
|
.endpoint('foo/bar')
|
|
206
204
|
...
|
|
207
205
|
}
|
|
@@ -232,7 +230,7 @@ Names are the same as the local handlers:
|
|
|
232
230
|
baseUrl: 'https://example.com/your/api/base',
|
|
233
231
|
handlers: {
|
|
234
232
|
paymentRequired(e => {
|
|
235
|
-
redirect(307, '/checkout')
|
|
233
|
+
throw redirect(307, '/checkout')
|
|
236
234
|
})
|
|
237
235
|
}
|
|
238
236
|
})
|
package/package.json
CHANGED
|
@@ -1,24 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@beyonk/http",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.1.1",
|
|
4
4
|
"description": "An isomorphic http client for Svelte apps",
|
|
5
|
-
"main": "lib/entrypoint.js",
|
|
6
|
-
"module": "lib/entrypoint.js",
|
|
7
5
|
"type": "module",
|
|
8
|
-
"directories": {
|
|
9
|
-
"lib": "lib"
|
|
10
|
-
},
|
|
11
6
|
"repository": {
|
|
12
7
|
"type": "git",
|
|
13
8
|
"url": "https://github.com/beyonk-adventures/http.git"
|
|
14
9
|
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"import": "./dist/index.js",
|
|
17
|
+
"require": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
15
20
|
"devDependencies": {
|
|
16
|
-
"@beyonk/eslint-config": "^
|
|
17
|
-
"@beyonk/esm": "^4.0.1",
|
|
21
|
+
"@beyonk/eslint-config": "^9.0.3",
|
|
18
22
|
"@hapi/code": "^5.3.1",
|
|
19
|
-
"eslint": "^
|
|
23
|
+
"eslint": "^9.29.0",
|
|
20
24
|
"mocha": "^9.0.2",
|
|
21
|
-
"sinon": "^7.5.0"
|
|
25
|
+
"sinon": "^7.5.0",
|
|
26
|
+
"tsup": "^8.4.0",
|
|
27
|
+
"typescript": "^5.8.3"
|
|
22
28
|
},
|
|
23
29
|
"eslintConfig": {
|
|
24
30
|
"extends": "@beyonk",
|
|
@@ -45,9 +51,9 @@
|
|
|
45
51
|
"volta": {
|
|
46
52
|
"node": "18.15.0"
|
|
47
53
|
},
|
|
48
|
-
"packageManager": "pnpm@8.0.0",
|
|
49
54
|
"scripts": {
|
|
50
55
|
"test": "mocha './!(node_modules)/**/**.+(spec).js'",
|
|
51
|
-
"lint": "eslint lib --ext .js"
|
|
56
|
+
"lint": "eslint lib --ext .js",
|
|
57
|
+
"build": "tsup"
|
|
52
58
|
}
|
|
53
59
|
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
name: publish
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches:
|
|
6
|
-
- '*'
|
|
7
|
-
tags:
|
|
8
|
-
- 'v*'
|
|
9
|
-
|
|
10
|
-
jobs:
|
|
11
|
-
build:
|
|
12
|
-
runs-on: ubuntu-latest
|
|
13
|
-
steps:
|
|
14
|
-
- uses: actions/checkout@v3
|
|
15
|
-
with:
|
|
16
|
-
ref: master
|
|
17
|
-
|
|
18
|
-
- uses: volta-cli/action@v4
|
|
19
|
-
|
|
20
|
-
- name: Cache pnpm modules
|
|
21
|
-
uses: actions/cache@v2
|
|
22
|
-
with:
|
|
23
|
-
path: ~/.pnpm-store
|
|
24
|
-
key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
|
|
25
|
-
restore-keys: |
|
|
26
|
-
${{ runner.os }}-
|
|
27
|
-
|
|
28
|
-
- uses: pnpm/action-setup@v2.2.4
|
|
29
|
-
with:
|
|
30
|
-
run_install: true
|
|
31
|
-
|
|
32
|
-
- run: pnpm lint
|
|
33
|
-
|
|
34
|
-
publish-npm:
|
|
35
|
-
if: startsWith(github.ref, 'refs/tags/v')
|
|
36
|
-
needs: build
|
|
37
|
-
runs-on: ubuntu-latest
|
|
38
|
-
steps:
|
|
39
|
-
- uses: actions/checkout@v3
|
|
40
|
-
with:
|
|
41
|
-
ref: master
|
|
42
|
-
|
|
43
|
-
- uses: volta-cli/action@v4
|
|
44
|
-
|
|
45
|
-
- name: Authorize NPM
|
|
46
|
-
run: npm config set //registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}
|
|
47
|
-
|
|
48
|
-
- name: Cache pnpm modules
|
|
49
|
-
uses: actions/cache@v2
|
|
50
|
-
with:
|
|
51
|
-
path: ~/.pnpm-store
|
|
52
|
-
key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
|
|
53
|
-
restore-keys: |
|
|
54
|
-
${{ runner.os }}-
|
|
55
|
-
|
|
56
|
-
- uses: pnpm/action-setup@v2.2.4
|
|
57
|
-
with:
|
|
58
|
-
run_install: true
|
|
59
|
-
|
|
60
|
-
- run: pnpm publish
|
package/lib/api/_just-compose.js
DELETED
package/lib/api/index.js
DELETED
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
import { AccessDeniedMixin } from '../error-handlers/access-denied.js'
|
|
2
|
-
import { ConflictMixin } from '../error-handlers/conflict.js'
|
|
3
|
-
import { DefaultMixin } from '../error-handlers/default.js'
|
|
4
|
-
import { ForbiddenMixin } from '../error-handlers/forbidden.js'
|
|
5
|
-
import { HandleMixin } from '../error-handlers/handle.js'
|
|
6
|
-
import { NotFoundMixin } from '../error-handlers/not-found.js'
|
|
7
|
-
import { BadDataMixin } from '../error-handlers/bad-data.js'
|
|
8
|
-
import { PaymentRequiredMixin } from '../error-handlers/payment-required.js'
|
|
9
|
-
import { PreconditionFailedMixin } from '../error-handlers/precondition-failed.js'
|
|
10
|
-
import { TooManyRequestsMixin } from '../error-handlers/too-many-requests.js'
|
|
11
|
-
import { NotAcceptableMixin } from '../error-handlers/not-acceptable.js'
|
|
12
|
-
import { GoneMixin } from '../error-handlers/gone.js'
|
|
13
|
-
import { byCode } from '../errors.js'
|
|
14
|
-
import { compose } from './_just-compose.js'
|
|
15
|
-
|
|
16
|
-
class ApiBase {}
|
|
17
|
-
const Behaviours = compose(
|
|
18
|
-
AccessDeniedMixin,
|
|
19
|
-
ConflictMixin,
|
|
20
|
-
DefaultMixin,
|
|
21
|
-
ForbiddenMixin,
|
|
22
|
-
HandleMixin,
|
|
23
|
-
NotFoundMixin,
|
|
24
|
-
BadDataMixin,
|
|
25
|
-
PaymentRequiredMixin,
|
|
26
|
-
PreconditionFailedMixin,
|
|
27
|
-
TooManyRequestsMixin,
|
|
28
|
-
NotAcceptableMixin,
|
|
29
|
-
GoneMixin
|
|
30
|
-
)(ApiBase)
|
|
31
|
-
|
|
32
|
-
class Api extends Behaviours {
|
|
33
|
-
constructor (options) {
|
|
34
|
-
super()
|
|
35
|
-
this.options = Object.assign({
|
|
36
|
-
retry: false,
|
|
37
|
-
parseErrors: true,
|
|
38
|
-
handlers: {}
|
|
39
|
-
}, options)
|
|
40
|
-
|
|
41
|
-
this.handlers = {}
|
|
42
|
-
this.client = null
|
|
43
|
-
this.resetRequest()
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
resetRequest () {
|
|
47
|
-
this.config = {
|
|
48
|
-
endpoint: null,
|
|
49
|
-
method: 'get',
|
|
50
|
-
payload: null,
|
|
51
|
-
query: null,
|
|
52
|
-
headers: {},
|
|
53
|
-
overrides: {}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
getClient () {
|
|
58
|
-
if (this.options.mock) {
|
|
59
|
-
console.warn('@beyonk/http: Using mocked http client')
|
|
60
|
-
return this.options.mock
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (this.client) {
|
|
64
|
-
return this.client
|
|
65
|
-
} else if (typeof window !== 'undefined') {
|
|
66
|
-
return window.fetch.bind(window)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
throw Error("No client provided and can't find one automatically")
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
async send (fn) {
|
|
73
|
-
const endpoint = this.config.endpoint.includes('://') ? this.config.endpoint : `${this.options.baseUrl}/${this.config.endpoint}`
|
|
74
|
-
const hasPayload = !!this.config.payload
|
|
75
|
-
|
|
76
|
-
const options = Object.assign(
|
|
77
|
-
{
|
|
78
|
-
method: this.config.method,
|
|
79
|
-
cors: true,
|
|
80
|
-
credentials: 'include',
|
|
81
|
-
headers: Object.assign(
|
|
82
|
-
{ Accept: 'application/json' },
|
|
83
|
-
hasPayload ? { 'Content-Type': 'application/json' } : {},
|
|
84
|
-
this.config.headers
|
|
85
|
-
)
|
|
86
|
-
},
|
|
87
|
-
hasPayload ? { body: JSON.stringify(this.config.payload) } : {},
|
|
88
|
-
this.config.overrides
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
const client = this.getClient()
|
|
92
|
-
const ep = this.config.query ? `${endpoint}?${this.config.query}` : `${endpoint}`
|
|
93
|
-
|
|
94
|
-
let result
|
|
95
|
-
try {
|
|
96
|
-
result = await this._doQuery(1, client, ep, options)
|
|
97
|
-
} catch (e) {
|
|
98
|
-
console.log(e)
|
|
99
|
-
return this.handle(e, this.ctx)
|
|
100
|
-
} finally {
|
|
101
|
-
this.resetRequest()
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const { json, httpStatus } = result
|
|
105
|
-
return fn ? fn(json, httpStatus) : json
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
_hasContent (response) {
|
|
109
|
-
const contentLength = parseInt(response.headers.get('content-length'), 10)
|
|
110
|
-
|
|
111
|
-
const isNoContentResponse = response.status === 204
|
|
112
|
-
if (isNoContentResponse) {
|
|
113
|
-
return false
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const headerExists = !isNaN(contentLength)
|
|
117
|
-
return !headerExists || contentLength > 0
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
async _doQuery (attempt, client, endpoint, options) {
|
|
121
|
-
const retry = this.options.retry || { attempts: 1 }
|
|
122
|
-
try {
|
|
123
|
-
const r = await client(endpoint, options)
|
|
124
|
-
|
|
125
|
-
if (r.status >= 200 && r.status < 400) {
|
|
126
|
-
let json
|
|
127
|
-
|
|
128
|
-
if (this._hasContent(r)) {
|
|
129
|
-
try {
|
|
130
|
-
json = await r.json()
|
|
131
|
-
} catch (e) {
|
|
132
|
-
console.error('Unable to parse response json', e.message)
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return { httpStatus: r.status, json }
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
let content = ''
|
|
140
|
-
try {
|
|
141
|
-
content = this.options.parseErrors ? await r.json() : await r.text()
|
|
142
|
-
} catch (e) {
|
|
143
|
-
console.log('Failed to parse error body when asked.')
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const ClientError = byCode(r.status)
|
|
147
|
-
throw new ClientError(r.statusText, content)
|
|
148
|
-
} catch (e) {
|
|
149
|
-
if (attempt < retry.attempts && retry.errors.includes(e.code)) {
|
|
150
|
-
console.warn(`Got ${e.code} when calling ${endpoint}. Retrying request (${attempt}/${retry.attempts})`)
|
|
151
|
-
return this._doQuery(++attempt, client, endpoint, options)
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
throw e
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
context (ctx) {
|
|
159
|
-
if (ctx.fetch) {
|
|
160
|
-
this.client = ctx.fetch
|
|
161
|
-
}
|
|
162
|
-
this.ctx = ctx
|
|
163
|
-
return this
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
override (override) {
|
|
167
|
-
this.config.overrides = override
|
|
168
|
-
return this
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
headers (headers) {
|
|
172
|
-
this.config.headers = headers
|
|
173
|
-
return this
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
async get (fn) {
|
|
177
|
-
this.config.method = 'GET'
|
|
178
|
-
return this.send(fn)
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
async post (fn) {
|
|
182
|
-
this.config.method = 'POST'
|
|
183
|
-
return this.send(fn)
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
async patch (fn) {
|
|
187
|
-
this.config.method = 'PATCH'
|
|
188
|
-
return this.send(fn)
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
async put (fn) {
|
|
192
|
-
this.config.method = 'PUT'
|
|
193
|
-
return this.send(fn)
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
async del (fn) {
|
|
197
|
-
this.config.method = 'DELETE'
|
|
198
|
-
return this.send(fn)
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
endpoint (endpoint) {
|
|
202
|
-
this.config.endpoint = endpoint
|
|
203
|
-
return this
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
query (query) {
|
|
207
|
-
const q = Object.entries(query).reduce((curr, [ k, v ]) => {
|
|
208
|
-
if (typeof v === 'undefined') {
|
|
209
|
-
return curr
|
|
210
|
-
}
|
|
211
|
-
if (Array.isArray(v)) {
|
|
212
|
-
curr.push(...v.map(n => `${k}=${encodeURIComponent(n)}`))
|
|
213
|
-
} else {
|
|
214
|
-
curr.push(`${k}=${encodeURIComponent(v)}`)
|
|
215
|
-
}
|
|
216
|
-
return curr
|
|
217
|
-
}, [])
|
|
218
|
-
|
|
219
|
-
this.config.query = q.join('&')
|
|
220
|
-
return this
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
payload (payload) {
|
|
224
|
-
this.config.payload = payload
|
|
225
|
-
return this
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
export {
|
|
230
|
-
Api
|
|
231
|
-
}
|