@d1g1tal/transportr 1.4.4 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,90 +1,347 @@
1
1
  # transportr
2
- JavaScript wrapper for Fetch API
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@d1g1tal/transportr?color=blue)](https://www.npmjs.com/package/@d1g1tal/transportr)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@d1g1tal/transportr)](https://www.npmjs.com/package/@d1g1tal/transportr)
5
+ [![CI](https://github.com/D1g1talEntr0py/transportr/actions/workflows/ci.yml/badge.svg)](https://github.com/D1g1talEntr0py/transportr/actions/workflows/ci.yml)
6
+ [![codecov](https://codecov.io/gh/D1g1talEntr0py/transportr/graph/badge.svg)](https://codecov.io/gh/D1g1talEntr0py/transportr)
7
+ [![License: ISC](https://img.shields.io/github/license/D1g1talEntr0py/transportr)](https://github.com/D1g1talEntr0py/transportr/blob/main/LICENSE)
8
+ [![Node.js](https://img.shields.io/node/v/@d1g1tal/transportr)](https://nodejs.org)
9
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
10
+
11
+ A TypeScript Fetch API wrapper providing type-safe HTTP requests with advanced abort/timeout handling, event-driven architecture, and automatic content-type based response processing.
12
+
13
+ ## Features
14
+
15
+ - **Type-safe** — Full TypeScript support with strict types, branded JSON strings, and typed headers
16
+ - **Automatic response handling** — Content-type based response parsing (JSON, HTML, XML, images, streams, etc.)
17
+ - **Abort & timeout management** — Per-request timeouts, `AbortController` integration, and `abortAll()` for cleanup
18
+ - **Event-driven** — Global and instance-level lifecycle events (`configured`, `success`, `error`, `complete`, etc.)
19
+ - **Retry logic** — Configurable retry with exponential backoff, status code filtering, and method filtering
20
+ - **Request deduplication** — Identical in-flight GET/HEAD requests share a single fetch
21
+ - **Lifecycle hooks** — `beforeRequest`, `afterResponse`, `beforeError` hooks at global, instance, and per-request levels
22
+ - **XSRF/CSRF protection** — Automatic cookie-to-header token injection
23
+ - **HTML selectors** — Extract specific elements from HTML responses with CSS selectors
24
+ - **FormData auto-detection** — Automatically handles FormData, Blob, ArrayBuffer, and stream bodies
25
+
3
26
  ## Installation
27
+
4
28
  ```bash
5
- npm install @d1g1tal/transportr
29
+ pnpm add @d1g1tal/transportr
6
30
  ```
7
- ## Usage
8
- ```javascript
9
- import Transportr from '@d1g1tal/transportr';
10
31
 
11
- // Creates default instance configured for JSON requests using UTF-8 encoding.
12
- const transportr = new Transportr('https://jsonplaceholder.typicode.com', { headers: { [Transportr.RequestHeader.CONTENT_TYPE]: Transportr.MediaType.JSON }, encoding: 'utf-8', });
32
+ ## Requirements
13
33
 
14
- transportr.get('/todos/1')
15
- .then(json => console.log(json))
16
- .catch(error => console.error(error.message));
34
+ - **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
35
+ - `jsdom` is an **optional peer dependency** — only needed for HTML/XML/DOM features in Node.js. Install it separately if you use `getHtml()`, `getXml()`, `getHtmlFragment()`, `getScript()`, `getStylesheet()`, or `getImage()` in a non-browser environment:
36
+
37
+ ```bash
38
+ pnpm add jsdom
17
39
  ```
18
- Or
19
40
 
20
- ```javascript
21
- const transportr = new Transportr('https://jsonplaceholder.typicode.com');
41
+ ## Quick Start
22
42
 
23
- try {
24
- const todo1 = await transportr.getJson('/todos/1');
25
- console.log(todo1);
43
+ ```typescript
44
+ import { Transportr } from '@d1g1tal/transportr';
45
+
46
+ const api = new Transportr('https://api.example.com');
47
+
48
+ // GET JSON
49
+ const data = await api.getJson('/users/1');
50
+
51
+ // POST with JSON body
52
+ const created = await api.post('/users', { body: { name: 'Alice' } });
53
+
54
+ // GET with search params
55
+ const results = await api.getJson('/search', { searchParams: { q: 'term', page: 1 } });
56
+
57
+ // Typed response using generics
58
+ interface User { id: number; name: string; }
59
+ const user = await api.get<User>('/users/1');
60
+ ```
61
+
62
+ ## API
63
+
64
+ ### Constructor
65
+
66
+ ```typescript
67
+ new Transportr(url?: URL | string | RequestOptions, options?: RequestOptions)
68
+ ```
69
+
70
+ Creates a new instance. When `url` is omitted, defaults to `globalThis.location.origin`.
71
+
72
+ ```typescript
73
+ // With base URL
74
+ const api = new Transportr('https://api.example.com/v2');
75
+
76
+ // With URL and default options
77
+ const api = new Transportr('https://api.example.com', {
78
+ timeout: 10000,
79
+ headers: { 'Authorization': 'Bearer token' }
80
+ });
81
+
82
+ // With options only (uses current origin)
83
+ const api = new Transportr({ timeout: 5000 });
84
+ ```
85
+
86
+ ### Request Methods
87
+
88
+ | Method | Description |
89
+ |--------|-------------|
90
+ | `get(path?, options?)` | GET request with auto content-type handling |
91
+ | `post(path?, options?)` | POST request |
92
+ | `put(path?, options?)` | PUT request |
93
+ | `patch(path?, options?)` | PATCH request |
94
+ | `delete(path?, options?)` | DELETE request |
95
+ | `head(path?, options?)` | HEAD request |
96
+ | `options(path?, options?)` | OPTIONS request (returns allowed methods) |
97
+ | `request(path?, options?)` | Raw request returning `TypedResponse<T>` |
98
+
99
+ ### Typed Response Methods
100
+
101
+ | Method | Returns | Accept Header |
102
+ |--------|---------|---------------|
103
+ | `getJson(path?, options?)` | `Json` | `application/json` |
104
+ | `getHtml(path?, options?, selector?)` | `Document \| Element` | `text/html` |
105
+ | `getHtmlFragment(path?, options?, selector?)` | `DocumentFragment \| Element` | `text/html` |
106
+ | `getXml(path?, options?)` | `Document` | `application/xml` |
107
+ | `getScript(path?, options?)` | `void` (injected into DOM) | `application/javascript` |
108
+ | `getStylesheet(path?, options?)` | `void` (injected into DOM) | `text/css` |
109
+ | `getBlob(path?, options?)` | `Blob` | `application/octet-stream` |
110
+ | `getImage(path?, options?)` | `HTMLImageElement` | `image/*` |
111
+ | `getBuffer(path?, options?)` | `ArrayBuffer` | `application/octet-stream` |
112
+ | `getStream(path?, options?)` | `ReadableStream` | `application/octet-stream` |
113
+
114
+ ### Request Options
115
+
116
+ ```typescript
117
+ type RequestOptions = {
118
+ headers?: RequestHeaders;
119
+ searchParams?: URLSearchParams | string | Record<string, string | number | boolean>;
120
+ timeout?: number; // Default: 30000ms
121
+ global?: boolean; // Emit global events (default: true)
122
+ body?: BodyInit | JsonObject; // Auto-serialized for JSON content-type
123
+ retry?: number | RetryOptions;
124
+ dedupe?: boolean; // Deduplicate identical GET/HEAD requests
125
+ xsrf?: boolean | XsrfOptions;
126
+ hooks?: HooksOptions;
127
+ // ...all standard RequestInit properties (cache, credentials, mode, etc.)
128
+ };
129
+ ```
130
+
131
+ ### Retry
132
+
133
+ ```typescript
134
+ // Simple: retry up to 3 times with default settings
135
+ await api.get('/data', { retry: 3 });
136
+
137
+ // Advanced configuration
138
+ await api.get('/data', {
139
+ retry: {
140
+ limit: 3,
141
+ statusCodes: [408, 413, 429, 500, 502, 503, 504],
142
+ methods: ['GET', 'PUT', 'HEAD', 'DELETE', 'OPTIONS'],
143
+ delay: 300, // ms before first retry
144
+ backoffFactor: 2 // exponential backoff multiplier
145
+ }
146
+ });
147
+ ```
148
+
149
+ ### Request Deduplication
150
+
151
+ When `dedupe: true`, identical in-flight GET/HEAD requests share a single fetch call. Each consumer receives a cloned response.
152
+
153
+ ```typescript
154
+ // Only one fetch call is made
155
+ const [a, b] = await Promise.all([
156
+ api.get('/data', { dedupe: true }),
157
+ api.get('/data', { dedupe: true })
158
+ ]);
159
+ ```
160
+
161
+ ### Lifecycle Hooks
162
+
163
+ Hooks run in order: global → instance → per-request.
164
+
165
+ ```typescript
166
+ // Global hooks (all instances)
167
+ Transportr.addHooks({
168
+ beforeRequest: [async (options, url) => {
169
+ options.headers.set('X-Request-ID', crypto.randomUUID());
170
+ return options;
171
+ }],
172
+ afterResponse: [async (response, options) => response],
173
+ beforeError: [(error) => error]
174
+ });
175
+
176
+ // Instance hooks
177
+ api.addHooks({
178
+ afterResponse: [async (response) => {
179
+ console.log(`Response: ${response.status}`);
180
+ return response;
181
+ }]
182
+ });
183
+
184
+ // Per-request hooks
185
+ await api.get('/data', {
186
+ hooks: { beforeRequest: [async (opts) => opts] }
187
+ });
188
+ ```
189
+
190
+ ### Events
26
191
 
27
- const todo2 = await transportr.getJson('/todos/2');
28
- console.log(todo2);
192
+ ```typescript
193
+ // Global events (all instances)
194
+ const reg = Transportr.register(Transportr.RequestEvents.SUCCESS, (event, data) => {
195
+ console.log('Request succeeded:', data);
196
+ });
197
+
198
+ // Instance events
199
+ const reg = api.register(Transportr.RequestEvents.ERROR, (event, error) => {
200
+ console.error('Request failed:', error);
201
+ });
202
+
203
+ // Unregister
204
+ api.unregister(reg); // Returns `this` for chaining
205
+ ```
206
+
207
+ **Event lifecycle**: `configured` → `success | error | aborted | timeout` → `complete` → `all-complete`
208
+
209
+ Additional events: `retry` (emitted on each retry attempt)
210
+
211
+ ### Error Handling
212
+
213
+ Non-2xx responses throw an error with `name === 'HttpError'`. Aborted and timed-out requests also produce an `HttpError` with synthetic status codes.
214
+
215
+ ```typescript
216
+ import type { HttpError } from '@d1g1tal/transportr';
217
+
218
+ try {
219
+ const user = await api.getJson('/users/1');
29
220
  } catch (error) {
30
- console.error(error.message);
221
+ if (error instanceof Error && error.name === 'HttpError') {
222
+ const httpError = error as unknown as HttpError;
223
+ console.error(httpError.statusCode); // HTTP status code
224
+ console.error(httpError.statusText); // HTTP status text
225
+ console.error(httpError.entity); // parsed response body (if any)
226
+ console.error(httpError.url?.href); // request URL
227
+ console.error(httpError.method); // HTTP method used
228
+ console.error(httpError.timing); // { start, end, duration } in ms
229
+ }
31
230
  }
32
231
  ```
33
232
 
34
- ## API
35
- ### Transportr
36
- #### constructor(options)
37
- ##### options
38
- Type: `Object`
39
-
40
- ###### options.baseURL
41
- Type: `String`
42
- Base URL for all requests.
43
-
44
- ###### options.headers
45
- Type: `Object`
46
- Default headers for all requests.
47
-
48
- ###### options.timeout
49
- Type: `Number`
50
- Default timeout for all requests.
51
-
52
- ###### options.credentials
53
- Type: `String`
54
- Default credentials for all requests.
55
-
56
- ###### options.mode
57
- Type: `String`
58
- Default mode for all requests.
59
-
60
- ###### options.cache
61
- Type: `String`
62
- Default cache for all requests.
63
-
64
- ###### options.redirect
65
- Type: `String`
66
- Default redirect for all requests.
67
-
68
- ###### options.referrer
69
- Type: `String`
70
- Default referrer for all requests.
71
-
72
- ###### options.integrity
73
- Type: `String`
74
- Default integrity for all requests.
75
-
76
- ###### options.keepalive
77
- Type: `Boolean`
78
- Default keepalive for all requests.
79
-
80
- ###### options.signal
81
- Type: `AbortSignal`
82
- Default signal for all requests.
83
-
84
- ###### options.encoding
85
- Type: `String`
86
- Default encoding for all requests.
87
-
88
- ###### options.body
89
- Type: `Object|String|FormData|URLSearchParams|Blob|BufferSource|ReadableStream`
90
- Default body for all requests.
233
+ **Synthetic status codes for non-HTTP failures:**
234
+
235
+ | Code | Text | Cause |
236
+ |------|------|-------|
237
+ | `499` | `Aborted` | Cancelled via `controller.abort()` or `Transportr.abortAll()` |
238
+ | `504` | `Request Timeout` | `timeout` option exceeded |
239
+
240
+ ### Abort & Timeout
241
+
242
+ ```typescript
243
+ // Per-request timeout
244
+ await api.get('/slow', { timeout: 5000 });
245
+
246
+ // Manual abort via AbortController
247
+ const controller = new AbortController();
248
+ api.get('/data', { signal: controller.signal });
249
+ controller.abort();
250
+
251
+ // Abort all in-flight requests
252
+ Transportr.abortAll();
253
+ ```
254
+
255
+ ### XSRF/CSRF Protection
256
+
257
+ ```typescript
258
+ // Default: reads 'XSRF-TOKEN' cookie, sets 'X-XSRF-TOKEN' header
259
+ await api.post('/data', { body: payload, xsrf: true });
260
+
261
+ // Custom cookie/header names
262
+ await api.post('/data', {
263
+ body: payload,
264
+ xsrf: { cookieName: 'MY-CSRF', headerName: 'X-MY-CSRF' }
265
+ });
266
+ ```
267
+
268
+ ### HTML Selector Support
269
+
270
+ ```typescript
271
+ // Get a specific element from HTML response
272
+ const nav = await api.getHtml('/page', {}, 'nav.main');
273
+ const item = await api.getHtmlFragment('/partial', {}, '.item:first-child');
274
+ ```
275
+
276
+ ### FormData & Raw Bodies
277
+
278
+ FormData, Blob, ArrayBuffer, ReadableStream, TypedArray, and URLSearchParams are sent as-is. The `Content-Type` header is automatically removed so the runtime can set it (e.g., multipart boundary for FormData).
279
+
280
+ ```typescript
281
+ const form = new FormData();
282
+ form.append('file', fileBlob, 'photo.jpg');
283
+ await api.post('/upload', { body: form });
284
+ ```
285
+
286
+ ### Custom Content-Type Handlers
287
+
288
+ ```typescript
289
+ // Register a custom handler (takes priority over built-in)
290
+ Transportr.registerContentTypeHandler('csv', async (response) => {
291
+ const text = await response.text();
292
+ return text.split('\n').map(row => row.split(','));
293
+ });
294
+
295
+ // Remove a handler
296
+ Transportr.unregisterContentTypeHandler('csv');
297
+ ```
298
+
299
+ ### Cleanup
300
+
301
+ ```typescript
302
+ // Tear down a single instance
303
+ api.destroy();
304
+
305
+ // Tear down all global state
306
+ Transportr.unregisterAll();
307
+
308
+ // Clear only global hooks without aborting in-flight requests
309
+ Transportr.clearHooks();
310
+ ```
311
+
312
+ ### Method Chaining
313
+
314
+ Instance methods `unregister()`, `addHooks()`, and `clearHooks()` return `this`:
315
+
316
+ ```typescript
317
+ api
318
+ .addHooks({ beforeRequest: [myHook] })
319
+ .clearHooks()
320
+ .addHooks({ afterResponse: [logHook] });
321
+ ```
322
+
323
+ ### Instance Properties
324
+
325
+ | Property | Type | Description |
326
+ |----------|------|-------------|
327
+ | `baseUrl` | `URL` | The base URL used for all requests from this instance |
328
+
329
+ ### Static Properties
330
+
331
+ | Property | Description |
332
+ |----------|-------------|
333
+ | `Transportr.MediaType` | HTTP media type constants |
334
+ | `Transportr.RequestMethod` | HTTP method constants |
335
+ | `Transportr.RequestHeader` | Request header constants |
336
+ | `Transportr.ResponseHeader` | Response header constants |
337
+ | `Transportr.CachingPolicy` | Cache policy constants |
338
+ | `Transportr.CredentialsPolicy` | Credentials policy constants |
339
+ | `Transportr.RequestModes` | Request mode constants |
340
+ | `Transportr.RequestPriorities` | Request priority constants |
341
+ | `Transportr.RedirectPolicies` | Redirect policy constants |
342
+ | `Transportr.ReferrerPolicy` | Referrer policy constants |
343
+ | `Transportr.RequestEvents` | Event name constants |
344
+
345
+ ## License
346
+
347
+ [ISC](LICENSE)
@@ -0,0 +1,8 @@
1
+ var{entries:_t,setPrototypeOf:ct,isFrozen:Yt,getPrototypeOf:Xt,getOwnPropertyDescriptor:jt}=Object,{freeze:S,seal:b,create:me}=Object,{apply:ve,construct:Ue}=typeof Reflect<"u"&&Reflect;S||(S=function(o){return o});b||(b=function(o){return o});ve||(ve=function(o,l){for(var a=arguments.length,c=new Array(a>2?a-2:0),D=2;D<a;D++)c[D-2]=arguments[D];return o.apply(l,c)});Ue||(Ue=function(o){for(var l=arguments.length,a=new Array(l>1?l-1:0),c=1;c<l;c++)a[c-1]=arguments[c];return new o(...a)});var fe=R(Array.prototype.forEach),Vt=R(Array.prototype.lastIndexOf),ft=R(Array.prototype.pop),q=R(Array.prototype.push),$t=R(Array.prototype.splice),pe=R(String.prototype.toLowerCase),Ie=R(String.prototype.toString),Me=R(String.prototype.match),K=R(String.prototype.replace),qt=R(String.prototype.indexOf),Kt=R(String.prototype.trim),y=R(Object.prototype.hasOwnProperty),h=R(RegExp.prototype.test),Z=Zt(TypeError);function R(s){return function(o){o instanceof RegExp&&(o.lastIndex=0);for(var l=arguments.length,a=new Array(l>1?l-1:0),c=1;c<l;c++)a[c-1]=arguments[c];return ve(s,o,a)}}function Zt(s){return function(){for(var o=arguments.length,l=new Array(o),a=0;a<o;a++)l[a]=arguments[a];return Ue(s,l)}}function r(s,o){let l=arguments.length>2&&arguments[2]!==void 0?arguments[2]:pe;ct&&ct(s,null);let a=o.length;for(;a--;){let c=o[a];if(typeof c=="string"){let D=l(c);D!==c&&(Yt(o)||(o[a]=D),c=D)}s[c]=!0}return s}function Jt(s){for(let o=0;o<s.length;o++)y(s,o)||(s[o]=null);return s}function C(s){let o=me(null);for(let[l,a]of _t(s))y(s,l)&&(Array.isArray(a)?o[l]=Jt(a):a&&typeof a=="object"&&a.constructor===Object?o[l]=C(a):o[l]=a);return o}function J(s,o){for(;s!==null;){let a=jt(s,o);if(a){if(a.get)return R(a.get);if(typeof a.value=="function")return R(a.value)}s=Xt(s)}function l(){return null}return l}var ut=S(["a","abbr","acronym","address","area","article","aside","audio","b","bdi","bdo","big","blink","blockquote","body","br","button","canvas","caption","center","cite","code","col","colgroup","content","data","datalist","dd","decorator","del","details","dfn","dialog","dir","div","dl","dt","element","em","fieldset","figcaption","figure","font","footer","form","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","img","input","ins","kbd","label","legend","li","main","map","mark","marquee","menu","menuitem","meter","nav","nobr","ol","optgroup","option","output","p","picture","pre","progress","q","rp","rt","ruby","s","samp","search","section","select","shadow","slot","small","source","spacer","span","strike","strong","style","sub","summary","sup","table","tbody","td","template","textarea","tfoot","th","thead","time","tr","track","tt","u","ul","var","video","wbr"]),we=S(["svg","a","altglyph","altglyphdef","altglyphitem","animatecolor","animatemotion","animatetransform","circle","clippath","defs","desc","ellipse","enterkeyhint","exportparts","filter","font","g","glyph","glyphref","hkern","image","inputmode","line","lineargradient","marker","mask","metadata","mpath","part","path","pattern","polygon","polyline","radialgradient","rect","stop","style","switch","symbol","text","textpath","title","tref","tspan","view","vkern"]),xe=S(["feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feDistantLight","feDropShadow","feFlood","feFuncA","feFuncB","feFuncG","feFuncR","feGaussianBlur","feImage","feMerge","feMergeNode","feMorphology","feOffset","fePointLight","feSpecularLighting","feSpotLight","feTile","feTurbulence"]),Qt=S(["animate","color-profile","cursor","discard","font-face","font-face-format","font-face-name","font-face-src","font-face-uri","foreignobject","hatch","hatchpath","mesh","meshgradient","meshpatch","meshrow","missing-glyph","script","set","solidcolor","unknown","use"]),Pe=S(["math","menclose","merror","mfenced","mfrac","mglyph","mi","mlabeledtr","mmultiscripts","mn","mo","mover","mpadded","mphantom","mroot","mrow","ms","mspace","msqrt","mstyle","msub","msup","msubsup","mtable","mtd","mtext","mtr","munder","munderover","mprescripts"]),en=S(["maction","maligngroup","malignmark","mlongdiv","mscarries","mscarry","msgroup","mstack","msline","msrow","semantics","annotation","annotation-xml","mprescripts","none"]),mt=S(["#text"]),pt=S(["accept","action","align","alt","autocapitalize","autocomplete","autopictureinpicture","autoplay","background","bgcolor","border","capture","cellpadding","cellspacing","checked","cite","class","clear","color","cols","colspan","controls","controlslist","coords","crossorigin","datetime","decoding","default","dir","disabled","disablepictureinpicture","disableremoteplayback","download","draggable","enctype","enterkeyhint","exportparts","face","for","headers","height","hidden","high","href","hreflang","id","inert","inputmode","integrity","ismap","kind","label","lang","list","loading","loop","low","max","maxlength","media","method","min","minlength","multiple","muted","name","nonce","noshade","novalidate","nowrap","open","optimum","part","pattern","placeholder","playsinline","popover","popovertarget","popovertargetaction","poster","preload","pubdate","radiogroup","readonly","rel","required","rev","reversed","role","rows","rowspan","spellcheck","scope","selected","shape","size","sizes","slot","span","srclang","start","src","srcset","step","style","summary","tabindex","title","translate","type","usemap","valign","value","width","wrap","xmlns","slot"]),ke=S(["accent-height","accumulate","additive","alignment-baseline","amplitude","ascent","attributename","attributetype","azimuth","basefrequency","baseline-shift","begin","bias","by","class","clip","clippathunits","clip-path","clip-rule","color","color-interpolation","color-interpolation-filters","color-profile","color-rendering","cx","cy","d","dx","dy","diffuseconstant","direction","display","divisor","dur","edgemode","elevation","end","exponent","fill","fill-opacity","fill-rule","filter","filterunits","flood-color","flood-opacity","font-family","font-size","font-size-adjust","font-stretch","font-style","font-variant","font-weight","fx","fy","g1","g2","glyph-name","glyphref","gradientunits","gradienttransform","height","href","id","image-rendering","in","in2","intercept","k","k1","k2","k3","k4","kerning","keypoints","keysplines","keytimes","lang","lengthadjust","letter-spacing","kernelmatrix","kernelunitlength","lighting-color","local","marker-end","marker-mid","marker-start","markerheight","markerunits","markerwidth","maskcontentunits","maskunits","max","mask","mask-type","media","method","mode","min","name","numoctaves","offset","operator","opacity","order","orient","orientation","origin","overflow","paint-order","path","pathlength","patterncontentunits","patterntransform","patternunits","points","preservealpha","preserveaspectratio","primitiveunits","r","rx","ry","radius","refx","refy","repeatcount","repeatdur","restart","result","rotate","scale","seed","shape-rendering","slope","specularconstant","specularexponent","spreadmethod","startoffset","stddeviation","stitchtiles","stop-color","stop-opacity","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke","stroke-width","style","surfacescale","systemlanguage","tabindex","tablevalues","targetx","targety","transform","transform-origin","text-anchor","text-decoration","text-rendering","textlength","type","u1","u2","unicode","values","viewbox","visibility","version","vert-adv-y","vert-origin-x","vert-origin-y","width","word-spacing","wrap","writing-mode","xchannelselector","ychannelselector","x","x1","x2","xmlns","y","y1","y2","z","zoomandpan"]),Tt=S(["accent","accentunder","align","bevelled","close","columnsalign","columnlines","columnspan","denomalign","depth","dir","display","displaystyle","encoding","fence","frame","height","href","id","largeop","length","linethickness","lspace","lquote","mathbackground","mathcolor","mathsize","mathvariant","maxsize","minsize","movablelimits","notation","numalign","open","rowalign","rowlines","rowspacing","rowspan","rspace","rquote","scriptlevel","scriptminsize","scriptsizemultiplier","selection","separator","separators","stretchy","subscriptshift","supscriptshift","symmetric","voffset","width","xmlns"]),ue=S(["xlink:href","xml:id","xlink:title","xml:space","xmlns:xlink"]),tn=b(/\{\{[\w\W]*|[\w\W]*\}\}/gm),nn=b(/<%[\w\W]*|[\w\W]*%>/gm),on=b(/\$\{[\w\W]*/gm),an=b(/^data-[\-\w.\u00B7-\uFFFF]+$/),rn=b(/^aria-[\-\w]+$/),gt=b(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),sn=b(/^(?:\w+script|data):/i),ln=b(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),At=b(/^html$/i),cn=b(/^[a-z][.\w]*(-[.\w]+)+$/i),dt=Object.freeze({__proto__:null,ARIA_ATTR:rn,ATTR_WHITESPACE:ln,CUSTOM_ELEMENT:cn,DATA_ATTR:an,DOCTYPE_NAME:At,ERB_EXPR:nn,IS_ALLOWED_URI:gt,IS_SCRIPT_OR_DATA:sn,MUSTACHE_EXPR:tn,TMPLIT_EXPR:on}),Q={element:1,attribute:2,text:3,cdataSection:4,entityReference:5,entityNode:6,progressingInstruction:7,comment:8,document:9,documentType:10,documentFragment:11,notation:12},fn=function(){return typeof window>"u"?null:window},un=function(o,l){if(typeof o!="object"||typeof o.createPolicy!="function")return null;let a=null,c="data-tt-policy-suffix";l&&l.hasAttribute(c)&&(a=l.getAttribute(c));let D="dompurify"+(a?"#"+a:"");try{return o.createPolicy(D,{createHTML(v){return v},createScriptURL(v){return v}})}catch{return console.warn("TrustedTypes policy "+D+" could not be created."),null}},Et=function(){return{afterSanitizeAttributes:[],afterSanitizeElements:[],afterSanitizeShadowDOM:[],beforeSanitizeAttributes:[],beforeSanitizeElements:[],beforeSanitizeShadowDOM:[],uponSanitizeAttribute:[],uponSanitizeElement:[],uponSanitizeShadowNode:[]}};function ht(){let s=arguments.length>0&&arguments[0]!==void 0?arguments[0]:fn(),o=i=>ht(i);if(o.version="3.3.3",o.removed=[],!s||!s.document||s.document.nodeType!==Q.document||!s.Element)return o.isSupported=!1,o;let{document:l}=s,a=l,c=a.currentScript,{DocumentFragment:D,HTMLTemplateElement:v,Node:Te,Element:Fe,NodeFilter:B,NamedNodeMap:St=s.NamedNodeMap||s.MozNamedAttrMap,HTMLFormElement:Rt,DOMParser:Dt,trustedTypes:ee}=s,Y=Fe.prototype,Ot=J(Y,"cloneNode"),yt=J(Y,"remove"),bt=J(Y,"nextSibling"),Lt=J(Y,"childNodes"),te=J(Y,"parentNode");if(typeof v=="function"){let i=l.createElement("template");i.content&&i.content.ownerDocument&&(l=i.content.ownerDocument)}let g,X="",{implementation:de,createNodeIterator:Nt,createDocumentFragment:Ct,getElementsByTagName:It}=l,{importNode:Mt}=a,A=Et();o.isSupported=typeof _t=="function"&&typeof te=="function"&&de&&de.createHTMLDocument!==void 0;let{MUSTACHE_EXPR:Ee,ERB_EXPR:_e,TMPLIT_EXPR:ge,DATA_ATTR:wt,ARIA_ATTR:xt,IS_SCRIPT_OR_DATA:Pt,ATTR_WHITESPACE:He,CUSTOM_ELEMENT:kt}=dt,{IS_ALLOWED_URI:ze}=dt,T=null,Ge=r({},[...ut,...we,...xe,...Pe,...mt]),d=null,We=r({},[...pt,...ke,...Tt,...ue]),u=Object.seal(me(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),j=null,ne=null,x=Object.seal(me(null,{tagCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeCheck:{writable:!0,configurable:!1,enumerable:!0,value:null}})),Be=!0,Ae=!0,Ye=!1,Xe=!0,U=!1,oe=!0,P=!1,he=!1,Se=!1,F=!1,ie=!1,ae=!1,je=!0,Ve=!1,vt="user-content-",Re=!0,V=!1,H={},L=null,De=r({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]),$e=null,qe=r({},["audio","video","img","source","image","track"]),Oe=null,Ke=r({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),re="http://www.w3.org/1998/Math/MathML",se="http://www.w3.org/2000/svg",I="http://www.w3.org/1999/xhtml",z=I,ye=!1,be=null,Ut=r({},[re,se,I],Ie),le=r({},["mi","mo","mn","ms","mtext"]),ce=r({},["annotation-xml"]),Ft=r({},["title","style","font","a","script"]),$=null,Ht=["application/xhtml+xml","text/html"],zt="text/html",p=null,G=null,Gt=l.createElement("form"),Ze=function(e){return e instanceof RegExp||e instanceof Function},Le=function(){let e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};if(!(G&&G===e)){if((!e||typeof e!="object")&&(e={}),e=C(e),$=Ht.indexOf(e.PARSER_MEDIA_TYPE)===-1?zt:e.PARSER_MEDIA_TYPE,p=$==="application/xhtml+xml"?Ie:pe,T=y(e,"ALLOWED_TAGS")?r({},e.ALLOWED_TAGS,p):Ge,d=y(e,"ALLOWED_ATTR")?r({},e.ALLOWED_ATTR,p):We,be=y(e,"ALLOWED_NAMESPACES")?r({},e.ALLOWED_NAMESPACES,Ie):Ut,Oe=y(e,"ADD_URI_SAFE_ATTR")?r(C(Ke),e.ADD_URI_SAFE_ATTR,p):Ke,$e=y(e,"ADD_DATA_URI_TAGS")?r(C(qe),e.ADD_DATA_URI_TAGS,p):qe,L=y(e,"FORBID_CONTENTS")?r({},e.FORBID_CONTENTS,p):De,j=y(e,"FORBID_TAGS")?r({},e.FORBID_TAGS,p):C({}),ne=y(e,"FORBID_ATTR")?r({},e.FORBID_ATTR,p):C({}),H=y(e,"USE_PROFILES")?e.USE_PROFILES:!1,Be=e.ALLOW_ARIA_ATTR!==!1,Ae=e.ALLOW_DATA_ATTR!==!1,Ye=e.ALLOW_UNKNOWN_PROTOCOLS||!1,Xe=e.ALLOW_SELF_CLOSE_IN_ATTR!==!1,U=e.SAFE_FOR_TEMPLATES||!1,oe=e.SAFE_FOR_XML!==!1,P=e.WHOLE_DOCUMENT||!1,F=e.RETURN_DOM||!1,ie=e.RETURN_DOM_FRAGMENT||!1,ae=e.RETURN_TRUSTED_TYPE||!1,Se=e.FORCE_BODY||!1,je=e.SANITIZE_DOM!==!1,Ve=e.SANITIZE_NAMED_PROPS||!1,Re=e.KEEP_CONTENT!==!1,V=e.IN_PLACE||!1,ze=e.ALLOWED_URI_REGEXP||gt,z=e.NAMESPACE||I,le=e.MATHML_TEXT_INTEGRATION_POINTS||le,ce=e.HTML_INTEGRATION_POINTS||ce,u=e.CUSTOM_ELEMENT_HANDLING||{},e.CUSTOM_ELEMENT_HANDLING&&Ze(e.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(u.tagNameCheck=e.CUSTOM_ELEMENT_HANDLING.tagNameCheck),e.CUSTOM_ELEMENT_HANDLING&&Ze(e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(u.attributeNameCheck=e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),e.CUSTOM_ELEMENT_HANDLING&&typeof e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements=="boolean"&&(u.allowCustomizedBuiltInElements=e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),U&&(Ae=!1),ie&&(F=!0),H&&(T=r({},mt),d=me(null),H.html===!0&&(r(T,ut),r(d,pt)),H.svg===!0&&(r(T,we),r(d,ke),r(d,ue)),H.svgFilters===!0&&(r(T,xe),r(d,ke),r(d,ue)),H.mathMl===!0&&(r(T,Pe),r(d,Tt),r(d,ue))),y(e,"ADD_TAGS")||(x.tagCheck=null),y(e,"ADD_ATTR")||(x.attributeCheck=null),e.ADD_TAGS&&(typeof e.ADD_TAGS=="function"?x.tagCheck=e.ADD_TAGS:(T===Ge&&(T=C(T)),r(T,e.ADD_TAGS,p))),e.ADD_ATTR&&(typeof e.ADD_ATTR=="function"?x.attributeCheck=e.ADD_ATTR:(d===We&&(d=C(d)),r(d,e.ADD_ATTR,p))),e.ADD_URI_SAFE_ATTR&&r(Oe,e.ADD_URI_SAFE_ATTR,p),e.FORBID_CONTENTS&&(L===De&&(L=C(L)),r(L,e.FORBID_CONTENTS,p)),e.ADD_FORBID_CONTENTS&&(L===De&&(L=C(L)),r(L,e.ADD_FORBID_CONTENTS,p)),Re&&(T["#text"]=!0),P&&r(T,["html","head","body"]),T.table&&(r(T,["tbody"]),delete j.tbody),e.TRUSTED_TYPES_POLICY){if(typeof e.TRUSTED_TYPES_POLICY.createHTML!="function")throw Z('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');if(typeof e.TRUSTED_TYPES_POLICY.createScriptURL!="function")throw Z('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');g=e.TRUSTED_TYPES_POLICY,X=g.createHTML("")}else g===void 0&&(g=un(ee,c)),g!==null&&typeof X=="string"&&(X=g.createHTML(""));S&&S(e),G=e}},Je=r({},[...we,...xe,...Qt]),Qe=r({},[...Pe,...en]),Wt=function(e){let t=te(e);(!t||!t.tagName)&&(t={namespaceURI:z,tagName:"template"});let n=pe(e.tagName),f=pe(t.tagName);return be[e.namespaceURI]?e.namespaceURI===se?t.namespaceURI===I?n==="svg":t.namespaceURI===re?n==="svg"&&(f==="annotation-xml"||le[f]):!!Je[n]:e.namespaceURI===re?t.namespaceURI===I?n==="math":t.namespaceURI===se?n==="math"&&ce[f]:!!Qe[n]:e.namespaceURI===I?t.namespaceURI===se&&!ce[f]||t.namespaceURI===re&&!le[f]?!1:!Qe[n]&&(Ft[n]||!Je[n]):!!($==="application/xhtml+xml"&&be[e.namespaceURI]):!1},N=function(e){q(o.removed,{element:e});try{te(e).removeChild(e)}catch{yt(e)}},k=function(e,t){try{q(o.removed,{attribute:t.getAttributeNode(e),from:t})}catch{q(o.removed,{attribute:null,from:t})}if(t.removeAttribute(e),e==="is")if(F||ie)try{N(t)}catch{}else try{t.setAttribute(e,"")}catch{}},et=function(e){let t=null,n=null;if(Se)e="<remove></remove>"+e;else{let m=Me(e,/^[\r\n\t ]+/);n=m&&m[0]}$==="application/xhtml+xml"&&z===I&&(e='<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>'+e+"</body></html>");let f=g?g.createHTML(e):e;if(z===I)try{t=new Dt().parseFromString(f,$)}catch{}if(!t||!t.documentElement){t=de.createDocument(z,"template",null);try{t.documentElement.innerHTML=ye?X:f}catch{}}let _=t.body||t.documentElement;return e&&n&&_.insertBefore(l.createTextNode(n),_.childNodes[0]||null),z===I?It.call(t,P?"html":"body")[0]:P?t.documentElement:_},tt=function(e){return Nt.call(e.ownerDocument||e,e,B.SHOW_ELEMENT|B.SHOW_COMMENT|B.SHOW_TEXT|B.SHOW_PROCESSING_INSTRUCTION|B.SHOW_CDATA_SECTION,null)},Ne=function(e){return e instanceof Rt&&(typeof e.nodeName!="string"||typeof e.textContent!="string"||typeof e.removeChild!="function"||!(e.attributes instanceof St)||typeof e.removeAttribute!="function"||typeof e.setAttribute!="function"||typeof e.namespaceURI!="string"||typeof e.insertBefore!="function"||typeof e.hasChildNodes!="function")},nt=function(e){return typeof Te=="function"&&e instanceof Te};function M(i,e,t){fe(i,n=>{n.call(o,e,t,G)})}let ot=function(e){let t=null;if(M(A.beforeSanitizeElements,e,null),Ne(e))return N(e),!0;let n=p(e.nodeName);if(M(A.uponSanitizeElement,e,{tagName:n,allowedTags:T}),oe&&e.hasChildNodes()&&!nt(e.firstElementChild)&&h(/<[/\w!]/g,e.innerHTML)&&h(/<[/\w!]/g,e.textContent)||e.nodeType===Q.progressingInstruction||oe&&e.nodeType===Q.comment&&h(/<[/\w]/g,e.data))return N(e),!0;if(!(x.tagCheck instanceof Function&&x.tagCheck(n))&&(!T[n]||j[n])){if(!j[n]&&at(n)&&(u.tagNameCheck instanceof RegExp&&h(u.tagNameCheck,n)||u.tagNameCheck instanceof Function&&u.tagNameCheck(n)))return!1;if(Re&&!L[n]){let f=te(e)||e.parentNode,_=Lt(e)||e.childNodes;if(_&&f){let m=_.length;for(let O=m-1;O>=0;--O){let w=Ot(_[O],!0);w.__removalCount=(e.__removalCount||0)+1,f.insertBefore(w,bt(e))}}}return N(e),!0}return e instanceof Fe&&!Wt(e)||(n==="noscript"||n==="noembed"||n==="noframes")&&h(/<\/no(script|embed|frames)/i,e.innerHTML)?(N(e),!0):(U&&e.nodeType===Q.text&&(t=e.textContent,fe([Ee,_e,ge],f=>{t=K(t,f," ")}),e.textContent!==t&&(q(o.removed,{element:e.cloneNode()}),e.textContent=t)),M(A.afterSanitizeElements,e,null),!1)},it=function(e,t,n){if(ne[t]||je&&(t==="id"||t==="name")&&(n in l||n in Gt))return!1;if(!(Ae&&!ne[t]&&h(wt,t))){if(!(Be&&h(xt,t))){if(!(x.attributeCheck instanceof Function&&x.attributeCheck(t,e))){if(!d[t]||ne[t]){if(!(at(e)&&(u.tagNameCheck instanceof RegExp&&h(u.tagNameCheck,e)||u.tagNameCheck instanceof Function&&u.tagNameCheck(e))&&(u.attributeNameCheck instanceof RegExp&&h(u.attributeNameCheck,t)||u.attributeNameCheck instanceof Function&&u.attributeNameCheck(t,e))||t==="is"&&u.allowCustomizedBuiltInElements&&(u.tagNameCheck instanceof RegExp&&h(u.tagNameCheck,n)||u.tagNameCheck instanceof Function&&u.tagNameCheck(n))))return!1}else if(!Oe[t]){if(!h(ze,K(n,He,""))){if(!((t==="src"||t==="xlink:href"||t==="href")&&e!=="script"&&qt(n,"data:")===0&&$e[e])){if(!(Ye&&!h(Pt,K(n,He,"")))){if(n)return!1}}}}}}}return!0},at=function(e){return e!=="annotation-xml"&&Me(e,kt)},rt=function(e){M(A.beforeSanitizeAttributes,e,null);let{attributes:t}=e;if(!t||Ne(e))return;let n={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:d,forceKeepAttr:void 0},f=t.length;for(;f--;){let _=t[f],{name:m,namespaceURI:O,value:w}=_,W=p(m),Ce=w,E=m==="value"?Ce:Kt(Ce);if(n.attrName=W,n.attrValue=E,n.keepAttr=!0,n.forceKeepAttr=void 0,M(A.uponSanitizeAttribute,e,n),E=n.attrValue,Ve&&(W==="id"||W==="name")&&(k(m,e),E=vt+E),oe&&h(/((--!?|])>)|<\/(style|script|title|xmp|textarea|noscript|iframe|noembed|noframes)/i,E)){k(m,e);continue}if(W==="attributename"&&Me(E,"href")){k(m,e);continue}if(n.forceKeepAttr)continue;if(!n.keepAttr){k(m,e);continue}if(!Xe&&h(/\/>/i,E)){k(m,e);continue}U&&fe([Ee,_e,ge],lt=>{E=K(E,lt," ")});let st=p(e.nodeName);if(!it(st,W,E)){k(m,e);continue}if(g&&typeof ee=="object"&&typeof ee.getAttributeType=="function"&&!O)switch(ee.getAttributeType(st,W)){case"TrustedHTML":{E=g.createHTML(E);break}case"TrustedScriptURL":{E=g.createScriptURL(E);break}}if(E!==Ce)try{O?e.setAttributeNS(O,m,E):e.setAttribute(m,E),Ne(e)?N(e):ft(o.removed)}catch{k(m,e)}}M(A.afterSanitizeAttributes,e,null)},Bt=function i(e){let t=null,n=tt(e);for(M(A.beforeSanitizeShadowDOM,e,null);t=n.nextNode();)M(A.uponSanitizeShadowNode,t,null),ot(t),rt(t),t.content instanceof D&&i(t.content);M(A.afterSanitizeShadowDOM,e,null)};return o.sanitize=function(i){let e=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},t=null,n=null,f=null,_=null;if(ye=!i,ye&&(i="<!-->"),typeof i!="string"&&!nt(i))if(typeof i.toString=="function"){if(i=i.toString(),typeof i!="string")throw Z("dirty is not a string, aborting")}else throw Z("toString is not a function");if(!o.isSupported)return i;if(he||Le(e),o.removed=[],typeof i=="string"&&(V=!1),V){if(i.nodeName){let w=p(i.nodeName);if(!T[w]||j[w])throw Z("root node is forbidden and cannot be sanitized in-place")}}else if(i instanceof Te)t=et("<!---->"),n=t.ownerDocument.importNode(i,!0),n.nodeType===Q.element&&n.nodeName==="BODY"||n.nodeName==="HTML"?t=n:t.appendChild(n);else{if(!F&&!U&&!P&&i.indexOf("<")===-1)return g&&ae?g.createHTML(i):i;if(t=et(i),!t)return F?null:ae?X:""}t&&Se&&N(t.firstChild);let m=tt(V?i:t);for(;f=m.nextNode();)ot(f),rt(f),f.content instanceof D&&Bt(f.content);if(V)return i;if(F){if(ie)for(_=Ct.call(t.ownerDocument);t.firstChild;)_.appendChild(t.firstChild);else _=t;return(d.shadowroot||d.shadowrootmode)&&(_=Mt.call(a,_,!0)),_}let O=P?t.outerHTML:t.innerHTML;return P&&T["!doctype"]&&t.ownerDocument&&t.ownerDocument.doctype&&t.ownerDocument.doctype.name&&h(At,t.ownerDocument.doctype.name)&&(O="<!DOCTYPE "+t.ownerDocument.doctype.name+`>
2
+ `+O),U&&fe([Ee,_e,ge],w=>{O=K(O,w," ")}),g&&ae?g.createHTML(O):O},o.setConfig=function(){let i=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};Le(i),he=!0},o.clearConfig=function(){G=null,he=!1},o.isValidAttribute=function(i,e,t){G||Le({});let n=p(i),f=p(e);return it(n,f,t)},o.addHook=function(i,e){typeof e=="function"&&q(A[i],e)},o.removeHook=function(i,e){if(e!==void 0){let t=Vt(A[i],e);return t===-1?void 0:$t(A[i],t,1)[0]}return ft(A[i])},o.removeHooks=function(i){A[i]=[]},o.removeAllHooks=function(){A=Et()},o}var mn=ht();export{mn as default};
3
+ /*! Bundled license information:
4
+
5
+ dompurify/dist/purify.es.mjs:
6
+ (*! @license DOMPurify 3.3.3 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.3.3/LICENSE *)
7
+ */
8
+ //# sourceMappingURL=OP3JQ447.js.map