@wix/sdk 1.12.8 → 1.12.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,48 @@
1
- import { BaseEventMetadata, EventDefinition, EventHandler } from '@wix/sdk-types';
1
+ import { AuthenticationStrategy, EventDefinition, EventHandler, EventIdentity } from '@wix/sdk-types';
2
+ import { Emitter } from './nanoevents.js';
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
- export declare function runHandler<T extends EventDefinition>(eventDefinition: T, handler: EventHandler<T>, payload: unknown, baseEventMetadata: BaseEventMetadata): void | Promise<void>;
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.runHandler = exports.buildEventDefinition = exports.isEventHandlerModule = void 0;
3
+ exports.eventHandlersModules = exports.buildEventDefinition = exports.isEventHandlerModule = void 0;
4
+ const sdk_types_1 = require("@wix/sdk-types");
5
+ const nanoevents_js_1 = require("./nanoevents.js");
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
- exports.runHandler = runHandler;
56
+ function eventHandlersModules(authStrategy) {
57
+ const eventHandlers = new Map();
58
+ const webhooksEmitter = (0, nanoevents_js_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;
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Create event emitter.
3
+ *
4
+ * ```js
5
+ * import { createNanoEvents } from 'nanoevents'
6
+ *
7
+ * class Ticker {
8
+ * constructor() {
9
+ * this.emitter = createNanoEvents()
10
+ * }
11
+ * on(...args) {
12
+ * return this.emitter.on(...args)
13
+ * }
14
+ * tick() {
15
+ * this.emitter.emit('tick')
16
+ * }
17
+ * }
18
+ * ```
19
+ * @returns Event emitter.
20
+ */
21
+ export declare function createNanoEvents<Events extends EventsMap = DefaultEvents>(): Emitter<Events>;
22
+ interface EventsMap {
23
+ [event: string]: any;
24
+ }
25
+ interface DefaultEvents extends EventsMap {
26
+ [event: string]: (...args: any) => void;
27
+ }
28
+ export type Unsubscribe = () => void;
29
+ export interface Emitter<Events extends EventsMap = DefaultEvents> {
30
+ /**
31
+ * Calls each of the listeners registered for a given event.
32
+ *
33
+ * ```js
34
+ * ee.emit('tick', tickType, tickDuration)
35
+ * ```
36
+ * @param event The event name.
37
+ * @param args The arguments for listeners.
38
+ */
39
+ emit<K extends keyof Events>(this: this, event: K, ...args: Parameters<Events[K]>): void;
40
+ /**
41
+ * Event names in keys and arrays with listeners in values.
42
+ *
43
+ * ```js
44
+ * emitter1.events = emitter2.events
45
+ * emitter2.events = { }
46
+ * ```
47
+ */
48
+ events: Partial<{
49
+ [E in keyof Events]: Events[E][];
50
+ }>;
51
+ /**
52
+ * Add a listener for a given event.
53
+ *
54
+ * ```js
55
+ * const unbind = ee.on('tick', (tickType, tickDuration) => {
56
+ * count += 1
57
+ * })
58
+ *
59
+ * disable () {
60
+ * unbind()
61
+ * }
62
+ * ```
63
+ * @param event The event name.
64
+ * @param cb The listener function.
65
+ * @returns Unbind listener from event.
66
+ */
67
+ on<K extends keyof Events>(this: this, event: K, cb: Events[K]): Unsubscribe;
68
+ }
69
+ export {};
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ // Inlined from https://github.com/ai/nanoevents/blob/main/index.js
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.createNanoEvents = void 0;
5
+ /**
6
+ * Create event emitter.
7
+ *
8
+ * ```js
9
+ * import { createNanoEvents } from 'nanoevents'
10
+ *
11
+ * class Ticker {
12
+ * constructor() {
13
+ * this.emitter = createNanoEvents()
14
+ * }
15
+ * on(...args) {
16
+ * return this.emitter.on(...args)
17
+ * }
18
+ * tick() {
19
+ * this.emitter.emit('tick')
20
+ * }
21
+ * }
22
+ * ```
23
+ * @returns Event emitter.
24
+ */
25
+ function createNanoEvents() {
26
+ return {
27
+ emit(event, ...args) {
28
+ for (let i = 0, callbacks = this.events[event] || [], length = callbacks.length; i < length; i++) {
29
+ callbacks[i](...args);
30
+ }
31
+ },
32
+ events: {},
33
+ on(event, cb) {
34
+ (this.events[event] ||= []).push(cb);
35
+ return () => {
36
+ this.events[event] = this.events[event]?.filter((i) => cb !== i);
37
+ };
38
+ },
39
+ };
40
+ }
41
+ exports.createNanoEvents = createNanoEvents;
@@ -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.js';
2
3
  export declare const isServicePluginModule: (val: any) => val is ServicePluginDefinition<ServicePluginContract>;
3
- export declare function buildServicePluginDefinition<T extends ServicePluginDefinition<any>>(servicePluginDefinition: T, registrServicePluginImplementation: (servicePluginDefinition: T, implementation: T['__contract']) => void, decodeJWT?: (token: string, verifyCallerClaims?: boolean) => Promise<{
4
- decoded: {
5
- data: string;
6
- };
7
- valid: boolean;
8
- }>): (implementation: T['__contract']) => void;
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.buildServicePluginDefinition = exports.isServicePluginModule = void 0;
3
+ exports.servicePluginsModules = exports.isServicePluginModule = void 0;
4
+ const nanoevents_js_1 = require("./nanoevents.js");
4
5
  const isServicePluginModule = (val) => val.__type === 'service-plugin-definition';
5
6
  exports.isServicePluginModule = isServicePluginModule;
6
- function buildServicePluginDefinition(servicePluginDefinition, registrServicePluginImplementation, decodeJWT) {
7
- return (implementation) => {
8
- registrServicePluginImplementation(servicePluginDefinition, implementation);
7
+ function servicePluginsModules(authStrategy) {
8
+ const servicePluginsImplementations = new Map();
9
+ const servicePluginsEmitter = (0, nanoevents_js_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.buildServicePluginDefinition = buildServicePluginDefinition;
79
+ exports.servicePluginsModules = servicePluginsModules;
@@ -1,6 +1,8 @@
1
- import { AuthenticationStrategy, BoundAuthenticationStrategy, BuildDescriptors, Descriptors, EventDefinition, EventIdentity, Host, HostModule, RESTFunctionDescriptor, ServicePluginContract, ServicePluginDefinition } from '@wix/sdk-types';
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
- getRegisteredEvents(): string[];
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;
@@ -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 (0, event_handlers_modules_js_1.buildEventDefinition)(modules, (eventDefinition, handler) => {
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 (0, service_plugin_modules_js_1.buildServicePluginDefinition)(modules, (servicePluginDefinition, implementation) => {
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
- getRegisteredEvents: () => Array.from(eventHandlers.keys()),
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;