@wix/sdk 1.11.0 → 1.12.0

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.
@@ -18,6 +18,7 @@ export type AppStrategy = AuthenticationStrategy<undefined, (opts: {
18
18
  accessToken: string;
19
19
  refreshToken: string;
20
20
  }>;
21
+ elevated(): Promise<AppStrategy>;
21
22
  };
22
23
  /**
23
24
  * Creates an authentication strategy for Wix Apps OAuth installation process.
@@ -185,6 +185,38 @@ export function AppStrategy(opts) {
185
185
  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
186
  }
187
187
  },
188
+ async elevated() {
189
+ if ('accessToken' in opts && opts.accessToken) {
190
+ const tokenInfoRes = await fetch('https://www.wixapis.com/oauth2/token-info', {
191
+ method: 'POST',
192
+ headers: {
193
+ 'Content-Type': 'application/json',
194
+ },
195
+ body: JSON.stringify({
196
+ token: opts.accessToken,
197
+ }),
198
+ });
199
+ if (tokenInfoRes.status !== 200) {
200
+ throw new Error(`Failed to get token info. Unexpected status code from Wix OAuth API: ${tokenInfoRes.status}`);
201
+ }
202
+ const tokenInfo = await tokenInfoRes.json();
203
+ if (tokenInfo.app_id !== opts.appId) {
204
+ throw new Error(`Invalid access token. The token is not issued for the app with ID "${opts.appId}"`);
205
+ }
206
+ if (!tokenInfo.instanceId) {
207
+ throw new Error('Unexpected token info. The token does not contain instance ID');
208
+ }
209
+ return AppStrategy({
210
+ appId: opts.appId,
211
+ appSecret: opts.appSecret,
212
+ publicKey: opts.publicKey,
213
+ instanceId: tokenInfo.instanceId,
214
+ });
215
+ }
216
+ else {
217
+ throw new Error('Providing an access token is required to perform elevation. Make sure to pass it to the AppStrategy');
218
+ }
219
+ },
188
220
  async decodeJWT(token, verifyCallerClaims = false) {
189
221
  if (!opts.publicKey) {
190
222
  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 {
@@ -2,5 +2,5 @@ import { BuildRESTFunction, PublicMetadata, RESTFunctionDescriptor } from '@wix/
2
2
  export type RESTModuleOptions = {
3
3
  HTTPHost?: string;
4
4
  };
5
- export declare const getDefaultDomain: (method: string, url: string) => "www.wixapis.com" | "readonly.wixapis.com";
5
+ export declare const getDefaultDomain: (_method: string, _url: string) => string;
6
6
  export declare function buildRESTDescriptor<T extends RESTFunctionDescriptor>(origFunc: T, publicMetadata: PublicMetadata, boundFetch: (url: string | URL, init?: RequestInit) => Promise<Response>, options?: RESTModuleOptions): BuildRESTFunction<T>;
@@ -1,9 +1,6 @@
1
1
  import { biHeaderGenerator } from './bi/biHeaderGenerator.js';
2
- import { API_URL, FORCE_WRITE_API_URLS, READ_ONLY_API_URL } from './common.js';
3
- export const getDefaultDomain = (method, url) => method === 'GET' &&
4
- !FORCE_WRITE_API_URLS.some((write_url) => url === write_url)
5
- ? READ_ONLY_API_URL
6
- : API_URL;
2
+ import { API_URL } from './common.js';
3
+ export const getDefaultDomain = (_method, _url) => API_URL;
7
4
  export function buildRESTDescriptor(origFunc, publicMetadata, boundFetch, options) {
8
5
  return origFunc({
9
6
  request: async (factory) => {
@@ -33,7 +33,9 @@ export type WixClient<H extends Host<any> | undefined = undefined, Z extends Aut
33
33
  fetch(relativeUrl: string, options: RequestInit): Promise<Response>;
34
34
  fetchWithAuth: typeof fetch;
35
35
  use<R extends Descriptors = EmptyObject>(modules: H extends Host<any> ? AssertHostMatches<R, H> : R): BuildDescriptors<R, H>;
36
- enableContext(contextType: ContextType): void;
36
+ enableContext(contextType: ContextType, opts?: {
37
+ elevated: boolean;
38
+ }): void;
37
39
  graphql<Result, Variables>(query: string | ((string | String) & TypedQueryInput<Result, Variables>), variables?: Variables): Promise<{
38
40
  data: Result;
39
41
  errors?: GraphQLFormattedError[];
@@ -46,6 +48,9 @@ export type WixClient<H extends Host<any> | undefined = undefined, Z extends Aut
46
48
  processRequest<ExpectedEvents extends EventDefinition<any>[] = []>(request: Request, opts?: {
47
49
  expectedEvents: ExpectedEvents;
48
50
  }): Promise<ProcessedEvent<ExpectedEvents>>;
51
+ parseJWT(jwt: string): Promise<ProcessedEvent>;
52
+ parseRequest(request: Request): Promise<ProcessedEvent>;
53
+ executeHandlers(event: ProcessedEvent): Promise<void>;
49
54
  apps: {
50
55
  AppInstalled: EventDefinition<{
51
56
  appId: string;
@@ -66,6 +71,9 @@ export type WixClient<H extends Host<any> | undefined = undefined, Z extends Aut
66
71
  body: string;
67
72
  }): Promise<unknown>;
68
73
  processRequest(request: Request): Promise<Response>;
74
+ parseJWT(jwt: string): Promise<unknown>;
75
+ parseRequest(request: Request): Promise<unknown>;
76
+ executeHandler(servicePluginRequest: ProcessedEvent): Promise<void>;
69
77
  };
70
78
  } & BuildDescriptors<T, H>;
71
79
  type ResolvePossibleEvents<T extends EventDefinition<any>[]> = {
@@ -95,17 +95,32 @@ export function createClient(config) {
95
95
  : undefined),
96
96
  setHeaders,
97
97
  use,
98
- enableContext(contextType) {
98
+ enableContext(contextType, opts = { elevated: false }) {
99
99
  if (contextType === 'global') {
100
100
  if (globalThis.__wix_context__ != null) {
101
- globalThis.__wix_context__.client = this;
101
+ if (opts.elevated) {
102
+ globalThis.__wix_context__.elevatedClient = this;
103
+ }
104
+ else {
105
+ globalThis.__wix_context__.client = this;
106
+ }
102
107
  }
103
108
  else {
104
- globalThis.__wix_context__ = { client: this };
109
+ if (opts.elevated) {
110
+ globalThis.__wix_context__ = { elevatedClient: this };
111
+ }
112
+ else {
113
+ globalThis.__wix_context__ = { client: this };
114
+ }
105
115
  }
106
116
  }
107
117
  else {
108
- wixContext.client = this;
118
+ if (opts.elevated) {
119
+ wixContext.elevatedClient = this;
120
+ }
121
+ else {
122
+ wixContext.client = this;
123
+ }
109
124
  }
110
125
  },
111
126
  fetch: (relativeUrl, options) => {
@@ -149,26 +164,10 @@ export function createClient(config) {
149
164
  },
150
165
  webhooks: {
151
166
  getRegisteredEvents: () => Array.from(eventHandlers.keys()),
152
- process: async (jwt, opts = {
167
+ async process(jwt, opts = {
153
168
  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);
169
+ }) {
170
+ const { eventType, identity, instanceId, payload } = await this.parseJWT(jwt);
172
171
  const allExpectedEvents = [
173
172
  ...opts.expectedEvents,
174
173
  ...Array.from(eventHandlers.keys()).map((type) => ({ type })),
@@ -195,6 +194,49 @@ export function createClient(config) {
195
194
  const body = await request.text();
196
195
  return this.process(body, opts);
197
196
  },
197
+ async parseJWT(jwt) {
198
+ if (!authStrategy.decodeJWT) {
199
+ throw new Error('decodeJWT is not supported by the authentication strategy');
200
+ }
201
+ const { decoded, valid } = await authStrategy.decodeJWT(jwt);
202
+ if (!valid) {
203
+ throw new Error('JWT is not valid');
204
+ }
205
+ if (typeof decoded.data !== 'string') {
206
+ throw new Error(`Unexpected type of JWT data: expected string, got ${typeof decoded.data}`);
207
+ }
208
+ const parsedDecoded = JSON.parse(decoded.data);
209
+ const eventType = parsedDecoded.eventType;
210
+ const instanceId = parsedDecoded.instanceId;
211
+ const identity = parsedDecoded.identity
212
+ ? JSON.parse(parsedDecoded.identity)
213
+ : undefined;
214
+ const payload = JSON.parse(parsedDecoded.data);
215
+ return {
216
+ instanceId,
217
+ eventType,
218
+ payload,
219
+ identity,
220
+ };
221
+ },
222
+ async parseRequest(request) {
223
+ const jwt = await request.text();
224
+ return this.parseJWT(jwt);
225
+ },
226
+ async executeHandlers(event) {
227
+ const allExpectedEvents = Array.from(eventHandlers.keys()).map((type) => ({ type }));
228
+ if (allExpectedEvents.length > 0 &&
229
+ !allExpectedEvents.some(({ type }) => type === event.eventType)) {
230
+ throw new Error(`Unexpected event type: ${event.eventType}. Expected one of: ${allExpectedEvents
231
+ .map((x) => x.type)
232
+ .join(', ')}`);
233
+ }
234
+ const handlers = eventHandlers.get(event.eventType) ?? [];
235
+ await Promise.all(handlers.map(({ eventDefinition, handler }) => runHandler(eventDefinition, handler, event.payload, {
236
+ instanceId: event.instanceId,
237
+ identity: event.identity,
238
+ })));
239
+ },
198
240
  apps: {
199
241
  AppInstalled: EventDefinition('AppInstalled')(),
200
242
  AppRemoved: EventDefinition('AppRemoved')(),
@@ -203,10 +245,20 @@ export function createClient(config) {
203
245
  servicePlugins: {
204
246
  getRegisteredServicePlugins: () => servicePluginsImplementations,
205
247
  async process(request) {
248
+ const servicePluginRequest = await this.parseJWT(request.body);
249
+ return this.executeHandler(servicePluginRequest, request.url);
250
+ },
251
+ async processRequest(request) {
252
+ const url = request.url;
253
+ const body = await request.text();
254
+ const implMethodResult = await this.process({ url, body });
255
+ return Response.json(implMethodResult);
256
+ },
257
+ async parseJWT(jwt) {
206
258
  if (!authStrategy.decodeJWT) {
207
259
  throw new Error('decodeJWT is not supported by the authentication strategy');
208
260
  }
209
- const { decoded, valid } = await authStrategy.decodeJWT(request.body, true);
261
+ const { decoded, valid } = await authStrategy.decodeJWT(jwt, true);
210
262
  if (!valid) {
211
263
  throw new Error('JWT is not valid');
212
264
  }
@@ -219,7 +271,10 @@ export function createClient(config) {
219
271
  typeof decoded.data.metadata.appExtensionType !== 'string') {
220
272
  throw new Error('Unexpected JWT data: expected object with metadata.appExtensionType string');
221
273
  }
222
- const componentType = decoded.data?.metadata.appExtensionType.toLowerCase();
274
+ return decoded.data;
275
+ },
276
+ async executeHandler(servicePluginRequest, url) {
277
+ const componentType = servicePluginRequest.metadata.appExtensionType.toLowerCase();
223
278
  const implementations = servicePluginsImplementations.get(componentType) ?? [];
224
279
  if (implementations.length === 0) {
225
280
  throw new Error(`No service plugin implementations found for component type ${componentType}`);
@@ -228,22 +283,15 @@ export function createClient(config) {
228
283
  throw new Error(`Multiple service plugin implementations found for component type ${componentType}. This is currently not supported`);
229
284
  }
230
285
  const { implementation: impl, servicePluginDefinition } = implementations[0];
231
- const method = servicePluginDefinition.methods.find((m) => request.url.endsWith(m.primaryHttpMappingPath));
286
+ const method = servicePluginDefinition.methods.find((m) => url.endsWith(m.primaryHttpMappingPath));
232
287
  if (!method) {
233
- throw new Error('Unexpect request: request url did not match any method: ' +
234
- request.url);
288
+ throw new Error('Unexpect request: request url did not match any method: ' + url);
235
289
  }
236
290
  const implMethod = impl[method.name];
237
291
  if (!implMethod) {
238
292
  throw new Error(`Got request for service plugin method ${method.name} but no implementation was provided. Available methods: ${Object.keys(impl).join(', ')}`);
239
293
  }
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);
294
+ return method.transformations.toREST(await implMethod(method.transformations.fromREST(servicePluginRequest)));
247
295
  },
248
296
  },
249
297
  };
@@ -18,6 +18,7 @@ export type AppStrategy = AuthenticationStrategy<undefined, (opts: {
18
18
  accessToken: string;
19
19
  refreshToken: string;
20
20
  }>;
21
+ elevated(): Promise<AppStrategy>;
21
22
  };
22
23
  /**
23
24
  * Creates an authentication strategy for Wix Apps OAuth installation process.
@@ -211,6 +211,38 @@ function AppStrategy(opts) {
211
211
  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
212
  }
213
213
  },
214
+ async elevated() {
215
+ if ('accessToken' in opts && opts.accessToken) {
216
+ const tokenInfoRes = await fetch('https://www.wixapis.com/oauth2/token-info', {
217
+ method: 'POST',
218
+ headers: {
219
+ 'Content-Type': 'application/json',
220
+ },
221
+ body: JSON.stringify({
222
+ token: opts.accessToken,
223
+ }),
224
+ });
225
+ if (tokenInfoRes.status !== 200) {
226
+ throw new Error(`Failed to get token info. Unexpected status code from Wix OAuth API: ${tokenInfoRes.status}`);
227
+ }
228
+ const tokenInfo = await tokenInfoRes.json();
229
+ if (tokenInfo.app_id !== opts.appId) {
230
+ throw new Error(`Invalid access token. The token is not issued for the app with ID "${opts.appId}"`);
231
+ }
232
+ if (!tokenInfo.instanceId) {
233
+ throw new Error('Unexpected token info. The token does not contain instance ID');
234
+ }
235
+ return AppStrategy({
236
+ appId: opts.appId,
237
+ appSecret: opts.appSecret,
238
+ publicKey: opts.publicKey,
239
+ instanceId: tokenInfo.instanceId,
240
+ });
241
+ }
242
+ else {
243
+ throw new Error('Providing an access token is required to perform elevation. Make sure to pass it to the AppStrategy');
244
+ }
245
+ },
214
246
  async decodeJWT(token, verifyCallerClaims = false) {
215
247
  if (!opts.publicKey) {
216
248
  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 {
@@ -2,5 +2,5 @@ import { BuildRESTFunction, PublicMetadata, RESTFunctionDescriptor } from '@wix/
2
2
  export type RESTModuleOptions = {
3
3
  HTTPHost?: string;
4
4
  };
5
- export declare const getDefaultDomain: (method: string, url: string) => "www.wixapis.com" | "readonly.wixapis.com";
5
+ export declare const getDefaultDomain: (_method: string, _url: string) => string;
6
6
  export declare function buildRESTDescriptor<T extends RESTFunctionDescriptor>(origFunc: T, publicMetadata: PublicMetadata, boundFetch: (url: string | URL, init?: RequestInit) => Promise<Response>, options?: RESTModuleOptions): BuildRESTFunction<T>;
@@ -3,10 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.buildRESTDescriptor = exports.getDefaultDomain = void 0;
4
4
  const biHeaderGenerator_js_1 = require("./bi/biHeaderGenerator.js");
5
5
  const common_js_1 = require("./common.js");
6
- const getDefaultDomain = (method, url) => method === 'GET' &&
7
- !common_js_1.FORCE_WRITE_API_URLS.some((write_url) => url === write_url)
8
- ? common_js_1.READ_ONLY_API_URL
9
- : common_js_1.API_URL;
6
+ const getDefaultDomain = (_method, _url) => common_js_1.API_URL;
10
7
  exports.getDefaultDomain = getDefaultDomain;
11
8
  function buildRESTDescriptor(origFunc, publicMetadata, boundFetch, options) {
12
9
  return origFunc({
@@ -33,7 +33,9 @@ export type WixClient<H extends Host<any> | undefined = undefined, Z extends Aut
33
33
  fetch(relativeUrl: string, options: RequestInit): Promise<Response>;
34
34
  fetchWithAuth: typeof fetch;
35
35
  use<R extends Descriptors = EmptyObject>(modules: H extends Host<any> ? AssertHostMatches<R, H> : R): BuildDescriptors<R, H>;
36
- enableContext(contextType: ContextType): void;
36
+ enableContext(contextType: ContextType, opts?: {
37
+ elevated: boolean;
38
+ }): void;
37
39
  graphql<Result, Variables>(query: string | ((string | String) & TypedQueryInput<Result, Variables>), variables?: Variables): Promise<{
38
40
  data: Result;
39
41
  errors?: GraphQLFormattedError[];
@@ -46,6 +48,9 @@ export type WixClient<H extends Host<any> | undefined = undefined, Z extends Aut
46
48
  processRequest<ExpectedEvents extends EventDefinition<any>[] = []>(request: Request, opts?: {
47
49
  expectedEvents: ExpectedEvents;
48
50
  }): Promise<ProcessedEvent<ExpectedEvents>>;
51
+ parseJWT(jwt: string): Promise<ProcessedEvent>;
52
+ parseRequest(request: Request): Promise<ProcessedEvent>;
53
+ executeHandlers(event: ProcessedEvent): Promise<void>;
49
54
  apps: {
50
55
  AppInstalled: EventDefinition<{
51
56
  appId: string;
@@ -66,6 +71,9 @@ export type WixClient<H extends Host<any> | undefined = undefined, Z extends Aut
66
71
  body: string;
67
72
  }): Promise<unknown>;
68
73
  processRequest(request: Request): Promise<Response>;
74
+ parseJWT(jwt: string): Promise<unknown>;
75
+ parseRequest(request: Request): Promise<unknown>;
76
+ executeHandler(servicePluginRequest: ProcessedEvent): Promise<void>;
69
77
  };
70
78
  } & BuildDescriptors<T, H>;
71
79
  type ResolvePossibleEvents<T extends EventDefinition<any>[]> = {
@@ -98,17 +98,32 @@ function createClient(config) {
98
98
  : undefined),
99
99
  setHeaders,
100
100
  use,
101
- enableContext(contextType) {
101
+ enableContext(contextType, opts = { elevated: false }) {
102
102
  if (contextType === 'global') {
103
103
  if (globalThis.__wix_context__ != null) {
104
- globalThis.__wix_context__.client = this;
104
+ if (opts.elevated) {
105
+ globalThis.__wix_context__.elevatedClient = this;
106
+ }
107
+ else {
108
+ globalThis.__wix_context__.client = this;
109
+ }
105
110
  }
106
111
  else {
107
- globalThis.__wix_context__ = { client: this };
112
+ if (opts.elevated) {
113
+ globalThis.__wix_context__ = { elevatedClient: this };
114
+ }
115
+ else {
116
+ globalThis.__wix_context__ = { client: this };
117
+ }
108
118
  }
109
119
  }
110
120
  else {
111
- sdk_context_1.wixContext.client = this;
121
+ if (opts.elevated) {
122
+ sdk_context_1.wixContext.elevatedClient = this;
123
+ }
124
+ else {
125
+ sdk_context_1.wixContext.client = this;
126
+ }
112
127
  }
113
128
  },
114
129
  fetch: (relativeUrl, options) => {
@@ -152,26 +167,10 @@ function createClient(config) {
152
167
  },
153
168
  webhooks: {
154
169
  getRegisteredEvents: () => Array.from(eventHandlers.keys()),
155
- process: async (jwt, opts = {
170
+ async process(jwt, opts = {
156
171
  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);
172
+ }) {
173
+ const { eventType, identity, instanceId, payload } = await this.parseJWT(jwt);
175
174
  const allExpectedEvents = [
176
175
  ...opts.expectedEvents,
177
176
  ...Array.from(eventHandlers.keys()).map((type) => ({ type })),
@@ -198,6 +197,49 @@ function createClient(config) {
198
197
  const body = await request.text();
199
198
  return this.process(body, opts);
200
199
  },
200
+ async parseJWT(jwt) {
201
+ if (!authStrategy.decodeJWT) {
202
+ throw new Error('decodeJWT is not supported by the authentication strategy');
203
+ }
204
+ const { decoded, valid } = await authStrategy.decodeJWT(jwt);
205
+ if (!valid) {
206
+ throw new Error('JWT is not valid');
207
+ }
208
+ if (typeof decoded.data !== 'string') {
209
+ throw new Error(`Unexpected type of JWT data: expected string, got ${typeof decoded.data}`);
210
+ }
211
+ const parsedDecoded = JSON.parse(decoded.data);
212
+ const eventType = parsedDecoded.eventType;
213
+ const instanceId = parsedDecoded.instanceId;
214
+ const identity = parsedDecoded.identity
215
+ ? JSON.parse(parsedDecoded.identity)
216
+ : undefined;
217
+ const payload = JSON.parse(parsedDecoded.data);
218
+ return {
219
+ instanceId,
220
+ eventType,
221
+ payload,
222
+ identity,
223
+ };
224
+ },
225
+ async parseRequest(request) {
226
+ const jwt = await request.text();
227
+ return this.parseJWT(jwt);
228
+ },
229
+ async executeHandlers(event) {
230
+ const allExpectedEvents = Array.from(eventHandlers.keys()).map((type) => ({ type }));
231
+ if (allExpectedEvents.length > 0 &&
232
+ !allExpectedEvents.some(({ type }) => type === event.eventType)) {
233
+ throw new Error(`Unexpected event type: ${event.eventType}. Expected one of: ${allExpectedEvents
234
+ .map((x) => x.type)
235
+ .join(', ')}`);
236
+ }
237
+ const handlers = eventHandlers.get(event.eventType) ?? [];
238
+ await Promise.all(handlers.map(({ eventDefinition, handler }) => (0, event_handlers_modules_js_1.runHandler)(eventDefinition, handler, event.payload, {
239
+ instanceId: event.instanceId,
240
+ identity: event.identity,
241
+ })));
242
+ },
201
243
  apps: {
202
244
  AppInstalled: (0, sdk_types_1.EventDefinition)('AppInstalled')(),
203
245
  AppRemoved: (0, sdk_types_1.EventDefinition)('AppRemoved')(),
@@ -206,10 +248,20 @@ function createClient(config) {
206
248
  servicePlugins: {
207
249
  getRegisteredServicePlugins: () => servicePluginsImplementations,
208
250
  async process(request) {
251
+ const servicePluginRequest = await this.parseJWT(request.body);
252
+ return this.executeHandler(servicePluginRequest, request.url);
253
+ },
254
+ async processRequest(request) {
255
+ const url = request.url;
256
+ const body = await request.text();
257
+ const implMethodResult = await this.process({ url, body });
258
+ return Response.json(implMethodResult);
259
+ },
260
+ async parseJWT(jwt) {
209
261
  if (!authStrategy.decodeJWT) {
210
262
  throw new Error('decodeJWT is not supported by the authentication strategy');
211
263
  }
212
- const { decoded, valid } = await authStrategy.decodeJWT(request.body, true);
264
+ const { decoded, valid } = await authStrategy.decodeJWT(jwt, true);
213
265
  if (!valid) {
214
266
  throw new Error('JWT is not valid');
215
267
  }
@@ -222,7 +274,10 @@ function createClient(config) {
222
274
  typeof decoded.data.metadata.appExtensionType !== 'string') {
223
275
  throw new Error('Unexpected JWT data: expected object with metadata.appExtensionType string');
224
276
  }
225
- const componentType = decoded.data?.metadata.appExtensionType.toLowerCase();
277
+ return decoded.data;
278
+ },
279
+ async executeHandler(servicePluginRequest, url) {
280
+ const componentType = servicePluginRequest.metadata.appExtensionType.toLowerCase();
226
281
  const implementations = servicePluginsImplementations.get(componentType) ?? [];
227
282
  if (implementations.length === 0) {
228
283
  throw new Error(`No service plugin implementations found for component type ${componentType}`);
@@ -231,22 +286,15 @@ function createClient(config) {
231
286
  throw new Error(`Multiple service plugin implementations found for component type ${componentType}. This is currently not supported`);
232
287
  }
233
288
  const { implementation: impl, servicePluginDefinition } = implementations[0];
234
- const method = servicePluginDefinition.methods.find((m) => request.url.endsWith(m.primaryHttpMappingPath));
289
+ const method = servicePluginDefinition.methods.find((m) => url.endsWith(m.primaryHttpMappingPath));
235
290
  if (!method) {
236
- throw new Error('Unexpect request: request url did not match any method: ' +
237
- request.url);
291
+ throw new Error('Unexpect request: request url did not match any method: ' + url);
238
292
  }
239
293
  const implMethod = impl[method.name];
240
294
  if (!implMethod) {
241
295
  throw new Error(`Got request for service plugin method ${method.name} but no implementation was provided. Available methods: ${Object.keys(impl).join(', ')}`);
242
296
  }
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);
297
+ return method.transformations.toREST(await implMethod(method.transformations.fromREST(servicePluginRequest)));
250
298
  },
251
299
  },
252
300
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/sdk",
3
- "version": "1.11.0",
3
+ "version": "1.12.0",
4
4
  "license": "UNLICENSED",
5
5
  "author": {
6
6
  "name": "Ronny Ringel",
@@ -65,10 +65,10 @@
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",
71
+ "@wix/sdk-runtime": "0.3.2",
72
72
  "@wix/sdk-types": "^1.9.0",
73
73
  "crypto-js": "^4.2.0",
74
74
  "jose": "^5.2.1",
@@ -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.2",
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": "57511fd343222c563e2451556e20ff0de7c4a0a79996b4d145f363cd"
125
+ "falconPackageHash": "d1f932da0dd434abd01b86780407acb15e03bd9750a3c70519f12aec"
126
126
  }