@appweaver/core 1.3.1 → 1.4.1
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/export/export-service.d.ts +4 -3
- package/export/export-service.js +39 -22
- package/factory/create-model.js +54 -22
- package/factory/create-service.js +5 -3
- package/package.json +2 -2
- package/prisma/client/commonInputTypes.d.ts +0 -50
- package/prisma/client/internal/class.js +3 -3
- package/prisma/client/models/File.d.ts +15 -28
- package/resource/resource-loader.js +6 -0
- package/resource/resource-routes.js +2 -2
- package/resource/resource-schema.d.ts +38 -12
- package/resource/resource-schema.js +63 -15
- package/resource/resource-service.d.ts +25 -16
- package/resource/resource-service.js +61 -26
- package/resource/schemas/resource-sort-schema.js +2 -2
- package/resource/utils/cursor-util.d.ts +60 -0
- package/resource/utils/cursor-util.js +117 -0
- package/resource/utils/index.d.ts +1 -0
- package/resource/utils/index.js +1 -0
- package/resource/utils/relation-util.d.ts +3 -3
- package/resource/utils/relation-util.js +52 -16
- package/resource/utils/sort-util.d.ts +11 -0
- package/resource/utils/sort-util.js +18 -0
- package/security/api-key/api-key-auth.js +4 -1
- package/security/auth-service.d.ts +7 -7
- package/security/auth-service.js +43 -5
- package/security/create-auth-resources.d.ts +2 -1
- package/security/oauth2/create-oauth2-plugin.js +3 -34
- package/security/oauth2/oauth2-microsoft.js +1 -1
- package/security/oauth2/oauth2-util.d.ts +9 -7
- package/security/oauth2/oauth2-util.js +17 -10
- package/security/resources/api-key/model.js +2 -0
- package/security/resources/connected-account/model.js +2 -0
- package/security/store/database-security-store.js +2 -1
- package/server/swagger.js +49 -1
- package/storage/file-service.d.ts +19 -4
- package/storage/file-service.js +199 -146
- package/storage/resources/file/model.js +4 -2
- package/types/auth.d.ts +8 -8
- package/types/generated.d.ts +8 -2
- package/types/index.d.ts +1 -0
- package/types/index.js +1 -0
- package/types/storage.d.ts +16 -0
- package/types/storage.js +2 -0
- package/utils/index.d.ts +1 -0
- package/utils/index.js +1 -0
- package/utils/model-util.d.ts +12 -0
- package/utils/model-util.js +113 -0
package/security/auth-service.js
CHANGED
|
@@ -6,6 +6,7 @@ const helper_1 = require("./helper");
|
|
|
6
6
|
const oauth2_service_1 = require("./oauth2/oauth2-service");
|
|
7
7
|
const context_1 = require("../context");
|
|
8
8
|
const cache_1 = require("../cache");
|
|
9
|
+
const storage_1 = require("../storage");
|
|
9
10
|
const errors_1 = require("../errors");
|
|
10
11
|
const AUTH_KEY = 'auth';
|
|
11
12
|
class AuthService {
|
|
@@ -21,7 +22,7 @@ class AuthService {
|
|
|
21
22
|
/**
|
|
22
23
|
* Finds an authenticated user by their unique identifier.
|
|
23
24
|
*
|
|
24
|
-
* @param {
|
|
25
|
+
* @param {ResourceId} id - The unique identifier of the authenticated user to find.
|
|
25
26
|
* @return {Promise<AuthUser | null>} A promise that resolves to the authenticated user object if found, otherwise
|
|
26
27
|
* null.
|
|
27
28
|
*/
|
|
@@ -80,7 +81,7 @@ class AuthService {
|
|
|
80
81
|
/**
|
|
81
82
|
* Updates an authenticated user's information in the system.
|
|
82
83
|
*
|
|
83
|
-
* @param {
|
|
84
|
+
* @param {ResourceId} id - The unique identifier of the authenticated user to be updated.
|
|
84
85
|
* @param {Partial<AuthUser> & { password?: string }} data - The partial user data to update, optionally including a
|
|
85
86
|
* password.
|
|
86
87
|
* @return {Promise<AuthUser>} A promise that resolves to the updated authenticated user object.
|
|
@@ -106,10 +107,11 @@ class AuthService {
|
|
|
106
107
|
* @throws {HttpError} Throws an error if the registration process fails.
|
|
107
108
|
*/
|
|
108
109
|
async registerAuthUser(source, email, password, data) {
|
|
110
|
+
let authUser;
|
|
109
111
|
try {
|
|
110
112
|
const serviceConfig = this._authUserService[common_1.CONFIG];
|
|
111
|
-
const registrationData = serviceConfig.registrationData(source, email, password, data);
|
|
112
|
-
|
|
113
|
+
const registrationData = await serviceConfig.registrationData(source, email, password, data);
|
|
114
|
+
authUser = await this._authUserService.create({
|
|
113
115
|
...registrationData,
|
|
114
116
|
verifiedEmail: source !== common_1.AuthSource.Password
|
|
115
117
|
});
|
|
@@ -117,6 +119,42 @@ class AuthService {
|
|
|
117
119
|
catch (e) {
|
|
118
120
|
throw new errors_1.HttpError('Auth user registration error', 500, e);
|
|
119
121
|
}
|
|
122
|
+
await this.saveRegistrationFiles(authUser, source, data);
|
|
123
|
+
return authUser;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Saves the files the `registrationFiles` service configuration selects for a newly registered user, each one to the
|
|
127
|
+
* file field of the auth model it is keyed by. The files are stored only after the user exists, since a file record
|
|
128
|
+
* is linked to the resource that owns it. Storing a file is best-effort, so a rejected file, such as an avatar the
|
|
129
|
+
* provider served in an unsupported format, is logged and never fails the registration.
|
|
130
|
+
*
|
|
131
|
+
* @internal
|
|
132
|
+
*/
|
|
133
|
+
async saveRegistrationFiles(authUser, source, data) {
|
|
134
|
+
const serviceConfig = this._authUserService[common_1.CONFIG];
|
|
135
|
+
if (!serviceConfig.registrationFiles) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
let files;
|
|
139
|
+
try {
|
|
140
|
+
files = (await serviceConfig.registrationFiles(source, data)) ?? {};
|
|
141
|
+
}
|
|
142
|
+
catch (e) {
|
|
143
|
+
common_1.logger.error({ id: authUser.id, err: e }, 'Registration files selection error');
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const fileService = (0, context_1.inject)(storage_1.FileService);
|
|
147
|
+
for (const [field, file] of Object.entries(files)) {
|
|
148
|
+
if (!file) {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
try {
|
|
152
|
+
await fileService.saveBuffer(field, file, authUser, this._authUserService.client);
|
|
153
|
+
}
|
|
154
|
+
catch (e) {
|
|
155
|
+
common_1.logger.error({ id: authUser.id, field, err: e }, 'Registration file save error');
|
|
156
|
+
}
|
|
157
|
+
}
|
|
120
158
|
}
|
|
121
159
|
/**
|
|
122
160
|
* Changes the password for the authenticated user.
|
|
@@ -292,7 +330,7 @@ class AuthService {
|
|
|
292
330
|
/**
|
|
293
331
|
* Logs out a user by updating their authentication information with a logout timestamp.
|
|
294
332
|
*
|
|
295
|
-
* @param {
|
|
333
|
+
* @param {ResourceId} id - The unique identifier of the user to be logged out.
|
|
296
334
|
* @return {Promise<boolean>} A promise that resolves to a boolean indicating whether the logout operation was
|
|
297
335
|
* successful.
|
|
298
336
|
*/
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Ctor, IResourceService, ResourceModel, ResourceModelConfig, ResourceServiceConfig } from '@appweaver/common';
|
|
2
|
-
import { CheckOAuth2UserFn, RegistrationDataFn } from '../types';
|
|
2
|
+
import { CheckOAuth2UserFn, RegistrationDataFn, RegistrationFilesFn } from '../types';
|
|
3
3
|
export declare function createAuthModel(config: ResourceModelConfig): ResourceModel;
|
|
4
4
|
export declare function createAuthService<T = any, C = any, U = any>(config: ResourceServiceConfig<T, C, U> & {
|
|
5
5
|
registrationData?: RegistrationDataFn<T>;
|
|
6
|
+
registrationFiles?: RegistrationFilesFn;
|
|
6
7
|
checkOAuth2User?: CheckOAuth2UserFn;
|
|
7
8
|
}): Ctor<IResourceService<T, T, C, U>>;
|
|
@@ -13,6 +13,7 @@ const auth_service_1 = require("../auth-service");
|
|
|
13
13
|
const oauth2_service_1 = require("./oauth2-service");
|
|
14
14
|
const helper_1 = require("../helper");
|
|
15
15
|
const oauth2_schema_1 = require("./oauth2-schema");
|
|
16
|
+
const oauth2_util_1 = require("./oauth2-util");
|
|
16
17
|
function createOAuth2Plugin(authSource, oAuth2Config) {
|
|
17
18
|
const name = authSource.replace('oauth2', '');
|
|
18
19
|
const upperName = name.toUpperCase();
|
|
@@ -100,7 +101,8 @@ function createOAuth2Plugin(authSource, oAuth2Config) {
|
|
|
100
101
|
}
|
|
101
102
|
authUser = await authService.registerAuthUser(authSource, userInfo.email, undefined, {
|
|
102
103
|
...(0, common_1.pickProperties)(userInfo, ['firstName', 'lastName', 'avatarUrl']),
|
|
103
|
-
avatarFile: userInfo.avatarFile ??
|
|
104
|
+
avatarFile: userInfo.avatarFile ??
|
|
105
|
+
(await (0, oauth2_util_1.fetchAvatarFile)(userInfo.avatarUrl, userInfo.id))
|
|
104
106
|
});
|
|
105
107
|
}
|
|
106
108
|
const stateData = request.oauth2State;
|
|
@@ -137,36 +139,3 @@ function createOAuth2Plugin(authSource, oAuth2Config) {
|
|
|
137
139
|
});
|
|
138
140
|
});
|
|
139
141
|
}
|
|
140
|
-
/**
|
|
141
|
-
* Downloads the user's avatar image from the OAuth2 provider so it can be passed to the `registrationData` callback.
|
|
142
|
-
* Fetching is best-effort: any failure is logged and `undefined` is returned so the registration flow is not blocked.
|
|
143
|
-
*
|
|
144
|
-
* @param {UserInfo} userInfo - The user info extracted from the OAuth2 provider, including the optional avatar URL.
|
|
145
|
-
* @return {Promise<AvatarFile | undefined>} A promise resolving to the downloaded avatar file, or `undefined` when
|
|
146
|
-
* avatar fetching is disabled, no avatar URL is available, or the download fails.
|
|
147
|
-
*/
|
|
148
|
-
async function fetchAvatarFile(userInfo) {
|
|
149
|
-
if (!common_1.config.SECURITY_OAUTH2_FETCH_AVATAR_ENABLED || !userInfo.avatarUrl) {
|
|
150
|
-
return undefined;
|
|
151
|
-
}
|
|
152
|
-
try {
|
|
153
|
-
const resp = await fetch(userInfo.avatarUrl, { method: 'GET' });
|
|
154
|
-
if (!resp.ok) {
|
|
155
|
-
common_1.logger.debug({ url: userInfo.avatarUrl, status: resp.status }, 'OAuth2 avatar fetch failed');
|
|
156
|
-
return undefined;
|
|
157
|
-
}
|
|
158
|
-
const mimeType = resp.headers.get('content-type') ?? 'image/jpeg';
|
|
159
|
-
const data = Buffer.from(await resp.arrayBuffer());
|
|
160
|
-
const extension = mimeType.split('/')[1]?.split(';')[0] ?? 'jpg';
|
|
161
|
-
return {
|
|
162
|
-
name: `avatar-${userInfo.id}.${extension}`,
|
|
163
|
-
mimeType,
|
|
164
|
-
size: data.length,
|
|
165
|
-
data
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
catch (e) {
|
|
169
|
-
common_1.logger.debug({ url: userInfo.avatarUrl, err: e }, 'OAuth2 avatar fetch error');
|
|
170
|
-
return undefined;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
@@ -31,6 +31,6 @@ async function fetchMicrosoftUser(accessToken) {
|
|
|
31
31
|
firstName: data.givenName ?? firstName,
|
|
32
32
|
lastName: data.surname ?? lastName,
|
|
33
33
|
// Microsoft Graph serves the photo as authenticated binary content, so it has to be downloaded here.
|
|
34
|
-
avatarFile: await (0, oauth2_util_1.
|
|
34
|
+
avatarFile: await (0, oauth2_util_1.fetchAvatarFile)(`${userInfoUrl}/photo/$value`, data.id, accessToken)
|
|
35
35
|
};
|
|
36
36
|
}
|
|
@@ -6,20 +6,22 @@ import { AvatarFile } from '../../types';
|
|
|
6
6
|
* @param {string} url - The user info endpoint to call.
|
|
7
7
|
* @param {string} accessToken - The access token obtained from the authorization code flow.
|
|
8
8
|
* @param {Record<string, string>} [headers] - Extra request headers required by the provider.
|
|
9
|
-
* @return {Promise<
|
|
9
|
+
* @return {Promise<Object>} A promise resolving to the parsed response body.
|
|
10
10
|
* @throws {HttpError} If the provider responds with a non-2xx status.
|
|
11
11
|
*/
|
|
12
12
|
export declare function fetchUserInfo<T>(providerName: string, url: string, accessToken: string, headers?: Record<string, string>): Promise<T>;
|
|
13
13
|
/**
|
|
14
|
-
* Downloads
|
|
15
|
-
*
|
|
14
|
+
* Downloads the user's avatar image so it can be passed to the `registrationData` and `registrationFiles` callbacks as
|
|
15
|
+
* `avatarFile`. Fetching is opt-in through `SECURITY_OAUTH2_FETCH_AVATAR_ENABLED` and best-effort: every reason the
|
|
16
|
+
* image does not arrive is logged and `undefined` is returned, so the registration flow is never blocked by it.
|
|
16
17
|
*
|
|
17
|
-
* @param {string} url - The avatar endpoint to call.
|
|
18
|
-
* @param {string} accessToken - The access token obtained from the authorization code flow.
|
|
18
|
+
* @param {string | undefined} url - The avatar endpoint to call.
|
|
19
19
|
* @param {string} id - The provider's user identifier, used to name the file.
|
|
20
|
-
* @
|
|
20
|
+
* @param {string} [accessToken] - Access token, for providers whose avatar endpoint requires authentication.
|
|
21
|
+
* @return {Promise<AvatarFile | undefined>} A promise resolving to the downloaded avatar, or `undefined` when
|
|
22
|
+
* fetching is disabled, no avatar URL is available, or the download fails.
|
|
21
23
|
*/
|
|
22
|
-
export declare function
|
|
24
|
+
export declare function fetchAvatarFile(url: string | undefined, id: string, accessToken?: string): Promise<AvatarFile | undefined>;
|
|
23
25
|
/**
|
|
24
26
|
* Splits a provider's single display name field into a first and last name. Everything after the first whitespace
|
|
25
27
|
* separated word becomes the last name, so multipart surnames are kept intact.
|
|
@@ -34,7 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.fetchUserInfo = fetchUserInfo;
|
|
37
|
-
exports.
|
|
37
|
+
exports.fetchAvatarFile = fetchAvatarFile;
|
|
38
38
|
exports.splitFullName = splitFullName;
|
|
39
39
|
exports.requireEmail = requireEmail;
|
|
40
40
|
exports.decodeJwtPayload = decodeJwtPayload;
|
|
@@ -51,7 +51,7 @@ const APPLE_TOKEN_AUDIENCE = 'https://appleid.apple.com';
|
|
|
51
51
|
* @param {string} url - The user info endpoint to call.
|
|
52
52
|
* @param {string} accessToken - The access token obtained from the authorization code flow.
|
|
53
53
|
* @param {Record<string, string>} [headers] - Extra request headers required by the provider.
|
|
54
|
-
* @return {Promise<
|
|
54
|
+
* @return {Promise<Object>} A promise resolving to the parsed response body.
|
|
55
55
|
* @throws {HttpError} If the provider responds with a non-2xx status.
|
|
56
56
|
*/
|
|
57
57
|
async function fetchUserInfo(providerName, url, accessToken, headers = {}) {
|
|
@@ -65,24 +65,30 @@ async function fetchUserInfo(providerName, url, accessToken, headers = {}) {
|
|
|
65
65
|
return resp.json();
|
|
66
66
|
}
|
|
67
67
|
/**
|
|
68
|
-
* Downloads
|
|
69
|
-
*
|
|
68
|
+
* Downloads the user's avatar image so it can be passed to the `registrationData` and `registrationFiles` callbacks as
|
|
69
|
+
* `avatarFile`. Fetching is opt-in through `SECURITY_OAUTH2_FETCH_AVATAR_ENABLED` and best-effort: every reason the
|
|
70
|
+
* image does not arrive is logged and `undefined` is returned, so the registration flow is never blocked by it.
|
|
70
71
|
*
|
|
71
|
-
* @param {string} url - The avatar endpoint to call.
|
|
72
|
-
* @param {string} accessToken - The access token obtained from the authorization code flow.
|
|
72
|
+
* @param {string | undefined} url - The avatar endpoint to call.
|
|
73
73
|
* @param {string} id - The provider's user identifier, used to name the file.
|
|
74
|
-
* @
|
|
74
|
+
* @param {string} [accessToken] - Access token, for providers whose avatar endpoint requires authentication.
|
|
75
|
+
* @return {Promise<AvatarFile | undefined>} A promise resolving to the downloaded avatar, or `undefined` when
|
|
76
|
+
* fetching is disabled, no avatar URL is available, or the download fails.
|
|
75
77
|
*/
|
|
76
|
-
async function
|
|
78
|
+
async function fetchAvatarFile(url, id, accessToken) {
|
|
77
79
|
if (!common_1.config.SECURITY_OAUTH2_FETCH_AVATAR_ENABLED) {
|
|
78
80
|
return undefined;
|
|
79
81
|
}
|
|
82
|
+
if (!url) {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
80
85
|
try {
|
|
81
86
|
const resp = await fetch(url, {
|
|
82
87
|
method: 'GET',
|
|
83
|
-
headers: { authorization: `Bearer ${accessToken}` }
|
|
88
|
+
headers: accessToken ? { authorization: `Bearer ${accessToken}` } : {}
|
|
84
89
|
});
|
|
85
90
|
if (!resp.ok) {
|
|
91
|
+
common_1.logger.error({ url, status: resp.status }, 'OAuth2 avatar fetch failed');
|
|
86
92
|
return undefined;
|
|
87
93
|
}
|
|
88
94
|
const mimeType = resp.headers.get('content-type') ?? 'image/jpeg';
|
|
@@ -95,7 +101,8 @@ async function fetchAuthenticatedAvatar(url, accessToken, id) {
|
|
|
95
101
|
data
|
|
96
102
|
};
|
|
97
103
|
}
|
|
98
|
-
catch {
|
|
104
|
+
catch (e) {
|
|
105
|
+
common_1.logger.error({ url, err: e }, 'OAuth2 avatar fetch error');
|
|
99
106
|
return undefined;
|
|
100
107
|
}
|
|
101
108
|
}
|
|
@@ -45,7 +45,8 @@ class DatabaseSecurityStore extends common_1.SecurityStore {
|
|
|
45
45
|
}
|
|
46
46
|
/** @internal */
|
|
47
47
|
async removeOneTimeToken(id) {
|
|
48
|
-
|
|
48
|
+
// The generated client types the id after the configured primary key
|
|
49
|
+
await this._db.client().oneTimeToken.delete({ where: { id: id } });
|
|
49
50
|
}
|
|
50
51
|
}
|
|
51
52
|
exports.DatabaseSecurityStore = DatabaseSecurityStore;
|
package/server/swagger.js
CHANGED
|
@@ -11,7 +11,7 @@ const context_1 = require("../context");
|
|
|
11
11
|
exports.default = (0, fastify_plugin_1.default)((server) => {
|
|
12
12
|
server.register(swagger_1.default, {
|
|
13
13
|
hideUntagged: common_1.config.SWAGGER_HIDE_UNTAGGED,
|
|
14
|
-
transformObject: (document) => addConfig(normalizeUnionTypes(pruneUnusedSchemas(document))),
|
|
14
|
+
transformObject: (document) => addConfig(normalizeUnionTypes(pruneUnusedSchemas(inlineNullableRefs(document)))),
|
|
15
15
|
openapi: {
|
|
16
16
|
info: {
|
|
17
17
|
title: common_1.config.APP_NAME,
|
|
@@ -64,6 +64,54 @@ exports.default = (0, fastify_plugin_1.default)((server) => {
|
|
|
64
64
|
});
|
|
65
65
|
}
|
|
66
66
|
});
|
|
67
|
+
/**
|
|
68
|
+
* Replaces every reference to a nullable model variant with the union it stands
|
|
69
|
+
* for. Each model registers a `<Model>SingleNullable` schema the response
|
|
70
|
+
* serializer needs as a name of its own, since it cannot compile an inline
|
|
71
|
+
* union that cycles back to a model it is already writing. The document says
|
|
72
|
+
* the same thing without that indirection, leaving the variants unreferenced
|
|
73
|
+
* for {@link pruneUnusedSchemas} to drop.
|
|
74
|
+
*
|
|
75
|
+
* @param {Object} document The transform argument of the Swagger plugin,
|
|
76
|
+
* wrapping the OpenAPI document in its `openapiObject` property.
|
|
77
|
+
* @returns {Object} The same argument, with every reference to a nullable model
|
|
78
|
+
* variant replaced in place.
|
|
79
|
+
*/
|
|
80
|
+
function inlineNullableRefs(document) {
|
|
81
|
+
const schemas = document.openapiObject?.components?.schemas ?? {};
|
|
82
|
+
// The schemas are registered under generated names, so the variants are
|
|
83
|
+
// recognized by the title carrying the name they were declared with
|
|
84
|
+
const variants = new Map();
|
|
85
|
+
for (const [name, schema] of Object.entries(schemas)) {
|
|
86
|
+
if (/SingleNullable$/.test(schema?.title ?? '') && (0, common_1.isArray)(schema?.anyOf)) {
|
|
87
|
+
variants.set(`#/components/schemas/${name}`, schema.anyOf);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (variants.size === 0) {
|
|
91
|
+
return document;
|
|
92
|
+
}
|
|
93
|
+
const visit = (node) => {
|
|
94
|
+
if (!node || typeof node !== 'object') {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if ((0, common_1.isArray)(node)) {
|
|
98
|
+
for (const item of node)
|
|
99
|
+
visit(item);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
for (const value of Object.values(node)) {
|
|
103
|
+
visit(value);
|
|
104
|
+
}
|
|
105
|
+
const union = variants.get(node.$ref);
|
|
106
|
+
if (union) {
|
|
107
|
+
delete node.$ref;
|
|
108
|
+
node.anyOf = structuredClone(union);
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
visit(document.openapiObject?.paths);
|
|
112
|
+
visit(schemas);
|
|
113
|
+
return document;
|
|
114
|
+
}
|
|
67
115
|
/**
|
|
68
116
|
* Rewrites the JSON Schema type lists of the document into the equivalent
|
|
69
117
|
* `anyOf` unions. The query filter schemas declare their plain values as a
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Multipart, MultipartFile } from '@fastify/multipart';
|
|
2
|
-
import { ContentStream, Resource, ResourceClient } from '@appweaver/common';
|
|
3
|
-
import { File } from '../types';
|
|
2
|
+
import { ContentStream, Resource, ResourceClient, ResourceId } from '@appweaver/common';
|
|
3
|
+
import { File, FileBuffer } from '../types';
|
|
4
4
|
export type FileStream = {
|
|
5
5
|
content: ContentStream;
|
|
6
6
|
fileName: string;
|
|
@@ -41,6 +41,21 @@ export declare class FileService {
|
|
|
41
41
|
* @throws {HttpError} Throws an error if file validation, storage, or resource association fails.
|
|
42
42
|
*/
|
|
43
43
|
saveFile(data: MultipartFile, resource: Resource, client: ResourceClient): Promise<File>;
|
|
44
|
+
/**
|
|
45
|
+
* Saves an in-memory file to storage and associates it with a file field of a specific resource. Behaves exactly like
|
|
46
|
+
* {@link saveFile}, except the content is taken from a buffer instead of a multipart upload, which makes it usable
|
|
47
|
+
* outside a file upload request, for an avatar downloaded from an OAuth2 provider or an image the application
|
|
48
|
+
* generates itself.
|
|
49
|
+
*
|
|
50
|
+
* @param {string} fieldName The file field of the resource the file is saved to.
|
|
51
|
+
* @param {FileBuffer} file The file content, along with its original name and media type.
|
|
52
|
+
* @param {Resource} resource The resource object with which the file is being associated.
|
|
53
|
+
* @param {ResourceClient} client The database client responsible for handling the resource.
|
|
54
|
+
* @return {Promise<File>} A promise that resolves to the saved file object or rejects with an error if the operation
|
|
55
|
+
* fails.
|
|
56
|
+
* @throws {HttpError} Throws an error if file validation, storage, or resource association fails.
|
|
57
|
+
*/
|
|
58
|
+
saveBuffer(fieldName: string, file: FileBuffer, resource: Resource, client: ResourceClient): Promise<File>;
|
|
44
59
|
/**
|
|
45
60
|
* Saves files received as an asynchronous iterable of multipart data.
|
|
46
61
|
*
|
|
@@ -85,8 +100,8 @@ export declare class FileService {
|
|
|
85
100
|
* setting (or set to `'keep'`) are left untouched.
|
|
86
101
|
*
|
|
87
102
|
* @param {string} resourceName - The resource model name.
|
|
88
|
-
* @param {
|
|
103
|
+
* @param {ResourceId} id - The ID of the deleted resource.
|
|
89
104
|
* @return {Promise<File[]>} A promise that resolves to the list of successfully deleted files.
|
|
90
105
|
*/
|
|
91
|
-
deleteResourceFiles(resourceName: string,
|
|
106
|
+
deleteResourceFiles(resourceName: string, id: ResourceId): Promise<File[]>;
|
|
92
107
|
}
|