@unchainedshop/api 4.2.2 → 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.
Files changed (117) hide show
  1. package/lib/express/chatHandler.d.ts.map +1 -1
  2. package/lib/express/chatHandler.js +1 -3
  3. package/lib/express/chatHandler.js.map +1 -1
  4. package/lib/express/index.d.ts.map +1 -1
  5. package/lib/express/index.js +1 -1
  6. package/lib/express/index.js.map +1 -1
  7. package/lib/fastify/chatHandler.d.ts.map +1 -1
  8. package/lib/fastify/chatHandler.js +1 -3
  9. package/lib/fastify/chatHandler.js.map +1 -1
  10. package/lib/fastify/ercMetadataHandler.d.ts.map +1 -1
  11. package/lib/fastify/ercMetadataHandler.js +7 -4
  12. package/lib/fastify/ercMetadataHandler.js.map +1 -1
  13. package/lib/fastify/index.js +1 -1
  14. package/lib/fastify/index.js.map +1 -1
  15. package/lib/loaders/index.d.ts +27 -1
  16. package/lib/loaders/index.d.ts.map +1 -1
  17. package/lib/loaders/index.js +10 -2
  18. package/lib/loaders/index.js.map +1 -1
  19. package/lib/loaders/productBySKULoader.d.ts +10 -0
  20. package/lib/loaders/productBySKULoader.d.ts.map +1 -0
  21. package/lib/loaders/productBySKULoader.js +16 -0
  22. package/lib/loaders/productBySKULoader.js.map +1 -0
  23. package/lib/loaders/productVariationByKeyLoader.d.ts +12 -0
  24. package/lib/loaders/productVariationByKeyLoader.d.ts.map +1 -0
  25. package/lib/loaders/productVariationByKeyLoader.js +14 -0
  26. package/lib/loaders/productVariationByKeyLoader.js.map +1 -0
  27. package/lib/loaders/productVariationLoader.d.ts +10 -0
  28. package/lib/loaders/productVariationLoader.d.ts.map +1 -0
  29. package/lib/loaders/productVariationLoader.js +13 -0
  30. package/lib/loaders/productVariationLoader.js.map +1 -0
  31. package/lib/loaders/productVariationTextLoader.d.ts +14 -0
  32. package/lib/loaders/productVariationTextLoader.d.ts.map +1 -0
  33. package/lib/loaders/productVariationTextLoader.js +24 -0
  34. package/lib/loaders/productVariationTextLoader.js.map +1 -0
  35. package/lib/loaders/quotationLoader.d.ts +10 -0
  36. package/lib/loaders/quotationLoader.d.ts.map +1 -0
  37. package/lib/loaders/quotationLoader.js +13 -0
  38. package/lib/loaders/quotationLoader.js.map +1 -0
  39. package/lib/mcp/resources/localization.d.ts.map +1 -1
  40. package/lib/mcp/resources/localization.js +0 -15
  41. package/lib/mcp/resources/localization.js.map +1 -1
  42. package/lib/mongo-store.d.ts +94 -0
  43. package/lib/mongo-store.d.ts.map +1 -0
  44. package/lib/mongo-store.js +368 -0
  45. package/lib/mongo-store.js.map +1 -0
  46. package/lib/resolvers/type/delivery-provider-interface.d.ts +18 -0
  47. package/lib/resolvers/type/delivery-provider-interface.d.ts.map +1 -0
  48. package/lib/resolvers/type/delivery-provider-interface.js +48 -0
  49. package/lib/resolvers/type/delivery-provider-interface.js.map +1 -0
  50. package/lib/resolvers/type/delivery-provider-pickup-types.d.ts +20 -0
  51. package/lib/resolvers/type/delivery-provider-pickup-types.d.ts.map +1 -0
  52. package/lib/resolvers/type/delivery-provider-pickup-types.js +10 -0
  53. package/lib/resolvers/type/delivery-provider-pickup-types.js.map +1 -0
  54. package/lib/resolvers/type/delivery-provider-shipping-types.d.ts +17 -0
  55. package/lib/resolvers/type/delivery-provider-shipping-types.d.ts.map +1 -0
  56. package/lib/resolvers/type/delivery-provider-shipping-types.js +5 -0
  57. package/lib/resolvers/type/delivery-provider-shipping-types.js.map +1 -0
  58. package/lib/resolvers/type/delivery-provider-types.d.ts +7 -11
  59. package/lib/resolvers/type/delivery-provider-types.d.ts.map +1 -1
  60. package/lib/resolvers/type/delivery-provider-types.js +17 -43
  61. package/lib/resolvers/type/delivery-provider-types.js.map +1 -1
  62. package/lib/resolvers/type/index.d.ts +40 -11
  63. package/lib/resolvers/type/index.d.ts.map +1 -1
  64. package/lib/resolvers/type/index.js +4 -0
  65. package/lib/resolvers/type/index.js.map +1 -1
  66. package/lib/resolvers/type/order/order-item-types.d.ts +1 -1
  67. package/lib/resolvers/type/order/order-item-types.d.ts.map +1 -1
  68. package/lib/resolvers/type/order/order-item-types.js +2 -3
  69. package/lib/resolvers/type/order/order-item-types.js.map +1 -1
  70. package/lib/resolvers/type/price-types.d.ts.map +1 -1
  71. package/lib/resolvers/type/price-types.js +19 -5
  72. package/lib/resolvers/type/price-types.js.map +1 -1
  73. package/lib/resolvers/type/product/product-variation-assignment-vector.d.ts.map +1 -1
  74. package/lib/resolvers/type/product/product-variation-assignment-vector.js +4 -6
  75. package/lib/resolvers/type/product/product-variation-assignment-vector.js.map +1 -1
  76. package/lib/resolvers/type/product/product-variation-option-types.d.ts.map +1 -1
  77. package/lib/resolvers/type/product/product-variation-option-types.js +2 -3
  78. package/lib/resolvers/type/product/product-variation-option-types.js.map +1 -1
  79. package/lib/resolvers/type/product/product-variation-types.d.ts.map +1 -1
  80. package/lib/resolvers/type/product/product-variation-types.js +2 -3
  81. package/lib/resolvers/type/product/product-variation-types.js.map +1 -1
  82. package/lib/schema/types/delivery.d.ts.map +1 -1
  83. package/lib/schema/types/delivery.js +38 -1
  84. package/lib/schema/types/delivery.js.map +1 -1
  85. package/lib/schema/types/order/delivery.d.ts.map +1 -1
  86. package/lib/schema/types/order/delivery.js +3 -2
  87. package/lib/schema/types/order/delivery.js.map +1 -1
  88. package/lib/schema/types/order/pick-up-location.d.ts.map +1 -1
  89. package/lib/schema/types/order/pick-up-location.js +1 -2
  90. package/lib/schema/types/order/pick-up-location.js.map +1 -1
  91. package/package.json +11 -14
  92. package/src/express/chatHandler.ts +3 -8
  93. package/src/express/index.ts +3 -2
  94. package/src/fastify/chatHandler.ts +3 -8
  95. package/src/fastify/ercMetadataHandler.ts +9 -4
  96. package/src/fastify/index.ts +1 -1
  97. package/src/loaders/index.ts +11 -2
  98. package/src/loaders/productVariationByKeyLoader.ts +20 -0
  99. package/src/loaders/productVariationLoader.ts +19 -0
  100. package/src/loaders/productVariationTextLoader.ts +37 -0
  101. package/src/loaders/quotationLoader.ts +19 -0
  102. package/src/mcp/resources/localization.ts +0 -15
  103. package/src/mongo-store.ts +500 -0
  104. package/src/resolvers/type/delivery-provider-interface.ts +55 -0
  105. package/src/resolvers/type/delivery-provider-pickup-types.ts +12 -0
  106. package/src/resolvers/type/delivery-provider-shipping-types.ts +5 -0
  107. package/src/resolvers/type/delivery-provider-types.ts +22 -68
  108. package/src/resolvers/type/index.ts +4 -0
  109. package/src/resolvers/type/order/order-item-types.ts +2 -3
  110. package/src/resolvers/type/price-types.ts +19 -5
  111. package/src/resolvers/type/product/product-variation-assignment-vector.ts +4 -6
  112. package/src/resolvers/type/product/product-variation-option-types.ts +2 -3
  113. package/src/resolvers/type/product/product-variation-types.ts +2 -3
  114. package/src/schema/types/delivery.ts +38 -1
  115. package/src/schema/types/order/delivery.ts +3 -2
  116. package/src/schema/types/order/pick-up-location.ts +1 -2
  117. /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
