@d1g1tal/transportr 2.1.2 → 2.2.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/CHANGELOG.md +231 -0
- package/LICENSE +18 -9
- package/README.md +150 -19
- package/dist/transportr.d.ts +1 -1
- package/dist/transportr.js +2 -2
- package/dist/transportr.js.map +4 -4
- package/package.json +20 -19
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
## [2.2.1](https://github.com/D1g1talEntr0py/transportr/compare/v2.2.0...v2.2.1) (2026-04-04)
|
|
2
|
+
|
|
3
|
+
### Bug Fixes
|
|
4
|
+
|
|
5
|
+
* **deps:** update subscribr dependency to address security issues via Dependabot (0a04a16e34daaae749927b4893f15a972d4eb5e0)
|
|
6
|
+
|
|
7
|
+
### Miscellaneous Chores
|
|
8
|
+
|
|
9
|
+
* adjust typescript configuration and vs code settings (c1f28dff23025853f236fa380bc4f6e0ec26dd8c)
|
|
10
|
+
Updates `tsconfig.json` to use module preservation and stable type ordering, and refines cases for standard libraries. Updates `.vscode` configuration to point correctly to the local typescript SDK path.
|
|
11
|
+
|
|
12
|
+
* **deps-dev:** update essential dev dependencies (b94738075ce674d7e65952433cd553fa7af0bc35)
|
|
13
|
+
Bumps various development dependencies including TypeScript build tools, type definitions, and ESLint plugins. Updates the lockfile alongside package.json changes.
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Tests
|
|
17
|
+
|
|
18
|
+
* remove vitest ui script (7d894526ffb17345986375d3700f53b42ba5a2bb)
|
|
19
|
+
Drops the `test:ui` script from package.json.
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Build System
|
|
23
|
+
|
|
24
|
+
* auto-include changelog in releases (fd40332bd99c6b3a2ae5f260e9b7afcf0902665b)
|
|
25
|
+
Adds `CHANGELOG.md` to the package distribution files to ensure it gets packaged and published to npm.
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
### Continuous Integration
|
|
29
|
+
|
|
30
|
+
* fix the versioning system that was broken by attempting to fix the fact that a refactor doesn't change the version (3b0642134714bd634ae11f8a3d4f4695ea25c953)
|
|
31
|
+
|
|
32
|
+
## [2.2.0](https://github.com/D1g1talEntr0py/transportr/compare/v2.1.2...v2.2.0) (2026-03-31)
|
|
33
|
+
|
|
34
|
+
### Features
|
|
35
|
+
|
|
36
|
+
* **docs:** expand package manager installation snippets (caea4a7d21067bd248f6cadc118010d91c28c59b)
|
|
37
|
+
Adds missing installation commands for native npm and yarn to the README explicitly, ensuring compatibility statements for multiple ecosystems.
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
### Bug Fixes
|
|
41
|
+
|
|
42
|
+
* **deps:** update dependencies to address CVE-2026-33228 (67315abc69d4e9ca5d93ea7543d7149c42e616d8)
|
|
43
|
+
Upgrades the transitive dependency `flatted` to 3.4.2 to fix a prototype pollution vulnerability (CWE-1321). This update also includes a major version bump for TypeScript to v6.0.2, alongside several other development dependency bumps such as vitest, eslint plugins, and pnpm.
|
|
44
|
+
|
|
45
|
+
* **license:** change license from ISC to MIT (597c7c4414c8403ecdc4105c9250356b63faaf81)
|
|
46
|
+
Transitions the project license to MIT, updating the LICENSE file, the metadata field in `package.json`, and the visual status badge in the documentation.
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
### Code Refactoring
|
|
50
|
+
|
|
51
|
+
* **config:** simplify compilation settings for TypeScript 6 (6d232397646a323241e094e3b723976e67be4786)
|
|
52
|
+
Removes historically explicit configuration options from `tsconfig.json` that are either default behavior or obsolete in TypeScript 6. Scope is securely narrowed to explicitly include and target the `./src` directory.
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
### Documentation
|
|
56
|
+
|
|
57
|
+
* consolidate ai agent instructions (aaeccb9ea8be76a2524b86df51564cb3599de7d1)
|
|
58
|
+
Deletes the separate `AGENTS.md` file and rolls its relevant details and guidelines directly into `.github/copilot-instructions.md`. This centralizes architectural conventions, code formatting rules, testing guidelines, and new feature details (e.g., retries, lifecycle hooks, and XSRF protection) for AI coding assistants.
|
|
59
|
+
|
|
60
|
+
* update readme with cdn usage and submodule documentation (fa18f735cea5ce79763d127fff09332317f17f55)
|
|
61
|
+
Expands the project README to clarify native browser and CDN usage without bundlers through an import map. Adds new sections that detail submodules for HTTP constants (e.g., headers, methods, media-types) to make the code examples and documentation more comprehensive and usable.
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
### Build System
|
|
65
|
+
|
|
66
|
+
* **deps:** update dependencies and package manager settings (1d2faaadb889fd71ff6c37f898de70a090df586b)
|
|
67
|
+
Removes the explicit `auto-install-peers=false` configuration from `.npmrc` and enables `autoInstallPeers: true` in the `pnpm-lock.yaml` settings. Updates the pnpm package manager version to 10.32.1 and bumps various dependencies, including `@d1g1tal/media-type`, `@d1g1tal/subscribr`, and development tools like `eslint`, `@typescript-eslint/eslint-plugin`, and `jsdom`.
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
### Continuous Integration
|
|
71
|
+
|
|
72
|
+
* update github actions workflows (0f2108390b52fb66aa25a2f337616efb45bec339)
|
|
73
|
+
Updates GitHub Actions to use newer action versions, modernizes the `pnpm-setup` and `setup-node` tasks, and removes the environment variable `FORCE_JAVASCRIPT_ACTIONS_TO_NODE24`. Additionally, modifies the publishing workflow to properly install the latest `npm` version instead of clearing the auth token.
|
|
74
|
+
|
|
75
|
+
## [2.1.2](https://github.com/D1g1talEntr0py/transportr/compare/v2.1.1...v2.1.2) (2026-03-14)
|
|
76
|
+
|
|
77
|
+
### ⚠ BREAKING CHANGES
|
|
78
|
+
|
|
79
|
+
* Transportr.MediaType, Transportr.RequestMethod, Transportr.RequestHeader,
|
|
80
|
+
Transportr.ResponseHeader, and Transportr.CachingPolicy static properties have been removed.
|
|
81
|
+
|
|
82
|
+
Import constants directly from the package submodule paths instead:
|
|
83
|
+
- import { HttpMediaType } from '@d1g1tal/transportr/media-types'
|
|
84
|
+
- import { HttpRequestMethod } from '@d1g1tal/transportr/methods'
|
|
85
|
+
- import { HttpRequestHeader } from '@d1g1tal/transportr/headers'
|
|
86
|
+
- import { HttpResponseHeader } from '@d1g1tal/transportr/response-headers'
|
|
87
|
+
|
|
88
|
+
### Code Refactoring
|
|
89
|
+
|
|
90
|
+
* remove static enum properties from Transportr class (8cde6bdddb5c00ed858517a938689099a02d1b7c)
|
|
91
|
+
|
|
92
|
+
## [2.1.1](https://github.com/D1g1talEntr0py/transportr/compare/v2.1.0...v2.1.1) (2026-03-14)
|
|
93
|
+
|
|
94
|
+
### Bug Fixes
|
|
95
|
+
|
|
96
|
+
* **ci:** fix the conflict for auto installing peer dependencies (23302387f160e55a60d775ffeb6f7ec4127721f6)
|
|
97
|
+
|
|
98
|
+
## [2.1.0](https://github.com/D1g1talEntr0py/transportr/compare/v2.0.0...v2.1.0) (2026-03-14)
|
|
99
|
+
|
|
100
|
+
### Features
|
|
101
|
+
|
|
102
|
+
* lower Node.js requirement to v20 and make jsdom optional (94dbcabeec9de2674f00b1c10cde6b48273d7a69)
|
|
103
|
+
Reduces the minimum required Node.js version from 22.0.0 to 20.0.0 to broaden compatibility. Makes `jsdom` an optional peer dependency, ensuring users are only required to install it if they utilize DOM-specific parsing features. Incorporates lazy-loading for DOMPurify and standardizes the JSDOM URL environment.
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
### Code Refactoring
|
|
107
|
+
|
|
108
|
+
* replace custom enums with native string literals (c51a0dcdfeef4b5eda2aa1e1fe475e540b41a1e9)
|
|
109
|
+
Simplifies the codebase by stripping out internal `HttpMediaType`, `HttpRequestMethod`, `HttpRequestHeader`, and `HttpResponseHeader` abstractions. Instead, the implementation now leverages native string literals natively supported by JavaScript, reducing overhead and streamlining type checks.
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
### Documentation
|
|
113
|
+
|
|
114
|
+
* correct TypeScript version in changelog (d196f4a315ec366397d7677fc5b8930f24930dc8)
|
|
115
|
+
Fixes typos in the CHANGELOG that referenced an incorrect 'TypeScript 6' version, ensuring accurate historical logs.
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
### Miscellaneous Chores
|
|
119
|
+
|
|
120
|
+
* add .npmrc to set auto-install-peers=false (21393af89a95c63dcbc003bf37804977728537e0)
|
|
121
|
+
|
|
122
|
+
### Tests
|
|
123
|
+
|
|
124
|
+
* modify tests to be compatible with Node 22 (71669f94854a1229bfe9c30d7f3dc0654b782fce)
|
|
125
|
+
|
|
126
|
+
### Build System
|
|
127
|
+
|
|
128
|
+
* expose package submodules and introduce release script (b119ef8f2c3a8365a71119a95e4ce3be3574846b)
|
|
129
|
+
Expands the package's module definitions by exposing distinct exports for headers, methods, and media-types. Adds a dedicated minified release build command to optimize the final artifact.
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
### Continuous Integration
|
|
133
|
+
|
|
134
|
+
* stop ignoring the config.ts for the test API key as it is just a placeholder now (a581ecc4ebbdf7661822412c8d26b9707b52d7ab)
|
|
135
|
+
* update the secret key (85673375cf8338f72ea0d9f4154bf61cb08179c7)
|
|
136
|
+
|
|
137
|
+
## [2.0.0](https://github.com/D1g1talEntr0py/transportr/compare/v1.4.4...v2.0.0) (2026-03-13)
|
|
138
|
+
|
|
139
|
+
### ⚠ BREAKING CHANGES
|
|
140
|
+
|
|
141
|
+
* Complete rewrite from JavaScript to TypeScript.
|
|
142
|
+
|
|
143
|
+
Source rewrite:
|
|
144
|
+
- AbortSignal → SignalController using native AbortController.any() and AbortSignal.timeout()
|
|
145
|
+
- ParameterMap class eliminated; options processing uses shallow merge with deep merge only for headers/searchParams
|
|
146
|
+
- Response handlers extracted to response-handlers.ts with DOMPurify sanitization
|
|
147
|
+
- Lazy JSDOM auto-import for Node.js DOM handler support
|
|
148
|
+
- contentTypeHandlers changed from handler-keyed Map to content-type-keyed array with MediaType.matches()
|
|
149
|
+
- MediaType caching with LRU eviction (100 entries)
|
|
150
|
+
- All modules use named exports instead of default exports
|
|
151
|
+
|
|
152
|
+
Type system:
|
|
153
|
+
- Branded types: JsonString<T>, JsonValue<T> for type-safe serialization
|
|
154
|
+
- TypedResponse<T> extending Response with typed json() method
|
|
155
|
+
- TypedHeaders with strongly-typed header names and AuthorizationScheme validation
|
|
156
|
+
- RequestOptions discriminated union based on method type (body allowed/disallowed)
|
|
157
|
+
- Recursive JSON types: Json, JsonPrimitive, JsonArray, JsonObject
|
|
158
|
+
- Utility types: Prettify<T>, LiteralUnion<T>
|
|
159
|
+
|
|
160
|
+
New utilities (utils.ts):
|
|
161
|
+
- serialize<T>() with branded JsonString<T> return type
|
|
162
|
+
- isRawBody() for FormData/Blob/ArrayBuffer/ReadableStream detection
|
|
163
|
+
- isObject(), isString() type predicates
|
|
164
|
+
- objectMerge(), getCookieValue()
|
|
165
|
+
- Removes @d1g1tal/chrysalis dependency
|
|
166
|
+
|
|
167
|
+
API changes:
|
|
168
|
+
- post(path, options) signature (body now in options)
|
|
169
|
+
- DELETE added to requestBodyMethods
|
|
170
|
+
- registerContentTypeHandler()/unregisterContentTypeHandler() public API
|
|
171
|
+
- Instance destroy() and static unregisterAll() teardown methods
|
|
172
|
+
- Enhanced HttpError with url, method, timing properties
|
|
173
|
+
- handleImage returns HTMLImageElement instead of blob URL string
|
|
174
|
+
- HTML selector support on getHtml() and getHtmlFragment()
|
|
175
|
+
|
|
176
|
+
### Features
|
|
177
|
+
|
|
178
|
+
* rewrite source in TypeScript with full type system (b4f219ce9b91b814943664301af0699fe3f31061)
|
|
179
|
+
|
|
180
|
+
### Documentation
|
|
181
|
+
|
|
182
|
+
* add release process, agent guidelines, and update README (584594ba5dd37d1a33e24547507d3e3ccf9da044)
|
|
183
|
+
- Add docs/release-process.md with semantic-release workflow documentation
|
|
184
|
+
- Add AGENTS.md with AI agent coding standards and protocols
|
|
185
|
+
- Update README.md for TypeScript API and new features
|
|
186
|
+
- Update LICENSE
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
### Miscellaneous Chores
|
|
190
|
+
|
|
191
|
+
* migrate build tooling to TypeScript 5.9 and Vitest 4 (7cca59051a0106ab19975bd4496bf7f037a5b912)
|
|
192
|
+
- Replace .eslintrc.json with ESLint flat config (eslint.config.js)
|
|
193
|
+
- Remove esbuild.js and jsconfig.json in favor of tsconfig.json
|
|
194
|
+
- Add vitest.config.ts with dual-project setup (unit/integration)
|
|
195
|
+
- Add pnpm-workspace.yaml
|
|
196
|
+
- Remove @d1g1tal/chrysalis dependency
|
|
197
|
+
- Add dompurify, jsdom dependencies
|
|
198
|
+
- Update @d1g1tal/media-type to v6, @d1g1tal/subscribr to v4
|
|
199
|
+
- Update .gitignore and .vscode/settings.json
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
### Tests
|
|
203
|
+
|
|
204
|
+
* add comprehensive TypeScript test suite (1934c956c43992497ba70360f02fc3da38fe87bc)
|
|
205
|
+
- Rewrite all existing JS tests in TypeScript with Vitest 4
|
|
206
|
+
- Add test setup (tests/scripts/setup.ts) with URL.createObjectURL/revokeObjectURL mocks
|
|
207
|
+
- Add test config (tests/scripts/config.ts) with mockapi.io integration key
|
|
208
|
+
|
|
209
|
+
New test files:
|
|
210
|
+
- retry.test.ts: exponential backoff, custom delay, status codes, network errors
|
|
211
|
+
- hooks.test.ts: beforeRequest, afterResponse, beforeError at global/instance/request scope
|
|
212
|
+
- browser-environment.test.ts: DOM-specific behavior validation
|
|
213
|
+
- environment-specific.test.ts: Node.js vs browser environment detection
|
|
214
|
+
- response-handlers.test.ts: JSON, HTML, XML, script, CSS, blob, image, stream handlers
|
|
215
|
+
- signal-controller.test.ts: SignalController lifecycle, timeout detection, destroy cleanup
|
|
216
|
+
- signal-controller-cleanup.test.ts: memory leak prevention, controller Set management
|
|
217
|
+
- request-options-optimization.test.ts: shallow vs deep merge, raw body detection
|
|
218
|
+
- mediatype-caching.test.ts: LRU eviction, cache hit/miss behavior
|
|
219
|
+
- utils.test.ts: serialize, isRawBody, isObject, objectMerge, getCookieValue
|
|
220
|
+
- network-integration.test.ts: real HTTP calls to mockapi.io
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
### Continuous Integration
|
|
224
|
+
|
|
225
|
+
* add GitHub Actions workflows and semantic-release (2f2809b53b318af2dc41084e858547db022c1cee)
|
|
226
|
+
- ci.yml: lint, type-check, build, unit tests on Node.js 22, 24, 25 with Codecov upload
|
|
227
|
+
- integration.yml: integration tests against mockapi.io on main push
|
|
228
|
+
- publish.yml: automated semantic-release with npm provenance attestation
|
|
229
|
+
- .releaserc.json: conventional commits, changelog generation, npm publish, GitHub releases
|
|
230
|
+
- .githooks/commit-msg: git hook enforcing Conventional Commits format
|
|
231
|
+
- .github/copilot-instructions.md: AI assistant project context
|
package/LICENSE
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
MIT License
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
that the above copyright notice and this permission notice appear in all copies.
|
|
3
|
+
Copyright (c) 2023 Jason DiMeo
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](https://www.npmjs.com/package/@d1g1tal/transportr)
|
|
5
5
|
[](https://github.com/D1g1talEntr0py/transportr/actions/workflows/ci.yml)
|
|
6
6
|
[](https://codecov.io/gh/D1g1talEntr0py/transportr)
|
|
7
|
-
[](https://github.com/D1g1talEntr0py/transportr/blob/main/LICENSE)
|
|
8
8
|
[](https://nodejs.org)
|
|
9
9
|
[](https://www.typescriptlang.org/)
|
|
10
10
|
|
|
@@ -23,12 +23,6 @@ A TypeScript Fetch API wrapper providing type-safe HTTP requests with advanced a
|
|
|
23
23
|
- **HTML selectors** — Extract specific elements from HTML responses with CSS selectors
|
|
24
24
|
- **FormData auto-detection** — Automatically handles FormData, Blob, ArrayBuffer, and stream bodies
|
|
25
25
|
|
|
26
|
-
## Installation
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
pnpm add @d1g1tal/transportr
|
|
30
|
-
```
|
|
31
|
-
|
|
32
26
|
## Requirements
|
|
33
27
|
|
|
34
28
|
- **Node.js** ≥ 20.0.0 or a modern browser with native [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) and `AbortController` support
|
|
@@ -38,17 +32,40 @@ pnpm add @d1g1tal/transportr
|
|
|
38
32
|
pnpm add jsdom
|
|
39
33
|
```
|
|
40
34
|
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# With pnpm:
|
|
39
|
+
pnpm add @d1g1tal/transportr
|
|
40
|
+
|
|
41
|
+
# Or with npm:
|
|
42
|
+
npm install @d1g1tal/transportr
|
|
43
|
+
|
|
44
|
+
# Or with yarn
|
|
45
|
+
yarn add @d1g1tal/transportr
|
|
46
|
+
```
|
|
47
|
+
|
|
41
48
|
## Quick Start
|
|
42
49
|
|
|
50
|
+
Only the main module is required — the submodule constants (`HttpRequestHeader`, `HttpMediaType`, etc.) are optional conveniences. Anywhere a constant is used, a plain string works just as well.
|
|
51
|
+
|
|
52
|
+
Out of the box, every instance defaults to:
|
|
53
|
+
- `Content-Type: application/json; charset=utf-8`
|
|
54
|
+
- `Accept: application/json; charset=utf-8`
|
|
55
|
+
- `timeout`: 30 000 ms
|
|
56
|
+
- `cache`: `no-store`
|
|
57
|
+
- `credentials`: `same-origin`
|
|
58
|
+
- `mode`: `cors`
|
|
59
|
+
|
|
43
60
|
```typescript
|
|
44
61
|
import { Transportr } from '@d1g1tal/transportr';
|
|
45
62
|
|
|
46
63
|
const api = new Transportr('https://api.example.com');
|
|
47
64
|
|
|
48
|
-
// GET JSON
|
|
65
|
+
// GET JSON — default Accept header is already application/json
|
|
49
66
|
const data = await api.getJson('/users/1');
|
|
50
67
|
|
|
51
|
-
// POST with JSON body
|
|
68
|
+
// POST with JSON body — automatically serialized, no Content-Type needed
|
|
52
69
|
const created = await api.post('/users', { body: { name: 'Alice' } });
|
|
53
70
|
|
|
54
71
|
// GET with search params
|
|
@@ -57,8 +74,77 @@ const results = await api.getJson('/search', { searchParams: { q: 'term', page:
|
|
|
57
74
|
// Typed response using generics
|
|
58
75
|
interface User { id: number; name: string; }
|
|
59
76
|
const user = await api.get<User>('/users/1');
|
|
77
|
+
|
|
78
|
+
// Plain strings work anywhere — constants are just for convenience
|
|
79
|
+
const api2 = new Transportr('https://api.example.com', {
|
|
80
|
+
headers: { 'authorization': 'Bearer token', 'accept-language': 'en-US' }
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Browser / CDN Usage
|
|
85
|
+
|
|
86
|
+
The package is published as pure ESM and works directly in modern browsers — no bundler required. All dependencies (`@d1g1tal/media-type`, `@d1g1tal/subscribr`, DOMPurify) are bundled into the output, so there are no external module URLs to manage. `jsdom` is not needed in a browser environment.
|
|
87
|
+
|
|
88
|
+
### With an import map (recommended)
|
|
89
|
+
|
|
90
|
+
An [import map](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/script/type/importmap) mirrors the package's named submodule exports and keeps your code identical to the Node.js form — use bare specifiers exactly as you would in a bundled project:
|
|
91
|
+
|
|
92
|
+
```html
|
|
93
|
+
<script type="importmap">
|
|
94
|
+
{
|
|
95
|
+
"imports": {
|
|
96
|
+
"@d1g1tal/transportr": "https://cdn.jsdelivr.net/npm/@d1g1tal/transportr/dist/transportr.js",
|
|
97
|
+
"@d1g1tal/transportr/headers": "https://cdn.jsdelivr.net/npm/@d1g1tal/transportr/dist/headers.js",
|
|
98
|
+
"@d1g1tal/transportr/methods": "https://cdn.jsdelivr.net/npm/@d1g1tal/transportr/dist/methods.js",
|
|
99
|
+
"@d1g1tal/transportr/media-types": "https://cdn.jsdelivr.net/npm/@d1g1tal/transportr/dist/media-types.js",
|
|
100
|
+
"@d1g1tal/transportr/response-headers": "https://cdn.jsdelivr.net/npm/@d1g1tal/transportr/dist/response-headers.js"
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
</script>
|
|
104
|
+
|
|
105
|
+
<script type="module">
|
|
106
|
+
import { Transportr } from '@d1g1tal/transportr';
|
|
107
|
+
import { HttpRequestHeader } from '@d1g1tal/transportr/headers';
|
|
108
|
+
import { HttpRequestMethod } from '@d1g1tal/transportr/methods';
|
|
109
|
+
import { HttpMediaType } from '@d1g1tal/transportr/media-types';
|
|
110
|
+
import { HttpResponseHeader } from '@d1g1tal/transportr/response-headers';
|
|
111
|
+
|
|
112
|
+
const api = new Transportr('https://api.example.com', {
|
|
113
|
+
headers: {
|
|
114
|
+
[HttpRequestHeader.AUTHORIZATION]: 'Bearer token',
|
|
115
|
+
[HttpRequestHeader.ACCEPT]: HttpMediaType.JSON
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
const data = await api.getJson('/users/1');
|
|
120
|
+
console.log(data);
|
|
121
|
+
</script>
|
|
60
122
|
```
|
|
61
123
|
|
|
124
|
+
### Without an import map
|
|
125
|
+
|
|
126
|
+
The CDN resolves the `"."` entry in `exports` automatically, so no explicit file path is needed for the main module. Submodules use their CDN paths directly:
|
|
127
|
+
|
|
128
|
+
```html
|
|
129
|
+
<script type="module">
|
|
130
|
+
import { Transportr } from 'https://cdn.jsdelivr.net/npm/@d1g1tal/transportr';
|
|
131
|
+
import { HttpRequestHeader } from 'https://cdn.jsdelivr.net/npm/@d1g1tal/transportr/dist/headers.js';
|
|
132
|
+
import { HttpMediaType } from 'https://cdn.jsdelivr.net/npm/@d1g1tal/transportr/dist/media-types.js';
|
|
133
|
+
|
|
134
|
+
const api = new Transportr('https://api.example.com', {
|
|
135
|
+
headers: {
|
|
136
|
+
[HttpRequestHeader.AUTHORIZATION]: 'Bearer token',
|
|
137
|
+
[HttpRequestHeader.ACCEPT]: HttpMediaType.JSON
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
const data = await api.getJson('/users/1');
|
|
142
|
+
console.log(data);
|
|
143
|
+
</script>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Import map support is available in all browsers covered by this project's `browserslist` configuration (Chrome 89+, Firefox 108+, Safari 16.4+).
|
|
147
|
+
|
|
62
148
|
## API
|
|
63
149
|
|
|
64
150
|
### Constructor
|
|
@@ -339,21 +425,66 @@ api
|
|
|
339
425
|
|
|
340
426
|
### Submodule Imports
|
|
341
427
|
|
|
342
|
-
HTTP constant objects are available as named submodule imports
|
|
428
|
+
HTTP constant objects are available as named submodule imports. Each is a tree-shakeable, side-effect-free object of string constants — useful for avoiding magic strings and getting autocomplete.
|
|
429
|
+
|
|
430
|
+
#### `@d1g1tal/transportr/headers`
|
|
431
|
+
|
|
432
|
+
Request header name constants.
|
|
343
433
|
|
|
344
434
|
```typescript
|
|
345
|
-
import { HttpMediaType } from '@d1g1tal/transportr/media-types';
|
|
346
|
-
import { HttpRequestMethod } from '@d1g1tal/transportr/methods';
|
|
347
435
|
import { HttpRequestHeader } from '@d1g1tal/transportr/headers';
|
|
348
|
-
|
|
436
|
+
|
|
437
|
+
const api = new Transportr('https://api.example.com', {
|
|
438
|
+
headers: {
|
|
439
|
+
[HttpRequestHeader.AUTHORIZATION]: 'Bearer token',
|
|
440
|
+
[HttpRequestHeader.CONTENT_TYPE]: 'application/json',
|
|
441
|
+
[HttpRequestHeader.ACCEPT_LANGUAGE]: 'en-US'
|
|
442
|
+
}
|
|
443
|
+
});
|
|
349
444
|
```
|
|
350
445
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
446
|
+
#### `@d1g1tal/transportr/methods`
|
|
447
|
+
|
|
448
|
+
HTTP method string constants.
|
|
449
|
+
|
|
450
|
+
```typescript
|
|
451
|
+
import { HttpRequestMethod } from '@d1g1tal/transportr/methods';
|
|
452
|
+
|
|
453
|
+
const response = await api.request('/data', { method: HttpRequestMethod.PATCH });
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
#### `@d1g1tal/transportr/media-types`
|
|
457
|
+
|
|
458
|
+
MIME type string constants covering common content types (JSON, HTML, XML, CSS, images, audio, video, and more).
|
|
459
|
+
|
|
460
|
+
```typescript
|
|
461
|
+
import { HttpMediaType } from '@d1g1tal/transportr/media-types';
|
|
462
|
+
|
|
463
|
+
const api = new Transportr('https://api.example.com', {
|
|
464
|
+
headers: { [HttpRequestHeader.ACCEPT]: HttpMediaType.JSON }
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
// Use as a content-type value
|
|
468
|
+
await api.post('/upload', {
|
|
469
|
+
body: csvData,
|
|
470
|
+
headers: { [HttpRequestHeader.CONTENT_TYPE]: HttpMediaType.CSV }
|
|
471
|
+
});
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
#### `@d1g1tal/transportr/response-headers`
|
|
475
|
+
|
|
476
|
+
Response header name constants — useful when reading headers from a response.
|
|
477
|
+
|
|
478
|
+
```typescript
|
|
479
|
+
import { HttpResponseHeader } from '@d1g1tal/transportr/response-headers';
|
|
480
|
+
|
|
481
|
+
const reg = api.register(Transportr.RequestEvents.SUCCESS, (event, data) => {
|
|
482
|
+
const response = data as Response;
|
|
483
|
+
const etag = response.headers.get(HttpResponseHeader.ETAG);
|
|
484
|
+
const retryAfter = response.headers.get(HttpResponseHeader.RETRY_AFTER);
|
|
485
|
+
const location = response.headers.get(HttpResponseHeader.LOCATION);
|
|
486
|
+
});
|
|
487
|
+
```
|
|
357
488
|
|
|
358
489
|
## License
|
|
359
490
|
|
package/dist/transportr.d.ts
CHANGED
package/dist/transportr.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
2
|
-
`,"\r"]),Ee=/[ \t\n\r]+$/u,Te=/^[ \t\n\r]+|[ \t\n\r]+$/ug,Oe=class E{static parse(e){e=e.replace(Te,"");let t=0,[r,n]=E.collect(e,t,["/"]);if(t=n,!r.length||t>=e.length||!P.test(r))throw new TypeError(E.generateErrorMessage("type",r));++t;let[o,i]=E.collect(e,t,[";"],!0,!0);if(t=i,!o.length||!P.test(o))throw new TypeError(E.generateErrorMessage("subtype",o));let u=new W;for(;t<e.length;){for(++t;be.has(e[t]);)++t;let a;if([a,t]=E.collect(e,t,[";","="],!1),t>=e.length||e[t]===";")continue;++t;let l;if(e[t]==='"')for([l,t]=E.collectHttpQuotedString(e,t);t<e.length&&e[t]!==";";)++t;else if([l,t]=E.collect(e,t,[";"],!1,!0),!l)continue;a&&W.isValid(a,l)&&!u.has(a)&&u.set(a,l)}return{type:r,subtype:o,parameters:u}}get[Symbol.toStringTag](){return"MediaTypeParser"}static collect(e,t,r,n=!0,o=!1){let i="";for(let{length:u}=e;t<u&&!r.includes(e[t]);t++)i+=e[t];return n&&(i=i.toLowerCase()),o&&(i=i.replace(Ee,"")),[i,t]}static collectHttpQuotedString(e,t){let r="";for(let n=e.length,o;++t<n&&(o=e[t])!=='"';)r+=o=="\\"&&++t<n?e[t]:o;return[r,t]}static generateErrorMessage(e,t){return`Invalid ${e} "${t}": only HTTP token code points are valid.`}},y=class Y{_type;_subtype;_parameters;constructor(e,t={}){if(t===null||typeof t!="object"||Array.isArray(t))throw new TypeError("The parameters argument must be an object");({type:this._type,subtype:this._subtype,parameters:this._parameters}=Oe.parse(e));for(let[r,n]of Object.entries(t))this._parameters.set(r,n)}static parse(e){try{return new Y(e)}catch{}return null}get type(){return this._type}get subtype(){return this._subtype}get essence(){return`${this._type}/${this._subtype}`}get parameters(){return this._parameters}matches(e){return typeof e=="string"?this.essence.includes(e):this._type===e._type&&this._subtype===e._subtype}toString(){return`${this.essence}${this._parameters.toString()}`}get[Symbol.toStringTag](){return"MediaType"}};var Se=class extends Map{set(s,e){return super.set(s,e instanceof Set?e:(super.get(s)??new Set).add(e)),this}find(s,e){let t=this.get(s);if(t!==void 0)return Array.from(t).find(e)}hasValue(s,e){let t=super.get(s);return t?t.has(e):!1}deleteValue(s,e){if(e===void 0)return this.delete(s);let t=super.get(s);if(t){let r=t.delete(e);return t.size===0&&super.delete(s),r}return!1}get[Symbol.toStringTag](){return"SetMultiMap"}},ve=class{context;eventHandler;constructor(s,e){this.context=s,this.eventHandler=e}handle(s,e){this.eventHandler.call(this.context,s,e)}get[Symbol.toStringTag](){return"ContextEventHandler"}},we=class{_eventName;_contextEventHandler;constructor(s,e){this._eventName=s,this._contextEventHandler=e}get eventName(){return this._eventName}get contextEventHandler(){return this._contextEventHandler}get[Symbol.toStringTag](){return"Subscription"}},C=class{subscribers=new Se;errorHandler;setErrorHandler(s){this.errorHandler=s}subscribe(s,e,t=e,r){if(this.validateEventName(s),r?.once){let i=e;e=(u,a)=>{i.call(t,u,a),this.unsubscribe(o)}}let n=new ve(t,e);this.subscribers.set(s,n);let o=new we(s,n);return o}unsubscribe({eventName:s,contextEventHandler:e}){let t=this.subscribers.get(s)??new Set,r=t.delete(e);return r&&t.size===0&&this.subscribers.delete(s),r}publish(s,e=new CustomEvent(s),t){this.validateEventName(s),this.subscribers.get(s)?.forEach(r=>{try{r.handle(e,t)}catch(n){this.errorHandler?this.errorHandler(n,s,e,t):console.error(`Error in event handler for '${s}':`,n)}})}isSubscribed({eventName:s,contextEventHandler:e}){return this.subscribers.get(s)?.has(e)??!1}validateEventName(s){if(!s||typeof s!="string")throw new TypeError("Event name must be a non-empty string");if(s.trim()!==s)throw new Error("Event name cannot have leading or trailing whitespace")}destroy(){this.subscribers.clear()}get[Symbol.toStringTag](){return"Subscribr"}};var v=class extends Error{_entity;responseStatus;_url;_method;_timing;constructor(e,{message:t,cause:r,entity:n,url:o,method:i,timing:u}={}){super(t,{cause:r}),this._entity=n,this.responseStatus=e,this._url=o,this._method=i,this._timing=u}get entity(){return this._entity}get statusCode(){return this.responseStatus.code}get statusText(){return this.responseStatus?.text}get url(){return this._url}get method(){return this._method}get timing(){return this._timing}get name(){return"HttpError"}get[Symbol.toStringTag](){return this.name}};var T=class{_code;_text;constructor(e,t){this._code=e,this._text=t}get code(){return this._code}get text(){return this._text}get[Symbol.toStringTag](){return"ResponseStatus"}toString(){return`${this._code} ${this._text}`}};var w={charset:"utf-8"},Q=/\/$/,Z="XSRF-TOKEN",ee="X-XSRF-TOKEN",R={PNG:new y("image/png"),TEXT:new y("text/plain",w),JSON:new y("application/json",w),HTML:new y("text/html",w),JAVA_SCRIPT:new y("text/javascript",w),CSS:new y("text/css",w),XML:new y("application/xml",w),BIN:new y("application/octet-stream")},x=R.JSON.toString(),te={DEFAULT:"default",FORCE_CACHE:"force-cache",NO_CACHE:"no-cache",NO_STORE:"no-store",ONLY_IF_CACHED:"only-if-cached",RELOAD:"reload"},m={CONFIGURED:"configured",SUCCESS:"success",ERROR:"error",ABORTED:"aborted",TIMEOUT:"timeout",RETRY:"retry",COMPLETE:"complete",ALL_COMPLETE:"all-complete"},O={ABORT:"abort",TIMEOUT:"timeout"},S={ABORT:"AbortError",TIMEOUT:"TimeoutError"},H={once:!0,passive:!0},L=()=>new CustomEvent(O.ABORT,{detail:{cause:S.ABORT}}),se=()=>new CustomEvent(O.TIMEOUT,{detail:{cause:S.TIMEOUT}}),re=["POST","PUT","PATCH","DELETE"],ne=new T(500,"Internal Server Error"),oe=new T(499,"Aborted"),ie=new T(504,"Request Timeout"),I=[408,413,429,500,502,503,504],B=["GET","PUT","HEAD","DELETE","OPTIONS"],k=300,A=2;var M=class{abortSignal;abortController=new AbortController;events=new Map;constructor({signal:e,timeout:t=1/0}={}){if(t<0)throw new RangeError("The timeout cannot be negative");let r=[this.abortController.signal];e!=null&&r.push(e),t!==1/0&&r.push(AbortSignal.timeout(t)),(this.abortSignal=AbortSignal.any(r)).addEventListener(O.ABORT,this,H)}handleEvent({target:{reason:e}}){this.abortController.signal.aborted||e instanceof DOMException&&e.name===S.TIMEOUT&&this.abortSignal.dispatchEvent(se())}get signal(){return this.abortSignal}onAbort(e){return this.addEventListener(O.ABORT,e)}onTimeout(e){return this.addEventListener(O.TIMEOUT,e)}abort(e=L()){this.abortController.abort(e.detail?.cause)}destroy(){this.abortSignal.removeEventListener(O.ABORT,this,H);for(let[e,t]of this.events)this.abortSignal.removeEventListener(t,e,H);return this.events.clear(),this}addEventListener(e,t){return this.abortSignal.addEventListener(e,t,H),this.events.set(t,e),this}get[Symbol.toStringTag](){return"SignalController"}};var ae,qe,N=()=>qe??=import("./OP3JQ447.js").then(({default:s})=>e=>s.sanitize(e)),q=async()=>typeof document<"u"&&typeof DOMParser<"u"&&typeof DocumentFragment<"u"?Promise.resolve():ae??=import("jsdom").then(({JSDOM:s})=>{let{window:e}=new s("<!DOCTYPE html><html><head></head><body></body></html>",{url:"http://localhost"});globalThis.window=e,Object.assign(globalThis,{document:e.document,DOMParser:e.DOMParser,DocumentFragment:e.DocumentFragment})}).catch(()=>{throw ae=void 0,new Error("jsdom is required for HTML/XML/DOM features in Node.js environments. Install it with: npm install jsdom")}),ce=async s=>await s.text(),_=async s=>{await q();let e=URL.createObjectURL(await s.blob());return new Promise((t,r)=>{let n=document.createElement("script");Object.assign(n,{src:e,type:"text/javascript",async:!0}),n.onload=()=>{URL.revokeObjectURL(e),document.head.removeChild(n),t()},n.onerror=()=>{URL.revokeObjectURL(e),document.head.removeChild(n),r(new Error("Script failed to load"))},document.head.appendChild(n)})},D=async s=>{await q();let e=URL.createObjectURL(await s.blob());return new Promise((t,r)=>{let n=document.createElement("link");Object.assign(n,{href:e,type:"text/css",rel:"stylesheet"}),n.onload=()=>t(URL.revokeObjectURL(e)),n.onerror=()=>{URL.revokeObjectURL(e),document.head.removeChild(n),r(new Error("Stylesheet load failed"))},document.head.appendChild(n)})},j=async s=>await s.json(),ue=async s=>await s.blob(),F=async s=>{await q();let e=URL.createObjectURL(await s.blob());return new Promise((t,r)=>{let n=new Image;n.onload=()=>{URL.revokeObjectURL(e),t(n)},n.onerror=()=>{URL.revokeObjectURL(e),r(new Error("Image failed to load"))},n.src=e})},le=async s=>await s.arrayBuffer(),$=async s=>Promise.resolve(s.body),G=async s=>{await q();let e=await N();return new DOMParser().parseFromString(e(await s.text()),"application/xml")},J=async s=>{await q();let e=await N();return new DOMParser().parseFromString(e(await s.text()),"text/html")},de=async s=>{await q();let e=await N();return document.createRange().createContextualFragment(e(await s.text()))};var pe=s=>s!==void 0&&re.includes(s),fe=s=>s instanceof FormData||s instanceof Blob||s instanceof ArrayBuffer||s instanceof ReadableStream||s instanceof URLSearchParams||ArrayBuffer.isView(s),he=s=>{if(typeof document>"u"||!document.cookie)return;let e=`${s}=`,t=document.cookie.split(";");for(let r=0,n=t.length;r<n;r++){let o=t[r].trim();if(o.startsWith(e))return decodeURIComponent(o.slice(e.length))}},ge=s=>JSON.stringify(s),z=s=>s!==null&&typeof s=="string",b=s=>s!==null&&typeof s=="object"&&!Array.isArray(s)&&Object.getPrototypeOf(s)===Object.prototype,V=(...s)=>{let e=s.length;if(e===0)return;if(e===1){let[r]=s;return b(r)?X(r):r}let t={};for(let r of s){if(!b(r))return;for(let[n,o]of Object.entries(r)){let i=t[n];Array.isArray(o)?t[n]=[...o,...Array.isArray(i)?i.filter(u=>!o.includes(u)):[]]:b(o)?t[n]=b(i)?V(i,o):X(o):t[n]=o}}return t};function X(s){if(b(s)){let e={},t=Object.keys(s);for(let r=0,n=t.length,o;r<n;r++)o=t[r],e[o]=X(s[o]);return e}return s}var Re=class s{_baseUrl;_options;subscribr;hooks={beforeRequest:[],afterResponse:[],beforeError:[]};static globalSubscribr=new C;static globalHooks={beforeRequest:[],afterResponse:[],beforeError:[]};static signalControllers=new Set;static inflightRequests=new Map;static mediaTypeCache=new Map(Object.values(R).map(e=>[e.toString(),e]));static contentTypeHandlers=[[R.TEXT.type,ce],[R.JSON.subtype,j],[R.BIN.subtype,$],[R.HTML.subtype,J],[R.XML.subtype,G],[R.PNG.type,F],[R.JAVA_SCRIPT.subtype,_],[R.CSS.subtype,D]];constructor(e=globalThis.location?.origin??"http://localhost",t={}){b(e)&&([e,t]=[globalThis.location?.origin??"http://localhost",e]),this._baseUrl=s.getBaseUrl(e),this._options=s.createOptions(t,s.defaultRequestOptions),this.subscribr=new C}static CredentialsPolicy={INCLUDE:"include",OMIT:"omit",SAME_ORIGIN:"same-origin"};static RequestModes={CORS:"cors",NAVIGATE:"navigate",NO_CORS:"no-cors",SAME_ORIGIN:"same-origin"};static RequestPriorities={HIGH:"high",LOW:"low",AUTO:"auto"};static RedirectPolicies={ERROR:"error",FOLLOW:"follow",MANUAL:"manual"};static ReferrerPolicy={NO_REFERRER:"no-referrer",NO_REFERRER_WHEN_DOWNGRADE:"no-referrer-when-downgrade",ORIGIN:"origin",ORIGIN_WHEN_CROSS_ORIGIN:"origin-when-cross-origin",SAME_ORIGIN:"same-origin",STRICT_ORIGIN:"strict-origin",STRICT_ORIGIN_WHEN_CROSS_ORIGIN:"strict-origin-when-cross-origin",UNSAFE_URL:"unsafe-url"};static RequestEvents=m;static defaultRequestOptions={body:void 0,cache:te.NO_STORE,credentials:s.CredentialsPolicy.SAME_ORIGIN,headers:new Headers({"content-type":x,accept:x}),searchParams:void 0,integrity:void 0,keepalive:void 0,method:"GET",mode:s.RequestModes.CORS,priority:s.RequestPriorities.AUTO,redirect:s.RedirectPolicies.FOLLOW,referrer:"about:client",referrerPolicy:s.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN,signal:void 0,timeout:3e4,global:!0};static register(e,t,r){return s.globalSubscribr.subscribe(e,t,r)}static unregister(e){return s.globalSubscribr.unsubscribe(e)}static abortAll(){for(let e of this.signalControllers)e.abort(L());this.signalControllers.clear()}static registerContentTypeHandler(e,t){s.contentTypeHandlers.unshift([e,t])}static unregisterContentTypeHandler(e){let t=s.contentTypeHandlers.findIndex(([r])=>r===e);return t===-1?!1:(s.contentTypeHandlers.splice(t,1),!0)}static addHooks(e){e.beforeRequest&&s.globalHooks.beforeRequest.push(...e.beforeRequest),e.afterResponse&&s.globalHooks.afterResponse.push(...e.afterResponse),e.beforeError&&s.globalHooks.beforeError.push(...e.beforeError)}static clearHooks(){s.globalHooks={beforeRequest:[],afterResponse:[],beforeError:[]}}static unregisterAll(){s.abortAll(),s.globalSubscribr=new C,s.clearHooks(),s.inflightRequests.clear()}get baseUrl(){return this._baseUrl}register(e,t,r){return this.subscribr.subscribe(e,t,r)}unregister(e){return this.subscribr.unsubscribe(e)}addHooks(e){return e.beforeRequest&&this.hooks.beforeRequest.push(...e.beforeRequest),e.afterResponse&&this.hooks.afterResponse.push(...e.afterResponse),e.beforeError&&this.hooks.beforeError.push(...e.beforeError),this}clearHooks(){return this.hooks.beforeRequest.length=0,this.hooks.afterResponse.length=0,this.hooks.beforeError.length=0,this}destroy(){this.clearHooks(),this.subscribr.destroy()}async get(e,t){return this._get(e,t)}async post(e,t){return typeof e!="string"&&([e,t]=[void 0,e]),this.execute(e,t,{method:"POST"})}async put(e,t){return this.execute(e,t,{method:"PUT"})}async patch(e,t){return this.execute(e,t,{method:"PATCH"})}async delete(e,t){return this.execute(e,t,{method:"DELETE"})}async head(e,t){return this.execute(e,t,{method:"HEAD"})}async options(e,t={}){b(e)&&([e,t]=[void 0,e]);let r=this.processRequestOptions(t,{method:"OPTIONS"}),{requestOptions:n}=r,o=n.hooks,i=s.createUrl(this._baseUrl,e,n.searchParams),u=[s.globalHooks.beforeRequest,this.hooks.beforeRequest,o?.beforeRequest];for(let d of u)if(d)for(let c of d){let g=await c(n,i);g&&(Object.assign(n,g),g.searchParams!==void 0&&(i=s.createUrl(this._baseUrl,e,n.searchParams)))}let a=await this._request(e,r),l=[s.globalHooks.afterResponse,this.hooks.afterResponse,o?.afterResponse];for(let d of l)if(d)for(let c of d){let g=await c(a,n);g&&(a=g)}let h=a.headers.get("allow")?.split(",").map(d=>d.trim());return this.publish({name:m.SUCCESS,data:h,global:t.global}),h}async request(e,t={}){b(e)&&([e,t]=[void 0,e]);let r=await this._request(e,this.processRequestOptions(t,{}));return this.publish({name:m.SUCCESS,data:r,global:t.global}),r}async getJson(e,t){return this._get(e,t,{headers:{accept:`${R.JSON}`}},j)}async getXml(e,t){return this._get(e,t,{headers:{accept:`${R.XML}`}},G)}async getHtml(e,t,r){let n=await this._get(e,t,{headers:{accept:`${R.HTML}`}},J);return r&&n?n.querySelector(r):n}async getHtmlFragment(e,t,r){let n=await this._get(e,t,{headers:{accept:`${R.HTML}`}},de);return r&&n?n.querySelector(r):n}async getScript(e,t){return this._get(e,t,{headers:{accept:`${R.JAVA_SCRIPT}`}},_)}async getStylesheet(e,t){return this._get(e,t,{headers:{accept:`${R.CSS}`}},D)}async getBlob(e,t){return this._get(e,t,{headers:{accept:"application/octet-stream"}},ue)}async getImage(e,t){return this._get(e,t,{headers:{accept:"image/*"}},F)}async getBuffer(e,t){return this._get(e,t,{headers:{accept:"application/octet-stream"}},le)}async getStream(e,t){return this._get(e,t,{headers:{accept:"application/octet-stream"}},$)}async _get(e,t,r={},n){return this.execute(e,t,{...r,method:"GET",body:void 0},n)}async _request(e,{signalController:t,requestOptions:r,global:n}){s.signalControllers.add(t);let o=s.normalizeRetryOptions(r.retry),i=r.method??"GET",u=o.limit>0&&o.methods.includes(i),a=r.dedupe===!0&&(i==="GET"||i==="HEAD"),l=0,h=performance.now(),d=()=>{let c=performance.now();return{start:h,end:c,duration:c-h}};try{let c=s.createUrl(this._baseUrl,e,r.searchParams),g=a?`${i}:${c.href}`:"";if(a){let f=s.inflightRequests.get(g);if(f)return(await f).clone()}let p=async()=>{for(;;)try{let f=await fetch(c,r);if(!f.ok){if(u&&l<o.limit&&o.statusCodes.includes(f.status)){l++,this.publish({name:m.RETRY,data:{attempt:l,status:f.status,method:i,path:e,timing:d()},global:n}),await s.retryDelay(o,l);continue}let U;try{U=await f.text()}catch{}throw await this.handleError(e,f,{entity:U,url:c,method:i,timing:d()},r)}return f}catch(f){if(f instanceof v)throw f;if(u&&l<o.limit){l++,this.publish({name:m.RETRY,data:{attempt:l,error:f.message,method:i,path:e,timing:d()},global:n}),await s.retryDelay(o,l);continue}throw await this.handleError(e,void 0,{cause:f,url:c,method:i,timing:d()},r)}};if(a){let f=p();s.inflightRequests.set(g,f);try{return await f}finally{s.inflightRequests.delete(g)}}return await p()}finally{if(s.signalControllers.delete(t.destroy()),!r.signal?.aborted){let c=d();this.publish({name:m.COMPLETE,data:{timing:c},global:n}),s.signalControllers.size===0&&this.publish({name:m.ALL_COMPLETE,global:n})}}}static normalizeRetryOptions(e){return e===void 0?{limit:0,statusCodes:[],methods:[],delay:k,backoffFactor:A}:typeof e=="number"?{limit:e,statusCodes:[...I],methods:[...B],delay:k,backoffFactor:A}:{limit:e.limit??0,statusCodes:e.statusCodes??[...I],methods:e.methods??[...B],delay:e.delay??k,backoffFactor:e.backoffFactor??A}}static retryDelay(e,t){let r=typeof e.delay=="function"?e.delay(t):e.delay*e.backoffFactor**(t-1);return new Promise(n=>setTimeout(n,r))}async execute(e,t={},r={},n){b(e)&&([e,t]=[void 0,e]);let o=this.processRequestOptions(t,r),{requestOptions:i}=o,u=i.hooks,a=s.createUrl(this._baseUrl,e,i.searchParams),l=[s.globalHooks.beforeRequest,this.hooks.beforeRequest,u?.beforeRequest];for(let c of l)if(c)for(let g of c){let p=await g(i,a);p&&(Object.assign(i,p),p.searchParams!==void 0&&(a=s.createUrl(this._baseUrl,e,i.searchParams)))}let h=await this._request(e,o),d=[s.globalHooks.afterResponse,this.hooks.afterResponse,u?.afterResponse];for(let c of d)if(c)for(let g of c){let p=await g(h,i);p&&(h=p)}try{!n&&h.status!==204&&(n=this.getResponseHandler(h.headers.get("content-type")));let c=await n?.(h);return this.publish({name:m.SUCCESS,data:c,global:o.global}),c}catch(c){throw await this.handleError(e,h,{cause:c},i)}}static createOptions({headers:e,searchParams:t,...r},{headers:n,searchParams:o,...i}){return n=s.mergeHeaders(new Headers,e,n),o=s.mergeSearchParams(new URLSearchParams,t,o),{...V(i,r)??{},headers:n,searchParams:o}}static mergeHeaders(e,...t){for(let r of t)if(r!==void 0)if(r instanceof Headers)r.forEach((n,o)=>e.set(o,n));else if(Array.isArray(r))for(let[n,o]of r)e.set(n,o);else{let n=r,o=Object.keys(n);for(let i=0;i<o.length;i++){let u=o[i],a=n[u];a!==void 0&&e.set(u,String(a))}}return e}static mergeSearchParams(e,...t){for(let r of t)if(r!==void 0)if(r instanceof URLSearchParams)r.forEach((n,o)=>e.set(o,n));else if(z(r)||Array.isArray(r))for(let[n,o]of new URLSearchParams(r))e.set(n,o);else{let n=Object.keys(r);for(let o=0;o<n.length;o++){let i=n[o],u=r[i];u!==void 0&&e.set(i,String(u))}}return e}processRequestOptions({body:e,headers:t,searchParams:r,...n},{headers:o,searchParams:i,...u}){let a={...this._options,...n,...u,headers:s.mergeHeaders(new Headers,this._options.headers,t,o),searchParams:s.mergeSearchParams(new URLSearchParams,this._options.searchParams,r,i)};if(pe(a.method))if(fe(e))a.body=e,a.headers.delete("content-type");else{let p=a.headers.get("content-type")?.includes("json")??!1;a.body=p&&b(e)?ge(e):e}else a.headers.delete("content-type"),a.body instanceof URLSearchParams&&s.mergeSearchParams(a.searchParams,a.body),a.body=void 0;let{signal:l,timeout:h,global:d=!1,xsrf:c}=a;if(c){let p=typeof c=="object"?c:{},f=he(p.cookieName??Z);f&&a.headers.set(p.headerName??ee,f)}let g=new M({signal:l,timeout:h}).onAbort(p=>this.publish({name:m.ABORTED,event:p,global:d})).onTimeout(p=>this.publish({name:m.TIMEOUT,event:p,global:d}));return a.signal=g.signal,this.publish({name:m.CONFIGURED,data:a,global:d}),{signalController:g,requestOptions:a,global:d}}static getBaseUrl(e){if(e instanceof URL)return e;if(!z(e))throw new TypeError("Invalid URL");return new URL(e,e.startsWith("/")?globalThis.location.origin:void 0)}static getOrParseMediaType(e){if(e===null)return;let t=s.mediaTypeCache.get(e);if(t!==void 0)return t;if(t=y.parse(e)??void 0,t!==void 0){if(s.mediaTypeCache.size>=100){let r=s.mediaTypeCache.keys().next().value;r!==void 0&&s.mediaTypeCache.delete(r)}s.mediaTypeCache.set(e,t)}return t}static createUrl(e,t,r){let n=t?new URL(`${e.pathname.replace(Q,"")}${t}`,e.origin):new URL(e);return r&&s.mergeSearchParams(n.searchParams,r),n}static generateResponseStatusFromError(e,{status:t,statusText:r}=new Response){switch(e){case S.ABORT:return oe;case S.TIMEOUT:return ie;default:return t>=400?new T(t,r):ne}}async handleError(e,t,{cause:r,entity:n,url:o,method:i,timing:u}={},a){let l=i&&o?`${i} ${o.href} failed${t?` with status ${t.status}`:""}`:`An error has occurred with your request to: '${e}'`,h=new v(s.generateResponseStatusFromError(r?.name,t),{message:l,cause:r,entity:n,url:o,method:i,timing:u}),d=[s.globalHooks.beforeError,this.hooks.beforeError,a?.hooks?.beforeError];for(let c of d)if(c)for(let g of c){let p=await g(h);p instanceof v&&(h=p)}return this.publish({name:m.ERROR,data:h}),h}publish({name:e,event:t=new CustomEvent(e),data:r,global:n=!0}){n&&s.globalSubscribr.publish(e,t,r),this.subscribr.publish(e,t,r)}getResponseHandler(e){if(!e)return;let t=s.getOrParseMediaType(e);if(t){for(let[r,n]of s.contentTypeHandlers)if(t.matches(r))return n}}get[Symbol.toStringTag](){return"Transportr"}};export{Re as Transportr};
|
|
1
|
+
var C=/^[-!#$%&'*+.^_`|~A-Za-z0-9]*$/u,me=/(["\\])/ug,ye=/^[\t\u0020-\u007E\u0080-\u00FF]*$/u,K=class W extends Map{constructor(e=[]){super(e)}static isValid(e,t){return C.test(e)&&ye.test(t)}get(e){return super.get(e.toLowerCase())}has(e){return super.has(e.toLowerCase())}set(e,t){if(!W.isValid(e,t))throw new Error(`Invalid media type parameter name/value: ${e}/${t}`);return super.set(e.toLowerCase(),t),this}delete(e){return super.delete(e.toLowerCase())}toString(){return Array.from(this).map(([e,t])=>`;${e}=${!t||!C.test(t)?`"${t.replace(me,"\\$1")}"`:t}`).join("")}get[Symbol.toStringTag](){return"MediaTypeParameters"}},be=new Set([" "," ",`
|
|
2
|
+
`,"\r"]),Ee=/[ \t\n\r]+$/u,Te=/^[ \t\n\r]+|[ \t\n\r]+$/ug,Oe=class E{static parse(e){e=e.replace(Te,"");let t=0,[r,n]=E.collect(e,t,["/"]);if(t=n,!r.length||t>=e.length||!C.test(r))throw new TypeError(E.generateErrorMessage("type",r));++t;let[o,i]=E.collect(e,t,[";"],!0,!0);if(t=i,!o.length||!C.test(o))throw new TypeError(E.generateErrorMessage("subtype",o));let l=new K;for(;t<e.length;){for(++t;be.has(e[t]);)++t;let a;if([a,t]=E.collect(e,t,[";","="],!1),t>=e.length||e[t]===";")continue;++t;let c;if(e[t]==='"')for([c,t]=E.collectHttpQuotedString(e,t);t<e.length&&e[t]!==";";)++t;else if([c,t]=E.collect(e,t,[";"],!1,!0),!c)continue;a&&K.isValid(a,c)&&!l.has(a)&&l.set(a,c)}return{type:r,subtype:o,parameters:l}}get[Symbol.toStringTag](){return"MediaTypeParser"}static collect(e,t,r,n=!0,o=!1){let i="";for(let{length:l}=e;t<l&&!r.includes(e[t]);t++)i+=e[t];return n&&(i=i.toLowerCase()),o&&(i=i.replace(Ee,"")),[i,t]}static collectHttpQuotedString(e,t){let r="";for(let n=e.length,o;++t<n&&(o=e[t])!=='"';)r+=o=="\\"&&++t<n?e[t]:o;return[r,t]}static generateErrorMessage(e,t){return`Invalid ${e} "${t}": only HTTP token code points are valid.`}},y=class Y{_type;_subtype;_parameters;constructor(e,t={}){if(t===null||typeof t!="object"||Array.isArray(t))throw new TypeError("The parameters argument must be an object");({type:this._type,subtype:this._subtype,parameters:this._parameters}=Oe.parse(e));for(let[r,n]of Object.entries(t))this._parameters.set(r,n)}static parse(e){try{return new Y(e)}catch{}return null}get type(){return this._type}get subtype(){return this._subtype}get essence(){return`${this._type}/${this._subtype}`}get parameters(){return this._parameters}matches(e){return typeof e=="string"?this.essence.includes(e):this._type===e._type&&this._subtype===e._subtype}toString(){return`${this.essence}${this._parameters.toString()}`}get[Symbol.toStringTag](){return"MediaType"}};var Se=class extends Map{set(s,e){return super.set(s,e instanceof Set?e:(super.get(s)??new Set).add(e)),this}getOrInsert(s,e){return this.has(s)?super.get(s):(super.set(s,e instanceof Set?e:(super.get(s)??new Set).add(e)),e)}getOrInsertComputed(s,e){if(this.has(s))return super.get(s);let t=e(s);return super.set(s,t instanceof Set?t:(super.get(s)??new Set).add(t)),t}find(s,e){let t=this.get(s);if(t!==void 0)return Array.from(t).find(e)}hasValue(s,e){let t=super.get(s);return t?t.has(e):!1}deleteValue(s,e){if(e===void 0)return this.delete(s);let t=super.get(s);if(t){let r=t.delete(e);return t.size===0&&super.delete(s),r}return!1}get[Symbol.toStringTag](){return"SetMultiMap"}},ve=class{context;eventHandler;constructor(s,e){this.context=s,this.eventHandler=e}handle(s,e){this.eventHandler.call(this.context,s,e)}get[Symbol.toStringTag](){return"ContextEventHandler"}},we=class{_eventName;_contextEventHandler;constructor(s,e){this._eventName=s,this._contextEventHandler=e}get eventName(){return this._eventName}get contextEventHandler(){return this._contextEventHandler}get[Symbol.toStringTag](){return"Subscription"}},P=class{subscribers=new Se;errorHandler;setErrorHandler(s){this.errorHandler=s}subscribe(s,e,t=e,r){if(this.validateEventName(s),r?.once){let i=e;e=(l,a)=>{i.call(t,l,a),this.unsubscribe(o)}}let n=new ve(t,e);this.subscribers.set(s,n);let o=new we(s,n);return o}unsubscribe({eventName:s,contextEventHandler:e}){let t=this.subscribers.get(s)??new Set,r=t.delete(e);return r&&t.size===0&&this.subscribers.delete(s),r}publish(s,e=new CustomEvent(s),t){this.validateEventName(s),this.subscribers.get(s)?.forEach(r=>{try{r.handle(e,t)}catch(n){this.errorHandler?this.errorHandler(n,s,e,t):console.error(`Error in event handler for '${s}':`,n)}})}isSubscribed({eventName:s,contextEventHandler:e}){return this.subscribers.get(s)?.has(e)??!1}validateEventName(s){if(!s||typeof s!="string")throw new TypeError("Event name must be a non-empty string");if(s.trim()!==s)throw new Error("Event name cannot have leading or trailing whitespace")}destroy(){this.subscribers.clear()}get[Symbol.toStringTag](){return"Subscribr"}};var v=class extends Error{_entity;responseStatus;_url;_method;_timing;constructor(e,{message:t,cause:r,entity:n,url:o,method:i,timing:l}={}){super(t,{cause:r}),this._entity=n,this.responseStatus=e,this._url=o,this._method=i,this._timing=l}get entity(){return this._entity}get statusCode(){return this.responseStatus.code}get statusText(){return this.responseStatus?.text}get url(){return this._url}get method(){return this._method}get timing(){return this._timing}get name(){return"HttpError"}get[Symbol.toStringTag](){return this.name}};var T=class{_code;_text;constructor(e,t){this._code=e,this._text=t}get code(){return this._code}get text(){return this._text}get[Symbol.toStringTag](){return"ResponseStatus"}toString(){return`${this._code} ${this._text}`}};var w={charset:"utf-8"},Q=/\/$/,Z="XSRF-TOKEN",ee="X-XSRF-TOKEN",R={PNG:new y("image/png"),TEXT:new y("text/plain",w),JSON:new y("application/json",w),HTML:new y("text/html",w),JAVA_SCRIPT:new y("text/javascript",w),CSS:new y("text/css",w),XML:new y("application/xml",w),BIN:new y("application/octet-stream")},x=R.JSON.toString(),te={DEFAULT:"default",FORCE_CACHE:"force-cache",NO_CACHE:"no-cache",NO_STORE:"no-store",ONLY_IF_CACHED:"only-if-cached",RELOAD:"reload"},m={CONFIGURED:"configured",SUCCESS:"success",ERROR:"error",ABORTED:"aborted",TIMEOUT:"timeout",RETRY:"retry",COMPLETE:"complete",ALL_COMPLETE:"all-complete"},O={ABORT:"abort",TIMEOUT:"timeout"},S={ABORT:"AbortError",TIMEOUT:"TimeoutError"},H={once:!0,passive:!0},L=()=>new CustomEvent(O.ABORT,{detail:{cause:S.ABORT}}),se=()=>new CustomEvent(O.TIMEOUT,{detail:{cause:S.TIMEOUT}}),re=["POST","PUT","PATCH","DELETE"],ne=new T(500,"Internal Server Error"),oe=new T(499,"Aborted"),ie=new T(504,"Request Timeout"),I=[408,413,429,500,502,503,504],N=["GET","PUT","HEAD","DELETE","OPTIONS"],k=300,A=2;var U=class{abortSignal;abortController=new AbortController;events=new Map;constructor({signal:e,timeout:t=1/0}={}){if(t<0)throw new RangeError("The timeout cannot be negative");let r=[this.abortController.signal];e!=null&&r.push(e),t!==1/0&&r.push(AbortSignal.timeout(t)),(this.abortSignal=AbortSignal.any(r)).addEventListener(O.ABORT,this,H)}handleEvent({target:{reason:e}}){this.abortController.signal.aborted||e instanceof DOMException&&e.name===S.TIMEOUT&&this.abortSignal.dispatchEvent(se())}get signal(){return this.abortSignal}onAbort(e){return this.addEventListener(O.ABORT,e)}onTimeout(e){return this.addEventListener(O.TIMEOUT,e)}abort(e=L()){this.abortController.abort(e.detail?.cause)}destroy(){this.abortSignal.removeEventListener(O.ABORT,this,H);for(let[e,t]of this.events)this.abortSignal.removeEventListener(t,e,H);return this.events.clear(),this}addEventListener(e,t){return this.abortSignal.addEventListener(e,t,H),this.events.set(t,e),this}get[Symbol.toStringTag](){return"SignalController"}};var ae,qe,B=()=>qe??=import("./OP3JQ447.js").then(({default:s})=>e=>s.sanitize(e)),q=async()=>typeof document<"u"&&typeof DOMParser<"u"&&typeof DocumentFragment<"u"?Promise.resolve():ae??=import("jsdom").then(({JSDOM:s})=>{let{window:e}=new s("<!DOCTYPE html><html><head></head><body></body></html>",{url:"http://localhost"});globalThis.window=e,Object.assign(globalThis,{document:e.document,DOMParser:e.DOMParser,DocumentFragment:e.DocumentFragment})}).catch(()=>{throw ae=void 0,new Error("jsdom is required for HTML/XML/DOM features in Node.js environments. Install it with: npm install jsdom")}),ue=async s=>await s.text(),_=async s=>{await q();let e=URL.createObjectURL(await s.blob());return new Promise((t,r)=>{let n=document.createElement("script");Object.assign(n,{src:e,type:"text/javascript",async:!0}),n.onload=()=>{URL.revokeObjectURL(e),document.head.removeChild(n),t()},n.onerror=()=>{URL.revokeObjectURL(e),document.head.removeChild(n),r(new Error("Script failed to load"))},document.head.appendChild(n)})},D=async s=>{await q();let e=URL.createObjectURL(await s.blob());return new Promise((t,r)=>{let n=document.createElement("link");Object.assign(n,{href:e,type:"text/css",rel:"stylesheet"}),n.onload=()=>t(URL.revokeObjectURL(e)),n.onerror=()=>{URL.revokeObjectURL(e),document.head.removeChild(n),r(new Error("Stylesheet load failed"))},document.head.appendChild(n)})},j=async s=>await s.json(),le=async s=>await s.blob(),F=async s=>{await q();let e=URL.createObjectURL(await s.blob());return new Promise((t,r)=>{let n=new Image;n.onload=()=>{URL.revokeObjectURL(e),t(n)},n.onerror=()=>{URL.revokeObjectURL(e),r(new Error("Image failed to load"))},n.src=e})},ce=async s=>await s.arrayBuffer(),$=async s=>Promise.resolve(s.body),G=async s=>{await q();let e=await B();return new DOMParser().parseFromString(e(await s.text()),"application/xml")},J=async s=>{await q();let e=await B();return new DOMParser().parseFromString(e(await s.text()),"text/html")},de=async s=>{await q();let e=await B();return document.createRange().createContextualFragment(e(await s.text()))};var pe=s=>s!==void 0&&re.includes(s),fe=s=>s instanceof FormData||s instanceof Blob||s instanceof ArrayBuffer||s instanceof ReadableStream||s instanceof URLSearchParams||ArrayBuffer.isView(s),he=s=>{if(typeof document>"u"||!document.cookie)return;let e=`${s}=`,t=document.cookie.split(";");for(let r=0,n=t.length;r<n;r++){let o=t[r].trim();if(o.startsWith(e))return decodeURIComponent(o.slice(e.length))}},ge=s=>JSON.stringify(s),z=s=>s!==null&&typeof s=="string",b=s=>s!==null&&typeof s=="object"&&!Array.isArray(s)&&Object.getPrototypeOf(s)===Object.prototype,V=(...s)=>{let e=s.length;if(e===0)return;if(e===1){let[r]=s;return b(r)?X(r):r}let t={};for(let r of s){if(!b(r))return;for(let[n,o]of Object.entries(r)){let i=t[n];Array.isArray(o)?t[n]=[...o,...Array.isArray(i)?i.filter(l=>!o.includes(l)):[]]:b(o)?t[n]=b(i)?V(i,o):X(o):t[n]=o}}return t};function X(s){if(b(s)){let e={},t=Object.keys(s);for(let r=0,n=t.length,o;r<n;r++)o=t[r],e[o]=X(s[o]);return e}return s}var Re=class s{_baseUrl;_options;subscribr;hooks={beforeRequest:[],afterResponse:[],beforeError:[]};static globalSubscribr=new P;static globalHooks={beforeRequest:[],afterResponse:[],beforeError:[]};static signalControllers=new Set;static inflightRequests=new Map;static mediaTypeCache=new Map(Object.values(R).map(e=>[e.toString(),e]));static contentTypeHandlers=[[R.TEXT.type,ue],[R.JSON.subtype,j],[R.BIN.subtype,$],[R.HTML.subtype,J],[R.XML.subtype,G],[R.PNG.type,F],[R.JAVA_SCRIPT.subtype,_],[R.CSS.subtype,D]];constructor(e=globalThis.location?.origin??"http://localhost",t={}){b(e)&&([e,t]=[globalThis.location?.origin??"http://localhost",e]),this._baseUrl=s.getBaseUrl(e),this._options=s.createOptions(t,s.defaultRequestOptions),this.subscribr=new P}static CredentialsPolicy={INCLUDE:"include",OMIT:"omit",SAME_ORIGIN:"same-origin"};static RequestModes={CORS:"cors",NAVIGATE:"navigate",NO_CORS:"no-cors",SAME_ORIGIN:"same-origin"};static RequestPriorities={HIGH:"high",LOW:"low",AUTO:"auto"};static RedirectPolicies={ERROR:"error",FOLLOW:"follow",MANUAL:"manual"};static ReferrerPolicy={NO_REFERRER:"no-referrer",NO_REFERRER_WHEN_DOWNGRADE:"no-referrer-when-downgrade",ORIGIN:"origin",ORIGIN_WHEN_CROSS_ORIGIN:"origin-when-cross-origin",SAME_ORIGIN:"same-origin",STRICT_ORIGIN:"strict-origin",STRICT_ORIGIN_WHEN_CROSS_ORIGIN:"strict-origin-when-cross-origin",UNSAFE_URL:"unsafe-url"};static RequestEvents=m;static defaultRequestOptions={body:void 0,cache:te.NO_STORE,credentials:s.CredentialsPolicy.SAME_ORIGIN,headers:new Headers({"content-type":x,accept:x}),searchParams:void 0,integrity:void 0,keepalive:void 0,method:"GET",mode:s.RequestModes.CORS,priority:s.RequestPriorities.AUTO,redirect:s.RedirectPolicies.FOLLOW,referrer:"about:client",referrerPolicy:s.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN,signal:void 0,timeout:3e4,global:!0};static register(e,t,r){return s.globalSubscribr.subscribe(e,t,r)}static unregister(e){return s.globalSubscribr.unsubscribe(e)}static abortAll(){for(let e of this.signalControllers)e.abort(L());this.signalControllers.clear()}static registerContentTypeHandler(e,t){s.contentTypeHandlers.unshift([e,t])}static unregisterContentTypeHandler(e){let t=s.contentTypeHandlers.findIndex(([r])=>r===e);return t===-1?!1:(s.contentTypeHandlers.splice(t,1),!0)}static addHooks(e){e.beforeRequest&&s.globalHooks.beforeRequest.push(...e.beforeRequest),e.afterResponse&&s.globalHooks.afterResponse.push(...e.afterResponse),e.beforeError&&s.globalHooks.beforeError.push(...e.beforeError)}static clearHooks(){s.globalHooks={beforeRequest:[],afterResponse:[],beforeError:[]}}static unregisterAll(){s.abortAll(),s.globalSubscribr=new P,s.clearHooks(),s.inflightRequests.clear()}get baseUrl(){return this._baseUrl}register(e,t,r){return this.subscribr.subscribe(e,t,r)}unregister(e){return this.subscribr.unsubscribe(e)}addHooks(e){return e.beforeRequest&&this.hooks.beforeRequest.push(...e.beforeRequest),e.afterResponse&&this.hooks.afterResponse.push(...e.afterResponse),e.beforeError&&this.hooks.beforeError.push(...e.beforeError),this}clearHooks(){return this.hooks.beforeRequest.length=0,this.hooks.afterResponse.length=0,this.hooks.beforeError.length=0,this}destroy(){this.clearHooks(),this.subscribr.destroy()}async get(e,t){return this._get(e,t)}async post(e,t){return typeof e!="string"&&([e,t]=[void 0,e]),this.execute(e,t,{method:"POST"})}async put(e,t){return this.execute(e,t,{method:"PUT"})}async patch(e,t){return this.execute(e,t,{method:"PATCH"})}async delete(e,t){return this.execute(e,t,{method:"DELETE"})}async head(e,t){return this.execute(e,t,{method:"HEAD"})}async options(e,t={}){b(e)&&([e,t]=[void 0,e]);let r=this.processRequestOptions(t,{method:"OPTIONS"}),{requestOptions:n}=r,o=n.hooks,i=s.createUrl(this._baseUrl,e,n.searchParams),l=[s.globalHooks.beforeRequest,this.hooks.beforeRequest,o?.beforeRequest];for(let d of l)if(d)for(let u of d){let g=await u(n,i);g&&(Object.assign(n,g),g.searchParams!==void 0&&(i=s.createUrl(this._baseUrl,e,n.searchParams)))}let a=await this._request(e,r),c=[s.globalHooks.afterResponse,this.hooks.afterResponse,o?.afterResponse];for(let d of c)if(d)for(let u of d){let g=await u(a,n);g&&(a=g)}let h=a.headers.get("allow")?.split(",").map(d=>d.trim());return this.publish({name:m.SUCCESS,data:h,global:t.global}),h}async request(e,t={}){b(e)&&([e,t]=[void 0,e]);let r=await this._request(e,this.processRequestOptions(t,{}));return this.publish({name:m.SUCCESS,data:r,global:t.global}),r}async getJson(e,t){return this._get(e,t,{headers:{accept:`${R.JSON}`}},j)}async getXml(e,t){return this._get(e,t,{headers:{accept:`${R.XML}`}},G)}async getHtml(e,t,r){let n=await this._get(e,t,{headers:{accept:`${R.HTML}`}},J);return r&&n?n.querySelector(r):n}async getHtmlFragment(e,t,r){let n=await this._get(e,t,{headers:{accept:`${R.HTML}`}},de);return r&&n?n.querySelector(r):n}async getScript(e,t){return this._get(e,t,{headers:{accept:`${R.JAVA_SCRIPT}`}},_)}async getStylesheet(e,t){return this._get(e,t,{headers:{accept:`${R.CSS}`}},D)}async getBlob(e,t){return this._get(e,t,{headers:{accept:"application/octet-stream"}},le)}async getImage(e,t){return this._get(e,t,{headers:{accept:"image/*"}},F)}async getBuffer(e,t){return this._get(e,t,{headers:{accept:"application/octet-stream"}},ce)}async getStream(e,t){return this._get(e,t,{headers:{accept:"application/octet-stream"}},$)}async _get(e,t,r={},n){return this.execute(e,t,{...r,method:"GET",body:void 0},n)}async _request(e,{signalController:t,requestOptions:r,global:n}){s.signalControllers.add(t);let o=s.normalizeRetryOptions(r.retry),i=r.method??"GET",l=o.limit>0&&o.methods.includes(i),a=r.dedupe===!0&&(i==="GET"||i==="HEAD"),c=0,h=performance.now(),d=()=>{let u=performance.now();return{start:h,end:u,duration:u-h}};try{let u=s.createUrl(this._baseUrl,e,r.searchParams),g=a?`${i}:${u.href}`:"";if(a){let f=s.inflightRequests.get(g);if(f)return(await f).clone()}let p=async()=>{for(;;)try{let f=await fetch(u,r);if(!f.ok){if(l&&c<o.limit&&o.statusCodes.includes(f.status)){c++,this.publish({name:m.RETRY,data:{attempt:c,status:f.status,method:i,path:e,timing:d()},global:n}),await s.retryDelay(o,c);continue}let M;try{M=await f.text()}catch{}throw await this.handleError(e,f,{entity:M,url:u,method:i,timing:d()},r)}return f}catch(f){if(f instanceof v)throw f;if(l&&c<o.limit){c++,this.publish({name:m.RETRY,data:{attempt:c,error:f.message,method:i,path:e,timing:d()},global:n}),await s.retryDelay(o,c);continue}throw await this.handleError(e,void 0,{cause:f,url:u,method:i,timing:d()},r)}};if(a){let f=p();s.inflightRequests.set(g,f);try{return await f}finally{s.inflightRequests.delete(g)}}return await p()}finally{if(s.signalControllers.delete(t.destroy()),!r.signal?.aborted){let u=d();this.publish({name:m.COMPLETE,data:{timing:u},global:n}),s.signalControllers.size===0&&this.publish({name:m.ALL_COMPLETE,global:n})}}}static normalizeRetryOptions(e){return e===void 0?{limit:0,statusCodes:[],methods:[],delay:k,backoffFactor:A}:typeof e=="number"?{limit:e,statusCodes:[...I],methods:[...N],delay:k,backoffFactor:A}:{limit:e.limit??0,statusCodes:e.statusCodes??[...I],methods:e.methods??[...N],delay:e.delay??k,backoffFactor:e.backoffFactor??A}}static retryDelay(e,t){let r=typeof e.delay=="function"?e.delay(t):e.delay*e.backoffFactor**(t-1);return new Promise(n=>setTimeout(n,r))}async execute(e,t={},r={},n){b(e)&&([e,t]=[void 0,e]);let o=this.processRequestOptions(t,r),{requestOptions:i}=o,l=i.hooks,a=s.createUrl(this._baseUrl,e,i.searchParams),c=[s.globalHooks.beforeRequest,this.hooks.beforeRequest,l?.beforeRequest];for(let u of c)if(u)for(let g of u){let p=await g(i,a);p&&(Object.assign(i,p),p.searchParams!==void 0&&(a=s.createUrl(this._baseUrl,e,i.searchParams)))}let h=await this._request(e,o),d=[s.globalHooks.afterResponse,this.hooks.afterResponse,l?.afterResponse];for(let u of d)if(u)for(let g of u){let p=await g(h,i);p&&(h=p)}try{!n&&h.status!==204&&(n=this.getResponseHandler(h.headers.get("content-type")));let u=await n?.(h);return this.publish({name:m.SUCCESS,data:u,global:o.global}),u}catch(u){throw await this.handleError(e,h,{cause:u},i)}}static createOptions({headers:e,searchParams:t,...r},{headers:n,searchParams:o,...i}){return n=s.mergeHeaders(new Headers,e,n),o=s.mergeSearchParams(new URLSearchParams,t,o),{...V(i,r)??{},headers:n,searchParams:o}}static mergeHeaders(e,...t){for(let r of t)if(r!==void 0)if(r instanceof Headers)r.forEach((n,o)=>e.set(o,n));else if(Array.isArray(r))for(let[n,o]of r)e.set(n,o);else{let n=r,o=Object.keys(n);for(let i=0;i<o.length;i++){let l=o[i],a=n[l];a!==void 0&&e.set(l,String(a))}}return e}static mergeSearchParams(e,...t){for(let r of t)if(r!==void 0)if(r instanceof URLSearchParams)r.forEach((n,o)=>e.set(o,n));else if(z(r)||Array.isArray(r))for(let[n,o]of new URLSearchParams(r))e.set(n,o);else{let n=Object.keys(r);for(let o=0;o<n.length;o++){let i=n[o],l=r[i];l!==void 0&&e.set(i,String(l))}}return e}processRequestOptions({body:e,headers:t,searchParams:r,...n},{headers:o,searchParams:i,...l}){let a={...this._options,...n,...l,headers:s.mergeHeaders(new Headers,this._options.headers,t,o),searchParams:s.mergeSearchParams(new URLSearchParams,this._options.searchParams,r,i)};if(pe(a.method))if(fe(e))a.body=e,a.headers.delete("content-type");else{let p=a.headers.get("content-type")?.includes("json")??!1;a.body=p&&b(e)?ge(e):e}else a.headers.delete("content-type"),a.body instanceof URLSearchParams&&s.mergeSearchParams(a.searchParams,a.body),a.body=void 0;let{signal:c,timeout:h,global:d=!1,xsrf:u}=a;if(u){let p=typeof u=="object"?u:{},f=he(p.cookieName??Z);f&&a.headers.set(p.headerName??ee,f)}let g=new U({signal:c,timeout:h}).onAbort(p=>this.publish({name:m.ABORTED,event:p,global:d})).onTimeout(p=>this.publish({name:m.TIMEOUT,event:p,global:d}));return a.signal=g.signal,this.publish({name:m.CONFIGURED,data:a,global:d}),{signalController:g,requestOptions:a,global:d}}static getBaseUrl(e){if(e instanceof URL)return e;if(!z(e))throw new TypeError("Invalid URL");return new URL(e,e.startsWith("/")?globalThis.location.origin:void 0)}static getOrParseMediaType(e){if(e===null)return;let t=s.mediaTypeCache.get(e);if(t!==void 0)return t;if(t=y.parse(e)??void 0,t!==void 0){if(s.mediaTypeCache.size>=100){let r=s.mediaTypeCache.keys().next().value;r!==void 0&&s.mediaTypeCache.delete(r)}s.mediaTypeCache.set(e,t)}return t}static createUrl(e,t,r){let n=t?new URL(`${e.pathname.replace(Q,"")}${t}`,e.origin):new URL(e);return r&&s.mergeSearchParams(n.searchParams,r),n}static generateResponseStatusFromError(e,{status:t,statusText:r}=new Response){switch(e){case S.ABORT:return oe;case S.TIMEOUT:return ie;default:return t>=400?new T(t,r):ne}}async handleError(e,t,{cause:r,entity:n,url:o,method:i,timing:l}={},a){let c=i&&o?`${i} ${o.href} failed${t?` with status ${t.status}`:""}`:`An error has occurred with your request to: '${e}'`,h=new v(s.generateResponseStatusFromError(r?.name,t),{message:c,cause:r,entity:n,url:o,method:i,timing:l}),d=[s.globalHooks.beforeError,this.hooks.beforeError,a?.hooks?.beforeError];for(let u of d)if(u)for(let g of u){let p=await g(h);p instanceof v&&(h=p)}return this.publish({name:m.ERROR,data:h}),h}publish({name:e,event:t=new CustomEvent(e),data:r,global:n=!0}){n&&s.globalSubscribr.publish(e,t,r),this.subscribr.publish(e,t,r)}getResponseHandler(e){if(!e)return;let t=s.getOrParseMediaType(e);if(t){for(let[r,n]of s.contentTypeHandlers)if(t.matches(r))return n}}get[Symbol.toStringTag](){return"Transportr"}};export{Re as Transportr};
|
|
3
3
|
//# sourceMappingURL=transportr.js.map
|