react-inlinesvg 1.1.7 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-inlinesvg",
3
- "version": "1.1.7",
3
+ "version": "2.1.0",
4
4
  "description": "An SVG loader for React",
5
5
  "author": "Gil Barbara <gilbarbara@gmail.com>",
6
6
  "contributors": [
@@ -18,83 +18,85 @@
18
18
  },
19
19
  "homepage": "https://github.com/gilbarbara/react-inlinesvg#readme",
20
20
  "main": "lib/index.js",
21
+ "module": "esm/index.js",
21
22
  "files": [
23
+ "esm",
22
24
  "lib",
23
25
  "src"
24
26
  ],
25
27
  "types": "lib/index.d.ts",
28
+ "sideEffects": true,
26
29
  "license": "MIT",
27
30
  "keywords": [
28
31
  "react",
29
32
  "svg"
30
33
  ],
31
34
  "peerDependencies": {
32
- "react": "^16.3.0",
33
- "react-dom": "^16.3.0"
35
+ "react": "^16.8.0"
34
36
  },
35
37
  "dependencies": {
36
38
  "exenv": "^1.2.2",
37
- "react-from-dom": "^0.2.3"
39
+ "react-from-dom": "^0.4.2"
38
40
  },
39
41
  "devDependencies": {
40
42
  "@gilbarbara/tsconfig": "^0.1.0",
41
- "@size-limit/preset-small-lib": "^2.1.6",
42
- "@types/enzyme": "^3.10.3",
43
- "@types/enzyme-adapter-react-16": "^1.0.5",
43
+ "@size-limit/preset-small-lib": "^4.5.7",
44
+ "@types/enzyme": "^3.10.5",
45
+ "@types/enzyme-adapter-react-16": "^1.0.6",
44
46
  "@types/exenv": "^1.2.0",
45
- "@types/fetch-mock": "^7.3.1",
46
- "@types/jest": "^24.0.18",
47
- "@types/node": "^12.7.7",
48
- "@types/node-fetch": "^2.5.2",
49
- "@types/react": "^16.9.3",
50
- "@types/react-dom": "^16.9.1",
51
- "cross-env": "^6.0.0",
52
- "enzyme": "^3.10.0",
53
- "enzyme-adapter-react-16": "^1.14.0",
54
- "fetch-mock": "^7.3.9",
55
- "http-server": "^0.11.1",
56
- "husky": "^3.0.5",
57
- "jest": "^24.9.0",
58
- "jest-chain": "^1.1.2",
59
- "jest-enzyme": "^7.1.1",
60
- "jest-extended": "^0.11.2",
61
- "jest-watch-typeahead": "^0.4.0",
62
- "node-fetch": "^2.6.0",
63
- "prettier": "^1.18.2",
64
- "react": "^16.9.0",
65
- "react-dom": "^16.9.0",
47
+ "@types/fetch-mock": "^7.3.3",
48
+ "@types/jest": "^26.0.13",
49
+ "@types/node": "^14.6.4",
50
+ "@types/node-fetch": "^2.5.7",
51
+ "@types/react": "^16.9.49",
52
+ "@types/react-dom": "^16.9.8",
53
+ "@typescript-eslint/eslint-plugin": "^4.0.1",
54
+ "@typescript-eslint/parser": "^4.0.1",
55
+ "del-cli": "^3.0.1",
56
+ "enzyme": "^3.11.0",
57
+ "enzyme-adapter-react-16": "^1.15.4",
58
+ "eslint": "^7.8.1",
59
+ "eslint-config-airbnb": "^18.2.0",
60
+ "eslint-config-prettier": "^6.11.0",
61
+ "eslint-plugin-import": "^2.22.0",
62
+ "eslint-plugin-jsx-a11y": "^6.3.1",
63
+ "eslint-plugin-prettier": "^3.1.4",
64
+ "eslint-plugin-react": "^7.20.6",
65
+ "http-server": "^0.12.3",
66
+ "husky": "^4.2.5",
67
+ "jest": "^26.4.2",
68
+ "jest-chain": "^1.1.5",
69
+ "jest-enzyme": "^7.1.2",
70
+ "jest-extended": "^0.11.5",
71
+ "jest-fetch-mock": "^3.0.3",
72
+ "jest-watch-typeahead": "^0.6.1",
73
+ "node-fetch": "^2.6.1",
74
+ "prettier": "^2.1.1",
75
+ "react": "^16.13.1",
76
+ "react-dom": "^16.13.1",
66
77
  "repo-tools": "^0.2.0",
67
- "rimraf": "^3.0.0",
68
- "size-limit": "^2.1.6",
69
- "start-server-and-test": "^1.10.0",
70
- "styled-components": "^4.4.0",
71
- "ts-jest": "^24.1.0",
72
- "ts-node": "^8.4.1",
73
- "tslint": "^5.20.0",
74
- "tslint-config-prettier": "^1.18.0",
75
- "tslint-react": "^4.1.0",
76
- "typescript": "^3.6.3"
78
+ "size-limit": "^4.5.7",
79
+ "start-server-and-test": "^1.11.3",
80
+ "ts-jest": "^26.3.0",
81
+ "typescript": "^4.0.2"
77
82
  },