+ }
@@ -0,0 +1,55 @@
1
+ import { DeliveryDirector, DeliveryPricingDirector } from '@unchainedshop/core';
2
+ import { Context } from '../../context.js';
3
+
4
+ export const DeliveryProviderInterface = {
5
+ async isActive(deliveryProvider, _, context: Context) {
6
+ const director = await DeliveryDirector.actions(deliveryProvider, {}, context);
7
+ return Boolean(director.isActive());
8
+ },
9
+
10
+ async configurationError(deliveryProvider, _, context: Context) {
11
+ const director = await DeliveryDirector.actions(deliveryProvider, {}, context);
12
+ return director.configurationError();
13
+ },
14
+
15
+ interface(deliveryProvider) {
16
+ const Adapter = DeliveryDirector.getAdapter(deliveryProvider.adapterKey);
17
+ if (!Adapter) return null;
18
+ return {
19
+ _id: Adapter.key,
20
+ label: Adapter.label,
21
+ version: Adapter.version,
22
+ };
23
+ },
24
+
25
+ async simulatedPrice(deliveryProvider, args, context: Context) {
26
+ const { loaders, countryCode, user } = context;
27
+ const { currencyCode: forcedCurrencyCode, orderId, useNetPrice, context: providerContext } = args;
28
+
29
+ const order = await loaders.orderLoader.load({ orderId });
30
+ const currencyCode = forcedCurrencyCode || order?.currencyCode || context.currencyCode;
31
+
32
+ const pricingContext = {
33
+ countryCode,
34
+ currencyCode,
35
+ provider: deliveryProvider,
36
+ order,
37
+ providerContext,
38
+ user: user!,
39
+ };
40
+
41
+ const calculated = await DeliveryPricingDirector.rebuildCalculation(pricingContext, context);
42
+ if (!calculated?.length) return null;
43
+
44
+ const pricing = DeliveryPricingDirector.calculationSheet(pricingContext, calculated);
45
+ const orderPrice = pricing.total({ useNetPrice });
46
+
47
+ return {
48
+ amount: orderPrice.amount,
49
+ currencyCode: orderPrice.currencyCode,
50
+ countryCode,
51
+ isTaxable: pricing.taxSum() > 0,
52
+ isNetPrice: useNetPrice,
53
+ };
54
+ },
55
+ };
@@ -0,0 +1,12 @@
1
+ import { DeliveryDirector } from '@unchainedshop/core';
2
+ import { Context } from '../../context.js';
3
+ import { DeliveryProvider } from '@unchainedshop/core-delivery';
4
+ import { DeliveryProviderInterface } from './delivery-provider-interface.js';
5
+
6
+ export const DeliveryProviderPickUp = {
7
+ ...DeliveryProviderInterface,
8
+ async pickUpLocations(provider: DeliveryProvider, _: never, context: Context) {
9
+ const director = await DeliveryDirector.actions(provider, {}, context);
10
+ return director.pickUpLocations() || [];
11
+ },
12
+ };
@@ -0,0 +1,5 @@
1
+ import { DeliveryProviderInterface } from './delivery-provider-interface.js';
2
+
3
+ export const DeliveryProviderShipping = {
4
+ ...DeliveryProviderInterface,
5
+ };
@@ -1,73 +1,27 @@
1
1
  import { Context } from '../../context.js';
