@unchainedshop/plugins 2.12.2 → 3.0.0-alpha2

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 (50) hide show
  1. package/lib/payment/cryptopay/plugin.js +3 -3
  2. package/lib/payment/cryptopay/plugin.js.map +1 -1
  3. package/lib/payment/payrexx/index.js +0 -1
  4. package/lib/payment/payrexx/index.js.map +1 -1
  5. package/lib/plugins-index.d.ts +0 -2
  6. package/lib/plugins-index.d.ts.map +1 -1
  7. package/lib/plugins-index.js +9 -13
  8. package/lib/plugins-index.js.map +1 -1
  9. package/lib/pricing/product-catalog-price.d.ts +1 -0
  10. package/lib/pricing/product-catalog-price.d.ts.map +1 -1
  11. package/lib/pricing/product-catalog-price.js +18 -5
  12. package/lib/pricing/product-catalog-price.js.map +1 -1
  13. package/lib/pricing/product-price-rateconversion.d.ts.map +1 -1
  14. package/lib/pricing/product-price-rateconversion.js +1 -1
  15. package/lib/pricing/product-price-rateconversion.js.map +1 -1
  16. package/lib/worker/bulk-import.d.ts.map +1 -1
  17. package/lib/worker/bulk-import.js +2 -1
  18. package/lib/worker/bulk-import.js.map +1 -1
  19. package/lib/worker/enrollment-order-generator.d.ts.map +1 -1
  20. package/lib/worker/enrollment-order-generator.js +1 -0
  21. package/lib/worker/enrollment-order-generator.js.map +1 -1
  22. package/lib/worker/update-coinbase-rates.js +4 -7
  23. package/lib/worker/update-coinbase-rates.js.map +1 -1
  24. package/lib/worker/update-ecb-rates.js +2 -2
  25. package/lib/worker/update-ecb-rates.js.map +1 -1
  26. package/package.json +20 -22
  27. package/src/payment/cryptopay/plugin.ts +3 -3
  28. package/src/payment/payrexx/index.ts +0 -1
  29. package/src/plugins-index.ts +9 -35
  30. package/src/pricing/product-catalog-price.ts +24 -17
  31. package/src/pricing/product-price-rateconversion.ts +2 -1
  32. package/src/worker/bulk-import.ts +6 -1
  33. package/src/worker/enrollment-order-generator.ts +3 -1
  34. package/src/worker/update-coinbase-rates.ts +4 -11
  35. package/src/worker/update-ecb-rates.ts +2 -2
  36. package/lib/accounts/google-oauth.d.ts +0 -4
  37. package/lib/accounts/google-oauth.d.ts.map +0 -1
  38. package/lib/accounts/google-oauth.js +0 -145
  39. package/lib/accounts/google-oauth.js.map +0 -1
  40. package/lib/accounts/linkedin-oauth.d.ts +0 -4
  41. package/lib/accounts/linkedin-oauth.d.ts.map +0 -1
  42. package/lib/accounts/linkedin-oauth.js +0 -82
  43. package/lib/accounts/linkedin-oauth.js.map +0 -1
  44. package/lib/warehousing/google-sheets.d.ts +0 -2
  45. package/lib/warehousing/google-sheets.d.ts.map +0 -1
  46. package/lib/warehousing/google-sheets.js +0 -154
  47. package/lib/warehousing/google-sheets.js.map +0 -1
  48. package/src/accounts/google-oauth.ts +0 -181
  49. package/src/accounts/linkedin-oauth.ts +0 -103
  50. package/src/warehousing/google-sheets.ts +0 -167
@@ -1,4 +1,3 @@
1
- import { useMiddlewareWithCurrentContext } from '@unchainedshop/api/express/index.js';
2
1
  import { ModuleInput, UnchainedCore } from '@unchainedshop/types/core.js';
3
2
  import express from 'express';
4
3
 
@@ -71,9 +70,6 @@ import './files/gridfs/gridfs-adapter.js';
71
70
  import { gridfsHandler } from './files/gridfs/gridfs-webhook.js';
72
71
  import { configureGridFSFileUploadModule } from './files/gridfs/index.js';
73
72
 
