@wix/sdk 1.11.1 → 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.
- package/build/auth/AppStrategy.d.ts +1 -0
- package/build/auth/AppStrategy.js +32 -0
- package/build/auth/oauth2/types.d.ts +12 -0
- package/build/wixClient.d.ts +9 -1
- package/build/wixClient.js +83 -35
- package/cjs/build/auth/AppStrategy.d.ts +1 -0
- package/cjs/build/auth/AppStrategy.js +32 -0
- package/cjs/build/auth/oauth2/types.d.ts +12 -0
- package/cjs/build/wixClient.d.ts +9 -1
- package/cjs/build/wixClient.js +83 -35
- package/package.json +5 -5
|
@@ -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 {
|
package/build/wixClient.d.ts
CHANGED
|
@@ -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
|
|
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>[]> = {
|
package/build/wixClient.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
167
|
+
async process(jwt, opts = {
|
|
153
168
|
expectedEvents: [],
|
|
154
|
-
})
|
|
155
|
-
|
|
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(
|
|
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
|
-
|
|
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) =>
|
|
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(
|
|
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
|
};
|
|
@@ -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 {
|
package/cjs/build/wixClient.d.ts
CHANGED
|
@@ -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
|
|
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>[]> = {
|
package/cjs/build/wixClient.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
170
|
+
async process(jwt, opts = {
|
|
156
171
|
expectedEvents: [],
|
|
157
|
-
})
|
|
158
|
-
|
|
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(
|
|
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
|
-
|
|
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) =>
|
|
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(
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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": "
|
|
125
|
+
"falconPackageHash": "d1f932da0dd434abd01b86780407acb15e03bd9750a3c70519f12aec"
|
|
126
126
|
}
|