2
- import { DeliveryProvider as DeliveryProviderType } from '@unchainedshop/core-delivery';
3
- import { DeliveryDirector, DeliveryPricingDirector } from '@unchainedshop/core';
2
+ import {
3
+ DeliveryProvider as DeliveryProviderActual,
4
+ DeliveryProviderType,
5
+ } from '@unchainedshop/core-delivery';
6
+ import { objectInvert } from '@unchainedshop/utils';
7
+ import { DeliveryProviderInterface } from './delivery-provider-interface.js';
8
+
9
+ const DeliveryProviderMap = {
10
+ DeliveryProviderShipping: DeliveryProviderType.SHIPPING,
11
+ DeliveryProviderPickUp: DeliveryProviderType.PICKUP,
12
+ };
4
13
 
5
14
  export const DeliveryProvider = {
6
- interface(deliveryProvider: DeliveryProviderType) {
7
- const Adapter = DeliveryDirector.getAdapter(deliveryProvider.adapterKey);
8
- if (!Adapter) return null;
9
- return {
10
- _id: Adapter.key,
11
- label: Adapter.label,
12
- version: Adapter.version,
13
- };
14
- },
15
-
16
- async isActive(deliveryProvider: DeliveryProviderType, _: never, requestContext: Context) {
17
- const director = await DeliveryDirector.actions(deliveryProvider, {}, requestContext);
18
- return Boolean(director.isActive());
19
- },
20
-
21
- async configurationError(deliveryProvider: DeliveryProviderType, _: never, requestContext: Context) {
22
- const director = await DeliveryDirector.actions(deliveryProvider, {}, requestContext);
23
- return director.configurationError();
24
- },
25
-
26
- async simulatedPrice(
27
- deliveryProvider: DeliveryProviderType,
28
- {
29
- currencyCode: forcedCurrencyCode,
30
- orderId,
31
- useNetPrice,
32
- context: providerContext,
33
- }: {
34
- currencyCode?: string;
35
- orderId: string;
36
- useNetPrice?: boolean;
37
- context: any;
38
- },
39
- requestContext: Context,
40
- ) {
41
- const { loaders, countryCode, user } = requestContext;
42
-
43
- const order = await loaders.orderLoader.load({ orderId });
44
- const currencyCode = forcedCurrencyCode || order?.currencyCode || requestContext.currencyCode;
45
- const pricingContext = {
46
- countryCode,
47
- currencyCode,
48
- provider: deliveryProvider,
49
- order,
50
- providerContext,
51
- user: user!,
52
- };
53
-
54
- const calculated = await DeliveryPricingDirector.rebuildCalculation(pricingContext, requestContext);
55
-
56
- if (!calculated || !calculated.length) return null;
57
-
58
- const pricing = DeliveryPricingDirector.calculationSheet(pricingContext, calculated);
59
-
60
- const orderPrice = pricing.total({ useNetPrice }) as {
61
- amount: number;
62
- currencyCode: string;
63
- };
64
-
65
- return {
66
- amount: orderPrice.amount,
67
- currencyCode: orderPrice.currencyCode,
68
- countryCode,
69
- isTaxable: pricing.taxSum() > 0,
70
- isNetPrice: useNetPrice,
71
- };
15
+ __resolveType: async (obj: DeliveryProviderActual, { loaders }: Context) => {
16
+ const provider = await loaders.deliveryProviderLoader.load({
17
+ deliveryProviderId: obj._id,
18
+ });
19
+
20
+ const invertedProductTypes = objectInvert(DeliveryProviderMap);
21
+ if (provider) {
22
+ return invertedProductTypes[provider.type];
23
+ }
24
+ return invertedProductTypes[DeliveryProviderType.SHIPPING];
72
25
  },
26
+ ...DeliveryProviderInterface,
73
27
  };
@@ -67,6 +67,8 @@ import { Web3Address } from './web3-address.js';
67
67
  import { LoginMethodResponse } from './login-method-response-types.js';
68
68
  import { ProductSearchResult } from './product-search-result-types.js';
69
69
  import { OrderStatistics } from './order/order-statistics-types.js';
70
+ import { DeliveryProviderPickUp } from './delivery-provider-pickup-types.js';
71
+ import { DeliveryProviderShipping } from './delivery-provider-shipping-types.js';
70
72
 
71
73
  const types = {
72
74
  Assortment,
@@ -81,6 +83,8 @@ const types = {
81
83
  Country,
82
84
  Currency,
83
85
  DeliveryProvider,
86
+ DeliveryProviderPickUp,
87
+ DeliveryProviderShipping,
84
88
  Dimensions,
85
89
  Enrollment,
86
90
  EnrollmentDelivery,
@@ -113,10 +113,9 @@ export const OrderItem = {
113
113
  return product;
114
114
  },
115
115
 
116
- async quotation(orderPosition: OrderPosition, _, { modules }: Context): Promise<Quotation | null> {
116
+ async quotation(orderPosition: OrderPosition, _, { loaders }: Context): Promise<Quotation | null> {
117
117
  if (!orderPosition.quotationId) return null;
118
- // TODO: use quotation loader
119
- return modules.quotations.findQuotation({ quotationId: orderPosition.quotationId });
118
+ return loaders.quotationLoader.load({ quotationId: orderPosition.quotationId });
120
119
  },
121
120
 
122
121
  async total(