@gjsify/fetch 0.0.2

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.
Files changed (58) hide show
  1. package/README.md +9 -0
  2. package/lib/cjs/body.js +284 -0
  3. package/lib/cjs/errors/abort-error.js +28 -0
  4. package/lib/cjs/errors/base.js +36 -0
  5. package/lib/cjs/errors/fetch-error.js +40 -0
  6. package/lib/cjs/headers.js +231 -0
  7. package/lib/cjs/index.js +246 -0
  8. package/lib/cjs/request.js +306 -0
  9. package/lib/cjs/response.js +162 -0
  10. package/lib/cjs/types/index.js +17 -0
  11. package/lib/cjs/types/system-error.js +16 -0
  12. package/lib/cjs/utils/blob-from.js +124 -0
  13. package/lib/cjs/utils/get-search.js +30 -0
  14. package/lib/cjs/utils/is-redirect.js +26 -0
  15. package/lib/cjs/utils/is.js +47 -0
  16. package/lib/cjs/utils/multipart-parser.js +372 -0
  17. package/lib/cjs/utils/referrer.js +172 -0
  18. package/lib/esm/body.js +255 -0
  19. package/lib/esm/errors/abort-error.js +9 -0
  20. package/lib/esm/errors/base.js +17 -0
  21. package/lib/esm/errors/fetch-error.js +21 -0
  22. package/lib/esm/headers.js +202 -0
  23. package/lib/esm/index.js +224 -0
  24. package/lib/esm/request.js +281 -0
  25. package/lib/esm/response.js +133 -0
  26. package/lib/esm/types/index.js +1 -0
  27. package/lib/esm/types/system-error.js +1 -0
  28. package/lib/esm/utils/blob-from.js +101 -0
  29. package/lib/esm/utils/get-search.js +11 -0
  30. package/lib/esm/utils/is-redirect.js +7 -0
  31. package/lib/esm/utils/is.js +28 -0
  32. package/lib/esm/utils/multipart-parser.js +353 -0
  33. package/lib/esm/utils/referrer.js +153 -0
  34. package/package.json +53 -0
  35. package/src/body.ts +415 -0
  36. package/src/errors/abort-error.ts +10 -0
  37. package/src/errors/base.ts +20 -0
  38. package/src/errors/fetch-error.ts +26 -0
  39. package/src/headers.ts +279 -0
  40. package/src/index.spec.ts +13 -0
  41. package/src/index.ts +367 -0
  42. package/src/request.ts +396 -0
  43. package/src/response.ts +197 -0
  44. package/src/test.mts +6 -0
  45. package/src/types/index.ts +1 -0
  46. package/src/types/system-error.ts +11 -0
  47. package/src/utils/blob-from.ts +168 -0
  48. package/src/utils/get-search.ts +9 -0
  49. package/src/utils/is-redirect.ts +11 -0
  50. package/src/utils/is.ts +88 -0
  51. package/src/utils/multipart-parser.ts +448 -0
  52. package/src/utils/referrer.ts +350 -0
  53. package/test.gjs.js +34758 -0
  54. package/test.gjs.mjs +53177 -0
  55. package/test.node.js +1226 -0
  56. package/test.node.mjs +6294 -0
  57. package/tsconfig.json +19 -0
  58. package/tsconfig.types.json +8 -0