78
83
  "scripts": {
79
- "build": "npm run clean && npm run build:ts",
80
- "build:ts": "tsc",
81
- "watch": "npm run build:ts -- -w",
82
- "clean": "rimraf lib",
83
- "start": "http-server -p 1337 --cors test/__fixtures__",
84
+ "build": "npm run clean && npm run build:cjs && npm run build:esm",
85
+ "build:cjs": "tsc",
86
+ "build:esm": "tsc -m es6 --outDir esm",
87
+ "clean": "del lib/* && del esm/*",
88
+ "watch:cjs": "npm run build:cjs -- -w",
89
+ "watch:esm": "npm run build:esm -- -w",
90
+ "start": "http-server test/__fixtures__ -p 1337 --cors",
84
91
  "test": "start-server-and-test start http://localhost:1337 test:coverage",
85
92
  "test:coverage": "jest --coverage --bail",
86
93
  "test:watch": "jest --watch --verbose",
87
- "lint": "tslint 'src/**/*.ts?(x)' 'test/**/*.ts?(x)' 'tools/**/*.ts?(x)'",
94
+ "lint": "eslint --ext .ts,.tsx src test",
88
95
  "format": "prettier \"**/*.{js,jsx,json,yml,yaml,css,less,scss,ts,tsx,md,graphql,mdx}\" --write",
89
- "validate": "npm run lint && npm run test && npm run size",
90
- "size": "npm run build && size-limit",
96
+ "validate": "npm run lint && npm run test && npm run build && npm run size",
97
+ "size": "size-limit",
91
98
  "prepublishOnly": "npm run validate"
92
99
  },
