@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.
- package/build/auth/AppStrategy.d.ts +2 -7
- package/build/auth/AppStrategy.js +32 -33
- package/build/auth/oauth2/types.d.ts +12 -0
- package/build/wixClient.d.ts +10 -3
- package/build/wixClient.js +83 -41
- package/cjs/build/auth/AppStrategy.d.ts +2 -7
- package/cjs/build/auth/AppStrategy.js +32 -33
- package/cjs/build/auth/oauth2/types.d.ts +12 -0
- package/cjs/build/wixClient.d.ts +10 -3
- package/cjs/build/wixClient.js +83 -41
- package/package.json +6 -6
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
import { AuthenticationStrategy } from '@wix/sdk-types';
|
|
2
|
-
export type AppStrategy = AuthenticationStrategy<undefined
|
|
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 {
|
package/build/wixClient.d.ts
CHANGED
|
@@ -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
|
|
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
|
|
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;
|
package/build/wixClient.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
161
|
+
async process(jwt, opts = {
|
|
153
162
|
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);
|
|
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(
|
|
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
|
-
|
|
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) =>
|
|
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(
|
|
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
|
|
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 {
|
package/cjs/build/wixClient.d.ts
CHANGED
|
@@ -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
|
|
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
|
|
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;
|
package/cjs/build/wixClient.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
164
|
+
async process(jwt, opts = {
|
|
156
165
|
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);
|
|
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(
|
|
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
|
-
|
|
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) =>
|
|
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(
|
|
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.
|
|
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.
|
|
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.
|
|
72
|
-
"@wix/sdk-types": "^1.9.
|
|
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.
|
|
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": "
|
|
125
|
+
"falconPackageHash": "177ec0d44fe0da191345f8a3682db306bf5ed81105ff12431590e217"
|
|
126
126
|
}
|