@@ -0,0 +1,168 @@
1
+ import { DOMException } from "@gjsify/deno-runtime/ext/web/01_dom_exception";
2
+ import { Blob, File } from "@gjsify/deno-runtime/ext/web/09_file";
3
+
4
+ import {
5
+ realpathSync,
6
+ statSync,
7
+ rmdirSync,
8
+ createReadStream,
9
+ promises as fs
10
+ } from 'node:fs'
11
+ import { basename, sep, join } from 'node:path'
12
+ import { tmpdir } from 'node:os'
13
+ import process from 'node:process'
14
+
15
+ // import Blob from './index.js'
16
+
17
+ const { stat, mkdtemp } = fs
18
+ let i = 0, tempDir, registry
19
+
20
+ /**
21
+ * @param {string} path filepath on the disk
22
+ * @param {string} [type] mimetype to use
23
+ */
24
+ const blobFromSync = (path: string, type: string) => fromBlob(statSync(path), path, type)
25
+
26
+ /**
27
+ * @param {string} path filepath on the disk
28
+ * @param {string} [type] mimetype to use
29
+ * @returns {Promise<Blob>}
30
+ */
31
+ const blobFrom = (path: string, type: string): Promise<Blob> => stat(path).then(stat => fromBlob(stat, path, type))
32
+
33
+ /**
34
+ * @param {string} path filepath on the disk
35
+ * @param {string} [type] mimetype to use
36
+ * @returns {Promise<File>}
37
+ */
38
+ const fileFrom = (path: string, type: string): Promise<File> => stat(path).then(stat => fromFile(stat, path, type))
39
+
40
+ /**
41
+ * @param {string} path filepath on the disk
42
+ * @param {string} [type] mimetype to use
43
+ */
44
+ const fileFromSync = (path: string, type: string) => fromFile(statSync(path), path, type)
45
+
46
+ // @ts-ignore
47
+ const fromBlob = (stat, path, type = '') => new Blob([new BlobDataItem({
48
+ path,
49
+ size: stat.size,
50
+ lastModified: stat.mtimeMs,
51
+ start: 0
52
+ })], { type })
53
+
54
+ // @ts-ignore
55
+ const fromFile = (stat, path, type = '') => new File([new BlobDataItem({
56
+ path,
57
+ size: stat.size,
58
+ lastModified: stat.mtimeMs,
59
+ start: 0
60
+ })], basename(path), { type, lastModified: stat.mtimeMs })
61
+
62
+ /**
63
+ * Creates a temporary blob backed by the filesystem.
64
+ * NOTE: requires node.js v14 or higher to use FinalizationRegistry
65
+ *
66
+ * @param {*} data Same as fs.writeFile data
67
+ * @param {BlobPropertyBag & {signal?: AbortSignal}} options
68
+ * @param {AbortSignal} [signal] in case you wish to cancel the write operation
69
+ * @returns {Promise<Blob>}
70
+ */
71
+ const createTemporaryBlob = async (data: any, { signal, type }: BlobPropertyBag & { signal?: AbortSignal; } = {}): Promise<Blob> => {
72
+ registry = registry || new FinalizationRegistry(fs.unlink)
73
+ tempDir = tempDir || await mkdtemp(realpathSync(tmpdir()) + sep)
74
+ const id = `${i++}`
75
+ const destination = join(tempDir, id)
76
+ if (data instanceof ArrayBuffer) data = new Uint8Array(data)
77
+ await fs.writeFile(destination, data, { signal })
78
+ const blob = await blobFrom(destination, type)
79
+ registry.register(blob, destination)
80
+ return blob
81
+ }
82
+
83
+ /**
84
+ * Creates a temporary File backed by the filesystem.
85
+ * Pretty much the same as constructing a new File(data, name, options)
86
+ *
87
+ * NOTE: requires node.js v14 or higher to use FinalizationRegistry
88
+ * @param {*} data
89
+ * @param {string} name
90
+ * @param {FilePropertyBag & {signal?: AbortSignal}} opts
91
+ * @returns {Promise<File>}
92
+ */
93
+ const createTemporaryFile = async (data: any, name: string, opts: FilePropertyBag & { signal?: AbortSignal; }): Promise<File> => {
94
+ const blob = await createTemporaryBlob(data)
95
+ return new File([blob], name, opts)
96
+ }
97
+
98
+ /**
99
+ * This is a blob backed up by a file on the disk
100
+ * with minium requirement. Its wrapped around a Blob as a blobPart
101
+ * so you have no direct access to this.
102
+ *
103
+ * @private
104
+ */
105
+ class BlobDataItem {
106
+ #path: string;
107
+ #start: number;
108
+ size
109
+ lastModified
110
+ originalSize
111
+
112
+ constructor(options) {
113
+ this.#path = options.path
114
+ this.#start = options.start
115
+ this.size = options.size
116
+ this.lastModified = options.lastModified
117
+ this.originalSize = options.originalSize === undefined
118
+ ? options.size
119
+ : options.originalSize
120
+ }
121
+
122
+ /**
123
+ * Slicing arguments is first validated and formatted
124
+ * to not be out of range by Blob.prototype.slice
125
+ */
126
+ slice(start: number, end: number) {
127
+ return new BlobDataItem({
128
+ path: this.#path,
129
+ lastModified: this.lastModified,
130
+ originalSize: this.originalSize,
131
+ size: end - start,
132
+ start: this.#start + start
133
+ })
134
+ }
135
+
136
+ async * stream() {
137
+ const { mtimeMs, size } = await stat(this.#path)
138
+
139
+ if (mtimeMs > this.lastModified || this.originalSize !== size) {
140
+ throw new DOMException('The requested file could not be read, typically due to permission problems that have occurred after a reference to a file was acquired.', 'NotReadableError')
141
+ }
142
+
143
+ yield* createReadStream(this.#path, {
144
+ start: this.#start,
145
+ end: this.#start + this.size - 1
146
+ })
147
+ }
148
+
149
+ get [Symbol.toStringTag]() {
150
+ return 'Blob'
151
+ }
152
+ }
153
+
154
+ process.once('exit', () => {
155
+ tempDir && rmdirSync(tempDir, { recursive: true })
156
+ })
157
+
158
+ export default blobFromSync
159
+ export {
160
+ Blob,
161
+ blobFrom,
162
+ blobFromSync,
163
+ createTemporaryBlob,
164
+ File,
165
+ fileFrom,
166
+ fileFromSync,
167
+ createTemporaryFile
168
+ }
@@ -0,0 +1,9 @@
1
+ export const getSearch = (parsedURL: URL) => {
2
+ if (parsedURL.search) {
3
+ return parsedURL.search;
4
+ }
5
+
6
+ const lastOffset = parsedURL.href.length - 1;
7
+ const hash = parsedURL.hash || (parsedURL.href[lastOffset] === '#' ? '#' : '');
8
+ return parsedURL.href[lastOffset - hash.length] === '?' ? '?' : '';
9
+ };
@@ -0,0 +1,11 @@
1
+ const redirectStatus = new Set([301, 302, 303, 307, 308]);
2
+
3
+ /**
4
+ * Redirect code matching
5
+ *
6
+ * @param {number} code - Status code
7
+ * @return {boolean}
8
+ */
9
+ export const isRedirect = code => {
10
+ return redirectStatus.has(code);
11
+ };
@@ -0,0 +1,88 @@
1
+ import { URL } from '@gjsify/deno-runtime/ext/url/00_url';
2
+ import { Blob } from "@gjsify/deno-runtime/ext/web/09_file";
3
+
4
+ /**
5
+ * Is.js
6
+ *
7
+ * Object type checks.
8
+ */
9
+
10
+ const NAME = Symbol.toStringTag;
11
+
12
+ /**
13
+ * Check if `obj` is a URLSearchParams object
14
+ * ref: https://github.com/node-fetch/node-fetch/issues/296#issuecomment-307598143
15
+ * @param {*} object - Object to check for
16
+ * @return {boolean}
17
+ */
18
+ export const isURLSearchParameters = object => {
19
+ return (
20
+ typeof object === 'object' &&
21
+ typeof object.append === 'function' &&
22
+ typeof object.delete === 'function' &&
23
+ typeof object.get === 'function' &&
24
+ typeof object.getAll === 'function' &&
25
+ typeof object.has === 'function' &&
26
+ typeof object.set === 'function' &&
27
+ typeof object.sort === 'function' &&
28
+ object[NAME] === 'URLSearchParams'
29
+ );
30
+ };
31
+
32
+ /**
33
+ * Check if `object` is a W3C `Blob` object (which `File` inherits from)
34
+ * @param object Object to check for
35
+ */
36
+ export const isBlob = (value: any): value is Blob => {
37
+ return (
38
+ value &&
39
+ typeof value === 'object' &&
40
+ typeof value.arrayBuffer === 'function' &&
41
+ typeof value.type === 'string' &&
42
+ typeof value.stream === 'function' &&
43
+ typeof value.constructor === 'function' &&
44
+ /^(Blob|File)$/.test(value[NAME])
45
+ );
46
+ };
47
+
48
+ /**
49
+ * Check if `obj` is an instance of AbortSignal.
50
+ * @param object - Object to check for
51
+ */
52
+ export const isAbortSignal = (object: any) => {
53
+ return (
54
+ typeof object === 'object' && (
55
+ object[NAME] === 'AbortSignal' ||
56
+ object[NAME] === 'EventTarget'
57
+ )
58
+ );
59
+ };
60
+
61
+ /**
62
+ * isDomainOrSubdomain reports whether sub is a subdomain (or exact match) of
63
+ * the parent domain.
64
+ *
65
+ * Both domains must already be in canonical form.
66
+ * @param {string|URL} original
67
+ * @param {string|URL} destination
68
+ */
69
+ export const isDomainOrSubdomain = (destination, original) => {
70
+ const orig = new URL(original).hostname;
71
+ const dest = new URL(destination).hostname;
72
+
73
+ return orig === dest || orig.endsWith(`.${dest}`);
74
+ };
75
+
76
+ /**
77
+ * isSameProtocol reports whether the two provided URLs use the same protocol.
78
+ *
79
+ * Both domains must already be in canonical form.
80
+ * @param {string|URL} original
81
+ * @param {string|URL} destination
82
+ */
83
+ export const isSameProtocol = (destination, original) => {
84
+ const orig = new URL(original).protocol;
85
+ const dest = new URL(destination).protocol;
86
+
87
+ return orig === dest;
88
+ };