74
- import './accounts/google-oauth.js';
75
- import './accounts/linkedin-oauth.js';
76
-
77
73
  const {
78
74
  CRYPTOPAY_WEBHOOK_PATH = '/payment/cryptopay',
79
75
  STRIPE_WEBHOOK_PATH = '/payment/stripe',
@@ -113,26 +109,12 @@ export const connectDefaultPluginsToExpress4 = (
113
109
  app,
114
110
  { unchainedAPI }: { unchainedAPI: UnchainedCore },
115
111
  ) => {
116
- useMiddlewareWithCurrentContext(app, GRIDFS_PUT_SERVER_PATH, gridfsHandler);
117
-
118
- useMiddlewareWithCurrentContext(app, CRYPTOPAY_WEBHOOK_PATH, express.json(), cryptopayHandler);
119
-
120
- useMiddlewareWithCurrentContext(
121
- app,
122
- STRIPE_WEBHOOK_PATH,
123
- express.raw({ type: 'application/json' }),
124
- stripeHandler,
125
- );
112
+ app.use(GRIDFS_PUT_SERVER_PATH, gridfsHandler);
113
+ app.use(CRYPTOPAY_WEBHOOK_PATH, express.json(), cryptopayHandler);
114
+ app.use(STRIPE_WEBHOOK_PATH, express.raw({ type: 'application/json' }), stripeHandler);
115
+ app.use(PFCHECKOUT_WEBHOOK_PATH, express.json(), postfinanceCheckoutHandler);
126
116
 
127
- useMiddlewareWithCurrentContext(
128
- app,
129
- PFCHECKOUT_WEBHOOK_PATH,
130
- express.json(),
131
- postfinanceCheckoutHandler,
132
- );
133
-
134
- useMiddlewareWithCurrentContext(
135
- app,
117
+ app.use(
136
118
  DATATRANS_WEBHOOK_PATH,
137
119
  express.text({
138
120
  type: 'application/json',
@@ -140,8 +122,7 @@ export const connectDefaultPluginsToExpress4 = (
140
122
  datatransHandler,
141
123
  );
142
124
 
143
- useMiddlewareWithCurrentContext(
144
- app,
125
+ app.use(
145
126
  APPLE_IAP_WEBHOOK_PATH,
146
127
  express.json({
147
128
  strict: false,
@@ -149,17 +130,10 @@ export const connectDefaultPluginsToExpress4 = (
149
130
  appleIAPHandler,
150
131
  );
151
132
 
152
- useMiddlewareWithCurrentContext(
153
- app,
154
- PAYREXX_WEBHOOK_PATH,
155
- express.json({ type: 'application/json' }),
156
- payrexxHandler,
157
- );
158
-
159
- useMiddlewareWithCurrentContext(app, SAFERPAY_WEBHOOK_PATH, saferpayHandler);
133
+ app.use(PAYREXX_WEBHOOK_PATH, express.json({ type: 'application/json' }), payrexxHandler);
134
+ app.use(SAFERPAY_WEBHOOK_PATH, saferpayHandler);
160
135
 
161
- // useMiddlewareWithCurrentContext(
162
- // app,
136
+ // app.use(
163
137
  // MINIO_PUT_SERVER_PATH,
164
138
  // express.json({
165
139
  // strict: false,
@@ -1,5 +1,27 @@
1
1
  import { IProductPricingAdapter } from '@unchainedshop/types/products.pricing.js';
2
2
  import { ProductPricingDirector, ProductPricingAdapter } from '@unchainedshop/core-products';
3
+ import { resolveBestCurrency } from '@unchainedshop/utils';
4
+ import memoizee from 'memoizee';
5
+
6
+ const { NODE_ENV } = process.env;
7
+
8
+ export const resolveCurrency = memoizee(
9
+ async (context) => {
10
+ const { country, currency: forcedCurrency, modules } = context;
11
+ const countryObject = await modules.countries.findCountry({ isoCode: country });
12
+ const currencies = await modules.currencies.findCurrencies({ includeInactive: false });
13
+ const currency =
14
+ forcedCurrency || resolveBestCurrency(countryObject.defaultCurrencyCode, currencies);
15
+ return currency;
16
+ },
17
+ {
18
+ maxAge: NODE_ENV === 'production' ? 1000 * 60 : 100, // minute or 100ms
19
+ promise: true,
20
+ normalizer(args) {
21
+ return `${args[0].currency}-${args[0].country}`;
22
+ },
23
+ },
24
+ );
3
25
 
4
26
  export const ProductPrice: IProductPricingAdapter = {
5
27
  ...ProductPricingAdapter,
@@ -20,23 +42,8 @@ export const ProductPrice: IProductPricingAdapter = {
20
42
  ...pricingAdapter,
21
43
 
22
44
  calculate: async () => {
23
- const {
24
- product,
25
- country,
26
- currency: forcedCurrency,
27
- quantity,
28
- modules,
29
- services,
30
- } = params.context;
31
- const currency =
32
- forcedCurrency ||
33
- (await services.countries.resolveDefaultCurrencyCode(
34
- {
35
- isoCode: country,
36
- },
37
- params.context,
38
- ));
39
-
45
+ const { product, country, quantity, modules } = params.context;
46
+ const currency = await resolveCurrency(params.context);
40
47
  const price = await modules.products.prices.price(product, { country, currency, quantity });
41
48
  if (price) {
42
49
  const itemTotal = price.amount * quantity;
@@ -46,7 +46,8 @@ export const ProductPriceRateConversion: IProductPricingAdapter = {
46
46
  isoCode: targetCurrency,
47
47
  });
48
48
 
49
- if (!targetCurrencyObj?.isActive) return pricingAdapter.calculate();
49
+ if (!targetCurrencyObj?.isActive || !fromCurrencyObj?.isActive)
50
+ return pricingAdapter.calculate();
50
51
 
51
52
  const rateData = await modules.products.prices.rates.getRate(fromCurrencyObj, targetCurrencyObj);
52
53
 
@@ -62,11 +62,16 @@ export const BulkImportWorker: IWorkerAdapter<any, Record<string, unknown>> = {
62
62
 
63
63
  doWork: async (rawPayload, unchainedAPI) => {
64
64
  try {
65
- const { createShouldUpsertIfIDExists = false, skipCacheInvalidation = false } = rawPayload;
65
+ const {
66
+ createShouldUpsertIfIDExists = false,
67
+ skipCacheInvalidation = false,
68
+ updateShouldUpsertIfIDNotExists = false,
69
+ } = rawPayload;
66
70
 
67
71
  const bulkImporter = unchainedAPI.bulkImporter.createBulkImporter({
68
72
  logger,
69
73
  createShouldUpsertIfIDExists,
74
+ updateShouldUpsertIfIDNotExists,
70
75
  skipCacheInvalidation,
71
76
  });
72
77
 
@@ -53,15 +53,17 @@ const generateOrder = async (
53
53
  }
54
54
 
55
55
  const { paymentProviderId, context: paymentContext } = enrollment.payment;
56
-
57
56
  if (paymentProviderId) {
58
57
  await modules.orders.setPaymentProvider(orderId, paymentProviderId, unchainedAPI);
59
58
  }
59
+
60
60
  const { deliveryProviderId, context: deliveryContext } = enrollment.delivery;
61
61
  if (deliveryProviderId) {
62
62
  await modules.orders.setDeliveryProvider(orderId, deliveryProviderId, unchainedAPI);
63
63
  }
64
64
 
65
+ await modules.orders.updateCalculation(orderId, unchainedAPI);
66
+
65
67
  order = await modules.orders.checkout(
66
68
  order._id,
67
69
  {
@@ -3,7 +3,7 @@ import { IWorkerAdapter } from '@unchainedshop/types/worker.js';
3
3
  import { WorkerAdapter, WorkerDirector } from '@unchainedshop/core-worker';
4
4
  import later from '@breejs/later';
5
5
  import { ProductPriceRate } from '@unchainedshop/types/products.pricing.js';
6
- import { systemLocale } from '@unchainedshop/utils';
6
+ import { resolveBestCurrency } from '@unchainedshop/utils';
7
7
 
8
8
  const getExchangeRates = async (base) => {
9
9
  return fetch(`https://api.coinbase.com/v2/exchange-rates?currency=${base}`, {
@@ -24,17 +24,10 @@ const UpdateCoinbaseRates: IWorkerAdapter<any, any> = {
24
24
  type: 'UPDATE_COINBASE_RATES',
25
25
 
26
26
  doWork: async (input, unchainedAPI) => {
27
- const { modules, services } = unchainedAPI;
28
-
29
27
  try {
30
- const currencyCode = await services.countries.resolveDefaultCurrencyCode(
31
- {
32
- isoCode: systemLocale.country,
33
- },
34
- unchainedAPI,
35
- );
28
+ const currencies = await unchainedAPI.modules.currencies.findCurrencies({ includeInactive: true });
29
+ const currencyCode = resolveBestCurrency(null, currencies); // Get fallback currency
36
30
 
37
- const currencies = await modules.currencies.findCurrencies({ includeInactive: true });
38
31
  const currencyCodes = currencies.map((currency) => currency.isoCode);
39
32
 
40
33
  const {
@@ -61,7 +54,7 @@ const UpdateCoinbaseRates: IWorkerAdapter<any, any> = {
61
54
  currencyCodes.includes(rate.quoteCurrency) && rate.quoteCurrency !== rate.baseCurrency,
62
55
  );
63
56
 
64
- const success = await modules.products.prices.rates.updateRates(rates);
57
+ const success = await unchainedAPI.modules.products.prices.rates.updateRates(rates);
65
58
  return {
66
59
  success,
67
60
  result: {
@@ -2,7 +2,7 @@
2
2
  import { IWorkerAdapter } from '@unchainedshop/types/worker.js';
3
3
  import { WorkerAdapter, WorkerDirector } from '@unchainedshop/core-worker';
4
4
  import later from '@breejs/later';
5
- import xmlJs from 'xml-js';
5
+ import { xml2json } from 'xml-js';
6
6
  import { ProductPriceRate } from '@unchainedshop/types/products.pricing.js';
7
7
 
8
8
  const getExchangeRates = async () => {
@@ -10,7 +10,7 @@ const getExchangeRates = async () => {
10
10
  method: 'GET',
11
11
  })
12
12
  .then((res) => res.text())
13
- .then((text) => JSON.parse(xmlJs.xml2json(text)))
13
+ .then((text) => JSON.parse(xml2json(text)))
14
14
  .then((json) =>
15
15
  json.elements?.[0]?.elements
16
16
  .filter((e) => e.name.toLowerCase() === 'cube')[0]
@@ -1,4 +0,0 @@
1
- import { IOAuth2Adapter } from '@unchainedshop/types/accounts.js';
2
- declare const GoogleOAuth2Adapter: IOAuth2Adapter;
3
- export default GoogleOAuth2Adapter;
4
- //# sourceMappingURL=google-oauth.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"google-oauth.d.ts","sourceRoot":"","sources":["../../src/accounts/google-oauth.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAmFlE,QAAA,MAAM,mBAAmB,EAAE,cA4F1B,CAAC;AAIF,eAAe,mBAAmB,CAAC"}
@@ -1,145 +0,0 @@
1
- import { OAuth2Director, OAuth2Adapter } from '@unchainedshop/core-accountsjs';
2
- const { GOOGLE_OAUTH_CLIENT_ID, GOOGLE_OAUTH_CLIENT_SECRET } = process.env;
3
- const getGoggleAuthorizationCode = async ({ code, redirectUri, clientId, clientSecret, }) => {
4
- const response = await fetch('https://oauth2.googleapis.com/token', {
5
- method: 'POST',
6
- headers: {
7
- 'Content-Type': 'application/json',
8
- },
9
- // eslint-disable-next-line
10
- // @ts-ignore
11
- duplex: 'half',
12
- body: JSON.stringify({
13
- code,
14
- client_id: clientId,
15
- grant_type: 'authorization_code',
16
- client_secret: clientSecret,
17
- redirect_uri: redirectUri,
18
- access_type: 'offline',
19
- }),
20
- });
21
- return response.json();
22
- };
23
- const normalizeProfileData = (data) => {
24
- const { names = [], genders = [], addresses = [], emailAddresses = [], phoneNumbers = [], birthdays = [], photos = [], } = data;
25
- const [name] = names;
26
- const [gender] = genders;
27
- const [email] = emailAddresses;
28
- const [birthday] = birthdays;
29
- const [phone] = phoneNumbers;
30
- const [address] = addresses;
31
- const [photo] = photos;
32
- return {
33
- id: data.sub,
34
- firstName: name?.givenName,
35
- lastName: name?.familyName,
36
- displayName: name?.displayName,
37
- gender: gender?.value,
38
- email: email?.value,
39
- birthDate: birthday?.date
40
- ? new Date(birthday?.date?.year ?? 0, birthdays?.date?.month ?? 0, birthday?.date?.day ?? 0)
41
- : undefined,
42
- phoneNumber: phone?.canonicalForm,
43
- address: address?.formattedValue,
44
- avatarUrl: photo?.url,
45
- };
46
- };
47
- const parseGoogleIdToken = (idToken) => {
48
- const [, base64UserInfo] = idToken.split('.');
49
- const buff = Buffer.from(base64UserInfo, 'base64');
50
- const data = JSON.parse(buff.toString());
51
- return {
52
- id: data.sub,
53
- email: data?.email,
54
- firstName: data?.given_name,
55
- lastName: data?.family_name,
56
- avatarUrl: data?.picture,
57
- fullName: data?.name,
58
- exp: data?.exp,
59
- ...data,
60
- };
61
- };
62
- const GoogleOAuth2Adapter = {
63
- ...OAuth2Adapter,
64
- key: 'google-oauth2',
65
- label: 'Google Oauth',
66
- version: '1',
67
- provider: 'google',
68
- config: {
69
- clientId: GOOGLE_OAUTH_CLIENT_ID,
70
- scopes: [
71
- 'genders',
72
- 'emailAddresses',
73
- 'phoneNumbers',
74
- 'addresses',
75
- 'birthdays',
76
- 'metadata',
77
- 'names',
78
- 'photos',
79
- 'locations',
80
- ],
81
- },
82
- actions: () => {
83
- return {
84
- ...OAuth2Adapter.actions(null),
85
- configurationError: () => {
86
- return '';
87
- },
88
- isActive: () => {
89
- return Boolean(GOOGLE_OAUTH_CLIENT_ID && GOOGLE_OAUTH_CLIENT_SECRET);
90
- },
91
- getAuthorizationToken: async (authorizationCode, redirectUrl) => {
92
- return getGoggleAuthorizationCode({
93
- code: authorizationCode,
94
- clientId: GoogleOAuth2Adapter.config.clientId,
95
- redirectUri: redirectUrl,
96
- clientSecret: GOOGLE_OAUTH_CLIENT_SECRET,
97
- });
98
- },
99
- getAccountData: async ({ access_token, id_token }) => {
100
- const response = await fetch(`https://people.googleapis.com/v1/people/me?personFields=${GoogleOAuth2Adapter.config.scopes.join(',')}`, {
101
- headers: {
102
- Authorization: `Bearer ${access_token}`,
103
- },
104
- });
105
- if (response.status === 403)
106
- return parseGoogleIdToken(id_token);
107
- const profileInfoJSON = await response.json();
108
- if (profileInfoJSON?.error)
109
- throw new Error(profileInfoJSON?.error.message);
110
- return normalizeProfileData(profileInfoJSON);
111
- },
112
- isTokenValid: async (accessToken) => {
113
- const response = await fetch(`https://oauth2.googleapis.com/tokeninfo?id_token=${accessToken?.id_token}`);
114
- const tokenInfo = await response.json();
115
- if (tokenInfo.error) {
116
- return false;
117
- }
118
- return true;
119
- },
120
- refreshToken: async ({ refresh_token }) => {
121
- const response = await fetch('https://oauth2.googleapis.com/token', {
122
- method: 'POST',
123
- // eslint-disable-next-line
124
- // @ts-ignore
125
- duplex: 'half',
126
- headers: {
127
- 'Content-Type': 'application/json',
128
- },
129
- body: JSON.stringify({
130
- client_id: GoogleOAuth2Adapter.config.clientId,
131
- grant_type: 'refresh_token',
132
- client_secret: GOOGLE_OAUTH_CLIENT_SECRET,
133
- refresh_token,
134
- access_type: 'offline',
135
- }),
136
- });
137
- const refreshedAccessToken = await response.json();
138
- return refreshedAccessToken;
139
- },
140
- };
141
- },
142
- };
143
- OAuth2Director.registerAdapter(GoogleOAuth2Adapter);
144
- export default GoogleOAuth2Adapter;
145
- //# sourceMappingURL=google-oauth.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"google-oauth.js","sourceRoot":"","sources":["../../src/accounts/google-oauth.ts"],"names":[],"mappings":"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"}
@@ -1,4 +0,0 @@
1
- import { IOAuth2Adapter } from '@unchainedshop/types/accounts.js';
2
- declare const LinkedInOAuthAdapter: IOAuth2Adapter;
3
- export default LinkedInOAuthAdapter;
4
- //# sourceMappingURL=linkedin-oauth.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"linkedin-oauth.d.ts","sourceRoot":"","sources":["../../src/accounts/linkedin-oauth.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AA2ClE,QAAA,MAAM,oBAAoB,EAAE,cAsD3B,CAAC;AAIF,eAAe,oBAAoB,CAAC"}
@@ -1,82 +0,0 @@
1
- import { OAuth2Director, OAuth2Adapter } from '@unchainedshop/core-accountsjs';
2
- const { LINKED_IN_OAUTH_CLIENT_ID, LINKED_IN_OAUTH_CLIENT_SECRET } = process.env;
3
- const getLinkedInAuthorizationCode = async ({ code, redirectUri, clientId, clientSecret, }) => {
4
- const response = await fetch('https://www.linkedin.com/oauth/v2/accessToken', {
5
- method: 'POST',
6
- // eslint-disable-next-line
7
- // @ts-ignore
8
- duplex: 'half',
9
- headers: {
10
- 'Content-Type': 'application/x-www-form-urlencoded',
11
- },
12
- body: new URLSearchParams({
13
- code,
14
- client_id: clientId,
15
- grant_type: 'authorization_code',
16
- client_secret: clientSecret,
17
- redirect_uri: redirectUri,
18
- }),
19
- });
20
- return response.json();
21
- };
22
- const normalizeProfileData = (data) => {
23
- const { name, given_name, family_name, email, email_verified, picture, sub } = data;
24
- return {
25
- id: sub,
26
- displayName: name,
27
- firstName: given_name,
28
- lastName: family_name,
29
- email: email_verified ? email : undefined,
30
- avatarUrl: picture,
31
- };
32
- };
33
- const LinkedInOAuthAdapter = {
34
- ...OAuth2Adapter,
35
- key: 'linked-in-oauth2',
36
- label: 'LinkedIn Oauth',
37
- version: '1',
38
- provider: 'linkedin',
39
- config: {
40
- clientId: LINKED_IN_OAUTH_CLIENT_ID,
41
- scopes: ['r_liteprofile', 'r_emailaddress', 'email', 'openid', 'profile'],
42
- },
43
- actions: () => {
44
- return {
45
- ...OAuth2Adapter.actions(null),
46
- configurationError: () => {
47
- return '';
48
- },
49
- isActive: () => {
50
- return Boolean(LINKED_IN_OAUTH_CLIENT_ID && LINKED_IN_OAUTH_CLIENT_SECRET);
51
- },
52
- getAuthorizationToken: async (authorizationCode, redirectUrl) => {
53
- return getLinkedInAuthorizationCode({
54
- code: authorizationCode,
55
- clientId: LinkedInOAuthAdapter.config.clientId,
56
- redirectUri: redirectUrl,
57
- clientSecret: LINKED_IN_OAUTH_CLIENT_SECRET,
58
- });
59
- },
60
- getAccountData: async ({ access_token }) => {
61
- const response = await fetch('https://api.linkedin.com/v2/userinfo', {
62
- headers: {
63
- Authorization: `Bearer ${access_token}`,
64
- },
65
- });
66
- const profileInfoJSON = await response.json();
67
- return normalizeProfileData(profileInfoJSON);
68
- },
69
- isTokenValid: async ({ access_token }) => {
70
- const response = await fetch(`https://api.linkedin.com/oauth/v2/accessTokenValidation?q=full&access_token=${access_token}`);
71
- const tokenInfo = await response.json();
72
- if (tokenInfo.error) {
73
- return false;
74
- }
75
- return true;
76
- },
77
- };
78
- },
79
- };
80
- OAuth2Director.registerAdapter(LinkedInOAuthAdapter);
81
- export default LinkedInOAuthAdapter;
82
- //# sourceMappingURL=linkedin-oauth.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"linkedin-oauth.js","sourceRoot":"","sources":["../../src/accounts/linkedin-oauth.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAE/E,MAAM,EAAE,yBAAyB,EAAE,6BAA6B,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC;AAEjF,MAAM,4BAA4B,GAAG,KAAK,EAAE,EAC1C,IAAI,EACJ,WAAW,EACX,QAAQ,EACR,YAAY,GACb,EAAgB,EAAE;IACjB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,+CAA+C,EAAE;QAC5E,MAAM,EAAE,MAAM;QACd,2BAA2B;QAC3B,aAAa;QACb,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,mCAAmC;SACpD;QACD,IAAI,EAAE,IAAI,eAAe,CAAC;YACxB,IAAI;YACJ,SAAS,EAAE,QAAQ;YACnB,UAAU,EAAE,oBAAoB;YAChC,aAAa,EAAE,YAAY;YAC3B,YAAY,EAAE,WAAW;SAC1B,CAAC;KACH,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAG,CAAC,IAAI,EAAO,EAAE;IACzC,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IACpF,OAAO;QACL,EAAE,EAAE,GAAG;QACP,WAAW,EAAE,IAAI;QACjB,SAAS,EAAE,UAAU;QACrB,QAAQ,EAAE,WAAW;QACrB,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;QACzC,SAAS,EAAE,OAAO;KACnB,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAmB;IAC3C,GAAG,aAAa;IAChB,GAAG,EAAE,kBAAkB;IACvB,KAAK,EAAE,gBAAgB;IACvB,OAAO,EAAE,GAAG;IACZ,QAAQ,EAAE,UAAU;IACpB,MAAM,EAAE;QACN,QAAQ,EAAE,yBAAyB;QACnC,MAAM,EAAE,CAAC,eAAe,EAAE,gBAAgB,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC;KAC1E;IAED,OAAO,EAAE,GAAG,EAAE;QACZ,OAAO;YACL,GAAG,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC;YAC9B,kBAAkB,EAAE,GAAG,EAAE;gBACvB,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,QAAQ,EAAE,GAAG,EAAE;gBACb,OAAO,OAAO,CAAC,yBAAyB,IAAI,6BAA6B,CAAC,CAAC;YAC7E,CAAC;YACD,qBAAqB,EAAE,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,EAAE;gBAC9D,OAAO,4BAA4B,CAAC;oBAClC,IAAI,EAAE,iBAAiB;oBACvB,QAAQ,EAAE,oBAAoB,CAAC,MAAM,CAAC,QAAQ;oBAC9C,WAAW,EAAE,WAAW;oBACxB,YAAY,EAAE,6BAA6B;iBAC5C,CAAC,CAAC;YACL,CAAC;YACD,cAAc,EAAE,KAAK,EAAE,EAAE,YAAY,EAAO,EAAE,EAAE;gBAC9C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,sCAAsC,EAAE;oBACnE,OAAO,EAAE;wBACP,aAAa,EAAE,UAAU,YAAY,EAAE;qBACxC;iBACF,CAAC,CAAC;gBAEH,MAAM,eAAe,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBAE9C,OAAO,oBAAoB,CAAC,eAAe,CAAC,CAAC;YAC/C,CAAC;YACD,YAAY,EAAE,KAAK,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE;gBACvC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAC1B,+EAA+E,YAAY,EAAE,CAC9F,CAAC;gBAEF,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBAExC,IAAI,SAAS,CAAC,KAAK,EAAE,CAAC;oBACpB,OAAO,KAAK,CAAC;gBACf,CAAC;gBAED,OAAO,IAAI,CAAC;YACd,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,cAAc,CAAC,eAAe,CAAC,oBAAoB,CAAC,CAAC;AAErD,eAAe,oBAAoB,CAAC"}
@@ -1,2 +0,0 @@
1
- import 'abort-controller/polyfill.js';
2
- //# sourceMappingURL=google-sheets.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"google-sheets.d.ts","sourceRoot":"","sources":["../../src/warehousing/google-sheets.ts"],"names":[],"mappings":"AAOA,OAAO,8BAA8B,CAAC"}
@@ -1,154 +0,0 @@
1
- import { WarehousingDirector, WarehousingAdapter, WarehousingProviderType, } from '@unchainedshop/core-warehousing';
2
- import Sheets from 'node-sheets';
3
- import { log, LogLevel } from '@unchainedshop/logger';
4
- import 'abort-controller/polyfill.js';
5
- import * as lruCache from 'lru-cache';
6
- const { NODE_ENV, GOOGLE_SHEETS_ID, GOOGLE_SHEETS_PRIVATE_KEY_DATA } = process.env;
7
- const ttl = NODE_ENV === 'production' ? 1000 * 60 : 0; // 1 minute or 1 second
8
- const downloadSpreadsheet = async () => {
9
- if (!GOOGLE_SHEETS_PRIVATE_KEY_DATA || !GOOGLE_SHEETS_ID)
10
- return null;
11
- try {
12
- // https://docs.google.com/spreadsheets/d/GOOGLE_SHEETS_ID/edit?usp=sharing
13
- const gs = new Sheets(GOOGLE_SHEETS_ID);
14
- const authData = JSON.parse(GOOGLE_SHEETS_PRIVATE_KEY_DATA);
15
- await gs.authorizeJWT(authData);
16
- const delivery = await gs.tables('delivery!A:ZZZ');
17
- const inventory = await gs.tables('inventory!A:ZZZ');
18
- log(`GoogleSheet: Updated cache with TTL: ${ttl}`, {
19
- level: LogLevel.Verbose,
20
- });
21
- return {
22
- delivery,
23
- inventory,
24
- };
25
- }
26
- catch (err) {
27
- log(err, { level: LogLevel.Error });
28
- throw err;
29
- }
30
- };
31
- const updateGoogleCache = async (cache) => {
32
- try {
33
- const sheet = await downloadSpreadsheet();
34
- if (sheet) {
35
- cache.set('tables', sheet);
36
- return sheet;
37
- }
38
- }
39
- catch (e) {
40
- log(e, { level: LogLevel.Error });
41
- }
42
- return null;
43
- };
44
- const googleCache = new lruCache.LRUCache({
45
- max: 500,
46
- ttl, // 1 second in dev
47
- allowStale: true,
48
- dispose: () => {
49
- updateGoogleCache(googleCache);
50
- },
51
- });
52
- updateGoogleCache(googleCache);
53
- const getRows = async (name) => {
54
- const cachedTables = googleCache.get('tables');
55
- let tables = cachedTables;
56
- if (!cachedTables) {
57
- tables = await updateGoogleCache(googleCache);
58
- }
59
- if (!tables || !tables[name] || !tables[name].rows)
60
- return [];
61
- return tables[name].rows;
62
- };
63
- const getRemoteTime = async (sku, quantity, selector) => {
64
- const rows = await getRows('delivery');
65
- const resolvedRow = rows.reduce((result, row) => {
66
- const parsedQuantity = parseInt(row.Quantity.value, 10);
67
- const parsedSKU = row.SKU.value.toUpperCase();
68
- if (parsedSKU === sku && parsedQuantity <= quantity) {
69
- return row;
70
- }
71
- return result;
72
- }, null);
73
- if (!resolvedRow)
74
- return null;
75
- const time = parseInt(resolvedRow[selector].value, 10) || 0;
76
- log(`GoogleSheet: Resolve Time ${selector} (${quantity}) for ${sku}: ${time}`, {
77
- level: LogLevel.Verbose,
78
- });
79
- return time;
80
- };
81
- const getRemoteInventory = async (sku) => {
82
- const rows = await getRows('inventory');
83
- const resolvedRow = [].concat(rows).reduce((result, row) => {
84
- if (result || !row)
85
- return result;
86
- const parsedSKU = row.SKU.value.toUpperCase();
87
- if (parsedSKU === sku) {
88
- return row;
89
- }
90
- return result;
91
- }, null);
92
- if (!resolvedRow)
93
- return null;
94
- const amount = parseInt(resolvedRow.Stock.value, 10) || 0;
95
- log(`GoogleSheet: Resolve Inventory for ${sku}: ${amount}`, {
96
- level: LogLevel.Verbose,
97
- });
98
- return amount;
99
- };
100
- const GoogleSheets = {
101
- ...WarehousingAdapter,
102
- key: 'shop.unchained.warehousing.google-sheets',
103
- label: 'Google Sheets',
104
- version: '1.0.0',
105
- orderIndex: 0,
106
- typeSupported: (type) => {
107
- return type === WarehousingProviderType.PHYSICAL;
108
- },
109
- initialConfiguration: [
110
- {
111
- key: 'sheetId',
112
- value: null,
113
- },
114
- ],
115
- actions: (config, context) => {
116
- return {
117
- ...WarehousingAdapter.actions(config, context),
118
- isActive: () => {
119
- return true;
120
- },
121
- configurationError: () => {
122
- return null;
123
- },
124
- stock: async () => {
125
- const { sku } = context.product.warehousing || {};
126
- return getRemoteInventory(sku);
127
- },
128
- productionTime: async (quantity) => {
129
- const { sku } = context.product.warehousing || {};
130
- if (!sku)
131
- return null;
132
- const selector = 'WAREHOUSE_HOURS';
133
- const timeInHours = await getRemoteTime(sku.toUpperCase(), quantity, selector);
134
- if (!timeInHours)
135
- return null;
136
- return timeInHours * 60 * 60 * 1000;
137
- },
138
- commissioningTime: async (quantity) => {
139
- const { product, deliveryProvider } = context;
140
- const { sku } = product.warehousing || {};
141
- if (!sku)
142
- return null;
143
- const { type } = deliveryProvider;
144
- const selector = `DELIVERY_HOURS:${type}`;
145
- const timeInHours = await getRemoteTime(sku.toUpperCase(), quantity, selector);
146
- if (!timeInHours)
147
- return null;
148
- return timeInHours * 60 * 60 * 1000;
149
- },
150
- };
151
- },
152
- };
153
- WarehousingDirector.registerAdapter(GoogleSheets);
154
- //# sourceMappingURL=google-sheets.js.map