@wix/sdk 1.12.8 → 1.12.9
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/event-handlers-modules.d.ts +46 -2
- package/build/event-handlers-modules.js +99 -1
- package/build/service-plugin-modules.d.ts +32 -7
- package/build/service-plugin-modules.js +71 -3
- package/build/wixClient.d.ts +5 -49
- package/build/wixClient.js +9 -147
- package/cjs/build/event-handlers-modules.d.ts +46 -2
- package/cjs/build/event-handlers-modules.js +100 -2
- package/cjs/build/service-plugin-modules.d.ts +32 -7
- package/cjs/build/service-plugin-modules.js +73 -5
- package/cjs/build/wixClient.d.ts +5 -49
- package/cjs/build/wixClient.js +6 -144
- package/package.json +6 -5
|
@@ -1,4 +1,48 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AuthenticationStrategy, EventDefinition, EventHandler, EventIdentity } from '@wix/sdk-types';
|
|
2
|
+
import { Emitter } from 'nanoevents';
|
|
2
3
|
export declare const isEventHandlerModule: (val: any) => val is EventDefinition<unknown, string>;
|
|
3
4
|
export declare function buildEventDefinition<T extends EventDefinition<any, string>>(eventDefinition: T, registerHandler: (eventDefinition: T, handler: EventHandler<T>) => void): (handler: EventHandler<T>) => void;
|
|
4
|
-
|
|
5
|
+
type ResolvePossibleEvents<T extends EventDefinition<any>[]> = {
|
|
6
|
+
[K in keyof T]: T[K] extends EventDefinition<any> ? {
|
|
7
|
+
eventType: T[K]['type'];
|
|
8
|
+
payload: T[K]['__payload'];
|
|
9
|
+
} : never;
|
|
10
|
+
} extends (infer U)[] ? U : never;
|
|
11
|
+
export type ProcessedEvent<T extends EventDefinition<any>[] = []> = {
|
|
12
|
+
instanceId: string;
|
|
13
|
+
identity?: EventIdentity;
|
|
14
|
+
} & (T['length'] extends 0 ? {
|
|
15
|
+
eventType: string;
|
|
16
|
+
payload: unknown;
|
|
17
|
+
} : ResolvePossibleEvents<T>);
|
|
18
|
+
export type EventHandlersClient = Emitter<{
|
|
19
|
+
registered: (event: EventDefinition<any>) => void;
|
|
20
|
+
}> & {
|
|
21
|
+
getRegisteredEvents(): Map<string, {
|
|
22
|
+
eventDefinition: EventDefinition;
|
|
23
|
+
handler: EventHandler<EventDefinition>;
|
|
24
|
+
}[]>;
|
|
25
|
+
process<ExpectedEvents extends EventDefinition<any>[] = []>(jwt: string, opts?: {
|
|
26
|
+
expectedEvents: ExpectedEvents;
|
|
27
|
+
}): Promise<ProcessedEvent<ExpectedEvents>>;
|
|
28
|
+
processRequest<ExpectedEvents extends EventDefinition<any>[] = []>(request: Request, opts?: {
|
|
29
|
+
expectedEvents: ExpectedEvents;
|
|
30
|
+
}): Promise<ProcessedEvent<ExpectedEvents>>;
|
|
31
|
+
parseJWT(jwt: string): Promise<ProcessedEvent>;
|
|
32
|
+
parseRequest(request: Request): Promise<ProcessedEvent>;
|
|
33
|
+
executeHandlers(event: ProcessedEvent): Promise<void>;
|
|
34
|
+
apps: {
|
|
35
|
+
AppInstalled: EventDefinition<{
|
|
36
|
+
appId: string;
|
|
37
|
+
originInstanceId: string;
|
|
38
|
+
}, 'AppInstalled'>;
|
|
39
|
+
AppRemoved: EventDefinition<{
|
|
40
|
+
appId: string;
|
|
41
|
+
}, 'AppRemoved'>;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
export declare function eventHandlersModules(authStrategy: AuthenticationStrategy<any>): {
|
|
45
|
+
initModule(eventDefinition: EventDefinition<any, string>): (handler: EventHandler<EventDefinition<any, string>>) => void;
|
|
46
|
+
client: EventHandlersClient;
|
|
47
|
+
};
|
|
48
|
+
export {};
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { EventDefinition, } from '@wix/sdk-types';
|
|
2
|
+
import { createNanoEvents } from 'nanoevents';
|
|
1
3
|
export const isEventHandlerModule = (val) => val.__type === 'event-definition';
|
|
2
4
|
export function buildEventDefinition(eventDefinition, registerHandler) {
|
|
3
5
|
return (handler) => {
|
|
4
6
|
registerHandler(eventDefinition, handler);
|
|
5
7
|
};
|
|
6
8
|
}
|
|
7
|
-
|
|
9
|
+
function runHandler(eventDefinition, handler, payload, baseEventMetadata) {
|
|
8
10
|
let envelope;
|
|
9
11
|
if (eventDefinition.isDomainEvent) {
|
|
10
12
|
const domainEventPayload = payload;
|
|
@@ -46,3 +48,99 @@ export function runHandler(eventDefinition, handler, payload, baseEventMetadata)
|
|
|
46
48
|
const transformFromRESTFn = eventDefinition.transformations ?? ((x) => x);
|
|
47
49
|
return handler(transformFromRESTFn(envelope));
|
|
48
50
|
}
|
|
51
|
+
export function eventHandlersModules(authStrategy) {
|
|
52
|
+
const eventHandlers = new Map();
|
|
53
|
+
const webhooksEmitter = createNanoEvents();
|
|
54
|
+
const client = {
|
|
55
|
+
...webhooksEmitter,
|
|
56
|
+
getRegisteredEvents: () => eventHandlers,
|
|
57
|
+
async process(jwt, opts = {
|
|
58
|
+
expectedEvents: [],
|
|
59
|
+
}) {
|
|
60
|
+
const { eventType, identity, instanceId, payload } = await this.parseJWT(jwt);
|
|
61
|
+
const allExpectedEvents = [
|
|
62
|
+
...opts.expectedEvents,
|
|
63
|
+
...Array.from(eventHandlers.keys()).map((type) => ({ type })),
|
|
64
|
+
];
|
|
65
|
+
if (allExpectedEvents.length > 0 &&
|
|
66
|
+
!allExpectedEvents.some(({ type }) => type === eventType)) {
|
|
67
|
+
throw new Error(`Unexpected event type: ${eventType}. Expected one of: ${allExpectedEvents
|
|
68
|
+
.map((x) => x.type)
|
|
69
|
+
.join(', ')}`);
|
|
70
|
+
}
|
|
71
|
+
const handlers = eventHandlers.get(eventType) ?? [];
|
|
72
|
+
await Promise.all(handlers.map(({ eventDefinition, handler }) => runHandler(eventDefinition, handler, payload, {
|
|
73
|
+
instanceId,
|
|
74
|
+
identity,
|
|
75
|
+
})));
|
|
76
|
+
return {
|
|
77
|
+
instanceId,
|
|
78
|
+
eventType,
|
|
79
|
+
payload,
|
|
80
|
+
identity,
|
|
81
|
+
};
|
|
82
|
+
},
|
|
83
|
+
async processRequest(request, opts) {
|
|
84
|
+
const body = await request.text();
|
|
85
|
+
return this.process(body, opts);
|
|
86
|
+
},
|
|
87
|
+
async parseJWT(jwt) {
|
|
88
|
+
if (!authStrategy.decodeJWT) {
|
|
89
|
+
throw new Error('decodeJWT is not supported by the authentication strategy');
|
|
90
|
+
}
|
|
91
|
+
const { decoded, valid } = await authStrategy.decodeJWT(jwt);
|
|
92
|
+
if (!valid) {
|
|
93
|
+
throw new Error('JWT is not valid');
|
|
94
|
+
}
|
|
95
|
+
if (typeof decoded.data !== 'string') {
|
|
96
|
+
throw new Error(`Unexpected type of JWT data: expected string, got ${typeof decoded.data}`);
|
|
97
|
+
}
|
|
98
|
+
const parsedDecoded = JSON.parse(decoded.data);
|
|
99
|
+
const eventType = parsedDecoded.eventType;
|
|
100
|
+
const instanceId = parsedDecoded.instanceId;
|
|
101
|
+
const identity = parsedDecoded.identity
|
|
102
|
+
? JSON.parse(parsedDecoded.identity)
|
|
103
|
+
: undefined;
|
|
104
|
+
const payload = JSON.parse(parsedDecoded.data);
|
|
105
|
+
return {
|
|
106
|
+
instanceId,
|
|
107
|
+
eventType,
|
|
108
|
+
payload,
|
|
109
|
+
identity,
|
|
110
|
+
};
|
|
111
|
+
},
|
|
112
|
+
async parseRequest(request) {
|
|
113
|
+
const jwt = await request.text();
|
|
114
|
+
return this.parseJWT(jwt);
|
|
115
|
+
},
|
|
116
|
+
async executeHandlers(event) {
|
|
117
|
+
const allExpectedEvents = Array.from(eventHandlers.keys()).map((type) => ({ type }));
|
|
118
|
+
if (allExpectedEvents.length > 0 &&
|
|
119
|
+
!allExpectedEvents.some(({ type }) => type === event.eventType)) {
|
|
120
|
+
throw new Error(`Unexpected event type: ${event.eventType}. Expected one of: ${allExpectedEvents
|
|
121
|
+
.map((x) => x.type)
|
|
122
|
+
.join(', ')}`);
|
|
123
|
+
}
|
|
124
|
+
const handlers = eventHandlers.get(event.eventType) ?? [];
|
|
125
|
+
await Promise.all(handlers.map(({ eventDefinition, handler }) => runHandler(eventDefinition, handler, event.payload, {
|
|
126
|
+
instanceId: event.instanceId,
|
|
127
|
+
identity: event.identity,
|
|
128
|
+
})));
|
|
129
|
+
},
|
|
130
|
+
apps: {
|
|
131
|
+
AppInstalled: EventDefinition('AppInstalled')(),
|
|
132
|
+
AppRemoved: EventDefinition('AppRemoved')(),
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
return {
|
|
136
|
+
initModule(eventDefinition) {
|
|
137
|
+
return (handler) => {
|
|
138
|
+
const handlers = eventHandlers.get(eventDefinition.type) ?? [];
|
|
139
|
+
handlers.push({ eventDefinition, handler });
|
|
140
|
+
eventHandlers.set(eventDefinition.type, handlers);
|
|
141
|
+
webhooksEmitter.emit('registered', eventDefinition);
|
|
142
|
+
};
|
|
143
|
+
},
|
|
144
|
+
client,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
@@ -1,8 +1,33 @@
|
|
|
1
|
-
import { ServicePluginContract, ServicePluginDefinition } from '@wix/sdk-types';
|
|
1
|
+
import { AuthenticationStrategy, ServicePluginContract, ServicePluginDefinition } from '@wix/sdk-types';
|
|
2
|
+
import { Emitter } from 'nanoevents';
|
|
2
3
|
export declare const isServicePluginModule: (val: any) => val is ServicePluginDefinition<ServicePluginContract>;
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
export type UnknownServicePluginResponse = unknown;
|
|
5
|
+
type ServicePluginRequestMetadata = {
|
|
6
|
+
instanceId: string;
|
|
7
|
+
appExtensionType: string;
|
|
8
|
+
};
|
|
9
|
+
type ServicePluginRequest = {
|
|
10
|
+
metadata: ServicePluginRequestMetadata;
|
|
11
|
+
request: unknown;
|
|
12
|
+
};
|
|
13
|
+
export type ServicePluginsClient = Emitter<{
|
|
14
|
+
registered: (servicePluginDefinition: ServicePluginDefinition<ServicePluginContract>) => void;
|
|
15
|
+
}> & {
|
|
16
|
+
getRegisteredServicePlugins(): Map<string, {
|
|
17
|
+
servicePluginDefinition: ServicePluginDefinition<any>;
|
|
18
|
+
implementation: ServicePluginContract;
|
|
19
|
+
}[]>;
|
|
20
|
+
process(request: {
|
|
21
|
+
url: string;
|
|
22
|
+
body: string;
|
|
23
|
+
}): Promise<unknown>;
|
|
24
|
+
processRequest(request: Request): Promise<Response>;
|
|
25
|
+
parseJWT(jwt: string): Promise<ServicePluginRequest>;
|
|
26
|
+
parseRequest(request: Request): Promise<ServicePluginRequest>;
|
|
27
|
+
executeHandler(servicePluginRequest: ServicePluginRequest, url: string): Promise<UnknownServicePluginResponse>;
|
|
28
|
+
};
|
|
29
|
+
export declare function servicePluginsModules(authStrategy: AuthenticationStrategy<any>): {
|
|
30
|
+
initModule<T extends ServicePluginDefinition<any>>(servicePluginDefinition: T): (implementation: T["__contract"]) => void;
|
|
31
|
+
client: ServicePluginsClient;
|
|
32
|
+
};
|
|
33
|
+
export {};
|
|
@@ -1,6 +1,74 @@
|
|
|
1
|
+
import { createNanoEvents } from 'nanoevents';
|
|
1
2
|
export const isServicePluginModule = (val) => val.__type === 'service-plugin-definition';
|
|
2
|
-
export function
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
export function servicePluginsModules(authStrategy) {
|
|
4
|
+
const servicePluginsImplementations = new Map();
|
|
5
|
+
const servicePluginsEmitter = createNanoEvents();
|
|
6
|
+
const client = {
|
|
7
|
+
...servicePluginsEmitter,
|
|
8
|
+
getRegisteredServicePlugins: () => servicePluginsImplementations,
|
|
9
|
+
async parseJWT(jwt) {
|
|
10
|
+
if (!authStrategy.decodeJWT) {
|
|
11
|
+
throw new Error('decodeJWT is not supported by the authentication strategy');
|
|
12
|
+
}
|
|
13
|
+
const { decoded, valid } = await authStrategy.decodeJWT(jwt, true);
|
|
14
|
+
if (!valid) {
|
|
15
|
+
throw new Error('JWT is not valid');
|
|
16
|
+
}
|
|
17
|
+
if (typeof decoded.data !== 'object' ||
|
|
18
|
+
decoded.data === null ||
|
|
19
|
+
!('metadata' in decoded.data) ||
|
|
20
|
+
typeof decoded.data.metadata !== 'object' ||
|
|
21
|
+
decoded.data.metadata === null ||
|
|
22
|
+
!('appExtensionType' in decoded.data.metadata) ||
|
|
23
|
+
typeof decoded.data.metadata.appExtensionType !== 'string') {
|
|
24
|
+
throw new Error('Unexpected JWT data: expected object with metadata.appExtensionType string');
|
|
25
|
+
}
|
|
26
|
+
return decoded.data;
|
|
27
|
+
},
|
|
28
|
+
async process(request) {
|
|
29
|
+
const servicePluginRequest = await this.parseJWT(request.body);
|
|
30
|
+
return this.executeHandler(servicePluginRequest, request.url);
|
|
31
|
+
},
|
|
32
|
+
async parseRequest(request) {
|
|
33
|
+
const body = await request.text();
|
|
34
|
+
return this.parseJWT(body);
|
|
35
|
+
},
|
|
36
|
+
async processRequest(request) {
|
|
37
|
+
const url = request.url;
|
|
38
|
+
const body = await request.text();
|
|
39
|
+
const implMethodResult = await this.process({ url, body });
|
|
40
|
+
return Response.json(implMethodResult);
|
|
41
|
+
},
|
|
42
|
+
async executeHandler(servicePluginRequest, url) {
|
|
43
|
+
const componentType = servicePluginRequest.metadata.appExtensionType.toLowerCase();
|
|
44
|
+
const implementations = servicePluginsImplementations.get(componentType) ?? [];
|
|
45
|
+
if (implementations.length === 0) {
|
|
46
|
+
throw new Error(`No service plugin implementations found for component type ${componentType}`);
|
|
47
|
+
}
|
|
48
|
+
else if (implementations.length > 1) {
|
|
49
|
+
throw new Error(`Multiple service plugin implementations found for component type ${componentType}. This is currently not supported`);
|
|
50
|
+
}
|
|
51
|
+
const { implementation: impl, servicePluginDefinition } = implementations[0];
|
|
52
|
+
const method = servicePluginDefinition.methods.find((m) => url.endsWith(m.primaryHttpMappingPath));
|
|
53
|
+
if (!method) {
|
|
54
|
+
throw new Error('Unexpect request: request url did not match any method: ' + url);
|
|
55
|
+
}
|
|
56
|
+
const implMethod = impl[method.name];
|
|
57
|
+
if (!implMethod) {
|
|
58
|
+
throw new Error(`Got request for service plugin method ${method.name} but no implementation was provided. Available methods: ${Object.keys(impl).join(', ')}`);
|
|
59
|
+
}
|
|
60
|
+
return method.transformations.toREST(await implMethod(method.transformations.fromREST(servicePluginRequest)));
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
return {
|
|
64
|
+
initModule(servicePluginDefinition) {
|
|
65
|
+
return (implementation) => {
|
|
66
|
+
const implementations = servicePluginsImplementations.get(servicePluginDefinition.componentType.toLowerCase()) ?? [];
|
|
67
|
+
implementations.push({ servicePluginDefinition, implementation });
|
|
68
|
+
servicePluginsImplementations.set(servicePluginDefinition.componentType.toLowerCase(), implementations);
|
|
69
|
+
servicePluginsEmitter.emit('registered', servicePluginDefinition);
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
client,
|
|
5
73
|
};
|
|
6
74
|
}
|
package/build/wixClient.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { AuthenticationStrategy, BoundAuthenticationStrategy, BuildDescriptors, Descriptors,
|
|
1
|
+
import { AuthenticationStrategy, BoundAuthenticationStrategy, BuildDescriptors, Descriptors, Host, HostModule, RESTFunctionDescriptor } from '@wix/sdk-types';
|
|
2
2
|
import { EmptyObject } from 'type-fest/source/empty-object.js';
|
|
3
3
|
import type { GraphQLFormattedError } from 'graphql';
|
|
4
|
+
import { EventHandlersClient } from './event-handlers-modules.js';
|
|
5
|
+
import { ServicePluginsClient } from './service-plugin-modules.js';
|
|
4
6
|
export type ContextType = 'global' | 'module';
|
|
5
7
|
type Headers = Record<string, string>;
|
|
6
8
|
/**
|
|
@@ -42,55 +44,9 @@ export type WixClient<H extends Host<any> | undefined = undefined, Z extends Aut
|
|
|
42
44
|
data: Result;
|
|
43
45
|
errors?: GraphQLFormattedError[];
|
|
44
46
|
}>;
|
|
45
|
-
webhooks:
|
|
46
|
-
|
|
47
|
-
process<ExpectedEvents extends EventDefinition<any>[] = []>(jwt: string, opts?: {
|
|
48
|
-
expectedEvents: ExpectedEvents;
|
|
49
|
-
}): Promise<ProcessedEvent<ExpectedEvents>>;
|
|
50
|
-
processRequest<ExpectedEvents extends EventDefinition<any>[] = []>(request: Request, opts?: {
|
|
51
|
-
expectedEvents: ExpectedEvents;
|
|
52
|
-
}): Promise<ProcessedEvent<ExpectedEvents>>;
|
|
53
|
-
parseJWT(jwt: string): Promise<ProcessedEvent>;
|
|
54
|
-
parseRequest(request: Request): Promise<ProcessedEvent>;
|
|
55
|
-
executeHandlers(event: ProcessedEvent): Promise<void>;
|
|
56
|
-
apps: {
|
|
57
|
-
AppInstalled: EventDefinition<{
|
|
58
|
-
appId: string;
|
|
59
|
-
originInstanceId: string;
|
|
60
|
-
}, 'AppInstalled'>;
|
|
61
|
-
AppRemoved: EventDefinition<{
|
|
62
|
-
appId: string;
|
|
63
|
-
}, 'AppRemoved'>;
|
|
64
|
-
};
|
|
65
|
-
};
|
|
66
|
-
servicePlugins: {
|
|
67
|
-
getRegisteredServicePlugins(): Map<string, {
|
|
68
|
-
servicePluginDefinition: ServicePluginDefinition<any>;
|
|
69
|
-
implementation: ServicePluginContract;
|
|
70
|
-
}[]>;
|
|
71
|
-
process(request: {
|
|
72
|
-
url: string;
|
|
73
|
-
body: string;
|
|
74
|
-
}): Promise<unknown>;
|
|
75
|
-
processRequest(request: Request): Promise<Response>;
|
|
76
|
-
parseJWT(jwt: string): Promise<unknown>;
|
|
77
|
-
parseRequest(request: Request): Promise<unknown>;
|
|
78
|
-
executeHandler(servicePluginRequest: ProcessedEvent): Promise<void>;
|
|
79
|
-
};
|
|
47
|
+
webhooks: EventHandlersClient;
|
|
48
|
+
servicePlugins: ServicePluginsClient;
|
|
80
49
|
} & BuildDescriptors<T, H>;
|
|
81
|
-
type ResolvePossibleEvents<T extends EventDefinition<any>[]> = {
|
|
82
|
-
[K in keyof T]: T[K] extends EventDefinition<any> ? {
|
|
83
|
-
eventType: T[K]['type'];
|
|
84
|
-
payload: T[K]['__payload'];
|
|
85
|
-
} : never;
|
|
86
|
-
} extends (infer U)[] ? U : never;
|
|
87
|
-
export type ProcessedEvent<T extends EventDefinition<any>[] = []> = {
|
|
88
|
-
instanceId: string;
|
|
89
|
-
identity?: EventIdentity;
|
|
90
|
-
} & (T['length'] extends 0 ? {
|
|
91
|
-
eventType: string;
|
|
92
|
-
payload: unknown;
|
|
93
|
-
} : ResolvePossibleEvents<T>);
|
|
94
50
|
export declare function createClient<H extends Host<any> | undefined = undefined, Z extends AuthenticationStrategy<H> = AuthenticationStrategy<H>, T extends Descriptors = EmptyObject>(config: {
|
|
95
51
|
modules?: H extends Host<any> ? AssertHostMatches<T, H> : T;
|
|
96
52
|
auth?: Z;
|
package/build/wixClient.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import { wixContext } from '@wix/sdk-context';
|
|
2
|
-
import {
|
|
2
|
+
import { SERVICE_PLUGIN_ERROR_TYPE, } from '@wix/sdk-types';
|
|
3
3
|
import { ambassadorModuleOptions, isAmbassadorModule, toHTTPModule, } from './ambassador-modules.js';
|
|
4
4
|
import { API_URL, PUBLIC_METADATA_KEY } from './common.js';
|
|
5
5
|
import { FetchErrorResponse } from './fetch-error.js';
|
|
6
6
|
import { getDefaultContentHeader, isObject } from './helpers.js';
|
|
7
7
|
import { buildHostModule, isHostModule } from './host-modules.js';
|
|
8
8
|
import { buildRESTDescriptor } from './rest-modules.js';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { eventHandlersModules, isEventHandlerModule, } from './event-handlers-modules.js';
|
|
10
|
+
import { isServicePluginModule, servicePluginsModules, } from './service-plugin-modules.js';
|
|
11
11
|
export function createClient(config) {
|
|
12
12
|
const _headers = config.headers || { Authorization: '' };
|
|
13
|
-
const eventHandlers = new Map();
|
|
14
|
-
const servicePluginsImplementations = new Map();
|
|
15
13
|
const authStrategy = config.auth ||
|
|
16
14
|
{
|
|
17
15
|
getAuthHeaders: (_) => Promise.resolve({ headers: {} }),
|
|
18
16
|
};
|
|
19
17
|
const boundGetAuthHeaders = authStrategy.getAuthHeaders.bind(undefined, config.host);
|
|
20
18
|
authStrategy.getAuthHeaders = boundGetAuthHeaders;
|
|
19
|
+
const { client: servicePluginsClient, initModule: initServicePluginModule } = servicePluginsModules(authStrategy);
|
|
20
|
+
const { client: eventHandlersClient, initModule: initEventHandlerModule } = eventHandlersModules(authStrategy);
|
|
21
21
|
const boundFetch = async (url, options) => {
|
|
22
22
|
const authHeaders = await boundGetAuthHeaders();
|
|
23
23
|
const defaultContentTypeHeader = getDefaultContentHeader(options);
|
|
@@ -36,18 +36,10 @@ export function createClient(config) {
|
|
|
36
36
|
// excessively deep and possibly infinite.`
|
|
37
37
|
const use = (modules, metadata) => {
|
|
38
38
|
if (isEventHandlerModule(modules)) {
|
|
39
|
-
return
|
|
40
|
-
const handlers = eventHandlers.get(eventDefinition.type) ?? [];
|
|
41
|
-
handlers.push({ eventDefinition, handler });
|
|
42
|
-
eventHandlers.set(eventDefinition.type, handlers);
|
|
43
|
-
});
|
|
39
|
+
return initEventHandlerModule(modules);
|
|
44
40
|
}
|
|
45
41
|
else if (isServicePluginModule(modules)) {
|
|
46
|
-
return
|
|
47
|
-
const implementations = servicePluginsImplementations.get(servicePluginDefinition.componentType.toLowerCase()) ?? [];
|
|
48
|
-
implementations.push({ servicePluginDefinition, implementation });
|
|
49
|
-
servicePluginsImplementations.set(servicePluginDefinition.componentType.toLowerCase(), implementations);
|
|
50
|
-
});
|
|
42
|
+
return initServicePluginModule(modules);
|
|
51
43
|
}
|
|
52
44
|
else if (isHostModule(modules) && config.host) {
|
|
53
45
|
return buildHostModule(modules, config.host);
|
|
@@ -161,137 +153,7 @@ export function createClient(config) {
|
|
|
161
153
|
const { data, errors } = await res.json();
|
|
162
154
|
return { data: data ?? {}, errors };
|
|
163
155
|
},
|
|
164
|
-
webhooks:
|
|
165
|
-
|
|
166
|
-
async process(jwt, opts = {
|
|
167
|
-
expectedEvents: [],
|
|
168
|
-
}) {
|
|
169
|
-
const { eventType, identity, instanceId, payload } = await this.parseJWT(jwt);
|
|
170
|
-
const allExpectedEvents = [
|
|
171
|
-
...opts.expectedEvents,
|
|
172
|
-
...Array.from(eventHandlers.keys()).map((type) => ({ type })),
|
|
173
|
-
];
|
|
174
|
-
if (allExpectedEvents.length > 0 &&
|
|
175
|
-
!allExpectedEvents.some(({ type }) => type === eventType)) {
|
|
176
|
-
throw new Error(`Unexpected event type: ${eventType}. Expected one of: ${allExpectedEvents
|
|
177
|
-
.map((x) => x.type)
|
|
178
|
-
.join(', ')}`);
|
|
179
|
-
}
|
|
180
|
-
const handlers = eventHandlers.get(eventType) ?? [];
|
|
181
|
-
await Promise.all(handlers.map(({ eventDefinition, handler }) => runHandler(eventDefinition, handler, payload, {
|
|
182
|
-
instanceId,
|
|
183
|
-
identity,
|
|
184
|
-
})));
|
|
185
|
-
return {
|
|
186
|
-
instanceId,
|
|
187
|
-
eventType,
|
|
188
|
-
payload,
|
|
189
|
-
identity,
|
|
190
|
-
};
|
|
191
|
-
},
|
|
192
|
-
async processRequest(request, opts) {
|
|
193
|
-
const body = await request.text();
|
|
194
|
-
return this.process(body, opts);
|
|
195
|
-
},
|
|
196
|
-
async parseJWT(jwt) {
|
|
197
|
-
if (!authStrategy.decodeJWT) {
|
|
198
|
-
throw new Error('decodeJWT is not supported by the authentication strategy');
|
|
199
|
-
}
|
|
200
|
-
const { decoded, valid } = await authStrategy.decodeJWT(jwt);
|
|
201
|
-
if (!valid) {
|
|
202
|
-
throw new Error('JWT is not valid');
|
|
203
|
-
}
|
|
204
|
-
if (typeof decoded.data !== 'string') {
|
|
205
|
-
throw new Error(`Unexpected type of JWT data: expected string, got ${typeof decoded.data}`);
|
|
206
|
-
}
|
|
207
|
-
const parsedDecoded = JSON.parse(decoded.data);
|
|
208
|
-
const eventType = parsedDecoded.eventType;
|
|
209
|
-
const instanceId = parsedDecoded.instanceId;
|
|
210
|
-
const identity = parsedDecoded.identity
|
|
211
|
-
? JSON.parse(parsedDecoded.identity)
|
|
212
|
-
: undefined;
|
|
213
|
-
const payload = JSON.parse(parsedDecoded.data);
|
|
214
|
-
return {
|
|
215
|
-
instanceId,
|
|
216
|
-
eventType,
|
|
217
|
-
payload,
|
|
218
|
-
identity,
|
|
219
|
-
};
|
|
220
|
-
},
|
|
221
|
-
async parseRequest(request) {
|
|
222
|
-
const jwt = await request.text();
|
|
223
|
-
return this.parseJWT(jwt);
|
|
224
|
-
},
|
|
225
|
-
async executeHandlers(event) {
|
|
226
|
-
const allExpectedEvents = Array.from(eventHandlers.keys()).map((type) => ({ type }));
|
|
227
|
-
if (allExpectedEvents.length > 0 &&
|
|
228
|
-
!allExpectedEvents.some(({ type }) => type === event.eventType)) {
|
|
229
|
-
throw new Error(`Unexpected event type: ${event.eventType}. Expected one of: ${allExpectedEvents
|
|
230
|
-
.map((x) => x.type)
|
|
231
|
-
.join(', ')}`);
|
|
232
|
-
}
|
|
233
|
-
const handlers = eventHandlers.get(event.eventType) ?? [];
|
|
234
|
-
await Promise.all(handlers.map(({ eventDefinition, handler }) => runHandler(eventDefinition, handler, event.payload, {
|
|
235
|
-
instanceId: event.instanceId,
|
|
236
|
-
identity: event.identity,
|
|
237
|
-
})));
|
|
238
|
-
},
|
|
239
|
-
apps: {
|
|
240
|
-
AppInstalled: EventDefinition('AppInstalled')(),
|
|
241
|
-
AppRemoved: EventDefinition('AppRemoved')(),
|
|
242
|
-
},
|
|
243
|
-
},
|
|
244
|
-
servicePlugins: {
|
|
245
|
-
getRegisteredServicePlugins: () => servicePluginsImplementations,
|
|
246
|
-
async process(request) {
|
|
247
|
-
const servicePluginRequest = await this.parseJWT(request.body);
|
|
248
|
-
return this.executeHandler(servicePluginRequest, request.url);
|
|
249
|
-
},
|
|
250
|
-
async processRequest(request) {
|
|
251
|
-
const url = request.url;
|
|
252
|
-
const body = await request.text();
|
|
253
|
-
const implMethodResult = await this.process({ url, body });
|
|
254
|
-
return Response.json(implMethodResult);
|
|
255
|
-
},
|
|
256
|
-
async parseJWT(jwt) {
|
|
257
|
-
if (!authStrategy.decodeJWT) {
|
|
258
|
-
throw new Error('decodeJWT is not supported by the authentication strategy');
|
|
259
|
-
}
|
|
260
|
-
const { decoded, valid } = await authStrategy.decodeJWT(jwt, true);
|
|
261
|
-
if (!valid) {
|
|
262
|
-
throw new Error('JWT is not valid');
|
|
263
|
-
}
|
|
264
|
-
if (typeof decoded.data !== 'object' ||
|
|
265
|
-
decoded.data === null ||
|
|
266
|
-
!('metadata' in decoded.data) ||
|
|
267
|
-
typeof decoded.data.metadata !== 'object' ||
|
|
268
|
-
decoded.data.metadata === null ||
|
|
269
|
-
!('appExtensionType' in decoded.data.metadata) ||
|
|
270
|
-
typeof decoded.data.metadata.appExtensionType !== 'string') {
|
|
271
|
-
throw new Error('Unexpected JWT data: expected object with metadata.appExtensionType string');
|
|
272
|
-
}
|
|
273
|
-
return decoded.data;
|
|
274
|
-
},
|
|
275
|
-
async executeHandler(servicePluginRequest, url) {
|
|
276
|
-
const componentType = servicePluginRequest.metadata.appExtensionType.toLowerCase();
|
|
277
|
-
const implementations = servicePluginsImplementations.get(componentType) ?? [];
|
|
278
|
-
if (implementations.length === 0) {
|
|
279
|
-
throw new Error(`No service plugin implementations found for component type ${componentType}`);
|
|
280
|
-
}
|
|
281
|
-
else if (implementations.length > 1) {
|
|
282
|
-
throw new Error(`Multiple service plugin implementations found for component type ${componentType}. This is currently not supported`);
|
|
283
|
-
}
|
|
284
|
-
const { implementation: impl, servicePluginDefinition } = implementations[0];
|
|
285
|
-
const method = servicePluginDefinition.methods.find((m) => url.endsWith(m.primaryHttpMappingPath));
|
|
286
|
-
if (!method) {
|
|
287
|
-
throw new Error('Unexpect request: request url did not match any method: ' + url);
|
|
288
|
-
}
|
|
289
|
-
const implMethod = impl[method.name];
|
|
290
|
-
if (!implMethod) {
|
|
291
|
-
throw new Error(`Got request for service plugin method ${method.name} but no implementation was provided. Available methods: ${Object.keys(impl).join(', ')}`);
|
|
292
|
-
}
|
|
293
|
-
return method.transformations.toREST(await implMethod(method.transformations.fromREST(servicePluginRequest)));
|
|
294
|
-
},
|
|
295
|
-
},
|
|
156
|
+
webhooks: eventHandlersClient,
|
|
157
|
+
servicePlugins: servicePluginsClient,
|
|
296
158
|
};
|
|
297
159
|
}
|
|
@@ -1,4 +1,48 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AuthenticationStrategy, EventDefinition, EventHandler, EventIdentity } from '@wix/sdk-types';
|
|
2
|
+
import { Emitter } from 'nanoevents';
|
|
2
3
|
export declare const isEventHandlerModule: (val: any) => val is EventDefinition<unknown, string>;
|
|
3
4
|
export declare function buildEventDefinition<T extends EventDefinition<any, string>>(eventDefinition: T, registerHandler: (eventDefinition: T, handler: EventHandler<T>) => void): (handler: EventHandler<T>) => void;
|
|
4
|
-
|
|
5
|
+
type ResolvePossibleEvents<T extends EventDefinition<any>[]> = {
|
|
6
|
+
[K in keyof T]: T[K] extends EventDefinition<any> ? {
|
|
7
|
+
eventType: T[K]['type'];
|
|
8
|
+
payload: T[K]['__payload'];
|
|
9
|
+
} : never;
|
|
10
|
+
} extends (infer U)[] ? U : never;
|
|
11
|
+
export type ProcessedEvent<T extends EventDefinition<any>[] = []> = {
|
|
12
|
+
instanceId: string;
|
|
13
|
+
identity?: EventIdentity;
|
|
14
|
+
} & (T['length'] extends 0 ? {
|
|
15
|
+
eventType: string;
|
|
16
|
+
payload: unknown;
|
|
17
|
+
} : ResolvePossibleEvents<T>);
|
|
18
|
+
export type EventHandlersClient = Emitter<{
|
|
19
|
+
registered: (event: EventDefinition<any>) => void;
|
|
20
|
+
}> & {
|
|
21
|
+
getRegisteredEvents(): Map<string, {
|
|
22
|
+
eventDefinition: EventDefinition;
|
|
23
|
+
handler: EventHandler<EventDefinition>;
|
|
24
|
+
}[]>;
|
|
25
|
+
process<ExpectedEvents extends EventDefinition<any>[] = []>(jwt: string, opts?: {
|
|
26
|
+
expectedEvents: ExpectedEvents;
|
|
27
|
+
}): Promise<ProcessedEvent<ExpectedEvents>>;
|
|
28
|
+
processRequest<ExpectedEvents extends EventDefinition<any>[] = []>(request: Request, opts?: {
|
|
29
|
+
expectedEvents: ExpectedEvents;
|
|
30
|
+
}): Promise<ProcessedEvent<ExpectedEvents>>;
|
|
31
|
+
parseJWT(jwt: string): Promise<ProcessedEvent>;
|
|
32
|
+
parseRequest(request: Request): Promise<ProcessedEvent>;
|
|
33
|
+
executeHandlers(event: ProcessedEvent): Promise<void>;
|
|
34
|
+
apps: {
|
|
35
|
+
AppInstalled: EventDefinition<{
|
|
36
|
+
appId: string;
|
|
37
|
+
originInstanceId: string;
|
|
38
|
+
}, 'AppInstalled'>;
|
|
39
|
+
AppRemoved: EventDefinition<{
|
|
40
|
+
appId: string;
|
|
41
|
+
}, 'AppRemoved'>;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
export declare function eventHandlersModules(authStrategy: AuthenticationStrategy<any>): {
|
|
45
|
+
initModule(eventDefinition: EventDefinition<any, string>): (handler: EventHandler<EventDefinition<any, string>>) => void;
|
|
46
|
+
client: EventHandlersClient;
|
|
47
|
+
};
|
|
48
|
+
export {};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.eventHandlersModules = exports.buildEventDefinition = exports.isEventHandlerModule = void 0;
|
|
4
|
+
const sdk_types_1 = require("@wix/sdk-types");
|
|
5
|
+
const nanoevents_1 = require("nanoevents");
|
|
4
6
|
const isEventHandlerModule = (val) => val.__type === 'event-definition';
|
|
5
7
|
exports.isEventHandlerModule = isEventHandlerModule;
|
|
6
8
|
function buildEventDefinition(eventDefinition, registerHandler) {
|
|
@@ -51,4 +53,100 @@ function runHandler(eventDefinition, handler, payload, baseEventMetadata) {
|
|
|
51
53
|
const transformFromRESTFn = eventDefinition.transformations ?? ((x) => x);
|
|
52
54
|
return handler(transformFromRESTFn(envelope));
|
|
53
55
|
}
|
|
54
|
-
|
|
56
|
+
function eventHandlersModules(authStrategy) {
|
|
57
|
+
const eventHandlers = new Map();
|
|
58
|
+
const webhooksEmitter = (0, nanoevents_1.createNanoEvents)();
|
|
59
|
+
const client = {
|
|
60
|
+
...webhooksEmitter,
|
|
61
|
+
getRegisteredEvents: () => eventHandlers,
|
|
62
|
+
async process(jwt, opts = {
|
|
63
|
+
expectedEvents: [],
|
|
64
|
+
}) {
|
|
65
|
+
const { eventType, identity, instanceId, payload } = await this.parseJWT(jwt);
|
|
66
|
+
const allExpectedEvents = [
|
|
67
|
+
...opts.expectedEvents,
|
|
68
|
+
...Array.from(eventHandlers.keys()).map((type) => ({ type })),
|
|
69
|
+
];
|
|
70
|
+
if (allExpectedEvents.length > 0 &&
|
|
71
|
+
!allExpectedEvents.some(({ type }) => type === eventType)) {
|
|
72
|
+
throw new Error(`Unexpected event type: ${eventType}. Expected one of: ${allExpectedEvents
|
|
73
|
+
.map((x) => x.type)
|
|
74
|
+
.join(', ')}`);
|
|
75
|
+
}
|
|
76
|
+
const handlers = eventHandlers.get(eventType) ?? [];
|
|
77
|
+
await Promise.all(handlers.map(({ eventDefinition, handler }) => runHandler(eventDefinition, handler, payload, {
|
|
78
|
+
instanceId,
|
|
79
|
+
identity,
|
|
80
|
+
})));
|
|
81
|
+
return {
|
|
82
|
+
instanceId,
|
|
83
|
+
eventType,
|
|
84
|
+
payload,
|
|
85
|
+
identity,
|
|
86
|
+
};
|
|
87
|
+
},
|
|
88
|
+
async processRequest(request, opts) {
|
|
89
|
+
const body = await request.text();
|
|
90
|
+
return this.process(body, opts);
|
|
91
|
+
},
|
|
92
|
+
async parseJWT(jwt) {
|
|
93
|
+
if (!authStrategy.decodeJWT) {
|
|
94
|
+
throw new Error('decodeJWT is not supported by the authentication strategy');
|
|
95
|
+
}
|
|
96
|
+
const { decoded, valid } = await authStrategy.decodeJWT(jwt);
|
|
97
|
+
if (!valid) {
|
|
98
|
+
throw new Error('JWT is not valid');
|
|
99
|
+
}
|
|
100
|
+
if (typeof decoded.data !== 'string') {
|
|
101
|
+
throw new Error(`Unexpected type of JWT data: expected string, got ${typeof decoded.data}`);
|
|
102
|
+
}
|
|
103
|
+
const parsedDecoded = JSON.parse(decoded.data);
|
|
104
|
+
const eventType = parsedDecoded.eventType;
|
|
105
|
+
const instanceId = parsedDecoded.instanceId;
|
|
106
|
+
const identity = parsedDecoded.identity
|
|
107
|
+
? JSON.parse(parsedDecoded.identity)
|
|
108
|
+
: undefined;
|
|
109
|
+
const payload = JSON.parse(parsedDecoded.data);
|
|
110
|
+
return {
|
|
111
|
+
instanceId,
|
|
112
|
+
eventType,
|
|
113
|
+
payload,
|
|
114
|
+
identity,
|
|
115
|
+
};
|
|
116
|
+
},
|
|
117
|
+
async parseRequest(request) {
|
|
118
|
+
const jwt = await request.text();
|
|
119
|
+
return this.parseJWT(jwt);
|
|
120
|
+
},
|
|
121
|
+
async executeHandlers(event) {
|
|
122
|
+
const allExpectedEvents = Array.from(eventHandlers.keys()).map((type) => ({ type }));
|
|
123
|
+
if (allExpectedEvents.length > 0 &&
|
|
124
|
+
!allExpectedEvents.some(({ type }) => type === event.eventType)) {
|
|
125
|
+
throw new Error(`Unexpected event type: ${event.eventType}. Expected one of: ${allExpectedEvents
|
|
126
|
+
.map((x) => x.type)
|
|
127
|
+
.join(', ')}`);
|
|
128
|
+
}
|
|
129
|
+
const handlers = eventHandlers.get(event.eventType) ?? [];
|
|
130
|
+
await Promise.all(handlers.map(({ eventDefinition, handler }) => runHandler(eventDefinition, handler, event.payload, {
|
|
131
|
+
instanceId: event.instanceId,
|
|
132
|
+
identity: event.identity,
|
|
133
|
+
})));
|
|
134
|
+
},
|
|
135
|
+
apps: {
|
|
136
|
+
AppInstalled: (0, sdk_types_1.EventDefinition)('AppInstalled')(),
|
|
137
|
+
AppRemoved: (0, sdk_types_1.EventDefinition)('AppRemoved')(),
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
return {
|
|
141
|
+
initModule(eventDefinition) {
|
|
142
|
+
return (handler) => {
|
|
143
|
+
const handlers = eventHandlers.get(eventDefinition.type) ?? [];
|
|
144
|
+
handlers.push({ eventDefinition, handler });
|
|
145
|
+
eventHandlers.set(eventDefinition.type, handlers);
|
|
146
|
+
webhooksEmitter.emit('registered', eventDefinition);
|
|
147
|
+
};
|
|
148
|
+
},
|
|
149
|
+
client,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
exports.eventHandlersModules = eventHandlersModules;
|
|
@@ -1,8 +1,33 @@
|
|
|
1
|
-
import { ServicePluginContract, ServicePluginDefinition } from '@wix/sdk-types';
|
|
1
|
+
import { AuthenticationStrategy, ServicePluginContract, ServicePluginDefinition } from '@wix/sdk-types';
|
|
2
|
+
import { Emitter } from 'nanoevents';
|
|
2
3
|
export declare const isServicePluginModule: (val: any) => val is ServicePluginDefinition<ServicePluginContract>;
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
export type UnknownServicePluginResponse = unknown;
|
|
5
|
+
type ServicePluginRequestMetadata = {
|
|
6
|
+
instanceId: string;
|
|
7
|
+
appExtensionType: string;
|
|
8
|
+
};
|
|
9
|
+
type ServicePluginRequest = {
|
|
10
|
+
metadata: ServicePluginRequestMetadata;
|
|
11
|
+
request: unknown;
|
|
12
|
+
};
|
|
13
|
+
export type ServicePluginsClient = Emitter<{
|
|
14
|
+
registered: (servicePluginDefinition: ServicePluginDefinition<ServicePluginContract>) => void;
|
|
15
|
+
}> & {
|
|
16
|
+
getRegisteredServicePlugins(): Map<string, {
|
|
17
|
+
servicePluginDefinition: ServicePluginDefinition<any>;
|
|
18
|
+
implementation: ServicePluginContract;
|
|
19
|
+
}[]>;
|
|
20
|
+
process(request: {
|
|
21
|
+
url: string;
|
|
22
|
+
body: string;
|
|
23
|
+
}): Promise<unknown>;
|
|
24
|
+
processRequest(request: Request): Promise<Response>;
|
|
25
|
+
parseJWT(jwt: string): Promise<ServicePluginRequest>;
|
|
26
|
+
parseRequest(request: Request): Promise<ServicePluginRequest>;
|
|
27
|
+
executeHandler(servicePluginRequest: ServicePluginRequest, url: string): Promise<UnknownServicePluginResponse>;
|
|
28
|
+
};
|
|
29
|
+
export declare function servicePluginsModules(authStrategy: AuthenticationStrategy<any>): {
|
|
30
|
+
initModule<T extends ServicePluginDefinition<any>>(servicePluginDefinition: T): (implementation: T["__contract"]) => void;
|
|
31
|
+
client: ServicePluginsClient;
|
|
32
|
+
};
|
|
33
|
+
export {};
|
|
@@ -1,11 +1,79 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.servicePluginsModules = exports.isServicePluginModule = void 0;
|
|
4
|
+
const nanoevents_1 = require("nanoevents");
|
|
4
5
|
const isServicePluginModule = (val) => val.__type === 'service-plugin-definition';
|
|
5
6
|
exports.isServicePluginModule = isServicePluginModule;
|
|
6
|
-
function
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
function servicePluginsModules(authStrategy) {
|
|
8
|
+
const servicePluginsImplementations = new Map();
|
|
9
|
+
const servicePluginsEmitter = (0, nanoevents_1.createNanoEvents)();
|
|
10
|
+
const client = {
|
|
11
|
+
...servicePluginsEmitter,
|
|
12
|
+
getRegisteredServicePlugins: () => servicePluginsImplementations,
|
|
13
|
+
async parseJWT(jwt) {
|
|
14
|
+
if (!authStrategy.decodeJWT) {
|
|
15
|
+
throw new Error('decodeJWT is not supported by the authentication strategy');
|
|
16
|
+
}
|
|
17
|
+
const { decoded, valid } = await authStrategy.decodeJWT(jwt, true);
|
|
18
|
+
if (!valid) {
|
|
19
|
+
throw new Error('JWT is not valid');
|
|
20
|
+
}
|
|
21
|
+
if (typeof decoded.data !== 'object' ||
|
|
22
|
+
decoded.data === null ||
|
|
23
|
+
!('metadata' in decoded.data) ||
|
|
24
|
+
typeof decoded.data.metadata !== 'object' ||
|
|
25
|
+
decoded.data.metadata === null ||
|
|
26
|
+
!('appExtensionType' in decoded.data.metadata) ||
|
|
27
|
+
typeof decoded.data.metadata.appExtensionType !== 'string') {
|
|
28
|
+
throw new Error('Unexpected JWT data: expected object with metadata.appExtensionType string');
|
|
29
|
+
}
|
|
30
|
+
return decoded.data;
|
|
31
|
+
},
|
|
32
|
+
async process(request) {
|
|
33
|
+
const servicePluginRequest = await this.parseJWT(request.body);
|
|
34
|
+
return this.executeHandler(servicePluginRequest, request.url);
|
|
35
|
+
},
|
|
36
|
+
async parseRequest(request) {
|
|
37
|
+
const body = await request.text();
|
|
38
|
+
return this.parseJWT(body);
|
|
39
|
+
},
|
|
40
|
+
async processRequest(request) {
|
|
41
|
+
const url = request.url;
|
|
42
|
+
const body = await request.text();
|
|
43
|
+
const implMethodResult = await this.process({ url, body });
|
|
44
|
+
return Response.json(implMethodResult);
|
|
45
|
+
},
|
|
46
|
+
async executeHandler(servicePluginRequest, url) {
|
|
47
|
+
const componentType = servicePluginRequest.metadata.appExtensionType.toLowerCase();
|
|
48
|
+
const implementations = servicePluginsImplementations.get(componentType) ?? [];
|
|
49
|
+
if (implementations.length === 0) {
|
|
50
|
+
throw new Error(`No service plugin implementations found for component type ${componentType}`);
|
|
51
|
+
}
|
|
52
|
+
else if (implementations.length > 1) {
|
|
53
|
+
throw new Error(`Multiple service plugin implementations found for component type ${componentType}. This is currently not supported`);
|
|
54
|
+
}
|
|
55
|
+
const { implementation: impl, servicePluginDefinition } = implementations[0];
|
|
56
|
+
const method = servicePluginDefinition.methods.find((m) => url.endsWith(m.primaryHttpMappingPath));
|
|
57
|
+
if (!method) {
|
|
58
|
+
throw new Error('Unexpect request: request url did not match any method: ' + url);
|
|
59
|
+
}
|
|
60
|
+
const implMethod = impl[method.name];
|
|
61
|
+
if (!implMethod) {
|
|
62
|
+
throw new Error(`Got request for service plugin method ${method.name} but no implementation was provided. Available methods: ${Object.keys(impl).join(', ')}`);
|
|
63
|
+
}
|
|
64
|
+
return method.transformations.toREST(await implMethod(method.transformations.fromREST(servicePluginRequest)));
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
return {
|
|
68
|
+
initModule(servicePluginDefinition) {
|
|
69
|
+
return (implementation) => {
|
|
70
|
+
const implementations = servicePluginsImplementations.get(servicePluginDefinition.componentType.toLowerCase()) ?? [];
|
|
71
|
+
implementations.push({ servicePluginDefinition, implementation });
|
|
72
|
+
servicePluginsImplementations.set(servicePluginDefinition.componentType.toLowerCase(), implementations);
|
|
73
|
+
servicePluginsEmitter.emit('registered', servicePluginDefinition);
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
client,
|
|
9
77
|
};
|
|
10
78
|
}
|
|
11
|
-
exports.
|
|
79
|
+
exports.servicePluginsModules = servicePluginsModules;
|
package/cjs/build/wixClient.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { AuthenticationStrategy, BoundAuthenticationStrategy, BuildDescriptors, Descriptors,
|
|
1
|
+
import { AuthenticationStrategy, BoundAuthenticationStrategy, BuildDescriptors, Descriptors, Host, HostModule, RESTFunctionDescriptor } from '@wix/sdk-types';
|
|
2
2
|
import { EmptyObject } from 'type-fest/source/empty-object.js';
|
|
3
3
|
import type { GraphQLFormattedError } from 'graphql';
|
|
4
|
+
import { EventHandlersClient } from './event-handlers-modules.js';
|
|
5
|
+
import { ServicePluginsClient } from './service-plugin-modules.js';
|
|
4
6
|
export type ContextType = 'global' | 'module';
|
|
5
7
|
type Headers = Record<string, string>;
|
|
6
8
|
/**
|
|
@@ -42,55 +44,9 @@ export type WixClient<H extends Host<any> | undefined = undefined, Z extends Aut
|
|
|
42
44
|
data: Result;
|
|
43
45
|
errors?: GraphQLFormattedError[];
|
|
44
46
|
}>;
|
|
45
|
-
webhooks:
|
|
46
|
-
|
|
47
|
-
process<ExpectedEvents extends EventDefinition<any>[] = []>(jwt: string, opts?: {
|
|
48
|
-
expectedEvents: ExpectedEvents;
|
|
49
|
-
}): Promise<ProcessedEvent<ExpectedEvents>>;
|
|
50
|
-
processRequest<ExpectedEvents extends EventDefinition<any>[] = []>(request: Request, opts?: {
|
|
51
|
-
expectedEvents: ExpectedEvents;
|
|
52
|
-
}): Promise<ProcessedEvent<ExpectedEvents>>;
|
|
53
|
-
parseJWT(jwt: string): Promise<ProcessedEvent>;
|
|
54
|
-
parseRequest(request: Request): Promise<ProcessedEvent>;
|
|
55
|
-
executeHandlers(event: ProcessedEvent): Promise<void>;
|
|
56
|
-
apps: {
|
|
57
|
-
AppInstalled: EventDefinition<{
|
|
58
|
-
appId: string;
|
|
59
|
-
originInstanceId: string;
|
|
60
|
-
}, 'AppInstalled'>;
|
|
61
|
-
AppRemoved: EventDefinition<{
|
|
62
|
-
appId: string;
|
|
63
|
-
}, 'AppRemoved'>;
|
|
64
|
-
};
|
|
65
|
-
};
|
|
66
|
-
servicePlugins: {
|
|
67
|
-
getRegisteredServicePlugins(): Map<string, {
|
|
68
|
-
servicePluginDefinition: ServicePluginDefinition<any>;
|
|
69
|
-
implementation: ServicePluginContract;
|
|
70
|
-
}[]>;
|
|
71
|
-
process(request: {
|
|
72
|
-
url: string;
|
|
73
|
-
body: string;
|
|
74
|
-
}): Promise<unknown>;
|
|
75
|
-
processRequest(request: Request): Promise<Response>;
|
|
76
|
-
parseJWT(jwt: string): Promise<unknown>;
|
|
77
|
-
parseRequest(request: Request): Promise<unknown>;
|
|
78
|
-
executeHandler(servicePluginRequest: ProcessedEvent): Promise<void>;
|
|
79
|
-
};
|
|
47
|
+
webhooks: EventHandlersClient;
|
|
48
|
+
servicePlugins: ServicePluginsClient;
|
|
80
49
|
} & BuildDescriptors<T, H>;
|
|
81
|
-
type ResolvePossibleEvents<T extends EventDefinition<any>[]> = {
|
|
82
|
-
[K in keyof T]: T[K] extends EventDefinition<any> ? {
|
|
83
|
-
eventType: T[K]['type'];
|
|
84
|
-
payload: T[K]['__payload'];
|
|
85
|
-
} : never;
|
|
86
|
-
} extends (infer U)[] ? U : never;
|
|
87
|
-
export type ProcessedEvent<T extends EventDefinition<any>[] = []> = {
|
|
88
|
-
instanceId: string;
|
|
89
|
-
identity?: EventIdentity;
|
|
90
|
-
} & (T['length'] extends 0 ? {
|
|
91
|
-
eventType: string;
|
|
92
|
-
payload: unknown;
|
|
93
|
-
} : ResolvePossibleEvents<T>);
|
|
94
50
|
export declare function createClient<H extends Host<any> | undefined = undefined, Z extends AuthenticationStrategy<H> = AuthenticationStrategy<H>, T extends Descriptors = EmptyObject>(config: {
|
|
95
51
|
modules?: H extends Host<any> ? AssertHostMatches<T, H> : T;
|
|
96
52
|
auth?: Z;
|
package/cjs/build/wixClient.js
CHANGED
|
@@ -13,14 +13,14 @@ const event_handlers_modules_js_1 = require("./event-handlers-modules.js");
|
|
|
13
13
|
const service_plugin_modules_js_1 = require("./service-plugin-modules.js");
|
|
14
14
|
function createClient(config) {
|
|
15
15
|
const _headers = config.headers || { Authorization: '' };
|
|
16
|
-
const eventHandlers = new Map();
|
|
17
|
-
const servicePluginsImplementations = new Map();
|
|
18
16
|
const authStrategy = config.auth ||
|
|
19
17
|
{
|
|
20
18
|
getAuthHeaders: (_) => Promise.resolve({ headers: {} }),
|
|
21
19
|
};
|
|
22
20
|
const boundGetAuthHeaders = authStrategy.getAuthHeaders.bind(undefined, config.host);
|
|
23
21
|
authStrategy.getAuthHeaders = boundGetAuthHeaders;
|
|
22
|
+
const { client: servicePluginsClient, initModule: initServicePluginModule } = (0, service_plugin_modules_js_1.servicePluginsModules)(authStrategy);
|
|
23
|
+
const { client: eventHandlersClient, initModule: initEventHandlerModule } = (0, event_handlers_modules_js_1.eventHandlersModules)(authStrategy);
|
|
24
24
|
const boundFetch = async (url, options) => {
|
|
25
25
|
const authHeaders = await boundGetAuthHeaders();
|
|
26
26
|
const defaultContentTypeHeader = (0, helpers_js_1.getDefaultContentHeader)(options);
|
|
@@ -39,18 +39,10 @@ function createClient(config) {
|
|
|
39
39
|
// excessively deep and possibly infinite.`
|
|
40
40
|
const use = (modules, metadata) => {
|
|
41
41
|
if ((0, event_handlers_modules_js_1.isEventHandlerModule)(modules)) {
|
|
42
|
-
return (
|
|
43
|
-
const handlers = eventHandlers.get(eventDefinition.type) ?? [];
|
|
44
|
-
handlers.push({ eventDefinition, handler });
|
|
45
|
-
eventHandlers.set(eventDefinition.type, handlers);
|
|
46
|
-
});
|
|
42
|
+
return initEventHandlerModule(modules);
|
|
47
43
|
}
|
|
48
44
|
else if ((0, service_plugin_modules_js_1.isServicePluginModule)(modules)) {
|
|
49
|
-
return (
|
|
50
|
-
const implementations = servicePluginsImplementations.get(servicePluginDefinition.componentType.toLowerCase()) ?? [];
|
|
51
|
-
implementations.push({ servicePluginDefinition, implementation });
|
|
52
|
-
servicePluginsImplementations.set(servicePluginDefinition.componentType.toLowerCase(), implementations);
|
|
53
|
-
});
|
|
45
|
+
return initServicePluginModule(modules);
|
|
54
46
|
}
|
|
55
47
|
else if ((0, host_modules_js_1.isHostModule)(modules) && config.host) {
|
|
56
48
|
return (0, host_modules_js_1.buildHostModule)(modules, config.host);
|
|
@@ -164,138 +156,8 @@ function createClient(config) {
|
|
|
164
156
|
const { data, errors } = await res.json();
|
|
165
157
|
return { data: data ?? {}, errors };
|
|
166
158
|
},
|
|
167
|
-
webhooks:
|
|
168
|
-
|
|
169
|
-
async process(jwt, opts = {
|
|
170
|
-
expectedEvents: [],
|
|
171
|
-
}) {
|
|
172
|
-
const { eventType, identity, instanceId, payload } = await this.parseJWT(jwt);
|
|
173
|
-
const allExpectedEvents = [
|
|
174
|
-
...opts.expectedEvents,
|
|
175
|
-
...Array.from(eventHandlers.keys()).map((type) => ({ type })),
|
|
176
|
-
];
|
|
177
|
-
if (allExpectedEvents.length > 0 &&
|
|
178
|
-
!allExpectedEvents.some(({ type }) => type === eventType)) {
|
|
179
|
-
throw new Error(`Unexpected event type: ${eventType}. Expected one of: ${allExpectedEvents
|
|
180
|
-
.map((x) => x.type)
|
|
181
|
-
.join(', ')}`);
|
|
182
|
-
}
|
|
183
|
-
const handlers = eventHandlers.get(eventType) ?? [];
|
|
184
|
-
await Promise.all(handlers.map(({ eventDefinition, handler }) => (0, event_handlers_modules_js_1.runHandler)(eventDefinition, handler, payload, {
|
|
185
|
-
instanceId,
|
|
186
|
-
identity,
|
|
187
|
-
})));
|
|
188
|
-
return {
|
|
189
|
-
instanceId,
|
|
190
|
-
eventType,
|
|
191
|
-
payload,
|
|
192
|
-
identity,
|
|
193
|
-
};
|
|
194
|
-
},
|
|
195
|
-
async processRequest(request, opts) {
|
|
196
|
-
const body = await request.text();
|
|
197
|
-
return this.process(body, opts);
|
|
198
|
-
},
|
|
199
|
-
async parseJWT(jwt) {
|
|
200
|
-
if (!authStrategy.decodeJWT) {
|
|
201
|
-
throw new Error('decodeJWT is not supported by the authentication strategy');
|
|
202
|
-
}
|
|
203
|
-
const { decoded, valid } = await authStrategy.decodeJWT(jwt);
|
|
204
|
-
if (!valid) {
|
|
205
|
-
throw new Error('JWT is not valid');
|
|
206
|
-
}
|
|
207
|
-
if (typeof decoded.data !== 'string') {
|
|
208
|
-
throw new Error(`Unexpected type of JWT data: expected string, got ${typeof decoded.data}`);
|
|
209
|
-
}
|
|
210
|
-
const parsedDecoded = JSON.parse(decoded.data);
|
|
211
|
-
const eventType = parsedDecoded.eventType;
|
|
212
|
-
const instanceId = parsedDecoded.instanceId;
|
|
213
|
-
const identity = parsedDecoded.identity
|
|
214
|
-
? JSON.parse(parsedDecoded.identity)
|
|
215
|
-
: undefined;
|
|
216
|
-
const payload = JSON.parse(parsedDecoded.data);
|
|
217
|
-
return {
|
|
218
|
-
instanceId,
|
|
219
|
-
eventType,
|
|
220
|
-
payload,
|
|
221
|
-
identity,
|
|
222
|
-
};
|
|
223
|
-
},
|
|
224
|
-
async parseRequest(request) {
|
|
225
|
-
const jwt = await request.text();
|
|
226
|
-
return this.parseJWT(jwt);
|
|
227
|
-
},
|
|
228
|
-
async executeHandlers(event) {
|
|
229
|
-
const allExpectedEvents = Array.from(eventHandlers.keys()).map((type) => ({ type }));
|
|
230
|
-
if (allExpectedEvents.length > 0 &&
|
|
231
|
-
!allExpectedEvents.some(({ type }) => type === event.eventType)) {
|
|
232
|
-
throw new Error(`Unexpected event type: ${event.eventType}. Expected one of: ${allExpectedEvents
|
|
233
|
-
.map((x) => x.type)
|
|
234
|
-
.join(', ')}`);
|
|
235
|
-
}
|
|
236
|
-
const handlers = eventHandlers.get(event.eventType) ?? [];
|
|
237
|
-
await Promise.all(handlers.map(({ eventDefinition, handler }) => (0, event_handlers_modules_js_1.runHandler)(eventDefinition, handler, event.payload, {
|
|
238
|
-
instanceId: event.instanceId,
|
|
239
|
-
identity: event.identity,
|
|
240
|
-
})));
|
|
241
|
-
},
|
|
242
|
-
apps: {
|
|
243
|
-
AppInstalled: (0, sdk_types_1.EventDefinition)('AppInstalled')(),
|
|
244
|
-
AppRemoved: (0, sdk_types_1.EventDefinition)('AppRemoved')(),
|
|
245
|
-
},
|
|
246
|
-
},
|
|
247
|
-
servicePlugins: {
|
|
248
|
-
getRegisteredServicePlugins: () => servicePluginsImplementations,
|
|
249
|
-
async process(request) {
|
|
250
|
-
const servicePluginRequest = await this.parseJWT(request.body);
|
|
251
|
-
return this.executeHandler(servicePluginRequest, request.url);
|
|
252
|
-
},
|
|
253
|
-
async processRequest(request) {
|
|
254
|
-
const url = request.url;
|
|
255
|
-
const body = await request.text();
|
|
256
|
-
const implMethodResult = await this.process({ url, body });
|
|
257
|
-
return Response.json(implMethodResult);
|
|
258
|
-
},
|
|
259
|
-
async parseJWT(jwt) {
|
|
260
|
-
if (!authStrategy.decodeJWT) {
|
|
261
|
-
throw new Error('decodeJWT is not supported by the authentication strategy');
|
|
262
|
-
}
|
|
263
|
-
const { decoded, valid } = await authStrategy.decodeJWT(jwt, true);
|
|
264
|
-
if (!valid) {
|
|
265
|
-
throw new Error('JWT is not valid');
|
|
266
|
-
}
|
|
267
|
-
if (typeof decoded.data !== 'object' ||
|
|
268
|
-
decoded.data === null ||
|
|
269
|
-
!('metadata' in decoded.data) ||
|
|
270
|
-
typeof decoded.data.metadata !== 'object' ||
|
|
271
|
-
decoded.data.metadata === null ||
|
|
272
|
-
!('appExtensionType' in decoded.data.metadata) ||
|
|
273
|
-
typeof decoded.data.metadata.appExtensionType !== 'string') {
|
|
274
|
-
throw new Error('Unexpected JWT data: expected object with metadata.appExtensionType string');
|
|
275
|
-
}
|
|
276
|
-
return decoded.data;
|
|
277
|
-
},
|
|
278
|
-
async executeHandler(servicePluginRequest, url) {
|
|
279
|
-
const componentType = servicePluginRequest.metadata.appExtensionType.toLowerCase();
|
|
280
|
-
const implementations = servicePluginsImplementations.get(componentType) ?? [];
|
|
281
|
-
if (implementations.length === 0) {
|
|
282
|
-
throw new Error(`No service plugin implementations found for component type ${componentType}`);
|
|
283
|
-
}
|
|
284
|
-
else if (implementations.length > 1) {
|
|
285
|
-
throw new Error(`Multiple service plugin implementations found for component type ${componentType}. This is currently not supported`);
|
|
286
|
-
}
|
|
287
|
-
const { implementation: impl, servicePluginDefinition } = implementations[0];
|
|
288
|
-
const method = servicePluginDefinition.methods.find((m) => url.endsWith(m.primaryHttpMappingPath));
|
|
289
|
-
if (!method) {
|
|
290
|
-
throw new Error('Unexpect request: request url did not match any method: ' + url);
|
|
291
|
-
}
|
|
292
|
-
const implMethod = impl[method.name];
|
|
293
|
-
if (!implMethod) {
|
|
294
|
-
throw new Error(`Got request for service plugin method ${method.name} but no implementation was provided. Available methods: ${Object.keys(impl).join(', ')}`);
|
|
295
|
-
}
|
|
296
|
-
return method.transformations.toREST(await implMethod(method.transformations.fromREST(servicePluginRequest)));
|
|
297
|
-
},
|
|
298
|
-
},
|
|
159
|
+
webhooks: eventHandlersClient,
|
|
160
|
+
servicePlugins: servicePluginsClient,
|
|
299
161
|
};
|
|
300
162
|
}
|
|
301
163
|
exports.createClient = createClient;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/sdk",
|
|
3
|
-
"version": "1.12.
|
|
3
|
+
"version": "1.12.9",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Ronny Ringel",
|
|
@@ -65,13 +65,14 @@
|
|
|
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.77.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.14",
|
|
72
72
|
"@wix/sdk-types": "^1.9.2",
|
|
73
73
|
"crypto-js": "^4.2.0",
|
|
74
74
|
"jose": "^5.2.1",
|
|
75
|
+
"nanoevents": "^9.0.0",
|
|
75
76
|
"pkce-challenge": "^3.1.0",
|
|
76
77
|
"querystring": "^0.2.1",
|
|
77
78
|
"type-fest": "^4.9.0"
|
|
@@ -88,7 +89,7 @@
|
|
|
88
89
|
"@wix/events": "^1.0.179",
|
|
89
90
|
"@wix/metro": "^1.0.73",
|
|
90
91
|
"@wix/metro-runtime": "^1.1677.0",
|
|
91
|
-
"@wix/sdk-runtime": "0.3.
|
|
92
|
+
"@wix/sdk-runtime": "0.3.14",
|
|
92
93
|
"eslint": "^8.56.0",
|
|
93
94
|
"eslint-config-sdk": "0.0.0",
|
|
94
95
|
"graphql": "^16.8.0",
|
|
@@ -122,5 +123,5 @@
|
|
|
122
123
|
"wallaby": {
|
|
123
124
|
"autoDetect": true
|
|
124
125
|
},
|
|
125
|
-
"falconPackageHash": "
|
|
126
|
+
"falconPackageHash": "fac4a20ec702fb1a9e081a3fe2eb9dc105d284baeb49281de73dbf0e"
|
|
126
127
|
}
|