@jskit-ai/users-core 0.1.67 → 0.1.69
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.descriptor.mjs +10 -10
- package/package.json +9 -9
- package/src/server/common/repositories/userProfilesRepository.js +34 -38
- package/src/server/common/repositories/userSettingsRepository.js +14 -15
- package/src/shared/resources/userProfileResource.js +7 -0
- package/test/repositoryContracts.test.js +67 -54
- package/test/usersRouteRequestInputValidator.test.js +18 -0
package/package.descriptor.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export default Object.freeze({
|
|
2
2
|
packageVersion: 1,
|
|
3
3
|
packageId: "@jskit-ai/users-core",
|
|
4
|
-
version: "0.1.
|
|
4
|
+
version: "0.1.69",
|
|
5
5
|
kind: "runtime",
|
|
6
6
|
description: "Users/account runtime plus HTTP routes for account features.",
|
|
7
7
|
dependsOn: [
|
|
@@ -132,16 +132,16 @@ export default Object.freeze({
|
|
|
132
132
|
mutations: {
|
|
133
133
|
dependencies: {
|
|
134
134
|
runtime: {
|
|
135
|
-
"@jskit-ai/auth-core": "0.1.
|
|
136
|
-
"@jskit-ai/crud-core": "0.1.
|
|
137
|
-
"@jskit-ai/database-runtime": "0.1.
|
|
138
|
-
"@jskit-ai/http-runtime": "0.1.
|
|
139
|
-
"@jskit-ai/json-rest-api-core": "0.1.
|
|
140
|
-
"@jskit-ai/kernel": "0.1.
|
|
141
|
-
"@jskit-ai/resource-core": "0.1.
|
|
142
|
-
"@jskit-ai/resource-crud-core": "0.1.
|
|
135
|
+
"@jskit-ai/auth-core": "0.1.58",
|
|
136
|
+
"@jskit-ai/crud-core": "0.1.67",
|
|
137
|
+
"@jskit-ai/database-runtime": "0.1.59",
|
|
138
|
+
"@jskit-ai/http-runtime": "0.1.58",
|
|
139
|
+
"@jskit-ai/json-rest-api-core": "0.1.4",
|
|
140
|
+
"@jskit-ai/kernel": "0.1.59",
|
|
141
|
+
"@jskit-ai/resource-core": "0.1.4",
|
|
142
|
+
"@jskit-ai/resource-crud-core": "0.1.4",
|
|
143
143
|
"@local/users": "file:packages/users",
|
|
144
|
-
"@jskit-ai/uploads-runtime": "0.1.
|
|
144
|
+
"@jskit-ai/uploads-runtime": "0.1.37"
|
|
145
145
|
},
|
|
146
146
|
dev: {}
|
|
147
147
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jskit-ai/users-core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.69",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "node --test"
|
|
@@ -11,14 +11,14 @@
|
|
|
11
11
|
"./shared/resources/userSettingsResource": "./src/shared/resources/userSettingsResource.js"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@jskit-ai/auth-core": "0.1.
|
|
15
|
-
"@jskit-ai/database-runtime": "0.1.
|
|
16
|
-
"@jskit-ai/http-runtime": "0.1.
|
|
17
|
-
"@jskit-ai/json-rest-api-core": "0.1.
|
|
18
|
-
"@jskit-ai/kernel": "0.1.
|
|
19
|
-
"@jskit-ai/resource-crud-core": "0.1.
|
|
20
|
-
"@jskit-ai/resource-core": "0.1.
|
|
21
|
-
"@jskit-ai/uploads-runtime": "0.1.
|
|
14
|
+
"@jskit-ai/auth-core": "0.1.58",
|
|
15
|
+
"@jskit-ai/database-runtime": "0.1.59",
|
|
16
|
+
"@jskit-ai/http-runtime": "0.1.58",
|
|
17
|
+
"@jskit-ai/json-rest-api-core": "0.1.4",
|
|
18
|
+
"@jskit-ai/kernel": "0.1.59",
|
|
19
|
+
"@jskit-ai/resource-crud-core": "0.1.4",
|
|
20
|
+
"@jskit-ai/resource-core": "0.1.4",
|
|
21
|
+
"@jskit-ai/uploads-runtime": "0.1.37",
|
|
22
22
|
"json-rest-schema": "1.x.x"
|
|
23
23
|
}
|
|
24
24
|
}
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
import {
|
|
12
12
|
createJsonApiInputRecord,
|
|
13
13
|
createJsonRestContext,
|
|
14
|
-
|
|
14
|
+
extractJsonRestCollectionRows
|
|
15
15
|
} from "@jskit-ai/json-rest-api-core/server/jsonRestApiHost";
|
|
16
16
|
import { normalizeIdentity } from "../support/identity.js";
|
|
17
17
|
|
|
@@ -142,18 +142,18 @@ async function resolveUniqueUsername(api, baseUsername, { excludeUserId = null,
|
|
|
142
142
|
|
|
143
143
|
for (let suffix = 0; suffix < 1000; suffix += 1) {
|
|
144
144
|
const candidate = buildUsernameCandidate(baseUsername, suffix);
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
const existing =
|
|
145
|
+
const existingRows = extractJsonRestCollectionRows(
|
|
146
|
+
await api.resources.userProfiles.query({
|
|
147
|
+
queryParams: {
|
|
148
|
+
filters: {
|
|
149
|
+
username: candidate
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
transaction,
|
|
153
|
+
simplified: true
|
|
154
|
+
})
|
|
155
|
+
);
|
|
156
|
+
const existing = existingRows[0] || null;
|
|
157
157
|
const existingId = normalizeDbRecordId(existing?.id, { fallback: null });
|
|
158
158
|
if (!existing || existingId === normalizedExcludeUserId) {
|
|
159
159
|
return candidate;
|
|
@@ -174,19 +174,20 @@ function createRepository({ api, knex } = {}) {
|
|
|
174
174
|
const withTransaction = createWithTransaction(knex);
|
|
175
175
|
|
|
176
176
|
async function queryFirst(filters = {}, options = {}) {
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
177
|
+
const rows = extractJsonRestCollectionRows(
|
|
178
|
+
await api.resources.userProfiles.query(
|
|
179
|
+
{
|
|
180
|
+
queryParams: {
|
|
181
|
+
filters
|
|
182
|
+
},
|
|
183
|
+
transaction: options?.trx || null,
|
|
184
|
+
simplified: true
|
|
181
185
|
},
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
},
|
|
185
|
-
createJsonRestContext(options?.context || null)
|
|
186
|
+
createJsonRestContext(options?.context || null)
|
|
187
|
+
)
|
|
186
188
|
);
|
|
187
189
|
|
|
188
|
-
|
|
189
|
-
return Array.isArray(rows) ? rows[0] || null : null;
|
|
190
|
+
return rows[0] || null;
|
|
190
191
|
}
|
|
191
192
|
|
|
192
193
|
async function findById(userId, options = {}) {
|
|
@@ -242,13 +243,12 @@ function createRepository({ api, knex } = {}) {
|
|
|
242
243
|
id: normalizedUserId
|
|
243
244
|
}
|
|
244
245
|
),
|
|
245
|
-
transaction: options?.trx || null
|
|
246
|
-
simplified: false
|
|
246
|
+
transaction: options?.trx || null
|
|
247
247
|
},
|
|
248
248
|
createJsonRestContext(options?.context || null)
|
|
249
249
|
);
|
|
250
250
|
|
|
251
|
-
return normalizeProfileRecord(
|
|
251
|
+
return normalizeProfileRecord(updated);
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
async function updateAvatarById(userId, avatar = {}, options = {}) {
|
|
@@ -271,13 +271,12 @@ function createRepository({ api, knex } = {}) {
|
|
|
271
271
|
id: normalizedUserId
|
|
272
272
|
}
|
|
273
273
|
),
|
|
274
|
-
transaction: options?.trx || null
|
|
275
|
-
simplified: false
|
|
274
|
+
transaction: options?.trx || null
|
|
276
275
|
},
|
|
277
276
|
createJsonRestContext(options?.context || null)
|
|
278
277
|
);
|
|
279
278
|
|
|
280
|
-
return normalizeProfileRecord(
|
|
279
|
+
return normalizeProfileRecord(updated);
|
|
281
280
|
}
|
|
282
281
|
|
|
283
282
|
async function clearAvatarById(userId, options = {}) {
|
|
@@ -300,13 +299,12 @@ function createRepository({ api, knex } = {}) {
|
|
|
300
299
|
id: normalizedUserId
|
|
301
300
|
}
|
|
302
301
|
),
|
|
303
|
-
transaction: options?.trx || null
|
|
304
|
-
simplified: false
|
|
302
|
+
transaction: options?.trx || null
|
|
305
303
|
},
|
|
306
304
|
createJsonRestContext(options?.context || null)
|
|
307
305
|
);
|
|
308
306
|
|
|
309
|
-
return normalizeProfileRecord(
|
|
307
|
+
return normalizeProfileRecord(updated);
|
|
310
308
|
}
|
|
311
309
|
|
|
312
310
|
async function upsert(profileLike = {}, options = {}) {
|
|
@@ -357,13 +355,12 @@ function createRepository({ api, knex } = {}) {
|
|
|
357
355
|
id: normalizeDbRecordId(existing.id, { fallback: null })
|
|
358
356
|
}
|
|
359
357
|
),
|
|
360
|
-
transaction: trx
|
|
361
|
-
simplified: false
|
|
358
|
+
transaction: trx
|
|
362
359
|
},
|
|
363
360
|
createJsonRestContext(options?.context || null)
|
|
364
361
|
);
|
|
365
362
|
|
|
366
|
-
return normalizeProfileRecord(
|
|
363
|
+
return normalizeProfileRecord(updated);
|
|
367
364
|
}
|
|
368
365
|
|
|
369
366
|
const username = await resolveUniqueUsername(
|
|
@@ -382,13 +379,12 @@ function createRepository({ api, knex } = {}) {
|
|
|
382
379
|
username,
|
|
383
380
|
createdAt: new Date()
|
|
384
381
|
}),
|
|
385
|
-
transaction: trx
|
|
386
|
-
simplified: false
|
|
382
|
+
transaction: trx
|
|
387
383
|
},
|
|
388
384
|
createJsonRestContext(options?.context || null)
|
|
389
385
|
);
|
|
390
386
|
|
|
391
|
-
return normalizeProfileRecord(
|
|
387
|
+
return normalizeProfileRecord(created);
|
|
392
388
|
} catch (error) {
|
|
393
389
|
if (duplicateTargetsEmail(error)) {
|
|
394
390
|
throw createDuplicateEmailConflictError();
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
import {
|
|
8
8
|
createJsonApiInputRecord,
|
|
9
9
|
createJsonRestContext,
|
|
10
|
-
|
|
10
|
+
extractJsonRestCollectionRows
|
|
11
11
|
} from "@jskit-ai/json-rest-api-core/server/jsonRestApiHost";
|
|
12
12
|
import { DEFAULT_USER_SETTINGS } from "../../../shared/settings.js";
|
|
13
13
|
|
|
@@ -67,19 +67,20 @@ function createRepository({ api, knex } = {}) {
|
|
|
67
67
|
const withTransaction = createWithTransaction(knex);
|
|
68
68
|
|
|
69
69
|
async function queryFirst(filters = {}, options = {}) {
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
const rows = extractJsonRestCollectionRows(
|
|
71
|
+
await api.resources.userSettings.query(
|
|
72
|
+
{
|
|
73
|
+
queryParams: {
|
|
74
|
+
filters
|
|
75
|
+
},
|
|
76
|
+
transaction: options?.trx || null,
|
|
77
|
+
simplified: true
|
|
74
78
|
},
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
},
|
|
78
|
-
createJsonRestContext(options?.context || null)
|
|
79
|
+
createJsonRestContext(options?.context || null)
|
|
80
|
+
)
|
|
79
81
|
);
|
|
80
82
|
|
|
81
|
-
|
|
82
|
-
return Array.isArray(rows) ? rows[0] || null : null;
|
|
83
|
+
return rows[0] || null;
|
|
83
84
|
}
|
|
84
85
|
|
|
85
86
|
async function findByUserId(userId, options = {}) {
|
|
@@ -112,8 +113,7 @@ function createRepository({ api, knex } = {}) {
|
|
|
112
113
|
id: normalizedUserId
|
|
113
114
|
}
|
|
114
115
|
),
|
|
115
|
-
transaction: options?.trx || null
|
|
116
|
-
simplified: false
|
|
116
|
+
transaction: options?.trx || null
|
|
117
117
|
},
|
|
118
118
|
createJsonRestContext(options?.context || null)
|
|
119
119
|
);
|
|
@@ -152,8 +152,7 @@ function createRepository({ api, knex } = {}) {
|
|
|
152
152
|
id: normalizedUserId
|
|
153
153
|
}
|
|
154
154
|
),
|
|
155
|
-
transaction: options?.trx || null
|
|
156
|
-
simplified: false
|
|
155
|
+
transaction: options?.trx || null
|
|
157
156
|
},
|
|
158
157
|
createJsonRestContext(options?.context || null)
|
|
159
158
|
);
|
|
@@ -42,6 +42,13 @@ const userProfileBodySchema = createSchema({
|
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
const avatarUploadBodySchema = createSchema({
|
|
45
|
+
stream: {
|
|
46
|
+
type: "none",
|
|
47
|
+
required: true,
|
|
48
|
+
messages: {
|
|
49
|
+
default: "Avatar stream is missing."
|
|
50
|
+
}
|
|
51
|
+
},
|
|
45
52
|
mimeType: {
|
|
46
53
|
type: "string",
|
|
47
54
|
required: false,
|
|
@@ -16,18 +16,24 @@ function createKnexStub() {
|
|
|
16
16
|
return knex;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
function asCollectionDocument(rows = []) {
|
|
20
|
+
return {
|
|
21
|
+
data: Array.isArray(rows) ? rows : []
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
19
25
|
test("users-core repositories expose withTransaction", async () => {
|
|
20
26
|
const knex = createKnexStub();
|
|
21
27
|
const api = {
|
|
22
28
|
resources: {
|
|
23
29
|
userProfiles: {
|
|
24
30
|
async query() {
|
|
25
|
-
return
|
|
31
|
+
return asCollectionDocument([]);
|
|
26
32
|
}
|
|
27
33
|
},
|
|
28
34
|
userSettings: {
|
|
29
35
|
async query() {
|
|
30
|
-
return
|
|
36
|
+
return asCollectionDocument([]);
|
|
31
37
|
}
|
|
32
38
|
}
|
|
33
39
|
}
|
|
@@ -54,23 +60,12 @@ function createUserProfilesApiStub(expectedRecord) {
|
|
|
54
60
|
userProfiles: {
|
|
55
61
|
async query({ queryParams }) {
|
|
56
62
|
calls.push(queryParams?.filters || {});
|
|
57
|
-
return
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
id: String(expectedRecord.id)
|
|
61
|
-
attributes: {
|
|
62
|
-
authProvider: expectedRecord.authProvider,
|
|
63
|
-
authProviderUserSid: expectedRecord.authProviderUserSid,
|
|
64
|
-
email: expectedRecord.email,
|
|
65
|
-
username: expectedRecord.username,
|
|
66
|
-
displayName: expectedRecord.displayName,
|
|
67
|
-
avatarStorageKey: expectedRecord.avatarStorageKey,
|
|
68
|
-
avatarVersion: expectedRecord.avatarVersion,
|
|
69
|
-
avatarUpdatedAt: expectedRecord.avatarUpdatedAt,
|
|
70
|
-
createdAt: expectedRecord.createdAt
|
|
71
|
-
}
|
|
63
|
+
return asCollectionDocument(
|
|
64
|
+
expectedRecord ? [{
|
|
65
|
+
...expectedRecord,
|
|
66
|
+
id: String(expectedRecord.id)
|
|
72
67
|
}] : []
|
|
73
|
-
|
|
68
|
+
);
|
|
74
69
|
}
|
|
75
70
|
}
|
|
76
71
|
}
|
|
@@ -89,28 +84,20 @@ test("userSettingsRepository.ensureForUserId sends transaction outside simplifie
|
|
|
89
84
|
userSettings: {
|
|
90
85
|
async query() {
|
|
91
86
|
queryCount += 1;
|
|
92
|
-
return
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
type: "userSettings",
|
|
87
|
+
return asCollectionDocument(
|
|
88
|
+
queryCount < 2
|
|
89
|
+
? []
|
|
90
|
+
: [{
|
|
97
91
|
id: "7",
|
|
98
|
-
|
|
99
|
-
...DEFAULT_USER_SETTINGS
|
|
100
|
-
}
|
|
92
|
+
...DEFAULT_USER_SETTINGS
|
|
101
93
|
}]
|
|
102
|
-
|
|
94
|
+
);
|
|
103
95
|
},
|
|
104
96
|
async post(params) {
|
|
105
97
|
postParams = params;
|
|
106
98
|
return {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
id: "7",
|
|
110
|
-
attributes: {
|
|
111
|
-
...DEFAULT_USER_SETTINGS
|
|
112
|
-
}
|
|
113
|
-
}
|
|
99
|
+
id: "7",
|
|
100
|
+
...DEFAULT_USER_SETTINGS
|
|
114
101
|
};
|
|
115
102
|
}
|
|
116
103
|
}
|
|
@@ -120,7 +107,7 @@ test("userSettingsRepository.ensureForUserId sends transaction outside simplifie
|
|
|
120
107
|
|
|
121
108
|
const record = await repository.ensureForUserId("7", { trx });
|
|
122
109
|
|
|
123
|
-
assert.equal(postParams?.simplified,
|
|
110
|
+
assert.equal(postParams?.simplified, undefined);
|
|
124
111
|
assert.equal(postParams?.transaction, trx);
|
|
125
112
|
assert.deepEqual(postParams?.inputRecord?.data, {
|
|
126
113
|
type: "userSettings",
|
|
@@ -144,32 +131,27 @@ test("userProfilesRepository.upsert sends native JSON:API write documents with t
|
|
|
144
131
|
async query({ queryParams }) {
|
|
145
132
|
const filters = queryParams?.filters || {};
|
|
146
133
|
if (Object.hasOwn(filters, "authProvider") || Object.hasOwn(filters, "authProviderUserSid")) {
|
|
147
|
-
return
|
|
134
|
+
return asCollectionDocument([]);
|
|
148
135
|
}
|
|
149
136
|
if (Object.hasOwn(filters, "username")) {
|
|
150
|
-
return
|
|
137
|
+
return asCollectionDocument([]);
|
|
151
138
|
}
|
|
152
|
-
return
|
|
139
|
+
return asCollectionDocument([]);
|
|
153
140
|
},
|
|
154
141
|
async post(params) {
|
|
155
142
|
postParams = params;
|
|
156
143
|
const attributes = params.inputRecord?.data?.attributes || {};
|
|
157
144
|
return {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
avatarVersion: null,
|
|
169
|
-
avatarUpdatedAt: null,
|
|
170
|
-
createdAt: attributes.createdAt
|
|
171
|
-
}
|
|
172
|
-
}
|
|
145
|
+
id: "11",
|
|
146
|
+
authProvider: attributes.authProvider,
|
|
147
|
+
authProviderUserSid: attributes.authProviderUserSid,
|
|
148
|
+
email: attributes.email,
|
|
149
|
+
username: attributes.username,
|
|
150
|
+
displayName: attributes.displayName,
|
|
151
|
+
avatarStorageKey: null,
|
|
152
|
+
avatarVersion: null,
|
|
153
|
+
avatarUpdatedAt: null,
|
|
154
|
+
createdAt: attributes.createdAt
|
|
173
155
|
};
|
|
174
156
|
}
|
|
175
157
|
}
|
|
@@ -184,7 +166,7 @@ test("userProfilesRepository.upsert sends native JSON:API write documents with t
|
|
|
184
166
|
displayName: "Ada Example"
|
|
185
167
|
}, { trx });
|
|
186
168
|
|
|
187
|
-
assert.equal(postParams?.simplified,
|
|
169
|
+
assert.equal(postParams?.simplified, undefined);
|
|
188
170
|
assert.equal(postParams?.transaction, trx);
|
|
189
171
|
assert.equal(postParams?.inputRecord?.transaction, undefined);
|
|
190
172
|
assert.equal(postParams?.inputRecord?.data?.type, "userProfiles");
|
|
@@ -218,6 +200,37 @@ test("userProfilesRepository.findByEmail normalizes email lookup", async () => {
|
|
|
218
200
|
assert.equal(profile?.displayName, "Ada Example");
|
|
219
201
|
});
|
|
220
202
|
|
|
203
|
+
test("userProfilesRepository.findByIdentity reads existing profiles from collection documents", async () => {
|
|
204
|
+
const { api, calls } = createUserProfilesApiStub({
|
|
205
|
+
id: 7,
|
|
206
|
+
authProvider: "supabase",
|
|
207
|
+
authProviderUserSid: "supabase-user-7",
|
|
208
|
+
email: "ada@example.com",
|
|
209
|
+
username: "ada",
|
|
210
|
+
displayName: "Ada Example",
|
|
211
|
+
avatarStorageKey: null,
|
|
212
|
+
avatarVersion: null,
|
|
213
|
+
avatarUpdatedAt: null,
|
|
214
|
+
createdAt: "2026-04-20T00:00:00.000Z"
|
|
215
|
+
});
|
|
216
|
+
const repository = createUserProfilesRepository({
|
|
217
|
+
api,
|
|
218
|
+
knex: createKnexStub()
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
const profile = await repository.findByIdentity({
|
|
222
|
+
provider: "supabase",
|
|
223
|
+
providerUserId: "supabase-user-7"
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
assert.deepEqual(calls, [{
|
|
227
|
+
authProvider: "supabase",
|
|
228
|
+
authProviderUserSid: "supabase-user-7"
|
|
229
|
+
}]);
|
|
230
|
+
assert.equal(profile?.id, "7");
|
|
231
|
+
assert.equal(profile?.displayName, "Ada Example");
|
|
232
|
+
});
|
|
233
|
+
|
|
221
234
|
test("userProfilesRepository.findByEmail returns null when the row is missing", async () => {
|
|
222
235
|
const { api } = createUserProfilesApiStub(undefined);
|
|
223
236
|
const repository = createUserProfilesRepository({
|
|
@@ -3,6 +3,8 @@ import test from "node:test";
|
|
|
3
3
|
import { UsersCoreServiceProvider } from "../src/server/UsersCoreServiceProvider.js";
|
|
4
4
|
import { INTERNAL_JSON_REST_API } from "@jskit-ai/json-rest-api-core/server/jsonRestApiHost";
|
|
5
5
|
import { createRouter } from "../../kernel/server/http/lib/router.js";
|
|
6
|
+
import { validateOperationSection } from "../../http-runtime/src/shared/validators/operationValidation.js";
|
|
7
|
+
import { userProfileResource } from "../src/shared/resources/userProfileResource.js";
|
|
6
8
|
|
|
7
9
|
function createReplyDouble() {
|
|
8
10
|
return {
|
|
@@ -268,3 +270,19 @@ test("account settings jsonapi transport resolves response resource id from requ
|
|
|
268
270
|
}
|
|
269
271
|
});
|
|
270
272
|
});
|
|
273
|
+
|
|
274
|
+
test("avatar upload operation accepts the internal multipart stream field", () => {
|
|
275
|
+
const parsed = validateOperationSection({
|
|
276
|
+
operation: userProfileResource.operations.avatarUpload,
|
|
277
|
+
section: "body",
|
|
278
|
+
value: {
|
|
279
|
+
stream: {},
|
|
280
|
+
mimeType: "image/png",
|
|
281
|
+
fileName: "avatar.png"
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
assert.equal(parsed.ok, true);
|
|
286
|
+
assert.equal(parsed.value.mimeType, "image/png");
|
|
287
|
+
assert.equal(parsed.value.fileName, "avatar.png");
|
|
288
|
+
});
|