@ditojs/server 1.23.0 → 1.24.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 +13 -14
- package/src/app/Application.js +3 -3
- package/src/models/Model.js +2 -2
- package/src/storage/AssetFile.js +5 -3
- package/src/storage/DiskStorage.js +2 -2
- package/src/storage/S3Storage.js +38 -10
- package/src/storage/Storage.js +4 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ditojs/server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.24.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Dito.js Server – Dito.js is a declarative and modern web framework, based on Objection.js, Koa.js and Vue.js",
|
|
6
6
|
"repository": "https://github.com/ditojs/dito/tree/master/packages/server",
|
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
"node >= 18"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@ditojs/admin": "^1.
|
|
26
|
-
"@ditojs/build": "^1.
|
|
27
|
-
"@ditojs/router": "^1.
|
|
28
|
-
"@ditojs/utils": "^1.
|
|
25
|
+
"@ditojs/admin": "^1.24.0",
|
|
26
|
+
"@ditojs/build": "^1.24.0",
|
|
27
|
+
"@ditojs/router": "^1.24.0",
|
|
28
|
+
"@ditojs/utils": "^1.24.0",
|
|
29
29
|
"@koa/cors": "^4.0.0",
|
|
30
30
|
"@koa/multer": "^3.0.2",
|
|
31
31
|
"@originjs/vite-plugin-commonjs": "^1.0.3",
|
|
@@ -35,9 +35,8 @@
|
|
|
35
35
|
"bytes": "^3.1.2",
|
|
36
36
|
"data-uri-to-buffer": "^4.0.1",
|
|
37
37
|
"eventemitter2": "^6.4.9",
|
|
38
|
-
"file-type": "^18.2.
|
|
38
|
+
"file-type": "^18.2.1",
|
|
39
39
|
"image-size": "^1.0.2",
|
|
40
|
-
"is-svg": "^4.3.2",
|
|
41
40
|
"koa": "^2.14.1",
|
|
42
41
|
"koa-bodyparser": "^4.3.0",
|
|
43
42
|
"koa-compose": "^4.1.0",
|
|
@@ -59,12 +58,12 @@
|
|
|
59
58
|
"passthrough-counter": "^1.0.0",
|
|
60
59
|
"picocolors": "^1.0.0",
|
|
61
60
|
"picomatch": "^2.3.1",
|
|
62
|
-
"pino": "^8.
|
|
63
|
-
"pino-pretty": "^9.
|
|
61
|
+
"pino": "^8.11.0",
|
|
62
|
+
"pino-pretty": "^9.4.0",
|
|
64
63
|
"pluralize": "^8.0.0",
|
|
65
64
|
"repl": "^0.1.3",
|
|
66
65
|
"uuid": "^9.0.0",
|
|
67
|
-
"vite": "^4.1.
|
|
66
|
+
"vite": "^4.1.4",
|
|
68
67
|
"vite-plugin-vue2": "^2.0.3",
|
|
69
68
|
"vue": "^2.7.14",
|
|
70
69
|
"vue-template-compiler": "^2.7.14"
|
|
@@ -83,15 +82,15 @@
|
|
|
83
82
|
"@types/koa-response-time": "^2.1.2",
|
|
84
83
|
"@types/koa-session": "^5.10.6",
|
|
85
84
|
"@types/koa-static": "^4.0.2",
|
|
86
|
-
"@types/koa__cors": "^3.3.
|
|
87
|
-
"@types/node": "^18.
|
|
85
|
+
"@types/koa__cors": "^3.3.1",
|
|
86
|
+
"@types/node": "^18.14.2",
|
|
88
87
|
"knex": "^2.4.2",
|
|
89
88
|
"objection": "^3.0.1",
|
|
90
|
-
"type-fest": "^3.
|
|
89
|
+
"type-fest": "^3.6.1",
|
|
91
90
|
"typescript": "^4.9.5"
|
|
92
91
|
},
|
|
93
92
|
"types": "types",
|
|
94
|
-
"gitHead": "
|
|
93
|
+
"gitHead": "0ca96ce0335509daa9ebbac278ae2d346015baad",
|
|
95
94
|
"scripts": {
|
|
96
95
|
"types": "tsc --noEmit ./src/index.d.ts"
|
|
97
96
|
},
|
package/src/app/Application.js
CHANGED
|
@@ -706,7 +706,7 @@ export class Application extends Koa {
|
|
|
706
706
|
this.on('error', this.logError)
|
|
707
707
|
}
|
|
708
708
|
// It's ok to call this multiple times, because only the entries in the
|
|
709
|
-
//
|
|
709
|
+
// registers (storages, services, models, controllers) that weren't
|
|
710
710
|
// initialized yet will be initialized.
|
|
711
711
|
await this.setup()
|
|
712
712
|
await this.emit('before:start')
|
|
@@ -797,7 +797,7 @@ export class Application extends Koa {
|
|
|
797
797
|
return null
|
|
798
798
|
}
|
|
799
799
|
|
|
800
|
-
async
|
|
800
|
+
async handleAddedAndRemovedAssets(
|
|
801
801
|
storage,
|
|
802
802
|
addedFiles,
|
|
803
803
|
removedFiles,
|
|
@@ -808,7 +808,7 @@ export class Application extends Koa {
|
|
|
808
808
|
cleanupTimeThreshold = 0
|
|
809
809
|
} = {}
|
|
810
810
|
} = this.config
|
|
811
|
-
// Only remove unused assets that haven't seen changes for given
|
|
811
|
+
// Only remove unused assets that haven't seen changes for given time frame.
|
|
812
812
|
const timeThreshold = isString(cleanupTimeThreshold)
|
|
813
813
|
? parseDuration(cleanupTimeThreshold)
|
|
814
814
|
: cleanupTimeThreshold
|
package/src/models/Model.js
CHANGED
|
@@ -985,14 +985,14 @@ export class Model extends objection.Model {
|
|
|
985
985
|
const removedFiles = beforeFiles.filter(file => !afterByKey[file.key])
|
|
986
986
|
const addedFiles = afterFiles.filter(file => !beforeByKey[file.key])
|
|
987
987
|
// Also handle modified files, which are files where the data property
|
|
988
|
-
// is changed before update / patch,
|
|
988
|
+
// is changed before update / patch, meaning the file is changed.
|
|
989
989
|
// NOTE: This will change the content for all the references to it,
|
|
990
990
|
// and thus should only really be used when there's only one reference.
|
|
991
991
|
const modifiedFiles = afterFiles.filter(
|
|
992
992
|
file => file.data && beforeByKey[file.key]
|
|
993
993
|
)
|
|
994
994
|
importedFiles.push(
|
|
995
|
-
...await this.app.
|
|
995
|
+
...await this.app.handleAddedAndRemovedAssets(
|
|
996
996
|
storage,
|
|
997
997
|
addedFiles,
|
|
998
998
|
removedFiles,
|
package/src/storage/AssetFile.js
CHANGED
|
@@ -8,11 +8,13 @@ const SYMBOL_STORAGE = Symbol('storage')
|
|
|
8
8
|
const SYMBOL_DATA = Symbol('data')
|
|
9
9
|
|
|
10
10
|
export class AssetFile {
|
|
11
|
-
constructor(name, data, type) {
|
|
11
|
+
constructor({ name, data, type, width, height }) {
|
|
12
12
|
this.key = AssetFile.getUniqueKey(name)
|
|
13
13
|
this.name = name
|
|
14
14
|
// Set `type` before `data`, so it can be used as default in `set data`
|
|
15
15
|
this.type = type
|
|
16
|
+
this.width = width
|
|
17
|
+
this.height = height
|
|
16
18
|
this.data = data
|
|
17
19
|
}
|
|
18
20
|
|
|
@@ -60,8 +62,8 @@ export class AssetFile {
|
|
|
60
62
|
return object
|
|
61
63
|
}
|
|
62
64
|
|
|
63
|
-
static create(
|
|
64
|
-
return new AssetFile(
|
|
65
|
+
static create(options) {
|
|
66
|
+
return new AssetFile(options)
|
|
65
67
|
}
|
|
66
68
|
|
|
67
69
|
static getUniqueKey(name) {
|
|
@@ -38,11 +38,11 @@ export class DiskStorage extends Storage {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
// @override
|
|
41
|
-
async _addFile(file,
|
|
41
|
+
async _addFile(file, data) {
|
|
42
42
|
const filePath = this._getFilePath(file)
|
|
43
43
|
const dir = path.dirname(filePath)
|
|
44
44
|
await fs.mkdir(dir, { recursive: true })
|
|
45
|
-
await fs.writeFile(filePath,
|
|
45
|
+
await fs.writeFile(filePath, data)
|
|
46
46
|
return file
|
|
47
47
|
}
|
|
48
48
|
|
package/src/storage/S3Storage.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import multerS3 from 'multer-s3'
|
|
2
2
|
import { fileTypeFromBuffer } from 'file-type'
|
|
3
|
-
import isSvg from 'is-svg'
|
|
4
3
|
import { Storage } from './Storage.js'
|
|
5
4
|
import { PassThrough } from 'stream'
|
|
6
5
|
import consumers from 'stream/consumers'
|
|
6
|
+
import imageSize from 'image-size'
|
|
7
7
|
|
|
8
8
|
export class S3Storage extends Storage {
|
|
9
9
|
static type = 's3'
|
|
@@ -56,7 +56,7 @@ export class S3Storage extends Storage {
|
|
|
56
56
|
const onData = chunk => {
|
|
57
57
|
if (!data) {
|
|
58
58
|
// 2. Try reading the mimetype from the first chunk.
|
|
59
|
-
const type =
|
|
59
|
+
const type = getFileTypeFromBuffer(chunk)
|
|
60
60
|
if (type) {
|
|
61
61
|
stream.off('data', onData)
|
|
62
62
|
done(type)
|
|
@@ -64,11 +64,9 @@ export class S3Storage extends Storage {
|
|
|
64
64
|
// 3. If that fails, keep collecting all chunks and determine
|
|
65
65
|
// the mimetype using the full data.
|
|
66
66
|
stream.once('end', () => {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
(isSvg(data) ? 'image/svg+xml' : 'application/octet-stream')
|
|
67
|
+
done(
|
|
68
|
+
getFileTypeFromBuffer(data) || 'application/octet-stream'
|
|
70
69
|
)
|
|
71
|
-
done(type)
|
|
72
70
|
})
|
|
73
71
|
}
|
|
74
72
|
}
|
|
@@ -107,19 +105,19 @@ export class S3Storage extends Storage {
|
|
|
107
105
|
}
|
|
108
106
|
|
|
109
107
|
// @override
|
|
110
|
-
async _addFile(file,
|
|
111
|
-
const
|
|
108
|
+
async _addFile(file, data) {
|
|
109
|
+
const result = await this.s3.putObject({
|
|
112
110
|
Bucket: this.bucket,
|
|
113
111
|
ACL: this.acl,
|
|
114
112
|
Key: file.key,
|
|
115
113
|
ContentType: file.type,
|
|
116
|
-
Body:
|
|
114
|
+
Body: data
|
|
117
115
|
})
|
|
118
116
|
// "Convert" `file` to something looking more like a S3 `storageFile`.
|
|
119
117
|
// For now, only the `location` property is of interest:
|
|
120
118
|
return {
|
|
121
119
|
...file,
|
|
122
|
-
location:
|
|
120
|
+
location: result.Location
|
|
123
121
|
}
|
|
124
122
|
}
|
|
125
123
|
|
|
@@ -163,3 +161,33 @@ export class S3Storage extends Storage {
|
|
|
163
161
|
return files
|
|
164
162
|
}
|
|
165
163
|
}
|
|
164
|
+
|
|
165
|
+
function getFileTypeFromBuffer(buffer) {
|
|
166
|
+
const type = fileTypeFromBuffer(buffer)
|
|
167
|
+
if (type) {
|
|
168
|
+
return type.mime
|
|
169
|
+
}
|
|
170
|
+
try {
|
|
171
|
+
const { type } = imageSize(buffer)
|
|
172
|
+
return {
|
|
173
|
+
jpg: 'image/jpeg',
|
|
174
|
+
png: 'image/png',
|
|
175
|
+
gif: 'image/gif',
|
|
176
|
+
svg: 'image/svg+xml',
|
|
177
|
+
webp: 'image/webp',
|
|
178
|
+
tiff: 'image/tiff',
|
|
179
|
+
j2c: 'image/jp2',
|
|
180
|
+
jp2: 'image/jp2',
|
|
181
|
+
ktx: 'image/ktx',
|
|
182
|
+
bmp: 'image/bmp',
|
|
183
|
+
tga: 'image/x-targa',
|
|
184
|
+
cur: 'image/x-win-bitmap',
|
|
185
|
+
icns: 'image/x-icon',
|
|
186
|
+
ico: 'image/x-icon',
|
|
187
|
+
pnm: 'image/x-portable-anymap',
|
|
188
|
+
dds: 'image/vnd-ms.dds',
|
|
189
|
+
psd: 'image/vnd.adobe.photoshop'
|
|
190
|
+
}[type]
|
|
191
|
+
} catch (err) {}
|
|
192
|
+
return null
|
|
193
|
+
}
|
package/src/storage/Storage.js
CHANGED
|
@@ -94,9 +94,9 @@ export class Storage {
|
|
|
94
94
|
return storageFiles.map(storageFile => this.convertStorageFile(storageFile))
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
async addFile(file,
|
|
98
|
-
const storageFile = await this._addFile(file,
|
|
99
|
-
file.size = Buffer.byteLength(
|
|
97
|
+
async addFile(file, data) {
|
|
98
|
+
const storageFile = await this._addFile(file, data)
|
|
99
|
+
file.size = Buffer.byteLength(data)
|
|
100
100
|
file.url = this._getFileUrl(storageFile)
|
|
101
101
|
// TODO: Support `config.readImageSize`, but this can only be done onces
|
|
102
102
|
// there are separate storage instances per model assets config!
|
|
@@ -146,7 +146,7 @@ export class Storage {
|
|
|
146
146
|
_getFileUrl(_file) {}
|
|
147
147
|
|
|
148
148
|
// @overridable
|
|
149
|
-
async _addFile(_file,
|
|
149
|
+
async _addFile(_file, _data) {}
|
|
150
150
|
|
|
151
151
|
// @overridable
|
|
152
152
|
async _removeFile(_file) {}
|