@wix/sdk 1.11.1 → 1.12.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.
@@ -1,11 +1,5 @@
1
1
  import { AuthenticationStrategy } from '@wix/sdk-types';
2
- export type AppStrategy = AuthenticationStrategy<undefined, (opts: {
3
- instanceId: string;
4
- } | {
5
- refreshToken: string;
6
- } | {
7
- fromRequest: Request;
8
- }) => AppStrategy> & {
2
+ export type AppStrategy = AuthenticationStrategy<undefined> & {
9
3
  getInstallUrl(opts: {
10
4
  redirectUrl: string;
11
5
  state?: string;
@@ -18,6 +12,7 @@ export type AppStrategy = AuthenticationStrategy<undefined, (opts: {
18
12
  accessToken: string;
19
13
  refreshToken: string;
20
14
  }>;
15
+ elevated(): Promise<AppStrategy>;
21
16
  };
22
17
  /**
23
18
  * Creates an authentication strategy for Wix Apps OAuth installation process.
@@ -53,39 +53,6 @@ export function AppStrategy(opts) {
53
53
  }
54
54
  return `https://www.wix.com/installer/install?${params.toString()}`;
55
55
  },
56
- withAuth(params) {
57
- if ('instanceId' in params) {
58
- return AppStrategy({
59
- appId: opts.appId,
60
- appSecret: opts.appSecret,
61
- publicKey: opts.publicKey,
62
- instanceId: params.instanceId,
63
- });
64
- }
65
- else if ('refreshToken' in params) {
66
- return AppStrategy({
67
- appId: opts.appId,
68
- appSecret: opts.appSecret,
69
- publicKey: opts.publicKey,
70
- refreshToken: params.refreshToken,
71
- });
72
- }
73
- else if ('fromRequest' in params) {
74
- const authFromRequest = params.fromRequest.headers.get('Authorization');
75
- if (!authFromRequest) {
76
- throw new Error('Missing Authorization header in the request');
77
- }
78
- return AppStrategy({
79
- appId: opts.appId,
80
- appSecret: opts.appSecret,
81
- publicKey: opts.publicKey,
82
- accessToken: authFromRequest,
83
- });
84
- }
85
- else {
86
- throw new Error('Invalid parameters for withAuth');
87
- }
88
- },
89
56
  async handleOAuthCallback(url, oauthOpts) {
90
57
  if (!opts.appSecret) {
91
58
  throw new Error('App secret is required for handling OAuth callback. Make sure to pass it to the AppStrategy');
@@ -185,6 +152,38 @@ export function AppStrategy(opts) {
185
152
  throw new Error('Missing refresh token or instance ID. Either one is needed to get app level access tokens. Make sure to pass one of them to the AppStrategy');
186
153
  }
187
154
  },
155
+ async elevated() {
156
+ if ('accessToken' in opts && opts.accessToken) {
157
+ const tokenInfoRes = await fetch('https://www.wixapis.com/oauth2/token-info', {
158
+ method: 'POST',
159
+ headers: {
160
+ 'Content-Type': 'application/json',
161
+ },
162
+ body: JSON.stringify({
163
+ token: opts.accessToken,
164
+ }),
165
+ });
166
+ if (tokenInfoRes.status !== 200) {
167
+ throw new Error(`Failed to get token info. Unexpected status code from Wix OAuth API: ${tokenInfoRes.status}`);
168
+ }
169
+ const tokenInfo = await tokenInfoRes.json();
170
+ if (tokenInfo.app_id !== opts.appId) {
171
+ throw new Error(`Invalid access token. The token is not issued for the app with ID "${opts.appId}"`);
172
+ }
173
+ if (!tokenInfo.instanceId) {
174
+ throw new Error('Unexpected token info. The token does not contain instance ID');
175
+ }
176
+ return AppStrategy({
177
+ appId: opts.appId,
178
+ appSecret: opts.appSecret,
179
+ publicKey: opts.publicKey,
180
+ instanceId: tokenInfo.instanceId,
181
+ });
182
+ }
183
+ else {
184
+ throw new Error('Providing an access token is required to perform elevation. Make sure to pass it to the AppStrategy');
185
+ }
186
+ },
188
187
  async decodeJWT(token, verifyCallerClaims = false) {
189
188
  if (!opts.publicKey) {
190
189
  throw new Error('Missing public key. Make sure to pass it to the AppStrategy');
@@ -66,6 +66,18 @@ export interface IOAuthStrategy extends AuthenticationStrategy {
66
66
  captchaInvisibleSiteKey: string;
67
67
  captchaVisibleSiteKey: string;
68
68
  loggedIn: () => boolean;
69
+ /**
70
+ * Retrieves and authenticates site member's access and refresh tokens given a member ID.
71
+ * A member ID for external login can be retrieved from the Wix Members API using `queryMembers`
72
+ * function, using any externally identifiable field (e.g. email, phone number, etc.).
73
+ *
74
+ * In addition to the member ID, an API Key with permissions on Wix Contacts & Members is required
75
+ * (this is an administrative API that bypasses the need for a session token and so can only be used
76
+ * from confidential clients).
77
+ * @param memberId The member ID to get the tokens for
78
+ * @param apiKey An API Key with permissions on Wix Contacts & Members
79
+ * @returns Tokens (access and refresh) for the member
80
+ */
69
81
  getMemberTokensForExternalLogin: (memberId: string, apiKey: string) => Promise<Tokens>;
70
82
  }
71
83
  export declare enum LoginState {
@@ -29,11 +29,12 @@ type TypedQueryInput<Result = {
29
29
  export type WixClient<H extends Host<any> | undefined = undefined, Z extends AuthenticationStrategy<H> = AuthenticationStrategy<H>, T extends Descriptors = {}> = {
30
30
  setHeaders(headers: Headers): void;
31
31
  auth: Omit<Z, 'getAuthHeaders'> & BoundAuthenticationStrategy;
32
- withAuth: Z['withAuth'] extends undefined ? never : (...args: Parameters<NonNullable<Z['withAuth']>>) => WixClient<H, Z, T>;
33
32
  fetch(relativeUrl: string, options: RequestInit): Promise<Response>;
34
33
  fetchWithAuth: typeof fetch;
35
34
  use<R extends Descriptors = EmptyObject>(modules: H extends Host<any> ? AssertHostMatches<R, H> : R): BuildDescriptors<R, H>;
36
- enableContext(contextType: ContextType): void;
35
+ enableContext(contextType: ContextType, opts?: {
36
+ elevated: boolean;
37
+ }): void;
37
38
  graphql<Result, Variables>(query: string | ((string | String) & TypedQueryInput<Result, Variables>), variables?: Variables): Promise<{
38
39
  data: Result;
39
40
  errors?: GraphQLFormattedError[];
@@ -46,6 +47,9 @@ export type WixClient<H extends Host<any> | undefined = undefined, Z extends Aut
46
47
  processRequest<ExpectedEvents extends EventDefinition<any>[] = []>(request: Request, opts?: {
47
48
  expectedEvents: ExpectedEvents;
48
49
  }): Promise<ProcessedEvent<ExpectedEvents>>;
50
+ parseJWT(jwt: string): Promise<ProcessedEvent>;
51
+ parseRequest(request: Request): Promise<ProcessedEvent>;
52
+ executeHandlers(event: ProcessedEvent): Promise<void>;
49
53
  apps: {
50
54
  AppInstalled: EventDefinition<{
51
55
  appId: string;
@@ -66,6 +70,9 @@ export type WixClient<H extends Host<any> | undefined = undefined, Z extends Aut
66
70
  body: string;
67
71
  }): Promise<unknown>;
68
72
  processRequest(request: Request): Promise<Response>;
73
+ parseJWT(jwt: string): Promise<unknown>;
74
+ parseRequest(request: Request): Promise<unknown>;
75
+ executeHandler(servicePluginRequest: ProcessedEvent): Promise<void>;
69
76
  };
70
77
  } & BuildDescriptors<T, H>;
71
78
  type ResolvePossibleEvents<T extends EventDefinition<any>[]> = {
@@ -81,7 +88,7 @@ export type ProcessedEvent<T extends EventDefinition<any>[] = []> = {
81
88
  eventType: string;
82
89
  payload: unknown;
83
90
  } : ResolvePossibleEvents<T>);
84
- export declare function createClient<H extends Host<any> | undefined = undefined, Z extends AuthenticationStrategy<H, any> = AuthenticationStrategy<H>, T extends Descriptors = EmptyObject>(config: {
91
+ export declare function createClient<H extends Host<any> | undefined = undefined, Z extends AuthenticationStrategy<H> = AuthenticationStrategy<H>, T extends Descriptors = EmptyObject>(config: {
85
92
  modules?: H extends Host<any> ? AssertHostMatches<T, H> : T;
86
93
  auth?: Z;
87
94
  headers?: Headers;
@@ -87,25 +87,34 @@ export function createClient(config) {
87
87
  return {
88
88
  ...wrappedModules,
89
89
  auth: authStrategy,
90
- withAuth: (authStrategy.withAuth
91
- ? (...args) => createClient({
92
- ...config,
93
- auth: authStrategy.withAuth(...args),
94
- })
95
- : undefined),
96
90
  setHeaders,
97
91
  use,
98
- enableContext(contextType) {
92
+ enableContext(contextType, opts = { elevated: false }) {
99
93
  if (contextType === 'global') {
100
94
  if (globalThis.__wix_context__ != null) {
101
- globalThis.__wix_context__.client = this;
95
+ if (opts.elevated) {
96
+ globalThis.__wix_context__.elevatedClient = this;
97
+ }
98
+ else {
99
+ globalThis.__wix_context__.client = this;
100
+ }
102
101
  }
103
102
  else {
104
- globalThis.__wix_context__ = { client: this };
103
+ if (opts.elevated) {
104
+ globalThis.__wix_context__ = { elevatedClient: this };
105
+ }
106
+ else {
107
+ globalThis.__wix_context__ = { client: this };
108
+ }
105
109
  }
106
110
  }
107
111
  else {
108
- wixContext.client = this;
112
+ if (opts.elevated) {
113
+ wixContext.elevatedClient = this;
114
+ }
115
+ else {
116
+ wixContext.client = this;
117
+ }
109
118
  }
110
119
  },
111
120
  fetch: (relativeUrl, options) => {
@@ -149,26 +158,10 @@ export function createClient(config) {
149
158
  },
150
159
  webhooks: {
151
160
  getRegisteredEvents: () => Array.from(eventHandlers.keys()),
152
- process: async (jwt, opts = {
161
+ async process(jwt, opts = {
153
162
  expectedEvents: [],
154
- }) => {
155
- if (!authStrategy.decodeJWT) {
156
- throw new Error('decodeJWT is not supported by the authentication strategy');
157
- }
158
- const { decoded, valid } = await authStrategy.decodeJWT(jwt);
159
- if (!valid) {
160
- throw new Error('JWT is not valid');
161
- }
162
- if (typeof decoded.data !== 'string') {
163
- throw new Error(`Unexpected type of JWT data: expected string, got ${typeof decoded.data}`);
164
- }
165
- const parsedDecoded = JSON.parse(decoded.data);
166
- const eventType = parsedDecoded.eventType;
167
- const instanceId = parsedDecoded.instanceId;
168
- const identity = parsedDecoded.identity
169
- ? JSON.parse(parsedDecoded.identity)
170
- : undefined;
171
- const payload = JSON.parse(parsedDecoded.data);
163
+ }) {
164
+ const { eventType, identity, instanceId, payload } = await this.parseJWT(jwt);
172
165
  const allExpectedEvents = [
173
166
  ...opts.expectedEvents,
174
167
  ...Array.from(eventHandlers.keys()).map((type) => ({ type })),
@@ -195,6 +188,49 @@ export function createClient(config) {
195
188
  const body = await request.text();
196
189
  return this.process(body, opts);
197
190
  },
191
+ async parseJWT(jwt) {
192
+ if (!authStrategy.decodeJWT) {
193
+ throw new Error('decodeJWT is not supported by the authentication strategy');
194
+ }
195
+ const { decoded, valid } = await authStrategy.decodeJWT(jwt);
196
+ if (!valid) {
197
+ throw new Error('JWT is not valid');
198
+ }
199
+ if (typeof decoded.data !== 'string') {
200
+ throw new Error(`Unexpected type of JWT data: expected string, got ${typeof decoded.data}`);
201
+ }
202
+ const parsedDecoded = JSON.parse(decoded.data);
203
+ const eventType = parsedDecoded.eventType;
204
+ const instanceId = parsedDecoded.instanceId;
205
+ const identity = parsedDecoded.identity
206
+ ? JSON.parse(parsedDecoded.identity)
207
+ : undefined;
208
+ const payload = JSON.parse(parsedDecoded.data);
209
+ return {
210
+ instanceId,
211
+ eventType,
212
+ payload,
213
+ identity,
214
+ };
215
+ },
216
+ async parseRequest(request) {
217
+ const jwt = await request.text();
218
+ return this.parseJWT(jwt);
219
+ },
220
+ async executeHandlers(event) {
221
+ const allExpectedEvents = Array.from(eventHandlers.keys()).map((type) => ({ type }));
222
+ if (allExpectedEvents.length > 0 &&
223
+ !allExpectedEvents.some(({ type }) => type === event.eventType)) {
224
+ throw new Error(`Unexpected event type: ${event.eventType}. Expected one of: ${allExpectedEvents
225
+ .map((x) => x.type)
226
+ .join(', ')}`);
227
+ }
228
+ const handlers = eventHandlers.get(event.eventType) ?? [];
229
+ await Promise.all(handlers.map(({ eventDefinition, handler }) => runHandler(eventDefinition, handler, event.payload, {
230
+ instanceId: event.instanceId,
231
+ identity: event.identity,
232
+ })));
233
+ },
198
234
  apps: {
199
235
  AppInstalled: EventDefinition('AppInstalled')(),
200
236
  AppRemoved: EventDefinition('AppRemoved')(),
@@ -203,10 +239,20 @@ export function createClient(config) {
203
239
  servicePlugins: {
204
240
  getRegisteredServicePlugins: () => servicePluginsImplementations,
205
241
  async process(request) {
242
+ const servicePluginRequest = await this.parseJWT(request.body);
243
+ return this.executeHandler(servicePluginRequest, request.url);
244
+ },
245
+ async processRequest(request) {
246
+ const url = request.url;
247
+ const body = await request.text();
248
+ const implMethodResult = await this.process({ url, body });
249
+ return Response.json(implMethodResult);
250
+ },
251
+ async parseJWT(jwt) {
206
252
  if (!authStrategy.decodeJWT) {
207
253
  throw new Error('decodeJWT is not supported by the authentication strategy');
208
254
  }
209
- const { decoded, valid } = await authStrategy.decodeJWT(request.body, true);
255
+ const { decoded, valid } = await authStrategy.decodeJWT(jwt, true);
210
256
  if (!valid) {
211
257
  throw new Error('JWT is not valid');
212
258
  }
@@ -219,7 +265,10 @@ export function createClient(config) {
219
265
  typeof decoded.data.metadata.appExtensionType !== 'string') {
220
266
  throw new Error('Unexpected JWT data: expected object with metadata.appExtensionType string');
221
267
  }
222
- const componentType = decoded.data?.metadata.appExtensionType.toLowerCase();
268
+ return decoded.data;
269
+ },
270
+ async executeHandler(servicePluginRequest, url) {
271
+ const componentType = servicePluginRequest.metadata.appExtensionType.toLowerCase();
223
272
  const implementations = servicePluginsImplementations.get(componentType) ?? [];
224
273
  if (implementations.length === 0) {
225
274
  throw new Error(`No service plugin implementations found for component type ${componentType}`);
@@ -228,22 +277,15 @@ export function createClient(config) {
228
277
  throw new Error(`Multiple service plugin implementations found for component type ${componentType}. This is currently not supported`);
229
278
  }
230
279
  const { implementation: impl, servicePluginDefinition } = implementations[0];
231
- const method = servicePluginDefinition.methods.find((m) => request.url.endsWith(m.primaryHttpMappingPath));
280
+ const method = servicePluginDefinition.methods.find((m) => url.endsWith(m.primaryHttpMappingPath));
232
281
  if (!method) {
233
- throw new Error('Unexpect request: request url did not match any method: ' +
234
- request.url);
282
+ throw new Error('Unexpect request: request url did not match any method: ' + url);
235
283
  }
236
284
  const implMethod = impl[method.name];
237
285
  if (!implMethod) {
238
286
  throw new Error(`Got request for service plugin method ${method.name} but no implementation was provided. Available methods: ${Object.keys(impl).join(', ')}`);
239
287
  }
240
- return method.transformations.toREST(await implMethod(method.transformations.fromREST(decoded.data)));
241
- },
242
- async processRequest(request) {
243
- const url = request.url;
244
- const body = await request.text();
245
- const implMethodResult = await this.process({ url, body });
246
- return Response.json(implMethodResult);
288
+ return method.transformations.toREST(await implMethod(method.transformations.fromREST(servicePluginRequest)));
247
289
  },
248
290
  },
249
291
  };
@@ -1,11 +1,5 @@
1
1
  import { AuthenticationStrategy } from '@wix/sdk-types';
2
- export type AppStrategy = AuthenticationStrategy<undefined, (opts: {
3
- instanceId: string;
4
- } | {
5
- refreshToken: string;
6
- } | {
7
- fromRequest: Request;
8
- }) => AppStrategy> & {
2
+ export type AppStrategy = AuthenticationStrategy<undefined> & {
9
3
  getInstallUrl(opts: {
10
4
  redirectUrl: string;
11
5
  state?: string;
@@ -18,6 +12,7 @@ export type AppStrategy = AuthenticationStrategy<undefined, (opts: {
18
12
  accessToken: string;
19
13
  refreshToken: string;
20
14
  }>;
15
+ elevated(): Promise<AppStrategy>;
21
16
  };
22
17
  /**
23
18
  * Creates an authentication strategy for Wix Apps OAuth installation process.
@@ -79,39 +79,6 @@ function AppStrategy(opts) {
79
79
  }
80
80
  return `https://www.wix.com/installer/install?${params.toString()}`;
81
81
  },
82
- withAuth(params) {
83
- if ('instanceId' in params) {
84
- return AppStrategy({
85
- appId: opts.appId,
86
- appSecret: opts.appSecret,
87
- publicKey: opts.publicKey,
88
- instanceId: params.instanceId,
89
- });
90
- }
91
- else if ('refreshToken' in params) {
92
- return AppStrategy({
93
- appId: opts.appId,
94
- appSecret: opts.appSecret,
95
- publicKey: opts.publicKey,
96
- refreshToken: params.refreshToken,
97
- });
98
- }
99
- else if ('fromRequest' in params) {
100
- const authFromRequest = params.fromRequest.headers.get('Authorization');
101
- if (!authFromRequest) {
102
- throw new Error('Missing Authorization header in the request');
103
- }
104
- return AppStrategy({
105
- appId: opts.appId,
106
- appSecret: opts.appSecret,
107
- publicKey: opts.publicKey,
108
- accessToken: authFromRequest,
109
- });
110
- }
111
- else {
112
- throw new Error('Invalid parameters for withAuth');
113
- }
114
- },
115
82
  async handleOAuthCallback(url, oauthOpts) {
116
83
  if (!opts.appSecret) {
117
84
  throw new Error('App secret is required for handling OAuth callback. Make sure to pass it to the AppStrategy');
@@ -211,6 +178,38 @@ function AppStrategy(opts) {
211
178
  throw new Error('Missing refresh token or instance ID. Either one is needed to get app level access tokens. Make sure to pass one of them to the AppStrategy');
212
179
  }
213
180
  },
181
+ async elevated() {
182
+ if ('accessToken' in opts && opts.accessToken) {
183
+ const tokenInfoRes = await fetch('https://www.wixapis.com/oauth2/token-info', {
184
+ method: 'POST',
185
+ headers: {
186
+ 'Content-Type': 'application/json',
187
+ },
188
+ body: JSON.stringify({
189
+ token: opts.accessToken,
190
+ }),
191
+ });
192
+ if (tokenInfoRes.status !== 200) {
193
+ throw new Error(`Failed to get token info. Unexpected status code from Wix OAuth API: ${tokenInfoRes.status}`);
194
+ }
195
+ const tokenInfo = await tokenInfoRes.json();
196
+ if (tokenInfo.app_id !== opts.appId) {
197
+ throw new Error(`Invalid access token. The token is not issued for the app with ID "${opts.appId}"`);
198
+ }
199
+ if (!tokenInfo.instanceId) {
200
+ throw new Error('Unexpected token info. The token does not contain instance ID');
201
+ }
202
+ return AppStrategy({
203
+ appId: opts.appId,
204
+ appSecret: opts.appSecret,
205
+ publicKey: opts.publicKey,
206
+ instanceId: tokenInfo.instanceId,
207
+ });
208
+ }
209
+ else {
210
+ throw new Error('Providing an access token is required to perform elevation. Make sure to pass it to the AppStrategy');
211
+ }
212
+ },
214
213
  async decodeJWT(token, verifyCallerClaims = false) {
215
214
  if (!opts.publicKey) {
216
215
  throw new Error('Missing public key. Make sure to pass it to the AppStrategy');
@@ -66,6 +66,18 @@ export interface IOAuthStrategy extends AuthenticationStrategy {
66
66
  captchaInvisibleSiteKey: string;
67
67
  captchaVisibleSiteKey: string;
68
68
  loggedIn: () => boolean;
69
+ /**
70
+ * Retrieves and authenticates site member's access and refresh tokens given a member ID.
71
+ * A member ID for external login can be retrieved from the Wix Members API using `queryMembers`
72
+ * function, using any externally identifiable field (e.g. email, phone number, etc.).
73
+ *
74
+ * In addition to the member ID, an API Key with permissions on Wix Contacts & Members is required
75
+ * (this is an administrative API that bypasses the need for a session token and so can only be used
76
+ * from confidential clients).
77
+ * @param memberId The member ID to get the tokens for
78
+ * @param apiKey An API Key with permissions on Wix Contacts & Members
79
+ * @returns Tokens (access and refresh) for the member
80
+ */
69
81
  getMemberTokensForExternalLogin: (memberId: string, apiKey: string) => Promise<Tokens>;
70
82
  }
71
83
  export declare enum LoginState {
@@ -29,11 +29,12 @@ type TypedQueryInput<Result = {
29
29
  export type WixClient<H extends Host<any> | undefined = undefined, Z extends AuthenticationStrategy<H> = AuthenticationStrategy<H>, T extends Descriptors = {}> = {
30
30
  setHeaders(headers: Headers): void;
31
31
  auth: Omit<Z, 'getAuthHeaders'> & BoundAuthenticationStrategy;
32
- withAuth: Z['withAuth'] extends undefined ? never : (...args: Parameters<NonNullable<Z['withAuth']>>) => WixClient<H, Z, T>;
33
32
  fetch(relativeUrl: string, options: RequestInit): Promise<Response>;
34
33
  fetchWithAuth: typeof fetch;
35
34
  use<R extends Descriptors = EmptyObject>(modules: H extends Host<any> ? AssertHostMatches<R, H> : R): BuildDescriptors<R, H>;
36
- enableContext(contextType: ContextType): void;
35
+ enableContext(contextType: ContextType, opts?: {
36
+ elevated: boolean;
37
+ }): void;
37
38
  graphql<Result, Variables>(query: string | ((string | String) & TypedQueryInput<Result, Variables>), variables?: Variables): Promise<{
38
39
  data: Result;
39
40
  errors?: GraphQLFormattedError[];
@@ -46,6 +47,9 @@ export type WixClient<H extends Host<any> | undefined = undefined, Z extends Aut
46
47
  processRequest<ExpectedEvents extends EventDefinition<any>[] = []>(request: Request, opts?: {
47
48
  expectedEvents: ExpectedEvents;
48
49
  }): Promise<ProcessedEvent<ExpectedEvents>>;
50
+ parseJWT(jwt: string): Promise<ProcessedEvent>;
51
+ parseRequest(request: Request): Promise<ProcessedEvent>;
52
+ executeHandlers(event: ProcessedEvent): Promise<void>;
49
53
  apps: {
50
54
  AppInstalled: EventDefinition<{
51
55
  appId: string;
@@ -66,6 +70,9 @@ export type WixClient<H extends Host<any> | undefined = undefined, Z extends Aut
66
70
  body: string;
67
71
  }): Promise<unknown>;
68
72
  processRequest(request: Request): Promise<Response>;
73
+ parseJWT(jwt: string): Promise<unknown>;
74
+ parseRequest(request: Request): Promise<unknown>;
75
+ executeHandler(servicePluginRequest: ProcessedEvent): Promise<void>;
69
76
  };
70
77
  } & BuildDescriptors<T, H>;
71
78
  type ResolvePossibleEvents<T extends EventDefinition<any>[]> = {
@@ -81,7 +88,7 @@ export type ProcessedEvent<T extends EventDefinition<any>[] = []> = {
81
88
  eventType: string;
82
89
  payload: unknown;
83
90
  } : ResolvePossibleEvents<T>);
84
- export declare function createClient<H extends Host<any> | undefined = undefined, Z extends AuthenticationStrategy<H, any> = AuthenticationStrategy<H>, T extends Descriptors = EmptyObject>(config: {
91
+ export declare function createClient<H extends Host<any> | undefined = undefined, Z extends AuthenticationStrategy<H> = AuthenticationStrategy<H>, T extends Descriptors = EmptyObject>(config: {
85
92
  modules?: H extends Host<any> ? AssertHostMatches<T, H> : T;
86
93
  auth?: Z;
87
94
  headers?: Headers;
@@ -90,25 +90,34 @@ function createClient(config) {
90
90
  return {
91
91
  ...wrappedModules,
92
92
  auth: authStrategy,
93
- withAuth: (authStrategy.withAuth
94
- ? (...args) => createClient({
95
- ...config,
96
- auth: authStrategy.withAuth(...args),
97
- })
98
- : undefined),
99
93
  setHeaders,
100
94
  use,
101
- enableContext(contextType) {
95
+ enableContext(contextType, opts = { elevated: false }) {
102
96
  if (contextType === 'global') {
103
97
  if (globalThis.__wix_context__ != null) {
104
- globalThis.__wix_context__.client = this;
98
+ if (opts.elevated) {
99
+ globalThis.__wix_context__.elevatedClient = this;
100
+ }
101
+ else {
102
+ globalThis.__wix_context__.client = this;
103
+ }
105
104
  }
106
105
  else {
107
- globalThis.__wix_context__ = { client: this };
106
+ if (opts.elevated) {
107
+ globalThis.__wix_context__ = { elevatedClient: this };
108
+ }
109
+ else {
110
+ globalThis.__wix_context__ = { client: this };
111
+ }
108
112
  }
109
113
  }
110
114
  else {
111
- sdk_context_1.wixContext.client = this;
115
+ if (opts.elevated) {
116
+ sdk_context_1.wixContext.elevatedClient = this;
117
+ }
118
+ else {
119
+ sdk_context_1.wixContext.client = this;
120
+ }
112
121
  }
113
122
  },
114
123
  fetch: (relativeUrl, options) => {
@@ -152,26 +161,10 @@ function createClient(config) {
152
161
  },
153
162
  webhooks: {
154
163
  getRegisteredEvents: () => Array.from(eventHandlers.keys()),
155
- process: async (jwt, opts = {
164
+ async process(jwt, opts = {
156
165
  expectedEvents: [],
157
- }) => {
158
- if (!authStrategy.decodeJWT) {
159
- throw new Error('decodeJWT is not supported by the authentication strategy');
160
- }
161
- const { decoded, valid } = await authStrategy.decodeJWT(jwt);
162
- if (!valid) {
163
- throw new Error('JWT is not valid');
164
- }
165
- if (typeof decoded.data !== 'string') {
166
- throw new Error(`Unexpected type of JWT data: expected string, got ${typeof decoded.data}`);
167
- }
168
- const parsedDecoded = JSON.parse(decoded.data);
169
- const eventType = parsedDecoded.eventType;
170
- const instanceId = parsedDecoded.instanceId;
171
- const identity = parsedDecoded.identity
172
- ? JSON.parse(parsedDecoded.identity)
173
- : undefined;
174
- const payload = JSON.parse(parsedDecoded.data);
166
+ }) {
167
+ const { eventType, identity, instanceId, payload } = await this.parseJWT(jwt);
175
168
  const allExpectedEvents = [
176
169
  ...opts.expectedEvents,
177
170
  ...Array.from(eventHandlers.keys()).map((type) => ({ type })),
@@ -198,6 +191,49 @@ function createClient(config) {
198
191
  const body = await request.text();
199
192
  return this.process(body, opts);
200
193
  },
194
+ async parseJWT(jwt) {
195
+ if (!authStrategy.decodeJWT) {
196
+ throw new Error('decodeJWT is not supported by the authentication strategy');
197
+ }
198
+ const { decoded, valid } = await authStrategy.decodeJWT(jwt);
199
+ if (!valid) {
200
+ throw new Error('JWT is not valid');
201
+ }
202
+ if (typeof decoded.data !== 'string') {
203
+ throw new Error(`Unexpected type of JWT data: expected string, got ${typeof decoded.data}`);
204
+ }
205
+ const parsedDecoded = JSON.parse(decoded.data);
206
+ const eventType = parsedDecoded.eventType;
207
+ const instanceId = parsedDecoded.instanceId;
208
+ const identity = parsedDecoded.identity
209
+ ? JSON.parse(parsedDecoded.identity)
210
+ : undefined;
211
+ const payload = JSON.parse(parsedDecoded.data);
212
+ return {
213
+ instanceId,
214
+ eventType,
215
+ payload,
216
+ identity,
217
+ };
218
+ },
219
+ async parseRequest(request) {
220
+ const jwt = await request.text();
221
+ return this.parseJWT(jwt);
222
+ },
223
+ async executeHandlers(event) {
224
+ const allExpectedEvents = Array.from(eventHandlers.keys()).map((type) => ({ type }));
225
+ if (allExpectedEvents.length > 0 &&
226
+ !allExpectedEvents.some(({ type }) => type === event.eventType)) {
227
+ throw new Error(`Unexpected event type: ${event.eventType}. Expected one of: ${allExpectedEvents
228
+ .map((x) => x.type)
229
+ .join(', ')}`);
230
+ }
231
+ const handlers = eventHandlers.get(event.eventType) ?? [];
232
+ await Promise.all(handlers.map(({ eventDefinition, handler }) => (0, event_handlers_modules_js_1.runHandler)(eventDefinition, handler, event.payload, {
233
+ instanceId: event.instanceId,
234
+ identity: event.identity,
235
+ })));
236
+ },
201
237
  apps: {
202
238
  AppInstalled: (0, sdk_types_1.EventDefinition)('AppInstalled')(),
203
239
  AppRemoved: (0, sdk_types_1.EventDefinition)('AppRemoved')(),
@@ -206,10 +242,20 @@ function createClient(config) {
206
242
  servicePlugins: {
207
243
  getRegisteredServicePlugins: () => servicePluginsImplementations,
208
244
  async process(request) {
245
+ const servicePluginRequest = await this.parseJWT(request.body);
246
+ return this.executeHandler(servicePluginRequest, request.url);
247
+ },
248
+ async processRequest(request) {
249
+ const url = request.url;
250
+ const body = await request.text();
251
+ const implMethodResult = await this.process({ url, body });
252
+ return Response.json(implMethodResult);
253
+ },
254
+ async parseJWT(jwt) {
209
255
  if (!authStrategy.decodeJWT) {
210
256
  throw new Error('decodeJWT is not supported by the authentication strategy');
211
257
  }
212
- const { decoded, valid } = await authStrategy.decodeJWT(request.body, true);
258
+ const { decoded, valid } = await authStrategy.decodeJWT(jwt, true);
213
259
  if (!valid) {
214
260
  throw new Error('JWT is not valid');
215
261
  }
@@ -222,7 +268,10 @@ function createClient(config) {
222
268
  typeof decoded.data.metadata.appExtensionType !== 'string') {
223
269
  throw new Error('Unexpected JWT data: expected object with metadata.appExtensionType string');
224
270
  }
225
- const componentType = decoded.data?.metadata.appExtensionType.toLowerCase();
271
+ return decoded.data;
272
+ },
273
+ async executeHandler(servicePluginRequest, url) {
274
+ const componentType = servicePluginRequest.metadata.appExtensionType.toLowerCase();
226
275
  const implementations = servicePluginsImplementations.get(componentType) ?? [];
227
276
  if (implementations.length === 0) {
228
277
  throw new Error(`No service plugin implementations found for component type ${componentType}`);
@@ -231,22 +280,15 @@ function createClient(config) {
231
280
  throw new Error(`Multiple service plugin implementations found for component type ${componentType}. This is currently not supported`);
232
281
  }
233
282
  const { implementation: impl, servicePluginDefinition } = implementations[0];
234
- const method = servicePluginDefinition.methods.find((m) => request.url.endsWith(m.primaryHttpMappingPath));
283
+ const method = servicePluginDefinition.methods.find((m) => url.endsWith(m.primaryHttpMappingPath));
235
284
  if (!method) {
236
- throw new Error('Unexpect request: request url did not match any method: ' +
237
- request.url);
285
+ throw new Error('Unexpect request: request url did not match any method: ' + url);
238
286
  }
239
287
  const implMethod = impl[method.name];
240
288
  if (!implMethod) {
241
289
  throw new Error(`Got request for service plugin method ${method.name} but no implementation was provided. Available methods: ${Object.keys(impl).join(', ')}`);
242
290
  }
243
- return method.transformations.toREST(await implMethod(method.transformations.fromREST(decoded.data)));
244
- },
245
- async processRequest(request) {
246
- const url = request.url;
247
- const body = await request.text();
248
- const implMethodResult = await this.process({ url, body });
249
- return Response.json(implMethodResult);
291
+ return method.transformations.toREST(await implMethod(method.transformations.fromREST(servicePluginRequest)));
250
292
  },
251
293
  },
252
294
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/sdk",
3
- "version": "1.11.1",
3
+ "version": "1.12.1",
4
4
  "license": "UNLICENSED",
5
5
  "author": {
6
6
  "name": "Ronny Ringel",
@@ -65,11 +65,11 @@
65
65
  "dependencies": {
66
66
  "@babel/runtime": "^7.23.2",
67
67
  "@wix/identity": "^1.0.78",
68
- "@wix/image-kit": "^1.70.0",
68
+ "@wix/image-kit": "^1.71.0",
69
69
  "@wix/redirects": "^1.0.41",
70
70
  "@wix/sdk-context": "^0.0.1",
71
- "@wix/sdk-runtime": "0.3.0",
72
- "@wix/sdk-types": "^1.9.0",
71
+ "@wix/sdk-runtime": "0.3.3",
72
+ "@wix/sdk-types": "^1.9.1",
73
73
  "crypto-js": "^4.2.0",
74
74
  "jose": "^5.2.1",
75
75
  "pkce-challenge": "^3.1.0",
@@ -88,7 +88,7 @@
88
88
  "@wix/events": "^1.0.179",
89
89
  "@wix/metro": "^1.0.73",
90
90
  "@wix/metro-runtime": "^1.1677.0",
91
- "@wix/sdk-runtime": "0.3.0",
91
+ "@wix/sdk-runtime": "0.3.3",
92
92
  "eslint": "^8.56.0",
93
93
  "eslint-config-sdk": "0.0.0",
94
94
  "graphql": "^16.8.0",
@@ -122,5 +122,5 @@
122
122
  "wallaby": {
123
123
  "autoDetect": true
124
124
  },
125
- "falconPackageHash": "463d0e16e85562d2b889feb9295a186f2437388d43ef754d18ab5ad7"
125
+ "falconPackageHash": "177ec0d44fe0da191345f8a3682db306bf5ed81105ff12431590e217"
126
126
  }