@juzi/file-box 1.7.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/LICENSE +201 -0
- package/README.md +613 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/src/config.d.ts +4 -0
- package/dist/cjs/src/config.d.ts.map +1 -0
- package/dist/cjs/src/config.js +9 -0
- package/dist/cjs/src/config.js.map +1 -0
- package/dist/cjs/src/file-box.d.ts +209 -0
- package/dist/cjs/src/file-box.d.ts.map +1 -0
- package/dist/cjs/src/file-box.js +804 -0
- package/dist/cjs/src/file-box.js.map +1 -0
- package/dist/cjs/src/file-box.spec.d.ts +14 -0
- package/dist/cjs/src/file-box.spec.d.ts.map +1 -0
- package/dist/cjs/src/file-box.spec.js +393 -0
- package/dist/cjs/src/file-box.spec.js.map +1 -0
- package/dist/cjs/src/file-box.type.d.ts +103 -0
- package/dist/cjs/src/file-box.type.d.ts.map +1 -0
- package/dist/cjs/src/file-box.type.js +34 -0
- package/dist/cjs/src/file-box.type.js.map +1 -0
- package/dist/cjs/src/interface.d.ts +25 -0
- package/dist/cjs/src/interface.d.ts.map +1 -0
- package/dist/cjs/src/interface.js +3 -0
- package/dist/cjs/src/interface.js.map +1 -0
- package/dist/cjs/src/interface.spec.d.ts +3 -0
- package/dist/cjs/src/interface.spec.d.ts.map +1 -0
- package/dist/cjs/src/interface.spec.js +11 -0
- package/dist/cjs/src/interface.spec.js.map +1 -0
- package/dist/cjs/src/misc.d.ts +17 -0
- package/dist/cjs/src/misc.d.ts.map +1 -0
- package/dist/cjs/src/misc.js +137 -0
- package/dist/cjs/src/misc.js.map +1 -0
- package/dist/cjs/src/misc.spec.d.ts +3 -0
- package/dist/cjs/src/misc.spec.d.ts.map +1 -0
- package/dist/cjs/src/misc.spec.js +51 -0
- package/dist/cjs/src/misc.spec.js.map +1 -0
- package/dist/cjs/src/mod.d.ts +9 -0
- package/dist/cjs/src/mod.d.ts.map +1 -0
- package/dist/cjs/src/mod.js +12 -0
- package/dist/cjs/src/mod.js.map +1 -0
- package/dist/cjs/src/pure-functions/sized-chunk-transformer.d.ts +13 -0
- package/dist/cjs/src/pure-functions/sized-chunk-transformer.d.ts.map +1 -0
- package/dist/cjs/src/pure-functions/sized-chunk-transformer.js +45 -0
- package/dist/cjs/src/pure-functions/sized-chunk-transformer.js.map +1 -0
- package/dist/cjs/src/pure-functions/sized-chunk-transformer.spec.d.ts +3 -0
- package/dist/cjs/src/pure-functions/sized-chunk-transformer.spec.d.ts.map +1 -0
- package/dist/cjs/src/pure-functions/sized-chunk-transformer.spec.js +39 -0
- package/dist/cjs/src/pure-functions/sized-chunk-transformer.spec.js.map +1 -0
- package/dist/cjs/src/qrcode.d.ts +6 -0
- package/dist/cjs/src/qrcode.d.ts.map +1 -0
- package/dist/cjs/src/qrcode.js +35 -0
- package/dist/cjs/src/qrcode.js.map +1 -0
- package/dist/cjs/src/qrcode.spec.d.ts +3 -0
- package/dist/cjs/src/qrcode.spec.d.ts.map +1 -0
- package/dist/cjs/src/qrcode.spec.js +47 -0
- package/dist/cjs/src/qrcode.spec.js.map +1 -0
- package/dist/cjs/src/urn-registry/mod.d.ts +3 -0
- package/dist/cjs/src/urn-registry/mod.d.ts.map +1 -0
- package/dist/cjs/src/urn-registry/mod.js +6 -0
- package/dist/cjs/src/urn-registry/mod.js.map +1 -0
- package/dist/cjs/src/urn-registry/random-uuid.d.ts +4 -0
- package/dist/cjs/src/urn-registry/random-uuid.d.ts.map +1 -0
- package/dist/cjs/src/urn-registry/random-uuid.js +30 -0
- package/dist/cjs/src/urn-registry/random-uuid.js.map +1 -0
- package/dist/cjs/src/urn-registry/uniform-resource-name-registry.d.ts +76 -0
- package/dist/cjs/src/urn-registry/uniform-resource-name-registry.d.ts.map +1 -0
- package/dist/cjs/src/urn-registry/uniform-resource-name-registry.js +259 -0
- package/dist/cjs/src/urn-registry/uniform-resource-name-registry.js.map +1 -0
- package/dist/cjs/src/urn-registry/uniform-resource-name-registry.spec.d.ts +3 -0
- package/dist/cjs/src/urn-registry/uniform-resource-name-registry.spec.d.ts.map +1 -0
- package/dist/cjs/src/urn-registry/uniform-resource-name-registry.spec.js +81 -0
- package/dist/cjs/src/urn-registry/uniform-resource-name-registry.spec.js.map +1 -0
- package/dist/cjs/src/urn-registry/uuid-to-big-int.d.ts +8 -0
- package/dist/cjs/src/urn-registry/uuid-to-big-int.d.ts.map +1 -0
- package/dist/cjs/src/urn-registry/uuid-to-big-int.js +16 -0
- package/dist/cjs/src/urn-registry/uuid-to-big-int.js.map +1 -0
- package/dist/cjs/src/urn-registry/uuid-to-big-int.spec.d.ts +3 -0
- package/dist/cjs/src/urn-registry/uuid-to-big-int.spec.d.ts.map +1 -0
- package/dist/cjs/src/urn-registry/uuid-to-big-int.spec.js +17 -0
- package/dist/cjs/src/urn-registry/uuid-to-big-int.spec.js.map +1 -0
- package/dist/cjs/src/version.d.ts +5 -0
- package/dist/cjs/src/version.d.ts.map +1 -0
- package/dist/cjs/src/version.js +8 -0
- package/dist/cjs/src/version.js.map +1 -0
- package/dist/cjs/src/version.spec.d.ts +3 -0
- package/dist/cjs/src/version.spec.d.ts.map +1 -0
- package/dist/cjs/src/version.spec.js +9 -0
- package/dist/cjs/src/version.spec.js.map +1 -0
- package/dist/cjs/tests/integration.spec.d.ts +3 -0
- package/dist/cjs/tests/integration.spec.d.ts.map +1 -0
- package/dist/cjs/tests/integration.spec.js +8 -0
- package/dist/cjs/tests/integration.spec.js.map +1 -0
- package/dist/cjs/tests/network-timeout.spec.d.ts +3 -0
- package/dist/cjs/tests/network-timeout.spec.d.ts.map +1 -0
- package/dist/cjs/tests/network-timeout.spec.js +121 -0
- package/dist/cjs/tests/network-timeout.spec.js.map +1 -0
- package/dist/esm/src/config.d.ts +4 -0
- package/dist/esm/src/config.d.ts.map +1 -0
- package/dist/esm/src/config.js +5 -0
- package/dist/esm/src/config.js.map +1 -0
- package/dist/esm/src/file-box.d.ts +209 -0
- package/dist/esm/src/file-box.d.ts.map +1 -0
- package/dist/esm/src/file-box.js +775 -0
- package/dist/esm/src/file-box.js.map +1 -0
- package/dist/esm/src/file-box.spec.d.ts +14 -0
- package/dist/esm/src/file-box.spec.d.ts.map +1 -0
- package/dist/esm/src/file-box.spec.js +386 -0
- package/dist/esm/src/file-box.spec.js.map +1 -0
- package/dist/esm/src/file-box.type.d.ts +103 -0
- package/dist/esm/src/file-box.type.d.ts.map +1 -0
- package/dist/esm/src/file-box.type.js +31 -0
- package/dist/esm/src/file-box.type.js.map +1 -0
- package/dist/esm/src/interface.d.ts +25 -0
- package/dist/esm/src/interface.d.ts.map +1 -0
- package/dist/esm/src/interface.js +2 -0
- package/dist/esm/src/interface.js.map +1 -0
- package/dist/esm/src/interface.spec.d.ts +3 -0
- package/dist/esm/src/interface.spec.d.ts.map +1 -0
- package/dist/esm/src/interface.spec.js +9 -0
- package/dist/esm/src/interface.spec.js.map +1 -0
- package/dist/esm/src/misc.d.ts +17 -0
- package/dist/esm/src/misc.d.ts.map +1 -0
- package/dist/esm/src/misc.js +126 -0
- package/dist/esm/src/misc.js.map +1 -0
- package/dist/esm/src/misc.spec.d.ts +3 -0
- package/dist/esm/src/misc.spec.d.ts.map +1 -0
- package/dist/esm/src/misc.spec.js +49 -0
- package/dist/esm/src/misc.spec.js.map +1 -0
- package/dist/esm/src/mod.d.ts +9 -0
- package/dist/esm/src/mod.d.ts.map +1 -0
- package/dist/esm/src/mod.js +6 -0
- package/dist/esm/src/mod.js.map +1 -0
- package/dist/esm/src/pure-functions/sized-chunk-transformer.d.ts +13 -0
- package/dist/esm/src/pure-functions/sized-chunk-transformer.d.ts.map +1 -0
- package/dist/esm/src/pure-functions/sized-chunk-transformer.js +39 -0
- package/dist/esm/src/pure-functions/sized-chunk-transformer.js.map +1 -0
- package/dist/esm/src/pure-functions/sized-chunk-transformer.spec.d.ts +3 -0
- package/dist/esm/src/pure-functions/sized-chunk-transformer.spec.d.ts.map +1 -0
- package/dist/esm/src/pure-functions/sized-chunk-transformer.spec.js +37 -0
- package/dist/esm/src/pure-functions/sized-chunk-transformer.spec.js.map +1 -0
- package/dist/esm/src/qrcode.d.ts +6 -0
- package/dist/esm/src/qrcode.d.ts.map +1 -0
- package/dist/esm/src/qrcode.js +27 -0
- package/dist/esm/src/qrcode.js.map +1 -0
- package/dist/esm/src/qrcode.spec.d.ts +3 -0
- package/dist/esm/src/qrcode.spec.d.ts.map +1 -0
- package/dist/esm/src/qrcode.spec.js +45 -0
- package/dist/esm/src/qrcode.spec.js.map +1 -0
- package/dist/esm/src/urn-registry/mod.d.ts +3 -0
- package/dist/esm/src/urn-registry/mod.d.ts.map +1 -0
- package/dist/esm/src/urn-registry/mod.js +3 -0
- package/dist/esm/src/urn-registry/mod.js.map +1 -0
- package/dist/esm/src/urn-registry/random-uuid.d.ts +4 -0
- package/dist/esm/src/urn-registry/random-uuid.d.ts.map +1 -0
- package/dist/esm/src/urn-registry/random-uuid.js +4 -0
- package/dist/esm/src/urn-registry/random-uuid.js.map +1 -0
- package/dist/esm/src/urn-registry/uniform-resource-name-registry.d.ts +76 -0
- package/dist/esm/src/urn-registry/uniform-resource-name-registry.d.ts.map +1 -0
- package/dist/esm/src/urn-registry/uniform-resource-name-registry.js +253 -0
- package/dist/esm/src/urn-registry/uniform-resource-name-registry.js.map +1 -0
- package/dist/esm/src/urn-registry/uniform-resource-name-registry.spec.d.ts +3 -0
- package/dist/esm/src/urn-registry/uniform-resource-name-registry.spec.d.ts.map +1 -0
- package/dist/esm/src/urn-registry/uniform-resource-name-registry.spec.js +79 -0
- package/dist/esm/src/urn-registry/uniform-resource-name-registry.spec.js.map +1 -0
- package/dist/esm/src/urn-registry/uuid-to-big-int.d.ts +8 -0
- package/dist/esm/src/urn-registry/uuid-to-big-int.d.ts.map +1 -0
- package/dist/esm/src/urn-registry/uuid-to-big-int.js +13 -0
- package/dist/esm/src/urn-registry/uuid-to-big-int.js.map +1 -0
- package/dist/esm/src/urn-registry/uuid-to-big-int.spec.d.ts +3 -0
- package/dist/esm/src/urn-registry/uuid-to-big-int.spec.d.ts.map +1 -0
- package/dist/esm/src/urn-registry/uuid-to-big-int.spec.js +15 -0
- package/dist/esm/src/urn-registry/uuid-to-big-int.spec.js.map +1 -0
- package/dist/esm/src/version.d.ts +5 -0
- package/dist/esm/src/version.d.ts.map +1 -0
- package/dist/esm/src/version.js +5 -0
- package/dist/esm/src/version.js.map +1 -0
- package/dist/esm/src/version.spec.d.ts +3 -0
- package/dist/esm/src/version.spec.d.ts.map +1 -0
- package/dist/esm/src/version.spec.js +7 -0
- package/dist/esm/src/version.spec.js.map +1 -0
- package/dist/esm/tests/integration.spec.d.ts +3 -0
- package/dist/esm/tests/integration.spec.d.ts.map +1 -0
- package/dist/esm/tests/integration.spec.js +6 -0
- package/dist/esm/tests/integration.spec.js.map +1 -0
- package/dist/esm/tests/network-timeout.spec.d.ts +3 -0
- package/dist/esm/tests/network-timeout.spec.d.ts.map +1 -0
- package/dist/esm/tests/network-timeout.spec.js +119 -0
- package/dist/esm/tests/network-timeout.spec.js.map +1 -0
- package/package.json +85 -0
- package/src/config.ts +5 -0
- package/src/file-box.spec.ts +480 -0
- package/src/file-box.ts +1042 -0
- package/src/file-box.type.ts +145 -0
- package/src/interface.spec.ts +17 -0
- package/src/interface.ts +47 -0
- package/src/misc.spec.ts +70 -0
- package/src/misc.ts +157 -0
- package/src/mod.ts +33 -0
- package/src/pure-functions/sized-chunk-transformer.spec.ts +52 -0
- package/src/pure-functions/sized-chunk-transformer.ts +49 -0
- package/src/qrcode.spec.ts +55 -0
- package/src/qrcode.ts +38 -0
- package/src/typings.d.ts +1 -0
- package/src/urn-registry/mod.ts +7 -0
- package/src/urn-registry/random-uuid.ts +7 -0
- package/src/urn-registry/uniform-resource-name-registry.spec.ts +109 -0
- package/src/urn-registry/uniform-resource-name-registry.ts +342 -0
- package/src/urn-registry/uuid-to-big-int.spec.ts +19 -0
- package/src/urn-registry/uuid-to-big-int.ts +16 -0
- package/src/version.spec.ts +9 -0
- package/src/version.ts +4 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import type http from 'http'
|
|
2
|
+
import type {
|
|
3
|
+
Readable,
|
|
4
|
+
Writable,
|
|
5
|
+
} from 'stream'
|
|
6
|
+
|
|
7
|
+
import type {
|
|
8
|
+
FileBox,
|
|
9
|
+
} from './file-box.js'
|
|
10
|
+
|
|
11
|
+
interface Pipeable {
|
|
12
|
+
// pipe: typeof Readable.prototype.pipe,
|
|
13
|
+
pipe<T extends Writable>(destination: T, options?: { end?: boolean; }): T;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Huan(202002):
|
|
18
|
+
* We need to keep this enum number to be consistent
|
|
19
|
+
* because of toJSON & fromJSON need the same type number across versoins.
|
|
20
|
+
* and gRPC maybe will use those numbers in the future as well.
|
|
21
|
+
*/
|
|
22
|
+
enum FileBoxType {
|
|
23
|
+
Unknown = 0,
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 1. toJSON() Serializable
|
|
27
|
+
* - Base64
|
|
28
|
+
* - Url
|
|
29
|
+
* - QRCode
|
|
30
|
+
* - UUID
|
|
31
|
+
*
|
|
32
|
+
* 2. toJSON() NOT Serializable: need to convert to FileBoxType.Base64 before call toJSON()
|
|
33
|
+
* - Buffer
|
|
34
|
+
* - Stream
|
|
35
|
+
* - File
|
|
36
|
+
*/
|
|
37
|
+
Base64 = 1,
|
|
38
|
+
Url = 2,
|
|
39
|
+
QRCode = 3,
|
|
40
|
+
|
|
41
|
+
Buffer = 4,
|
|
42
|
+
File = 5,
|
|
43
|
+
Stream = 6,
|
|
44
|
+
Uuid = 7,
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface Metadata {
|
|
48
|
+
[key: string]: any,
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* URI to the file
|
|
53
|
+
* See:
|
|
54
|
+
* https://nodejs.org/api/fs.html#fs_url_object_support
|
|
55
|
+
* https://danielmiessler.com/study/url-uri/
|
|
56
|
+
*
|
|
57
|
+
* FileType: LOCAL, REMOTE, BUFFER, STREAM
|
|
58
|
+
*
|
|
59
|
+
*/
|
|
60
|
+
interface FileBoxOptionsCommon {
|
|
61
|
+
/**
|
|
62
|
+
* File base name: name + ext
|
|
63
|
+
* like: "file.txt"
|
|
64
|
+
*/
|
|
65
|
+
name: string
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Can be only set once
|
|
69
|
+
*/
|
|
70
|
+
metadata?: Metadata,
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Size
|
|
74
|
+
*/
|
|
75
|
+
size?: number
|
|
76
|
+
md5?: string
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
interface FileBoxOptionsFile {
|
|
80
|
+
type : FileBoxType.File
|
|
81
|
+
path : string
|
|
82
|
+
}
|
|
83
|
+
interface FileBoxOptionsUrl {
|
|
84
|
+
type : FileBoxType.Url
|
|
85
|
+
url : string
|
|
86
|
+
headers? : http.OutgoingHttpHeaders
|
|
87
|
+
}
|
|
88
|
+
interface FileBoxOptionsBuffer {
|
|
89
|
+
type : FileBoxType.Buffer
|
|
90
|
+
buffer : Buffer
|
|
91
|
+
}
|
|
92
|
+
interface FileBoxOptionsStream {
|
|
93
|
+
type : FileBoxType.Stream
|
|
94
|
+
stream : Readable
|
|
95
|
+
}
|
|
96
|
+
interface FileBoxOptionsQRCode {
|
|
97
|
+
type : FileBoxType.QRCode,
|
|
98
|
+
qrCode : string,
|
|
99
|
+
}
|
|
100
|
+
interface FileBoxOptionsBase64 {
|
|
101
|
+
type : FileBoxType.Base64,
|
|
102
|
+
base64 : string,
|
|
103
|
+
}
|
|
104
|
+
interface FileBoxOptionsUuid {
|
|
105
|
+
type : FileBoxType.Uuid
|
|
106
|
+
uuid : string
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
type FileBoxOptions = FileBoxOptionsCommon & (
|
|
110
|
+
never
|
|
111
|
+
| FileBoxOptionsBase64
|
|
112
|
+
| FileBoxOptionsBuffer
|
|
113
|
+
| FileBoxOptionsFile
|
|
114
|
+
| FileBoxOptionsQRCode
|
|
115
|
+
| FileBoxOptionsStream
|
|
116
|
+
| FileBoxOptionsUrl
|
|
117
|
+
| FileBoxOptionsUuid
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
type FileBoxJsonObject = FileBoxOptionsCommon & (
|
|
121
|
+
| FileBoxOptionsBase64
|
|
122
|
+
| FileBoxOptionsUrl
|
|
123
|
+
| FileBoxOptionsQRCode
|
|
124
|
+
| FileBoxOptionsUuid
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
type UuidLoader = (this: FileBox, uuid: string) => Promise<Readable>
|
|
128
|
+
type UuidSaver = (this: FileBox, stream: Readable) => Promise<string>
|
|
129
|
+
|
|
130
|
+
export type {
|
|
131
|
+
FileBoxJsonObject,
|
|
132
|
+
FileBoxOptions,
|
|
133
|
+
FileBoxOptionsBase64,
|
|
134
|
+
FileBoxOptionsCommon,
|
|
135
|
+
FileBoxOptionsQRCode,
|
|
136
|
+
FileBoxOptionsUrl,
|
|
137
|
+
FileBoxOptionsUuid,
|
|
138
|
+
Metadata,
|
|
139
|
+
Pipeable,
|
|
140
|
+
UuidSaver,
|
|
141
|
+
UuidLoader,
|
|
142
|
+
}
|
|
143
|
+
export {
|
|
144
|
+
FileBoxType,
|
|
145
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env -S node --no-warnings --loader ts-node/esm
|
|
2
|
+
|
|
3
|
+
// tslint:disable:no-shadowed-variable
|
|
4
|
+
import { test } from 'tstest'
|
|
5
|
+
|
|
6
|
+
import type {
|
|
7
|
+
FileBoxInterface,
|
|
8
|
+
} from './interface.js'
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
FileBox,
|
|
12
|
+
} from './file-box.js'
|
|
13
|
+
|
|
14
|
+
test('FileBoxInterface', async t => {
|
|
15
|
+
const fileBox: FileBoxInterface = FileBox.fromQRCode('test')
|
|
16
|
+
t.ok(fileBox, 'should be ok with interface')
|
|
17
|
+
})
|
package/src/interface.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Constructor,
|
|
3
|
+
} from 'clone-class'
|
|
4
|
+
import type {
|
|
5
|
+
FileBox,
|
|
6
|
+
} from './file-box.js'
|
|
7
|
+
|
|
8
|
+
interface FileBoxInterface {
|
|
9
|
+
type : FileBox['type']
|
|
10
|
+
|
|
11
|
+
name : FileBox['name']
|
|
12
|
+
size : FileBox['size']
|
|
13
|
+
md5 : FileBox['md5']
|
|
14
|
+
mediaType : FileBox['mediaType']
|
|
15
|
+
metadata : FileBox['metadata']
|
|
16
|
+
|
|
17
|
+
// version: any
|
|
18
|
+
// ready: any
|
|
19
|
+
// syncRemote: any
|
|
20
|
+
// transformBufferToStream: any
|
|
21
|
+
// transformBase64ToStream: any
|
|
22
|
+
// transformFileToStream: any
|
|
23
|
+
// ransformUrlToStream: any
|
|
24
|
+
// transformQRCodeToStream: any
|
|
25
|
+
// transformUrlToStream: any
|
|
26
|
+
|
|
27
|
+
toBase64 : FileBox['toBase64']
|
|
28
|
+
toBuffer : FileBox['toBuffer']
|
|
29
|
+
toDataURL : FileBox['toDataURL']
|
|
30
|
+
toFile : FileBox['toFile']
|
|
31
|
+
toJSON : FileBox['toJSON']
|
|
32
|
+
toQRCode : FileBox['toQRCode']
|
|
33
|
+
toStream : FileBox['toStream']
|
|
34
|
+
toUuid : FileBox['toUuid']
|
|
35
|
+
|
|
36
|
+
pipe: FileBox['pipe']
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Huan(202110): TODO support static methods after TypeScript 4.5: fromXXX()
|
|
41
|
+
*/
|
|
42
|
+
type FileBoxConstructor = Constructor<FileBoxInterface>
|
|
43
|
+
|
|
44
|
+
export type {
|
|
45
|
+
FileBoxInterface,
|
|
46
|
+
FileBoxConstructor,
|
|
47
|
+
}
|
package/src/misc.spec.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env -S node --no-warnings --loader ts-node/esm
|
|
2
|
+
|
|
3
|
+
// tslint:disable:no-shadowed-variable
|
|
4
|
+
import { test } from 'tstest'
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
dataUrlToBase64,
|
|
8
|
+
httpHeaderToFileName,
|
|
9
|
+
httpHeadHeader,
|
|
10
|
+
httpStream,
|
|
11
|
+
streamToBuffer,
|
|
12
|
+
} from './misc.js'
|
|
13
|
+
|
|
14
|
+
test('dataUrl to base64', async t => {
|
|
15
|
+
const base64 = [
|
|
16
|
+
'R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl',
|
|
17
|
+
'3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
18
|
+
'ACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGA',
|
|
19
|
+
'iqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7',
|
|
20
|
+
].join('')
|
|
21
|
+
const dataUrl = [
|
|
22
|
+
'data:image/png;base64,',
|
|
23
|
+
base64,
|
|
24
|
+
].join('')
|
|
25
|
+
|
|
26
|
+
t.equal(base64, dataUrlToBase64(dataUrl), 'should get base64 from dataUrl')
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
test('httpHeadHeader', async t => {
|
|
30
|
+
const URL = 'https://github.com/huan/file-box/archive/v0.6.tar.gz'
|
|
31
|
+
|
|
32
|
+
const EXPECTED_HEADERS_KEY = 'content-disposition'
|
|
33
|
+
const EXPECTED_HEADERS_VALUE = 'attachment; filename=file-box-0.6.tar.gz'
|
|
34
|
+
|
|
35
|
+
const headers = await httpHeadHeader(URL)
|
|
36
|
+
|
|
37
|
+
t.equal(headers[EXPECTED_HEADERS_KEY], EXPECTED_HEADERS_VALUE, 'should get the headers right')
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
test('httpHeaderToFileName', async t => {
|
|
41
|
+
const HEADERS_QUOTATION_MARK: any = {
|
|
42
|
+
'content-disposition': 'attachment; filename="db-0.0.19.zip"',
|
|
43
|
+
}
|
|
44
|
+
const HEADERS_NO_QUOTATION_MARK: any = {
|
|
45
|
+
'content-disposition': 'attachment; filename=db-0.0.19.zip',
|
|
46
|
+
}
|
|
47
|
+
const EXPECTED_FILE_NAME = 'db-0.0.19.zip'
|
|
48
|
+
|
|
49
|
+
let filename = httpHeaderToFileName(HEADERS_QUOTATION_MARK)
|
|
50
|
+
t.equal(filename, EXPECTED_FILE_NAME, 'should get filename with quotation mark')
|
|
51
|
+
|
|
52
|
+
filename = httpHeaderToFileName(HEADERS_NO_QUOTATION_MARK)
|
|
53
|
+
t.equal(filename, EXPECTED_FILE_NAME, 'should get filename with no quotation mark')
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
test('httpStream', async t => {
|
|
57
|
+
const URL = 'https://httpbin.org/headers'
|
|
58
|
+
|
|
59
|
+
const MOL_KEY = 'Mol'
|
|
60
|
+
const MOL_VAL = '42'
|
|
61
|
+
|
|
62
|
+
const headers = {} as { [idx: string]: string }
|
|
63
|
+
headers[MOL_KEY] = MOL_VAL
|
|
64
|
+
|
|
65
|
+
const res = await httpStream(URL, headers)
|
|
66
|
+
|
|
67
|
+
const buffer = await streamToBuffer(res)
|
|
68
|
+
const obj = JSON.parse(buffer.toString())
|
|
69
|
+
t.equal(obj.headers[MOL_KEY], MOL_VAL, 'should send the header right')
|
|
70
|
+
})
|
package/src/misc.ts
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import http from 'http'
|
|
2
|
+
import https from 'https'
|
|
3
|
+
import { URL } from 'url'
|
|
4
|
+
import type stream from 'stream'
|
|
5
|
+
|
|
6
|
+
import { HTTP_TIMEOUT } from './config.js'
|
|
7
|
+
|
|
8
|
+
export function dataUrlToBase64 (dataUrl: string): string {
|
|
9
|
+
const dataList = dataUrl.split(',')
|
|
10
|
+
return dataList[dataList.length - 1]!
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Get http headers for specific `url`
|
|
15
|
+
* follow 302 redirection for max `REDIRECT_TTL` times.
|
|
16
|
+
*
|
|
17
|
+
* @credit https://stackoverflow.com/a/43632171/1123955
|
|
18
|
+
*/
|
|
19
|
+
export async function httpHeadHeader (url: string): Promise<http.IncomingHttpHeaders> {
|
|
20
|
+
|
|
21
|
+
let REDIRECT_TTL = 7
|
|
22
|
+
|
|
23
|
+
while (true) {
|
|
24
|
+
if (REDIRECT_TTL-- <= 0) {
|
|
25
|
+
throw new Error(`ttl expired! too many(>${REDIRECT_TTL}) 302 redirection.`)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const res = await _headHeader(url)
|
|
29
|
+
|
|
30
|
+
if (!/^3/.test(String(res.statusCode))) {
|
|
31
|
+
return res.headers
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// console.log('302 found for ' + url)
|
|
35
|
+
|
|
36
|
+
if (!res.headers.location) {
|
|
37
|
+
throw new Error('302 found but no location!')
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
url = res.headers.location
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function _headHeader (destUrl: string): Promise<http.IncomingMessage> {
|
|
44
|
+
const parsedUrl = new URL(destUrl)
|
|
45
|
+
const options = {
|
|
46
|
+
method : 'HEAD',
|
|
47
|
+
// method : 'GET',
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let request: typeof http.request
|
|
51
|
+
|
|
52
|
+
if (parsedUrl.protocol === 'https:') {
|
|
53
|
+
request = https.request
|
|
54
|
+
} else if (parsedUrl.protocol === 'http:') {
|
|
55
|
+
request = http.request
|
|
56
|
+
} else {
|
|
57
|
+
throw new Error('unknown protocol: ' + parsedUrl.protocol)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return new Promise<http.IncomingMessage>((resolve, reject) => {
|
|
61
|
+
let res: undefined | http.IncomingMessage
|
|
62
|
+
const req = request(parsedUrl, options, (response) => {
|
|
63
|
+
res = response
|
|
64
|
+
resolve(res)
|
|
65
|
+
})
|
|
66
|
+
.on('error', reject)
|
|
67
|
+
.setTimeout(HTTP_TIMEOUT, () => {
|
|
68
|
+
const e = new Error(`FileBox: Http request timeout (${HTTP_TIMEOUT})!`)
|
|
69
|
+
req.emit('error', e)
|
|
70
|
+
req.destroy()
|
|
71
|
+
})
|
|
72
|
+
.end()
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function httpHeaderToFileName (
|
|
78
|
+
headers: http.IncomingHttpHeaders,
|
|
79
|
+
): null | string {
|
|
80
|
+
const contentDisposition = headers['content-disposition']
|
|
81
|
+
|
|
82
|
+
if (!contentDisposition) {
|
|
83
|
+
return null
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 'content-disposition': 'attachment; filename=db-0.0.19.zip'
|
|
87
|
+
const matches = contentDisposition.match(/attachment; filename="?(.+[^"])"?$/i)
|
|
88
|
+
|
|
89
|
+
if (matches && matches[1]) {
|
|
90
|
+
return matches[1]
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return null
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export async function httpStream (
|
|
97
|
+
url : string,
|
|
98
|
+
headers : http.OutgoingHttpHeaders = {},
|
|
99
|
+
): Promise<http.IncomingMessage> {
|
|
100
|
+
const parsedUrl = new URL(url)
|
|
101
|
+
|
|
102
|
+
const protocol = parsedUrl.protocol
|
|
103
|
+
|
|
104
|
+
const options: http.RequestOptions = {}
|
|
105
|
+
|
|
106
|
+
let get: typeof https.get
|
|
107
|
+
|
|
108
|
+
if (!protocol) {
|
|
109
|
+
throw new Error('protocol is empty')
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (protocol.match(/^https:/i)) {
|
|
113
|
+
get = https.get
|
|
114
|
+
options.agent = https.globalAgent
|
|
115
|
+
} else if (protocol.match(/^http:/i)) {
|
|
116
|
+
get = http.get
|
|
117
|
+
options.agent = http.globalAgent
|
|
118
|
+
} else {
|
|
119
|
+
throw new Error('protocol unknown: ' + protocol)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
options.headers = {
|
|
123
|
+
...headers,
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return new Promise<http.IncomingMessage>((resolve, reject) => {
|
|
127
|
+
let res: http.IncomingMessage | null = null
|
|
128
|
+
const req = get(parsedUrl, options, (response) => {
|
|
129
|
+
res = response
|
|
130
|
+
resolve(res)
|
|
131
|
+
})
|
|
132
|
+
.on('error', reject)
|
|
133
|
+
.setTimeout(HTTP_TIMEOUT, () => {
|
|
134
|
+
const e = new Error(`FileBox: Http request timeout (${HTTP_TIMEOUT})!`)
|
|
135
|
+
if (res) {
|
|
136
|
+
res.emit('error', e)
|
|
137
|
+
}
|
|
138
|
+
req.emit('error', e)
|
|
139
|
+
req.destroy()
|
|
140
|
+
})
|
|
141
|
+
.end()
|
|
142
|
+
})
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export async function streamToBuffer (
|
|
146
|
+
stream: stream.Readable,
|
|
147
|
+
): Promise<Buffer> {
|
|
148
|
+
return new Promise<Buffer>((resolve, reject) => {
|
|
149
|
+
const bufferList: Buffer[] = []
|
|
150
|
+
stream.once('error', reject)
|
|
151
|
+
stream.once('end', () => {
|
|
152
|
+
const fullBuffer = Buffer.concat(bufferList)
|
|
153
|
+
resolve(fullBuffer)
|
|
154
|
+
})
|
|
155
|
+
stream.on('data', buffer => bufferList.push(buffer))
|
|
156
|
+
})
|
|
157
|
+
}
|
package/src/mod.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FileBoxType,
|
|
3
|
+
} from './file-box.type.js'
|
|
4
|
+
import {
|
|
5
|
+
VERSION,
|
|
6
|
+
} from './config.js'
|
|
7
|
+
import {
|
|
8
|
+
FileBox,
|
|
9
|
+
} from './file-box.js'
|
|
10
|
+
import type {
|
|
11
|
+
FileBoxInterface,
|
|
12
|
+
FileBoxConstructor,
|
|
13
|
+
} from './interface.js'
|
|
14
|
+
import type {
|
|
15
|
+
UuidSaver,
|
|
16
|
+
UuidLoader,
|
|
17
|
+
} from './file-box.type.js'
|
|
18
|
+
import {
|
|
19
|
+
UniformResourceNameRegistry,
|
|
20
|
+
} from './urn-registry/uniform-resource-name-registry.js'
|
|
21
|
+
|
|
22
|
+
export type {
|
|
23
|
+
UuidSaver,
|
|
24
|
+
UuidLoader,
|
|
25
|
+
FileBoxInterface,
|
|
26
|
+
FileBoxConstructor,
|
|
27
|
+
}
|
|
28
|
+
export {
|
|
29
|
+
FileBox,
|
|
30
|
+
FileBoxType,
|
|
31
|
+
UniformResourceNameRegistry,
|
|
32
|
+
VERSION,
|
|
33
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env -S node --no-warnings --loader ts-node/esm
|
|
2
|
+
|
|
3
|
+
/* eslint @typescript-eslint/no-unused-vars:off */
|
|
4
|
+
|
|
5
|
+
import { test } from 'tstest'
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
PassThrough,
|
|
9
|
+
Readable,
|
|
10
|
+
} from 'stream'
|
|
11
|
+
|
|
12
|
+
import { sizedChunkTransformer } from './sized-chunk-transformer.js'
|
|
13
|
+
|
|
14
|
+
test('chunkerTransformStream()', async t => {
|
|
15
|
+
const DATA_LIST = [
|
|
16
|
+
'a',
|
|
17
|
+
'b',
|
|
18
|
+
]
|
|
19
|
+
const DATA = DATA_LIST.join('')
|
|
20
|
+
|
|
21
|
+
const createStream = () => {
|
|
22
|
+
const stream = new PassThrough()
|
|
23
|
+
stream.end(DATA)
|
|
24
|
+
return stream
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const getDataList = (stream: Readable) => {
|
|
28
|
+
return new Promise<any[]>(resolve => {
|
|
29
|
+
const list = [] as any[]
|
|
30
|
+
stream.on('end', () => resolve(list))
|
|
31
|
+
stream.on('data', chunk => list.push(chunk))
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const newStream0 = createStream()
|
|
36
|
+
const dataList0 = await getDataList(newStream0)
|
|
37
|
+
|
|
38
|
+
t.equal(dataList0.length, 1, 'should get 1 chunks')
|
|
39
|
+
t.equal(dataList0[0].toString(), DATA, 'should get data')
|
|
40
|
+
|
|
41
|
+
const newStream1 = createStream().pipe(sizedChunkTransformer(2))
|
|
42
|
+
const dataList1 = await getDataList(newStream1)
|
|
43
|
+
|
|
44
|
+
t.equal(dataList1.length, 1, 'should get 1 chunks')
|
|
45
|
+
t.equal(dataList1[0].toString(), DATA, 'should get data')
|
|
46
|
+
|
|
47
|
+
const newStream2 = createStream().pipe(sizedChunkTransformer(1))
|
|
48
|
+
const dataList2 = await getDataList(newStream2)
|
|
49
|
+
|
|
50
|
+
t.equal(dataList2.length, 2, 'should get 2 chunks')
|
|
51
|
+
t.equal(dataList2.join(''), DATA, 'should get data')
|
|
52
|
+
})
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ChunkerTransformStream, a transform stream to take arbitrary chunk sizes and make them consistent
|
|
3
|
+
* https://codereview.stackexchange.com/q/57492/185709
|
|
4
|
+
*/
|
|
5
|
+
import stream from 'stream'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* TCP streaming workload tuning
|
|
9
|
+
* https://www.ibm.com/docs/en/aix/7.2?topic=tuning-tcp-streaming-workload
|
|
10
|
+
*/
|
|
11
|
+
const DEFAULT_CHUNK_BYTE = 256 * 1024 // 256 KB
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param chunkByte The size of the chunks to be created
|
|
15
|
+
* @returns
|
|
16
|
+
*/
|
|
17
|
+
function sizedChunkTransformer (chunkByte = DEFAULT_CHUNK_BYTE) {
|
|
18
|
+
let buffer = Buffer.from([])
|
|
19
|
+
|
|
20
|
+
const transform: stream.TransformOptions['transform'] = function (chunk, _, done) {
|
|
21
|
+
buffer = Buffer.concat([ buffer, chunk ])
|
|
22
|
+
|
|
23
|
+
while (buffer.length >= chunkByte) {
|
|
24
|
+
this.push(buffer.slice(0, chunkByte))
|
|
25
|
+
buffer = buffer.slice(chunkByte)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
done()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const flush: stream.TransformOptions['flush'] = function (done) {
|
|
32
|
+
if (buffer.length) {
|
|
33
|
+
this.push(buffer)
|
|
34
|
+
}
|
|
35
|
+
done()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const chunker = new stream.Transform({
|
|
39
|
+
flush,
|
|
40
|
+
objectMode: true,
|
|
41
|
+
transform,
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
return chunker
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export {
|
|
48
|
+
sizedChunkTransformer,
|
|
49
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env -S node --no-warnings --loader ts-node/esm
|
|
2
|
+
|
|
3
|
+
import { test } from 'tstest'
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
bufferToQrValue,
|
|
7
|
+
qrValueToStream,
|
|
8
|
+
} from './qrcode.js'
|
|
9
|
+
|
|
10
|
+
test('imageBase64ToQrCode()', async t => {
|
|
11
|
+
const QRCODE_IMAGE_BASE64 = [
|
|
12
|
+
'iVBORw0KGgoAAAANSUhEUgAAAMgAAADIAQMAAACXljzdAAAABlBMVEX///8AAABVwtN+AAAA',
|
|
13
|
+
'CXBIWXMAAA7EAAAOxAGVKw4bAAAA7klEQVRYw+2WsQ3EIAxFjShSMgKjZLRktIzCCJQpIv7Z',
|
|
14
|
+
'hCiXO/qzT/wCWXo0X3wbEw0NWVaEKM187KHW2QLZ+AhpXovfQ+J6skEWHELqBa5NEeCwR7iS',
|
|
15
|
+
'V7BDzuzAiZ9eqn5IWjfWXHf7VCO5tPAM6U9AjSRideyHFn4FiuvDqV5CM9rZXuF2pZmIAjZy',
|
|
16
|
+
'x4S0MDdBxEmu3TrliPf7iglPvuLlRydfU3P70UweCSK+ZYK0mUg1O4AVcv0/8itGkC7SdiTH',
|
|
17
|
+
'0+Mz19oJZ4NkhhSPbIhQkQGI8u1HJzmzs7p7pzNAru2pJb6z8ykkQ0P/pheK6vjurjf7+wAA',
|
|
18
|
+
'AABJRU5ErkJggg==',
|
|
19
|
+
].join('')
|
|
20
|
+
const EXPECTED_QRCODE_TEXT = 'hello, world!'
|
|
21
|
+
|
|
22
|
+
const buf = Buffer.from(QRCODE_IMAGE_BASE64, 'base64')
|
|
23
|
+
const text = await bufferToQrValue(buf)
|
|
24
|
+
t.equal(text, EXPECTED_QRCODE_TEXT, 'should decode qrcode image base64')
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
test('qrValueToStream()', async t => {
|
|
28
|
+
const QRCODE_VALUE = 'hello, world!'
|
|
29
|
+
const EXPECTED_QRCODE_IMAGE_BASE64 = [
|
|
30
|
+
'iVBORw0KGgoAAAANSUhEUgAAAHQAAAB0CAYAAABUmhYnAAAAAklEQVR4AewaftIAAAKcSURBVO3BQY7',
|
|
31
|
+
'cQAwEwSxC//9yeo88NSBIsx7TjIg/WGMUa5RijVKsUYo1SrFGKdYoxRqlWKMUa5RijVKsUYo1SrFGKd',
|
|
32
|
+
'YoxRrl4qEk/CaVkyTcoXKShN+k8kSxRinWKMUa5eJlKm9Kwh0qn6TypiS8qVijFGuUYo1y8WFJuEPlj',
|
|
33
|
+
'iR0Kl0SOpUuCZ3KHUm4Q+WTijVKsUYp1igXw6n8T4o1SrFGKdYoF8MloVOZrFijFGuUYo1y8WEq3yQJ',
|
|
34
|
+
'ncoTKt+kWKMUa5RijXLxsiR8M5UuCZ3KSRK+WbFGKdYoxRrl4iGVf5nKicq/pFijFGuUYo0Sf/BAEjq',
|
|
35
|
+
'VLglvUnkiCZ3KSRLepPJJxRqlWKMUa5SLlyXhROU3JaFT6ZJwonKShCeS0Kk8UaxRijVKsUaJP3hREj',
|
|
36
|
+
'qVO5JwotIloVO5Iwl3qJwk4Q6VNxVrlGKNUqxRLv6yJJyodEl4Igl3qHRJ6FTuUPmkYo1SrFGKNcrFQ',
|
|
37
|
+
'0k4ScITSehUuiScJKFT6ZLQqXRJuEPljiR0Kk8Ua5RijVKsUS4eUvkmSbhDpUvCHUk4UflNxRqlWKMU',
|
|
38
|
+
'a5SLh5Lwm1Q6lS4JdyThCZWTJJyovKlYoxRrlGKNcvEylTcl4SQJnUqXhCdUuiScJOFvKtYoxRqlWKN',
|
|
39
|
+
'cfFgS7lB5k0qXhDuS0Kl0SehUTpLQJaFTeaJYoxRrlGKNcjFcEjqVJ5JwkoROpVP5pGKNUqxRijXKxX',
|
|
40
|
+
'8mCScqXRJOVE6S0Kl8UrFGKdYoxRrl4sNUPknlDpUuCV0SOpWTJHyTYo1SrFGKNcrFy5Lwm5LQqXQqX',
|
|
41
|
+
'RI6lZMkdConKidJ6FTeVKxRijVKsUaJP1hjFGuUYo1SrFGKNUqxRinWKMUapVijFGuUYo1SrFGKNUqx',
|
|
42
|
+
'RinWKMUa5Q8Ztu740xD9iQAAAABJRU5ErkJggg==',
|
|
43
|
+
].join('')
|
|
44
|
+
|
|
45
|
+
const stream = await qrValueToStream(QRCODE_VALUE)
|
|
46
|
+
|
|
47
|
+
const chunks = [] as Buffer[]
|
|
48
|
+
for await (const chunk of stream) {
|
|
49
|
+
chunks.push(chunk as Buffer)
|
|
50
|
+
}
|
|
51
|
+
const buf = Buffer.concat(chunks)
|
|
52
|
+
const base64Text = buf.toString('base64')
|
|
53
|
+
|
|
54
|
+
t.equal(base64Text, EXPECTED_QRCODE_IMAGE_BASE64, 'should encode QR Code value to expected image')
|
|
55
|
+
})
|
package/src/qrcode.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PassThrough,
|
|
3
|
+
Readable,
|
|
4
|
+
} from 'stream'
|
|
5
|
+
|
|
6
|
+
// The npm package of my best choice for QR code decoding on Angular SPA
|
|
7
|
+
// https://dev.to/j_sakamoto/the-npm-package-of-my-best-choice-for-qr-code-decoding-on-angular-spa-4747?returning-user=true
|
|
8
|
+
import Jimp from 'jimp'
|
|
9
|
+
import jsQR from 'jsqr'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* https://www.npmjs.com/package/qrcode
|
|
13
|
+
* Huan(202002): This module is encode only.
|
|
14
|
+
*/
|
|
15
|
+
import { toFileStream } from 'qrcode'
|
|
16
|
+
|
|
17
|
+
export async function bufferToQrValue (buf: Buffer): Promise<string> {
|
|
18
|
+
const image = await Jimp.read(buf)
|
|
19
|
+
const qrCodeImageArray = new Uint8ClampedArray(image.bitmap.data.buffer)
|
|
20
|
+
|
|
21
|
+
const qrCodeResult = jsQR(
|
|
22
|
+
qrCodeImageArray,
|
|
23
|
+
image.bitmap.width,
|
|
24
|
+
image.bitmap.height,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
if (qrCodeResult) {
|
|
28
|
+
return qrCodeResult.data
|
|
29
|
+
} else {
|
|
30
|
+
throw new Error('bufferToQrcode(buf) fail!')
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function qrValueToStream (value: string): Promise<Readable> {
|
|
35
|
+
const stream = new PassThrough()
|
|
36
|
+
await toFileStream(stream, value) // only support .png for now
|
|
37
|
+
return stream
|
|
38
|
+
}
|
package/src/typings.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
declare module 'jsqr'
|