@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.
Files changed (210) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +613 -0
  3. package/dist/cjs/package.json +3 -0
  4. package/dist/cjs/src/config.d.ts +4 -0
  5. package/dist/cjs/src/config.d.ts.map +1 -0
  6. package/dist/cjs/src/config.js +9 -0
  7. package/dist/cjs/src/config.js.map +1 -0
  8. package/dist/cjs/src/file-box.d.ts +209 -0
  9. package/dist/cjs/src/file-box.d.ts.map +1 -0
  10. package/dist/cjs/src/file-box.js +804 -0
  11. package/dist/cjs/src/file-box.js.map +1 -0
  12. package/dist/cjs/src/file-box.spec.d.ts +14 -0
  13. package/dist/cjs/src/file-box.spec.d.ts.map +1 -0
  14. package/dist/cjs/src/file-box.spec.js +393 -0
  15. package/dist/cjs/src/file-box.spec.js.map +1 -0
  16. package/dist/cjs/src/file-box.type.d.ts +103 -0
  17. package/dist/cjs/src/file-box.type.d.ts.map +1 -0
  18. package/dist/cjs/src/file-box.type.js +34 -0
  19. package/dist/cjs/src/file-box.type.js.map +1 -0
  20. package/dist/cjs/src/interface.d.ts +25 -0
  21. package/dist/cjs/src/interface.d.ts.map +1 -0
  22. package/dist/cjs/src/interface.js +3 -0
  23. package/dist/cjs/src/interface.js.map +1 -0
  24. package/dist/cjs/src/interface.spec.d.ts +3 -0
  25. package/dist/cjs/src/interface.spec.d.ts.map +1 -0
  26. package/dist/cjs/src/interface.spec.js +11 -0
  27. package/dist/cjs/src/interface.spec.js.map +1 -0
  28. package/dist/cjs/src/misc.d.ts +17 -0
  29. package/dist/cjs/src/misc.d.ts.map +1 -0
  30. package/dist/cjs/src/misc.js +137 -0
  31. package/dist/cjs/src/misc.js.map +1 -0
  32. package/dist/cjs/src/misc.spec.d.ts +3 -0
  33. package/dist/cjs/src/misc.spec.d.ts.map +1 -0
  34. package/dist/cjs/src/misc.spec.js +51 -0
  35. package/dist/cjs/src/misc.spec.js.map +1 -0
  36. package/dist/cjs/src/mod.d.ts +9 -0
  37. package/dist/cjs/src/mod.d.ts.map +1 -0
  38. package/dist/cjs/src/mod.js +12 -0
  39. package/dist/cjs/src/mod.js.map +1 -0
  40. package/dist/cjs/src/pure-functions/sized-chunk-transformer.d.ts +13 -0
  41. package/dist/cjs/src/pure-functions/sized-chunk-transformer.d.ts.map +1 -0
  42. package/dist/cjs/src/pure-functions/sized-chunk-transformer.js +45 -0
  43. package/dist/cjs/src/pure-functions/sized-chunk-transformer.js.map +1 -0
  44. package/dist/cjs/src/pure-functions/sized-chunk-transformer.spec.d.ts +3 -0
  45. package/dist/cjs/src/pure-functions/sized-chunk-transformer.spec.d.ts.map +1 -0
  46. package/dist/cjs/src/pure-functions/sized-chunk-transformer.spec.js +39 -0
  47. package/dist/cjs/src/pure-functions/sized-chunk-transformer.spec.js.map +1 -0
  48. package/dist/cjs/src/qrcode.d.ts +6 -0
  49. package/dist/cjs/src/qrcode.d.ts.map +1 -0
  50. package/dist/cjs/src/qrcode.js +35 -0
  51. package/dist/cjs/src/qrcode.js.map +1 -0
  52. package/dist/cjs/src/qrcode.spec.d.ts +3 -0
  53. package/dist/cjs/src/qrcode.spec.d.ts.map +1 -0
  54. package/dist/cjs/src/qrcode.spec.js +47 -0
  55. package/dist/cjs/src/qrcode.spec.js.map +1 -0
  56. package/dist/cjs/src/urn-registry/mod.d.ts +3 -0
  57. package/dist/cjs/src/urn-registry/mod.d.ts.map +1 -0
  58. package/dist/cjs/src/urn-registry/mod.js +6 -0
  59. package/dist/cjs/src/urn-registry/mod.js.map +1 -0
  60. package/dist/cjs/src/urn-registry/random-uuid.d.ts +4 -0
  61. package/dist/cjs/src/urn-registry/random-uuid.d.ts.map +1 -0
  62. package/dist/cjs/src/urn-registry/random-uuid.js +30 -0
  63. package/dist/cjs/src/urn-registry/random-uuid.js.map +1 -0
  64. package/dist/cjs/src/urn-registry/uniform-resource-name-registry.d.ts +76 -0
  65. package/dist/cjs/src/urn-registry/uniform-resource-name-registry.d.ts.map +1 -0
  66. package/dist/cjs/src/urn-registry/uniform-resource-name-registry.js +259 -0
  67. package/dist/cjs/src/urn-registry/uniform-resource-name-registry.js.map +1 -0
  68. package/dist/cjs/src/urn-registry/uniform-resource-name-registry.spec.d.ts +3 -0
  69. package/dist/cjs/src/urn-registry/uniform-resource-name-registry.spec.d.ts.map +1 -0
  70. package/dist/cjs/src/urn-registry/uniform-resource-name-registry.spec.js +81 -0
  71. package/dist/cjs/src/urn-registry/uniform-resource-name-registry.spec.js.map +1 -0
  72. package/dist/cjs/src/urn-registry/uuid-to-big-int.d.ts +8 -0
  73. package/dist/cjs/src/urn-registry/uuid-to-big-int.d.ts.map +1 -0
  74. package/dist/cjs/src/urn-registry/uuid-to-big-int.js +16 -0
  75. package/dist/cjs/src/urn-registry/uuid-to-big-int.js.map +1 -0
  76. package/dist/cjs/src/urn-registry/uuid-to-big-int.spec.d.ts +3 -0
  77. package/dist/cjs/src/urn-registry/uuid-to-big-int.spec.d.ts.map +1 -0
  78. package/dist/cjs/src/urn-registry/uuid-to-big-int.spec.js +17 -0
  79. package/dist/cjs/src/urn-registry/uuid-to-big-int.spec.js.map +1 -0
  80. package/dist/cjs/src/version.d.ts +5 -0
  81. package/dist/cjs/src/version.d.ts.map +1 -0
  82. package/dist/cjs/src/version.js +8 -0
  83. package/dist/cjs/src/version.js.map +1 -0
  84. package/dist/cjs/src/version.spec.d.ts +3 -0
  85. package/dist/cjs/src/version.spec.d.ts.map +1 -0
  86. package/dist/cjs/src/version.spec.js +9 -0
  87. package/dist/cjs/src/version.spec.js.map +1 -0
  88. package/dist/cjs/tests/integration.spec.d.ts +3 -0
  89. package/dist/cjs/tests/integration.spec.d.ts.map +1 -0
  90. package/dist/cjs/tests/integration.spec.js +8 -0
  91. package/dist/cjs/tests/integration.spec.js.map +1 -0
  92. package/dist/cjs/tests/network-timeout.spec.d.ts +3 -0
  93. package/dist/cjs/tests/network-timeout.spec.d.ts.map +1 -0
  94. package/dist/cjs/tests/network-timeout.spec.js +121 -0
  95. package/dist/cjs/tests/network-timeout.spec.js.map +1 -0
  96. package/dist/esm/src/config.d.ts +4 -0
  97. package/dist/esm/src/config.d.ts.map +1 -0
  98. package/dist/esm/src/config.js +5 -0
  99. package/dist/esm/src/config.js.map +1 -0
  100. package/dist/esm/src/file-box.d.ts +209 -0
  101. package/dist/esm/src/file-box.d.ts.map +1 -0
  102. package/dist/esm/src/file-box.js +775 -0
  103. package/dist/esm/src/file-box.js.map +1 -0
  104. package/dist/esm/src/file-box.spec.d.ts +14 -0
  105. package/dist/esm/src/file-box.spec.d.ts.map +1 -0
  106. package/dist/esm/src/file-box.spec.js +386 -0
  107. package/dist/esm/src/file-box.spec.js.map +1 -0
  108. package/dist/esm/src/file-box.type.d.ts +103 -0
  109. package/dist/esm/src/file-box.type.d.ts.map +1 -0
  110. package/dist/esm/src/file-box.type.js +31 -0
  111. package/dist/esm/src/file-box.type.js.map +1 -0
  112. package/dist/esm/src/interface.d.ts +25 -0
  113. package/dist/esm/src/interface.d.ts.map +1 -0
  114. package/dist/esm/src/interface.js +2 -0
  115. package/dist/esm/src/interface.js.map +1 -0
  116. package/dist/esm/src/interface.spec.d.ts +3 -0
  117. package/dist/esm/src/interface.spec.d.ts.map +1 -0
  118. package/dist/esm/src/interface.spec.js +9 -0
  119. package/dist/esm/src/interface.spec.js.map +1 -0
  120. package/dist/esm/src/misc.d.ts +17 -0
  121. package/dist/esm/src/misc.d.ts.map +1 -0
  122. package/dist/esm/src/misc.js +126 -0
  123. package/dist/esm/src/misc.js.map +1 -0
  124. package/dist/esm/src/misc.spec.d.ts +3 -0
  125. package/dist/esm/src/misc.spec.d.ts.map +1 -0
  126. package/dist/esm/src/misc.spec.js +49 -0
  127. package/dist/esm/src/misc.spec.js.map +1 -0
  128. package/dist/esm/src/mod.d.ts +9 -0
  129. package/dist/esm/src/mod.d.ts.map +1 -0
  130. package/dist/esm/src/mod.js +6 -0
  131. package/dist/esm/src/mod.js.map +1 -0
  132. package/dist/esm/src/pure-functions/sized-chunk-transformer.d.ts +13 -0
  133. package/dist/esm/src/pure-functions/sized-chunk-transformer.d.ts.map +1 -0
  134. package/dist/esm/src/pure-functions/sized-chunk-transformer.js +39 -0
  135. package/dist/esm/src/pure-functions/sized-chunk-transformer.js.map +1 -0
  136. package/dist/esm/src/pure-functions/sized-chunk-transformer.spec.d.ts +3 -0
  137. package/dist/esm/src/pure-functions/sized-chunk-transformer.spec.d.ts.map +1 -0
  138. package/dist/esm/src/pure-functions/sized-chunk-transformer.spec.js +37 -0
  139. package/dist/esm/src/pure-functions/sized-chunk-transformer.spec.js.map +1 -0
  140. package/dist/esm/src/qrcode.d.ts +6 -0
  141. package/dist/esm/src/qrcode.d.ts.map +1 -0
  142. package/dist/esm/src/qrcode.js +27 -0
  143. package/dist/esm/src/qrcode.js.map +1 -0
  144. package/dist/esm/src/qrcode.spec.d.ts +3 -0
  145. package/dist/esm/src/qrcode.spec.d.ts.map +1 -0
  146. package/dist/esm/src/qrcode.spec.js +45 -0
  147. package/dist/esm/src/qrcode.spec.js.map +1 -0
  148. package/dist/esm/src/urn-registry/mod.d.ts +3 -0
  149. package/dist/esm/src/urn-registry/mod.d.ts.map +1 -0
  150. package/dist/esm/src/urn-registry/mod.js +3 -0
  151. package/dist/esm/src/urn-registry/mod.js.map +1 -0
  152. package/dist/esm/src/urn-registry/random-uuid.d.ts +4 -0
  153. package/dist/esm/src/urn-registry/random-uuid.d.ts.map +1 -0
  154. package/dist/esm/src/urn-registry/random-uuid.js +4 -0
  155. package/dist/esm/src/urn-registry/random-uuid.js.map +1 -0
  156. package/dist/esm/src/urn-registry/uniform-resource-name-registry.d.ts +76 -0
  157. package/dist/esm/src/urn-registry/uniform-resource-name-registry.d.ts.map +1 -0
  158. package/dist/esm/src/urn-registry/uniform-resource-name-registry.js +253 -0
  159. package/dist/esm/src/urn-registry/uniform-resource-name-registry.js.map +1 -0
  160. package/dist/esm/src/urn-registry/uniform-resource-name-registry.spec.d.ts +3 -0
  161. package/dist/esm/src/urn-registry/uniform-resource-name-registry.spec.d.ts.map +1 -0
  162. package/dist/esm/src/urn-registry/uniform-resource-name-registry.spec.js +79 -0
  163. package/dist/esm/src/urn-registry/uniform-resource-name-registry.spec.js.map +1 -0
  164. package/dist/esm/src/urn-registry/uuid-to-big-int.d.ts +8 -0
  165. package/dist/esm/src/urn-registry/uuid-to-big-int.d.ts.map +1 -0
  166. package/dist/esm/src/urn-registry/uuid-to-big-int.js +13 -0
  167. package/dist/esm/src/urn-registry/uuid-to-big-int.js.map +1 -0
  168. package/dist/esm/src/urn-registry/uuid-to-big-int.spec.d.ts +3 -0
  169. package/dist/esm/src/urn-registry/uuid-to-big-int.spec.d.ts.map +1 -0
  170. package/dist/esm/src/urn-registry/uuid-to-big-int.spec.js +15 -0
  171. package/dist/esm/src/urn-registry/uuid-to-big-int.spec.js.map +1 -0
  172. package/dist/esm/src/version.d.ts +5 -0
  173. package/dist/esm/src/version.d.ts.map +1 -0
  174. package/dist/esm/src/version.js +5 -0
  175. package/dist/esm/src/version.js.map +1 -0
  176. package/dist/esm/src/version.spec.d.ts +3 -0
  177. package/dist/esm/src/version.spec.d.ts.map +1 -0
  178. package/dist/esm/src/version.spec.js +7 -0
  179. package/dist/esm/src/version.spec.js.map +1 -0
  180. package/dist/esm/tests/integration.spec.d.ts +3 -0
  181. package/dist/esm/tests/integration.spec.d.ts.map +1 -0
  182. package/dist/esm/tests/integration.spec.js +6 -0
  183. package/dist/esm/tests/integration.spec.js.map +1 -0
  184. package/dist/esm/tests/network-timeout.spec.d.ts +3 -0
  185. package/dist/esm/tests/network-timeout.spec.d.ts.map +1 -0
  186. package/dist/esm/tests/network-timeout.spec.js +119 -0
  187. package/dist/esm/tests/network-timeout.spec.js.map +1 -0
  188. package/package.json +85 -0
  189. package/src/config.ts +5 -0
  190. package/src/file-box.spec.ts +480 -0
  191. package/src/file-box.ts +1042 -0
  192. package/src/file-box.type.ts +145 -0
  193. package/src/interface.spec.ts +17 -0
  194. package/src/interface.ts +47 -0
  195. package/src/misc.spec.ts +70 -0
  196. package/src/misc.ts +157 -0
  197. package/src/mod.ts +33 -0
  198. package/src/pure-functions/sized-chunk-transformer.spec.ts +52 -0
  199. package/src/pure-functions/sized-chunk-transformer.ts +49 -0
  200. package/src/qrcode.spec.ts +55 -0
  201. package/src/qrcode.ts +38 -0
  202. package/src/typings.d.ts +1 -0
  203. package/src/urn-registry/mod.ts +7 -0
  204. package/src/urn-registry/random-uuid.ts +7 -0
  205. package/src/urn-registry/uniform-resource-name-registry.spec.ts +109 -0
  206. package/src/urn-registry/uniform-resource-name-registry.ts +342 -0
  207. package/src/urn-registry/uuid-to-big-int.spec.ts +19 -0
  208. package/src/urn-registry/uuid-to-big-int.ts +16 -0
  209. package/src/version.spec.ts +9 -0
  210. package/src/version.ts +4 -0
