@unchainedshop/platform 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 (64) hide show
  1. package/lib/bulk-importer/createBulkImporter.d.ts +1 -0
  2. package/lib/bulk-importer/createBulkImporter.d.ts.map +1 -1
  3. package/lib/bulk-importer/createBulkImporter.js +2 -2
  4. package/lib/bulk-importer/createBulkImporter.js.map +1 -1
  5. package/lib/bulk-importer/handlers/assortment/create.d.ts.map +1 -1
  6. package/lib/bulk-importer/handlers/assortment/create.js +9 -7
  7. package/lib/bulk-importer/handlers/assortment/create.js.map +1 -1
  8. package/lib/bulk-importer/handlers/assortment/update.d.ts +3 -1
  9. package/lib/bulk-importer/handlers/assortment/update.d.ts.map +1 -1
  10. package/lib/bulk-importer/handlers/assortment/update.js +5 -1
  11. package/lib/bulk-importer/handlers/assortment/update.js.map +1 -1
  12. package/lib/bulk-importer/handlers/filter/create.d.ts.map +1 -1
  13. package/lib/bulk-importer/handlers/filter/create.js +10 -6
  14. package/lib/bulk-importer/handlers/filter/create.js.map +1 -1
  15. package/lib/bulk-importer/handlers/filter/update.d.ts +2 -1
  16. package/lib/bulk-importer/handlers/filter/update.d.ts.map +1 -1
  17. package/lib/bulk-importer/handlers/filter/update.js +15 -7
  18. package/lib/bulk-importer/handlers/filter/update.js.map +1 -1
  19. package/lib/bulk-importer/handlers/product/create.d.ts.map +1 -1
  20. package/lib/bulk-importer/handlers/product/create.js +9 -7
  21. package/lib/bulk-importer/handlers/product/create.js.map +1 -1
  22. package/lib/bulk-importer/handlers/product/update.d.ts +2 -1
  23. package/lib/bulk-importer/handlers/product/update.d.ts.map +1 -1
  24. package/lib/bulk-importer/handlers/product/update.js +5 -1
  25. package/lib/bulk-importer/handlers/product/update.js.map +1 -1
  26. package/lib/bulk-importer/handlers/product/upsertVariations.d.ts.map +1 -1
  27. package/lib/bulk-importer/handlers/product/upsertVariations.js +17 -11
  28. package/lib/bulk-importer/handlers/product/upsertVariations.js.map +1 -1
  29. package/lib/context/index.d.ts +0 -1
  30. package/lib/context/index.d.ts.map +1 -1
  31. package/lib/context/index.js +0 -1
  32. package/lib/context/index.js.map +1 -1
  33. package/lib/context/setAccessToken.d.ts +1 -1
  34. package/lib/context/setAccessToken.d.ts.map +1 -1
  35. package/lib/context/setAccessToken.js +3 -1
  36. package/lib/context/setAccessToken.js.map +1 -1
  37. package/lib/platform-index.d.ts +4 -4
  38. package/lib/platform-index.d.ts.map +1 -1
  39. package/lib/setup/setupAccounts.d.ts +1 -1
  40. package/lib/setup/setupAccounts.d.ts.map +1 -1
  41. package/lib/setup/setupAccounts.js +8 -160
  42. package/lib/setup/setupAccounts.js.map +1 -1
  43. package/lib/startPlatform.d.ts +6 -9
  44. package/lib/startPlatform.d.ts.map +1 -1
  45. package/lib/startPlatform.js +4 -10
  46. package/lib/startPlatform.js.map +1 -1
  47. package/package.json +14 -14
  48. package/src/bulk-importer/createBulkImporter.ts +8 -2
  49. package/src/bulk-importer/handlers/assortment/create.ts +12 -10
  50. package/src/bulk-importer/handlers/assortment/update.ts +10 -1
  51. package/src/bulk-importer/handlers/filter/create.ts +13 -11
  52. package/src/bulk-importer/handlers/filter/update.ts +18 -12
  53. package/src/bulk-importer/handlers/product/create.ts +12 -10
  54. package/src/bulk-importer/handlers/product/update.ts +9 -1
  55. package/src/bulk-importer/handlers/product/upsertVariations.ts +24 -20
  56. package/src/context/index.ts +0 -1
  57. package/src/context/setAccessToken.ts +8 -1
  58. package/src/setup/setupAccounts.ts +8 -237
  59. package/src/startPlatform.ts +10 -25
  60. package/lib/context/withAccessToken.d.ts +0 -4
  61. package/lib/context/withAccessToken.d.ts.map +0 -1
  62. package/lib/context/withAccessToken.js +0 -37
  63. package/lib/context/withAccessToken.js.map +0 -1
  64. package/src/context/withAccessToken.ts +0 -40
