@directus/api 20.0.0 → 20.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/dist/cli/commands/bootstrap/index.js +2 -1
- package/dist/database/run-ast.js +10 -2
- package/dist/services/files.js +14 -11
- package/dist/services/items.d.ts +3 -3
- package/dist/services/tus/data-store.js +2 -0
- package/dist/websocket/controllers/base.d.ts +1 -1
- package/dist/websocket/controllers/base.js +20 -16
- package/package.json +14 -14
|
@@ -72,5 +72,6 @@ async function createDefaultAdmin(schema) {
|
|
|
72
72
|
adminPassword = nanoid(12);
|
|
73
73
|
logger.info(`No admin password provided. Defaulting to "${adminPassword}"`);
|
|
74
74
|
}
|
|
75
|
-
|
|
75
|
+
const token = env['ADMIN_TOKEN'] ?? null;
|
|
76
|
+
await usersService.createOne({ email: adminEmail, password: adminPassword, token, role, ...defaultAdminUser });
|
|
76
77
|
}
|
package/dist/database/run-ast.js
CHANGED
|
@@ -210,10 +210,18 @@ async function getDBQuery(schema, knex, table, fieldNodes, query) {
|
|
|
210
210
|
}
|
|
211
211
|
innerQuerySortRecords.push({ alias: sortAlias, order: sortRecord.order });
|
|
212
212
|
});
|
|
213
|
-
dbQuery.orderByRaw(orderByString, orderByFields);
|
|
214
213
|
if (hasMultiRelationalSort) {
|
|
215
214
|
dbQuery = helpers.schema.applyMultiRelationalSort(knex, dbQuery, table, primaryKey, orderByString, orderByFields);
|
|
215
|
+
// Start order by with directus_row_number. The directus_row_number is derived from a window function that
|
|
216
|
+
// is ordered by the sort fields within every primary key partition. That ensures that the result with the
|
|
217
|
+
// row number = 1 is the top-most row of every partition, according to the selected sort fields.
|
|
218
|
+
// Since the only relevant result is the first row of this partition, adding the directus_row_number to the
|
|
219
|
+
// order by here ensures that all rows with a directus_row_number = 1 show up first in the inner query result,
|
|
220
|
+
// and are correctly truncated by the limit, but not earlier.
|
|
221
|
+
orderByString = `?? asc, ${orderByString}`;
|
|
222
|
+
orderByFields.unshift(knex.ref('directus_row_number'));
|
|
216
223
|
}
|
|
224
|
+
dbQuery.orderByRaw(orderByString, orderByFields);
|
|
217
225
|
}
|
|
218
226
|
else {
|
|
219
227
|
sortRecords.map((sortRecord) => {
|
|
@@ -236,7 +244,7 @@ async function getDBQuery(schema, knex, table, fieldNodes, query) {
|
|
|
236
244
|
.select(fieldNodes.map(preProcess))
|
|
237
245
|
.from(table)
|
|
238
246
|
.innerJoin(knex.raw('??', dbQuery.as('inner')), `${table}.${primaryKey}`, `inner.${primaryKey}`);
|
|
239
|
-
if (sortRecords
|
|
247
|
+
if (sortRecords) {
|
|
240
248
|
innerQuerySortRecords.map((innerQuerySortRecord) => {
|
|
241
249
|
wrapperQuery.orderBy(`inner.${innerQuerySortRecord.alias}`, innerQuerySortRecord.order);
|
|
242
250
|
});
|
package/dist/services/files.js
CHANGED
|
@@ -9,6 +9,7 @@ import { PassThrough as PassThroughStream, Transform as TransformStream } from '
|
|
|
9
9
|
import zlib from 'node:zlib';
|
|
10
10
|
import path from 'path';
|
|
11
11
|
import url from 'url';
|
|
12
|
+
import { RESUMABLE_UPLOADS } from '../constants.js';
|
|
12
13
|
import emitter from '../emitter.js';
|
|
13
14
|
import { useLogger } from '../logger.js';
|
|
14
15
|
import { getAxios } from '../request/index.js';
|
|
@@ -215,17 +216,19 @@ export class FilesService extends ItemsService {
|
|
|
215
216
|
}
|
|
216
217
|
async readByQuery(query, opts) {
|
|
217
218
|
const filteredQuery = cloneDeep(query);
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
filteredQuery.filter
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
filteredQuery.filter['_and']
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
219
|
+
if (RESUMABLE_UPLOADS.ENABLED === true) {
|
|
220
|
+
const filterPartialUploads = { tus_id: { _null: true } };
|
|
221
|
+
if (!filteredQuery.filter) {
|
|
222
|
+
filteredQuery.filter = filterPartialUploads;
|
|
223
|
+
}
|
|
224
|
+
else if ('_and' in filteredQuery.filter && Array.isArray(filteredQuery.filter['_and'])) {
|
|
225
|
+
filteredQuery.filter['_and'].push(filterPartialUploads);
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
filteredQuery.filter = {
|
|
229
|
+
_and: [filteredQuery.filter, filterPartialUploads],
|
|
230
|
+
};
|
|
231
|
+
}
|
|
229
232
|
}
|
|
230
233
|
return super.readByQuery(filteredQuery, opts);
|
|
231
234
|
}
|
package/dist/services/items.d.ts
CHANGED
|
@@ -11,14 +11,14 @@ export type MutationTracker = {
|
|
|
11
11
|
trackMutations: (count: number) => void;
|
|
12
12
|
getCount: () => number;
|
|
13
13
|
};
|
|
14
|
-
export declare class ItemsService<Item extends AnyItem = AnyItem> implements AbstractService {
|
|
15
|
-
collection:
|
|
14
|
+
export declare class ItemsService<Item extends AnyItem = AnyItem, Collection extends string = string> implements AbstractService {
|
|
15
|
+
collection: Collection;
|
|
16
16
|
knex: Knex;
|
|
17
17
|
accountability: Accountability | null;
|
|
18
18
|
eventScope: string;
|
|
19
19
|
schema: SchemaOverview;
|
|
20
20
|
cache: Keyv<any> | null;
|
|
21
|
-
constructor(collection:
|
|
21
|
+
constructor(collection: Collection, options: AbstractServiceOptions);
|
|
22
22
|
/**
|
|
23
23
|
* Create a fork of the current service, allowing instantiation with different options.
|
|
24
24
|
*/
|
|
@@ -109,6 +109,7 @@ export class TusDataStore extends DataStore {
|
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
async write(readable, tus_id, offset) {
|
|
112
|
+
const logger = useLogger();
|
|
112
113
|
const fileData = await this.getFileById(tus_id);
|
|
113
114
|
const filePath = fileData.filename_disk;
|
|
114
115
|
const sudoService = new ItemsService('directus_files', {
|
|
@@ -146,6 +147,7 @@ export class TusDataStore extends DataStore {
|
|
|
146
147
|
return newOffset;
|
|
147
148
|
}
|
|
148
149
|
catch (err) {
|
|
150
|
+
logger.error(err, 'Error writing chunk for upload "%s" at offset %d', tus_id, offset);
|
|
149
151
|
if ('status_code' in err && err.status_code === 500) {
|
|
150
152
|
throw err;
|
|
151
153
|
}
|
|
@@ -32,7 +32,7 @@ export default abstract class SocketController {
|
|
|
32
32
|
protected getRateLimiter(): RateLimiterAbstract | null;
|
|
33
33
|
private catchInvalidMessages;
|
|
34
34
|
protected handleUpgrade(request: IncomingMessage, socket: internal.Duplex, head: Buffer): Promise<void>;
|
|
35
|
-
protected handleTokenUpgrade({ request, socket, head }: UpgradeContext, token: string): Promise<void>;
|
|
35
|
+
protected handleTokenUpgrade({ request, socket, head }: UpgradeContext, token: string | null): Promise<void>;
|
|
36
36
|
protected handleHandshakeUpgrade({ request, socket, head }: UpgradeContext): Promise<void>;
|
|
37
37
|
createClient(ws: WebSocket, { accountability, expires_at }: AuthenticationState): WebSocketClient;
|
|
38
38
|
protected parseMessage(data: string): WebSocketMessage;
|
|
@@ -101,13 +101,14 @@ export default class SocketController {
|
|
|
101
101
|
const cookies = request.headers.cookie ? cookie.parse(request.headers.cookie) : {};
|
|
102
102
|
const context = { request, socket, head };
|
|
103
103
|
const sessionCookieName = env['SESSION_COOKIE_NAME'];
|
|
104
|
-
if (cookies[sessionCookieName]) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
104
|
+
if (this.authentication.mode === 'strict' || query['access_token'] || cookies[sessionCookieName]) {
|
|
105
|
+
let token = null;
|
|
106
|
+
if (typeof query['access_token'] === 'string') {
|
|
107
|
+
token = query['access_token'];
|
|
108
|
+
}
|
|
109
|
+
else if (typeof cookies[sessionCookieName] === 'string') {
|
|
110
|
+
token = cookies[sessionCookieName] ?? null;
|
|
111
|
+
}
|
|
111
112
|
await this.handleTokenUpgrade(context, token);
|
|
112
113
|
return;
|
|
113
114
|
}
|
|
@@ -122,16 +123,19 @@ export default class SocketController {
|
|
|
122
123
|
});
|
|
123
124
|
}
|
|
124
125
|
async handleTokenUpgrade({ request, socket, head }, token) {
|
|
125
|
-
let accountability
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
126
|
+
let accountability = null;
|
|
127
|
+
let expires_at = null;
|
|
128
|
+
if (token) {
|
|
129
|
+
try {
|
|
130
|
+
accountability = await getAccountabilityForToken(token);
|
|
131
|
+
expires_at = getExpiresAtForToken(token);
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
accountability = null;
|
|
135
|
+
expires_at = null;
|
|
136
|
+
}
|
|
133
137
|
}
|
|
134
|
-
if (!accountability || !accountability.user) {
|
|
138
|
+
if (!token || !accountability || !accountability.user) {
|
|
135
139
|
logger.debug('WebSocket upgrade denied - ' + JSON.stringify(accountability || 'invalid'));
|
|
136
140
|
socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
|
|
137
141
|
socket.destroy();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@directus/api",
|
|
3
|
-
"version": "20.
|
|
3
|
+
"version": "20.1.0",
|
|
4
4
|
"description": "Directus is a real-time API and App dashboard for managing SQL database content",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"directus",
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
"graphql-ws": "5.16.0",
|
|
100
100
|
"helmet": "7.1.0",
|
|
101
101
|
"icc": "3.0.0",
|
|
102
|
-
"inquirer": "9.2
|
|
102
|
+
"inquirer": "9.3.2",
|
|
103
103
|
"ioredis": "5.4.1",
|
|
104
104
|
"ip-matching": "2.1.2",
|
|
105
105
|
"isolated-vm": "4.7.2",
|
|
@@ -135,7 +135,7 @@
|
|
|
135
135
|
"pino-http": "9.0.0",
|
|
136
136
|
"pino-http-print": "3.1.0",
|
|
137
137
|
"pino-pretty": "11.2.1",
|
|
138
|
-
"qs": "6.12.
|
|
138
|
+
"qs": "6.12.2",
|
|
139
139
|
"rate-limiter-flexible": "5.0.3",
|
|
140
140
|
"rollup": "4.17.2",
|
|
141
141
|
"samlify": "2.8.10",
|
|
@@ -146,32 +146,32 @@
|
|
|
146
146
|
"tar": "7.4.0",
|
|
147
147
|
"tsx": "4.12.0",
|
|
148
148
|
"wellknown": "0.5.0",
|
|
149
|
-
"ws": "8.
|
|
149
|
+
"ws": "8.18.0",
|
|
150
150
|
"zod": "3.23.8",
|
|
151
151
|
"zod-validation-error": "3.3.0",
|
|
152
|
-
"@directus/app": "12.2.
|
|
152
|
+
"@directus/app": "12.2.1",
|
|
153
153
|
"@directus/constants": "11.0.4",
|
|
154
|
+
"@directus/env": "1.3.0",
|
|
154
155
|
"@directus/extensions": "1.0.9",
|
|
155
|
-
"@directus/errors": "0.3.3",
|
|
156
|
-
"@directus/env": "1.2.0",
|
|
157
156
|
"@directus/extensions-registry": "1.0.9",
|
|
158
|
-
"@directus/extensions-sdk": "11.0.9",
|
|
159
157
|
"@directus/format-title": "10.1.2",
|
|
158
|
+
"@directus/errors": "0.3.3",
|
|
160
159
|
"@directus/memory": "1.0.10",
|
|
160
|
+
"@directus/extensions-sdk": "11.0.9",
|
|
161
161
|
"@directus/pressure": "1.0.21",
|
|
162
162
|
"@directus/schema": "11.0.3",
|
|
163
163
|
"@directus/specs": "10.2.10",
|
|
164
164
|
"@directus/storage-driver-azure": "10.0.23",
|
|
165
|
+
"@directus/storage": "10.1.0",
|
|
165
166
|
"@directus/storage-driver-cloudinary": "10.0.23",
|
|
166
167
|
"@directus/storage-driver-gcs": "10.0.24",
|
|
167
|
-
"@directus/storage": "10.1.0",
|
|
168
168
|
"@directus/storage-driver-local": "10.1.0",
|
|
169
169
|
"@directus/storage-driver-s3": "10.1.0",
|
|
170
|
-
"@directus/system-data": "1.1.0",
|
|
171
170
|
"@directus/storage-driver-supabase": "1.0.15",
|
|
171
|
+
"@directus/system-data": "1.1.0",
|
|
172
172
|
"@directus/utils": "11.0.10",
|
|
173
173
|
"@directus/validation": "0.0.18",
|
|
174
|
-
"directus": "10.13.
|
|
174
|
+
"directus": "10.13.1"
|
|
175
175
|
},
|
|
176
176
|
"devDependencies": {
|
|
177
177
|
"@ngneat/falso": "7.2.0",
|
|
@@ -185,7 +185,7 @@
|
|
|
185
185
|
"@types/destroy": "1.0.3",
|
|
186
186
|
"@types/encodeurl": "1.0.2",
|
|
187
187
|
"@types/express": "4.17.21",
|
|
188
|
-
"@types/express-serve-static-core": "4.19.
|
|
188
|
+
"@types/express-serve-static-core": "4.19.5",
|
|
189
189
|
"@types/fs-extra": "11.0.4",
|
|
190
190
|
"@types/glob-to-regexp": "0.4.4",
|
|
191
191
|
"@types/inquirer": "9.0.7",
|
|
@@ -212,12 +212,12 @@
|
|
|
212
212
|
"knex-mock-client": "2.0.1",
|
|
213
213
|
"typescript": "5.4.5",
|
|
214
214
|
"vitest": "1.5.3",
|
|
215
|
-
"@directus/random": "0.2.8",
|
|
216
215
|
"@directus/tsconfig": "1.0.1",
|
|
216
|
+
"@directus/random": "0.2.8",
|
|
217
217
|
"@directus/types": "11.2.0"
|
|
218
218
|
},
|
|
219
219
|
"optionalDependencies": {
|
|
220
|
-
"@keyv/redis": "2.8.
|
|
220
|
+
"@keyv/redis": "2.8.5",
|
|
221
221
|
"mysql": "2.18.1",
|
|
222
222
|
"nodemailer-mailgun-transport": "2.1.5",
|
|
223
223
|
"nodemailer-sendgrid": "1.0.3",
|