package/package.json ADDED
@@ -0,0 +1,85 @@
1
+ {
2
+ "name": "@juzi/file-box",
3
+ "version": "1.7.0",
4
+ "description": "Pack a File into Box for easy move/transfer between servers no matter of where it is.(local path, remote url, or cloud storage)",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "import": "./dist/esm/src/mod.js",
9
+ "require": "./dist/cjs/src/mod.js"
10
+ }
11
+ },
12
+ "typings": "./dist/esm/src/mod.d.ts",
13
+ "engines": {
14
+ "node": ">=16",
15
+ "npm": ">=7"
16
+ },
17
+ "scripts": {
18
+ "clean": "shx rm -fr dist/*",
19
+ "dist": "npm-run-all clean build dist:commonjs",
20
+ "build": "tsc && tsc -p tsconfig.cjs.json",
21
+ "dist:commonjs": "jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json",
22
+ "lint": "npm-run-all lint:es lint:ts",
23
+ "lint:ts": "tsc --isolatedModules --noEmit",
24
+ "test": "npm-run-all lint test:unit",
25
+ "test:unit": "cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap --timeout=90 \"src/**/*.spec.ts\" \"tests/*.spec.ts\"",
26
+ "test:pack": "bash -x scripts/npm-pack-testing.sh",
27
+ "lint:es": "eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\""
28
+ },
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/huan/file-box.git"
32
+ },
33
+ "keywords": [
34
+ "file",
35
+ "virtual",
36
+ "cloud",
37
+ "url",
38
+ "stream",
39
+ "http",
40
+ "api"
41
+ ],
42
+ "author": "Huan LI <zixia@zixia.net>",
43
+ "license": "Apache-2.0",
44
+ "bugs": {
45
+ "url": "https://github.com/huan/file-box/issues"
46
+ },
47
+ "homepage": "https://github.com/huan/file-box#readme",
48
+ "devDependencies": {
49
+ "@chatie/eslint-config": "^1.0.4",
50
+ "@chatie/git-scripts": "^0.6.2",
51
+ "@chatie/semver": "^0.4.7",
52
+ "@chatie/tsconfig": "^4.6.2",
53
+ "@types/isomorphic-fetch": "0.0.35",
54
+ "@types/mime": "^2.0.3",
55
+ "@types/qrcode": "^1.4.1",
56
+ "@types/uuid": "^8.3.3",
57
+ "gts": "^3.1.0",
58
+ "pkg-jq": "^0.2.11",
59
+ "read-pkg-up": "^8.0.0",
60
+ "esquery": "1.4.0",
61
+ "reflect-metadata": "^0.1.13"
62
+ },
63
+ "dependencies": {
64
+ "brolog": "^1.14.2",
65
+ "clone-class": "^1.0.3",
66
+ "jimp": "^0.16.1",
67
+ "jsqr": "^1.4.0",
68
+ "mime": "^3.0.0",
69
+ "qrcode": "^1.5.0",
70
+ "uuid": "^8.3.2"
71
+ },
72
+ "files": [
73
+ "dist",
74
+ "src"
75
+ ],
76
+ "publishConfig": {
77
+ "access": "public",
78
+ "tag": "next"
79
+ },
80
+ "git": {
81
+ "scripts": {
82
+ "pre-push": "npx git-scripts-pre-push"
83
+ }
84
+ }
85
+ }
package/src/config.ts ADDED
@@ -0,0 +1,5 @@
1
+ /// <reference path="./typings.d.ts" />
2
+ export { VERSION } from './version.js'
3
+
4
+ export const HTTP_TIMEOUT = Number(process.env['FILEBOX_HTTP_TIMEOUT'])
5
+ || 60 * 1000
@@ -0,0 +1,480 @@
1
+ #!/usr/bin/env -S node --no-warnings --loader ts-node/esm
2
+
3
+ import 'reflect-metadata'
4
+
5
+ import assert from 'assert'
6
+ import { PassThrough, Readable } from 'stream'
7
+ import { test, sinon } from 'tstest'
8
+ import { instanceToClass } from 'clone-class'
9
+
10
+ import { FileBox } from './file-box.js'
11
+ import { FileBoxType } from './file-box.type.js'
12
+
13
+ const requiredMetadataKey = Symbol('required')
14
+
15
+ const tstest = {
16
+ classFixture () {
17
+ return (constructor: Function) => {
18
+ console.info(constructor.name)
19
+ console.info(constructor.prototype.name)
20
+ }
21
+ },
22
+ methodFixture () {
23
+ return (
24
+ ..._: any[]
25
+ // target : Object,
26
+ // propertyKey : string,
27
+ // descriptor : PropertyDescriptor,
28
+ ) => {
29
+ console.info('@fixture()')
30
+ }
31
+ },
32
+ parameterFixture () {
33
+ return (target: object, propertyKey: string | symbol, parameterIndex: number) => {
34
+ console.info(propertyKey)
35
+ const existingRequiredParameters: number[] = Reflect.getOwnMetadata(requiredMetadataKey, target, propertyKey) || []
36
+ existingRequiredParameters.push(parameterIndex)
37
+ Reflect.defineMetadata(requiredMetadataKey, existingRequiredParameters, target, propertyKey)
38
+ }
39
+ },
40
+ }
41
+
42
+ test('File smoke testing', async t => {
43
+ t.throws(() => FileBox.fromFile('x'), 'should throw for a non-existing file')
44
+ })
45
+
46
+ @tstest.classFixture()
47
+ export class FixtureFileBox {
48
+
49
+ @tstest.methodFixture()
50
+ public static localFileFixture () {
51
+ return {
52
+ content: 'T',
53
+ name: 'test.txt',
54
+ size: '1',
55
+ type: 'plain/text',
56
+ }
57
+ }
58
+
59
+ }
60
+
61
+ // tslint:disable:max-classes-per-file
62
+
63
+ export class TestFileBox {
64
+
65
+ public static testFileCreateLocal (
66
+ @tstest.parameterFixture() localFileFixture: any,
67
+ ) {
68
+ const file = FileBox.fromFile(localFileFixture)
69
+
70
+ test('File.createLocal()', async t => {
71
+ t.ok(file, 'ok')
72
+
73
+ })
74
+
75
+ test('File.fromRemote()', async t => {
76
+ const URL = 'http://httpbin.org/response-headers?Content-Type=text/plain;%20charset=UTF-8&Content-Disposition=attachment;%20filename%3d%22test.json%22'
77
+ assert(URL)
78
+ t.pass('ok')
79
+ })
80
+
81
+ }
82
+
83
+ }
84
+
85
+ test('toBase64()', async t => {
86
+ const BASE64_DECODED = 'FileBoxBase64\n'
87
+ const BASE64_ENCODED = 'RmlsZUJveEJhc2U2NAo='
88
+
89
+ const fileBox = FileBox.fromBase64(BASE64_ENCODED, 'test.txt')
90
+ const base64 = await fileBox.toBase64()
91
+
92
+ t.equal(base64, BASE64_ENCODED, 'should get base64 back')
93
+
94
+ const text = Buffer.from(base64, 'base64').toString()
95
+ t.equal(text, BASE64_DECODED, 'should get the text right')
96
+ })
97
+
98
+ test('fromBuffer() & toBase64()', async t => {
99
+ const BASE64_ENCODED = 'RmlsZUJveEJhc2U2NAo='
100
+
101
+ const buffer = Buffer.from(BASE64_ENCODED, 'base64')
102
+ const fileBox = FileBox.fromBuffer(buffer, 'test.txt')
103
+ const base64 = await fileBox.toBase64()
104
+
105
+ t.equal(base64, BASE64_ENCODED, 'should get base64 back from buffer')
106
+ })
107
+
108
+ test('syncRemote()', async t => {
109
+ class FileBoxTest extends FileBox {
110
+
111
+ static override fromUrl (...args: any[]): FileBoxTest { return (super.fromUrl as any)(...args) }
112
+ override _syncUrlMetadata () { return super._syncUrlMetadata() }
113
+
114
+ }
115
+
116
+ const URL = 'http://httpbin.org/response-headers?Content-Disposition=attachment;%20filename%3d%22test.txt%22&filename=test.txt'
117
+
118
+ const EXPECTED_NAME_FROM_URL = 'response-headers'
119
+ const EXPECTED_TYPE_FROM_URL = 'application/unknown'
120
+
121
+ const EXPECTED_NAME_FROM_HEADER = 'test.txt'
122
+ const EXPECTED_SIZE_FROM_HEADER = 159
123
+ const EXPECTED_TYPE_FROM_HEADER = 'application/json'
124
+
125
+ const fileBox = FileBoxTest.fromUrl(URL)
126
+
127
+ t.equal(fileBox.name, EXPECTED_NAME_FROM_URL, 'should get the name from url')
128
+ t.equal(fileBox.mediaType, EXPECTED_TYPE_FROM_URL, 'should get the mime type from url')
129
+
130
+ await fileBox._syncUrlMetadata()
131
+
132
+ t.equal(fileBox.size, EXPECTED_SIZE_FROM_HEADER, 'should get the size from remote header')
133
+ t.equal(fileBox.name, EXPECTED_NAME_FROM_HEADER, 'should get the name from remote header')
134
+ t.equal(fileBox.mediaType, EXPECTED_TYPE_FROM_HEADER, 'should get the mime type from remote http header')
135
+ })
136
+
137
+ test('fromURL() deal with url with querystring', async t => {
138
+ const URL = 'https://zixia.net/a.jpg?name=value&t=1324'
139
+ const EXPECTED_NAME = 'a.jpg'
140
+
141
+ const fileBox = FileBox.fromUrl(URL)
142
+ t.equal(fileBox.name, EXPECTED_NAME, 'should get basename from url with querystring')
143
+ })
144
+
145
+ test('toDataURL()', async t => {
146
+ const FILE_PATH = 'tests/fixtures/data.bin'
147
+ const EXPECTED_DATA_URL = 'data:application/octet-stream;base64,dGVzdA=='
148
+
149
+ const fileBox = FileBox.fromFile(FILE_PATH)
150
+
151
+ const dataUrl = await fileBox.toDataURL()
152
+
153
+ t.equal(dataUrl, EXPECTED_DATA_URL, 'should get the data url right')
154
+ })
155
+
156
+ test('toString()', async t => {
157
+ const FILE_PATH = 'tests/fixtures/data.bin'
158
+ const EXPECT_STRING = 'FileBox#File<data.bin>'
159
+
160
+ const fileBox = FileBox.fromFile(FILE_PATH)
161
+ t.equal(fileBox.toString(), EXPECT_STRING, 'should get the toString() result')
162
+ })
163
+
164
+ test('toBuffer()', async t => {
165
+ const FILE_PATH = 'tests/fixtures/data.bin'
166
+ const EXPECT_STRING = 'test'
167
+
168
+ const fileBox = FileBox.fromFile(FILE_PATH)
169
+ const buffer = await fileBox.toBuffer()
170
+
171
+ t.equal(buffer.toString(), EXPECT_STRING, 'should get the toBuffer() result')
172
+ })
173
+
174
+ /**
175
+ * Huan(202106): we keep this unit test for trying to figure out which operation system can support this long file name.
176
+ * See: https://github.com/huan/file-box/issues/58
177
+ */
178
+ test('toFile() with long name', async t => {
179
+ const IMAGE_URL = 'https://s3.cn-north-1.amazonaws.com.cn/xiaoju-material/public/5ffd393fc503f00039101dae_1620978346435_%E7%94%B5%E6%B1%A0%E5%9E%8B%E5%8F%B7%09%E8%BF%9B%E8%B4%A7%E4%BB%B7%E6%A0%BC%09%E5%8E%9F%E5%94%AE%E5%90%8E%E8%A1%A5%E6%AC%BE%E4%BB%B7%E6%A0%BC%09%E7%8E%B0%E5%85%AC%E5%8F%B8%E6%89%BF%E6%8B%85%E4%B8%80%E5%8D%8A%E7%9A%84%E4%BB%B7%E6%A0%BC%0AZD-20-100%09420%09270%09135%0AZD-Q85-D23L%09360%09270%09135%0AZD-H6-L3%09420%09315%09157.5%0A%E6%80%BB%E8%AE%A1%EF%BC%9A%091200%09855%09427.5%0A'
180
+
181
+ const linux = {
182
+ code : 'ENAMETOOLONG',
183
+ errno : -36,
184
+ syscall : 'open',
185
+ }
186
+ const darwin = {
187
+ code : 'ENAMETOOLONG',
188
+ errno : -63,
189
+ syscall : 'open',
190
+ }
191
+ const win32 = {
192
+ code : 'ENOENT',
193
+ errno : -4058,
194
+ syscall : 'open',
195
+ }
196
+
197
+ const FIXTURE_ERROR: {
198
+ [key in typeof process.platform]?: Object
199
+ } = {
200
+ darwin,
201
+ linux,
202
+ win32,
203
+ }
204
+
205
+ const fileBox = FileBox.fromUrl(IMAGE_URL)
206
+ await t.rejects(
207
+ fileBox.toFile(),
208
+ FIXTURE_ERROR[process.platform],
209
+ `should reject toFile() with ${JSON.stringify(FIXTURE_ERROR[process.platform])}`,
210
+ )
211
+ })
212
+
213
+ test('metadata', async t => {
214
+ const FILE_PATH = 'tests/fixtures/data.bin'
215
+
216
+ const EXPECTED_NAME = 'myname'
217
+ const EXPECTED_AGE = 'myage'
218
+ const EXPECTED_MOL = 42
219
+
220
+ // interface MetadataType {
221
+ // metaname : string,
222
+ // metaage : number,
223
+ // metaobj: {
224
+ // mol: number,
225
+ // }
226
+ // }
227
+
228
+ const EXPECTED_METADATA = {
229
+ metaage: EXPECTED_AGE,
230
+ metaname: EXPECTED_NAME,
231
+ metaobj: {
232
+ mol: EXPECTED_MOL,
233
+ },
234
+ }
235
+
236
+ const fileBox = FileBox.fromFile(FILE_PATH)
237
+
238
+ t.same((fileBox as FileBox).metadata, {}, 'should get a empty {} if not set')
239
+
240
+ t.doesNotThrow(
241
+ () => {
242
+ (fileBox as FileBox).metadata = EXPECTED_METADATA
243
+ },
244
+ 'should not throw for set metadata for the first time',
245
+ )
246
+
247
+ t.throws(
248
+ () => {
249
+ (fileBox as FileBox).metadata = EXPECTED_METADATA
250
+ },
251
+ 'should throw for set metadata again',
252
+ )
253
+
254
+ t.throws(
255
+ () => {
256
+ (fileBox as FileBox).metadata['mol'] = EXPECTED_MOL
257
+ },
258
+ 'should throw for change value of a property on metadata',
259
+ )
260
+
261
+ t.same((fileBox as FileBox).metadata, EXPECTED_METADATA, 'should get the metadata')
262
+ })
263
+
264
+ test('fromQRCode()', async t => {
265
+ const QRCODE_VALUE = 'hello, world!'
266
+ const EXPECTED_QRCODE_IMAGE_BASE64 = [
267
+ 'iVBORw0KGgoAAAANSUhEUgAAAHQAAAB0CAYAAABUmhYnAAAAAklEQVR4AewaftIAAAKcSURBVO3BQY7',
268
+ 'cQAwEwSxC//9yeo88NSBIsx7TjIg/WGMUa5RijVKsUYo1SrFGKdYoxRqlWKMUa5RijVKsUYo1SrFGKd',
269
+ 'YoxRrl4qEk/CaVkyTcoXKShN+k8kSxRinWKMUa5eJlKm9Kwh0qn6TypiS8qVijFGuUYo1y8WFJuEPlj',
270
+ 'iR0Kl0SOpUuCZ3KHUm4Q+WTijVKsUYp1igXw6n8T4o1SrFGKdYoF8MloVOZrFijFGuUYo1y8WEq3yQJ',
271
+ 'ncoTKt+kWKMUa5RijXLxsiR8M5UuCZ3KSRK+WbFGKdYoxRrl4iGVf5nKicq/pFijFGuUYo0Sf/BAEjq',
272
+ 'VLglvUnkiCZ3KSRLepPJJxRqlWKMUa5SLlyXhROU3JaFT6ZJwonKShCeS0Kk8UaxRijVKsUaJP3hREj',
273
+ 'qVO5JwotIloVO5Iwl3qJwk4Q6VNxVrlGKNUqxRLv6yJJyodEl4Igl3qHRJ6FTuUPmkYo1SrFGKNcrFQ',
274
+ '0k4ScITSehUuiScJKFT6ZLQqXRJuEPljiR0Kk8Ua5RijVKsUS4eUvkmSbhDpUvCHUk4UflNxRqlWKMU',
275
+ 'a5SLh5Lwm1Q6lS4JdyThCZWTJJyovKlYoxRrlGKNcvEylTcl4SQJnUqXhCdUuiScJOFvKtYoxRqlWKN',
276
+ 'cfFgS7lB5k0qXhDuS0Kl0SehUTpLQJaFTeaJYoxRrlGKNcjFcEjqVJ5JwkoROpVP5pGKNUqxRijXKxX',
277
+ '8mCScqXRJOVE6S0Kl8UrFGKdYoxRrl4sNUPknlDpUuCV0SOpWTJHyTYo1SrFGKNcrFy5Lwm5LQqXQqX',
278
+ 'RI6lZMkdConKidJ6FTeVKxRijVKsUaJP1hjFGuUYo1SrFGKNUqxRinWKMUapVijFGuUYo1SrFGKNUqx',
279
+ 'RinWKMUa5Q8Ztu740xD9iQAAAABJRU5ErkJggg==',
280
+ ].join('')
281
+
282
+ const fileBox = FileBox.fromQRCode(QRCODE_VALUE)
283
+ const base64Text = await fileBox.toBase64()
284
+
285
+ t.equal(base64Text, EXPECTED_QRCODE_IMAGE_BASE64, 'should encode QR Code value to expected image')
286
+ })
287
+
288
+ test('toQRCode()', async t => {
289
+ const QRCODE_IMAGE_BASE64 = [
290
+ 'iVBORw0KGgoAAAANSUhEUgAAAMgAAADIAQMAAACXljzdAAAABlBMVEX///8AAABVwtN+AAAA',
291
+ 'CXBIWXMAAA7EAAAOxAGVKw4bAAAA7klEQVRYw+2WsQ3EIAxFjShSMgKjZLRktIzCCJQpIv7Z',
292
+ 'hCiXO/qzT/wCWXo0X3wbEw0NWVaEKM187KHW2QLZ+AhpXovfQ+J6skEWHELqBa5NEeCwR7iS',
293
+ 'V7BDzuzAiZ9eqn5IWjfWXHf7VCO5tPAM6U9AjSRideyHFn4FiuvDqV5CM9rZXuF2pZmIAjZy',
294
+ 'x4S0MDdBxEmu3TrliPf7iglPvuLlRydfU3P70UweCSK+ZYK0mUg1O4AVcv0/8itGkC7SdiTH',
295
+ '0+Mz19oJZ4NkhhSPbIhQkQGI8u1HJzmzs7p7pzNAru2pJb6z8ykkQ0P/pheK6vjurjf7+wAA',
296
+ 'AABJRU5ErkJggg==',
297
+ ].join('')
298
+ const EXPECTED_QRCODE_TEXT = 'hello, world!'
299
+
300
+ const fileBox = FileBox.fromBase64(QRCODE_IMAGE_BASE64, 'qrcode.png')
301
+ const qrCodeValue = await fileBox.toQRCode()
302
+
303
+ t.equal(qrCodeValue, EXPECTED_QRCODE_TEXT, 'should decode qrcode image base64 to qr code value')
304
+ })
305
+
306
+ test('toJSON()', async t => {
307
+ // const BASE64_DECODED = 'FileBoxBase64\n'
308
+ const BASE64_ENCODED = 'RmlsZUJveEJhc2U2NAo='
309
+ const BASE64_FILENAME = 'test.txt'
310
+
311
+ /**
312
+ * Huan(202111): we have both `type` and `boxType` is because the compatible issue #73
313
+ * @see https://github.com/huan/file-box/issues/73
314
+ */
315
+ const EXPECTED_JSON_TEXT = '{"metadata":{},"name":"test.txt","size":14,"base64":"RmlsZUJveEJhc2U2NAo=","type":1,"boxType":1}'
316
+
317
+ const fileBox = FileBox.fromBase64(BASE64_ENCODED, BASE64_FILENAME)
318
+ const jsonText = JSON.stringify(fileBox)
319
+
320
+ t.equal(jsonText, EXPECTED_JSON_TEXT, 'should get expected json text')
321
+
322
+ const newFileBox = FileBox.fromJSON(jsonText)
323
+ const newBase64 = await newFileBox.toBase64()
324
+
325
+ t.equal(newBase64, BASE64_ENCODED, 'should get base64 back')
326
+ })
327
+
328
+ test('toJSON() for not supported type', async t => {
329
+ const BASE64_ENCODED = 'RmlsZUJveEJhc2U2NAo='
330
+
331
+ const buffer = Buffer.from(BASE64_ENCODED, 'base64')
332
+ const fileBox = FileBox.fromBuffer(buffer, 'test.txt')
333
+
334
+ t.equal(fileBox.type, FileBoxType.Buffer, 'should get type() as Buffer')
335
+ t.throws(() => JSON.stringify(fileBox), 'should throw for buffer type of FileBox')
336
+ })
337
+
338
+ /**
339
+ * Issue #50: Stream can not be consumed twice
340
+ * https://github.com/huan/file-box/issues/50
341
+ */
342
+ test('toStream() twice for a stream', async t => {
343
+ const stream = new PassThrough()
344
+ const box = FileBox.fromStream(stream, 'hello.dat')
345
+
346
+ stream.end('hello, world!')
347
+
348
+ // consume it
349
+ await t.resolves(box.toBase64(), 'should successful to read the stream for the first time')
350
+
351
+ // consume it twice
352
+ await t.rejects(box.toBuffer(), 'should throw when the file-box be consumed twice')
353
+ })
354
+
355
+ test('toUuid()', async t => {
356
+ const BASE64_ENCODED = 'RmlsZUJveEJhc2U2NAo='
357
+ const UUID = '12345678-1234-1234-1234-123456789012'
358
+
359
+ class FileBoxTest extends FileBox {}
360
+
361
+ const buffer = Buffer.from(BASE64_ENCODED, 'base64')
362
+ const fileBox = FileBoxTest.fromBuffer(buffer, 'test.txt')
363
+
364
+ await t.rejects(fileBox.toUuid(), 'should reject without `FileBox.setUuidSaver()` call`')
365
+
366
+ FileBoxTest.setUuidSaver(() => Promise.resolve(UUID))
367
+ t.equal(await fileBox.toUuid(), UUID, `should get UUID: ${UUID}`)
368
+ })
369
+
370
+ test('fromUuid()', async t => {
371
+ const UUID = '12345678-1234-1234-1234-123456789012'
372
+ const TEXT = 'hello, world!'
373
+
374
+ class FileBoxTest extends FileBox {}
375
+
376
+ const stream = new PassThrough()
377
+ stream.end(TEXT)
378
+
379
+ const uuidBox = FileBoxTest.fromUuid(UUID, { name: 'test.txt' })
380
+
381
+ await t.rejects(uuidBox.toBase64(), 'should reject without `FileBox.setUuidLoader()` call`')
382
+
383
+ FileBoxTest.setUuidLoader((_: string) => Promise.resolve(stream))
384
+ t.equal((await uuidBox.toBuffer()).toString(), TEXT, `should get BASE64: ${TEXT}`)
385
+ })
386
+
387
+ test('setUuidLoader()', async t => {
388
+ class FileBoxTest1 extends FileBox {}
389
+ class FileBoxTest2 extends FileBox {}
390
+
391
+ t.doesNotThrow(() => FileBoxTest1.setUuidLoader((_: string) => ({} as any)), 'should not throw for set loader for the first time')
392
+ t.throws(() => FileBoxTest1.setUuidLoader((_: string) => ({} as any)), 'should throw for set loader twice')
393
+
394
+ t.doesNotThrow(() => FileBoxTest2.setUuidLoader((_: string) => ({} as any)), 'should not throw for set loader for the first time')
395
+ t.throws(() => FileBoxTest2.setUuidLoader((_: string) => ({} as any)), 'should throw for set loader twice')
396
+ })
397
+
398
+ test('setUuidSaver()', async t => {
399
+ class FileBoxTest1 extends FileBox {}
400
+ class FileBoxTest2 extends FileBox {}
401
+
402
+ t.doesNotThrow(() => FileBoxTest1.setUuidSaver((_: Readable) => Promise.resolve('uuid')), 'should not throw for set loader for the first time')
403
+ t.throws(() => FileBoxTest1.setUuidSaver((_: Readable) => Promise.resolve('uuid')), 'should throw for set loader twice')
404
+
405
+ t.doesNotThrow(() => FileBoxTest2.setUuidSaver((_: Readable) => Promise.resolve('uuid')), 'should not throw for set loader for the first time')
406
+ t.throws(() => FileBoxTest2.setUuidSaver((_: Readable) => Promise.resolve('uuid')), 'should throw for set loader twice')
407
+ })
408
+
409
+ test('setUuidLoader() & setUuidSsaver() with `this`', async t => {
410
+ const sandbox = sinon.createSandbox()
411
+
412
+ const loader = sandbox.stub()
413
+ .returns(await FileBox.fromQRCode('qr').toStream())
414
+ const saver = sandbox.stub()
415
+ .returns('uuid')
416
+
417
+ class FileBoxTest extends FileBox {}
418
+
419
+ FileBoxTest.setUuidLoader(loader)
420
+ FileBoxTest.setUuidSaver(saver)
421
+
422
+ const fileBox = FileBoxTest.fromUuid('uuid', { name: 'test.txt' })
423
+ await fileBox.toBuffer()
424
+ t.equal(loader.thisValues[0], fileBox, 'should call loader with `this`')
425
+
426
+ const fileBox2 = FileBoxTest.fromBuffer(Buffer.from('test'), 'test.txt')
427
+ await fileBox2.toUuid()
428
+ t.equal(saver.thisValues[0], fileBox2, 'should call saver with `this`')
429
+ })
430
+
431
+ test('FileBox.validInterface()', async t => {
432
+ const fileBox = FileBox.fromQRCode('test')
433
+ /**
434
+ * 2 OK
435
+ */
436
+ t.ok(FileBox.validInstance(fileBox), 'should satisfy instance validation for a FileBox instance')
437
+ t.ok(FileBox.validInterface(fileBox), 'should satisfy interface validation for a FileBox instance')
438
+ t.ok(FileBox.valid(fileBox), 'should satisfy interface validation')
439
+ t.ok(fileBox instanceof FileBox, 'should be instance of FileBox')
440
+
441
+ const copy = {} as any
442
+ Object.getOwnPropertyNames(
443
+ Object.getPrototypeOf(fileBox),
444
+ ).forEach(prop => {
445
+ copy[prop] = (fileBox as FileBox)[prop as keyof FileBox]
446
+ })
447
+
448
+ function NOT_FILE_BOX_CONSTRUCTOR () {}
449
+ const target = {
450
+ ...copy,
451
+ constructor: NOT_FILE_BOX_CONSTRUCTOR,
452
+ }
453
+
454
+ /**
455
+ * 1 OK, 1 NG
456
+ */
457
+ t.ok(FileBox.validInstance(target), 'should pass instance validation instance test')
458
+ t.ok(FileBox.validInterface(target), 'should pass interface validation for an object with FileBox properties')
459
+ t.ok(FileBox.valid(target), 'should satisfy interface validation')
460
+ t.ok(target instanceof FileBox, 'should be instance of FileBox')
461
+
462
+ /**
463
+ * 2 NG
464
+ */
465
+ delete target.size
466
+ t.notOk(FileBox.validInterface(target), 'should not be a valid interface if it lack any property')
467
+ t.notOk(FileBox.valid(target), 'should not satisfy interface validation')
468
+ })
469
+
470
+ test('fromJSON() should keep class', async t => {
471
+ const JSON_TEXT = '{"metadata":{},"name":"smoke-testing.ts","size":735,"type":7,"uuid":"82f461b9-e654-422d-aade-222d05cb02ad","boxType":7}'
472
+
473
+ class FileBoxUuid extends FileBox {}
474
+ FileBoxUuid.setUuidLoader(() => ({} as any))
475
+ FileBoxUuid.setUuidSaver(() => ({} as any))
476
+
477
+ const fileBoxUuid = FileBoxUuid.fromJSON(JSON_TEXT)
478
+ const FromJsonKlass = instanceToClass(fileBoxUuid, FileBox)
479
+ t.equal(FromJsonKlass, FileBoxUuid, 'should get back FileBoxUuid class')
480
+ })