@@ -1,245 +1,16 @@
1
- import { User } from '@unchainedshop/types/user.js';
2
- import { randomValueHex } from '@unchainedshop/utils';
3
- import { accountsSettings } from '@unchainedshop/core-accountsjs';
4
- import moniker from 'moniker';
5
1
  import { UnchainedCore } from '@unchainedshop/types/core.js';
2
+ import { subscribe } from '@unchainedshop/events';
6
3
 
7
4
  export const setupAccounts = (unchainedAPI: UnchainedCore) => {
8
- const accountsServer = unchainedAPI.modules.accounts.getAccountsServer();
9
-
10
- accountsServer.users = unchainedAPI.modules.users;
11
-
12
- accountsServer.options.prepareMail = (
13
- to: string,
14
- token: string,
15
- user: User & { id: string },
16
- pathFragment: string,
17
- ) => {
18
- return {
19
- template: 'ACCOUNT_ACTION',
20
- recipientEmail: to,
21
- action: pathFragment,
22
- userId: user.id || user._id,
23
- token,
24
- skipMessaging: !!user.guest && pathFragment === 'verify-email',
25
- };
26
- };
27
-
28
- accountsServer.options.sendMail = (input: any) => {
29
- if (!input) return true;
30
- if (input.skipMessaging) return true;
31
-
32
- return unchainedAPI.modules.worker.addWork({
5
+ subscribe('USER_ACCOUNT_ACTION', async ({ payload }: { payload: any }) => {
6
+ await unchainedAPI.modules.worker.addWork({
33
7
  type: 'MESSAGE',
34
8
  retries: 0,
35
- input,
36
- });
37
- };
38
-
39
- accountsServer.services.guest = {
40
- async authenticate(params: { email?: string | null }) {
41
- const guestname = `${moniker.choose()}-${randomValueHex(5)}`;
42
-
43
- const guestUserId = await unchainedAPI.modules.accounts.createUser(
44
- {
45
- email: params.email || `${guestname}@unchained.local`,
46
- guest: true,
47
- password: null,
48
- initialPassword: true,
49
- },
50
- {},
51
- );
52
- return unchainedAPI.modules.users.findUserById(guestUserId);
53
- },
54
- };
55
-
56
- accountsServer.services.webAuthn = {
57
- async authenticate(params: { webAuthnPublicKeyCredentials: any }) {
58
- const username =
59
- Buffer.from(params.webAuthnPublicKeyCredentials?.response?.userHandle, 'base64').toString() ||
60
- '';
61
-
62
- const user = await unchainedAPI.modules.users.findUser({ username });
63
- if (!user) throw new Error('User not found');
64
-
65
- await unchainedAPI.modules.accounts.webAuthn.verifyCredentialRequest(
66
- user.services?.webAuthn,
67
- user.username,
68
- params.webAuthnPublicKeyCredentials,
69
- );
70
- return user;
71
- },
72
- };
73
-
74
- accountsServer.services.oauth2 = {
75
- async authenticate({
76
- authorizationCode,
77
- provider,
78
- redirectUrl,
79
- }: {
80
- authorizationCode: any;
81
- provider: string;
82
- redirectUrl: string;
83
- }): Promise<any> {
84
- if (!authorizationCode || !provider) {
85
- return undefined;
86
- }
87
-
88
- const { modules, services } = unchainedAPI;
89
-
90
- const authorizationToken = await modules.accounts.oAuth2.getAuthorizationToken(
91
- provider,
92
- authorizationCode,
93
- redirectUrl,
94
- );
95
-
96
- if (!authorizationToken) throw new Error('Unable to authorize user');
97
- const data = await modules.accounts.oAuth2.getAccountData(provider, authorizationToken);
98
- if (!data?.id) {
99
- throw new Error('OAuth authentication failed or no id returned from service');
100
- }
101
-
102
- const user = await unchainedAPI.modules.users.findUser({
103
- [`services.oauth.${provider}.id`]: data.id,
104
- });
105
-
106
- if (!user) {
107
- const newUserId = await unchainedAPI.modules.accounts.createUser(
108
- {
109
- username: data.username || `${data.id}`,
110
- email: data.email,
111
- guest: false,
112
- initialPassword: undefined,
113
- password: undefined,
114
- profile: {
115
- address: {
116
- firstName: data?.firstName,
117
- lastName: data?.lastName,
118
- addressLine: data?.address,
119
- city: data?.city,
120
- countryCode: data?.countryCode,
121
- regionCode: data?.regionCode,
122
- postalCode: data?.postalCode,
123
- company: data?.company,
124
- },
125
- gender: data?.gender,
126
- phoneMobile: data?.phoneNumber,
127
- displayName: data?.displayName,
128
- birthday: data?.birthDate,
129
- },
130
- },
131
- { skipPasswordEnrollment: true },
132
- );
133
-
134
- await modules.users.updateUser(
135
- { _id: newUserId },
136
- {
137
- $push: {
138
- [`services.oauth.${provider}`]: {
139
- id: data.id,
140
- authorizationToken,
141
- authorizationCode,
142
- data,
143
- },
144
- },
145
- },
146
- { upsert: true },
147
- );
148
-
149
- if (data?.avatarUrl) {
150
- const file = await services.files.uploadFileFromURL(
151
- {
152
- directoryName: 'user-avatars',
153
- fileInput: {
154
- fileLink: data.avatarUrl,
155
- fileName: `${data.firstName}-avatar`,
156
- },
157
- meta: { userId: newUserId },
158
- },
159
- unchainedAPI,
160
- );
161
- if (user?.avatarId) {
162
- await services.files.removeFiles(
163
- {
164
- fileIds: [user.avatarId as string],
165
- },
166
- unchainedAPI,
167
- );
168
- }
169
- return modules.users.updateAvatar(newUserId, file._id);
170
- }
171
- }
172
-
173
- return user;
174
- },
175
- };
176
-
177
- accountsServer.on('LoginTokenCreated', async (props) => {
178
- const { userId, connection = {} } = props;
179
-
180
- // TODO: Doubt that there is countryContext etc. here?
181
- const { userIdBeforeLogin, countryContext, remoteAddress, remotePort, userAgent, normalizedLocale } =
182
- connection;
183
-
184
- await unchainedAPI.modules.users.updateHeartbeat(userId, {
185
- remoteAddress,
186
- remotePort,
187
- userAgent,
188
- locale: normalizedLocale,
189
- countryCode: countryContext,
190
- });
191
-
192
- const user = await unchainedAPI.modules.users.findUserById(userId);
193
-
194
- if (userIdBeforeLogin) {
195
- const userBeforeLogin = await unchainedAPI.modules.users.findUserById(userIdBeforeLogin);
196
-
197
- await unchainedAPI.services.orders.migrateOrderCarts(
198
- {
199
- fromUserId: userBeforeLogin._id,
200
- toUserId: user._id,
201
- shouldMerge: accountsSettings.mergeUserCartsOnLogin,
202
- countryContext:
203
- countryContext || userBeforeLogin.lastLogin?.countryCode || user.lastLogin?.countryCode,
204
- },
205
- unchainedAPI,
206
- );
207
-
208
- await unchainedAPI.services.bookmarks.migrateBookmarks(
209
- {
210
- fromUserId: userBeforeLogin._id,
211
- toUserId: user._id,
212
- shouldMerge: accountsSettings.mergeUserCartsOnLogin,
213
- countryContext:
214
- countryContext || userBeforeLogin.lastLogin?.countryCode || user.lastLogin?.countryCode,
215
- },
216
- unchainedAPI,
217
- );
218
- }
219
-
220
- return unchainedAPI.services.orders.nextUserCart(
221
- {
222
- user,
223
- countryCode: countryContext,
9
+ input: {
10
+ template: 'ACCOUNT_ACTION',
11
+ recipientEmail: payload.address,
12
+ ...payload,
224
13
  },
225
- unchainedAPI,
226
- );
227
- });
228
-
229
- accountsServer.on('ResetPasswordSuccess', async (user: User) => {
230
- await unchainedAPI.modules.users.updateInitialPassword(user, false);
231
- });
232
-
233
- accountsServer.on('ChangePasswordSuccess', async (user: User) => {
234
- await unchainedAPI.modules.users.updateInitialPassword(user, false);
235
- });
236
-
237
- accountsServer.on('ValidateLogin', async (params: { service: string; user: User }) => {
238
- if (params.service !== 'guest' && params.user.guest) {
239
- await unchainedAPI.modules.users.updateGuest(params.user, false);
240
- }
241
- return true;
14
+ });
242
15
  });
243
-
244
- return accountsServer;
245
16
  };
@@ -1,4 +1,4 @@
1
- import { startAPIServer, roles } from '@unchainedshop/api';
1
+ import { startAPIServer, GraphQLServerOptions, roles } from '@unchainedshop/api';
2
2
  import { initCore } from '@unchainedshop/core';
3
3
  import { initDb } from '@unchainedshop/mongodb';
4
4
  import { createLogger } from '@unchainedshop/logger';
@@ -6,6 +6,7 @@ import { UnchainedCore, UnchainedCoreOptions } from '@unchainedshop/types/core.j
6
6
  import { getRegisteredEvents } from '@unchainedshop/events';
7
7
  import { WorkerDirector } from '@unchainedshop/core-worker';
8
8
  import { AdminUiConfig } from '@unchainedshop/types/api.js';
9
+ import { Db } from 'mongodb';
9
10
  import { BulkImportHandler, createBulkImporterFactory } from './bulk-importer/createBulkImporter.js';
10
11
  import { runMigrations } from './migrations/runMigrations.js';
11
12
  import { setupAccounts } from './setup/setupAccounts.js';
@@ -17,19 +18,14 @@ import { createMigrationRepository } from './migrations/migrationRepository.js';
17
18
  export { MessageTypes };
18
19
 
19
20
  export type PlatformOptions = {
20
- typeDefs?: Array<string>;
21
- resolvers?: any;
22
- schema?: any;
23
- plugins?: any[];
24
- cache?: any;
25
21
  bulkImporter?: {
26
22
  handlers?: Record<string, BulkImportHandler>;
27
23
  };
28
24
  context?: any;
29
25
  workQueueOptions?: SetupWorkqueueOptions & SetupCartsOptions;
30
- introspection?: boolean;
31
26
  adminUiConfig?: AdminUiConfig;
32
- } & Partial<Pick<UnchainedCoreOptions, 'modules' | 'services' | 'options' | 'rolesOptions'>>;
27
+ } & Partial<Pick<UnchainedCoreOptions, 'modules' | 'services' | 'options' | 'rolesOptions'>> &
28
+ GraphQLServerOptions;
33
29
 
34
30
  const logger = createLogger('unchained');
35
31
 
@@ -55,21 +51,16 @@ export const queueWorkers: Array<any> = [];
55
51
  export const startPlatform = async ({
56
52
  modules = {},
57
53
  services = {},
58
- typeDefs = [],
59
- resolvers = [],
60
54
  options = {},
61
55
  adminUiConfig = {},
62
56
  rolesOptions = {},
63
57
  bulkImporter: bulkImporterOptions,
64
- schema,
65
- plugins,
66
- cache,
67
58
  workQueueOptions,
68
- context,
69
- introspection,
59
+ ...arbitraryGraphQLServerOptions
70
60
  }: PlatformOptions): Promise<{
71
61
  unchainedAPI: UnchainedCore;
72
- apolloGraphQLServer: any;
62
+ yogaServer: any;
63
+ db: Db;
73
64
  }> => {
74
65
  exitOnMissingEnvironmentVariables();
75
66
 
@@ -107,19 +98,13 @@ export const startPlatform = async ({
107
98
  setupTemplates(unchainedAPI);
108
99
 
109
100
  // Start the graphQL server
110
- const apolloGraphQLServer = await startAPIServer({
101
+ const yogaServer = await startAPIServer({
111
102
  unchainedAPI,
112
103
  roles: configuredRoles,
113
104
  events: configuredEvents,
114
105
  workTypes: configuredWorkTypes,
115
- typeDefs,
116
- resolvers,
117
- schema,
118
- plugins,
119
- cache,
120
- context,
121
- introspection,
122
106
  adminUiConfig,
107
+ ...arbitraryGraphQLServerOptions,
123
108
  });
124
109
 
125
110
  // Setup work queues for scheduled work
@@ -134,5 +119,5 @@ export const startPlatform = async ({
134
119
  setImmediate(() => unchainedAPI.modules.filters.invalidateCache({}, unchainedAPI));
135
120
  }
136
121
 
137
- return { unchainedAPI, apolloGraphQLServer };
122
+ return { unchainedAPI, yogaServer, db };
138
123
  };
@@ -1,4 +0,0 @@
1
- import { Context } from '@unchainedshop/types/api.js';
2
- declare const _default: (fn?: (context: Context) => any) => any;
3
- export default _default;
4
- //# sourceMappingURL=withAccessToken.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"withAccessToken.d.ts","sourceRoot":"","sources":["../../src/context/withAccessToken.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;8BAOlC,CAAC,OAAO,EAAE,OAAO,KAAK,GAAG,KAAqB,GAAG;AAArE,wBA+BE"}
@@ -1,37 +0,0 @@
1
- import { createLogger } from '@unchainedshop/logger';
2
- import { timingSafeEqual } from 'crypto';
3
- const logger = createLogger('unchained:platform');
4
- const contextIdentity = (params) => params;
5
- export default (fn = contextIdentity) => {
6
- return async (params, unchainedContextFn) => {
7
- const unchainedContext = await unchainedContextFn(params);
8
- const newContext = {
9
- userId: unchainedContext.userId,
10
- user: unchainedContext.user,
11
- };
12
- if (!unchainedContext.userId && params.req.headers.authorization) {
13
- const [type, userToken] = params.req.headers.authorization.split(' ');
14
- if (type === 'Bearer' && userToken) {
15
- const [username, secret] = userToken.split(':');
16
- const user = await unchainedContext.modules.users.findUser({
17
- username,
18
- });
19
- if (secret && user?.services.token?.secret) {
20
- if (timingSafeEqual(Buffer.from(secret), Buffer.from(user?.services.token?.secret))) {
21
- newContext.userId = user._id;
22
- newContext.user = user;
23
- logger.debug('Token login success');
24
- }
25
- else {
26
- logger.warn('Token login failed');
27
- }
28
- }
29
- }
30
- }
31
- return fn({
32
- ...unchainedContext,
33
- ...newContext,
34
- });
35
- };
36
- };
37
- //# sourceMappingURL=withAccessToken.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"withAccessToken.js","sourceRoot":"","sources":["../../src/context/withAccessToken.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAErD,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAEzC,MAAM,MAAM,GAAG,YAAY,CAAC,oBAAoB,CAAC,CAAC;AAElD,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC;AAE3C,eAAe,CAAC,KAAgC,eAAe,EAAO,EAAE;IACtE,OAAO,KAAK,EAAE,MAAM,EAAE,kBAAkB,EAAE,EAAE;QAC1C,MAAM,gBAAgB,GAAG,MAAM,kBAAkB,CAAC,MAAM,CAAC,CAAC;QAC1D,MAAM,UAAU,GAAG;YACjB,MAAM,EAAE,gBAAgB,CAAC,MAAM;YAC/B,IAAI,EAAE,gBAAgB,CAAC,IAAI;SAC5B,CAAC;QACF,IAAI,CAAC,gBAAgB,CAAC,MAAM,IAAI,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;YACjE,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACtE,IAAI,IAAI,KAAK,QAAQ,IAAI,SAAS,EAAE,CAAC;gBACnC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAChD,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC;oBACzD,QAAQ;iBACT,CAAC,CAAC;gBAEH,IAAI,MAAM,IAAI,IAAI,EAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;oBAC3C,IAAI,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;wBACpF,UAAU,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC;wBAC7B,UAAU,CAAC,IAAI,GAAG,IAAI,CAAC;wBACvB,MAAM,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;oBACtC,CAAC;yBAAM,CAAC;wBACN,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;oBACpC,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,EAAE,CAAC;YACR,GAAG,gBAAgB;YACnB,GAAG,UAAU;SACd,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC,CAAC"}
@@ -1,40 +0,0 @@
1
- import { createLogger } from '@unchainedshop/logger';
2
- import { Context } from '@unchainedshop/types/api.js';
3
- import { timingSafeEqual } from 'crypto';
4
-
5
- const logger = createLogger('unchained:platform');
6
-
7
- const contextIdentity = (params) => params;
8
-
9
- export default (fn: (context: Context) => any = contextIdentity): any => {
10
- return async (params, unchainedContextFn) => {
11
- const unchainedContext = await unchainedContextFn(params);
12
- const newContext = {
13
- userId: unchainedContext.userId,
14
- user: unchainedContext.user,
15
- };
16
- if (!unchainedContext.userId && params.req.headers.authorization) {
17
- const [type, userToken] = params.req.headers.authorization.split(' ');
18
- if (type === 'Bearer' && userToken) {
19
- const [username, secret] = userToken.split(':');
20
- const user = await unchainedContext.modules.users.findUser({
21
- username,
22
- });
23
-
24
- if (secret && user?.services.token?.secret) {
25
- if (timingSafeEqual(Buffer.from(secret), Buffer.from(user?.services.token?.secret))) {
26
- newContext.userId = user._id;
27
- newContext.user = user;
28
- logger.debug('Token login success');
29
- } else {
30
- logger.warn('Token login failed');
31
- }
32
- }
33
- }
34
- }
35
- return fn({
36
- ...unchainedContext,
37
- ...newContext,
38
- });
39
- };
40
- };