93
- "browserslist": [
94
- "> 0.2%",
95
- "safari >= 9",
96
- "ios >= 9"
97
- ],
98
100
  "prettier": {
99
101
  "jsxBracketSameLine": false,
100
102
  "printWidth": 100,
@@ -104,12 +106,16 @@
104
106
  "size-limit": [
105
107
  {
106
108
  "path": "./lib/index.js",
107
- "limit": "8 KB"
109
+ "limit": "8 kB"
110
+ },
111
+ {
112
+ "path": "./esm/index.js",
113
+ "limit": "8 kB"
108
114
  }
109
115
  ],
110
116
  "husky": {
111
117
  "hooks": {
112
- "post-merge": "repo-tools istall-packages",
118
+ "post-merge": "repo-tools install-packages",
113
119
  "pre-commit": "repo-tools check-remote && npm run validate"
114
120
  }
115
121
  }
package/src/helpers.ts CHANGED
@@ -1,8 +1,19 @@
1
1
  import { canUseDOM as canUseDOMFlag } from 'exenv';
2
2
 
3
- export const canUseDOM = () => canUseDOMFlag;
3
+ export const STATUS = {
4
+ FAILED: 'failed',
5
+ LOADED: 'loaded',
6
+ LOADING: 'loading',
7
+ PENDING: 'pending',
8
+ READY: 'ready',
9
+ UNSUPPORTED: 'unsupported',
10
+ };
11
+
12
+ export function canUseDOM(): boolean {
13
+ return canUseDOMFlag;
14
+ }
4
15
 
5
- export const supportsInlineSVG = () => {
16
+ export function supportsInlineSVG(): boolean {
6
17
  /* istanbul ignore next */
7
18
  if (!document) {
8
19
  return false;
@@ -10,30 +21,14 @@ export const supportsInlineSVG = () => {
10
21
 
11
22
  const div = document.createElement('div');
12
23
  div.innerHTML = '<svg />';
13
- return div.firstChild && div.firstChild.namespaceURI === 'http://www.w3.org/2000/svg';
14
- };
15
-
16
- // tslint:disable-next-line:no-shadowed-variable
17
- export class InlineSVGError extends Error {
18
- public name: string;
19
- public message: string;
20
- public data?: object;
21
-
22
- constructor(message: string, data?: object) {
23
- super();
24
-
25
- this.name = 'InlineSVGError';
26
- this.message = message;
27
- this.data = data;
28
-
29
- return this;
30
- }
24
+ return !!div.firstChild && div.firstChild.namespaceURI === 'http://www.w3.org/2000/svg';
31
25
  }
32
26
 
33
- export const isSupportedEnvironment = () =>
34
- supportsInlineSVG() && typeof window !== 'undefined' && window !== null;
27
+ export function isSupportedEnvironment(): boolean {
28
+ return supportsInlineSVG() && typeof window !== 'undefined' && window !== null;
29
+ }
35
30
 
36
- export const randomString = (length: number) => {
31
+ export function randomString(length: number): string {
37
32
  const letters = 'abcdefghijklmnopqrstuvwxyz';
38
33
  const numbers = '1234567890';
39
34
  const charset = `${letters}${letters.toUpperCase()}${numbers}`;
@@ -45,5 +40,6 @@ export const randomString = (length: number) => {
45
40
  for (let i = 0; i < length; i++) {
46
41
  R += randomCharacter(charset);
47
42
  }
43
+
48
44
  return R;
49
- };
45
+ }
package/src/index.tsx CHANGED
@@ -2,67 +2,13 @@ import * as React from 'react';
2
2
 
3
3
  import convert from 'react-from-dom';
4
4
 
5
- import { canUseDOM, InlineSVGError, isSupportedEnvironment, randomString } from './helpers';
6
-
7
- export interface IProps {
8
- baseURL?: string;
9
- cacheRequests?: boolean;
10
- children?: React.ReactNode;
11
- description?: string;
12
- loader?: React.ReactNode;
13
- innerRef?: React.Ref<HTMLElement>;
14
- onError?: (error: InlineSVGError | IFetchError) => void;
15
- onLoad?: (src: string, isCached: boolean) => void;
16
- preProcessor?: (code: string) => string;
17
- src: string;
18
- title?: string;
19
- uniqueHash?: string;
20
- uniquifyIDs?: boolean;
21
- [key: string]: any;
22
- }
23
-
24
- export interface IState {
25
- content: string;
26
- element: React.ReactNode;
27
- hasCache: boolean;
28
- status: string;
29
- }
30
-
31
- export interface IFetchError extends Error {
32
- code: string;
33
- errno: string;
34
- message: string;
35
- type: string;
36
- }
37
-
38
- export interface IStorageItem {
39
- content: string;
40
- queue: any[];
41
- status: string;
42
- }
43
-
44
- export const STATUS = {
45
- FAILED: 'failed',
46
- LOADED: 'loaded',
47
- LOADING: 'loading',
48
- PENDING: 'pending',
49
- READY: 'ready',
50
- UNSUPPORTED: 'unsupported',
51
- };
52
-
53
- const cacheStore: { [key: string]: IStorageItem } = Object.create(null);
54
-
55
- export default class InlineSVG extends React.PureComponent<IProps, IState> {
56
- public static defaultProps = {
57
- cacheRequests: true,
58
- uniquifyIDs: false,
59
- };
5
+ import { STATUS, canUseDOM, isSupportedEnvironment, randomString } from './helpers';
6
+ import { FetchError, Props, State, StorageItem } from './types';
60
7
 
61
- // tslint:disable-next-line:variable-name
62
- private _isMounted = false;
63
- private readonly hash: string;
8
+ const cacheStore: { [key: string]: StorageItem } = Object.create(null);
64
9
 
65
- constructor(props: IProps) {
10
+ export default class InlineSVG extends React.PureComponent<Props, State> {
11
+ constructor(props: Props) {
66
12
  super(props);
67
13
 
68
14
  this.state = {
@@ -75,11 +21,18 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
75
21
  this.hash = props.uniqueHash || randomString(8);
76
22
  }
77
23
 
78
- public componentDidMount() {
79
- this._isMounted = true;
24
+ private isActive = false;
25
+ private readonly hash: string;
26
+
27
+ public static defaultProps = {
28
+ cacheRequests: true,
29
+ uniquifyIDs: false,
30
+ };
31
+
32
+ public componentDidMount(): void {
33
+ this.isActive = true;
80
34
 
81
35
  if (!canUseDOM()) {
82
- this.handleError(new InlineSVGError('No DOM'));
83
36
  return;
84
37
  }
85
38
 
@@ -91,12 +44,12 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
91
44
  if (status === STATUS.PENDING) {
92
45
  /* istanbul ignore else */
93
46
  if (!isSupportedEnvironment()) {
94
- throw new InlineSVGError('Browser does not support SVG');
47
+ throw new Error('Browser does not support SVG');
95
48
  }
96
49
 
97
50
  /* istanbul ignore else */
98
51
  if (!src) {
99
- throw new InlineSVGError('Missing src');
52
+ throw new Error('Missing src');
100
53
  }
101
54
 
102
55
  this.load();
@@ -106,7 +59,7 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
106
59
  }
107
60
  }
108
61
 
109
- public componentDidUpdate(prevProps: IProps, prevState: IState) {
62
+ public componentDidUpdate(prevProps: Props, prevState: State): void {
110
63
  if (!canUseDOM()) {
111
64
  return;
112
65
  }
@@ -123,7 +76,7 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
123
76
 
124
77
  if (prevProps.src !== src) {
125
78
  if (!src) {
126
- this.handleError(new InlineSVGError('Missing src'));
79
+ this.handleError(new Error('Missing src'));
127
80
  return;
128
81
  }
129
82
 
@@ -131,8 +84,8 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
131
84
  }
132
85
  }
133
86
 
134
- public componentWillUnmount() {
135
- this._isMounted = false;
87
+ public componentWillUnmount(): void {
88
+ this.isActive = false;
136
89
  }
137
90
 
138
91
  private processSVG() {
@@ -157,20 +110,21 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
157
110
  return node;
158
111
  }
159
112
 
160
- [...node.children].map(d => {
113
+ [...node.children].map((d) => {
161
114
  if (d.attributes && d.attributes.length) {
162
- const attributes = Object.values(d.attributes);
163
-
164
- attributes.forEach(a => {
165
- const match = a.value.match(/^url\((#[^)]+)/);
115
+ const attributes = Object.values(d.attributes).map((a) => {
116
+ const attr = a;
117
+ const match = a.value.match(/url\((.*?)\)/);
166
118
 
167
119
  if (match && match[1]) {
168
- a.value = `url(${baseURL}${match[1]}__${this.hash})`;
120
+ attr.value = a.value.replace(match[0], `url(${baseURL}${match[1]}__${this.hash})`);
169
121
  }
122
+
123
+ return attr;
170
124
  });
171
125
 
172
- replaceableAttributes.forEach(r => {
173
- const attribute = attributes.find(a => a.name === r);
126
+ replaceableAttributes.forEach((r) => {
127
+ const attribute = attributes.find((a) => a.name === r);
174
128
 
175
129
  if (attribute && !isDataValue(r, attribute.value)) {
176
130
  attribute.value = `${attribute.value}__${this.hash}`;
@@ -179,7 +133,7 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
179
133
  }
180
134
 
181
135
  if (d.children.length) {
182
- d = this.updateSVGAttributes(d as SVGSVGElement);
136
+ return this.updateSVGAttributes(d as SVGSVGElement);
183
137
  }
184
138
 
185
139
  return d;
@@ -196,7 +150,7 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
196
150
  const node = convert(svgText, { nodeOnly: true });
197
151
 
198
152
  if (!node || !(node instanceof SVGSVGElement)) {
199
- throw new InlineSVGError('Could not convert the src to a DOM Node');
153
+ throw new Error('Could not convert the src to a DOM Node');
200
154
  }
201
155
 
202
156
  const svg = this.updateSVGAttributes(node);
@@ -227,7 +181,7 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
227
181
 
228
182
  return svg;
229
183
  } catch (error) {
230
- this.handleError(error);
184
+ return this.handleError(error);
231
185
  }
232
186
  }
233
187
 
@@ -237,7 +191,7 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
237
191
  const element = convert(node);
238
192
 
239
193
  if (!element || !React.isValidElement(element)) {
240
- throw new InlineSVGError('Could not convert the src to a React element');
194
+ throw new Error('Could not convert the src to a React element');
241
195
  }
242
196
 
243
197
  this.setState({
@@ -245,13 +199,13 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
245
199
  status: STATUS.READY,
246
200
  });
247
201
  } catch (error) {
248
- this.handleError(new InlineSVGError(error.message));
202
+ this.handleError(new Error(error.message));
249
203
  }
250
204
  }
251
205
 
252
206
  private load() {
253
207
  /* istanbul ignore else */
254
- if (this._isMounted) {
208
+ if (this.isActive) {
255
209
  this.setState(
256
210
  {
257
211
  content: '',
@@ -265,7 +219,7 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
265
219
  if (cache) {
266
220
  /* istanbul ignore else */
267
221
  if (cache.status === STATUS.LOADING) {
268
- cache.queue.push(this.handleLoad);
222
+ cache.queue.push(this.handleCacheQueue);
269
223
  } else if (cache.status === STATUS.LOADED) {
270
224
  this.handleLoad(cache.content);
271
225
  }
@@ -292,9 +246,19 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
292
246
  }
293
247
  }
294
248
 
249
+ private handleCacheQueue = (content: string | Error) => {
250
+ /* istanbul ignore else */
251
+ if (typeof content === 'string') {
252
+ this.handleLoad(content);
253
+ return;
254
+ }
255
+
256
+ this.handleError(content);
257
+ };
258
+
295
259
  private handleLoad = (content: string) => {
296
260
  /* istanbul ignore else */
297
- if (this._isMounted) {
261
+ if (this.isActive) {
298
262
  this.setState(
299
263
  {
300
264
  content,
@@ -305,19 +269,13 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
305
269
  }
306
270
  };
307
271
 
308
- private handleError = (error: InlineSVGError | IFetchError) => {
272
+ private handleError = (error: Error | FetchError) => {
309
273
  const { onError } = this.props;
310
274
  const status =
311
275
  error.message === 'Browser does not support SVG' ? STATUS.UNSUPPORTED : STATUS.FAILED;
312
276
 
313
277
  /* istanbul ignore else */
314
- if (process.env.NODE_ENV !== 'production') {
315
- // tslint:disable-next-line:no-console
316
- console.error(error);
317
- }
318
-
319
- /* istanbul ignore else */
320
- if (this._isMounted) {
278
+ if (this.isActive) {
321
279
  this.setState({ status }, () => {
322
280
  /* istanbul ignore else */
323
281
  if (typeof onError === 'function') {
@@ -336,21 +294,21 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
336
294
  }
337
295
 
338
296
  return fetch(src)
339
- .then(response => {
297
+ .then((response) => {
340
298
  const contentType = response.headers.get('content-type');
341
299
  const [fileType] = (contentType || '').split(/ ?; ?/);
342
300
 
343
301
  if (response.status > 299) {
344
- throw new InlineSVGError('Not Found');
302
+ throw new Error('Not found');
345
303
  }
346
304
 
347
- if (!['image/svg+xml', 'text/plain'].some(d => fileType.indexOf(d) >= 0)) {
348
- throw new InlineSVGError(`Content type isn't valid: ${fileType}`);
305
+ if (!['image/svg+xml', 'text/plain'].some((d) => fileType.indexOf(d) >= 0)) {
306
+ throw new Error(`Content type isn't valid: ${fileType}`);
349
307
  }
350
308
 
351
309
  return response.text();
352
310
  })
353
- .then(content => {
311
+ .then((content) => {
354
312
  this.handleLoad(content);
355
313
 
356
314
  /* istanbul ignore else */
@@ -362,7 +320,7 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
362
320
  cache.content = content;
363
321
  cache.status = STATUS.LOADED;
364
322
 
365
- cache.queue = cache.queue.filter((cb: (content: string) => void) => {
323
+ cache.queue = cache.queue.filter((cb) => {
366
324
  cb(content);
367
325
 
368
326
  return false;
@@ -370,23 +328,29 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
370
328
  }
371
329
  }
372
330
  })
373
- .catch(error => {
331
+ .catch((error) => {
332
+ this.handleError(error);
333
+
374
334
  /* istanbul ignore else */
375
335
  if (cacheRequests) {
376
- delete cacheStore[src];
336
+ const cache = cacheStore[src];
337
+
338
+ /* istanbul ignore else */
339
+ if (cache) {
340
+ cache.queue.forEach((cb: (content: string) => void) => {
341
+ cb(error);
342
+ });
343
+
344
+ delete cacheStore[src];
345
+ }
377
346
  }
378
- this.handleError(error);
379
347
  });
380
348
  } catch (error) {
381
- this.handleError(new InlineSVGError(error.message));
349
+ return this.handleError(new Error(error.message));
382
350
  }
383
351
  };
384
352
 
385
- public render() {
386
- if (!canUseDOM()) {
387
- return null;
388
- }
389
-
353
+ public render(): React.ReactNode {
390
354
  const { element, status } = this.state;
391
355
  const {
392
356
  baseURL,
@@ -405,6 +369,10 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
405
369
  ...rest
406
370
  } = this.props;
407
371
 
372
+ if (!canUseDOM()) {
373
+ return loader;
374
+ }
375
+
408
376
  if (element) {
409
377
  return React.cloneElement(element as React.ReactElement, { ref: innerRef, ...rest });
410
378
  }
@@ -416,3 +384,5 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
416
384
  return loader;
417
385
  }
418
386
  }
387
+
388
+ export * from './types';
package/src/types.ts ADDED
@@ -0,0 +1,43 @@
1
+ import * as React from 'react';
2
+
3
+ type Callback = (...args: any[]) => void;
4
+
5
+ export type ErrorCallback = (error: Error | FetchError) => void;
6
+ export type LoadCallback = (src: string, isCached: boolean) => void;
7
+ export type PreProcessorCallback = (code: string) => string;
8
+
9
+ export interface Props extends Omit<React.HTMLProps<SVGElement>, 'onLoad' | 'onError'> {
10
+ baseURL?: string;
11
+ cacheRequests?: boolean;
12
+ children?: React.ReactNode;
13
+ description?: string;
14
+ innerRef?: React.Ref<HTMLElement>;
15
+ loader?: React.ReactNode;
16
+ onError?: ErrorCallback;
17
+ onLoad?: LoadCallback;
18
+ preProcessor?: PreProcessorCallback;
19
+ src: string;
20
+ title?: string;
21
+ uniqueHash?: string;
22
+ uniquifyIDs?: boolean;
23
+ }
24
+
25
+ export interface State {
26
+ content: string;
27
+ element: React.ReactNode;
28
+ hasCache: boolean;
29
+ status: string;
30
+ }
31
+
32
+ export interface FetchError extends Error {
33
+ code: string;
34
+ errno: string;
35
+ message: string;
36
+ type: string;
37
+ }
38
+
39
+ export interface StorageItem {
40
+ content: string;
41
+ queue: Callback[];
42
+ status: string;
43
+ }