@unchainedshop/api 4.3.0 → 4.3.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/lib/express/chatHandler.d.ts.map +1 -1
- package/lib/express/chatHandler.js +1 -3
- package/lib/express/chatHandler.js.map +1 -1
- package/lib/express/index.d.ts.map +1 -1
- package/lib/express/index.js +1 -1
- package/lib/express/index.js.map +1 -1
- package/lib/fastify/chatHandler.d.ts.map +1 -1
- package/lib/fastify/chatHandler.js +1 -3
- package/lib/fastify/chatHandler.js.map +1 -1
- package/lib/fastify/ercMetadataHandler.d.ts.map +1 -1
- package/lib/fastify/ercMetadataHandler.js +7 -4
- package/lib/fastify/ercMetadataHandler.js.map +1 -1
- package/lib/fastify/index.js +1 -1
- package/lib/fastify/index.js.map +1 -1
- package/lib/loaders/index.d.ts +27 -1
- package/lib/loaders/index.d.ts.map +1 -1
- package/lib/loaders/index.js +10 -2
- package/lib/loaders/index.js.map +1 -1
- package/lib/loaders/productBySKULoader.d.ts +10 -0
- package/lib/loaders/productBySKULoader.d.ts.map +1 -0
- package/lib/loaders/productBySKULoader.js +16 -0
- package/lib/loaders/productBySKULoader.js.map +1 -0
- package/lib/loaders/productVariationByKeyLoader.d.ts +12 -0
- package/lib/loaders/productVariationByKeyLoader.d.ts.map +1 -0
- package/lib/loaders/productVariationByKeyLoader.js +14 -0
- package/lib/loaders/productVariationByKeyLoader.js.map +1 -0
- package/lib/loaders/productVariationLoader.d.ts +10 -0
- package/lib/loaders/productVariationLoader.d.ts.map +1 -0
- package/lib/loaders/productVariationLoader.js +13 -0
- package/lib/loaders/productVariationLoader.js.map +1 -0
- package/lib/loaders/productVariationTextLoader.d.ts +14 -0
- package/lib/loaders/productVariationTextLoader.d.ts.map +1 -0
- package/lib/loaders/productVariationTextLoader.js +24 -0
- package/lib/loaders/productVariationTextLoader.js.map +1 -0
- package/lib/loaders/quotationLoader.d.ts +10 -0
- package/lib/loaders/quotationLoader.d.ts.map +1 -0
- package/lib/loaders/quotationLoader.js +13 -0
- package/lib/loaders/quotationLoader.js.map +1 -0
- package/lib/mcp/resources/localization.d.ts.map +1 -1
- package/lib/mcp/resources/localization.js +0 -15
- package/lib/mcp/resources/localization.js.map +1 -1
- package/lib/mongo-store.d.ts +94 -0
- package/lib/mongo-store.d.ts.map +1 -0
- package/lib/mongo-store.js +368 -0
- package/lib/mongo-store.js.map +1 -0
- package/lib/resolvers/type/index.d.ts +1 -1
- package/lib/resolvers/type/order/order-item-types.d.ts +1 -1
- package/lib/resolvers/type/order/order-item-types.d.ts.map +1 -1
- package/lib/resolvers/type/order/order-item-types.js +2 -3
- package/lib/resolvers/type/order/order-item-types.js.map +1 -1
- package/lib/resolvers/type/product/product-variation-assignment-vector.d.ts.map +1 -1
- package/lib/resolvers/type/product/product-variation-assignment-vector.js +4 -6
- package/lib/resolvers/type/product/product-variation-assignment-vector.js.map +1 -1
- package/lib/resolvers/type/product/product-variation-option-types.d.ts.map +1 -1
- package/lib/resolvers/type/product/product-variation-option-types.js +2 -3
- package/lib/resolvers/type/product/product-variation-option-types.js.map +1 -1
- package/lib/resolvers/type/product/product-variation-types.d.ts.map +1 -1
- package/lib/resolvers/type/product/product-variation-types.js +2 -3
- package/lib/resolvers/type/product/product-variation-types.js.map +1 -1
- package/package.json +6 -9
- package/src/express/chatHandler.ts +3 -8
- package/src/express/index.ts +3 -2
- package/src/fastify/chatHandler.ts +3 -8
- package/src/fastify/ercMetadataHandler.ts +9 -4
- package/src/fastify/index.ts +1 -1
- package/src/loaders/index.ts +11 -2
- package/src/loaders/productVariationByKeyLoader.ts +20 -0
- package/src/loaders/productVariationLoader.ts +19 -0
- package/src/loaders/productVariationTextLoader.ts +37 -0
- package/src/loaders/quotationLoader.ts +19 -0
- package/src/mcp/resources/localization.ts +0 -15
- package/src/mongo-store.ts +500 -0
- package/src/resolvers/type/order/order-item-types.ts +2 -3
- package/src/resolvers/type/product/product-variation-assignment-vector.ts +4 -6
- package/src/resolvers/type/product/product-variation-option-types.ts +2 -3
- package/src/resolvers/type/product/product-variation-types.ts +2 -3
- /package/src/loaders/{productLoaderBySKU.ts → productBySKULoader.ts} +0 -0
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
/*
|
|
2
|
+
MIT License
|
|
3
|
+
Fork of https://github.com/jdesboeufs/connect-mongo#readme Connect Mongo
|
|
4
|
+
Thanks to Casey Banner, Jerome Desboeufs, MC Or
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { assert } from 'node:console';
|
|
8
|
+
import util from 'node:util';
|
|
9
|
+
import * as session from 'express-session';
|
|
10
|
+
import { Collection, MongoClient, MongoClientOptions, WriteConcernSettings } from 'mongodb';
|
|
11
|
+
import { createLogger } from '@unchainedshop/logger';
|
|
12
|
+
|
|
13
|
+
const logger = createLogger('unchained:api');
|
|
14
|
+
|
|
15
|
+
export interface CryptoOptions {
|
|
16
|
+
secret: false | string;
|
|
17
|
+
algorithm?: string;
|
|
18
|
+
hashing?: string;
|
|
19
|
+
encodeas?: string;
|
|
20
|
+
key_size?: number;
|
|
21
|
+
iv_size?: number;
|
|
22
|
+
at_size?: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface ConnectMongoOptions {
|
|
26
|
+
mongoUrl?: string;
|
|
27
|
+
clientPromise?: Promise<MongoClient>;
|
|
28
|
+
client?: MongoClient;
|
|
29
|
+
collectionName?: string;
|
|
30
|
+
mongoOptions?: MongoClientOptions;
|
|
31
|
+
dbName?: string;
|
|
32
|
+
ttl?: number;
|
|
33
|
+
touchAfter?: number;
|
|
34
|
+
stringify?: boolean;
|
|
35
|
+
createAutoRemoveIdx?: boolean;
|
|
36
|
+
autoRemove?: 'native' | 'interval' | 'disabled';
|
|
37
|
+
autoRemoveInterval?: number;
|
|
38
|
+
// FIXME: remove those any
|
|
39
|
+
serialize?: (a: any) => any;
|
|
40
|
+
unserialize?: (a: any) => any;
|
|
41
|
+
writeOperationOptions?: WriteConcernSettings;
|
|
42
|
+
transformId?: (a: any) => any;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
type ConcretCryptoOptions = Required<CryptoOptions>;
|
|
46
|
+
|
|
47
|
+
interface ConcretConnectMongoOptions {
|
|
48
|
+
mongoUrl?: string;
|
|
49
|
+
clientPromise?: Promise<MongoClient>;
|
|
50
|
+
client?: MongoClient;
|
|
51
|
+
collectionName: string;
|
|
52
|
+
mongoOptions: MongoClientOptions;
|
|
53
|
+
dbName?: string;
|
|
54
|
+
ttl: number;
|
|
55
|
+
createAutoRemoveIdx?: boolean;
|
|
56
|
+
autoRemove: 'native' | 'interval' | 'disabled';
|
|
57
|
+
autoRemoveInterval: number;
|
|
58
|
+
touchAfter: number;
|
|
59
|
+
stringify: boolean;
|
|
60
|
+
// FIXME: remove those any
|
|
61
|
+
serialize?: (a: any) => any;
|
|
62
|
+
unserialize?: (a: any) => any;
|
|
63
|
+
writeOperationOptions?: WriteConcernSettings;
|
|
64
|
+
transformId?: (a: any) => any;
|
|
65
|
+
// FIXME: remove above any
|
|
66
|
+
crypto: ConcretCryptoOptions;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
interface InternalSessionType {
|
|
70
|
+
_id: string;
|
|
71
|
+
session: any;
|
|
72
|
+
expires?: Date;
|
|
73
|
+
lastModified?: Date;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
77
|
+
const noop = () => {};
|
|
78
|
+
const unit: <T>(a: T) => T = (a) => a;
|
|
79
|
+
|
|
80
|
+
function defaultSerializeFunction(session: session.SessionData): session.SessionData {
|
|
81
|
+
// Copy each property of the session to a new object
|
|
82
|
+
const obj = {};
|
|
83
|
+
let prop;
|
|
84
|
+
for (prop in session) {
|
|
85
|
+
if (prop === 'cookie') {
|
|
86
|
+
// Convert the cookie instance to an object, if possible
|
|
87
|
+
// This gets rid of the duplicate object under session.cookie.data property
|
|
88
|
+
// @ts-expect-error FIXME:
|
|
89
|
+
obj.cookie = session.cookie.toJSON ? session.cookie.toJSON() : session.cookie;
|
|
90
|
+
} else {
|
|
91
|
+
obj[prop] = session[prop];
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return obj as session.SessionData;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function computeTransformFunctions(options: ConcretConnectMongoOptions) {
|
|
99
|
+
if (options.serialize || options.unserialize) {
|
|
100
|
+
return {
|
|
101
|
+
serialize: options.serialize || defaultSerializeFunction,
|
|
102
|
+
unserialize: options.unserialize || unit,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (options.stringify === false) {
|
|
107
|
+
return {
|
|
108
|
+
serialize: defaultSerializeFunction,
|
|
109
|
+
unserialize: unit,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
// Default case
|
|
113
|
+
return {
|
|
114
|
+
serialize: JSON.stringify,
|
|
115
|
+
unserialize: JSON.parse,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export default class MongoStore extends session.Store {
|
|
120
|
+
private clientP: Promise<MongoClient>;
|
|
121
|
+
private crypto: any = null;
|
|
122
|
+
private timer?: NodeJS.Timeout;
|
|
123
|
+
collectionP: Promise<Collection<InternalSessionType>>;
|
|
124
|
+
private options: ConcretConnectMongoOptions;
|
|
125
|
+
// FIXME: remvoe any
|
|
126
|
+
private transformFunctions: {
|
|
127
|
+
serialize: (a: any) => any;
|
|
128
|
+
unserialize: (a: any) => any;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
constructor({
|
|
132
|
+
collectionName = 'sessions',
|
|
133
|
+
ttl = 1209600,
|
|
134
|
+
mongoOptions = {},
|
|
135
|
+
autoRemove = 'native',
|
|
136
|
+
autoRemoveInterval = 10,
|
|
137
|
+
touchAfter = 0,
|
|
138
|
+
stringify = true,
|
|
139
|
+
...required
|
|
140
|
+
}: ConnectMongoOptions) {
|
|
141
|
+
super();
|
|
142
|
+
logger.debug('create MongoStore instance');
|
|
143
|
+
const options: ConcretConnectMongoOptions = {
|
|
144
|
+
collectionName,
|
|
145
|
+
ttl,
|
|
146
|
+
mongoOptions,
|
|
147
|
+
autoRemove,
|
|
148
|
+
autoRemoveInterval,
|
|
149
|
+
touchAfter,
|
|
150
|
+
stringify,
|
|
151
|
+
crypto: {
|
|
152
|
+
secret: false,
|
|
153
|
+
algorithm: 'aes-256-gcm',
|
|
154
|
+
hashing: 'sha512',
|
|
155
|
+
encodeas: 'base64',
|
|
156
|
+
key_size: 32,
|
|
157
|
+
iv_size: 16,
|
|
158
|
+
at_size: 16,
|
|
159
|
+
},
|
|
160
|
+
...required,
|
|
161
|
+
};
|
|
162
|
+
// Check params
|
|
163
|
+
assert(
|
|
164
|
+
options.mongoUrl || options.clientPromise || options.client,
|
|
165
|
+
'You must provide either mongoUrl|clientPromise|client in options',
|
|
166
|
+
);
|
|
167
|
+
assert(
|
|
168
|
+
options.createAutoRemoveIdx === null || options.createAutoRemoveIdx === undefined,
|
|
169
|
+
'options.createAutoRemoveIdx has been reverted to autoRemove and autoRemoveInterval',
|
|
170
|
+
);
|
|
171
|
+
assert(
|
|
172
|
+
!options.autoRemoveInterval || options.autoRemoveInterval <= 71582,
|
|
173
|
+
/* (Math.pow(2, 32) - 1) / (1000 * 60) */ 'autoRemoveInterval is too large. options.autoRemoveInterval is in minutes but not seconds nor mills',
|
|
174
|
+
);
|
|
175
|
+
this.transformFunctions = computeTransformFunctions(options);
|
|
176
|
+
let _clientP: Promise<MongoClient>;
|
|
177
|
+
if (options.mongoUrl) {
|
|
178
|
+
_clientP = MongoClient.connect(options.mongoUrl, options.mongoOptions);
|
|
179
|
+
} else if (options.clientPromise) {
|
|
180
|
+
_clientP = options.clientPromise;
|
|
181
|
+
} else if (options.client) {
|
|
182
|
+
_clientP = Promise.resolve(options.client);
|
|
183
|
+
} else {
|
|
184
|
+
throw new Error('Cannot init client. Please provide correct options');
|
|
185
|
+
}
|
|
186
|
+
assert(!!_clientP, 'Client is null|undefined');
|
|
187
|
+
this.clientP = _clientP;
|
|
188
|
+
this.options = options;
|
|
189
|
+
this.collectionP = _clientP.then(async (con) => {
|
|
190
|
+
const collection = con.db(options.dbName).collection<InternalSessionType>(options.collectionName);
|
|
191
|
+
await this.setAutoRemove(collection);
|
|
192
|
+
return collection;
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
static create(options: ConnectMongoOptions): MongoStore {
|
|
197
|
+
return new MongoStore(options);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
private setAutoRemove(collection: Collection<InternalSessionType>): Promise<unknown> {
|
|
201
|
+
const removeQuery = () => ({
|
|
202
|
+
expires: {
|
|
203
|
+
$lt: new Date(),
|
|
204
|
+
},
|
|
205
|
+
});
|
|
206
|
+
switch (this.options.autoRemove) {
|
|
207
|
+
case 'native':
|
|
208
|
+
logger.debug('Creating MongoDB TTL index');
|
|
209
|
+
return collection.createIndex(
|
|
210
|
+
{ expires: 1 },
|
|
211
|
+
{
|
|
212
|
+
background: true,
|
|
213
|
+
expireAfterSeconds: 0,
|
|
214
|
+
},
|
|
215
|
+
);
|
|
216
|
+
case 'interval':
|
|
217
|
+
logger.debug('create Timer to remove expired sessions');
|
|
218
|
+
this.timer = setInterval(
|
|
219
|
+
() =>
|
|
220
|
+
collection.deleteMany(removeQuery(), {
|
|
221
|
+
writeConcern: {
|
|
222
|
+
w: 0,
|
|
223
|
+
j: false,
|
|
224
|
+
},
|
|
225
|
+
}),
|
|
226
|
+
this.options.autoRemoveInterval * 1000 * 60,
|
|
227
|
+
);
|
|
228
|
+
this.timer.unref();
|
|
229
|
+
return Promise.resolve();
|
|
230
|
+
case 'disabled':
|
|
231
|
+
default:
|
|
232
|
+
return Promise.resolve();
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
private computeStorageId(sessionId: string) {
|
|
237
|
+
if (this.options.transformId && typeof this.options.transformId === 'function') {
|
|
238
|
+
return this.options.transformId(sessionId);
|
|
239
|
+
}
|
|
240
|
+
return sessionId;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* promisify and bind the `this.crypto.get` function.
|
|
245
|
+
* Please check !!this.crypto === true before using this getter!
|
|
246
|
+
*/
|
|
247
|
+
private get cryptoGet() {
|
|
248
|
+
if (!this.crypto) {
|
|
249
|
+
throw new Error('Check this.crypto before calling this.cryptoGet!');
|
|
250
|
+
}
|
|
251
|
+
return util.promisify(this.crypto.get).bind(this.crypto);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Decrypt given session data
|
|
256
|
+
* @param session session data to be decrypt. Mutate the input session.
|
|
257
|
+
*/
|
|
258
|
+
private async decryptSession(session: session.SessionData | undefined | null) {
|
|
259
|
+
if (this.crypto && session) {
|
|
260
|
+
const plaintext = await this.cryptoGet(
|
|
261
|
+
this.options.crypto.secret as string,
|
|
262
|
+
(session as any).session,
|
|
263
|
+
).catch((err: any) => {
|
|
264
|
+
throw new Error(err);
|
|
265
|
+
});
|
|
266
|
+
(session as any).session = JSON.parse(plaintext);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Get a session from the store given a session ID (sid)
|
|
272
|
+
* @param sid session ID
|
|
273
|
+
*/
|
|
274
|
+
get(sid: string, callback: (err: any, session?: session.SessionData | null) => void): void {
|
|
275
|
+
(async () => {
|
|
276
|
+
try {
|
|
277
|
+
logger.debug(`MongoStore#get=${sid}`);
|
|
278
|
+
const collection = await this.collectionP;
|
|
279
|
+
const session = await collection.findOne({
|
|
280
|
+
_id: this.computeStorageId(sid),
|
|
281
|
+
$or: [{ expires: { $exists: false } }, { expires: { $gt: new Date() } }],
|
|
282
|
+
});
|
|
283
|
+
if (this.crypto && session) {
|
|
284
|
+
await this.decryptSession(session as unknown as session.SessionData).catch((err) =>
|
|
285
|
+
callback(err),
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
const s = session && this.transformFunctions.unserialize(session.session);
|
|
289
|
+
if (this.options.touchAfter > 0 && session?.lastModified) {
|
|
290
|
+
s.lastModified = session.lastModified;
|
|
291
|
+
}
|
|
292
|
+
this.emit('get', sid);
|
|
293
|
+
callback(null, s === undefined ? null : s);
|
|
294
|
+
} catch (error) {
|
|
295
|
+
callback(error);
|
|
296
|
+
}
|
|
297
|
+
})();
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Upsert a session into the store given a session ID (sid) and session (session) object.
|
|
302
|
+
* @param sid session ID
|
|
303
|
+
* @param session session object
|
|
304
|
+
*/
|
|
305
|
+
set(sid: string, session: session.SessionData, callback: (err: any) => void = noop): void {
|
|
306
|
+
(async () => {
|
|
307
|
+
try {
|
|
308
|
+
logger.debug(`MongoStore#set=${sid}`);
|
|
309
|
+
// Removing the lastModified prop from the session object before update
|
|
310
|
+
// @ts-expect-error Session not typed
|
|
311
|
+
if (this.options.touchAfter > 0 && session?.lastModified) {
|
|
312
|
+
// @ts-expect-error Session not typed
|
|
313
|
+
delete session.lastModified;
|
|
314
|
+
}
|
|
315
|
+
const s: InternalSessionType = {
|
|
316
|
+
_id: this.computeStorageId(sid),
|
|
317
|
+
session: this.transformFunctions.serialize(session),
|
|
318
|
+
};
|
|
319
|
+
// Expire handling
|
|
320
|
+
if (session?.cookie?.expires) {
|
|
321
|
+
s.expires = new Date(session.cookie.expires);
|
|
322
|
+
} else {
|
|
323
|
+
// If there's no expiration date specified, it is
|
|
324
|
+
// browser-session cookie or there is no cookie at all,
|
|
325
|
+
// as per the connect docs.
|
|
326
|
+
//
|
|
327
|
+
// So we set the expiration to two-weeks from now
|
|
328
|
+
// - as is common practice in the industry (e.g Django) -
|
|
329
|
+
// or the default specified in the options.
|
|
330
|
+
s.expires = new Date(Date.now() + this.options.ttl * 1000);
|
|
331
|
+
}
|
|
332
|
+
// Last modify handling
|
|
333
|
+
if (this.options.touchAfter > 0) {
|
|
334
|
+
s.lastModified = new Date();
|
|
335
|
+
}
|
|
336
|
+
if (this.crypto) {
|
|
337
|
+
const cryptoSet = util.promisify(this.crypto.set).bind(this.crypto);
|
|
338
|
+
const data = await cryptoSet(this.options.crypto.secret as string, s.session).catch(
|
|
339
|
+
(err: any) => {
|
|
340
|
+
throw new Error(err);
|
|
341
|
+
},
|
|
342
|
+
);
|
|
343
|
+
s.session = data as unknown as session.SessionData;
|
|
344
|
+
}
|
|
345
|
+
const collection = await this.collectionP;
|
|
346
|
+
const rawResp = await collection.updateOne(
|
|
347
|
+
{ _id: s._id },
|
|
348
|
+
{ $set: s },
|
|
349
|
+
{
|
|
350
|
+
upsert: true,
|
|
351
|
+
writeConcern: this.options.writeOperationOptions,
|
|
352
|
+
},
|
|
353
|
+
);
|
|
354
|
+
if (rawResp.upsertedCount > 0) {
|
|
355
|
+
this.emit('create', sid);
|
|
356
|
+
} else {
|
|
357
|
+
this.emit('update', sid);
|
|
358
|
+
}
|
|
359
|
+
this.emit('set', sid);
|
|
360
|
+
} catch (error) {
|
|
361
|
+
return callback(error);
|
|
362
|
+
}
|
|
363
|
+
return callback(null);
|
|
364
|
+
})();
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
touch(
|
|
368
|
+
sid: string,
|
|
369
|
+
session: session.SessionData & { lastModified?: Date },
|
|
370
|
+
callback: (err: any) => void = noop,
|
|
371
|
+
): void {
|
|
372
|
+
(async () => {
|
|
373
|
+
try {
|
|
374
|
+
logger.debug(`MongoStore#touch=${sid}`);
|
|
375
|
+
const updateFields: {
|
|
376
|
+
lastModified?: Date;
|
|
377
|
+
expires?: Date;
|
|
378
|
+
session?: session.SessionData;
|
|
379
|
+
} = {};
|
|
380
|
+
const touchAfter = this.options.touchAfter * 1000;
|
|
381
|
+
const lastModified = session.lastModified ? session.lastModified.getTime() : 0;
|
|
382
|
+
const currentDate = new Date();
|
|
383
|
+
|
|
384
|
+
// If the given options has a touchAfter property, check if the
|
|
385
|
+
// current timestamp - lastModified timestamp is bigger than
|
|
386
|
+
// the specified, if it's not, don't touch the session
|
|
387
|
+
if (touchAfter > 0 && lastModified > 0) {
|
|
388
|
+
const timeElapsed = currentDate.getTime() - lastModified;
|
|
389
|
+
if (timeElapsed < touchAfter) {
|
|
390
|
+
logger.debug(`Skip touching session=${sid}`);
|
|
391
|
+
return callback(null);
|
|
392
|
+
}
|
|
393
|
+
updateFields.lastModified = currentDate;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
if (session?.cookie?.expires) {
|
|
397
|
+
updateFields.expires = new Date(session.cookie.expires);
|
|
398
|
+
} else {
|
|
399
|
+
updateFields.expires = new Date(Date.now() + this.options.ttl * 1000);
|
|
400
|
+
}
|
|
401
|
+
const collection = await this.collectionP;
|
|
402
|
+
const rawResp = await collection.updateOne(
|
|
403
|
+
{ _id: this.computeStorageId(sid) },
|
|
404
|
+
{ $set: updateFields },
|
|
405
|
+
{ writeConcern: this.options.writeOperationOptions },
|
|
406
|
+
);
|
|
407
|
+
if (rawResp.matchedCount === 0) {
|
|
408
|
+
return callback(new Error('Unable to find the session to touch'));
|
|
409
|
+
} else {
|
|
410
|
+
this.emit('touch', sid, session);
|
|
411
|
+
return callback(null);
|
|
412
|
+
}
|
|
413
|
+
} catch (error) {
|
|
414
|
+
return callback(error);
|
|
415
|
+
}
|
|
416
|
+
})();
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Get all sessions in the store as an array
|
|
421
|
+
*/
|
|
422
|
+
all(
|
|
423
|
+
callback: (
|
|
424
|
+
err: any,
|
|
425
|
+
obj?: session.SessionData[] | Record<string, session.SessionData> | null,
|
|
426
|
+
) => void,
|
|
427
|
+
): void {
|
|
428
|
+
(async () => {
|
|
429
|
+
try {
|
|
430
|
+
logger.debug('MongoStore#all()');
|
|
431
|
+
const collection = await this.collectionP;
|
|
432
|
+
const sessions = collection.find({
|
|
433
|
+
$or: [{ expires: { $exists: false } }, { expires: { $gt: new Date() } }],
|
|
434
|
+
});
|
|
435
|
+
const results: session.SessionData[] = [];
|
|
436
|
+
for await (const session of sessions) {
|
|
437
|
+
if (this.crypto && session) {
|
|
438
|
+
await this.decryptSession(session as unknown as session.SessionData);
|
|
439
|
+
}
|
|
440
|
+
results.push(this.transformFunctions.unserialize(session.session));
|
|
441
|
+
}
|
|
442
|
+
this.emit('all', results);
|
|
443
|
+
callback(null, results);
|
|
444
|
+
} catch (error) {
|
|
445
|
+
callback(error);
|
|
446
|
+
}
|
|
447
|
+
})();
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Destroy/delete a session from the store given a session ID (sid)
|
|
452
|
+
* @param sid session ID
|
|
453
|
+
*/
|
|
454
|
+
destroy(sid: string, callback: (err: any) => void = noop): void {
|
|
455
|
+
logger.debug(`MongoStore#destroy=${sid}`);
|
|
456
|
+
this.collectionP
|
|
457
|
+
.then((colleciton) =>
|
|
458
|
+
colleciton.deleteOne(
|
|
459
|
+
{ _id: this.computeStorageId(sid) },
|
|
460
|
+
{ writeConcern: this.options.writeOperationOptions },
|
|
461
|
+
),
|
|
462
|
+
)
|
|
463
|
+
.then(() => {
|
|
464
|
+
this.emit('destroy', sid);
|
|
465
|
+
callback(null);
|
|
466
|
+
})
|
|
467
|
+
.catch((err) => callback(err));
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Get the count of all sessions in the store
|
|
472
|
+
*/
|
|
473
|
+
length(callback: (err: any, length: number) => void): void {
|
|
474
|
+
logger.debug('MongoStore#length()');
|
|
475
|
+
this.collectionP
|
|
476
|
+
.then((collection) => collection.countDocuments())
|
|
477
|
+
.then((c) => callback(null, c))
|
|
478
|
+
// @ts-expect-error Callback wrong type
|
|
479
|
+
.catch((err) => callback(err));
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Delete all sessions from the store.
|
|
484
|
+
*/
|
|
485
|
+
clear(callback: (err: any) => void = noop): void {
|
|
486
|
+
logger.debug('MongoStore#clear()');
|
|
487
|
+
this.collectionP
|
|
488
|
+
.then((collection) => collection.drop())
|
|
489
|
+
.then(() => callback(null))
|
|
490
|
+
.catch((err) => callback(err));
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Close database connection
|
|
495
|
+
*/
|
|
496
|
+
close(): Promise<void> {
|
|
497
|
+
logger.debug('MongoStore#close()');
|
|
498
|
+
return this.clientP.then((c) => c.close());
|
|
499
|
+
}
|
|
500
|
+
}
|
|
@@ -113,10 +113,9 @@ export const OrderItem = {
|
|
|
113
113
|
return product;
|
|
114
114
|
},
|
|
115
115
|
|
|
116
|
-
async quotation(orderPosition: OrderPosition, _, {
|
|
116
|
+
async quotation(orderPosition: OrderPosition, _, { loaders }: Context): Promise<Quotation | null> {
|
|
117
117
|
if (!orderPosition.quotationId) return null;
|
|
118
|
-
|
|
119
|
-
return modules.quotations.findQuotation({ quotationId: orderPosition.quotationId });
|
|
118
|
+
return loaders.quotationLoader.load({ quotationId: orderPosition.quotationId });
|
|
120
119
|
},
|
|
121
120
|
|
|
122
121
|
async total(
|
|
@@ -17,9 +17,8 @@ export interface ProductVariationAssignmentVectorHelperTypes {
|
|
|
17
17
|
export const ProductVariationAssignmentVector: ProductVariationAssignmentVectorHelperTypes = {
|
|
18
18
|
_id: ({ product, key, value }) => `${product._id}:${key}=${value}`,
|
|
19
19
|
|
|
20
|
-
option: async (obj, _, {
|
|
21
|
-
|
|
22
|
-
const productVariation = await modules.products.variations.findProductVariationByKey({
|
|
20
|
+
option: async (obj, _, { loaders }) => {
|
|
21
|
+
const productVariation = await loaders.productVariationByKeyLoader.load({
|
|
23
22
|
productId: obj.product._id,
|
|
24
23
|
key: obj.key,
|
|
25
24
|
});
|
|
@@ -32,9 +31,8 @@ export const ProductVariationAssignmentVector: ProductVariationAssignmentVectorH
|
|
|
32
31
|
};
|
|
33
32
|
},
|
|
34
33
|
|
|
35
|
-
variation: (obj, _, {
|
|
36
|
-
|
|
37
|
-
return modules.products.variations.findProductVariationByKey({
|
|
34
|
+
variation: (obj, _, { loaders }) => {
|
|
35
|
+
return loaders.productVariationByKeyLoader.load({
|
|
38
36
|
productId: obj?.product?._id,
|
|
39
37
|
key: obj?.key,
|
|
40
38
|
});
|
|
@@ -20,9 +20,8 @@ export const ProductVariationOption: ProductVariationOptionHelperTypes = {
|
|
|
20
20
|
return obj.productVariationOption;
|
|
21
21
|
},
|
|
22
22
|
|
|
23
|
-
texts: async (obj, { forceLocale }, {
|
|
24
|
-
|
|
25
|
-
return modules.products.variations.texts.findLocalizedVariationText({
|
|
23
|
+
texts: async (obj, { forceLocale }, { loaders, locale }) => {
|
|
24
|
+
return loaders.productVariationTextLoader.load({
|
|
26
25
|
productVariationId: obj._id,
|
|
27
26
|
productVariationOptionValue: obj.productVariationOption,
|
|
28
27
|
locale: forceLocale ? new Intl.Locale(forceLocale) : locale,
|
|
@@ -28,9 +28,8 @@ export const ProductVariation: ProductVariationHelperTypes = {
|
|
|
28
28
|
}));
|
|
29
29
|
},
|
|
30
30
|
|
|
31
|
-
texts: async (obj, { forceLocale }, {
|
|
32
|
-
|
|
33
|
-
return modules.products.variations.texts.findLocalizedVariationText({
|
|
31
|
+
texts: async (obj, { forceLocale }, { loaders, locale }) => {
|
|
32
|
+
return loaders.productVariationTextLoader.load({
|
|
34
33
|
productVariationId: obj._id,
|
|
35
34
|
locale: forceLocale ? new Intl.Locale(forceLocale) : locale,
|
|
36
35
|
});
|
|
File without changes
|